Ui - 600 - 3000 $ ist mir etwas zu viel
.
Ich kann ja mal das Demo probieren.
Das Demo von DSPack - dürfte auch nich ganz sync sein, und scheinbar machen die nichts anderes als ich.
Das Problem bei mir ist, dass ich einen PushSource Filter habe und keinen Capture oder Preview.
Jedenfalls lasse ich mal Source Code sprechen - vielleicht fällt jemanden ja auf was kompletter unsinn ist.
Tut mir leid, dass der Code so ein Chaos ist, aber wenn man schon seit tagen alles mögliche herumprobiert, kommt sowas raus.
Main Project Filter Initialisation und Rendering:
Delphi-Quellcode:
procedure TForm1.Button1Click(Sender: TObject);
var CaptureFile: WideString;
Writer: IFileSinkFilter;
Multiplexer : IBaseFilter;
SysDev: TSysDevEnum;
begin
if FileExists('c:\test.avi') then deletefile('c:\test.avi');
if InjectLibrary then
begin
//. todo : check for injected lib instead of sleep
sleep (2000);
memo1.Lines.Add('ok');
SysDev:= TSysDevEnum.Create;
//. todo - do not hardcode indexcategory
SysDev.SelectIndexCategory(1);
MemMapSelfCreated.BaseFilter.Moniker := SysDev.GetMoniker(SysDev.FilterIndexOfFriendlyName('Memory Map BitmapFilter'));
memo1.Lines.Add(' using:' + SysDev.Filters[SysDev.FilterIndexOfFriendlyName('Memory Map BitmapFilter')].FriendlyName );
if FilterGraph1.Active then FilterGraph1.Active := false;
FilterGraph1.ClearGraph;
FilterGraph1.Active:= True;
FilterGraph1.GraphEdit := True;
CaptureFile := 'c:\test.avi';
MemMapSelfCreated.FilterGraph := FilterGraph1;
//VideoWindow1.FilterGraph := FilterGraph1;
with FilterGraph1 as ICaptureGraphBuilder2 do
begin
SetOutputFileName(MEDIASUBTYPE_Avi, PWideChar(CaptureFile), Multiplexer, writer);
//ShowFilterPropertyPage(Self.Handle, Multiplexer as IBaseFilter, ppDefault);
//RenderStream(nil, @MEDIATYPE_Video, MemMapSelfCreated as IBaseFilter,
// {DivXCompressor as IBaseFilter} nil, VideoWindow1 as IBaseFilter);
RenderStream(nil{@PIN_CATEGORY_CAPTURE}, @MEDIATYPE_Video, MemMapSelfCreated{MemMapSource} as IBaseFilter,
DivXCompressor as IBaseFilter, Multiplexer as IBaseFilter);
//ShowFilterPropertyPage(Self.Handle, DivXCompressor as IBaseFilter, ppVFWCompConfig);
RenderStream(nil{@PIN_CATEGORY_CAPTURE}, @MEDIATYPE_Audio, AudioSource as IBaseFilter,
Mp3Compressor as IBaseFilter, Multiplexer as IBaseFilter);
end;
with Multiplexer as IConfigAviMux do
begin
setmasterstream(1);
end;
with Multiplexer as IConfigInterleaving do
begin
put_Mode(INTERLEAVE_FULL);
end;
FilterGraph1.Play;
end;
end;
Anmerkung:
DivXCompressor: hier habe ich divx, HuffYuV und Mjpeg ausprobiert - mit teilweise besseren und schlechteren ergebnissen.
Mjpeg scheint am bessten zu funktionieren.
HuffYuV spielt im video dann als slow motion??? - keine ahnung warum
DivX hat zu viele frame loss - dürfte zu langsam sein für live capture von einem PushSoure filter ( 800x600 24 bit bitmap mit 25 fps )
Mp3Compressor: hier habe ich sowol mpeg layer3 also auch keinen kompressor versucht ... macht nicht viel unterschied.
Der Filter Selbst:
Delphi-Quellcode:
function TBCPushPinDesktop.FillBuffer(Sample: IMediaSample): HResult;
var
pData: PByte;
cbData: Longint;
pvih: PVIDEOINFOHEADER;
Start, Stop: REFERENCE_TIME;
function min(v1, v2: DWord): DWord;
begin
if v1 <= v2
then
Result := v1
else
Result := v2;
end;
function CopyMemToBitmap(pData : PByte;
pHeader : PBitmapInfo) : boolean;
//var
//FileHeader : BITMAPFILEHEADER;
begin
Result := false;
if not (FSpeicher =
nil)
then
begin
//copymemory(@FileHeader,FSpeicher,Sizeof(BITMAPFILEHEADER));
copymemory(@pHeader.bmiHeader, Pointer(DWord(FSpeicher)+sizeOf(BITMAPFILEHEADER)), SizeOf(BITMAPINFOHEADER));
copymemory(pData, Pointer(DWord(FSpeicher) + SizeOf(BITMAPFILEHEADER) + SizeOf(BITMAPINFOHEADER)),pHeader.bmiHeader.biSizeImage);
Result := true;
end;
end;
begin
if (Sample =
nil)
then
begin
Result := E_POINTER;
Exit;
end;
FSharedState.Lock;
try
// Access the sample's data buffer
Sample.GetPointer(pData);
cbData := Sample.GetSize;
// Check that we're still using video
Assert(IsEqualGUID(AMMediaType.formattype, FORMAT_VideoInfo));
pvih := AMMediaType.pbFormat;
// Copy the DIB bits over into our filter's output buffer.
// Since sample size may be larger than the image size, bound the copy size.
pVih.bmiHeader.biSizeImage := min(pVih.bmiHeader.biSizeImage, cbData);
if (WaitForSingleObject(myMutex, 100) = WAIT_OBJECT_0)
then
begin
CopyMemToBitmap(pData, @pVih.bmiHeader);
Result := S_OK;
end;
// else Result := S_FALSE;
ReleaseMutex(myMutex);
Result := S_OK;
// Set the timestamps that will govern playback frame rate.
// If this file is getting written out as an AVI,
// then you'll also need to configure the AVI Mux filter to
// set the Average Time Per Frame for the AVI Header.
// The current time is the sample's start
Start := (FFrameNumber * FFrameLength);
Stop := Start + FFrameLength;
Sample.SetTime(@Start, @Stop);
Inc(FFrameNumber);
// Set TRUE on every sample for uncompressed frames
Sample.SetSyncPoint(True);
finally
FSharedState.UnLock;
end;
end;
Anmerkung:
Hier habe ich vor allem mit dem
Mutex gespielt - timeout von 100 ms funktionert im video window sehr gut ( sollte niemals so lange warten müssen ).
Auch mit dem Result hab ich herumprobiert, ob das jemals false werden sollte weiß ich nicht, aber es macht keinen unterschied nach meiner erfahrung.
start/stop Time und SetSyncPoint sind aus dem originalen pushsource filter und dürfte so stimmen, aber sicher bin ich nicht.
lg
Arnulf