Нужно произвести захват видеокадра с камеры (камера может быть любой - USB, подключенная к спец. плате). вроде бы все хорошо, но проблемма состоит в том чтобы инициалицировать камеру, т.е. задать размер кадра, тип медиаданных, глубину цвета и т.д.. Использую для тестов встроенную вэбкамеру в ноутбук и подключенную к плате цифровую камеру (CNB или DSP 220 Digital Zoom - если это кому-то что-то говорит ).
В случае вэбкамеры инициализация идет видимо по умолчанию (640х480, 24 bit, RGB24) и хоть какой-то захват идет... Но все попытки поменять данные - ни к чему не приводят - упрямо остаются такими же на выходе, хотя в MediaType SampleGrabber'а они все же записываются (проверял в режиме debug'a). А вот в случае подключенной к плате - вообще ничего - как телевизор без антены, однако если ее инициализирровать запустив другую программу (есть такая, но без исходников) и после запустить мою прогу, то вроде все идет, но с установками, той, другой программы.
Может кто знает как разрешить проблему? Меня пока устроило бы даже частичное решение - пусть любая камера инициализируется хоть какими-то значениями, лишь на медиаконтроле было изображение и метод SampleGrabber.GetBitmap(...) давал бы не 0-картинку. Но хотелось бы все же нормальной работы - метод StretchDraw все же искажает изображения, а речь идет о фото на документы.
Версия Delphi - 2010. Но можно и С++ Builder.
Вот мой код - попытка инициализации. Я понимаю до совершенства далеко, но не до "вылизывания" мне - начальство по маковке стучит: мол поскорее нужно... Закоменчены результаты всевозможных экспериментов.
Код:
procedure TVideoForm.BitBtn3Click(Sender: TObject);
var
SMTeeFilter : IBaseFilter;
m_VideoType: PAMMediaType;
hr: HResult;
StreamConfig: IAMStreamConfig;
begin
{
Колмпоненты на форме
DSPack:
Filter - TFilter
FilterGraph - TFilterGraph
SampleGrabber - TSampleGrabber
VideoWindow - TVideoWindow
ComboBox1 - список устройств видеозахвата (будет одна камера - потому
можно будет "упразднить")
кроме того имеется TImage - но он не обязателен
}
try
// CoCreateInstance(CLSID_SmartTee, nil,
// CLSCTX_INPROC, IID_IBaseFilter, SMTeeFilter);
// hr := (FilterGraph as IGraphBuilder).AddFilter(SMTeeFilter, 'Smart Tee');
// не работает - пишет, что "интерфейс не поддерживается"
StreamConfig := NIL;
m_VideoType := nil;
FilterGraph.ClearGraph();
FilterGraph.Active := False;
Filter.BaseFilter.Moniker := SysDev.GetMoniker(ComboBox1.ItemIndex);
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);
{ hr := FindInterface(@PIN_CATEGORY_CAPTURE,
@MEDIATYPE_Video,
SampleGrabber as IBaseFilter,
IID_IAMStreamConfig, StreamConfig); //возвращает hr < 0}
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 := 24;
//25 fps
PVideoInfoHeader(m_VideoType.pbFormat)^.AvgTimePerFrame:= 10000000 div 25;
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_RGB24;
// StreamConfig.SetFormat(m_VideoType^); //толку никакого от этого медода
end;
// ShowMessage(IntTostr(sizeof(m_VideoType^))); - 72 байта
// SampleGrabber.MediaType.SetFormat(m_VideoType, sizeof(m_VideoType^));
// Результата этот метод не дает
//вручною записываю все данные
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;
//значения в MediaType - таким образом записаны, но
//SampleGrabber.GetBitmap(...) выдает 640х480х24
//если задать например m_VideoType.subtype := MEDIASUBTYPE_YUYV;
//то возникает error "Контакты не присоединены..." - что в общем - то понятно
//но камера подключенныя к плате такой тип поддерживает, но там тот же error.
//ниже следующий код - попытка "обновить" буфер захвата камеры
//но ничего он не дает...
SampleGrabber.UpdateMediaType();
FilterGraph.ClearGraph;
FilterGraph.Active := False;
Filter.BaseFilter.Moniker := SysDev.GetMoniker(ComboBox1.ItemIndex);
Filter.FilterGraph := FilterGraph;
FilterGraph.Active := True;
{ 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 - на вэбкамере идет, на другой
//нет вообще ничего
//даже "шипения" на медиаконтроле
RenderStream(@PIN_CATEGORY_CAPTURE, nil,
Filter as IBaseFilter,
SampleGrabber as IBaseFilter,
VideoWindow as IbaseFilter);
{ RenderStream(nil, nil, SMTeeFilter as IBaseFilter,
SampleGrabber as IBaseFilter,
VideoWindow as IbaseFilter);
SMTeeFilter - вообще не вставляется.}
end;
FilterGraph.Play();
except
{}
end;
end;
В случае вэбкамеры инициализация идет видимо по умолчанию (640х480, 24 bit, RGB24) и хоть какой-то захват идет... Но все попытки поменять данные - ни к чему не приводят - упрямо остаются такими же на выходе, хотя в MediaType SampleGrabber'а они все же записываются (проверял в режиме debug'a). А вот в случае подключенной к плате - вообще ничего - как телевизор без антены, однако если ее инициализирровать запустив другую программу (есть такая, но без исходников) и после запустить мою прогу, то вроде все идет, но с установками, той, другой программы.
Может кто знает как разрешить проблему? Меня пока устроило бы даже частичное решение - пусть любая камера инициализируется хоть какими-то значениями, лишь на медиаконтроле было изображение и метод SampleGrabber.GetBitmap(...) давал бы не 0-картинку. Но хотелось бы все же нормальной работы - метод StretchDraw все же искажает изображения, а речь идет о фото на документы.
Версия Delphi - 2010. Но можно и С++ Builder.
Вот мой код - попытка инициализации. Я понимаю до совершенства далеко, но не до "вылизывания" мне - начальство по маковке стучит: мол поскорее нужно... Закоменчены результаты всевозможных экспериментов.
Код:
procedure TVideoForm.BitBtn3Click(Sender: TObject);
var
SMTeeFilter : IBaseFilter;
m_VideoType: PAMMediaType;
hr: HResult;
StreamConfig: IAMStreamConfig;
begin
{
Колмпоненты на форме
DSPack:
Filter - TFilter
FilterGraph - TFilterGraph
SampleGrabber - TSampleGrabber
VideoWindow - TVideoWindow
ComboBox1 - список устройств видеозахвата (будет одна камера - потому
можно будет "упразднить")
кроме того имеется TImage - но он не обязателен
}
try
// CoCreateInstance(CLSID_SmartTee, nil,
// CLSCTX_INPROC, IID_IBaseFilter, SMTeeFilter);
// hr := (FilterGraph as IGraphBuilder).AddFilter(SMTeeFilter, 'Smart Tee');
// не работает - пишет, что "интерфейс не поддерживается"
StreamConfig := NIL;
m_VideoType := nil;
FilterGraph.ClearGraph();
FilterGraph.Active := False;
Filter.BaseFilter.Moniker := SysDev.GetMoniker(ComboBox1.ItemIndex);
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);
{ hr := FindInterface(@PIN_CATEGORY_CAPTURE,
@MEDIATYPE_Video,
SampleGrabber as IBaseFilter,
IID_IAMStreamConfig, StreamConfig); //возвращает hr < 0}
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 := 24;
//25 fps
PVideoInfoHeader(m_VideoType.pbFormat)^.AvgTimePerFrame:= 10000000 div 25;
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_RGB24;
// StreamConfig.SetFormat(m_VideoType^); //толку никакого от этого медода
end;
// ShowMessage(IntTostr(sizeof(m_VideoType^))); - 72 байта
// SampleGrabber.MediaType.SetFormat(m_VideoType, sizeof(m_VideoType^));
// Результата этот метод не дает
//вручною записываю все данные
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;
//значения в MediaType - таким образом записаны, но
//SampleGrabber.GetBitmap(...) выдает 640х480х24
//если задать например m_VideoType.subtype := MEDIASUBTYPE_YUYV;
//то возникает error "Контакты не присоединены..." - что в общем - то понятно
//но камера подключенныя к плате такой тип поддерживает, но там тот же error.
//ниже следующий код - попытка "обновить" буфер захвата камеры
//но ничего он не дает...
SampleGrabber.UpdateMediaType();
FilterGraph.ClearGraph;
FilterGraph.Active := False;
Filter.BaseFilter.Moniker := SysDev.GetMoniker(ComboBox1.ItemIndex);
Filter.FilterGraph := FilterGraph;
FilterGraph.Active := True;
{ 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 - на вэбкамере идет, на другой
//нет вообще ничего
//даже "шипения" на медиаконтроле
RenderStream(@PIN_CATEGORY_CAPTURE, nil,
Filter as IBaseFilter,
SampleGrabber as IBaseFilter,
VideoWindow as IbaseFilter);
{ RenderStream(nil, nil, SMTeeFilter as IBaseFilter,
SampleGrabber as IBaseFilter,
VideoWindow as IbaseFilter);
SMTeeFilter - вообще не вставляется.}
end;
FilterGraph.Play();
except
{}
end;
end;