Re[4]: [DirectShow] Произвольный доступ к кадру AVI
От: D. Mon Великобритания http://thedeemon.livejournal.com
Дата: 29.05.12 12:08
Оценка: 2 (1)
Нужно построить цепочку
source file -> AVI Splitter -> Decoder -> Sample Grabber -> Null Renderer

OneShot не надо true, включаем в граббере буферизацию сэмплов, переводим граф в состояние паузы, делаем seek на нужную позицию, берем сохраненный в граббере кадр.

Вручную все добавлять необязательно. Можно добавить File Source Async, сказать ему открыть нужный файл, затем добавить сэмпл граббер и сказать ему в каком формате принимать данные (например, RGB24 или RGB32 или YV12), затем через RenderStream соединяем эти два фильтра, промежуточные добавятся сами.
[DirectShow] Произвольный доступ к кадру AVI
От: VAstronom  
Дата: 24.05.12 16:10
Оценка:
Стоит задача анализа содержимого видео файла. Я больше инженер, чем программист, но пришлось разбираться с DirectShow, поэтому сильно не
пинайте… Использую Builder6.

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

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

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

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

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

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

//------------------------------------------------------------------------------//
HRESULT         hr;

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

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

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


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

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

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

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

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

    //--------------------------------------------------------------------------
    return 0;
}

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

    CoUninitialize();
}

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

  __int64 Nframe;
  WCHAR wFileName[MAX_PATH];

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

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

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

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

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

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

  return 0;
}

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

  delete [] pDIB;
}

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

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


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

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

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

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

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

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

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

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

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

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

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

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

  Form1->Caption="Frame "+IntToStr(Nf)+" "+As[0]+" "+As[1]+" "+As[2]+" "+As[3];
  Form1->Image1->Canvas->Draw(0,0, mFRAME);                                     // отрисовка картинки.
  Form1->Image1->Refresh();
}
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>
Re[2]: [DirectShow] Произвольный доступ к кадру AVI
От: VAstronom  
Дата: 25.05.12 06:08
Оценка:
А>Нужно использовать SampleGrabber фильтр. В нем изображение еще не ушло в видео память и потому более быстро доступно через интерфейс IMediaSample. Либо можно написать свой фильтр который будет делать то что надо, благо примеров в СДК полно.

SampleGrabber, IMediaSample?
Спасибо, поковыряю...
Re[3]: [DirectShow] Произвольный доступ к кадру AVI
От: VAstronom  
Дата: 29.05.12 11:38
Оценка:
Ну не выходит, каменный цветок…
Если снять в коде комментарий с «НульРендер», это все вообще не работает.
Как советует MSDN, объявил SampleGrabber
задал
hr = pGrabber->SetOneShot(TRUE);
hr = pGrabber->SetBufferSamples(TRUE);
однако
pGrabber->GetCurrentBuffer( &lBufSize,NULL);
данных не получает.

hr = pControl->Run();
hr = pEvent->WaitForCompletion(INFINITE, &evCode);
менять кадры толком не хочет.
Фактически, своими силами так ничего и не добился.

В ГрафЕдит формируется такая схема
Avi_file -> AVI Splitter -> SampleGpabber->LAV Video Decoder -> VideoRender
Причем AVI Splitter и LAV Video Decoder подключаются без меня.
Может быть, код не работает т.к. я сам подключение пинов не делаю и SampleGpabber «в автомате» получается перед декомпрессией потока? Соответственно буфер пуст…
Допустим, подключение AVI Splitter в исходниках встречается, но как задать этот «LAV Video Decoder»? И нужно ли их вообще задавать в ручную?

Очень раздражает, что примеры из Dxsdk вроде как есть, а в С++ Builder их толком не перетянешь. Компилятор ругается на чего-то в черт знает каком заголовочном файле, не говоря уж о том, что он не понимает функции в самом примере. Может я не те либы ему подсунул? Брал отсюда:
http://clootie.narod.ru/cbuilder/index.html#DX_CBuilder_Libs_90 (CBuilder_DX92_libs.zip Clootie_DX92_dlls.zip)
В системе стоит ХР + DX9.0c. Остаток чего то взял из c:\Dxsdk\lib\

