Вторник, 16.04.2024, 20:41
Приветствую Вас Гость

Не ошибается тот, кто ничего не делает.
Но и ничего не делать - ошибка.

Эмиль Кроткий

[ Новые сообщения · Участники · Правила форума · Поиск · RSS ]
  • Страница 1 из 1
  • 1
Форум » Delphi » DirectShow и Delphi. » SampleGrabber - пустой скриншот (нулевой размер файла)
SampleGrabber - пустой скриншот
BLACK_CRAFTER666Дата: Пятница, 09.08.2013, 16:16 | Сообщение # 1
Сержант
Группа: Пользователи
Сообщений: 31
Репутация: 0
Статус: Offline
И снова здравствуйте smile
Путём соединения Pin'ов, строю в своей программе такой граф: http://i33.fastpic.ru/big/2013/0810/43/1f12989a40129d93978f2fc6a1812343.jpg
на удивление, картинка есть smile
Но вот косяк. При попытке снятия скриншота, получается пустой BMP-файл.
Код:

     
Код
Result := pGrabber.SetMediaType(MT); //MT беру из нулевого пина фильтра источника
      if Result = s_ok then
      begin
        pGrabber.SetOneShot(False);
        pGrabber.SetBufferSamples(True);
      end;

function MakeScreenshot(var bmp: TBitmap):Boolean;
var
    BMIHeader : TBitmapInfoHeader;
    bmpInfo : PBitmapInfo;
//  bmp: TBitmap;
    hr : HRESULT;
    buffer : Pointer;
    BufferSize: longint;
    mt : TAMMediaType;
    HBMP : HBITMAP;
begin
    Result := False;
    buffer := nil;
    BufferSize := 0;
//  BMIHeader := 0;
          ZeroMemory(@mt,SizeOf(mt));
          hr := pGrabber.GetConnectedMediaType(mt);
          if hr<>s_ok then
          begin
            case hr of
              E_POINTER:
              MessageBox(form1.Handle,PChar('MT E_POINTER'),'',MB_ICONERROR);
              VFW_E_NOT_CONNECTED:
              MessageBox(form1.Handle,PChar('MT VFW_E_NOT_CONNECTED'),'',MB_ICONERROR);
            end;
            Exit;
          end;
          if (IsEqualGUID(mt.majortype, MEDIATYPE_Video)) or                // зачем нужны
             (IsEqualGUID(mt.majortype,MEDIATYPE_Stream))  then begin // эти проверки?
            case mt.formattype.D1 of
              $05589F80: BMIHeader := PVideoInfoHeader(mt.pbFormat)^.bmiHeader; // выполняется это
              $F72A76A0: BMIHeader := PVideoInfoHeader2(mt.pbFormat)^.bmiHeader;
            else
            BMIHeader := PVideoInfoHeader2(mt.pbFormat)^.bmiHeader;
            end;
//          New(bmpinfo);
            ZeroMemory(BMPInfo, sizeof(BMPInfo));
            CopyMemory(@BMPInfo.bmiHeader, @bmiHeader, sizeof(TBITMAPINFOHEADER)); // тут структура вроде не пустая
            bmp.Handle := CreateDIBSection(0, BMPInfo^, DIB_RGB_COLORS, buffer, 0, 0); //возвращает 0
{          hbmp := CreateDIBSection(0, BMPInfo^, DIB_RGB_COLORS, buffer, 0, 0);
            If hbmp=ERROR_INVALID_PARAMETER then
            begin
              MessageBox(form1,PChar('ERROR_INVALID_PARAMETER'),'',0);
              Exit;
            end;}
            HR := pGrabber.GetCurrentBuffer(BufferSize, buffer); //размер приходит, а буфер = nil; HR = S_OK
            case hr of
      E_OUTOFMEMORY:
      MessageBox(0,PChar('??? ?? ??????'),PChar('SOUND ERROR'),MB_ICONERROR);
      E_INVALIDARG:
      MessageBox(0,PChar('E_INVALIDARG'),PChar('SOUND ERROR'),MB_ICONERROR);
      VFW_E_NOT_CONNECTED:
      MessageBox(0,PChar('VFW NOT CONNECTED'),PChar('SOUND ERROR'),MB_ICONERROR);
      E_POINTER:
      MessageBox(0,PChar('E_POINTER'),PChar('SOUND ERROR'),MB_ICONERROR);
      VFW_E_WRONG_STATE:
      MessageBox(0,PChar('WRONG STATE'),PChar('SOUND ERROR'),MB_ICONERROR);
{    S_OK:
      MessageBox(0,PChar('OK'),PChar('SOUND ERROR'),MB_OK);}
            end;
      end;
