Стоит задача анализа содержимого видео файла. Я больше инженер, чем программист, но пришлось разбираться с 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();
}