Народ, у кого какие идеи? Уже голова кипит от этого бардака. Вроде бы простая цепочка. Я бы сказал «классика», а столько головной боли!
Re[3]: [DirectShow] Произвольный доступ к кадру AVI
От: VAstronom  
Дата: 29.05.12 11:40
Оценка:
Собственно код для растерзания:


#include <vcl.h>
#include <dshow.h>
#include "qedit.h"
#pragma comment (lib, "strmiids.lib")

#include "Unit1.h"
//------------------------------------------------------------------------------

const GUID TIME_FORMAT_FRAME = { 0x7b785570, 0x8c82, 0x11cf, { 0xbc, 0xc, 0x0, 0xaa, 0x0, 0xac, 0x74, 0xf6}};

HRESULT         hr;
HDC             wrkDC;
long            lBufSize;                                                       // размер данных кадра (шапка + данные)
BYTE            *pDIB;                                                          // адрес попиксельного хранения кадра

IGraphBuilder   *pGraphBuilder;
IBasicVideo     *pBasicVideo;
IMediaSeeking   *pMediaSeeking;
IMediaControl   *pControl;
IMediaEventEx   *pEvent;
ISampleGrabber  *pGrabber;

IBaseFilter     *pGrabberF;
IBaseFilter     *pNRFilter;
//------------------------------------------------------------------------------

__int64 Frames;
long    Xframe, Yframe;

int OpenDirShow();
int OpenAVI(WCHAR *);
int ChgFrame(__int64);
void CloseDirShow();

extern Graphics::TBitmap *mFRAME;
//==============================================================================

int ds_test(char *NF)
{
   WCHAR wFileName[MAX_PATH];
   int err;
   __int64 i;

   err=OpenDirShow();

   if (!err)
   {
      MultiByteToWideChar(CP_ACP, 0, NF, -1, wFileName, MAX_PATH);              // строку преобразую в Юникод

      err=OpenAVI(wFileName);
      if (!err)
      {
        for (i=1; i<10; i++) err=ChgFrame(i);
      }
   }

   CloseDirShow();

   return err;
}
//==============================================================================//

int OpenDirShow()
{
    pGraphBuilder = NULL;                                                       // Интерфейс менеджера графа-фильтров
    pBasicVideo   = NULL;
    pMediaSeeking = NULL;
    pControl = NULL;
    pEvent   = NULL;

    pGrabberF = NULL;
    pGrabber = NULL;
    pNRFilter = NULL;
    //--------------------------------------------------------------------------

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

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

    hr = pGraphBuilder->QueryInterface(IID_IMediaControl,(void **) &pControl);  // получаем интерфейсы
    if(FAILED(hr)) return 103;

    hr = pGraphBuilder->QueryInterface(IID_IMediaEvent, (void **)&pEvent);
    if(FAILED(hr)) return 104;

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

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

    //--------------------------------------------------------------------------
    hr = CoCreateInstance(CLSID_SampleGrabber, NULL, CLSCTX_INPROC_SERVER, IID_IBaseFilter, (void**)&pGrabberF);
    if (FAILED(hr)) return 107;

    hr = pGraphBuilder->AddFilter(pGrabberF, L"Sample Grabber");
    if (FAILED(hr)) return 108;

    pGrabberF->QueryInterface(IID_ISampleGrabber, (void**)&pGrabber);
    if (FAILED(hr)) return 109;

    //--------------------------------------------------------------------------
    /*
    hr = CoCreateInstance(CLSID_NullRenderer, NULL, CLSCTX_INPROC_SERVER, IID_IBaseFilter, (void**)&pNRFilter);
    if (FAILED(hr)) return 110;

    hr = pGraphBuilder->AddFilter(pNRFilter, L"Null Filter");
    if (FAILED(hr)) return 111;
    */
    //--------------------------------------------------------------------------

    return 0;
}