//  BMIHeader := nil;
    bmpInfo := nil;
    buffer := nil;
    BufferSize := 0;
    MoFreeMediaType(@mt);
    Result := True;
end;

procedure TForm1.btn1Click(Sender: TObject);
var
    t : string;
    bmp : TBitmap;
begin
    bmp := TBitmap.Create;
    pMediaControl.Pause;
    if MakeScreenshot(bmp) then
    begin
      t := 'c:\900.bmp';
      bmp.SaveToFile(t);
      ShellExecute(0,nil,PChar(t),nil,nil,SW_SHOW);
    end;
    bmp.Free;
//  pMediaControl.Run;

end;

Я мало что понимаю в этой процедуре. Особенно это:

           
Код
bmp.Handle := CreateDIBSection(0, BMPInfo^, DIB_RGB_COLORS, buffer, 0, 0); //возвращает 0
            HR := pGrabber.GetCurrentBuffer(BufferSize, buffer); //размер приходит, а буфер = nil; HR = S_OK

Тут типа создается HBITMAP с пустым буфером и присваивается, как хэндл TBITMAP. А на следующей строчке мы пытаемся получить этот буфер из SampleGrabber'а (который, кстати, приходит со значением nil). Так и должно быть?
Правильно ли я вообще делаю? Есть идеи?

Добавлено (09.08.2013, 16:16)
---------------------------------------------
Переделал.

           
Код
bmpInfo.bmiHeader.biCompression := BI_RGB; //дописал это
            bmp.Handle := CreateDIBSection(0, pBMPInfo^, DIB_RGB_COLORS, buffer, 0, 0); // теперь тут стал приходить хэндл на битмап.


Код
BufferSize := 0; //убрал это

Стала приходить картинка, вроде этого: http://i49.fastpic.ru/big/2013/0809/6a/4a616e05e89d71ab825daa10594dfb6a.jpg
Кажись, палитра не соответствует. Но как это исправить?

Если убрать это:

           
Код
bmpInfo.bmiHeader.biCompression := BI_RGB;

То приходит пустой чёрный скриншот с размерами (w,h), как у видео.
Такое уже однажды было, но не помню, как я это исправил. Вроде как, пинком по компу smile Но сейчас это не канает.


Сообщение отредактировал BLACK_CRAFTER666 - Суббота, 10.08.2013, 11:00
 
xaramamburuДата: Пятница, 09.08.2013, 20:23 | Сообщение # 2
Полковник
Группа: Администраторы
Сообщений: 240
Репутация: 26
Статус: Offline
Откуда вы такой код взяли? А у меня здесь  http://basicsprog.ucoz.ru/publ/6-1-0-28 смотрели? Код был полностью рабочий, правда для камеры, но я эту функцию function TForm1.CaptureBitmap: HResult; вставлял в видеоплеер, вроде все работало. Ну а с вашим кодом надо пробовать колупаться, а так я вам сказать ничего не смогу. ))))
 
BLACK_CRAFTER666Дата: Суббота, 10.08.2013, 12:07 | Сообщение # 3
Сержант
Группа: Пользователи
Сообщений: 31
Репутация: 0
Статус: Offline
чорт! Я опять забыл прикрепить скриншот Графа smile Вот он: http://i33.fastpic.ru/big/2013/0810/43/1f12989a40129d93978f2fc6a1812343.jpg
Цитата (xaramamburu)
Откуда вы такой код взяли?

Мне его дали тролли с форума ProgrammersForum smile Изначально, он был немного не такой. Я его слегка изменил. Надо признать, код работает. Но только при интеллектуальном построении Графа.
Цитата (xaramamburu)
А у меня здесь http://basicsprog.ucoz.ru/publ/6-1-0-28 смотрели?

Очень странно smile Никогда не замечал, что там речь идет о скриншоте. Хотя, это даже в название статьи вынесено smile
Переписал ваш код своими словами :

Код
function MakeScreenshot(var bmp: TBitmap):Boolean;
var
    BufferSize : Integer;
    vih : TVideoInfoHeader;
    mt : TAMMediaType;
    BMPInfo : TBitmapInfo;
    Buffer : Pointer;
    tmp : array of Byte;
    hr : HRESULT;
    hbmp : HBITMAP;
begin
    Result := False;
    hr := pGrabber.GetCurrentBuffer(BufferSize,nil);
    ZeroMemory(@mt,SizeOf(tammediatype));
    hr := pGrabber.GetConnectedMediaType(mt);
    vih := tvideoinfoheader(mt.pbFormat^);
    ZeroMemory(@bmpinfo,SizeOf(tbitmapinfo));
    CopyMemory(@bmpinfo.bmiheader,@vih.bmiheader,SizeOf(tbitmapinfoheader));
    Buffer := nil;
    hbmp := CreateDIBSection(0,BMPInfo,DIB_RGB_COLORS,Buffer,0,0);
    case hbmp of
      0:
      begin
        MessageBox(form1.Handle,PChar('HBMP = 0'),'',0);
        Exit;
      end;
      ERROR_INVALID_PARAMETER:
      begin
        MessageBox(form1.Handle,PChar('ERROR_INVALID_PARAMETER'),'',0);
        Exit;
      end;
    end;
    bmp.Handle := hbmp;
    SetLength(tmp,BufferSize);
    pGrabber.GetCurrentBuffer(BufferSize,@tmp[0]);
    CopyMemory(Buffer,@tmp[0],mt.lSampleSize);
    SetLength(tmp,0);
    MoFreeMediaType(@mt);
    Result := True;
end;

Действительно, код работает. Однако, только при интеллектуальном построении.
В ходе экспериментов, я заметил следующее:
При интеллектуальном построении Графа, в структуру BMPinfo в ее поле biCompression приходит значение 0, что соответствует константе BI_RGB.
В этом случае, функция CreateDIBSection() выполняется успешно и возвращает хэндл на HBITMAP.
А если строить граф вручную, что я и делаю, то поле biCompression становится равно 844715353, что соответствует константе YUY2_Overlay.
В этом случае, функция CreateDIBSection() возвращает 0 и прога крашится на строчке CopyMemory(Buffer,@tmp[0],mt.lSampleSize);.
Если принудительно выставить:

Код
BMPInfo.bmiHeader.biCompression := BI_RGB;
    hbmp := CreateDIBSection(0,BMPInfo,DIB_RGB_COLORS,Buffer,0,0);

то крашей нет и получается разноцветный скриншот правильного разрешения.
Что думаете? Может надо YUY2 в RGB как-то конвертить или типа того?


Сообщение отредактировал BLACK_CRAFTER666 - Суббота, 10.08.2013, 17:25
 
xaramamburuДата: Суббота, 10.08.2013, 17:58 | Сообщение # 4
Полковник
Группа: Администраторы
Сообщений: 240
Репутация: 26
Статус: Offline
А почему у вас SampleGrabber стоит перед AVI Decompressor, дело в том, что на этот фильтр должно приходить закодированное с помощью кодеков видео, а уже после него видео в формате RGB. Как я понимаю SampleGrabber должен стоять перед VideoRenderer  или NullRenderer если вам ненужен вывод на экран, потому что на VideoRenderer приходит  картинка готовая для вывода на экран. Я даже не удивлюсь, если она окажется в формате BMP, хотя возможно и не так. А вы снимаете с SampleGrabber кодированный кадр, отсюда и красивая цветная крякозябла в место изображения. Да я еще забыл спросить как вы снимаете скриншот? Имеется в виду по кнопке или по таймеру. Там есть еще такой косяк, что если снимать по таймеру, то необходимо использовать Callback функцию, она срабатывает когда SampleGrabber получает кадр иначе вылетают ошибки типа VFW_E_WRONG_STATE.)))))
 
BLACK_CRAFTER666Дата: Суббота, 10.08.2013, 19:58 | Сообщение # 5
Сержант
Группа: Пользователи
Сообщений: 31
Репутация: 0
Статус: Offline
Цитата (xaramamburu)
А почему у вас SampleGrabber стоит перед AVI Decompressor

Я не знаю smile Я собирал этот граф в GraphStudio сам. Я подцепил SampleGrabber к ffdshow, а AVI Decompressor и ColorSpaceConverter сами добавились. Я думал, что так и надо smile
Цитата (xaramamburu)
Как я понимаю SampleGrabber должен стоять перед VideoRenderer или NullRenderer

