Re: [DirectShow] Произвольный доступ к кадру AVI
От: Аноним  
Дата: 24.05.12 16:56
Оценка:
Здравствуйте, VAstronom, Вы писали:

Нужно использовать SampleGrabber фильтр. В нем изображение еще не ушло в видео память и потому более быстро доступно через интерфейс IMediaSample. Либо можно написать свой фильтр который будет делать то что надо, благо примеров в СДК полно.

VA>Стоит задача анализа содержимого видео файла. Я больше инженер, чем программист, но пришлось разбираться с DirectShow, поэтому сильно не

VA>пинайте… Использую Builder6.

VA>Необходимо последовательно (иногда пропуская) сменять кадры, затем извлекать их содержимое для анализа. Соответственно на экране

VA>исходный кадр отображаться не должен, т.к. там будет измененная картинка.
VA>Для перехода к кадру использую связку
VA> pMediaSeeking->SetPositions(&Nf,AM_SEEKING_AbsolutePositioning,NULL,AM_SEEKING_NoPositioning);
VA> pBasicVideo->GetCurrentImage(&lBufSize,(long*)pDIB);
VA>но GetCurrentImage жутко тормозит и на получение одного кадра уходит пол секунды времени!

VA>Подскажите пожалуйста, как можно повысить быстродействие?


VA>Выкладываю весь блок кода, возможно ошибка в самом подходе к решению задачи?


VA>
VA>#include <vcl.h>
VA>#include <dshow.h>

VA>#include "Unit1.h"
VA>#include "c_DirectShow.h"                 // объявления функций ниже

VA>#pragma comment (lib, "strmiids.lib")                                           // IVideoFrameStep

VA>//------------------------------------------------------------------------------//
VA>HRESULT         hr;

VA>IGraphBuilder   *pGraphBuilder;
VA>IBasicVideo     *pBasicVideo;
VA>IMediaSeeking   *pMediaSeeking;
VA>//IVideoWindow    *pVideoWindow;

VA>BYTE *pDIB;                                                                     // попиксельный массив видео кадра с заголовком.

VA>extern Graphics::TBitmap *mFRAME;                                               // моя результирующая картинка
VA>//==============================================================================//


VA>//------------------------------------------------------------------------------//
VA>// Инициализация и построение постоянных графов.                                //
VA>//------------------------------------------------------------------------------//
VA>int OpenDirShow()
VA>{
VA>    pGraphBuilder = NULL;                                                       // Интерфейс менеджера графа-фильтров
VA>    pBasicVideo   = NULL;
VA>    pMediaSeeking = NULL;

VA>    //--------------------------------------------------------------------------
VA>    hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);                        // Инициализируем библиотеку COM
VA>    if(FAILED(hr)) return 1;

VA>    hr = CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER,        // Создание менеджера графа-фильтров
VA>                          IID_IGraphBuilder, (void **)&pGraphBuilder);
VA>    if(FAILED(hr)) return 2;

VA>    hr = pGraphBuilder->QueryInterface(IID_IBasicVideo,(void**)&pBasicVideo);
VA>    if(FAILED(hr)) return 3;

VA>    hr = pGraphBuilder->QueryInterface(IID_IMediaSeeking,(void**)&pMediaSeeking);
VA>    if(FAILED(hr)) return 4;

VA>    //--------------------------------------------------------------------------
VA>    return 0;
VA>}

VA>//------------------------------------------------------------------------------//
VA>// освобождение ресурсов.                                                       //
VA>//------------------------------------------------------------------------------//
VA>void CloseDirShow()
VA>{
VA>    if(pMediaSeeking)   pMediaSeeking->Release();
VA>    if(pBasicVideo)     pBasicVideo->Release();
VA>    if(pGraphBuilder)   pGraphBuilder->Release();

VA>    CoUninitialize();
VA>}

VA>//------------------------------------------------------------------------------//
VA>// Открываем видео файл (Для  Unicode)                                          //
VA>// Для не Unicode hr = pGraph->RenderFile((LPCWSTR)pcFileName, NULL);           //
VA>//------------------------------------------------------------------------------//
VA>// Получает:                                                                    //
VA>//  - имя файла                                                                 //
VA>// Возвращает:                                                                  //
VA>//  - количество кадров                                                         //
VA>//  - размер кадра                                                              //
VA>//------------------------------------------------------------------------------//
VA>int OpenAVI(char *pcFileName, __int64 *Lframe, long *Xframe, long *Yframe)
VA>{
VA>  const GUID TIME_FORMAT_FRAME = { 0x7b785570, 0x8c82, 0x11cf, { 0xbc, 0xc, 0x0, 0xaa, 0x0, 0xac, 0x74, 0xf6}};

VA>  __int64 Nframe;
VA>  WCHAR wFileName[MAX_PATH];

VA>  MultiByteToWideChar(CP_ACP, 0, pcFileName, -1, wFileName, MAX_PATH);          // строку преобразую в Юникод

VA>  hr = pGraphBuilder->RenderFile((LPCWSTR)wFileName, NULL);                     // открываю файл
VA>  if(FAILED(hr)) return 1;

VA>  pMediaSeeking->SetTimeFormat(&TIME_FORMAT_FRAME);                             // формат "кадры"

VA>  pMediaSeeking->GetDuration(Lframe);                                           // количество кадров
VA>  pBasicVideo->GetVideoSize(Xframe,Yframe);                                     // размер кадра

VA>//  hr = pGraphBuilder->QueryInterface(IID_IVideoWindow, (void**)&pVideoWindow);  // параметры отображения (где и как)?
VA>//  if(FAILED(hr)) return 2;

VA>  ChgFrame(1, *Lframe, *Xframe, *Yframe);                                       // отобразили кадр

VA>  return 0;
VA>}

VA>//------------------------------------------------------------------------------//
VA>// При закрытии видео файла освобождаем память занятую под кадр                 //
VA>//------------------------------------------------------------------------------//
VA>void CloseAVI()
VA>{
VA> // if(pVideoWindow) pVideoWindow->Release();

VA>  delete [] pDIB;
VA>}

VA>//------------------------------------------------------------------------------//
VA>// Произвольный доступ к заданному кадру. Рисует этот кадр на Form1->Image1     //
VA>// Получает:                                                                    //
VA>//  - признак инициализации (1 - при открытии файла) или работы (0)             //
VA>//  - номер кадра для показа                                                    //
VA>//  - размер кадра                                                              //
VA>//------------------------------------------------------------------------------//
VA>void ChgFrame(bool init, __int64 Nf, long Xf, long Yf)
VA>{
VA>  TDateTime TTT0,TTT1;
VA>  AnsiString As[4];

VA>  static long              lBufSize;                                            // размер данных кадра (шапка + данные)
VA>  static HDC               wrkDC;
VA>  static BITMAPINFOHEADER *bmih;
VA>  static BITMAPINFO        bmi;
VA>  static HBITMAP           hbmp;
VA>  static char             *pData;


VA>  TTT0=Time();
VA>                                                                                // переход к указному кадру
VA>  pMediaSeeking->SetPositions(&Nf,AM_SEEKING_AbsolutePositioning,NULL,AM_SEEKING_NoPositioning);
VA>//  pVideoFrameStep->Step(Nf, NULL);

VA>  if (init==1)                                                                  // при инициализации
VA>  {
VA>     wrkDC = GetDC(0);                                                          // ...\dx9sdk\Samples\C++\DirectShow\Editing\TransViewer
VA>     //wrkDC = CreateCompatibleDC(NULL);

VA>     pBasicVideo->GetCurrentImage(&lBufSize,NULL);                              // определяем размер памяти под кадр
VA>     pDIB=new BYTE[lBufSize];                                                   // резерв памяти под кадр

VA>     mFRAME->PixelFormat = pf24bit;
VA>     mFRAME->Width =Xf;
VA>     mFRAME->Height=Yf;
VA>  }
VA>  //----------------------------------------------------------------------------

VA>  TTT1=Time();
VA>  DateTimeToString(As[0], "ss.zzzz", TTT1-TTT0);

VA>  pBasicVideo->GetCurrentImage(&lBufSize,(long*)pDIB);                          // получаю данные кадра

VA>  TTT0=Time();
VA>  DateTimeToString(As[1], "ss.zzzz", TTT0-TTT1);

VA>  pData = (char*)(int)pDIB+sizeof(BITMAPINFOHEADER);                            // адрес первого пикселя

VA>  TTT1=Time();
VA>  DateTimeToString(As[2], "ss.zzzz", TTT1-TTT0);

VA>  bmih  = (BITMAPINFOHEADER*)pDIB;                                              // махинации для дальнейшей конвертации изображения
VA>  ZeroMemory(&bmi, sizeof(BITMAPINFO));
VA>  CopyMemory(&(bmi.bmiHeader), bmih, sizeof(BITMAPINFOHEADER));

VA>  hbmp=CreateDIBitmap(wrkDC,bmih,CBM_INIT,pDIB,(PBITMAPINFO)&bmi,DIB_RGB_COLORS);
VA>  mFRAME->Handle=hbmp;

VA>  TTT0=Time();
VA>  DateTimeToString(As[3], "ss.zzzz", TTT0-TTT1);

VA>  Form1->Caption="Frame "+IntToStr(Nf)+" "+As[0]+" "+As[1]+" "+As[2]+" "+As[3];
VA>  Form1->Image1->Canvas->Draw(0,0, mFRAME);                                     // отрисовка картинки.
VA>  Form1->Image1->Refresh();
VA>}
VA>
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.