//==============================================================================
void CloseDirShow()
{
    if(pNRFilter)  pNRFilter->Release();
    if(pGrabberF)  pGrabberF->Release();
    if(pGrabber)   pGrabber->Release();

    if(pControl) pControl->Release();
    if(pEvent)   pEvent->Release();

    if(pMediaSeeking)   pMediaSeeking->Release();
    if(pBasicVideo)     pBasicVideo->Release();
    if(pGraphBuilder)   pGraphBuilder->Release();

    CoUninitialize();
}

//==============================================================================
int OpenAVI(WCHAR *wFileName)
{
  hr = pGraphBuilder->RenderFile((LPCWSTR)wFileName, NULL);                     // открываю файл
  if(FAILED(hr)) return 201;

  AM_MEDIA_TYPE mt;                                                             // задали формат видео
  ZeroMemory(&mt, sizeof(AM_MEDIA_TYPE));
  mt.majortype = MEDIATYPE_Video;
  mt.subtype = MEDIASUBTYPE_RGB24;

  hr = pGrabber->SetMediaType(&mt);
  if(FAILED(hr)) return 202;

  hr = pMediaSeeking->SetTimeFormat(&TIME_FORMAT_FRAME);                        // формат "кадры"
  if(FAILED(hr)) return 203;
  //----------------------------------------------------------------------------

  hr = pGrabber->SetOneShot(TRUE);                                              // Режим отсановки потока, после захвата кадра граббером-ом (TRUE - останавливается )
  if(FAILED(hr)) return 204;

  hr = pGrabber->SetBufferSamples(TRUE);                                        // Устанавливаем режим захвата через функцию
  if(FAILED(hr)) return 205;
  //----------------------------------------------------------------------------

  hr = pGrabber->GetConnectedMediaType( &mt );                                  // запрашиваем парамтеры видео
  if(FAILED(hr)) return 206;

  if ((mt.formattype == FORMAT_VideoInfo) &&
      (mt.cbFormat >= sizeof(VIDEOINFOHEADER)) &&
      (mt.pbFormat != NULL))
    {
        VIDEOINFOHEADER * vih = (VIDEOINFOHEADER*) mt.pbFormat;

        Xframe = vih->bmiHeader.biWidth;                                        // размер кадра
        Yframe = vih->bmiHeader.biHeight;
    }
    else return 207;

  // FreeMediaType( mt );           ??

  hr = pMediaSeeking->GetDuration(&Frames);                                     // количество кадров
  if(FAILED(hr)) return 206;
  //----------------------------------------------------------------------------

   __int64 ZPosFr=0;
   pMediaSeeking->SetPositions(&ZPosFr,AM_SEEKING_AbsolutePositioning,NULL,AM_SEEKING_NoPositioning);

   wrkDC = GetDC(0);

   pBasicVideo->GetCurrentImage(&lBufSize,NULL);
//   pGrabber->GetCurrentBuffer( &lBufSize,NULL);                                 // определяем размер памяти под кадр
   pDIB = (BYTE*)CoTaskMemAlloc(lBufSize);

   mFRAME->PixelFormat = pf24bit;
   mFRAME->Width =Xframe;
   mFRAME->Height=Yframe;
  //----------------------------------------------------------------------------

  return 0;
}

