📄 upushsource.pas
字号:
begin
Result := E_INVALIDARG;
Exit;
end;
// Have we run off the end of types?
if (iPosition > 4) then
begin
Result := VFW_S_NO_MORE_ITEMS;
Exit;
end;
MediaType.cbFormat := SizeOf(TVideoInfo);
pvi := CoTaskMemAlloc(MediaType.cbFormat);
if (pvi = nil) then
begin
Result := E_OUTOFMEMORY;
Exit;
end;
// Initialize the VideoInfo structure before configuring its members
ZeroMemory(pvi, MediaType.cbFormat);
case iPosition of
0:
begin
// Return our highest quality 32bit format
// Since we use RGB888 (the default for 32 bit), there is
// no reason to use BI_BITFIELDS to specify the RGB
// masks. Also, not everything supports BI_BITFIELDS
pvi.bmiHeader.biCompression := BI_RGB;
pvi.bmiHeader.biBitCount := 32;
end;
1:
begin
// Return our 24bit format
pvi.bmiHeader.biCompression := BI_RGB;
pvi.bmiHeader.biBitCount := 24;
end;
2:
begin
// 16 bit per pixel RGB565
// Place the RGB masks as the first 3 doublewords in the palette area
for i := 0 to 2 do
pvi.TrueColorInfo.dwBitMasks[i] := bits565[i];
pvi.bmiHeader.biCompression := BI_BITFIELDS;
pvi.bmiHeader.biBitCount := 16;
end;
3:
begin
// 16 bits per pixel RGB555
// Place the RGB masks as the first 3 doublewords in the palette area
for i := 0 to 2 do
pvi.TrueColorInfo.dwBitMasks[i] := bits555[i];
pvi.bmiHeader.biCompression := BI_BITFIELDS;
pvi.bmiHeader.biBitCount := 16;
end;
4:
begin
// 8 bit palettised
pvi.bmiHeader.biCompression := BI_RGB;
pvi.bmiHeader.biBitCount := 8;
pvi.bmiHeader.biClrUsed := iPALETTE_COLORS;
end;
end;
// Adjust the parameters common to all formats
pvi.bmiHeader.biSize := SizeOf(TBitmapInfoHeader);
pvi.bmiHeader.biWidth := FImageWidth;
pvi.bmiHeader.biHeight := FImageHeight;
pvi.bmiHeader.biPlanes := 1;
pvi.bmiHeader.biSizeImage := GetBitmapSize(@pvi.bmiHeader);
pvi.bmiHeader.biClrImportant := 0;
// Clear source and target rectangles
// we want the whole image area rendered
SetRectEmpty(pvi.rcSource);
// no particular destination rectangle
SetRectEmpty(pvi.rcTarget);
MediaType.majortype := MEDIATYPE_Video;
MediaType.formattype := FORMAT_VideoInfo;
MediaType.bTemporalCompression := False;
MediaType.bFixedSizeSamples := True;
// Work out the GUID for the subtype from the header info.
MediaType.subtype := GetBitmapSubtype(@pvi.bmiHeader);
MediaType.pbFormat := pvi;
MediaType.lSampleSize := pvi.bmiHeader.biSizeImage;
Result := S_OK;
finally
FFilter.StateLock.UnLock;
end;
end;
// We will accept 8, 16, 24 or 32 bit video formats, in any
// image size that gives room to bounce.
// Returns E_INVALIDARG if the mediatype is not acceptable
function TBCPushPinDesktop.CheckMediaType(MediaType: PAMMediaType): HResult;
var
pvi: PVIDEOINFO;
SubType: TGUID;
begin
// we only output video
if not (IsEqualGUID(MediaType.majortype, MEDIATYPE_Video)) or
// in fixed size samples
not (MediaType.bFixedSizeSamples) then
begin
Result := E_INVALIDARG;
Exit;
end;
// Check for the subtypes we support
SubType := MediaType.subtype;
if IsEqualGUID(SubType, GUID_NULL) then
begin
Result := E_INVALIDARG;
Exit;
end;
if not (
IsEqualGUID(SubType, MEDIASUBTYPE_RGB8) or
IsEqualGUID(SubType, MEDIASUBTYPE_RGB565) or
IsEqualGUID(SubType, MEDIASUBTYPE_RGB555) or
IsEqualGUID(SubType, MEDIASUBTYPE_RGB24) or
IsEqualGUID(SubType, MEDIASUBTYPE_RGB32)
) then
begin
Result := E_INVALIDARG;
Exit;
end;
// Get the format area of the media type
pvi := MediaType.pbFormat;
if (pvi = nil) then
begin
Result := E_INVALIDARG;
Exit;
end;
// Check if the image width & height have changed
if (pvi.bmiHeader.biWidth <> FImageWidth) or
(abs(pvi.bmiHeader.biHeight) <> FImageHeight) then
// If the image width/height is changed, fail CheckMediaType() to force
// the renderer to resize the image.
begin
Result := E_INVALIDARG;
Exit;
end;
// Don't accept formats with negative height, which would cause the desktop
// image to be displayed upside down.
if (pvi.bmiHeader.biHeight < 0) then
begin
Result := E_INVALIDARG;
Exit;
end;
Result := S_OK; // This format is acceptable.
end;
//
// DecideBufferSize
//
// This will always be called after the format has been sucessfully
// negotiated. So we have a look at AMMediaType to see what size image we agreed.
// Then we can ask for buffers of the correct size to contain them.
//
function TBCPushPinDesktop.DecideBufferSize(Allocator: IMemAllocator;
Properties: PAllocatorProperties): HRESULT;
var
pvi: PVIDEOINFOHEADER;
Actual: ALLOCATOR_PROPERTIES;
begin
if (Allocator = nil) or (Properties = nil) then
begin
Result := E_POINTER;
Exit;
end;
FFilter.StateLock.Lock;
try
pvi := AMMediaType.pbFormat;
Properties.cBuffers := 1;
Properties.cbBuffer := pvi.bmiHeader.biSizeImage;
Assert(Properties.cbBuffer <> 0);
// Ask the allocator to reserve us some sample memory. NOTE: the function
// can succeed (return NOERROR) but still not have allocated the
// memory that we requested, so we must check we got whatever we wanted.
Result := Allocator.SetProperties(Properties^, Actual);
if Failed(Result) then
Exit;
// Is this allocator unsuitable?
if (Actual.cbBuffer < Properties.cbBuffer) then
begin
Result := E_FAIL;
Exit;
end;
// Make sure that we have only 1 buffer
Assert(Actual.cBuffers = 1);
Result := S_OK;
finally
FFilter.StateLock.UnLock;
end;
end;
//
// SetMediaType
//
// Called when a media type is agreed between filters
//
function TBCPushPinDesktop.SetMediaType(MediaType: PAMMediaType): HRESULT;
var
pvi: PVIDEOINFOHEADER;
begin
FFilter.StateLock.Lock;
try
// Pass the call up to my base class
Result := inherited SetMediaType(MediaType);
if Succeeded(Result) then
begin
pvi := AMMediaType.pbFormat;
if (pvi = nil) then
begin
Result := E_UNEXPECTED;
Exit;
end;
// 8-bit palettized,
// RGB565, RGB555,
// RGB24,
// RGB32
if pvi.bmiHeader.biBitCount in [8, 16, 24, 32] then
begin
// Save the current media type and bit depth
FMediaType := MediaType^;
FCurrentBitDepth := pvi.bmiHeader.biBitCount;
end
else
begin
// We should never agree any other media types
Assert(False);
Result := E_INVALIDARG;
end;
end;
finally
FFilter.StateLock.UnLock;
end;
end;
// This is where we insert the DIB bits into the video stream.
// FillBuffer is called once for every sample in the stream.
function TBCPushPinDesktop.FillBuffer(Sample: IMediaSample): HResult;
var
pData: PByte;
cbData: Longint;
hDib: HBitmap;
pvih: PVIDEOINFOHEADER;
Start, Stop: REFERENCE_TIME;
function min(v1, v2: DWord): DWord;
begin
if v1 <= v2 then
Result := v1
else
Result := v2;
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);
hDib := CopyScreenToBitmap(FScreenRect, pData, @pVih.bmiHeader);
if (hDib <> 0) then
DeleteObject(hDib);
// 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);
Result := S_OK;
finally
FSharedState.UnLock;
end;
end;
function TBCPushPinDesktop.Notify(Filter: IBaseFilter; q: TQuality): HRESULT;
begin
Result := E_FAIL;
end;
// --- TBCPushSourceBitmap ------------
constructor TBCPushSourceDesktop.Create(ObjName: string; Unk: IUnKnown;
out hr: HRESULT);
begin
inherited Create(ObjName, Unk, CLSID_PushSourceDesktop);
// The pin magically adds itself to our pin array.
FPin := TBCPushPinDesktop.Create(hr, Self);
if (hr <> S_OK) then
if (FPin = nil) then
hr := E_OUTOFMEMORY;
end;
constructor TBCPushSourceDesktop.CreateFromFactory(Factory: TBCClassFactory;
const Controller: IUnknown);
var
hr: HRESULT;
begin
Create(Factory.Name, Controller, hr);
end;
destructor TBCPushSourceDesktop.Destroy;
begin
FreeAndNil(FPin);
inherited;
end;
initialization
// provide entries in the CFactoryTemplate array
TBCClassFactory.CreateFilter(TBCPushSourceBitmap, PushBitmapName,
CLSID_PushSourceBitmap, CLSID_LegacyAmFilterCategory,
MERIT_DO_NOT_USE, 1, @sudOutputPinBitmap
);
TBCClassFactory.CreateFilter(TBCPushSourceBitmapSet, PushBitmapSetName,
CLSID_PushSourceBitmapSet, CLSID_LegacyAmFilterCategory,
MERIT_DO_NOT_USE, 1, @sudOutputPinBitmapSet
);
TBCClassFactory.CreateFilter(TBCPushSourceDesktop, PushDesktopName,
CLSID_PushSourceDesktop, CLSID_LegacyAmFilterCategory,
MERIT_DO_NOT_USE, 1, @sudOutputPinDesktop
);
end.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -