Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?
Гродненский Форум
24 Апрель 2024, 19:12:20
Новости, реклама:
   Главная   Новости Гродно Помощь Игры Календарь Войти Регистрация   Меню
Гродненский Форум > Компьютеры > Программирование
(Модераторы: Админ, barmalei) > Тема:

Видеозахват, DirectShow

Страниц  :   Вниз
  Печать  
Автор Тема: Видеозахват, DirectShow  (Прочитано 3582 раз)
0 Пользователей и 1 Гость смотрят эту тему.
Старый Волк
Гость
« : 01 Март 2012, 16:35:18 »

Доброго дня всем.

Имеется у меня ОГРОМНАЯ просьба к коллегам-программерам или просто хорошим (но талантливым в программировании) человекам Улыбка.

У меня БОЛЬШАЯ проблема с программированием видеокамеры, то есть с видеозахватом кадров с последующим сохранением. Вот уже больше года, как бьюсь. Это не смешно уже стало. Дело в том, что с веб-камерой, задача моментально решилась средствами DirectShow, в частности набор DSPack все замечательно зделал. И качество фоток прекрасное. Но у начальства (не непосредственного, а то что выше) лбы дубовые, а мозги толоконные или вообще высохли. И приобрели они вероятно по очень хорошей цене (полагаю 8-ми значная сумма там в BLR, а может просто им подарили...) кучу металлома под гордым названием "фотостанция". Это собственно комп Celeron 300/RAM, 256Mb (чудо современной техники, что в нем хорошего, то это его вес - вместе с 17" ЭЛТ (!) монитором потянет на килограмм 40), но с достаточно дорогой видеокартой и цифровой аналоговой камерой. Симпатичный глаз такой на штативе, с кейпадом, для управления поворотами. Изображение с нее хуже чем с вебки, но вид у нее видите ли солиднее... Нет слов. Но дело надо зделать, вопрос чести. Я все перепробовал, где понятие хоть какое-то имею. В том числе и напрямую через "AVICAP32.DLL" и через DirectShow.pas напрямую используя определенные там интерфейсы. Не идет окаянная...
Считаю, проблема или с правильным построением графа фильтров, либо с контакты (IPin) нужно в ручную как-то коннектить или другие фильтры использовать. Но последние варианты (IPin или не стандартные фильтры), мне не доступен - нет понятия о принципе и отсутствие опыта работы с устройствами. А может возраст уже...
У меня же пока получается лишь "телевизор без антены" или вообще ничего на видеоконтроле или error типа "деление на нуль"/"контакты не присоединены".
Камера что используется CNB DSP 220x (CNB Digital Signal Procesor). Карта видеозахвата - ATI Radeon 9000 Pro All-in-Wonder. Название устройства видеозахвата - ATI Rage Theater Video Capture.
Я догадываюсь, что нужно как-то через WDM-драйвер напрямую инициализировать камеру или карту, а далее работать средствами DirectShow. Но как это зделать? Далее я приведу три куска кода - больше ничего путного не наработал и не нашел нигде. У всех либо "все идет", либо ехидно ёрничают - по типу сами такие великие программеры, что разработали все интерфейсы и методы, а на деле же выдрали где-то из инета или "знакомые" подсказали.
В общем признателен буду за помощь. Мне достоверно известно, что есть умники в Минске где-то, что смогли зделать эту камеры, правда в CBuilder (я в Delphi работаю), но не играет роли - можно и в CBuilder. Если кто знает, как, но не хочет даром отдавать - могу заплатить. Из своего кармана естественно и это не жертва организации (пусть горит она синим пламенем), а нужно мне лично.

Вот мои (основные) наработки.

1. С ручной записью параметров видеорежима.

Код:
procedure TfrmDxMedia.RunCapture;
var
  m_VideoType: PAMMediaType;
  hr: HResult;
  StreamConfig: IAMStreamConfig;
begin
 try
   StreamConfig := NIL;
   m_VideoType := nil;

   FilterGraph.ClearGraph();
   FilterGraph.Active := False;
   StrDev := TStringList.Create();
   SysDev:= TSysDevEnum.Create(CLSID_VideoInputDeviceCategory);

   Filter.BaseFilter.Moniker := SysDev.GetMoniker(0); //устройство все равно единственное

   Filter.FilterGraph := FilterGraph();
   FilterGraph.Active := True;

   with FilterGraph as ICaptureGraphBuilder2 do begin
     hr := FindInterface(@PIN_CATEGORY_CAPTURE,
                         @MEDIATYPE_Video,
                         Filter as IBaseFilter,
                         IID_IAMStreamConfig, StreamConfig);
   end;

   if SUCCEEDED(hr) then begin
     StreamConfig.GetFormat(m_VideoType);
     PVideoInfoHeader(m_VideoType.pbFormat)^.bmiHeader.biWidth    := 320; //Это основной
     PVideoInfoHeader(m_VideoType.pbFormat)^.bmiHeader.biHeight   := 240; //видеорежим
     PVideoInfoHeader(m_VideoType.pbFormat)^.bmiHeader.biBitCount := 16;  //камеры CNB DSP 220x
//     PVideoInfoHeader(m_VideoType.pbFormat)^.AvgTimePerFrame:= 10000000 div 25; //25 fps - нет смысла

     with PVideoInfoHeader(m_VideoType.pbFormat)^.bmiHeader do
       m_VideoType.lSampleSize := biWidth * biHeight * biBitCount;

     PVideoInfoHeader(m_VideoType.pbFormat)^.bmiHeader.biSizeImage :=
                                 m_VideoType.lSampleSize;
     m_VideoType.subtype := MEDIASUBTYPE_UYVY; //такой тип данных у этой камеры

   end;
   SampleGrabber.MediaType.InitMediaType();
   SampleGrabber.MediaType.AMMediaType.majortype := m_VideoType.majortype;
   SampleGrabber.MediaType.AMMediaType.subtype   := m_VideoType.subtype;
   SampleGrabber.MediaType.AMMediaType.bFixedSizeSamples := m_VideoType.bFixedSizeSamples;
   SampleGrabber.MediaType.AMMediaType.bTemporalCompression := m_VideoType.bTemporalCompression;
   SampleGrabber.MediaType.AMMediaType.lSampleSize := m_VideoType.lSampleSize;
   SampleGrabber.MediaType.AMMediaType.formattype := m_VideoType.formattype;
   SampleGrabber.MediaType.AMMediaType.pUnk := m_VideoType.pUnk;
   SampleGrabber.MediaType.AMMediaType.cbFormat := m_VideoType.cbFormat;
   SampleGrabber.MediaType.AMMediaType.pbFormat := m_VideoType.pbFormat;
   SampleGrabber.UpdateMediaType(); //пробую обновить тип медиаданных - без этого все тоже.

//   ShowMessage(intTostr((PVideoInfoHeader(SampleGrabber.MediaType.AMMediaType.pbFormat)^.bmiHeader.biWidth)));
//    - 320 пикселей как и записывали.
//   ShowMessage(intTostr(SizeOf(SampleGrabber.MediaType.AMMediaType^))); - 72 байта

   m_VideoType := nil;
   StreamConfig := nil;

   with FilterGraph as ICaptureGraphBuilder2 do begin
     //пробовалось - @PIN_CATEGORY_PREVIEW - на вэбкамере идет, на CNB нет вообще ничего
     //даже "шипения" на медиаконтроле
     RenderStream(nil{@PIN_CATEGORY_CAPTURE}, @MEDIATYPE_Video, //nil,
                  Filter as IBaseFilter,
                  SampleGrabber as IBaseFilter,
                  VideoWindow as IbaseFilter);
   end;
   FilterGraph.Play();
 except
 {}
 end;
end;


2. С записью видеорежима передаваемого как параметр (номер по itemindex c combobox'a).

Код:
procedure TfrmDxMedia.RunCapture(iMode: integer);
var
  PinList: TPinList;
begin
 try
  FilterGraph.Active := true;
  if Filter.FilterGraph <> nil then begin
    PinList := TPinList.Create(Filter as IBaseFilter);
    with (PinList.First as IAMStreamConfig) do
        SetFormat(CVideoMediaTypes.Items[iMode].AMMediaType^); //формат видеоданных
    PinList.Free();
  end;
  with FilterGraph as IcaptureGraphBuilder2 do begin
  //закоментироаны варианты - эксперименты - все без толку.
{    if Filter.BaseFilter.DataLength > 0 then
      RenderStream(@PIN_CATEGORY_PREVIEW, nil, Filter as IBaseFilter,
        nil , VideoWindow as IBaseFilter);}

{    if Filter.BaseFilter.DataLength > 0 then
      RenderStream(@PIN_CATEGORY_CAPTURE, nil, Filter as IBaseFilter,
        nil , VideoWindow as IBaseFilter);}

{    if Filter.BaseFilter.DataLength > 0 then
      RenderStream(nil, nil, Filter as IBaseFilter,
        nil , VideoWindow as IBaseFilter);}

    if Filter.BaseFilter.DataLength > 0 then begin
      RenderStream(nil, @MEDIATYPE_Video, Filter as IBaseFilter,
                   SampleGrabber as IBaseFilter, VideoWindow as IbaseFilter);
    end;
  end;
  FilterGraph.Play();
 except

 end;
end;

3. Найденный мной вариант в сети. Пишут, что именно для ATI Rage Theater Video Capture. Но это у них все ok, а не у меня.

Код:
procedure TfrmDxMedia.RunCapture(iMode: integer);
var
  PinList: TPinList;
  CamPrev: IPin;
  hr: HResult;
  NullRenderer: IBaseFilter;
begin
 try
  if not FilterGraph.Active then FilterGraph.Active := true;
  if Filter.FilterGraph <> nil then begin
    PinList := TPinList.Create(Filter as IBaseFilter);
    with (PinList.First as IAMStreamConfig) do
        SetFormat(CVideoMediaTypes.Items[iMode].AMMediaType^);
    PinList.Free();
  end;

  with FilterGraph as ICaptureGraphBuilder2 do begin
    hr := FindPin(Filter as IBaseFilter, PINDIR_OUTPUT,
                  @PIN_CATEGORY_VIDEOPORT, nil, True, 0, CamPrev );
    if ( hr = S_OK ) then begin
      RenderStream(nil, nil, CamPrev, nil, VideoWindow as IBaseFilter);
      Renderstream(nil, nil, Filter as IBaseFilter,
                   SampleGrabber as IBaseFilter, NullRenderer as IBaseFilter);
    //пробовал и так эту строчку:
    //SampleGrabber as IBaseFilter, VideoWindow as IBaseFilter);
    //и так:
    //SampleGrabber as IBaseFilter, nil);
    // и даже так: nil, nil); 
    end else begin // just a std preview pin
      RenderStream(@PIN_CATEGORY_PREVIEW, nil, Filter as IBaseFilter,
                   SampleGrabber as IBaseFilter, VideoWindow as IBaseFilter);
    end;
    CamPrev:= nil;
  end;
  FilterGraph.Play();
 except

 end

end;

Это все что есть у меня. Остальное вариации на эти же темы. DotNet (С#, VB) не пойдет - железо (вот уже где правильное название для этой так называемой "станции") слабое. Но камера 100% рабочая, ибо есть демка на CBuilder (от тех умников из Минска). Но код разумеется зажали - ноу-хау, понимаете ли...
Все три варианта на У-РА идут с вебки, но с DSP все они = 0.
« Последнее редактирование: 02 Март 2012, 13:56:57 от Старый Волк » Записан
Старый Волк
Гость
« Ответ #1 : 05 Апрель 2012, 14:33:18 »

Тему можно закрывать. Проблема решена. Перерыв кучу интернет ссылок нашел прогу на C# для TVTuner и переделал ее под камеру, попутно переводя ее в Delphi.
Также помог Есенин С.А. (Не тот что поэтом был, а другой, автор книги "DirectX и Delphi. Разработка графических и мультимедийных приложений").
В общем вот решение проблемы - вдруг кому пригодится.

Код:
function BuildOfGraph: HResult;
begin
  ResetGraph();
  // Создаем объект для построения графа фильтров
  Result := CoCreateInstance(CLSID_FilterGraph,
                             NIL,
                             CLSCTX_INPROC_SERVER,
                             IID_IGraphBuilder,
                             FGraphBuilder);
  if FAILED(Result) then EXIT;
  // Создаем объект для построения графа захвата
  Result := CoCreateInstance(CLSID_CaptureGraphBuilder2,
                             NIL,
                             CLSCTX_INPROC_SERVER,
                             IID_ICaptureGraphBuilder2,
                             FCaptureGraphBuilder);
  if FAILED(Result) then EXIT;
  // Задаем граф фильтров для использования в построении графа захвата
  Result := FCaptureGraphBuilder.SetFiltergraph(FGraphBuilder);
  if FAILED(Result) then EXIT;
  // Получение устройтва захвата видео
  FVideoCaptureFilter := EnumerateDevices(CLSID_VideoInputDeviceCategory, VideoCaptureDeviceName, NIL, TRUE);
  if FVideoCaptureFilter <> NIL then  begin
      FGraphBuilder.AddFilter(FVideoCaptureFilter, 'VideoCaptureFilter');
      Result := FCaptureGraphBuilder.RenderStream(@PIN_CATEGORY_PREVIEW, @MEDIATYPE_Video, FVideoCaptureFilter, NIL, nil);
      if FAILED(Result) then EXIT;
      SetParamAndRouteCrossBar();
      if FVideoHandle > 0 then  begin
        FGraphBuilder.QueryInterface(IID_IVideoWindow, FVideoWindow);
        if FVideoWindow <> NIL then begin
          FVideoWindow.put_WindowStyle(WS_CHILD or WS_CLIPSIBLINGS);
          FVideoWindow.put_Owner(FVideoHandle);
          FVideoWindow.SetWindowPosition(FVideoRect.Left, FVideoRect.Top,
                                         FVideoRect.Right - FVideoRect.Left,
                                         FVideoRect.Bottom - FVideoRect.Top);
          FVideoWindow.put_Visible(TRUE);
        end;
      end;
  end;
  if FPlayed then begin
    // Запрашиваем интерфейс управления графом
    Result := FGraphBuilder.QueryInterface(IID_IMediaControl, FMediaControl);
    if FAILED(Result) then EXIT;
    // Запускаем граф
    Result := FMediaControl.Run();
  end;
end;

Основная проблема решается здесь посредством функции:

Код:
function SetParamAndRouteCrossBar(PAL_MODE: bool = true): bool;
var
   hr:  HRESULT;
   i: integer;
   pct: TPhysicalConnectorType;
   CrossBar: IUnknown;
   numOutPin, numInPin: Integer;
   nOutputVideoLink : integer;
   nInputVideoLink  : integer;
   pIdxRel : integer;
   AnalogVideoDecoder: IUnknown;
begin
    hr := FCaptureGraphBuilder.FindInterface(nil, nil, FVideoCaptureFilter, IID_IAMCrossbar, CrossBar);
    if (hr >= 0) then begin
        nOutputVideoLink := -1;
        nInputVideoLink  := -1;
        (CrossBar as IAMCrossbar).get_PinCounts(numOutPin, numInPin);
        for i := 0 to numInPin do begin
            (CrossBar as IAMCrossbar).get_CrossbarPinInfo(true, i, pIdxRel, pct);
            if (pct = PhysConn_Video_Composite) then nInputVideoLink := i;
            if (nInputVideoLink <> -1) then break;
        end;
        for i := 0 to numOutPin do begin
            (CrossBar as IAMCrossbar).get_CrossbarPinInfo(false, i, pIdxRel, pct);
            if (pct = PhysConn_Video_VideoDecoder) then nOutputVideoLink := i;
            if (nOutputVideoLink <> 1) then break;
        end;
        try
           if ((CrossBar as IAMCrossbar).Route(nOutputVideoLink, nInputVideoLink) >= 0) then result := true else result := false;
        except
           result := false;
        end
    end;
    if PAL_MODE then begin
      hr := FCaptureGraphBuilder.FindInterface(nil, nil, FVideoCaptureFilter, IID_IAMAnalogVideoDecoder, AnalogVideoDecoder);
      if hr >= 0 then begin
         if (AnalogVideoDecoder as IAMAnalogVideoDecoder).put_TVFormat(AnalogVideo_PAL_B) >= 0 then result := true else result := false;
      end else result := false;
    end;
    CrossBar := nil;
    AnalogVideoDecoder := nil;
end;

P.S. У меня просто камера выдает сигнал стандарта PAL - потому и параметр мне потребовался. Если стандарт NTSC то нужно будет предавать PAL_MODE = false.

Записан
Страниц  :   Вверх
  Печать  
 
Перейти в:  

Войти
Войдите, чтобы добавить комментарий

Войдите через социальную сеть

Имя пользователя:
Пароль:
Продолжительность сессии (в минутах):
Запомнить:
Забыли пароль?

Контакт
Powered by MySQL Powered by PHP Мобильная версия
Powered by SMF 1.1.20
SMF © 2006-2024, Simple Machines
Simple Audio Video Embedder
| Sitemap
Valid XHTML 1.0! Valid CSS!
Страница сгенерирована за 0,177 секунд. Запросов: 17.