//==============================================================================
int ChgFrame(__int64 Nf)
{
  static long              evCode;
  static BITMAPINFOHEADER *bmih;
  static BITMAPINFO        bmi;
  //----------------------------------------------------------------------------

//  hr = pControl->Run();                               if (FAILED(hr)) return 301;
//  hr = pEvent->WaitForCompletion(INFINITE, &evCode);  if (FAILED(hr)) return 302;

  hr = pMediaSeeking->SetPositions(&Nf,AM_SEEKING_AbsolutePositioning,NULL,AM_SEEKING_NoPositioning);
  if (FAILED(hr)) return 303;

  pBasicVideo->GetCurrentImage(&lBufSize,(long*)pDIB);                          // получаю данные кадра
//  hr = pGrabber->GetCurrentBuffer(&lBufSize,(long*)pDIB);
  if (FAILED(hr)) return 304;
  //----------------------------------------------------------------------------

  bmih  = (BITMAPINFOHEADER*)pDIB;
  ZeroMemory(&bmi, sizeof(BITMAPINFO));
  CopyMemory(&(bmi.bmiHeader), bmih, sizeof(BITMAPINFOHEADER));
  mFRAME->Handle=CreateDIBitmap(wrkDC,bmih,CBM_INIT,pDIB,(PBITMAPINFO)&bmi,DIB_RGB_COLORS);

  Form1->Image1->Canvas->Draw(0,0, mFRAME);                                     // отрисовка картинки.
  Form1->Image1->Refresh();

  return 0;
}
//==============================================================================
Re[5]: [DirectShow] Произвольный доступ к кадру AVI
От: VAstronom  
Дата: 31.05.12 13:48
Оценка:
DM>Нужно построить цепочку
DM>source file -> AVI Splitter -> Decoder -> Sample Grabber -> Null Renderer

DM>OneShot не надо true, включаем в граббере буферизацию сэмплов, переводим граф в состояние паузы, делаем seek на нужную позицию, берем сохраненный в граббере кадр.


DM>Вручную все добавлять необязательно. Можно добавить File Source Async, сказать ему открыть нужный файл, затем добавить сэмпл граббер и сказать ему в каком формате принимать данные (например, RGB24 или RGB32 или YV12), затем через RenderStream соединяем эти два фильтра, промежуточные добавятся сами.


-------------------------------
Спасибо за совет, попытался его реализовать, но пока безуспешно.

Во первых, пишет: RenderStream is not a member of IGraphBuilder. Что то здесь я не понял.
Ну ладно, вручную соединил выход pSourceFile и вход pGrabberF.

Странно то, что если код из функции ConnectFilters(pSourceFile, pGrabberF, &pPinOut);
вставить в функцию, он не работает (в коде закомментировано). При закрытии программы пишет ошибку обращения к памяти, хотя сама функция почти со всем тем же работает…

Теперь у меня стопорится на
hr = pGrabber->GetCurrentBuffer(&lBufSize,(long*)pDIB); Выдает пустой (белый) кадр, хотя lBufSize при инициализации примерно похоже на кадр (типа 1456886).
hr = pBasicVideo->GetCurrentImage(&lBufSize,NULL); которое раньше работало уже при попытке запроса возвращает ошибку.

Народ, извините меня, но очень хочется собрать рабочий шаблон подобной задачи (кадровый доступ). Уже столько времени угроблено, что жалко бросать нерешенную проблему. Может я чего то не понимаю, подскажите пожалуйста, какой и куда код надо вставить, что бы это заработало. Может есть другой способ перескакивать между кадрами, и зря я уцепился в эти pMediaSeeking и pBasicVideo?

-------------------------------
DM> делаем seek
это как? pMediaSeeking->SetPositions(...)?

DM> включаем в граббере буферизацию сэмплов

это как? OneShot(false)?

DM>берем сохраненный в граббере кадр.

так: pGrabber->GetCurrentBuffer(...)?
Re[4]: [DirectShow] Произвольный доступ к кадру AVI
От: VAstronom  
Дата: 31.05.12 13:50
Оценка:
Приложение к сообщению, текущий вариант реализации. Не работает.

#include <vcl.h>
#include <dshow.h>
#include <qedit.h>
#include <strmif.h>
#pragma comment (lib, "strmiids.lib")

#include "Unit1.h"

HRESULT         hr;

IGraphBuilder   *pGraph;
IMediaControl   *pControl;
ISampleGrabber  *pGrabber;

IBasicVideo     *pBasicVideo;
IMediaSeeking   *pMediaSeeking;

IBaseFilter     *pGrabberF;
IBaseFilter     *pNRFilter;
IBaseFilter     *pSourceFile;

HRESULT GetPin(IBaseFilter *ppWorkF, PIN_DIRECTION pDirPin, IPin **PinOut);
HRESULT ConnectFilters(IBaseFilter *ppFilterSource, IBaseFilter *ppFilterTarget, IPin **pOutputPin);