Source -> ffdshow -> avi decompressor -> color space converter -> Sample grabber -> video renderer. в graphsgtudio так не делается.
Я сделал так. Теперь hr := pGrabber.GetConnectedMediaType(mt); возвращает VFW_E_NOT_CONNECTED, хотя

     
Код
DesiredMT.majortype := MEDIATYPE_Video;
      DesiredMT.subtype := MEDIASUBTYPE_RGB24;
      DesiredMT.formattype := FORMAT_VideoInfo;
      Result := pGrabber.SetMediaType(DesiredMT);
      if Result = s_ok then
      begin
        pGrabber.SetOneShot(False);
        pGrabber.SetBufferSamples(True);
      end;

тут равно s_ok.
Пробовал брать MediaType из Color Space Converter'а - то же самое.
Цитата (xaramamburu)
Да я еще забыл спросить как вы снимаете скриншот?

По кнопке. По таймеру не планирую. В плеере это не надо smile


Сообщение отредактировал BLACK_CRAFTER666 - Суббота, 10.08.2013, 20:08
 
xaramamburuДата: Суббота, 10.08.2013, 20:29 | Сообщение # 6
Полковник
Группа: Администраторы
Сообщений: 240
Репутация: 26
Статус: Offline
Я имел ввиду так:
Source -> ffdshow -> avi decompressor ->Sample grabber  -> color space converter -> video renderer.
В GraphStudio соединяется без проблем.)))
 
BLACK_CRAFTER666Дата: Воскресенье, 11.08.2013, 11:06 | Сообщение # 7
Сержант
Группа: Пользователи
Сообщений: 31
Репутация: 0
Статус: Offline
Цитата (xaramamburu)
Source -> ffdshow -> avi decompressor ->Sample grabber -> color space converter -> video renderer.


hands respect мегареспект!!!!!!!!!!!!!!
Теперь тырит скриншоты из всех видосов! Это даже Light Alloy, почему-то, разучился это делать smile Хотя, вроде, плеер не из последних.
Подцепил ветку аудио-фильтров. Даже звук есть smile Не думал, что всё так просто smile Были бы, только, нормальные FAQ'и, вроде ваших статей book
p.s. Еще бы скринлист научиться делать и было бы вообще ништяк smile Полагаю, надо создать большой пустой битмап (размером около 1000х1000) и накладывать на него уменьшенные скриншоты. Но пока это дело десятое.
 
xaramamburuДата: Воскресенье, 11.08.2013, 19:33 | Сообщение # 8
Полковник
Группа: Администраторы
Сообщений: 240
Репутация: 26
Статус: Offline
Цитата
мегареспект!!!!!!!!!!!!!!
 
Ну помог чем мог.)))

Цитата
Были бы, только, нормальные FAQ'и, вроде ваших статей

К сожалению не все так лестно отзываются о моих статьях. Многие великие гуру с других форумов считают их копипастом. Хотя я и не спорю, что материал брал в интернете и из разных книг, но не целиком статьи, а определенные фрагменты кода, которые переделывал под свои задачи и старался его максимально прокомментировать, чтоб было понятно не только гуру но и простым смертным.

Цитата
Еще бы скринлист научиться делать и было бы вообще ништяк. Полагаю, надо создать большой пустой битмап (размером около 1000х1000) и накладывать на него уменьшенные скриншоты.

Ну ширину битмап можно предложить задать пользователю, а затем в зависимости от количества скриншотов вычислять их размер и высоту битмап.)))
 
BLACK_CRAFTER666Дата: Понедельник, 12.08.2013, 14:41 | Сообщение # 9
Сержант
Группа: Пользователи
Сообщений: 31
Репутация: 0
Статус: Offline
Цитата (xaramamburu)
К сожалению не все так лестно отзываются о моих статьях. Многие великие гуру с других форумов считают их копипастом.

Статьи нормальные. Для начальной стадии разработки очень полезно (кстати, у вас там есть пара мелких косяков). Единственное, чего очень не хватает это отдельных статей про функцию RenderStream() и добавление ключевых фильтров, про GraphStudio и Pin'ы. Без этого многие файлы просто не открываются и люди считают, что описанный способ не правильный. Может быть, когда время будет, напишу что-нибудь. По-идее, всё уже написано в темах. Надо только сделать в виде статьи и прокомментировать. Сейчас работаю над статьёй про WinAPI (я про нее не забыл) smile
Цитата (xaramamburu)
Ну ширину битмап можно предложить задать пользователю, а затем в зависимости от количества скриншотов вычислять их размер и высоту битмап.)))

Да-да. Я имел ввиду именно это))
 