//------------------------------------------------------------------------------
__int64 Frames;
long    Xframe, Yframe;
extern  Graphics::TBitmap *mFRAME;

HDC             wrkDC;
long            lBufSize;                                                       // размер данных кадра (шапка + данные)
BYTE            *pDIB;                                                          // адрес попиксельного хранения кадра

//==============================================================================
int OpenDirShow(WCHAR *wFileName)
{
    pDIB = NULL;

    pGraph    = NULL;
    pControl  = NULL;

    pGrabber  = NULL;

    pBasicVideo   = NULL;
    pMediaSeeking = NULL;

    pGrabberF = NULL;
    pNRFilter = NULL;
    pSourceFile=NULL;
    //--------------------------------------------------------------------------

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

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

    hr = pGraph->QueryInterface(IID_IMediaControl, (void **)&pControl);
    if (FAILED(hr)) return 102;
    //--------------------------------------------------------------------------

    hr = pGraph->AddSourceFilter(wFileName, L"Source", &pSourceFile);
    if (FAILED(hr)) return 103;
    //--------------------------------------------------------------------------

    hr = pGraph->QueryInterface(IID_IBasicVideo,(void**)&pBasicVideo);
    if(FAILED(hr)) return 104;

    hr = pGraph->QueryInterface(IID_IMediaSeeking,(void**)&pMediaSeeking);
    if(FAILED(hr)) return 105;
    //--------------------------------------------------------------------------

    hr = CoCreateInstance(CLSID_SampleGrabber, NULL, CLSCTX_INPROC_SERVER, IID_IBaseFilter, (void**)&pGrabberF);
    if (FAILED(hr)) return 106;

    hr = pGraph->AddFilter(pGrabberF, L"Sample Grabber");
    if (FAILED(hr)) return 107;

    pGrabberF->QueryInterface(IID_ISampleGrabber, (void**)&pGrabber);
    if (FAILED(hr)) return 108;

    AM_MEDIA_TYPE mt;                                                           // задали формат видео
    ZeroMemory(&mt, sizeof(AM_MEDIA_TYPE));
    mt.majortype = MEDIATYPE_Video;
    mt.subtype = MEDIASUBTYPE_RGB24;

    hr = pGrabber->SetMediaType(&mt);
    if(FAILED(hr)) return 109;

    hr = pGrabber->SetOneShot(FALSE);                                           // Режим отсановки потока, после захвата кадра граббером-ом (TRUE - останавливается )
    if(FAILED(hr)) return 110;

    hr = pGrabber->SetBufferSamples(TRUE);                                      // Устанавливаем режим захвата через функцию
    if(FAILED(hr)) return 111;
    //--------------------------------------------------------------------------

    hr = CoCreateInstance(CLSID_NullRenderer, NULL, CLSCTX_INPROC_SERVER, IID_IBaseFilter, (void**)&pNRFilter);
    if (FAILED(hr)) return 112;

    hr = pGraph->AddFilter(pNRFilter, L"Null Filter");
    if (FAILED(hr)) return 113;

    //--------------------------------------------------------------------------
    IPin *pPinOut(NULL);

    /*
    IPin *pPinIn(NULL);
    hr = GetPin(pSourceFile, PINDIR_OUTPUT, &pPinOut);  if (FAILED(hr)) { return 114; }
    hr = GetPin(pGrabberF,   PINDIR_INPUT,  &pPinIn);   if (FAILED(hr)) { return 115; }
    hr = pGraph->Connect(pPinOut, pPinIn);              if (FAILED(hr)) { return 116; }
    hr = GetPin(pGrabberF,   PINDIR_OUTPUT, &pPinOut);  if (FAILED(hr)) { return 117; }
    pPinIn->Release();
    */

    hr = ConnectFilters(pSourceFile, pGrabberF, &pPinOut);    if (FAILED(hr)) { return 118; }
    hr = pGraph->Render(pPinOut);                             if (FAILED(hr)) { return 119; }

    hr = pPinOut->Release();                                  if (FAILED(hr)) { return 120; }

//    hr = pGraph->RenderStream(NULL, &MEDIATYPE_Video, pSourceFile, NULL, pGrabberF);     // CDVGraph.cpp
//    hr = pGraph->RenderStream(&PIN_CATEGORY_PREVIEW, pBaseFilter, NULL, NULL); // RenderStream is not a member of IGraphBuilder

    hr = pControl->Run();                                     if (FAILED(hr)) { return 121; }
    hr = pControl->Pause();                                   if (FAILED(hr)) { return 122; }

    //--------------------------------------------------------------------------

    return 0;
}

//==============================================================================
void DSClose()
{
    if (pDIB != NULL)
    {
       delete [] pDIB;
    }

    if(pSourceFile)     pSourceFile->Release();
    if(pNRFilter)       pNRFilter->Release();
    if(pGrabberF)       pGrabberF->Release();

    if(pMediaSeeking)   pMediaSeeking->Release();
    if(pBasicVideo)     pBasicVideo->Release();

    if(pGrabber)        pGrabber->Release();
    if(pControl)        pControl->Release();
    if(pGraph)          pGraph->Release();

    CoUninitialize();
}
//------------------------------------------------------------------------------

// -----------------------------------------------------------------------------=======
// Соединение двух фильтров
// -----------------------------------------------------------------------------
HRESULT ConnectFilters(IBaseFilter *ppFilterSource, IBaseFilter *ppFilterTarget, IPin **pOutputPin)
{
   HRESULT hr=NULL;

   IPin  *pPinOut;
   IPin  *pPinIn;

   hr = GetPin(ppFilterSource, PINDIR_OUTPUT, &pPinOut);

   hr = GetPin(ppFilterTarget, PINDIR_INPUT, &pPinIn);
   if (SUCCEEDED(hr))
   {
      hr = pGraph->Connect(pPinOut, pPinIn);
      if (SUCCEEDED(hr))
      {
         hr = GetPin(ppFilterTarget, PINDIR_OUTPUT, pOutputPin);
         return S_OK;
      }
   }
   return E_FAIL;
}


// -----------------------------------------------------------------------------
//     Получение пина соответствующего фильтра
// -----------------------------------------------------------------------------
HRESULT GetPin(IBaseFilter *ppWorkF, PIN_DIRECTION pDirPin, IPin **PinOut)
{
   HRESULT hr;
   PIN_DIRECTION pDir;
   IPin          *pPin=NULL;
   IEnumPins      *pEnum=NULL;     // Энумератор пинов

   hr = ppWorkF->EnumPins(&pEnum);
   if(FAILED(hr)) return NULL;

       // Перечисляем все пины в фильтре и ищем
       // пин снужным нам направлением
   while (pEnum->Next(1, &pPin, NULL) == S_OK)
   {
      pPin->QueryDirection(&pDir); // Запрашиваем направленее пина
      if(pDir==pDirPin)
      {
         *PinOut=pPin;
         break;
      }
   }
   pPin->Release();
   pEnum->Release();
   return S_OK;
}