xaramamburuДата: Понедельник, 12.08.2013, 20:15 | Сообщение # 10
Полковник
Группа: Администраторы
Сообщений: 240
Репутация: 26
Статус: Offline
Косяков там хватает, но переделывать статьи уже нет смысла. Если хотите что то исправить или добавить, пишите в комментариях, для других будет полезно, да и я не против посмотреть на чужие идеи и что то новое. Многие кстати так и делают, если вы читали комментарии. Дело в том, что я когда начал писать видеоплеер, то понятия не имел, что такое DirectShow и когда у  меня пошло воспроизведение первого фильма  это было круто, появилось желание добавить перемотку, плейлист, время и т.д. И уже в течении недели все это было реализовано и я решил поделится эти в интернете и написал статью про создание простого видеоплеера. Но после того как народ начал делать плеер по этой статье начались первые проблемы:
1. Оказалось не все форматы видео воспроизводятся, причем один и тоже файл на одном компе работает нормально, а на другом напрочь отказывается воспроизводится.
2. Существует видео с несколькими аудио каналами, возник вопрос как их переключать.
3. И т.д.
Понятно, что если бы я сейчас писал это видеоплеер, то постарался бы решить эти проблемы с учетом информации, которая была получена за это время, но это уже другая история.))))
Цитата
Единственное, чего очень не хватает это отдельных статей про функцию RenderStream() и добавление ключевых фильтров, про GraphStudio и Pin'ы.

По функции RenderStream() информации в интернете достаточно, но вот как применять ее в комплексе с различными фильтрами, с указанием PIN_CATEGORY, MEDIATYPE, использовать построение по частям, добавление фильтров к сожалению очень мало, может конечно я плохо искал. Очень много можно взять информации с сайта http://directshow.wonderu.com в разделе статьи. А про построение через Pin'ы, я уже вам писал, что особо так и не разобрался. Если вы разобрались, то можете выложить какой нибудь примерчик, либо на форуме или написать небольшую статью, на примере построения заданной цепочки графа фильтров. Я думаю будет всем полезно.)))
 
BLACK_CRAFTER666Дата: Воскресенье, 18.08.2013, 14:55 | Сообщение # 11
Сержант
Группа: Пользователи
Сообщений: 31
Репутация: 0
Статус: Offline
Цитата (xaramamburu)
да и я не против посмотреть на чужие идеи и что то новое.

Сейчас в корне переписываю процедуру построения Графа. Там будет, на что посмотреть smile
Цитата (xaramamburu)
Дело в том, что я когда начал писать видеоплеер, то понятия не имел, что такое DirectShow и когда у меня пошло воспроизведение первого фильма это было круто,

Та же фигня smile
Цитата (xaramamburu)
2. Существует видео с несколькими аудио каналами, возник вопрос как их переключать.

Тоже интересует. Видел скриншот Графа, где в цепочку аудио добавлен какой-то "audio switcher". Еще не пробовал, но должно получиться.
Цитата (xaramamburu)
Понятно, что если бы я сейчас писал это видеоплеер, то постарался бы решить эти проблемы с учетом информации, которая была получена за это время, но это уже другая история.))))

Я уже это делаю smile
Цитата (xaramamburu)
А про построение через Pin'ы, я уже вам писал, что особо так и не разобрался. Если вы разобрались, то можете выложить какой нибудь примерчик, либо на форуме или написать небольшую статью, на примере построения заданной цепочки графа фильтров. Я думаю будет всем полезно.)))

Однако, научить меня у вас получилось smile
С Pin'ами всё довольно просто. Надо только понять, что это такое. Проблема в том, что в интернете об этом нет практически никакой "нубской" документации, а разобраться самому довольно затруднительно. Статью про Pin'ы я планирую написать, но позже.
Единственное, что осталось загадкой, это определение FourCC до подключения декодера. GraphStudio и MediaInfo как-то же это делают.
 
xaramamburuДата: Воскресенье, 18.08.2013, 17:56 | Сообщение # 12
Полковник
Группа: Администраторы
Сообщений: 240
Репутация: 26
Статус: Offline
Цитата
Однако, научить меня у вас получилось.

Ну, я только направление для поиска давал.)))

Цитата

Статью про Pin'ы я планирую написать, но позже.

Жду.

Цитата
Единственное, что осталось загадкой, это определение FourCC до подключения декодера.

Это можно сделать с помощью пакета DsPack, пример отправил вам на почту. Возможно поможет.)))
 
Форум » Delphi » DirectShow и Delphi. » SampleGrabber - пустой скриншот (нулевой размер файла)
  • Страница 1 из 1
  • 1
Поиск:


Copyright MyCorp © 2024Конструктор сайтов - uCoz