//==============================================================================
int AVI_INI()
{
  const GUID TIME_FORMAT_FRAME = { 0x7b785570, 0x8c82, 0x11cf, { 0xbc, 0xc, 0x0, 0xaa, 0x0, 0xac, 0x74, 0xf6}};

  hr = pMediaSeeking->SetTimeFormat(&TIME_FORMAT_FRAME);                        // формат "кадры"
  if(FAILED(hr)) return 201;
  //----------------------------------------------------------------------------

  AM_MEDIA_TYPE mt;
  hr = pGrabber->GetConnectedMediaType( &mt );                                  // запрашиваем парамтеры видео
  if(FAILED(hr)) return 202;

  if ((mt.formattype == FORMAT_VideoInfo) &&
      (mt.cbFormat >= sizeof(VIDEOINFOHEADER)) &&
      (mt.pbFormat != NULL))
    {
        VIDEOINFOHEADER * vih = (VIDEOINFOHEADER*) mt.pbFormat;

        Xframe = vih->bmiHeader.biWidth;                                        // размер кадра
        Yframe = vih->bmiHeader.biHeight;
    }
    else return 203;

  // FreeMediaType( mt );           ??

  hr = pMediaSeeking->GetDuration(&Frames);                                     // количество кадров
  if(FAILED(hr)) return 204;
  //----------------------------------------------------------------------------

   __int64 ZPosFr=0;
   hr = pMediaSeeking->SetPositions(&ZPosFr,AM_SEEKING_AbsolutePositioning,NULL,AM_SEEKING_NoPositioning);
   if(FAILED(hr)) return 205;

   hr = pGrabber->GetCurrentBuffer(&lBufSize,NULL);
//   hr = pBasicVideo->GetCurrentImage(&lBufSize,NULL);
   if(FAILED(hr)) return 206;

//   pDIB = (BYTE*)CoTaskMemAlloc(lBufSize);
    pDIB=new BYTE[lBufSize];

   mFRAME->PixelFormat = pf24bit;
   mFRAME->Width =Xframe;
   mFRAME->Height=Yframe;

   wrkDC = GetDC(0);
  //----------------------------------------------------------------------------

  return 0;
}


//==============================================================================
int ChgFrame(__int64 Nf)
{
  static BITMAPINFOHEADER *bmih;
  static BITMAPINFO        bmi;
  //----------------------------------------------------------------------------

  hr = pMediaSeeking->SetPositions(&Nf,AM_SEEKING_AbsolutePositioning,NULL,AM_SEEKING_NoPositioning);
  if (FAILED(hr)) return 301;

//  hr = pBasicVideo->GetCurrentImage(&lBufSize,(long*)pDIB);                         // получаю данные кадра
  hr = pGrabber->GetCurrentBuffer(&lBufSize,(long*)pDIB);
  if (FAILED(hr)) return 302;
  //----------------------------------------------------------------------------

  bmih  = (BITMAPINFOHEADER*)pDIB;
  ZeroMemory(&bmi, sizeof(BITMAPINFO));
  CopyMemory(&(bmi.bmiHeader), bmih, sizeof(BITMAPINFOHEADER));
  mFRAME->Handle=CreateDIBitmap(wrkDC,bmih,CBM_INIT,pDIB,(PBITMAPINFO)&bmi,DIB_RGB_COLORS);

  Form1->Image1->Canvas->Draw(0,0, mFRAME);                                     // отрисовка картинки.
  Form1->Image1->Refresh();

  return 0;
}
Re[6]: [DirectShow] Произвольный доступ к кадру AVI
От: VAstronom  
Дата: 05.06.12 07:50
Оценка:
VA>Спасибо за совет, попытался его реализовать, но пока безуспешно.

Видимо, все же успешно... Кадр через ScanLine выдернул из byte *pDIB.
Меня это устраивает т.к. дальше идет анализ данных, но для большинства
это не универсально. При этом код для отображения из моего примера:

  bmih  = (BITMAPINFOHEADER*)pDIB;
  ZeroMemory(&bmi, sizeof(BITMAPINFO));
  CopyMemory(&(bmi.bmiHeader), bmih, sizeof(BITMAPINFOHEADER));
  mFRAME->Handle=CreateDIBitmap(wrkDC,bmih,CBM_INIT,pDIB,(PBITMAPINFO)&bmi,DIB_RGB_COLORS);

  Form1->Image1->Canvas->Draw(0,0, mFRAME);


толком так и не заработал.

Достать кадр — это инструмент. Возможно, при решении целевой задачи
с этим кодом (доступ к кадру) возникнут новые грабли,
которых пока не видно. Время покажет...
Re: [DirectShow] Произвольный доступ к кадру AVI
От: VSlava  
Дата: 14.06.12 14:31
Оценка:
Для MPEG2 и MPEG4 SetPosition в произвольное место не работает.
Отображается ближайший ключевой кадр. С MPEG2 вообще кучеряво в связи с лицензиями.

Попробуйте предварительно поток конвертнуть в MJPEG.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.