5027 lines
188 KiB
Plaintext
5027 lines
188 KiB
Plaintext
(* ImageEn Build 7.0.0.06.2637 @ 7-4-17 14:58:42.679 *)
|
|
(*
|
|
Copyright (c) 1998-2017 by Carlotta Calandra. All rights reserved.
|
|
Copyright (c) 2011-2017 by Xequte Software.
|
|
|
|
This software comes without express or implied warranty.
|
|
In no case shall the author be liable for any damage or unwanted behavior of any
|
|
computer hardware and/or software.
|
|
|
|
Author grants you the right to include the component
|
|
in your application, whether COMMERCIAL, SHAREWARE, or FREEWARE.
|
|
|
|
ImageEn, IEvolution and ImageEn ActiveX may not be included in any
|
|
commercial, shareware or freeware libraries or components.
|
|
|
|
www.ImageEn.com
|
|
*)
|
|
|
|
(*
|
|
File version 1000
|
|
*)
|
|
|
|
|
|
unit iemmf;
|
|
|
|
|
|
{$R-}
|
|
{$Q-}
|
|
|
|
{$I ie.inc}
|
|
|
|
|
|
{$ifdef IEINCLUDEMEDIAFOUNDATION}
|
|
|
|
|
|
interface
|
|
|
|
|
|
uses Windows, Classes, Sysutils, Graphics, ActiveX, Contnrs, SyncObjs,
|
|
{$ifdef IEHASTYPES} Types, {$endif}
|
|
{$ifdef IEHASUITYPES} System.UITypes, {$endif}
|
|
hyieutils, hyiedefs, iewia, imageenproc, dialogs, iexBitmaps;
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// Windows Media Foundation interfaces
|
|
|
|
type IE_IMFAttributes = interface(IUnknown)
|
|
['{2cd2d921-c447-44a7-a13c-4adabfc247e3}']
|
|
function GetItem(const guidKey: TGUID; var pValue: PROPVARIANT): HRESULT; stdcall;
|
|
function GetItemType(const guidKey: TGUID; out pType: DWORD): HRESULT; stdcall;
|
|
function CompareItem(const guidKey: TGUID; const Value: PROPVARIANT; out pbResult: longbool): HRESULT; stdcall;
|
|
function Compare(pTheirs: IE_IMFAttributes; MatchType: DWORD; out pbResult: longbool): HRESULT; stdcall;
|
|
function GetUINT32(const guidKey: TGUID; out punValue: DWORD): HRESULT; stdcall;
|
|
function GetUINT64(const guidKey: TGUID; out punValue: uint64): HRESULT; stdcall;
|
|
function GetDouble(const guidKey: TGUID; out pfValue: double): HRESULT; stdcall;
|
|
function GetGUID(const guidKey: TGUID; out pguidValue: TGUID): HRESULT; stdcall;
|
|
function GetStringLength(const guidKey: TGUID; out pcchLength: DWORD): HRESULT; stdcall;
|
|
function GetString(const guidKey: TGUID; pwszValue: PWideChar; cchBufSize: DWORD; var pcchLength: DWORD): HRESULT; stdcall;
|
|
function GetAllocatedString(const guidKey: TGUID; out ppwszValue: PWideChar; out pcchLength: DWORD): HRESULT; stdcall;
|
|
function GetBlobSize(const guidKey: TGUID; out pcbBlobSize: DWORD): HRESULT; stdcall;
|
|
function GetBlob(const guidKey: TGUID; pBuf: pbyte; cbBufSize: DWORD; var pcbBlobSize: DWORD): HRESULT; stdcall;
|
|
function GetAllocatedBlob(const guidKey: TGUID; out ppBuf: pbyte; out pcbSize: DWORD): HRESULT; stdcall;
|
|
function GetUnknown(const guidKey: TGUID; const riid: TGUID; out ppv): HRESULT; stdcall;
|
|
function SetItem(const guidKey: TGUID; const Value: PROPVARIANT): HRESULT; stdcall;
|
|
function DeleteItem(const guidKey: TGUID): HRESULT; stdcall;
|
|
function DeleteAllItems(): HRESULT; stdcall;
|
|
function SetUINT32(const guidKey: TGUID; unValue: DWORD): HRESULT; stdcall;
|
|
function SetUINT64(const guidKey: TGUID; unValue: uint64): HRESULT; stdcall;
|
|
function SetDouble(const guidKey: TGUID; fValue: double): HRESULT; stdcall;
|
|
function SetGUID(const guidKey: TGUID; const guidValue: TGUID): HRESULT; stdcall;
|
|
function SetString(const guidKey: TGUID; wszValue: PWideChar): HRESULT; stdcall;
|
|
function SetBlob(const guidKey: TGUID; pBuf: pbyte; cbBufSize: DWORD): HRESULT; stdcall;
|
|
function SetUnknown(const guidKey: TGUID; pUnknown: IUnknown): HRESULT; stdcall;
|
|
function LockStore(): HRESULT; stdcall;
|
|
function UnlockStore(): HRESULT; stdcall;
|
|
function GetCount(out pcItems: DWORD): HRESULT; stdcall;
|
|
function GetItemByIndex(unIndex: DWORD; out pguidKey: TGUID; var pValue: PROPVARIANT): HRESULT; stdcall;
|
|
function CopyAllItems(pDest: IE_IMFAttributes): HRESULT; stdcall;
|
|
end;
|
|
|
|
|
|
type IE_IMFActivate = interface(IE_IMFAttributes)
|
|
['{7FEE9E9A-4A89-47a6-899C-B6A53A70FB67}']
|
|
function ActivateObject(const riid: TGUID; out ppv): HRESULT; stdcall;
|
|
function ShutdownObject(): HRESULT; stdcall;
|
|
function DetachObject(): HRESULT; stdcall;
|
|
end;
|
|
|
|
|
|
type IE_IMFMediaBuffer = interface(IUnknown)
|
|
['{045FA593-8799-42b8-BC8D-8968C6453507}']
|
|
function Lock(out ppbBuffer: pbyte; out pcbMaxLength: DWORD; out pcbCurrentLength: DWORD): HRESULT; stdcall;
|
|
function Unlock(): HRESULT; stdcall;
|
|
function GetCurrentLength(out pcbCurrentLength: DWORD): HRESULT; stdcall;
|
|
function SetCurrentLength(cbCurrentLength: DWORD): HRESULT; stdcall;
|
|
function GetMaxLength(out pcbMaxLength: DWORD): HRESULT; stdcall;
|
|
end;
|
|
|
|
|
|
const IE_IMF2DBuffer_GUID: TGUID = '{7DC9D5F9-9ED9-44ec-9BBF-0600BB589FBB}';
|
|
|
|
type IE_IMF2DBuffer = interface(IUnknown)
|
|
['{7DC9D5F9-9ED9-44ec-9BBF-0600BB589FBB}']
|
|
function Lock2D(out pbScanline0: pbyte; out plPitch: integer): HRESULT; stdcall;
|
|
function Unlock2D(): HRESULT; stdcall;
|
|
function GetScanline0AndPitch(out pbScanline0: pbyte; out plPitch: integer): HRESULT; stdcall;
|
|
function IsContiguousFormat(out pfIsContiguous: longbool): HRESULT; stdcall;
|
|
function GetContiguousLength(out pcbLength: DWORD): HRESULT; stdcall;
|
|
function ContiguousCopyTo(pbDestBuffer: pbyte; cbDestBuffer: DWORD): HRESULT; stdcall;
|
|
function ContiguousCopyFrom(pbSrcBuffer: pbyte; cbSrcBuffer: DWORD): HRESULT; stdcall;
|
|
end;
|
|
|
|
|
|
type IE_IMFSample = interface(IE_IMFAttributes)
|
|
['{c40a00f2-b93a-4d80-ae8c-5a1c634f58e4}']
|
|
function GetSampleFlags(out pdwSampleFlags: DWORD): HRESULT; stdcall;
|
|
function SetSampleFlags(dwSampleFlags: DWORD): HRESULT; stdcall;
|
|
function GetSampleTime(out phnsSampleTime: int64): HRESULT; stdcall;
|
|
function SetSampleTime(hnsSampleTime: int64): HRESULT; stdcall;
|
|
function GetSampleDuration(out phnsSampleDuration: int64): HRESULT; stdcall;
|
|
function SetSampleDuration(hnsSampleDuration: int64): HRESULT; stdcall;
|
|
function GetBufferCount(out pdwBufferCount: DWORD): HRESULT; stdcall;
|
|
function GetBufferByIndex(dwIndex: DWORD; out IE_IMFMediaBuffer): HRESULT; stdcall;
|
|
function ConvertToContiguousBuffer(out ppBuffer: IE_IMFMediaBuffer): HRESULT; stdcall;
|
|
function AddBuffer(pBuffer: IE_IMFMediaBuffer): HRESULT; stdcall;
|
|
function RemoveBufferByIndex(dwIndex: DWORD): HRESULT; stdcall;
|
|
function RemoveAllBuffers(): HRESULT; stdcall;
|
|
function GetTotalLength(out pcbTotalLength: DWORD): HRESULT; stdcall;
|
|
function CopyToBuffer(pBuffer: IE_IMFMediaBuffer): HRESULT; stdcall;
|
|
end;
|
|
|
|
|
|
type IE_IMFMediaEvent = interface(IE_IMFAttributes)
|
|
['{DF598932-F10C-4E39-BBA2-C308F101DAA3}']
|
|
function GetType(out pmet: DWORD): HRESULT; stdcall;
|
|
function GetExtendedType(out pguidExtendedType: TGUID): HRESULT; stdcall;
|
|
function GetStatus(out phrStatus: HRESULT): HRESULT; stdcall;
|
|
function GetValue(out pvValue: PROPVARIANT): HRESULT; stdcall;
|
|
end;
|
|
|
|
|
|
type IE_IMFSourceReaderCallback = interface(IUnknown)
|
|
['{deec8d99-fa1d-4d82-84c2-2c8969944867}']
|
|
function OnReadSample(hrStatus: HRESULT; dwStreamIndex: DWORD; dwStreamFlags: DWORD; llTimestamp: int64; pSample: IE_IMFSample): HRESULT; stdcall;
|
|
function OnFlush(dwStreamIndex: DWORD): HRESULT; stdcall;
|
|
function OnEvent(dwStreamIndex: DWORD; pEvent: IE_IMFMediaEvent): HRESULT; stdcall;
|
|
end;
|
|
|
|
|
|
type IE_IMFAsyncResult = interface(IUnknown)
|
|
['{ac6b7889-0740-4d51-8619-905994a55cc6}']
|
|
function GetState(out ppunkState: IUnknown): HRESULT; stdcall;
|
|
function GetStatus(): HRESULT; stdcall;
|
|
function SetStatus(hrStatus: HRESULT): HRESULT; stdcall;
|
|
function GetObject(out ppObject: IUnknown): HRESULT; stdcall;
|
|
function GetStateNoAddRef(): IUnknown;
|
|
end;
|
|
|
|
|
|
type IE_IMFAsyncCallback = interface(IUnknown)
|
|
['{a27003cf-2354-4f2a-8d6a-ab7cff15437e}']
|
|
function GetParameters(out pdwFlags: DWORD; out pdwQueue: DWORD): HRESULT; stdcall;
|
|
function Invoke(pAsyncResult: IE_IMFAsyncResult): HRESULT; stdcall;
|
|
end;
|
|
|
|
|
|
type IE_IMFMediaEventGenerator = interface(IUnknown)
|
|
['{2CD0BD52-BCD5-4B89-B62C-EADC0C031E7D}']
|
|
function GetEvent(dwFlags: DWORD; out ppEvent: IE_IMFMediaEvent): HRESULT; stdcall;
|
|
function BeginGetEvent(pCallback: IE_IMFAsyncCallback; punkState: IUnknown): HRESULT; stdcall;
|
|
function EndGetEvent(pResult: IE_IMFAsyncResult; out ppEvent: IE_IMFMediaEvent): HRESULT; stdcall;
|
|
function QueueEvent(met: DWORD; const guidExtendedType: TGUID; hrStatus: HRESULT; const pvValue: PROPVARIANT): HRESULT; stdcall;
|
|
end;
|
|
|
|
|
|
type IE_IMFMediaType = interface(IE_IMFAttributes)
|
|
['{44ae0fa8-ea31-4109-8d2e-4cae4997c555}']
|
|
function GetMajorType(out pguidMajorType: TGUID): HRESULT; stdcall;
|
|
function IsCompressedFormat(out pfCompressed: longbool): HRESULT; stdcall;
|
|
function IsEqual(pIMediaType: IE_IMFMediaType; out pdwFlags: DWORD): HRESULT; stdcall;
|
|
function GetRepresentation(guidRepresentation: TGUID; out ppvRepresentation: pointer): HRESULT; stdcall;
|
|
function FreeRepresentation(guidRepresentation: TGUID; pvRepresentation: pointer): HRESULT; stdcall;
|
|
end;
|
|
|
|
|
|
type IE_IMFMediaTypeHandler = interface(IUnknown)
|
|
['{e93dcf6c-4b07-4e1e-8123-aa16ed6eadf5}']
|
|
function IsMediaTypeSupported(pMediaType: IE_IMFMediaType; out ppMediaType: IE_IMFMediaType): HRESULT; stdcall;
|
|
function GetMediaTypeCount(out pdwTypeCount: DWORD): HRESULT; stdcall;
|
|
function GetMediaTypeByIndex(dwIndex: DWORD; out ppType: IE_IMFMediaType): HRESULT; stdcall;
|
|
function SetCurrentMediaType(pMediaType: IE_IMFMediaType): HRESULT; stdcall;
|
|
function GetCurrentMediaType(out ppMediaType: IE_IMFMediaType): HRESULT; stdcall;
|
|
function GetMajorType(out pguidMajorType: TGUID): HRESULT; stdcall;
|
|
end;
|
|
|
|
|
|
type IE_IMFStreamDescriptor = interface(IE_IMFAttributes)
|
|
['{56c03d9c-9dbb-45f5-ab4b-d80f47c05938}']
|
|
function GetStreamIdentifier(out pdwStreamIdentifier: DWORD): HRESULT; stdcall;
|
|
function GetMediaTypeHandler(out ppMediaTypeHandler: IE_IMFMediaTypeHandler): HRESULT; stdcall;
|
|
end;
|
|
|
|
|
|
type IE_IMFPresentationDescriptor = interface(IE_IMFAttributes)
|
|
['{03cb2711-24d7-4db6-a17f-f3a7a479a536}']
|
|
function GetStreamDescriptorCount(out pdwDescriptorCount: DWORD): HRESULT; stdcall;
|
|
function GetStreamDescriptorByIndex(dwIndex: DWORD; out pfSelected: longbool; out ppDescriptor: IE_IMFStreamDescriptor): HRESULT; stdcall;
|
|
function SelectStream(dwDescriptorIndex: DWORD): HRESULT; stdcall;
|
|
function DeselectStream(dwDescriptorIndex: DWORD): HRESULT; stdcall;
|
|
function Clone(out ppPresentationDescriptor: IE_IMFPresentationDescriptor): HRESULT; stdcall;
|
|
end;
|
|
|
|
|
|
const IE_IMFMediaSource_GUID: TGUID = '{279a808d-aec7-40c8-9c6b-a6b492c78a66}';
|
|
|
|
type IE_IMFMediaSource = interface(IE_IMFMediaEventGenerator)
|
|
['{279a808d-aec7-40c8-9c6b-a6b492c78a66}']
|
|
function GetCharacteristics(out pdwCharacteristics: DWORD): HRESULT; stdcall;
|
|
function CreatePresentationDescriptor(out ppPresentationDescriptor: IE_IMFPresentationDescriptor): HRESULT; stdcall;
|
|
function Start(pPresentationDescriptor: IE_IMFPresentationDescriptor; const pguidTimeFormat: TGUID; const pvarStartPosition: PROPVARIANT): HRESULT; stdcall;
|
|
function Stop(): HRESULT; stdcall;
|
|
function Pause(): HRESULT; stdcall;
|
|
function Shutdown(): HRESULT; stdcall;
|
|
end;
|
|
|
|
|
|
type IE_IMFSourceReader = interface(IUnknown)
|
|
['{70ae66f2-c809-4e4f-8915-bdcb406b7993}']
|
|
function GetStreamSelection(dwStreamIndex: DWORD; out pfSelected: longbool): HRESULT; stdcall;
|
|
function SetStreamSelection(dwStreamIndex: DWORD; fSelected: longbool): HRESULT; stdcall;
|
|
function GetNativeMediaType(dwStreamIndex: DWORD; dwMediaTypeIndex: DWORD; out ppMediaType: IE_IMFMediaType): HRESULT; stdcall;
|
|
function GetCurrentMediaType(dwStreamIndex: DWORD; out ppMediaType: IE_IMFMediaType): HRESULT; stdcall;
|
|
function SetCurrentMediaType(dwStreamIndex: DWORD; pdwReserved: PDWORD; pMediaType: IE_IMFMediaType): HRESULT; stdcall;
|
|
function SetCurrentPosition(const guidTimeFormat: TGUID; const varPosition: PROPVARIANT): HRESULT; stdcall;
|
|
function ReadSample(dwStreamIndex: DWORD; dwControlFlags: DWORD; out pdwActualStreamIndex: DWORD; out pdwStreamFlags: DWORD; out pllTimestamp: int64; var ppSample: IE_IMFSample): HRESULT; stdcall; // do not set ppSample as 'out'!
|
|
function Flush(dwStreamIndex: DWORD): HRESULT; stdcall;
|
|
function GetServiceForStream(dwStreamIndex: DWORD; const guidService: TGUID; const riid: TGUID; out ppvObject): HRESULT; stdcall;
|
|
function GetPresentationAttribute(dwStreamIndex: DWORD; const guidAttribute: TGUID; out pvarAttribute: PROPVARIANT): HRESULT; stdcall;
|
|
end;
|
|
|
|
|
|
type IE_IMFByteStream = interface(IUnknown)
|
|
['{ad4c1b00-4bf7-422f-9175-756693d9130d}']
|
|
function GetCapabilities(out pdwCapabilities: DWORD): HRESULT; stdcall;
|
|
function GetLength(out pqwLength: uint64): HRESULT; stdcall;
|
|
function SetLength(qwLength: uint64): HRESULT; stdcall;
|
|
function GetCurrentPosition(out pqwPosition: uint64): HRESULT; stdcall;
|
|
function SetCurrentPosition(qwPosition: uint64): HRESULT; stdcall;
|
|
function IsEndOfStream(out pfEndOfStream: longbool): HRESULT; stdcall;
|
|
function Read(pb: pbyte; cb: DWORD; out pcbRead: DWORD): HRESULT; stdcall;
|
|
function BeginRead(pb: pbyte; cb: DWORD; pCallback: IE_IMFAsyncCallback; punkState: IUnknown): HRESULT; stdcall;
|
|
function EndRead(pResult: IE_IMFAsyncResult; out pcbRead: DWORD): HRESULT; stdcall;
|
|
function Write(pb: pbyte; cb: DWORD; out pcbWritten: DWORD): HRESULT; stdcall;
|
|
function BeginWrite(pb: pbyte; cb: DWORD; pCallback: IE_IMFAsyncCallback; punkState: IUnknown): HRESULT; stdcall;
|
|
function EndWrite(pResult: IE_IMFAsyncResult; out pcbWritten: DWORD): HRESULT; stdcall;
|
|
function Seek(SeekOrigin: DWORD; llSeekOffset: int64; dwSeekFlags: DWORD; out pqwCurrentPosition: uint64): HRESULT; stdcall;
|
|
function Flush(): HRESULT; stdcall;
|
|
function Close(): HRESULT; stdcall;
|
|
end;
|
|
|
|
|
|
type IE_IMFStreamSink = interface(IE_IMFMediaEventGenerator)
|
|
['{0A97B3CF-8E7C-4a3d-8F8C-0C843DC247FB}']
|
|
function GetMediaSink({out ppMediaSink: IE_IMFMediaSink}): HRESULT; stdcall;
|
|
function GetIdentifier(out pdwIdentifier: DWORD): HRESULT; stdcall;
|
|
function GetMediaTypeHandler(out ppHandler: IE_IMFMediaTypeHandler): HRESULT; stdcall;
|
|
function ProcessSample(pSample: IE_IMFSample): HRESULT; stdcall;
|
|
function PlaceMarker(eMarkerType: DWORD; const pvarMarkerValue: PROPVARIANT; const pvarContextValue: PROPVARIANT): HRESULT; stdcall;
|
|
function Flush(): HRESULT; stdcall;
|
|
end;
|
|
|
|
|
|
type IE_IMFClock = interface(IUnknown)
|
|
['{2eb1e945-18b8-4139-9b1a-d5d584818530}']
|
|
function GetClockCharacteristics(out pdwCharacteristics: DWORD): HRESULT; stdcall;
|
|
function GetCorrelatedTime(dwReserved: DWORD; out pllClockTime: int64; out phnsSystemTime: int64): HRESULT; stdcall;
|
|
function GetContinuityKey(out pdwContinuityKey: DWORD): HRESULT; stdcall;
|
|
function GetState(dwReserved: DWORD; out peClockState: DWORD): HRESULT; stdcall;
|
|
function GetProperties({out pClockProperties: MFCLOCK_PROPERTIES}): HRESULT; stdcall;
|
|
end;
|
|
|
|
|
|
const IE_IMFPresentationTimeSource_GUID: TGUID = '{7FF12CCE-F76F-41c2-863B-1666C8E5E139}';
|
|
|
|
type IE_IMFPresentationTimeSource = interface(IE_IMFClock)
|
|
['{7FF12CCE-F76F-41c2-863B-1666C8E5E139}']
|
|
function GetUnderlyingClock(out ppClock: IE_IMFClock): HRESULT; stdcall;
|
|
end;
|
|
|
|
|
|
type IE_IMFClockStateSink = interface(IUnknown)
|
|
['{F6696E82-74F7-4f3d-A178-8A5E09C3659F}']
|
|
function OnClockStart(hnsSystemTime: int64; llClockStartOffset: int64): HRESULT; stdcall;
|
|
function OnClockStop(hnsSystemTime: int64): HRESULT; stdcall;
|
|
function OnClockPause(hnsSystemTime: int64): HRESULT; stdcall;
|
|
function OnClockRestart(hnsSystemTime: int64): HRESULT; stdcall;
|
|
function OnClockSetRate(hnsSystemTime: int64; flRate: single): HRESULT; stdcall;
|
|
end;
|
|
|
|
|
|
type IE_IMFPresentationClock = interface(IE_IMFClock)
|
|
['{868CE85C-8EA9-4f55-AB82-B009A910A805}']
|
|
function SetTimeSource(pTimeSource: IE_IMFPresentationTimeSource): HRESULT; stdcall;
|
|
function GetTimeSource(out ppTimeSource: IE_IMFPresentationTimeSource): HRESULT; stdcall;
|
|
function GetTime(out phnsClockTime: int64): HRESULT; stdcall;
|
|
function AddClockStateSink(pStateSink: IE_IMFClockStateSink): HRESULT; stdcall;
|
|
function RemoveClockStateSink(pStateSink: IE_IMFClockStateSink): HRESULT; stdcall;
|
|
function Start(llClockStartOffset: int64 ): HRESULT; stdcall;
|
|
function Stop(): HRESULT; stdcall;
|
|
function Pause(): HRESULT; stdcall;
|
|
end;
|
|
|
|
|
|
type IE_IMFMediaSink = interface(IUnknown)
|
|
['{6ef2a660-47c0-4666-b13d-cbb717f2fa2c}']
|
|
function GetCharacteristics(out pdwCharacteristics: DWORD): HRESULT; stdcall;
|
|
function AddStreamSink(dwStreamSinkIdentifier: DWORD; pMediaType: IE_IMFMediaType; out ppStreamSink: IE_IMFStreamSink): HRESULT; stdcall;
|
|
function RemoveStreamSink(dwStreamSinkIdentifier: DWORD): HRESULT; stdcall;
|
|
function GetStreamSinkCount(out pcStreamSinkCount: DWORD): HRESULT; stdcall;
|
|
function GetStreamSinkByIndex(dwIndex: DWORD; out ppStreamSink: IE_IMFStreamSink): HRESULT; stdcall;
|
|
function GetStreamSinkById(dwStreamSinkIdentifier: DWORD; out ppStreamSink: IE_IMFStreamSink): HRESULT; stdcall;
|
|
function SetPresentationClock(pPresentationClock: IE_IMFPresentationClock): HRESULT; stdcall;
|
|
function GetPresentationClock(out ppPresentationClock: IE_IMFPresentationClock): HRESULT; stdcall;
|
|
function Shutdown(): HRESULT; stdcall;
|
|
end;
|
|
|
|
|
|
type IE_IMFCollection = interface(IUnknown)
|
|
['{5BC8A76B-869A-46a3-9B03-FA218A66AEBE}']
|
|
function GetElementCount(out pcElements: DWORD): HRESULT; stdcall;
|
|
function GetElement(dwElementIndex: DWORD; out ppUnkElement: IUnknown): HRESULT; stdcall;
|
|
function AddElement(pUnkElement: IUnknown): HRESULT; stdcall;
|
|
function RemoveElement(dwElementIndex: DWORD; out ppUnkElement: IUnknown): HRESULT; stdcall;
|
|
function InsertElementAt(dwIndex: DWORD; pUnknown: IUnknown): HRESULT; stdcall;
|
|
function RemoveAllElements(): HRESULT; stdcall;
|
|
end;
|
|
|
|
|
|
type IE_MFT_INPUT_STREAM_INFO = packed record
|
|
hnsMaxLatency: int64;
|
|
dwFlags: DWORD;
|
|
cbSize: DWORD;
|
|
cbMaxLookahead: DWORD;
|
|
cbAlignment: DWORD;
|
|
end;
|
|
|
|
|
|
type IE_MFT_OUTPUT_STREAM_INFO = packed record
|
|
dwFlags: DWORD;
|
|
cbSize: DWORD;
|
|
cbAlignment: DWORD;
|
|
end;
|
|
|
|
|
|
type IE_MFT_OUTPUT_DATA_BUFFER = packed record
|
|
dwStreamID: DWORD;
|
|
pSample: IE_IMFSample;
|
|
dwStatus: DWORD;
|
|
pEvents: IE_IMFCollection;
|
|
end;
|
|
type PIE_MFT_OUTPUT_DATA_BUFFER = ^IE_MFT_OUTPUT_DATA_BUFFER;
|
|
|
|
|
|
const IE_IMFTransform_GUID: TGUID = '{bf94c121-5b05-4e6f-8000-ba598961414d}';
|
|
|
|
type IE_IMFTransform = interface(IUnknown)
|
|
['{bf94c121-5b05-4e6f-8000-ba598961414d}']
|
|
function GetStreamLimits(out pdwInputMinimum: DWORD; out pdwInputMaximum: DWORD; out pdwOutputMinimum: DWORD; out pdwOutputMaximum: DWORD): HRESULT; stdcall;
|
|
function GetStreamCount(out pcInputStreams: DWORD; out pcOutputStreams: DWORD): HRESULT; stdcall;
|
|
function GetStreamIDs(dwInputIDArraySize: DWORD; out pdwInputIDs: DWORD; dwOutputIDArraySize: DWORD; out pdwOutputIDs: DWORD): HRESULT; stdcall;
|
|
function GetInputStreamInfo(dwInputStreamID: DWORD; out pStreamInfo: IE_MFT_INPUT_STREAM_INFO): HRESULT; stdcall;
|
|
function GetOutputStreamInfo(dwOutputStreamID: DWORD; out pStreamInfo: IE_MFT_OUTPUT_STREAM_INFO): HRESULT; stdcall;
|
|
function GetAttributes(out pAttributes: IE_IMFAttributes): HRESULT; stdcall;
|
|
function GetInputStreamAttributes(dwInputStreamID: DWORD; out pAttributes: IE_IMFAttributes): HRESULT; stdcall;
|
|
function GetOutputStreamAttributes(dwOutputStreamID: DWORD; out pAttributes: IE_IMFAttributes): HRESULT; stdcall;
|
|
function DeleteInputStream(dwStreamID: DWORD): HRESULT; stdcall;
|
|
function AddInputStreams(cStreams: DWORD; adwStreamIDs: PDWORD): HRESULT; stdcall;
|
|
function GetInputAvailableType(dwInputStreamID: DWORD; dwTypeIndex: DWORD; out ppType: IE_IMFMediaType): HRESULT; stdcall;
|
|
function GetOutputAvailableType(dwOutputStreamID: DWORD; dwTypeIndex: DWORD; out ppType: IE_IMFMediaType): HRESULT; stdcall;
|
|
function SetInputType(dwInputStreamID: DWORD; pType: IE_IMFMediaType; dwFlags: DWORD): HRESULT; stdcall;
|
|
function SetOutputType(dwOutputStreamID: DWORD; pType: IE_IMFMediaType; dwFlags: DWORD): HRESULT; stdcall;
|
|
function GetInputCurrentType(dwInputStreamID: DWORD; out ppType: IE_IMFMediaType): HRESULT; stdcall;
|
|
function GetOutputCurrentType(dwOutputStreamID: DWORD; out ppType: IE_IMFMediaType): HRESULT; stdcall;
|
|
function GetInputStatus(dwInputStreamID: DWORD; out pdwFlags: DWORD): HRESULT; stdcall;
|
|
function GetOutputStatus(out pdwFlags: DWORD): HRESULT; stdcall;
|
|
function SetOutputBounds(hnsLowerBound: int64; hnsUpperBound: int64): HRESULT; stdcall;
|
|
function ProcessEvent(dwInputStreamID: DWORD; pEvent: IE_IMFMediaEvent): HRESULT; stdcall;
|
|
function ProcessMessage(eMessage: DWORD; ulParam: LPARAM): HRESULT; stdcall;
|
|
function ProcessInput(dwInputStreamID: DWORD; pSample: IE_IMFSample; dwFlags: DWORD): HRESULT; stdcall;
|
|
function ProcessOutput(dwFlags: DWORD; cOutputBufferCount: DWORD; pOutputSamples: PIE_MFT_OUTPUT_DATA_BUFFER; var pdwStatus: DWORD): HRESULT; stdcall;
|
|
end;
|
|
|
|
|
|
const IE_IWMResamplerProps_GUID: TGUID = '{E7E9984F-F09F-4da4-903F-6E2E0EFE56B5}';
|
|
|
|
type IE_IWMResamplerProps = interface(IUnknown)
|
|
['{E7E9984F-F09F-4da4-903F-6E2E0EFE56B5}']
|
|
function SetHalfFilterLength(lhalfFilterLen: integer): HRESULT; stdcall;
|
|
function SetUserChannelMtx(userChannelMtx: psingle): HRESULT; stdcall;
|
|
end;
|
|
|
|
|
|
const IE_IMFSourceReaderEx_GUID: TGUID = '{7b981cf0-560e-4116-9875-b099895f23d7}';
|
|
|
|
// Windows 8 and newer only!
|
|
type IE_IMFSourceReaderEx = interface(IE_IMFSourceReader)
|
|
['{7b981cf0-560e-4116-9875-b099895f23d7}']
|
|
function SetNativeMediaType(dwStreamIndex: DWORD; pMediaType: IE_IMFMediaType; out pdwStreamFlags: DWORD): HRESULT; stdcall;
|
|
function AddTransformForStream(dwStreamIndex: DWORD; pTransformOrActivate: IUnknown): HRESULT; stdcall;
|
|
function RemoveAllTransformsForStream(dwStreamIndex: DWORD): HRESULT; stdcall;
|
|
function GetTransformForStream(dwStreamIndex: DWORD; dwTransformIndex: DWORD; out pGuidCategory: TGUID; out ppTransform: IE_IMFTransform): HRESULT; stdcall;
|
|
end;
|
|
|
|
|
|
type IE_MFRECT = packed record
|
|
left: integer;
|
|
top: integer;
|
|
right: integer;
|
|
bottom: integer;
|
|
end;
|
|
|
|
|
|
const IE_IMFVideoProcessorControl_GUID: TGUID = '{A3F675D5-6119-4f7f-A100-1D8B280F0EFB}';
|
|
|
|
// Windows 8 and newer only!
|
|
type IE_IMFVideoProcessorControl = interface(IUnknown)
|
|
['{A3F675D5-6119-4f7f-A100-1D8B280F0EFB}']
|
|
function SetBorderColor(): HRESULT; stdcall;
|
|
function SetSourceRectangle(var pSrcRect: IE_MFRECT): HRESULT; stdcall;
|
|
function SetDestinationRectangle(var pDstRect: IE_MFRECT): HRESULT; stdcall;
|
|
function SetMirror(eMirror: DWORD): HRESULT; stdcall;
|
|
function SetRotation(eRotation: DWORD): HRESULT; stdcall;
|
|
function SetConstrictionSize(): HRESULT; stdcall;
|
|
end;
|
|
|
|
|
|
// Windows Media Foundation interfaces
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// TIEMMFDeviceList
|
|
|
|
type TIEMFDeviceList = class
|
|
private
|
|
m_devices: PPointerArray; // array of IE_IMFActivate objects
|
|
m_devicesCount: DWORD;
|
|
m_populated: boolean;
|
|
m_names: TStringList; // a copy of all device names as a TStringList object
|
|
public
|
|
constructor Create();
|
|
destructor Destroy(); override;
|
|
|
|
procedure Clear();
|
|
procedure Populate();
|
|
property Populated: boolean read m_populated;
|
|
|
|
function GetCount(): integer;
|
|
function GetName(index: integer): WideString;
|
|
function GetDevice(index: integer): IE_IMFActivate;
|
|
function GetNames(): TStringList;
|
|
end;
|
|
|
|
// TIEMFDeviceList
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// IIEMFCallbackHandler
|
|
|
|
type IIEMFCallbackHandler = interface(IInterface)
|
|
function OnReadSample(hrStatus: HRESULT; dwStreamIndex: DWORD; dwStreamFlags: DWORD; llTimestamp: int64; pSample: IE_IMFSample): HRESULT;
|
|
function OnFlush(dwStreamIndex: DWORD): HRESULT;
|
|
function OnEvent(dwStreamIndex: DWORD; pEvent: IE_IMFMediaEvent): HRESULT;
|
|
end;
|
|
|
|
// IIEMFCallbackHandler
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// TIEMFReceivedSample
|
|
|
|
{!!
|
|
<FS>TIEMFReceivedSample
|
|
|
|
<FM>Description<FN>
|
|
Represents a Media Foundation sample (video or audio).
|
|
|
|
<FM>Methods and Properties<FN>
|
|
<TABLE2>
|
|
<R> <C_IMG_METHOD> <C><A TIEMFReceivedSample.DecodeSample></C> </R>
|
|
<R> <C_IMG_PROPERTY> <C><A TIEMFReceivedSample.MediaType></C> </R>
|
|
<R> <C_IMG_PROPERTY> <C><A TIEMFReceivedSample.Sample></C> </R>
|
|
<R> <C_IMG_PROPERTY> <C><A TIEMFReceivedSample.StreamIndex></C> </R>
|
|
<R> <C_IMG_PROPERTY> <C><A TIEMFReceivedSample.StreamFlags></C> </R>
|
|
<R> <C_IMG_PROPERTY> <C><A TIEMFReceivedSample.StreamType></C> </R>
|
|
<R> <C_IMG_PROPERTY> <C><A TIEMFReceivedSample.TimeStamp></C> </R>
|
|
</TABLE>
|
|
!!}
|
|
type TIEMFReceivedSample = class
|
|
public
|
|
|
|
{!!
|
|
<FS>TIEMFReceivedSample.Sample
|
|
|
|
<FM>Declaration<FC>
|
|
Sample: IE_IMFSample;
|
|
|
|
<FM>Description<FN>
|
|
Contains the Media Foundation sample interface. See the <L http://msdn.microsoft.com/en-us/library/windows/desktop/ms702192(v=vs.85).aspx>MSDN documentation</L> for more info.
|
|
!!}
|
|
Sample: IE_IMFSample;
|
|
|
|
{!!
|
|
<FS>TIEMFReceivedSample.StreamIndex
|
|
|
|
<FM>Declaration<FC>
|
|
StreamIndex: DWORD;
|
|
|
|
<FM>Description<FN>
|
|
Contains the index of stream from where this sample comes.
|
|
!!}
|
|
StreamIndex: DWORD;
|
|
|
|
{!!
|
|
<FS>TIEMFReceivedSample.StreamFlags
|
|
|
|
<FM>Declaration<FC>
|
|
StreamFlags: DWORD;
|
|
|
|
<FM>Description<FN>
|
|
Media Foundation sample flags. See the <L http://msdn.microsoft.com/en-us/library/windows/desktop/dd375773(v=vs.85).aspx>MSDN documentation</L> for more info.
|
|
!!}
|
|
StreamFlags: DWORD;
|
|
|
|
{!!
|
|
<FS>TIEMFReceivedSample.TimeStamp
|
|
|
|
<FM>Declaration<FC>
|
|
TimeStamp: int64;
|
|
|
|
<FM>Description<FN>
|
|
The time stamp of the sample in 100 nanosecond units (There are 1 billion nanoseconds to a second).
|
|
|
|
<FM>See Also<FN>
|
|
- <A IEMediaFoundationTimeToStr>
|
|
- <A IEMediaFoundationTimeToSec>
|
|
!!}
|
|
TimeStamp: int64;
|
|
|
|
{!!
|
|
<FS>TIEMFReceivedSample.MediaType
|
|
|
|
<FM>Declaration<FC>
|
|
MediaType: IE_IMFMediaType;
|
|
|
|
<FM>Description<FN>
|
|
Media Foundation sample type. See the <L http://msdn.microsoft.com/en-us/library/ms704850(v=vs.85).aspx>MSDN documentation</L> for more info.
|
|
!!}
|
|
MediaType: IE_IMFMediaType;
|
|
|
|
{!!
|
|
<FS>TIEMFReceivedSample.StreamType
|
|
|
|
<FM>Declaration<FC>
|
|
StreamType: WideString;
|
|
|
|
<FM>Description<FN>
|
|
Returns a string representing the type of the stream. Can be any one of the values accepted by <A TIEMediaFoundationSourceReader.GetStreamType>.
|
|
!!}
|
|
StreamType: WideString;
|
|
|
|
constructor Create(sample: IE_IMFSample; streamIndex: DWORD; streamFlags: DWORD; timeStamp: int64; mediaType: IE_IMFMediaType);
|
|
destructor Destroy(); override;
|
|
function DecodeSample(destBitmap: TIEBitmap): boolean;
|
|
end;
|
|
|
|
// TIEMFReceivedSample
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// TIEMediaFoundationSourceReaderCallback
|
|
|
|
TIEMediaFoundationSourceReaderCallbackEventType = (mfrceONREADSAMPLE, mfrceONFLUSH, mfrceONEVENT);
|
|
|
|
TIEMediaFoundationSourceReaderCallbackEvent = function(event: TIEMediaFoundationSourceReaderCallbackEventType; hrStatus: HRESULT; dwStreamIndex: DWORD; dwStreamFlags: DWORD; llTimestamp: int64; pSample: IE_IMFSample; pEvent: IE_IMFMediaEvent): HRESULT of object;
|
|
|
|
type TIEMediaFoundationSourceReaderCallback = class(TInterfacedObject, IE_IMFSourceReaderCallback)
|
|
private
|
|
m_onCallBack: TIEMediaFoundationSourceReaderCallbackEvent;
|
|
public
|
|
constructor Create(OnCallBack: TIEMediaFoundationSourceReaderCallbackEvent);
|
|
protected
|
|
// IIEMFCallBackHandler implementation
|
|
function OnReadSample(hrStatus: HRESULT; dwStreamIndex: DWORD; dwStreamFlags: DWORD; llTimestamp: int64; pSample: IE_IMFSample): HRESULT; stdcall;
|
|
function OnFlush(dwStreamIndex: DWORD): HRESULT; stdcall;
|
|
function OnEvent(dwStreamIndex: DWORD; pEvent: IE_IMFMediaEvent): HRESULT; stdcall;
|
|
end;
|
|
|
|
// TIEMediaFoundationSourceReaderCallback
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// TIEMediaFoundationVideoSampleDecoder
|
|
|
|
{!!
|
|
<FS>TIEMediaFoundationVideoSampleDecoder
|
|
|
|
<FM>Declaration<FC>
|
|
type TIEMediaFoundationVideoSampleDecoder = class
|
|
public
|
|
function GetSubType(): WideString; virtual; abstract;
|
|
function Decode(width: DWORD; height: DWORD; stride: integer; buffer: pointer; bufferLen: DWORD; destBitmap: <A TIEBitmap>): boolean; virtual; abstract;
|
|
end;
|
|
|
|
<FM>Description<FN>
|
|
Applications can add new decoders by using <A IEMediaFoundationGetVideoSampleDecoders> and implementing this abstract class.
|
|
!!}
|
|
type TIEMediaFoundationVideoSampleDecoder = class
|
|
public
|
|
function GetSubType(): WideString; virtual; abstract;
|
|
function Decode(width: DWORD; height: DWORD; stride: integer; buffer: pointer; bufferLen: DWORD; destBitmap: TIEBitmap): boolean; virtual; abstract;
|
|
end;
|
|
|
|
// TIEMediaFoundationVideoSampleDecoder
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// IIEMediaFoundationReaderNotifyReceiver
|
|
|
|
{!!
|
|
<FS>IIEMediaFoundationReaderNotifyReceiver
|
|
|
|
<FM>Declaration<FC>
|
|
}
|
|
type IIEMediaFoundationReaderNotifyReceiver = interface
|
|
['{70E06CBA-1727-402B-857A-CC3679EDDC26}']
|
|
procedure ReceiveNotify(sender: TObject; notifyType: TIEMediaFountationNotifyType; dwStreamIndex: DWORD; dwStreamFlags: DWORD; llTimestamp: int64; pSample: IE_IMFSample; mediaType: IE_IMFMediaType; pEvent: IE_IMFMediaEvent);
|
|
end;
|
|
{!!}
|
|
|
|
// IIEMediaFoundationReaderNotifyReceiver
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// TIEMediaFoundationReaderWindowNotifyReceiver
|
|
// Just an helper for notifications sent by Windows messages
|
|
|
|
type TIEMediaFoundationReaderWindowNotifyReceiver = class(TInterfacedObject, IIEMediaFoundationReaderNotifyReceiver)
|
|
private
|
|
m_notifyWindow: THandle;
|
|
m_notifyMessage: DWORD;
|
|
public
|
|
constructor Create(notifyWindow: THandle; notifyMessage: DWORD);
|
|
destructor Destroy(); override;
|
|
procedure ReceiveNotify(sender: TObject; notifyType: TIEMediaFountationNotifyType; dwStreamIndex: DWORD; dwStreamFlags: DWORD; llTimestamp: int64; pSample: IE_IMFSample; mediaType: IE_IMFMediaType; pEvent: IE_IMFMediaEvent);
|
|
end;
|
|
|
|
// TIEMediaFoundationReaderWindowNotifyReceiver
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// TIEMediaFoundationAudioResampler
|
|
|
|
type TIEMediaFoundationAudioResampler = class
|
|
private
|
|
m_transform: IE_IMFTransform;
|
|
m_outputBufferSize: DWORD;
|
|
public
|
|
constructor Create();
|
|
destructor Destroy(); override;
|
|
|
|
function SetInputMediaType(mediaType: IE_IMFMediaType): boolean;
|
|
function SetOutputMediaType(mediaType: IE_IMFMediaType): boolean;
|
|
|
|
procedure Start();
|
|
procedure Stop();
|
|
|
|
function PushSample(sample: IE_IMFSample): boolean;
|
|
function GetSample(): IE_IMFSample;
|
|
end;
|
|
|
|
// TIEMediaFoundationAudioResampler
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// TIEMediaFoundationAudioRenderer
|
|
|
|
type TIEMediaFoundationAudioRendererRole = (
|
|
iemfarrECONSOLE = 0,
|
|
iemfarrEMULTIMEDIA = 1,
|
|
iemfarrECOMMUNICATIONS = 2);
|
|
|
|
|
|
{!!
|
|
<FS>TIEMediaFoundationAudioRenderer
|
|
|
|
<FM>Declaration<FC>
|
|
type TIEMediaFoundationAudioRenderer = class(TInterfacedObject, IIEMediaFoundationReaderNotifyReceiver);
|
|
|
|
<FM>Description<FN>
|
|
A wrapper for the Media Foundation audio renderer.
|
|
|
|
Applications can add a <FC>TIEMediaFoundationAudioRenderer<FN> as a notification receiver (see <A TIEMediaFoundationSourceReader.PushNotifyReceiver> method) in order to automatically render the audio stream.
|
|
|
|
Notes:
|
|
- Using TIEMediaFoundationAudioRenderer with <A TIEMediaFoundationSourceReader> may produce audio out of synchronization.
|
|
- The Audio renderer supports only PCM or Float media types, so applications should set the appropriate media type (see example).
|
|
|
|
<FM>Example<FC>
|
|
// Add the audio renderer
|
|
audioStreamindex := ImageEnView1.IO.MediaFoundationSourceReader.IndexOfFirstStream(mmf_AUDIO_STREAM);
|
|
ImageEnView1.IO.MediaFoundationSourceReader.SetSelectedStreams(audioStreamIndex, true);
|
|
ImageEnView1.IO.MediaFoundationSourceReader.SetMediaTypeAudio(audioStreamIndex, 'PCM');
|
|
ImageEnView1.IO.MediaFoundationSourceReader.PushNotifyReceiver( TIEMediaFoundationAudioRenderer.Create(audioStreamIndex) );
|
|
ImageEnView1.IO.MediaFoundationSourceReader.StartCapture();
|
|
|
|
// Remove the audio renderer
|
|
ImageEnView1.IO.MediaFoundationSourceReader.StopCapture();
|
|
ImageEnView1.IO.MediaFoundationSourceReader.PopNotifyReceiver();
|
|
|
|
<FM>See Also<FN>
|
|
- <A TIEMediaFoundationSourceReader.PopNotifyReceiver>
|
|
- <A TIEMediaFoundationSourceReader.PushNotifyReceiver>
|
|
!!}
|
|
type TIEMediaFoundationAudioRenderer = class(TInterfacedObject, IIEMediaFoundationReaderNotifyReceiver)
|
|
private
|
|
m_mediaSink: IE_IMFMediaSink;
|
|
m_streamSink: IE_IMFStreamSink;
|
|
m_presentationClock: IE_IMFPresentationClock;
|
|
m_streamIndex: DWORD;
|
|
m_resampler: TIEMediaFoundationAudioResampler;
|
|
public
|
|
constructor Create(streamIndex: DWORD; role: TIEMediaFoundationAudioRendererRole = iemfarrEMULTIMEDIA);
|
|
destructor Destroy(); override;
|
|
|
|
function SetMediaType(mediaType: IE_IMFMediaType): boolean;
|
|
procedure ReceiveNotify(sender: TObject; notifyType: TIEMediaFountationNotifyType; dwStreamIndex: DWORD; dwStreamFlags: DWORD; llTimestamp: int64; pSample: IE_IMFSample; mediaType: IE_IMFMediaType; pEvent: IE_IMFMediaEvent);
|
|
end;
|
|
|
|
// TIEMediaFoundationAudioRenderer
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// TIEMediaFoundationVideoProcessor
|
|
|
|
{!!
|
|
<FS>TIEMediaFoundationVideoProcessorMirror
|
|
|
|
<FM>Declaration<FC>
|
|
type TIEMediaFoundationVideoProcessorMirror = (mfpmNone = 0, mfpmHorizontal = 1, mfpmVertical = 2);
|
|
|
|
<TABLE>
|
|
<R> <H>Value</H> <H>Description</H> </R>
|
|
<R> <C><FC>mfpmNone<FN></C> <C>Do not flip the image.</C> </R>
|
|
<R> <C><FC>mfpmHorizontal<FN></C> <C>Flip the image horizontally.</C> </R>
|
|
<R> <C><FC>mfpmVertical<FN></C> <C>Flip the image vertically.</C> </R>
|
|
</TABLE>
|
|
!!}
|
|
type TIEMediaFoundationVideoProcessorMirror = (mfpmNone = 0, mfpmHorizontal = 1, mfpmVertical = 2);
|
|
|
|
{!!
|
|
<FS>TIEMediaFoundationVideoProcessorRotation
|
|
|
|
<FM>Declaration<FC>
|
|
type TIEMediaFoundationVideoProcessorRotation = (mfprNone = 0, mfprNormal = 1);
|
|
|
|
<TABLE>
|
|
<R> <H>Value</H> <H>Description</H> </R>
|
|
<R> <C><FC>mfprNone<FN></C> <C>Do not rotate the image.</C> </R>
|
|
<R> <C><FC>mfprNormal<FN></C> <C>Rotate the image to the correct viewing orientation.</C> </R>
|
|
</TABLE>
|
|
!!}
|
|
type TIEMediaFoundationVideoProcessorRotation = (mfprNone = 0, mfprNormal = 1);
|
|
|
|
{!!
|
|
<FS>TIEMediaFoundationVideoProcessor
|
|
|
|
<FM>Declaration<FC>
|
|
type TIEMediaFoundationVideoProcessor = class
|
|
|
|
<FM>Description<FN>
|
|
A wrapper for the Media Foundation Video Processor.
|
|
|
|
<FM>Example<FC>
|
|
// setup horizontal flip and automatic rotation
|
|
ImageEnView1.IO.MediaFoundationSourceReader.VideoProcessor.SetMirror(mfpmHorizontal);
|
|
ImageEnView1.IO.MediaFoundationSourceReader.VideoProcessor.SetRotation(mfprNormal);
|
|
ImageEnView1.IO.MediaFoundationSourceReader.StartCapture();
|
|
|
|
<FM>See Also<FN>
|
|
- <A TIEMediaFoundationSourceReader.VideoProcessor>
|
|
|
|
<FM>Methods and Properties<FN>
|
|
<TABLE2>
|
|
<R> <C_IMG_PROPERTY> <C><A TIEMediaFoundationVideoProcessor.IsAvailable></C> </R>
|
|
<R> <C_IMG_PROPERTY> <C><A TIEMediaFoundationVideoProcessor.SetDestinationRectangle></C> </R>
|
|
<R> <C_IMG_PROPERTY> <C><A TIEMediaFoundationVideoProcessor.SetMirror></C> </R>
|
|
<R> <C_IMG_PROPERTY> <C><A TIEMediaFoundationVideoProcessor.SetRotation></C> </R>
|
|
<R> <C_IMG_PROPERTY> <C><A TIEMediaFoundationVideoProcessor.SetSourceRectangle></C> </R>
|
|
</TABLE>
|
|
!!}
|
|
type TIEMediaFoundationVideoProcessor = class
|
|
private
|
|
m_transform: IE_IMFTransform;
|
|
m_control: IE_IMFVideoProcessorControl;
|
|
m_outputBufferSize: DWORD;
|
|
m_started: boolean;
|
|
m_mediaBuffer: IE_IMFMediaBuffer;
|
|
function GetIsAvailable(): boolean;
|
|
protected
|
|
function SetInputMediaType(mediaType: IE_IMFMediaType): boolean;
|
|
function SetOutputMediaType(mediaType: IE_IMFMediaType): boolean;
|
|
function GetOutputMediaType(): IE_IMFMediaType;
|
|
|
|
procedure Start();
|
|
procedure Stop();
|
|
property Started: boolean read m_started;
|
|
|
|
function PushSample(sample: IE_IMFSample): boolean; overload;
|
|
function PushSample(buffer: pointer; bufferLen: integer): boolean; overload;
|
|
function GetSample(): IE_IMFSample; overload;
|
|
procedure GetSample(destBuffer: pointer); overload;
|
|
public
|
|
constructor Create();
|
|
destructor Destroy(); override;
|
|
property IsAvailable: boolean read GetIsAvailable;
|
|
|
|
procedure SetSourceRectangle(rect: TRect);
|
|
procedure SetDestinationRectangle(rect: TRect);
|
|
procedure SetMirror(mirror: TIEMediaFoundationVideoProcessorMirror);
|
|
procedure SetRotation(rotation: TIEMediaFoundationVideoProcessorRotation);
|
|
end;
|
|
|
|
// TIEMediaFoundationVideoProcessor
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// TIEMediaFoundationSourceReader
|
|
//
|
|
// Using some Delphi versions (ie Delphi 7) combined with some Windows versions (ie Windows 8.1 64bit) it could be
|
|
// necessary to add a "OS Exception", otherwise you will get an exception exiting the application (like "Application-defined exception...").
|
|
// This happens only inside the IDE and you can avoid it adding an OS Exception (Debugger Options) with
|
|
// range $C000000D-$C000000D, with "User Program" and "Run Handlded" options enabled.
|
|
|
|
|
|
{!!
|
|
<FS>TIEMediaFoundationSourceReader
|
|
|
|
<FM>Description<FN>
|
|
Encapsulates Microsoft Media Foundation source reader object, allowing the capture of video and audio samples from a source.
|
|
|
|
Presently TIEMediaFoundationSourceReader can capture from video capture devices (webcams), files (all formats supported by Windows Media Player) and URLs.
|
|
|
|
To setup <FC>TIEMediaFoundationSourceReader<FN>, applications must specify a video/file source, a video/audio stream and a media type. Then call GetNextSample() to read samples (images) from the source.
|
|
<A TImageEnView> and <A TImageEnIO> embed a TIEMediaFoundationSourceReader object to simplify usage.
|
|
|
|
See the VideoCapture\MediaFoundation demos for usage samples.
|
|
|
|
TIEMediaFoundationSourceReader is available in Windows Vista and newer. We have tested to confirm compatibility with Windows 7, 8.1 and 10.
|
|
|
|
<IMG help_images\IEMediaFoundation_Grabbing.gif>
|
|
|
|
<FM>Demos<FN>
|
|
<TABLE2>
|
|
<R> <C_IMG_DEMO> <C>Demos\VideoCapture\MediaFoundationCam\MediaFoundationCam.dpr </C> </R>
|
|
<R> <C_IMG_DEMO> <C>Demos\VideoCapture\MediaFoundationFile\MediaFoundationFile.dpr </C> </R>
|
|
<R> <C_IMG_DEMO> <C>Demos\VideoCapture\MediaFoundationURL\MediaFoundationURL.dpr </C> </R>
|
|
</TABLE>
|
|
|
|
<FM>Example<FC>
|
|
// This is a minimal setup to capture from a webcam (the first webcam, using first proposed media type):
|
|
|
|
ImageEnView1.IO.MediaFoundationSourceReader.SetVideoInput(0); // select first video input (first webcam)
|
|
ImageEnView1.IO.MediaFoundationSourceReader.SetSelectedStreams('Video', true); // enable first video stream
|
|
ImageEnView1.IO.MediaFoundationSourceReader.SelectMediaType(mmf_VIDEO_STREAM, 0); // select first media type of the first video stream
|
|
ImageEnView1.IO.MediaFoundationSourceReader.StartCapture(); // start capture
|
|
|
|
// handler for TImageEnView.OnMediaFoundatioNotify event
|
|
procedure TForm1.ImageEnVect1MediaFoundationNotify(Sender, MediaFoundationObject: TObject; NotifyType: TIEMediaFountationNotifyType);
|
|
var
|
|
sample: TIEMFReceivedSample;
|
|
begin
|
|
if NotifyType = iemfnFRAME then // is this a frame?
|
|
begin
|
|
sample := ImageEnView1.IO.MediaFoundationSourceReader.GetNextSample(); // retrieve frame sample
|
|
try
|
|
sample.DecodeSample(ImageEnView1.IEBitmap); // convert frame sample to bitmap
|
|
ImageEnView1.Update(); // update TImageEnView to show the new bitmap
|
|
finally
|
|
sample.Free(); // free the sample
|
|
end;
|
|
end;
|
|
end;
|
|
<FN>
|
|
|
|
<FM>Methods and Properties<FN>
|
|
<FI>Media Foundation Availability<FN>
|
|
<TABLE2>
|
|
<R> <C_IMG_PROPERTY> <C><A TIEMediaFoundationSourceReader.IsAvailable></C> </R>
|
|
</TABLE>
|
|
|
|
<FI>Events/Frame Notification<FN>
|
|
<TABLE2>
|
|
<R> <C_IMG_METHOD> <C><A TIEMediaFoundationSourceReader.ClearNotifyReceivers></C> </R>
|
|
<R> <C_IMG_METHOD> <C><A TIEMediaFoundationSourceReader.PopNotifyReceiver></C> </R>
|
|
<R> <C_IMG_METHOD> <C><A TIEMediaFoundationSourceReader.PushNotifyReceiver></C> </R>
|
|
</TABLE>
|
|
|
|
<FI>Video Input Information<FN>
|
|
<TABLE2>
|
|
<R> <C_IMG_METHOD> <C><A TIEMediaFoundationSourceReader.UpdateVideoInputs></C> </R>
|
|
<R> <C_IMG_PROPERTY> <C><A TIEMediaFoundationSourceReader.VideoInputs></C> </R>
|
|
</TABLE>
|
|
|
|
<FI>Video Input Selection<FN>
|
|
<TABLE2>
|
|
<R> <C_IMG_METHOD> <C><A TIEMediaFoundationSourceReader.SetVideoInput></C> </R>
|
|
</TABLE>
|
|
|
|
<FI>File Input Selection<FN>
|
|
<TABLE2>
|
|
<R> <C_IMG_METHOD> <C><A TIEMediaFoundationSourceReader.SetFileInput></C> </R>
|
|
</TABLE>
|
|
|
|
<FI>URL Input Selection<FN>
|
|
<TABLE2>
|
|
<R> <C_IMG_METHOD> <C><A TIEMediaFoundationSourceReader.SetURLInput></C> </R>
|
|
</TABLE>
|
|
|
|
<FI>Stream Information<FN>
|
|
<TABLE2>
|
|
<R> <C_IMG_METHOD> <C><A TIEMediaFoundationSourceReader.GetStreamType></C> </R>
|
|
<R> <C_IMG_METHOD> <C><A TIEMediaFoundationSourceReader.IndexOfFirstStream></C> </R>
|
|
<R> <C_IMG_PROPERTY> <C><A TIEMediaFoundationSourceReader.StreamCount></C> </R>
|
|
</TABLE>
|
|
|
|
<FI>Stream Selection<FN>
|
|
<TABLE2>
|
|
<R> <C_IMG_METHOD> <C><A TIEMediaFoundationSourceReader.SetSelectedStreams></C> </R>
|
|
</TABLE>
|
|
|
|
<FI>Media Type Information<FN>
|
|
<TABLE2>
|
|
<R> <C_IMG_METHOD> <C><A TIEMediaFoundationSourceReader.GetMediaType></C> </R>
|
|
<R> <C_IMG_METHOD> <C><A TIEMediaFoundationSourceReader.GetMediaTypesCount></C> </R>
|
|
</TABLE>
|
|
|
|
<FI>Media Type Selection (for native media type selection)<FN>
|
|
<TABLE2>
|
|
<R> <C_IMG_METHOD> <C><A TIEMediaFoundationSourceReader.SelectMediaType></C> </R>
|
|
</TABLE>
|
|
|
|
<FI>Media Type Setting (for custom media types)<FN>
|
|
<TABLE2>
|
|
<R> <C_IMG_METHOD> <C><A TIEMediaFoundationSourceReader.SetMediaTypeAudio></C> </R>
|
|
<R> <C_IMG_METHOD> <C><A TIEMediaFoundationSourceReader.SetMediaTypeCustom></C> </R>
|
|
<R> <C_IMG_METHOD> <C><A TIEMediaFoundationSourceReader.SetMediaTypeVideo></C> </R>
|
|
</TABLE>
|
|
|
|
<FI>Current Media Type Info<FN>
|
|
<TABLE2>
|
|
<R> <C_IMG_METHOD> <C><A TIEMediaFoundationSourceReader.GetCurrentMediaType></C> </R>
|
|
</TABLE>
|
|
|
|
<FI>Seeking<FN>
|
|
<TABLE2>
|
|
<R> <C_IMG_PROPERTY> <C><A TIEMediaFoundationSourceReader.Duration></C> </R>
|
|
<R> <C_IMG_METHOD> <C><A TIEMediaFoundationSourceReader.SetPosition></C> </R>
|
|
</TABLE>
|
|
|
|
<FI>Capture Control<FN>
|
|
<TABLE2>
|
|
<R> <C_IMG_PROPERTY> <C><A TIEMediaFoundationSourceReader.Capturing></C> </R>
|
|
<R> <C_IMG_METHOD> <C><A TIEMediaFoundationSourceReader.Flush></C> </R>
|
|
<R> <C_IMG_METHOD> <C><A TIEMediaFoundationSourceReader.PauseCapture></C> </R>
|
|
<R> <C_IMG_METHOD> <C><A TIEMediaFoundationSourceReader.ResumeCapture></C> </R>
|
|
<R> <C_IMG_METHOD> <C><A TIEMediaFoundationSourceReader.StartCapture></C> </R>
|
|
<R> <C_IMG_METHOD> <C><A TIEMediaFoundationSourceReader.StopCapture></C> </R>
|
|
</TABLE>
|
|
|
|
<FI>Sample Capture<FN>
|
|
<TABLE2>
|
|
<R> <C_IMG_METHOD> <C><A TIEMediaFoundationSourceReader.GetNextSample></C> </R>
|
|
<R> <C_IMG_PROPERTY> <C><A TIEMediaFoundationSourceReader.SamplesBufferSize></C> </R>
|
|
<R> <C_IMG_PROPERTY> <C><A TIEMediaFoundationSourceReader.DiscardAudioSamples></C> </R>
|
|
</TABLE>
|
|
|
|
<FI>Video Processing<FN>
|
|
<TABLE2>
|
|
<R> <C_IMG_METHOD> <C><A TIEMediaFoundationSourceReader.VideoProcessor></C> </R>
|
|
</TABLE>
|
|
!!}
|
|
type TIEMediaFoundationSourceReader = class
|
|
private
|
|
m_lock: TCriticalSection;
|
|
m_isAvailable: boolean;
|
|
m_videoInputs: TIEMFDeviceList;
|
|
m_notifyReceivers: TInterfaceList; // a list of IIEMediaFoundationReaderNotifyReceiver interfaces
|
|
m_capturing: boolean;
|
|
m_receivedSamples: TObjectList; // samples received on async mode (list of TIEMFReceivedSample objects);
|
|
m_firstTimeStamp: int64;
|
|
m_delayFramePost: boolean;
|
|
m_frameRequested: integer; // increased by ReadSample() and decreased by SourceReaderCallback()
|
|
m_source: IE_IMFMediaSource;
|
|
m_sourceReader: IE_IMFSourceReader;
|
|
m_streams: TObjectList; // each m_streams[] item contains another TObjectList, which finally contains a TIEDictionary object with the mediatype attributes
|
|
m_selectedMediaType: TObjectList; // each m_selectedMediaType contains a TIEDictionary object with the current mediatype (maybe not one of m_streams[][] mediatypes)
|
|
m_selectedActivate: IE_IMFActivate; // set by SetSource()
|
|
m_duration: int64;
|
|
m_videoProcessor: TIEMediaFoundationVideoProcessor; // video processor (Win8 only)
|
|
m_samplesBufferSize: integer;
|
|
m_discardAudioSamples: boolean;
|
|
|
|
protected
|
|
procedure PopulateStreams();
|
|
procedure PopulateSelectedMediaType();
|
|
function GetStreamCount(): integer;
|
|
function GetDuration(): int64;
|
|
function GetVideoInputs(): TStringList;
|
|
procedure CheckVideoInputsPopulated();
|
|
procedure CheckVideoInputIndex(index: integer);
|
|
function IsAsyncMode(): boolean;
|
|
function AddReceivedSample(sample: TIEMFReceivedSample): TIEMFReceivedSample;
|
|
function PopReceivedSample(streamIndex: DWORD): TIEMFReceivedSample;
|
|
procedure ClearReceivedSamples();
|
|
function SourceReaderCallback(event: TIEMediaFoundationSourceReaderCallbackEventType; hrStatus: HRESULT; dwStreamIndex: DWORD; dwStreamFlags: DWORD; llTimestamp: int64; pSample: IE_IMFSample; pEvent: IE_IMFMediaEvent): HRESULT;
|
|
function ReadSample(streamIndex: DWORD): boolean; overload;
|
|
function ReadSample(streamType: WideString): TIEMFReceivedSample; overload;
|
|
procedure DrainSamples();
|
|
function SetInput(activate: IE_IMFActivate): boolean;
|
|
procedure SendNotify(notifyType: TIEMediaFountationNotifyType; dwStreamIndex: DWORD; dwStreamFlags: DWORD; llTimestamp: int64; pSample: IE_IMFSample; mediaType: IE_IMFMediaType; pEvent: IE_IMFMediaEvent);
|
|
function GetCurrentMediaTypeIntf(streamIndex: integer): IE_IMFMediaType; overload;
|
|
function GetCurrentMediaTypeIntf(streamType: WideString): IE_IMFMediaType; overload;
|
|
function GetCapturing(): boolean;
|
|
procedure DoVideoProcessing(var mediaType: IE_IMFMediaType; var sample: IE_IMFSample);
|
|
procedure SetupVideoProcessing();
|
|
procedure FinalizeVideoProcessing();
|
|
function GetVideoProcessor(): TIEMediaFoundationVideoProcessor;
|
|
procedure SetSamplesBufferSize(value: integer);
|
|
|
|
public
|
|
constructor Create();
|
|
destructor Destroy(); override;
|
|
|
|
procedure Lock();
|
|
procedure Unlock();
|
|
|
|
// Media foundation availability
|
|
{!!
|
|
<FS>TIEMediaFoundationSourceReader.IsAvailable
|
|
|
|
<FM>Declaration<FC>
|
|
property IsAvailable: boolean;
|
|
|
|
<FM>Description<FN>
|
|
Returns True if Media Foundation is available.
|
|
|
|
TIEMediaFoundationSourceReader has been tested to work with Windows 7, 8.1 and 10.
|
|
!!}
|
|
property IsAvailable: boolean read m_isAvailable;
|
|
|
|
// Events/frames notification
|
|
procedure PushNotifyReceiver(notifyReceiver: IIEMediaFoundationReaderNotifyReceiver);
|
|
procedure PopNotifyReceiver();
|
|
procedure ClearNotifyReceivers();
|
|
|
|
// Video inputs info
|
|
property VideoInputs: TStringList read GetVideoInputs;
|
|
procedure UpdateVideoInputs();
|
|
|
|
// Video inputs selection
|
|
function SetVideoInput(index: integer): boolean; overload;
|
|
function SetVideoInput(name: WideString): boolean; overload;
|
|
|
|
// File input selection
|
|
function SetFileInput(filename: WideString): boolean;
|
|
|
|
// URL input selection
|
|
function SetURLInput(URL: WideString): boolean;
|
|
|
|
// Streams info
|
|
property StreamCount: integer read GetStreamCount;
|
|
function IndexOfFirstStream(streamType: WideString): integer;
|
|
function GetStreamType(streamIndex: integer): WideString;
|
|
|
|
// Streams selection
|
|
procedure SetSelectedStreams(streamIndex: integer; selected: boolean); overload;
|
|
procedure SetSelectedStreams(streamType: WideString; selected: boolean); overload;
|
|
|
|
// Media types info
|
|
function GetMediaTypesCount(streamIndex: integer): integer; overload;
|
|
function GetMediaTypesCount(streamType: WideString): integer; overload;
|
|
function GetMediaType(streamIndex: integer; mediaTypeIndex: integer): TIEDictionary; overload;
|
|
function GetMediaType(streamType: WideString; mediaTypeIndex: integer): TIEDictionary; overload;
|
|
|
|
// Media types selection (for native media types selection)
|
|
function SelectMediaType(streamIndex: integer; mediaTypeIndex: integer): boolean; overload;
|
|
function SelectMediaType(streamType: WideString; mediaTypeIndex: integer): boolean; overload;
|
|
|
|
// Media type setting (for custom media types)
|
|
function SetMediaTypeCustom(streamIndex: integer; jsonDescription: WideString): boolean; overload;
|
|
function SetMediaTypeCustom(streamType: WideString; jsonDescription: WideString): boolean; overload;
|
|
function SetMediaTypeVideo(streamIndex: integer; subTypeStr: WideString; frameWidth: integer = 0; frameHeight: integer = 0; frameRate: double = 0.0; videoLighting: WideString = ''): boolean; overload;
|
|
function SetMediaTypeVideo(subTypeStr: WideString; frameWidth: integer = 0; frameHeight: integer = 0; frameRate: double = 0.0; videoLighting: WideString = ''): boolean; overload;
|
|
function SetMediaTypeAudio(streamIndex: integer; subTypeStr: WideString): boolean; overload;
|
|
function SetMediaTypeAudio(subTypeStr: WideString): boolean; overload;
|
|
|
|
// Current media type info
|
|
function GetCurrentMediaType(streamIndex: integer): TIEDictionary; overload;
|
|
function GetCurrentMediaType(streamType: WideString): TIEDictionary; overload;
|
|
|
|
// Seeking
|
|
procedure SetPosition(position: int64);
|
|
property Duration: int64 read m_duration;
|
|
|
|
// Capture control
|
|
function StartCapture(): boolean;
|
|
function PauseCapture(): boolean;
|
|
procedure ResumeCapture();
|
|
procedure StopCapture();
|
|
procedure Flush();
|
|
property Capturing: boolean read GetCapturing;
|
|
|
|
// Sample capture
|
|
function GetNextSample(): TIEMFReceivedSample;
|
|
property SamplesBufferSize: integer read m_samplesBufferSize write SetSamplesBufferSize;
|
|
|
|
{!!
|
|
<FS>TIEMediaFoundationSourceReader.DiscardAudioSamples
|
|
|
|
<FM>Declaration<FC>
|
|
property DiscardAudioSamples: boolean;
|
|
|
|
<FM>Description<FN>
|
|
If True, only video samples are sent back to the <A TImageEnView.OnMediaFoundationNotify> event.
|
|
|
|
Default: True
|
|
!!}
|
|
property DiscardAudioSamples: boolean read m_discardAudioSamples write m_discardAudioSamples;
|
|
|
|
// Additional processing
|
|
property VideoProcessor: TIEMediaFoundationVideoProcessor read GetVideoProcessor;
|
|
|
|
end;
|
|
|
|
// TIEMediaFoundationSourceReader
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
const
|
|
IEMAJORTYPE_DICT_KEY: WideString = 'MajorType'; // contains MF_MT_MAJOR_TYPE (string)
|
|
IESUBTYPE_DICT_KEY: WideString = 'SubType'; // contains MF_MT_SUBTYPE (string)
|
|
IECOMPRESSED_DICT_KEY: WideString = 'Compressed'; // contains MF_MT_COMPRESSED (boolean)
|
|
IEAVGBITRATE_DICT_KEY: WideString = 'AvgBitrate'; // contains MF_MT_AVG_BITRATE (integer)
|
|
IEDEFAULTSTRIDE_DICT_KEY: WideString = 'DefaultStride'; // contains MF_MT_DEFAULT_STRIDE (integer)
|
|
IEFRAMERATE_DICT_KEY: WideString = 'FrameRate'; // contains MF_MT_FRAME_RATE (double)
|
|
IEFRAMERATEMAX_DICT_KEY: WideString = 'FrameRateMax'; // contains MF_MT_FRAME_RATE_RANGE_MAX (double)
|
|
IEFRAMERATEMIN_DICT_KEY: WideString = 'FrameRateMin'; // contains MF_MT_FRAME_RATE_RANGE_MIN (double)
|
|
IEFRAMEWIDTH_DICT_KEY: WideString = 'FrameWidth'; // contains MF_MT_FRAME_SIZE (high dword) (integer)
|
|
IEFRAMEHEIGHT_DICT_KEY: WideString = 'FrameHeight'; // contains MF_MT_FRAME_SIZE (low dword) (integer)
|
|
IEINTERLACEMODE_DICT_KEY: WideString = 'InterlaceMode'; // contains MF_MT_INTERLACE_MODE (string)
|
|
IEVIDEOLIGHTING_DICT_KEY: WideString = 'VideoLighting'; // contains MF_MT_VIDEO_LIGHTING (string)
|
|
IEAUDIOBITSPERSAMPLE_DICT_KEY: WideString = 'AudioBitsPerSample'; // contains MF_MT_AUDIO_BITS_PER_SAMPLE (integer)
|
|
IEAUDIOFLOATSAMPLESPERSECOND_DICT_KEY: WideString = 'AudioFloatSamplesPerSecond'; // contains MF_MT_AUDIO_FLOAT_SAMPLES_PER_SECOND (double)
|
|
IEAUDIONUMCHANNELS_DICT_KEY: WideString = 'AudioNumChannels'; // contains MF_MT_AUDIO_NUM_CHANNELS (integer)
|
|
IEAUDIOSAMPLESPERSECOND_DICT_KEY: WideString = 'AudioSamplesPerSecond'; // contains MF_MT_AUDIO_SAMPLES_PER_SECOND (integer)
|
|
IEAUDIOBLOCKALIGNMENT_DICT_KEY: WideString = 'AudioBlockAlignment'; // contains MF_MT_AUDIO_BLOCK_ALIGNMENT (integer)
|
|
IEALLSAMPLESINDEPENDENT_DICT_KEY: WideString = 'AllSamplesIndependent'; // contains MF_MT_ALL_SAMPLES_INDEPENDENT (boolean)
|
|
IEAUDIOPREFERWAVEFORMATEX_DICT_KEY: WideString = 'AudioPreferWaveFormatEx'; // contains MF_MT_AUDIO_PREFER_WAVEFORMATEX (boolean)
|
|
IEAUDIOAVGBYTESPERSECOND_DICT_KEY: WideString = 'AudioAvgBytesPerSecond'; // contains MF_MT_AUDIO_AVG_BYTES_PER_SECOND (integer)
|
|
IEVIDEOROTATION_DICT_KEY: WideString = 'VideoRotation'; // contains MF_MT_VIDEO_ROTATION (integer)
|
|
IEPIXELASPECTRATIO_DICT_KEY: WideString = 'PixelAspectRatio'; // contains MF_MT_PIXEL_ASPECT_RATIO (string)
|
|
IESOURCECONTENTHINT_DICT_KEY: WideString = 'SourceContentHint'; // contains MF_MT_SOURCE_CONTENT_HINT (string: 'None', '16:9', '2.35:1')
|
|
|
|
|
|
// helpers
|
|
function IEMediaFoundationGetVideoSampleDecoders(): TObjectList;
|
|
function IEMediaFoundationTimeToStr(time: int64): string;
|
|
function IEMediaFoundationTimeToSec(time: int64): Double;
|
|
function IESecToMediaFoundationTime(sec: Double): int64;
|
|
|
|
const
|
|
// STREAM TYPES
|
|
mmf_ANY_STREAM = 'Any';
|
|
mmf_VIDEO_STREAM = 'Video';
|
|
mmf_AUDIO_STREAM = 'Audio';
|
|
mmf_PROTECTED_STREAM = 'Protected';
|
|
mmf_SAMI_STREAM = 'SAMI';
|
|
mmf_SCRIPT_STREAM = 'Script';
|
|
mmf_IMAGE_STREAM = 'Image';
|
|
mmf_HTML_STREAM = 'HTML';
|
|
mmf_BINARY_STREAM = 'Binary';
|
|
mmf_FILETRANSFER_STREAM = 'FileTransfer';
|
|
|
|
// VIDEO STREAM FORMATS
|
|
mmf_VideoFormat_RGB8 = 'RGB8';
|
|
mmf_VideoFormat_RGB555 = 'RGB555';
|
|
mmf_VideoFormat_RGB565 = 'RGB565';
|
|
mmf_VideoFormat_RGB24 = 'RGB24';
|
|
mmf_VideoFormat_RGB32 = 'RGB32';
|
|
mmf_VideoFormat_ARGB32 = 'ARGB32';
|
|
|
|
// AUDIO STREAM FORMATS
|
|
mmf_AudioFormat_PCM = 'PCM';
|
|
mmf_AudioFormat_Float = 'Float';
|
|
mmf_AudioFormat_DTS = 'DTS';
|
|
mmf_AudioFormat_Dolby_AC3_SPDIF = 'Dolby_AC3_SPDIF';
|
|
mmf_AudioFormat_DRM = 'DRM';
|
|
mmf_AudioFormat_WMAudioV8 = 'WMAudioV8';
|
|
mmf_AudioFormat_WMAudioV9 = 'WMAudioV9';
|
|
mmf_AudioFormat_WMAudio_Lossless = 'WMAudio_Lossless';
|
|
mmf_AudioFormat_WMASPDIF = 'WMASPDIF';
|
|
mmf_AudioFormat_MSP1 = 'MSP1';
|
|
mmf_AudioFormat_MP3 = 'MP3';
|
|
mmf_AudioFormat_MPEG = 'MPEG';
|
|
mmf_AudioFormat_AAC = 'AAC';
|
|
mmf_AudioFormat_ADTS = 'ADTS';
|
|
|
|
|
|
implementation
|
|
|
|
uses
|
|
TypInfo;
|
|
|
|
|
|
|
|
const
|
|
MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE: TGUID = (D1: $c60ac5fe; D2: $252a; D3: $478f; D4: ($a0, $ef, $bc, $8f, $a5, $f7, $ca, $d3));
|
|
MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_GUID: TGUID = (D1: $8ac3587a; D2: $4ae7; D3: $42d8; D4: ($99, $e0, $0a, $60, $13, $ee, $f9, $0f));
|
|
MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_AUDCAP_GUID: TGUID = (D1: $14dd9a1c; D2: $7cff; D3: $41be; D4: ($b1, $b9, $ba, $1a, $c6, $ec, $b5, $71));
|
|
MF_DEVSOURCE_ATTRIBUTE_FRIENDLY_NAME: TGUID = (D1: $60d0e559; D2: $52f8; D3: $4fa2; D4: ($bb, $ce, $ac, $db, $34, $a8, $ec, $1));
|
|
MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_SYMBOLIC_LINK: TGUID = (D1: $58f0aad8; D2: $22bf; D3: $4f8a; D4: ($bb, $3d, $d2, $c4, $97, $8c, $6e, $2f));
|
|
MF_SOURCE_READER_ASYNC_CALLBACK: TGUID = (D1: $1e3dbeac; D2: $bb43; D3: $4c35; D4: ($b5, $07, $cd, $64, $44, $64, $c9, $65));
|
|
MF_SOURCE_READER_ENABLE_VIDEO_PROCESSING: TGUID = (D1: $fb394f3d; D2: $ccf1; D3: $42ee; D4: ($bb, $b3, $f9, $b8, $45, $d5, $68, $1d));
|
|
MF_READWRITE_ENABLE_HARDWARE_TRANSFORMS: TGUID = (D1: $a634a91c; D2: $822b; D3: $41b9; D4: ($a4, $94, $4d, $e4, $64, $36, $12, $b0));
|
|
MF_AUDIO_RENDERER_ATTRIBUTE_ENDPOINT_ROLE: TGUID = (D1: $6ba644ff; D2: $27c5; D3: $4d02; D4: ($98, $87, $c2, $86, $19, $fd, $b9, $1b));
|
|
|
|
IID_IUnknown: TGUID = '{00000000-0000-0000-C000-000000000046}';
|
|
CLSID_CResamplerMediaObject: TGUID = '{f447b69e-1884-4a7e-8055-346f74d6edb3}';
|
|
CLSID_VideoProcessorMFT: TGUID = '{88753b26-5b24-49bd-b2e7-0c445c78c982}';
|
|
|
|
|
|
// Media Type Attributes
|
|
MF_MT_MAJOR_TYPE: TGUID = '{48eba18e-f8c9-4687-bf11-0a74c9f96a8f}'; // {GUID}
|
|
MF_MT_SUBTYPE: TGUID = '{f7e34c9a-42e8-4714-b74b-cb29d72c35e5}'; // {GUID}
|
|
MF_MT_COMPRESSED: TGUID = '{3afd0cee-18f2-4ba5-a110-8bea502e1f92}'; // {UINT32 (BOOL)}
|
|
MF_MT_FIXED_SIZE_SAMPLES: TGUID = '{b8ebefaf-b718-4e04-b0a9-116775e3321b}'; // {UINT32 (BOOL)}
|
|
MF_MT_SAMPLE_SIZE: TGUID = '{dad3ab78-1990-408b-bce2-eba673dacc10}'; // {UINT32}
|
|
MF_MT_AVG_BITRATE: TGUID = '{20332624-fb0d-4d9e-bd0d-cbf6786c102e}'; // {UINT32}
|
|
MF_MT_DEFAULT_STRIDE: TGUID = '{644b4e48-1e02-4516-b0eb-c01ca9d49ac6}'; // {UINT32 (INT32)} // in bytes
|
|
MF_MT_FRAME_RATE: TGUID = '{c459a2e8-3d2c-4e44-b132-fee5156c7bb0}'; // {UINT64 (HI32(Numerator),LO32(Denominator))}
|
|
MF_MT_FRAME_RATE_RANGE_MAX: TGUID = '{E3371D41-B4CF-4a05-BD4E-20B88BB2C4D6}'; // {UINT64 (HI32(Numerator),LO32(Denominator))}
|
|
MF_MT_FRAME_RATE_RANGE_MIN: TGUID = '{D2E7558C-DC1F-403f-9A72-D28BB1EB3B5E}'; // {UINT64 (HI32(Numerator),LO32(Denominator))}
|
|
MF_MT_FRAME_SIZE: TGUID = '{1652c33d-d6b2-4012-b834-72030849a37d}'; // {UINT64 (HI32(Width),LO32(Height))}
|
|
MF_MT_INTERLACE_MODE: TGUID = '{e2724bb8-e676-4806-b4b2-a8d6efb44ccd}'; // {UINT32 (oneof MFVideoInterlaceMode)}
|
|
MF_MT_VIDEO_LIGHTING: TGUID = '{53a0529c-890b-4216-8bf9-599367ad6d20}'; // {UINT32 (oneof MFVideoLighting)}
|
|
MF_MT_AUDIO_BITS_PER_SAMPLE: TGUID = '{f2deb57f-40fa-4764-aa33-ed4f2d1ff669}'; // {UINT32}
|
|
MF_MT_AUDIO_FLOAT_SAMPLES_PER_SECOND: TGUID = '{fb3b724a-cfb5-4319-aefe-6e42b2406132}'; // {double}
|
|
MF_MT_AUDIO_NUM_CHANNELS: TGUID = '{37e48bf5-645e-4c5b-89de-ada9e29b696a}'; // {UINT32}
|
|
MF_MT_AUDIO_SAMPLES_PER_SECOND: TGUID = '{5faeeae7-0290-4c31-9e8a-c534f68d9dba}'; // {UINT32}
|
|
MF_MT_AUDIO_BLOCK_ALIGNMENT: TGUID = '{322de230-9eeb-43bd-ab7a-ff412251541d}'; // {UINT32}
|
|
MF_MT_ALL_SAMPLES_INDEPENDENT: TGUID = '{c9173739-5e56-461c-b713-46fb995cb95f}'; // {UINT32 (BOOL)}
|
|
MF_MT_AUDIO_PREFER_WAVEFORMATEX: TGUID = '{a901aaba-e037-458a-bdf6-545be2074042}'; // {UINT32 (BOOL)}
|
|
MF_MT_AUDIO_AVG_BYTES_PER_SECOND: TGUID = '{1aab75c8-cfef-451c-ab95-ac034b8e1731}'; // {UINT32}
|
|
MF_MT_VIDEO_ROTATION: TGUID = '{C380465D-2271-428C-9B83-ECEA3B4A85C1}'; // {UINT32}
|
|
MF_MT_PIXEL_ASPECT_RATIO: TGUID = '{c6376a1e-8d0a-4027-be45-6d9a0ad39bb6}'; // {UINT64)
|
|
MF_MT_SOURCE_CONTENT_HINT: TGUID = '{68aca3cc-22d0-44e6-85f8-28167197fa38}'; // {UINT32}
|
|
|
|
// Major types
|
|
MFMediaType_Default: TGUID = (D1: $81A412E6; D2: $8103; D3: $4B06; D4: ($85, $7F, $18, $62, $78, $10, $24, $AC));
|
|
MFMediaType_Audio: TGUID = (D1: $73647561; D2: $0000; D3: $0010; D4: ($80, $00, $00, $AA, $00, $38, $9B, $71));
|
|
MFMediaType_Video: TGUID = (D1: $73646976; D2: $0000; D3: $0010; D4: ($80, $00, $00, $AA, $00, $38, $9B, $71));
|
|
MFMediaType_Protected: TGUID = (D1: $7b4b6fe6; D2: $9d04; D3: $4494; D4: ($be, $14, $7e, $0b, $d0, $76, $c8, $e4));
|
|
MFMediaType_SAMI: TGUID = (D1: $e69669a0; D2: $3dcd; D3: $40cb; D4: ($9e, $2e, $37, $08, $38, $7c, $06, $16));
|
|
MFMediaType_Script: TGUID = (D1: $72178C22; D2: $E45B; D3: $11D5; D4: ($BC, $2A, $00, $B0, $D0, $F3, $F4, $AB));
|
|
MFMediaType_Image: TGUID = (D1: $72178C23; D2: $E45B; D3: $11D5; D4: ($BC, $2A, $00, $B0, $D0, $F3, $F4, $AB));
|
|
MFMediaType_HTML: TGUID = (D1: $72178C24; D2: $E45B; D3: $11D5; D4: ($BC, $2A, $00, $B0, $D0, $F3, $F4, $AB));
|
|
MFMediaType_Binary: TGUID = (D1: $72178C25; D2: $E45B; D3: $11D5; D4: ($BC, $2A, $00, $B0, $D0, $F3, $F4, $AB));
|
|
MFMediaType_FileTransfer: TGUID = (D1: $72178C26; D2: $E45B; D3: $11D5; D4: ($BC, $2A, $00, $B0, $D0, $F3, $F4, $AB));
|
|
|
|
// Presentation Descriptor Attributes
|
|
MF_PD_DURATION: TGUID = (D1: $6c990d33; D2: $bb8e; D3: $477a; D4: ($85, $98, $0d, $5d, $96, $fc, $d8, $8a));
|
|
|
|
// Direct3D formats (used to build complete video subtype GUIDs)
|
|
D3DFMT_R8G8B8 = 20;
|
|
D3DFMT_A8R8G8B8 = 21;
|
|
D3DFMT_X8R8G8B8 = 22;
|
|
D3DFMT_R5G6B5 = 23;
|
|
D3DFMT_X1R5G5B5 = 24;
|
|
D3DFMT_P8 = 41;
|
|
|
|
// Wave formats (used to build complete audio subtype GUIDs)
|
|
WAVE_FORMAT_PCM = $0001;
|
|
WAVE_FORMAT_IEEE_FLOAT = $0003;
|
|
WAVE_FORMAT_DTS = $0008;
|
|
WAVE_FORMAT_DOLBY_AC3_SPDIF = $0092;
|
|
WAVE_FORMAT_DRM = $0009;
|
|
WAVE_FORMAT_WMAUDIO2 = $0161;
|
|
WAVE_FORMAT_WMAUDIO3 = $0162;
|
|
WAVE_FORMAT_WMAUDIO_LOSSLESS = $0163;
|
|
WAVE_FORMAT_WMASPDIF = $0164;
|
|
WAVE_FORMAT_WMAVOICE9 = $000A;
|
|
WAVE_FORMAT_MPEGLAYER3 = $0055;
|
|
WAVE_FORMAT_MPEG = $0050;
|
|
WAVE_FORMAT_MPEG_HEAAC = $1610;
|
|
WAVE_FORMAT_MPEG_ADTS_AAC = $1600;
|
|
|
|
// Video Subtype GUIDs (use IEConvertVideoSubTypeToString() and IEConvertStringToVideoSubType() for the other formats)
|
|
MFVideoFormat_Base: TGUID = (D1: $00000000; D2: $0000; D3: $0010; D4: ($80, $00, $00, $aa, $00, $38, $9b, $71));
|
|
|
|
// Audio Subtype GUIDs (use IEConvertAudioSubTypeToString() and IEConvertStringToAudioSubType() for the other formats)
|
|
MFAudioFormat_Base: TGUID = (D1: $00000000; D2: $0000; D3: $0010; D4: ($80, $00, $00, $aa, $00, $38, $9b, $71));
|
|
|
|
// IMFSourceReader::ReadSample parameter dwStreamIndex values:
|
|
MF_SOURCE_READER_FIRST_VIDEO_STREAM = $FFFFFFFC;
|
|
MF_SOURCE_READER_FIRST_AUDIO_STREAM = $FFFFFFFD;
|
|
MF_SOURCE_READER_ANY_STREAM = $FFFFFFFE;
|
|
MF_SOURCE_READER_ALL_STREAMS = $FFFFFFFE;
|
|
|
|
// IMFSourceReader::GetPresentationAttribute dwStreamIndex values:
|
|
MF_SOURCE_READER_MEDIASOURCE = $FFFFFFFF;
|
|
|
|
// IMFSourceReader::ReadSample parameter dwControlFlags values:
|
|
MF_SOURCE_READER_CONTROLF_DRAIN = $00000001;
|
|
|
|
// IMFSourceReader::ReadSample parameter pdwStreamFlags values:
|
|
MF_SOURCE_READERF_ERROR = $00000001;
|
|
MF_SOURCE_READERF_ENDOFSTREAM = $00000002;
|
|
MF_SOURCE_READERF_NEWSTREAM = $00000004;
|
|
MF_SOURCE_READERF_NATIVEMEDIATYPECHANGED = $00000010;
|
|
MF_SOURCE_READERF_CURRENTMEDIATYPECHANGED = $00000020;
|
|
MF_SOURCE_READERF_STREAMTICK = $00000100;
|
|
MF_SOURCE_READERF_ALLEFFECTSREMOVED = $00000200;
|
|
|
|
// MFVideoLighting values
|
|
MFVideoLighting_Unknown = 0;
|
|
MFVideoLighting_bright = 1;
|
|
MFVideoLighting_office = 2;
|
|
MFVideoLighting_dim = 3;
|
|
MFVideoLighting_dark = 4;
|
|
MFVideoLighting_Last = 5;
|
|
MFVideoLighting_ForceDWORD = $7FFFFFFF;
|
|
|
|
// MFVideoInterlaceMode values
|
|
MFVideoInterlace_Unknown = 0;
|
|
MFVideoInterlace_Progressive = 2;
|
|
MFVideoInterlace_FieldInterleavedUpperFirst = 3;
|
|
MFVideoInterlace_FieldInterleavedLowerFirst = 4;
|
|
MFVideoInterlace_FieldSingleUpper = 5;
|
|
MFVideoInterlace_FieldSingleLower = 6;
|
|
MFVideoInterlace_MixedInterlaceOrProgressive = 7;
|
|
|
|
// Other consts
|
|
MFSTARTUP_FULL = 0;
|
|
MF_SDK_VERSION = $0002;
|
|
MF_API_VERSION = $0070;
|
|
MF_VERSION = (MF_SDK_VERSION shl 16) or MF_API_VERSION;
|
|
|
|
// MF_FILE_ACCESSMODE values
|
|
MF_ACCESSMODE_READ = 1;
|
|
MF_ACCESSMODE_WRITE = 2;
|
|
MF_ACCESSMODE_READWRITE = 3;
|
|
|
|
// MF_FILE_OPENMODE values
|
|
MF_OPENMODE_FAIL_IF_NOT_EXIST = 0;
|
|
MF_OPENMODE_FAIL_IF_EXIST = 1;
|
|
MF_OPENMODE_RESET_IF_EXIST = 2;
|
|
MF_OPENMODE_APPEND_IF_EXIST = 3;
|
|
MF_OPENMODE_DELETE_IF_EXIST = 4;
|
|
|
|
// MF_FILE_FLAGS values
|
|
MF_FILEFLAGS_NONE = 0;
|
|
MF_FILEFLAGS_NOBUFFERING = $1;
|
|
MF_FILEFLAGS_ALLOW_WRITE_SHARING = $2;
|
|
|
|
// MFT_MESSAGE_TYPE values
|
|
MFT_MESSAGE_COMMAND_FLUSH = 0;
|
|
MFT_MESSAGE_COMMAND_DRAIN = $1;
|
|
MFT_MESSAGE_SET_D3D_MANAGER = $2;
|
|
MFT_MESSAGE_DROP_SAMPLES = $3;
|
|
MFT_MESSAGE_NOTIFY_BEGIN_STREAMING = $10000000;
|
|
MFT_MESSAGE_NOTIFY_END_STREAMING = $10000001;
|
|
MFT_MESSAGE_NOTIFY_END_OF_STREAM = $10000002;
|
|
MFT_MESSAGE_NOTIFY_START_OF_STREAM = $10000003;
|
|
MFT_MESSAGE_COMMAND_MARKER = $20000000;
|
|
|
|
// Errors
|
|
MF_E_TRANSFORM_NEED_MORE_INPUT: DWORD = $C00D6D72;
|
|
|
|
// Video Lighting types
|
|
MFVideoLighting_Bright_STR = 'Bright';
|
|
MFVideoLighting_Office_STR = 'Office';
|
|
MFVideoLighting_Dim_STR = 'Dim';
|
|
MFVideoLighting_Dark_STR = 'Dark';
|
|
|
|
// Interlace Modes
|
|
MFVideoInterlace_Progressive_STR = 'Progressive';
|
|
MFVideoInterlace_FieldInterleavedUpperFirst_STR = 'FieldInterleavedUpperFirst';
|
|
MFVideoInterlace_FieldInterleavedLowerFirst_STR = 'FieldInterleavedLowerFirst';
|
|
MFVideoInterlace_FieldSingleUpper_STR = 'FieldSingleUpper';
|
|
MFVideoInterlace_FieldSingleLower_STR = 'FieldSingleLower';
|
|
MFVideoInterlace_MixedInterlaceOrProgressive_STR = 'MixedInterlaceOrProgressive';
|
|
|
|
type
|
|
MF_FILE_ACCESSMODE = DWORD;
|
|
MF_FILE_OPENMODE = DWORD;
|
|
MF_FILE_FLAGS = DWORD;
|
|
|
|
|
|
var
|
|
// Windows Media Foundation libraries
|
|
mfplat_lib: THandle = 0;
|
|
mf_lib: THandle = 0;
|
|
mfreadwrite_lib: THandle = 0;
|
|
|
|
|
|
var
|
|
// video sample decoders (a list of TIEMediaFoundationVideoSampleDecoder implementations)
|
|
videoSampleDecoders: TObjectList = nil;
|
|
|
|
|
|
var
|
|
MFStartup: function(Version: DWORD; dwFlags: DWORD = MFSTARTUP_FULL): HRESULT; stdcall;
|
|
MFShutdown: function(): HRESULT; stdcall;
|
|
MFCreateAttributes: function(out ppMFAttributes: IE_IMFAttributes; cInitialSize: dword): HRESULT; stdcall;
|
|
MFEnumDeviceSources: function(pAttributes: IE_IMFAttributes; out pppSourceActivate: PPointerArray; out pcSourceActivate: DWORD): HRESULT; stdcall;
|
|
MFCreateSourceReaderFromMediaSource: function(pMediaSource: IE_IMFMediaSource; pAttributes: IE_IMFAttributes; out ppSourceReader: IE_IMFSourceReader): HRESULT; stdcall;
|
|
MFCreateMediaType: function(out ppMFType: IE_IMFMediaType): HRESULT; stdcall;
|
|
MFGetStrideForBitmapInfoHeader: function(format: DWORD; dwWidth: DWORD; out pStride: integer): HRESULT; stdcall;
|
|
MFCreateFile: function(AccessMode: MF_FILE_ACCESSMODE; OpenMode: MF_FILE_OPENMODE; fFlags: MF_FILE_FLAGS; pwszFileURL: PWideChar; out ppIByteStream: IE_IMFByteStream): HRESULT; stdcall;
|
|
MFCreateSourceReaderFromByteStream: function(pByteStream: IE_IMFByteStream; pAttributes: IE_IMFAttributes; out ppSourceReader: IE_IMFSourceReader): HRESULT; stdcall;
|
|
MFGetSystemTime: function(): int64; stdcall;
|
|
MFCreateSourceReaderFromURL: function(pwszURL: PWideChar; pAttributes: IE_IMFAttributes; out ppSourceReader: IE_IMFSourceReader): HRESULT; stdcall;
|
|
MFCreateAudioRenderer: function(pAudioAttributes: IE_IMFAttributes; out ppSink: IE_IMFMediaSink): HRESULT; stdcall;
|
|
MFCreatePresentationClock: function(out ppPresentationClock: IE_IMFPresentationClock): HRESULT; stdcall;
|
|
//MFCreateSystemTimeSource: function(out ppSystemTimeSource: IE_IMFPresentationTimeSource): HRESULT; stdcall;
|
|
MFCreateSample: function(out ppIMFSample: IE_IMFSample): HRESULT; stdcall;
|
|
MFCreateMemoryBuffer: function(cbMaxLength: DWORD; out ppBuffer: IE_IMFMediaBuffer): HRESULT; stdcall;
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// Helpers
|
|
|
|
|
|
{!!
|
|
<FS>IEMediaFoundationGetVideoSampleDecoders
|
|
|
|
<FM>Declaration<FC>
|
|
function IEMediaFoundationGetVideoSampleDecoders(): TObjectList;;
|
|
|
|
<FM>Description<FN>
|
|
Applications add new decoders by using this function and implementing the <A TIEMediaFoundationVideoSampleDecoder> abstract class.
|
|
|
|
<FM>Example<FC>
|
|
IEMediaFoundationGetVideoSampleDecoders().Add(TIEMediaFoundationVideoSampleDecoder_YOURFORMAT.Create());
|
|
!!}
|
|
function IEMediaFoundationGetVideoSampleDecoders(): TObjectList;
|
|
begin
|
|
if videoSampleDecoders = nil then
|
|
videoSampleDecoders := TObjectList.Create();
|
|
result := videoSampleDecoders;
|
|
end;
|
|
|
|
|
|
procedure IEMediaFoundationSetupDefaultVideoSampleDecoders(); forward;
|
|
|
|
|
|
function IEMFLoadLibrary(): boolean;
|
|
begin
|
|
if mfplat_lib = 0 then
|
|
begin
|
|
mfplat_lib := LoadLibrary('Mfplat.dll');
|
|
if mfplat_lib <> 0 then
|
|
begin
|
|
MFStartup := GetProcAddress(mfplat_lib, 'MFStartup');
|
|
MFShutdown := GetProcAddress(mfplat_lib, 'MFShutdown');
|
|
MFCreateAttributes := GetProcAddress(mfplat_lib, 'MFCreateAttributes');
|
|
MFCreateMediaType := GetProcAddress(mfplat_lib, 'MFCreateMediaType');
|
|
MFGetStrideForBitmapInfoHeader := GetProcAddress(mfplat_lib, 'MFGetStrideForBitmapInfoHeader');
|
|
MFCreateFile := GetProcAddress(mfplat_lib, 'MFCreateFile');
|
|
MFGetSystemTime := GetProcAddress(mfplat_lib, 'MFGetSystemTime');
|
|
MFCreateSample := GetProcAddress(mfplat_lib, 'MFCreateSample');
|
|
MFCreateMemoryBuffer := GetProcAddress(mfplat_lib, 'MFCreateMemoryBuffer');
|
|
end;
|
|
|
|
mf_lib := LoadLibrary('Mf.dll');
|
|
if mf_lib <> 0 then
|
|
begin
|
|
MFEnumDeviceSources := GetProcAddress(mf_lib, 'MFEnumDeviceSources');
|
|
MFCreateAudioRenderer := GetProcAddress(mf_lib, 'MFCreateAudioRenderer');
|
|
MFCreatePresentationClock := GetProcAddress(mf_lib, 'MFCreatePresentationClock');
|
|
end;
|
|
|
|
mfreadwrite_lib := LoadLibrary('Mfreadwrite.dll');
|
|
if mfreadwrite_lib <> 0 then
|
|
begin
|
|
MFCreateSourceReaderFromMediaSource := GetProcAddress(mfreadwrite_lib, 'MFCreateSourceReaderFromMediaSource');
|
|
MFCreateSourceReaderFromByteStream := GetProcAddress(mfreadwrite_lib, 'MFCreateSourceReaderFromByteStream');
|
|
MFCreateSourceReaderFromURL := GetProcAddress(mfreadwrite_lib, 'MFCreateSourceReaderFromURL');
|
|
end;
|
|
|
|
IEMediaFoundationSetupDefaultVideoSampleDecoders();
|
|
end;
|
|
|
|
result := (mfplat_lib <> 0) and (mf_lib <> 0) and (mfreadwrite_lib <> 0);
|
|
end;
|
|
|
|
|
|
procedure IEMFUnloadLibrary();
|
|
begin
|
|
if mfreadwrite_lib <> 0 then
|
|
FreeLibrary(mfreadwrite_lib);
|
|
|
|
if mf_lib <> 0 then
|
|
FreeLibrary(mf_lib);
|
|
|
|
if mfplat_lib <> 0 then
|
|
FreeLibrary(mfplat_lib);
|
|
|
|
FreeAndNil(videoSampleDecoders);
|
|
end;
|
|
|
|
|
|
function IEMFStartup(): boolean;
|
|
begin
|
|
CoInitializeEx(nil, COINIT_APARTMENTTHREADED or COINIT_DISABLE_OLE1DDE);
|
|
result := IEMFLoadLibrary() and assigned(MFStartup) and SUCCEEDED( MFStartup(MF_VERSION) );
|
|
end;
|
|
|
|
|
|
procedure IEMFShutdown();
|
|
begin
|
|
if (mfplat_lib <> 0) and (mf_lib <> 0) and (mfreadwrite_lib <> 0) and assigned(MFShutdown) then
|
|
MFShutdown();
|
|
CoUninitialize();
|
|
end;
|
|
|
|
|
|
function IEGetStringFromAllocatedString(attributes: IE_IMFAttributes; const guidKey: TGUID): WideString;
|
|
var
|
|
val: PWideChar;
|
|
len: DWORD;
|
|
begin
|
|
attributes.GetAllocatedString(MF_DEVSOURCE_ATTRIBUTE_FRIENDLY_NAME, val, len);
|
|
SetLength(result, len);
|
|
CopyMemory(@result[1], val, len * 2);
|
|
CoTaskMemFree(val);
|
|
end;
|
|
|
|
|
|
function IEConvertMajorTypeToString(const majorTypeGuid: TGUID): WideString;
|
|
begin
|
|
if CompareGUID(majorTypeGuid, MFMediaType_Audio) then
|
|
result := mmf_AUDIO_STREAM
|
|
else
|
|
if CompareGUID(majorTypeGuid, MFMediaType_Video) then
|
|
result := mmf_VIDEO_STREAM
|
|
else
|
|
if CompareGUID(majorTypeGuid, MFMediaType_Protected) then
|
|
result := mmf_PROTECTED_STREAM
|
|
else
|
|
if CompareGUID(majorTypeGuid, MFMediaType_SAMI) then
|
|
result := mmf_SAMI_STREAM
|
|
else
|
|
if CompareGUID(majorTypeGuid, MFMediaType_Script) then
|
|
result := mmf_SCRIPT_STREAM
|
|
else
|
|
if CompareGUID(majorTypeGuid, MFMediaType_Image) then
|
|
result := mmf_IMAGE_STREAM
|
|
else
|
|
if CompareGUID(majorTypeGuid, MFMediaType_HTML) then
|
|
result := mmf_HTML_STREAM
|
|
else
|
|
if CompareGUID(majorTypeGuid, MFMediaType_Binary) then
|
|
result := mmf_BINARY_STREAM
|
|
else
|
|
if CompareGUID(majorTypeGuid, MFMediaType_FileTransfer) then
|
|
result := mmf_FILETRANSFER_STREAM
|
|
else
|
|
result := 'Unknown';
|
|
end;
|
|
|
|
|
|
function IEConvertStringToMajorType(value: WideString): TGUID;
|
|
begin
|
|
if value = mmf_AUDIO_STREAM then
|
|
result := MFMediaType_Audio
|
|
else
|
|
if value = mmf_VIDEO_STREAM then
|
|
result := MFMediaType_Video
|
|
else
|
|
if value = mmf_PROTECTED_STREAM then
|
|
result := MFMediaType_Protected
|
|
else
|
|
if value = mmf_SAMI_STREAM then
|
|
result := MFMediaType_SAMI
|
|
else
|
|
if value = mmf_SCRIPT_STREAM then
|
|
result := MFMediaType_Script
|
|
else
|
|
if value = mmf_IMAGE_STREAM then
|
|
result := MFMediaType_Image
|
|
else
|
|
if value = mmf_HTML_STREAM then
|
|
result := MFMediaType_HTML
|
|
else
|
|
if value = mmf_BINARY_STREAM then
|
|
result := MFMediaType_Binary
|
|
else
|
|
if value = mmf_FILETRANSFER_STREAM then
|
|
result := MFMediaType_FileTransfer
|
|
else
|
|
result := MFMediaType_Default
|
|
end;
|
|
|
|
|
|
// ex: MFVideoFormat_RGB8 -> 'RGB8', MFAudioFormat_PCM -> 'PCM', etc..
|
|
function IEConvertSubTypeToString(const videoSubTypeGuid: TGUID): WideString;
|
|
var
|
|
astr: AnsiString;
|
|
begin
|
|
result := '';
|
|
if CompareMem(@videoSubTypeGuid.D2, @MFVideoFormat_Base.D2, sizeof(TGUID) - 4) then // compare only from D2 (do not compare D1)
|
|
begin
|
|
case videoSubTypeGuid.D1 of
|
|
D3DFMT_P8 : result := mmf_VideoFormat_RGB8;
|
|
D3DFMT_X1R5G5B5 : result := mmf_VideoFormat_RGB555;
|
|
D3DFMT_R5G6B5 : result := mmf_VideoFormat_RGB565;
|
|
D3DFMT_R8G8B8 : result := mmf_VideoFormat_RGB24;
|
|
D3DFMT_X8R8G8B8 : result := mmf_VideoFormat_RGB32;
|
|
D3DFMT_A8R8G8B8 : result := mmf_VideoFormat_ARGB32;
|
|
WAVE_FORMAT_PCM : result := mmf_AudioFormat_PCM;
|
|
WAVE_FORMAT_IEEE_FLOAT : result := mmf_AudioFormat_Float;
|
|
WAVE_FORMAT_DTS : result := mmf_AudioFormat_DTS;
|
|
WAVE_FORMAT_DOLBY_AC3_SPDIF : result := mmf_AudioFormat_Dolby_AC3_SPDIF;
|
|
WAVE_FORMAT_DRM : result := mmf_AudioFormat_DRM;
|
|
WAVE_FORMAT_WMAUDIO2 : result := mmf_AudioFormat_WMAudioV8;
|
|
WAVE_FORMAT_WMAUDIO3 : result := mmf_AudioFormat_WMAudioV9;
|
|
WAVE_FORMAT_WMAUDIO_LOSSLESS : result := mmf_AudioFormat_WMAudio_Lossless;
|
|
WAVE_FORMAT_WMASPDIF : result := mmf_AudioFormat_WMASPDIF;
|
|
WAVE_FORMAT_WMAVOICE9 : result := mmf_AudioFormat_MSP1;
|
|
WAVE_FORMAT_MPEGLAYER3 : result := mmf_AudioFormat_MP3;
|
|
WAVE_FORMAT_MPEG : result := mmf_AudioFormat_MPEG;
|
|
WAVE_FORMAT_MPEG_HEAAC : result := mmf_AudioFormat_AAC;
|
|
WAVE_FORMAT_MPEG_ADTS_AAC : result := mmf_AudioFormat_ADTS;
|
|
else
|
|
begin
|
|
// Extract fourcc code (other cases like MFVideoFormat_AI44...)
|
|
// these are: 'AI44', 'AYUV', 'YUY2', 'YVYU', 'YVU9', 'UYVY', 'NV11', 'NV12', 'YV12', 'I420', 'IYUV', 'Y210', 'Y216', 'Y410', 'Y416',
|
|
// 'Y41P', 'Y41T', 'Y42T', 'P210', 'P216', 'P010', 'P016', 'v210', 'v216', 'v410', 'MP43', 'MP4S', 'M4S2', 'MP4V', 'WMV1',
|
|
// 'WMV2', 'WMV3', 'WVC1', 'MSS1', 'MSS2', 'MPG1', 'dvsl', 'dvsd', 'dvhd', 'dv25', 'dv50', 'dvh1', 'dvc ', 'H264', 'MJPG'
|
|
SetLength(astr, 4);
|
|
CopyMemory(@astr[1], @videoSubTypeGuid.D1, 4);
|
|
result := WideString(astr);
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
|
|
function IEConvertStringToSubType(value: WideString): TGUID;
|
|
var
|
|
astr: AnsiString;
|
|
begin
|
|
CopyMemory(@result.D2, @MFVideoFormat_Base.D2, sizeof(TGUID) - 4); // copy from D2
|
|
|
|
// VIDEO
|
|
|
|
// MFVideoFormat_RGB8
|
|
if value = mmf_VideoFormat_RGB8 then
|
|
result.D1 := D3DFMT_P8
|
|
// MFVideoFormat_RGB555
|
|
else
|
|
if value = mmf_VideoFormat_RGB555 then
|
|
result.D1 := D3DFMT_X1R5G5B5
|
|
// MFVideoFormat_RGB565
|
|
else
|
|
if value = mmf_VideoFormat_RGB565 then
|
|
result.D1 := D3DFMT_R5G6B5
|
|
// MFVideoFormat_RGB24
|
|
else
|
|
if value = mmf_VideoFormat_RGB24 then
|
|
result.D1 := D3DFMT_R8G8B8
|
|
// MFVideoFormat_RGB32
|
|
else
|
|
if value = mmf_VideoFormat_RGB32 then
|
|
result.D1 := D3DFMT_X8R8G8B8
|
|
// MFVideoFormat_ARGB32
|
|
else
|
|
if value = mmf_VideoFormat_ARGB32 then
|
|
result.D1 := D3DFMT_A8R8G8B8
|
|
|
|
// AUDIO
|
|
|
|
// MFAudioFormat_PCM
|
|
else
|
|
if value = mmf_AudioFormat_PCM then
|
|
result.D1 := WAVE_FORMAT_PCM
|
|
// MFAudioFormat_Float
|
|
else
|
|
if value = mmf_AudioFormat_Float then
|
|
result.D1 := WAVE_FORMAT_IEEE_FLOAT
|
|
// MFAudioFormat_DTS
|
|
else
|
|
if value = mmf_AudioFormat_DTS then
|
|
result.D1 := WAVE_FORMAT_DTS
|
|
// MFAudioFormat_Dolby_AC3_SPDIF
|
|
else
|
|
if value = mmf_AudioFormat_Dolby_AC3_SPDIF then
|
|
result.D1 := WAVE_FORMAT_DOLBY_AC3_SPDIF
|
|
// MFAudioFormat_DRM
|
|
else
|
|
if value = mmf_AudioFormat_DRM then
|
|
result.D1 := WAVE_FORMAT_DRM
|
|
// MFAudioFormat_WMAudioV8
|
|
else
|
|
if value = mmf_AudioFormat_WMAudioV8 then
|
|
result.D1 := WAVE_FORMAT_WMAUDIO2
|
|
// MFAudioFormat_WMAudioV9
|
|
else
|
|
if value = mmf_AudioFormat_WMAudioV9 then
|
|
result.D1 := WAVE_FORMAT_WMAUDIO3
|
|
// MFAudioFormat_WMAudio_Lossless
|
|
else
|
|
if value = mmf_AudioFormat_WMAudio_Lossless then
|
|
result.D1 := WAVE_FORMAT_WMAUDIO_LOSSLESS
|
|
// MFAudioFormat_WMASPDIF
|
|
else
|
|
if value = mmf_AudioFormat_WMASPDIF then
|
|
result.D1 := WAVE_FORMAT_WMASPDIF
|
|
// MFAudioFormat_MSP1
|
|
else
|
|
if value = mmf_AudioFormat_MSP1 then
|
|
result.D1 := WAVE_FORMAT_WMAVOICE9
|
|
// MFAudioFormat_MP3
|
|
else
|
|
if value = mmf_AudioFormat_MP3 then
|
|
result.D1 := WAVE_FORMAT_MPEGLAYER3
|
|
// MFAudioFormat_MPEG
|
|
else
|
|
if value = mmf_AudioFormat_MPEG then
|
|
result.D1 := WAVE_FORMAT_MPEG
|
|
// MFAudioFormat_AAC
|
|
else
|
|
if value = mmf_AudioFormat_AAC then
|
|
result.D1 := WAVE_FORMAT_MPEG_HEAAC
|
|
// MFAudioFormat_ADTS
|
|
else
|
|
if value = mmf_AudioFormat_ADTS then
|
|
result.D1 := WAVE_FORMAT_MPEG_ADTS_AAC
|
|
|
|
// fourcc code (like MFVideoFormat_AI44...)
|
|
else
|
|
begin
|
|
astr := AnsiString(value);
|
|
CopyMemory(@result.D1, @astr[1], 4);
|
|
end;
|
|
end;
|
|
|
|
|
|
function IEGetMediaTypeFrameSize(mediaType: IE_IMFMediaType; out width: DWORD; out height: DWORD): boolean;
|
|
var
|
|
u64: uint64;
|
|
begin
|
|
width := 0;
|
|
height := 0;
|
|
result := SUCCEEDED(mediaType.GetUINT64(MF_MT_FRAME_SIZE, u64));
|
|
if result then
|
|
begin
|
|
width := u64 shr 32;
|
|
height := u64 and $FFFFFFFF;
|
|
end;
|
|
end;
|
|
|
|
|
|
function IEGetMediaTypeAspectRatio(mediaType: IE_IMFMediaType; out num: DWORD; out den: DWORD): boolean;
|
|
var
|
|
u64: uint64;
|
|
begin
|
|
num := 1;
|
|
den := 1;
|
|
result := SUCCEEDED(mediaType.GetUINT64(MF_MT_PIXEL_ASPECT_RATIO, u64));
|
|
if result then
|
|
begin
|
|
num := u64 shr 32;
|
|
den := u64 and $FFFFFFFF;
|
|
end;
|
|
end;
|
|
|
|
function IEGetMediaTypeFrameStride(mediaType: IE_IMFMediaType; const subType: TGUID; width: DWORD): integer;
|
|
var
|
|
u32: DWORD;
|
|
begin
|
|
result := 0; // invalid stride
|
|
if SUCCEEDED(mediaType.GetUINT32(MF_MT_DEFAULT_STRIDE, u32)) then
|
|
result := integer(u32)
|
|
else
|
|
if SUCCEEDED(MFGetStrideForBitmapInfoHeader(subType.D1, width, result)) then
|
|
result := {abs}(result) // on windows 8 MFGetStrideForBitmapInfoHeader with RGB32, even when it should not be
|
|
else
|
|
result := 0;
|
|
end;
|
|
|
|
|
|
function IEConvertVideoLightingToString(videoLighting: DWORD): WideString;
|
|
begin
|
|
case videoLighting of
|
|
MFVideoLighting_bright : result := MFVideoLighting_Bright_STR;
|
|
MFVideoLighting_office : result := MFVideoLighting_Office_STR;
|
|
MFVideoLighting_dim : result := MFVideoLighting_Dim_STR;
|
|
MFVideoLighting_dark : result := MFVideoLighting_Dark_STR;
|
|
else
|
|
result := 'Unknown';
|
|
end;
|
|
end;
|
|
|
|
|
|
function IEConvertStringToVideoLighting(value: WideString): DWORD;
|
|
begin
|
|
if value = MFVideoLighting_Bright_STR then
|
|
result := MFVideoLighting_bright
|
|
else
|
|
if value = MFVideoLighting_Office_STR then
|
|
result := MFVideoLighting_office
|
|
else
|
|
if value = MFVideoLighting_Dim_STR then
|
|
result := MFVideoLighting_dim
|
|
else
|
|
if value = MFVideoLighting_Dark_STR then
|
|
result := MFVideoLighting_dark
|
|
else
|
|
result := MFVideoLighting_Unknown;
|
|
end;
|
|
|
|
|
|
function IEConvertInterlaceModeToString(interlaceMode: DWORD): WideString;
|
|
begin
|
|
case interlaceMode of
|
|
MFVideoInterlace_Progressive : result := MFVideoInterlace_Progressive_STR;
|
|
MFVideoInterlace_FieldInterleavedUpperFirst : result := MFVideoInterlace_FieldInterleavedUpperFirst_STR;
|
|
MFVideoInterlace_FieldInterleavedLowerFirst : result := MFVideoInterlace_FieldInterleavedLowerFirst_STR;
|
|
MFVideoInterlace_FieldSingleUpper : result := MFVideoInterlace_FieldSingleUpper_STR;
|
|
MFVideoInterlace_FieldSingleLower : result := MFVideoInterlace_FieldSingleLower_STR;
|
|
MFVideoInterlace_MixedInterlaceOrProgressive : result := MFVideoInterlace_MixedInterlaceOrProgressive_STR;
|
|
else
|
|
result := 'Unknown';
|
|
end;
|
|
end;
|
|
|
|
|
|
function IEConvertStringToInterlaceMode(value: WideString): DWORD;
|
|
begin
|
|
if value = MFVideoInterlace_Progressive_STR then
|
|
result := MFVideoInterlace_Progressive
|
|
else
|
|
if value = MFVideoInterlace_FieldInterleavedUpperFirst_STR then
|
|
result := MFVideoInterlace_FieldInterleavedUpperFirst
|
|
else
|
|
if value = MFVideoInterlace_FieldInterleavedLowerFirst_STR then
|
|
result := MFVideoInterlace_FieldInterleavedLowerFirst
|
|
else
|
|
if value = MFVideoInterlace_FieldSingleUpper_STR then
|
|
result := MFVideoInterlace_FieldSingleUpper
|
|
else
|
|
if value = MFVideoInterlace_FieldSingleLower_STR then
|
|
result := MFVideoInterlace_FieldSingleLower
|
|
else
|
|
if value = MFVideoInterlace_MixedInterlaceOrProgressive_STR then
|
|
result := MFVideoInterlace_MixedInterlaceOrProgressive
|
|
else
|
|
result := MFVideoInterlace_Unknown;
|
|
end;
|
|
|
|
|
|
function IECreateDictionaryFromMediaType(mediaType: IE_IMFMediaType): TIEDictionary;
|
|
var
|
|
majType, subType: TGUID;
|
|
u32: DWORD;
|
|
u64: uint64;
|
|
f64: double;
|
|
width, height: DWORD;
|
|
ws: WideString;
|
|
begin
|
|
result := TIEDictionary.Create();
|
|
|
|
// MF_MT_MAJOR_TYPE -> IEMAJORTYPE_DICT_KEY
|
|
if not SUCCEEDED(mediaType.GetGUID(MF_MT_MAJOR_TYPE, majType)) then
|
|
exit;
|
|
result.Insert(IEMAJORTYPE_DICT_KEY, IEConvertMajorTypeToString(majType));
|
|
|
|
// MF_MT_SUBTYPE -> IESUBTYPE_DICT_KEY
|
|
if SUCCEEDED(mediaType.GetGUID(MF_MT_SUBTYPE, subType)) then
|
|
result.Insert(IESUBTYPE_DICT_KEY, IEConvertSubTypeToString(subType));
|
|
|
|
// MF_MT_COMPRESSED -> IECOMPRESSED_DICT_KEY
|
|
if SUCCEEDED(mediaType.GetUINT32(MF_MT_COMPRESSED, u32)) then
|
|
result.Insert(IECOMPRESSED_DICT_KEY, boolean(u32));
|
|
|
|
// MF_MT_AVG_BITRATE -> IEAVGBITRATE_DICT_KEY
|
|
if SUCCEEDED(mediaType.GetUINT32(MF_MT_AVG_BITRATE, u32)) then
|
|
result.Insert(IEAVGBITRATE_DICT_KEY, u32);
|
|
|
|
// MF_MT_FRAME_SIZE -> (IEFRAMEWIDTH_DICT_KEY, IEFRAMEHEIGHT_DICT_KEY)
|
|
if IEGetMediaTypeFrameSize(mediaType, width, height) then
|
|
begin
|
|
result.Insert(IEFRAMEWIDTH_DICT_KEY, width);
|
|
result.Insert(IEFRAMEHEIGHT_DICT_KEY, height);
|
|
end;
|
|
|
|
// MF_MT_DEFAULT_STRIDE -> IEDEFAULTSTRIDE_DICT_KEY
|
|
result.Insert(IEDEFAULTSTRIDE_DICT_KEY, IEGetMediaTypeFrameStride(mediaType, subType, width));
|
|
|
|
// MF_MT_FRAME_RATE -> IEFRAMERATE_DICT_KEY
|
|
if SUCCEEDED(mediaType.GetUINT64(MF_MT_FRAME_RATE, u64)) then
|
|
result.Insert(IEFRAMERATE_DICT_KEY, (u64 shr 32) / (u64 and $FFFFFFFF) );
|
|
|
|
// MF_MT_FRAME_RATE_RANGE_MAX -> IEFRAMERATEMAX_DICT_KEY
|
|
if SUCCEEDED(mediaType.GetUINT64(MF_MT_FRAME_RATE_RANGE_MAX, u64)) then
|
|
result.Insert(IEFRAMERATEMAX_DICT_KEY, (u64 shr 32) / (u64 and $FFFFFFFF) );
|
|
|
|
// MF_MT_FRAME_RATE_RANGE_MIN -> IEFRAMERATEMIN_DICT_KEY
|
|
if SUCCEEDED(mediaType.GetUINT64(MF_MT_FRAME_RATE_RANGE_MIN, u64)) then
|
|
result.Insert(IEFRAMERATEMIN_DICT_KEY, (u64 shr 32) / (u64 and $FFFFFFFF) );
|
|
|
|
// MF_MT_INTERLACE_MODE -> IEINTERLACEMODE_DICT_KEY
|
|
if SUCCEEDED(mediaType.GetUINT32(MF_MT_INTERLACE_MODE, u32)) then
|
|
result.Insert(IEINTERLACEMODE_DICT_KEY, IEConvertInterlaceModeToString(u32));
|
|
|
|
// MF_MT_VIDEO_LIGHTING -> IEVIDEOLIGHTING_DICT_KEY
|
|
if SUCCEEDED(mediaType.GetUINT32(MF_MT_VIDEO_LIGHTING, u32)) then
|
|
result.Insert(IEVIDEOLIGHTING_DICT_KEY, IEConvertVideoLightingToString(u32));
|
|
|
|
// MF_MT_AUDIO_BITS_PER_SAMPLE -> IEAUDIOBITSPERSAMPLE_DICT_KEY
|
|
if SUCCEEDED(mediaType.GetUINT32(MF_MT_AUDIO_BITS_PER_SAMPLE, u32)) then
|
|
result.Insert(IEAUDIOBITSPERSAMPLE_DICT_KEY, u32);
|
|
|
|
// MF_MT_AUDIO_FLOAT_SAMPLES_PER_SECOND -> IEAUDIOFLOATSAMPLESPERSECOND
|
|
if SUCCEEDED(mediaType.GetDouble(MF_MT_AUDIO_FLOAT_SAMPLES_PER_SECOND, f64)) then
|
|
result.Insert(IEAUDIOFLOATSAMPLESPERSECOND_DICT_KEY, f64);
|
|
|
|
// MF_MT_AUDIO_NUM_CHANNELS -> IEAUDIONUMCHANNELS_DICT_KEY
|
|
if SUCCEEDED(mediaType.GetUINT32(MF_MT_AUDIO_NUM_CHANNELS, u32)) then
|
|
result.Insert(IEAUDIONUMCHANNELS_DICT_KEY, u32);
|
|
|
|
// MF_MT_AUDIO_SAMPLES_PER_SECOND -> IEAUDIOSAMPLESPERSECOND_DICT_KEY
|
|
if SUCCEEDED(mediaType.GetUINT32(MF_MT_AUDIO_SAMPLES_PER_SECOND, u32)) then
|
|
result.Insert(IEAUDIOSAMPLESPERSECOND_DICT_KEY, u32);
|
|
|
|
// MF_MT_AUDIO_BLOCK_ALIGNMENT -> IEAUDIOBLOCKALIGNMENT_DICT_KEY
|
|
if SUCCEEDED(mediaType.GetUINT32(MF_MT_AUDIO_BLOCK_ALIGNMENT, u32)) then
|
|
result.Insert(IEAUDIOBLOCKALIGNMENT_DICT_KEY, u32);
|
|
|
|
// MF_MT_ALL_SAMPLES_INDEPENDENT -> IEALLSAMPLESINDEPENDENT_DICT_KEY
|
|
if SUCCEEDED(mediaType.GetUINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, u32)) then
|
|
result.Insert(IEALLSAMPLESINDEPENDENT_DICT_KEY, boolean(u32));
|
|
|
|
// MF_MT_AUDIO_PREFER_WAVEFORMATEX -> IEAUDIOPREFERWAVEFORMATEX_DICT_KEY
|
|
if SUCCEEDED(mediaType.GetUINT32(MF_MT_AUDIO_PREFER_WAVEFORMATEX, u32)) then
|
|
result.Insert(IEAUDIOPREFERWAVEFORMATEX_DICT_KEY, boolean(u32));
|
|
|
|
// MF_MT_AUDIO_AVG_BYTES_PER_SECOND -> IEAUDIOAVGBYTESPERSECOND_DICT_KEY
|
|
if SUCCEEDED(mediaType.GetUINT32(MF_MT_AUDIO_AVG_BYTES_PER_SECOND, u32)) then
|
|
result.Insert(IEAUDIOAVGBYTESPERSECOND_DICT_KEY, u32);
|
|
|
|
// MF_MT_VIDEO_ROTATION -> IEVIDEOROTATION_DICT_KEY (win8 only)
|
|
if SUCCEEDED(mediaType.GetUINT32(MF_MT_VIDEO_ROTATION, u32)) then
|
|
result.Insert(IEVIDEOROTATION_DICT_KEY, u32);
|
|
|
|
// MF_MT_PIXEL_ASPECT_RATIO -> IEPIXELASPECTRATIO_DICT_KEY
|
|
if SUCCEEDED(mediaType.GetUINT64(MF_MT_PIXEL_ASPECT_RATIO, u64)) then
|
|
result.Insert(IEPIXELASPECTRATIO_DICT_KEY, IntToStr(u64 shr 32) + ':' + IntToStr(u64 and $FFFFFFFF));
|
|
|
|
// MF_MT_SOURCE_CONTENT_HINT - > IESOURCECONTENTHINT_DICT_KEY
|
|
if SUCCEEDED(mediaType.GetUINT32(MF_MT_SOURCE_CONTENT_HINT, u32)) then
|
|
begin
|
|
case u32 of
|
|
0: ws := 'None';
|
|
1: ws := '16:9';
|
|
2: ws := '2.35:1'; // 47:20
|
|
end;
|
|
result.Insert(IESOURCECONTENTHINT_DICT_KEY, ws);
|
|
end;
|
|
end;
|
|
|
|
|
|
// not all IECreateDictionaryFromMediaType() keys are supported
|
|
function IECreateMediaTypeFromDictionary(dict: TIEDictionary): IE_IMFMediaType; overload;
|
|
var
|
|
num, den, w, h: integer;
|
|
p: integer;
|
|
ws: WideString;
|
|
begin
|
|
result := nil;
|
|
MFCreateMediaType(result);
|
|
|
|
// IEMAJORTYPE_DICT_KEY -> MF_MT_MAJOR_TYPE
|
|
if dict.HasKey(IEMAJORTYPE_DICT_KEY) then
|
|
result.SetGUID(MF_MT_MAJOR_TYPE, IEConvertStringToMajorType(dict.GetString(IEMAJORTYPE_DICT_KEY)));
|
|
|
|
// IESUBTYPE_DICT_KEY -> MF_MT_SUBTYPE
|
|
if dict.HasKey(IESUBTYPE_DICT_KEY) then
|
|
result.SetGUID(MF_MT_SUBTYPE, IEConvertStringToSubType(dict.GetString(IESUBTYPE_DICT_KEY)));
|
|
|
|
// IECOMPRESSED_DICT_KEY -> MF_MT_COMPRESSED
|
|
if dict.HasKey(IECOMPRESSED_DICT_KEY) then
|
|
result.SetUINT32(MF_MT_COMPRESSED, DWORD(dict.GetBoolean(IECOMPRESSED_DICT_KEY)));
|
|
|
|
// IEFRAMERATE_DICT_KEY -> MF_MT_FRAME_RATE
|
|
if dict.HasKey(IEFRAMERATE_DICT_KEY) then
|
|
begin
|
|
IEDecimalToFraction(dict.GetDouble(IEFRAMERATE_DICT_KEY), num, den);
|
|
result.SetUINT64(MF_MT_FRAME_RATE, (uint64(num) shl 32) or uint64(den));
|
|
end;
|
|
|
|
// (IEFRAMEWIDTH_DICT_KEY, IEFRAMEHEIGHT_DICT_KEY) -> MF_MT_FRAME_SIZE
|
|
if dict.HasKey(IEFRAMEWIDTH_DICT_KEY) and dict.HasKey(IEFRAMEHEIGHT_DICT_KEY) then
|
|
begin
|
|
w := dict.GetInteger(IEFRAMEWIDTH_DICT_KEY);
|
|
h := dict.GetInteger(IEFRAMEHEIGHT_DICT_KEY);
|
|
result.SetUINT64(MF_MT_FRAME_SIZE, (uint64(w) shl 32) or uint64(h));
|
|
end;
|
|
|
|
// IEINTERLACEMODE_DICT_KEY -> MF_MT_INTERLACE_MODE
|
|
if dict.HasKey(IEINTERLACEMODE_DICT_KEY) then
|
|
result.SetUINT32(MF_MT_INTERLACE_MODE, IEConvertStringToInterlaceMode(dict.GetString(IEINTERLACEMODE_DICT_KEY)));
|
|
|
|
// IEVIDEOLIGHTING_DICT_KEY -> MF_MT_VIDEO_LIGHTING
|
|
if dict.HasKey(IEVIDEOLIGHTING_DICT_KEY) then
|
|
result.SetUINT32(MF_MT_VIDEO_LIGHTING, IEConvertStringToVideoLighting(dict.GetString(IEVIDEOLIGHTING_DICT_KEY)));
|
|
|
|
// IEAUDIOSAMPLESPERSECOND_DICT_KEY -> MF_MT_AUDIO_SAMPLES_PER_SECOND
|
|
if dict.HasKey(IEAUDIOSAMPLESPERSECOND_DICT_KEY) then
|
|
result.SetUINT32(MF_MT_AUDIO_SAMPLES_PER_SECOND, dict.GetInteger(IEAUDIOSAMPLESPERSECOND_DICT_KEY));
|
|
|
|
// IEAUDIOBITSPERSAMPLE_DICT_KEY -> MF_MT_AUDIO_BITS_PER_SAMPLE
|
|
if dict.HasKey(IEAUDIOBITSPERSAMPLE_DICT_KEY) then
|
|
result.SetUINT32(MF_MT_AUDIO_BITS_PER_SAMPLE, dict.GetInteger(IEAUDIOBITSPERSAMPLE_DICT_KEY));
|
|
|
|
// IEAUDIONUMCHANNELS_DICT_KEY -> MF_MT_AUDIO_NUM_CHANNELS
|
|
if dict.HasKey(IEAUDIONUMCHANNELS_DICT_KEY) then
|
|
result.SetUINT32(MF_MT_AUDIO_NUM_CHANNELS, dict.GetInteger(IEAUDIONUMCHANNELS_DICT_KEY));
|
|
|
|
// IEAUDIOBLOCKALIGNMENT_DICT_KEY -> MF_MT_AUDIO_BLOCK_ALIGNMENT
|
|
if dict.HasKey(IEAUDIOBLOCKALIGNMENT_DICT_KEY) then
|
|
result.SetUINT32(MF_MT_AUDIO_BLOCK_ALIGNMENT, dict.GetInteger(IEAUDIOBLOCKALIGNMENT_DICT_KEY));
|
|
|
|
// IEALLSAMPLESINDEPENDENT_DICT_KEY -> MF_MT_ALL_SAMPLES_INDEPENDENT
|
|
if dict.HasKey(IEALLSAMPLESINDEPENDENT_DICT_KEY) then
|
|
result.SetUINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, DWORD(dict.GetBoolean(IEALLSAMPLESINDEPENDENT_DICT_KEY)));
|
|
|
|
// IEAUDIOPREFERWAVEFORMATEX_DICT_KEY -> MF_MT_AUDIO_PREFER_WAVEFORMATEX
|
|
if dict.HasKey(IEAUDIOPREFERWAVEFORMATEX_DICT_KEY) then
|
|
result.SetUINT32(MF_MT_AUDIO_PREFER_WAVEFORMATEX, DWORD(dict.GetBoolean(IEAUDIOPREFERWAVEFORMATEX_DICT_KEY)));
|
|
|
|
// MF_MT_AUDIO_AVG_BYTES_PER_SECOND -> IEAUDIOAVGBYTESPERSECOND_DICT_KEY
|
|
if dict.HasKey(IEAUDIOAVGBYTESPERSECOND_DICT_KEY) then
|
|
result.SetUINT32(MF_MT_AUDIO_AVG_BYTES_PER_SECOND, dict.GetInteger(IEAUDIOAVGBYTESPERSECOND_DICT_KEY));
|
|
|
|
// IEVIDEOROTATION_DICT_KEY -> MF_MT_VIDEO_ROTATION (win8 only)
|
|
if dict.HasKey(IEVIDEOROTATION_DICT_KEY) then
|
|
result.SetUINT32(MF_MT_VIDEO_ROTATION, dict.GetInteger(IEVIDEOROTATION_DICT_KEY));
|
|
|
|
// IEPIXELASPECTRATIO_DICT_KEY -> MF_MT_PIXEL_ASPECT_RATIO
|
|
if dict.HasKey(IEPIXELASPECTRATIO_DICT_KEY) then
|
|
begin
|
|
ws := dict.GetString(IEPIXELASPECTRATIO_DICT_KEY);
|
|
p := Pos(ws, ':');
|
|
if p > 0 then
|
|
begin
|
|
num := StrToIntDef(Copy(ws, 1, p - 1), 0);
|
|
den := StrToIntDef(Copy(ws, p + 1, length(ws)), 0);
|
|
if (num <> 0 ) and (den <> 0) then
|
|
result.SetUINT64(MF_MT_PIXEL_ASPECT_RATIO, (uint64(num) shl 32) or uint64(den));
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
|
|
function IECreateMediaTypeFromDictionary(dictStr: WideString): IE_IMFMediaType; overload;
|
|
var
|
|
dict: TIEDictionary;
|
|
begin
|
|
dict := TIEDictionary.Create();
|
|
try
|
|
dict.Parse(dictStr);
|
|
result := IECreateMediaTypeFromDictionary(dict);
|
|
finally
|
|
dict.Free;
|
|
end;
|
|
end;
|
|
|
|
|
|
{!!
|
|
<FS>IEMediaFoundationTimeToStr
|
|
|
|
<FM>Declaration<FC>
|
|
function IEMediaFoundationTimeToStr(time: int64): string;
|
|
|
|
<FM>Description<FN>
|
|
Converts Media Foundation times (100 nanosecond units) to their string representation (HH:MM:SS:DD).
|
|
|
|
<TABLE>
|
|
<R> <H>Parameter</H> <H>Description</H> </R>
|
|
<R> <C><FC>time<FN></C> <C>The Media Foundation time in 100 nanosecond units</C> </R>
|
|
</TABLE>
|
|
|
|
<FM>Example<FC>
|
|
// Get the source duration as a 'HH:MM:SS:DD' string
|
|
durationStr := IEMediaFoundationTimeToStr(ImageEnView1.IO.MediaFoundationSourceReader.Duration);
|
|
|
|
<FM>See Also<FN>
|
|
- <A TIEMediaFoundationSourceReader.Duration>
|
|
- <A IEMediaFoundationTimeToSec>
|
|
!!}
|
|
function IEMediaFoundationTimeToStr(time: int64): string;
|
|
var
|
|
tot: int64;
|
|
hh, mm, ss, ds: integer;
|
|
begin
|
|
tot := time div 100000;
|
|
hh := tot div 360000;
|
|
mm := (tot - (hh * 360000)) div 6000;
|
|
ss := (tot - (hh * 360000) - (mm * 6000)) div 100;
|
|
ds := (tot - (hh * 360000) - (mm * 6000) - (ss * 100));
|
|
result := Format('%.2d:%.2d:%.2d:%.2d', [hh, mm, ss, ds]);
|
|
end;
|
|
|
|
const
|
|
Nanoseconds_per_Second = Int64(1000000000);
|
|
|
|
{!!
|
|
<FS>IEMediaFoundationTimeToSec
|
|
|
|
<FM>Declaration<FC>
|
|
function IEMediaFoundationTimeToSec(time: int64): Double;
|
|
|
|
<FM>Description<FN>
|
|
Converts Media Foundation times (100 nanosecond units) to seconds (There are 1 billion nanoseconds to a second).
|
|
|
|
<TABLE>
|
|
<R> <H>Parameter</H> <H>Description</H> </R>
|
|
<R> <C><FC>time<FN></C> <C>The Media Foundation time in 100 nanosecond units</C> </R>
|
|
</TABLE>
|
|
|
|
<FM>Example<FC>
|
|
// Display length in seconds
|
|
if IEMediaFoundationTimeToSec(ImageEnView1.IO.MediaFoundationSourceReader.Duration) < 1 then
|
|
lblLength.Caption := '< 1 Sec.'
|
|
else
|
|
lblLength.Caption := format('%d Sec.', [Round(IEMediaFoundationTimeToSec(ImageEnView1.IO.MediaFoundationSourceReader.Duration))]);
|
|
|
|
<FM>See Also<FN>
|
|
- <A IESecToMediaFoundationTime>
|
|
- <A IEMediaFoundationTimeToStr>
|
|
!!}
|
|
function IEMediaFoundationTimeToSec(time: int64): Double;
|
|
begin
|
|
result := time / Nanoseconds_per_Second;
|
|
end;
|
|
|
|
|
|
{!!
|
|
<FS>IESecToMediaFoundationTime
|
|
|
|
<FM>Declaration<FC>
|
|
function IESecToMediaFoundationTime(sec: Double): int64;
|
|
|
|
<FM>Description<FN>
|
|
Converts a value in seconds to Media Foundation times (100 nanosecond units).
|
|
|
|
<TABLE>
|
|
<R> <H>Parameter</H> <H>Description</H> </R>
|
|
<R> <C><FC>time<FN></C> <C>The Media Foundation time in 100 nanosecond units</C> </R>
|
|
</TABLE>
|
|
|
|
<FM>Example<FC>
|
|
// Navigate ten seconds into the sample
|
|
ImageEnView1.IO.MediaFoundationSourceReader.SetPosition( IESecToMediaFoundationTime(10) );
|
|
|
|
<FM>See Also<FN>
|
|
- <A IEMediaFoundationTimeToSec>
|
|
!!}
|
|
function IESecToMediaFoundationTime(sec: Double): int64;
|
|
begin
|
|
result := Round(sec * Nanoseconds_per_Second);
|
|
end;
|
|
|
|
|
|
function IEGetMediaTypeMajorTypeStr(mediaType: IE_IMFMediaType): WideString;
|
|
var
|
|
majType: TGUID;
|
|
begin
|
|
if assigned(mediaType) then
|
|
begin
|
|
mediaType.GetGUID(MF_MT_MAJOR_TYPE, majType);
|
|
result := IEConvertMajorTypeToString(majType);
|
|
end
|
|
else
|
|
result := '';
|
|
end;
|
|
|
|
|
|
// Helpers
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// TIEMFDeviceList
|
|
|
|
constructor TIEMFDeviceList.Create();
|
|
begin
|
|
inherited;
|
|
m_devicesCount := 0;
|
|
m_devices := nil;
|
|
m_populated := false;
|
|
m_names := nil;
|
|
end;
|
|
|
|
|
|
destructor TIEMFDeviceList.Destroy();
|
|
begin
|
|
Clear();
|
|
inherited;
|
|
end;
|
|
|
|
|
|
procedure TIEMFDeviceList.Clear();
|
|
var
|
|
i: integer;
|
|
begin
|
|
for i := 0 to m_devicesCount - 1 do
|
|
begin
|
|
IE_IMFActivate(m_devices[i])._Release();
|
|
m_devices[i] := nil;
|
|
end;
|
|
CoTaskMemFree(m_devices);
|
|
|
|
m_devicesCount := 0;
|
|
m_devices := nil;
|
|
FreeAndNil(m_names);
|
|
end;
|
|
|
|
|
|
procedure TIEMFDeviceList.Populate();
|
|
var
|
|
attributes: IE_IMFAttributes;
|
|
begin
|
|
Clear();
|
|
|
|
attributes := nil;
|
|
MFCreateAttributes(attributes, 1);
|
|
attributes.SetGUID(MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE, MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_GUID);
|
|
|
|
m_populated := SUCCEEDED( MFEnumDeviceSources(attributes, m_devices, m_devicesCount) );
|
|
end;
|
|
|
|
|
|
// Populate() must be called before
|
|
function TIEMFDeviceList.GetCount(): integer;
|
|
begin
|
|
result := m_devicesCount;
|
|
end;
|
|
|
|
|
|
// Populate() must be called before
|
|
function TIEMFDeviceList.GetName(index: integer): WideString;
|
|
begin
|
|
result := IEGetStringFromAllocatedString(IE_IMFActivate(m_devices[index]), MF_DEVSOURCE_ATTRIBUTE_FRIENDLY_NAME);
|
|
end;
|
|
|
|
|
|
// Populate() must be called before
|
|
function TIEMFDeviceList.GetDevice(index: integer): IE_IMFActivate;
|
|
begin
|
|
result := IE_IMFActivate(m_devices[index]); // this increments IE_IMFActivate reference count
|
|
end;
|
|
|
|
|
|
// Populate() must be called before
|
|
function TIEMFDeviceList.GetNames(): TStringList;
|
|
var
|
|
i: integer;
|
|
begin
|
|
if m_names = nil then
|
|
begin
|
|
m_names := TStringList.Create();
|
|
for i := 0 to m_devicesCount - 1 do
|
|
m_names.Add(GetName(i));
|
|
end;
|
|
result := m_names;
|
|
end;
|
|
|
|
// TIEMFDeviceList
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// TIEMFReceivedSample
|
|
|
|
constructor TIEMFReceivedSample.Create(sample: IE_IMFSample; streamIndex: DWORD; streamFlags: DWORD; timeStamp: int64; mediaType: IE_IMFMediaType);
|
|
begin
|
|
inherited Create();
|
|
self.Sample := sample;
|
|
self.StreamIndex := streamIndex;
|
|
self.StreamFlags := streamFlags;
|
|
self.TimeStamp := timeStamp;
|
|
self.MediaType := mediaType;
|
|
self.StreamType := IEGetMediaTypeMajorTypeStr(mediaType);
|
|
end;
|
|
|
|
|
|
destructor TIEMFReceivedSample.Destroy();
|
|
begin
|
|
Sample := nil;
|
|
MediaType := nil;
|
|
inherited;
|
|
end;
|
|
|
|
|
|
{!!
|
|
<FS>TIEMFReceivedSample.DecodeSample
|
|
|
|
<FM>Declaration<FC>
|
|
function DecodeSample(destBitmap: <A TIEBitmap>): boolean;
|
|
|
|
<FM>Description<FN>
|
|
Decodes a video sample, filling the specified bitmap with the converted data.
|
|
|
|
Presently the following conversions are possible:
|
|
RGB24 -> RGB24 (copy only)
|
|
RGB32 -> RGB24
|
|
YUY2 -> RGB24
|
|
I420 -> RGB24
|
|
NV12 -> RGB24
|
|
|
|
<TABLE>
|
|
<R> <H>Parameter</H> <H>Description</H> </R>
|
|
<R> <C><FC>destBitmap<FN></C> <C>The destination bitmap for the decoded video sample</C> </R>
|
|
</TABLE>
|
|
|
|
Returns True on success. Returns False if the sample is not a video sample or if no decoder is found.
|
|
|
|
<FM>Example 1<FC>
|
|
// Handler for TImageEnView.OnMediaFoundatioNotify event
|
|
procedure TForm1.ImageEnVect1MediaFoundationNotify(Sender, MediaFoundationObject: TObject; NotifyType: TIEMediaFountationNotifyType);
|
|
var
|
|
sample: TIEMFReceivedSample;
|
|
begin
|
|
if NotifyType = iemfnFRAME then // is this a frame?
|
|
begin
|
|
sample := ImageEnView1.IO.MediaFoundationSourceReader.GetNextSample(); // retrieve frame sample
|
|
try
|
|
sample.DecodeSample(ImageEnView1.IEBitmap); // convert frame sample to bitmap
|
|
ImageEnView1.Update(); // update TImageEnView to show the new bitmap
|
|
finally
|
|
sample.Free(); // free the sample
|
|
end;
|
|
end;
|
|
end;
|
|
<FN>
|
|
|
|
Applications add new decoders by using the <A IEMediaFoundationGetVideoSampleDecoders> function and implementing the <A TIEMediaFoundationVideoSampleDecoder> abstract class.
|
|
|
|
<FM>Example 2<FC>
|
|
IEMediaFoundationGetVideoSampleDecoders().Add(TIEMediaFoundationVideoSampleDecoder_YOURFORMAT.Create());
|
|
!!}
|
|
function TIEMFReceivedSample.DecodeSample(destBitmap: TIEBitmap): boolean;
|
|
var
|
|
mediaBuffer: IE_IMFMediaBuffer;
|
|
buffer: pbyte;
|
|
bufferLen, maxBufferLen: DWORD;
|
|
frameWidth, frameHeight: DWORD;
|
|
frameStride: integer;
|
|
frameFormat: WideString;
|
|
i: integer;
|
|
subType: TGUID;
|
|
begin
|
|
result := false;
|
|
|
|
if StreamType <> mmf_VIDEO_STREAM then
|
|
exit;
|
|
|
|
mediaBuffer := nil;
|
|
if assigned(Sample) then
|
|
Sample.ConvertToContiguousBuffer(mediaBuffer);
|
|
|
|
if assigned(mediaBuffer) then
|
|
begin
|
|
MediaType.GetGUID(MF_MT_SUBTYPE, subType);
|
|
frameFormat := IEConvertSubTypeToString(subType);
|
|
IEGetMediaTypeFrameSize(MediaType, frameWidth, frameHeight);
|
|
frameStride := IEGetMediaTypeFrameStride(MediaType, subType, frameWidth);
|
|
|
|
if frameStride = 0 then
|
|
exit;
|
|
|
|
if not SUCCEEDED(mediaBuffer.Lock(buffer, maxBufferLen, bufferLen)) then
|
|
exit;
|
|
|
|
try
|
|
|
|
for i := 0 to IEMediaFoundationGetVideoSampleDecoders().Count - 1 do
|
|
if (IEMediaFoundationGetVideoSampleDecoders()[i] as TIEMediaFoundationVideoSampleDecoder).GetSubType() = frameFormat then
|
|
begin
|
|
result := (IEMediaFoundationGetVideoSampleDecoders()[i] as TIEMediaFoundationVideoSampleDecoder).Decode(frameWidth, frameHeight, frameStride, buffer, bufferLen, destBitmap);
|
|
break;
|
|
end;
|
|
|
|
finally
|
|
|
|
mediaBuffer.Unlock();
|
|
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
// TIEMFReceivedSample
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// TIEMediaFoundationVideoSampleDecoder_YUY2
|
|
|
|
type TIEMediaFoundationVideoSampleDecoder_YUY2 = class(TIEMediaFoundationVideoSampleDecoder)
|
|
public
|
|
function GetSubType(): WideString; override;
|
|
function Decode(width: DWORD; height: DWORD; stride: integer; buffer: pointer; bufferLen: DWORD; destBitmap: TIEBitmap): boolean; override;
|
|
end;
|
|
|
|
function TIEMediaFoundationVideoSampleDecoder_YUY2.GetSubType(): WideString;
|
|
begin
|
|
result := 'YUY2';
|
|
end;
|
|
|
|
function TIEMediaFoundationVideoSampleDecoder_YUY2.Decode(width: DWORD; height: DWORD; stride: integer; buffer: pointer; bufferLen: DWORD; destBitmap: TIEBitmap): boolean;
|
|
begin
|
|
destBitmap.Allocate(width, height, ie24RGB);
|
|
_CopyYUY2ToBitmap(buffer, destBitmap, stride > 0);
|
|
result := true;
|
|
end;
|
|
|
|
// TIEMediaFoundationVideoSampleDecoder_YUY2
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// TIEMediaFoundationVideoSampleDecoder_RGB24
|
|
|
|
type TIEMediaFoundationVideoSampleDecoder_RGB24 = class(TIEMediaFoundationVideoSampleDecoder)
|
|
public
|
|
function GetSubType(): WideString; override;
|
|
function Decode(width: DWORD; height: DWORD; stride: integer; buffer: pointer; bufferLen: DWORD; destBitmap: TIEBitmap): boolean; override;
|
|
end;
|
|
|
|
function TIEMediaFoundationVideoSampleDecoder_RGB24.GetSubType(): WideString;
|
|
begin
|
|
result := 'RGB24';
|
|
end;
|
|
|
|
function TIEMediaFoundationVideoSampleDecoder_RGB24.Decode(width: DWORD; height: DWORD; stride: integer; buffer: pointer; bufferLen: DWORD; destBitmap: TIEBitmap): boolean;
|
|
var
|
|
i: integer;
|
|
begin
|
|
destBitmap.Allocate(width, height, ie24RGB);
|
|
if stride < 0 then
|
|
for i := height - 1 downto 0 do
|
|
begin
|
|
CopyMemory(destBitmap.ScanLine[i], PRGB(buffer), width * 3);
|
|
inc(pbyte(buffer), -stride);
|
|
end
|
|
else
|
|
for i := 0 to height - 1 do
|
|
begin
|
|
CopyMemory(destBitmap.ScanLine[i], PRGB(buffer), width * 3);
|
|
inc(pbyte(buffer), stride);
|
|
end;
|
|
result := true;
|
|
end;
|
|
|
|
// TIEMediaFoundationVideoSampleDecoder_RGB24
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// TIEMediaFoundationVideoSampleDecoder_RGB32
|
|
|
|
type TIEMediaFoundationVideoSampleDecoder_RGB32 = class(TIEMediaFoundationVideoSampleDecoder)
|
|
public
|
|
function GetSubType(): WideString; override;
|
|
function Decode(width: DWORD; height: DWORD; stride: integer; buffer: pointer; bufferLen: DWORD; destBitmap: TIEBitmap): boolean; override;
|
|
end;
|
|
|
|
function TIEMediaFoundationVideoSampleDecoder_RGB32.GetSubType(): WideString;
|
|
begin
|
|
result := 'RGB32';
|
|
end;
|
|
|
|
function TIEMediaFoundationVideoSampleDecoder_RGB32.Decode(width: DWORD; height: DWORD; stride: integer; buffer: pointer; bufferLen: DWORD; destBitmap: TIEBitmap): boolean;
|
|
var
|
|
i: integer;
|
|
procedure CopyRow();
|
|
var
|
|
j: integer;
|
|
p_bgra: PRGBA;
|
|
p_bgr: PRGBA;
|
|
wm2: integer;
|
|
begin
|
|
p_bgra := buffer;
|
|
p_bgr := destBitmap.ScanLine[i];
|
|
wm2 := width - 2; // -2 = avoid copying the last pixel
|
|
for j := 0 to wm2 do
|
|
begin
|
|
p_bgr^ := p_bgra^;
|
|
inc(PRGB(p_bgr));
|
|
inc(p_bgra);
|
|
end;
|
|
// last pixel
|
|
p_bgr^.b := p_bgra^.b;
|
|
p_bgr^.g := p_bgra^.g;
|
|
p_bgr^.r := p_bgra^.r;
|
|
end;
|
|
begin
|
|
destBitmap.Allocate(width, height, ie24RGB);
|
|
if stride < 0 then
|
|
for i := height - 1 downto 0 do
|
|
begin
|
|
CopyRow();
|
|
inc(pbyte(buffer), -stride);
|
|
end
|
|
else
|
|
for i := 0 to height - 1 do
|
|
begin
|
|
CopyRow();
|
|
inc(pbyte(buffer), stride);
|
|
end;
|
|
result := true;
|
|
end;
|
|
|
|
// TIEMediaFoundationVideoSampleDecoder_RGB32
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// TIEMediaFoundationVideoSampleDecoder_I420
|
|
|
|
type TIEMediaFoundationVideoSampleDecoder_I420 = class(TIEMediaFoundationVideoSampleDecoder)
|
|
public
|
|
function GetSubType(): WideString; override;
|
|
function Decode(width: DWORD; height: DWORD; stride: integer; buffer: pointer; bufferLen: DWORD; destBitmap: TIEBitmap): boolean; override;
|
|
end;
|
|
|
|
function TIEMediaFoundationVideoSampleDecoder_I420.GetSubType(): WideString;
|
|
begin
|
|
result := 'I420';
|
|
end;
|
|
|
|
function TIEMediaFoundationVideoSampleDecoder_I420.Decode(width: DWORD; height: DWORD; stride: integer; buffer: pointer; bufferLen: DWORD; destBitmap: TIEBitmap): boolean;
|
|
begin
|
|
destBitmap.Allocate(width, height, ie24RGB);
|
|
_CopyI420ToBitmap(buffer, destBitmap, stride > 0);
|
|
result := true;
|
|
end;
|
|
|
|
// TIEMediaFoundationVideoSampleDecoder_I420
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// TIEMediaFoundationVideoSampleDecoder_NV12
|
|
|
|
type TIEMediaFoundationVideoSampleDecoder_NV12 = class(TIEMediaFoundationVideoSampleDecoder)
|
|
public
|
|
function GetSubType(): WideString; override;
|
|
function Decode(width: DWORD; height: DWORD; stride: integer; buffer: pointer; bufferLen: DWORD; destBitmap: TIEBitmap): boolean; override;
|
|
end;
|
|
|
|
function TIEMediaFoundationVideoSampleDecoder_NV12.GetSubType(): WideString;
|
|
begin
|
|
result := 'NV12';
|
|
end;
|
|
|
|
function TIEMediaFoundationVideoSampleDecoder_NV12.Decode(width: DWORD; height: DWORD; stride: integer; buffer: pointer; bufferLen: DWORD; destBitmap: TIEBitmap): boolean;
|
|
begin
|
|
destBitmap.Allocate(width, height, ie24RGB);
|
|
_CopyNV12ToBitmap(buffer, destBitmap, stride > 0);
|
|
result := true;
|
|
end;
|
|
|
|
// TIEMediaFoundationVideoSampleDecoder_NV12
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// TIEMediaFoundationReaderWindowNotifyReceiver
|
|
|
|
constructor TIEMediaFoundationReaderWindowNotifyReceiver.Create(notifyWindow: THandle; notifyMessage: DWORD);
|
|
begin
|
|
inherited Create();
|
|
m_notifyWindow := notifyWindow;
|
|
m_notifyMessage := notifyMessage;
|
|
end;
|
|
|
|
|
|
destructor TIEMediaFoundationReaderWindowNotifyReceiver.Destroy();
|
|
begin
|
|
inherited;
|
|
end;
|
|
|
|
|
|
procedure TIEMediaFoundationReaderWindowNotifyReceiver.ReceiveNotify(sender: TObject; notifyType: TIEMediaFountationNotifyType; dwStreamIndex: DWORD; dwStreamFlags: DWORD; llTimestamp: int64; pSample: IE_IMFSample; mediaType: IE_IMFMediaType; pEvent: IE_IMFMediaEvent);
|
|
begin
|
|
if (TIEMediaFoundationSourceReader(sender).DiscardAudioSamples = false) or (IEGetMediaTypeMajorTypeStr(mediaType) <> mmf_AUDIO_STREAM) or (notifyType <> iemfnFRAME) then
|
|
PostMessage(m_notifyWindow, m_notifyMessage, WPARAM(notifyType), LPARAM(pointer(sender)));
|
|
end;
|
|
|
|
// TIEMediaFoundationReaderWindowNotifyReceiver
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// TIEMediaFoundationSourceReaderCallback
|
|
|
|
constructor TIEMediaFoundationSourceReaderCallback.Create(OnCallBack: TIEMediaFoundationSourceReaderCallbackEvent);
|
|
begin
|
|
m_onCallBack := OnCallBack;
|
|
end;
|
|
|
|
|
|
function TIEMediaFoundationSourceReaderCallback.OnReadSample(hrStatus: HRESULT; dwStreamIndex: DWORD; dwStreamFlags: DWORD; llTimestamp: int64; pSample: IE_IMFSample): HRESULT;
|
|
begin
|
|
result := m_onCallBack(mfrceONREADSAMPLE, hrStatus, dwStreamIndex, dwStreamFlags, llTimestamp, pSample, nil);
|
|
end;
|
|
|
|
|
|
function TIEMediaFoundationSourceReaderCallback.OnFlush(dwStreamIndex: DWORD): HRESULT;
|
|
begin
|
|
result := m_onCallBack(mfrceONFLUSH, S_OK, dwStreamIndex, 0, 0, nil, nil);
|
|
end;
|
|
|
|
|
|
function TIEMediaFoundationSourceReaderCallback.OnEvent(dwStreamIndex: DWORD; pEvent: IE_IMFMediaEvent): HRESULT;
|
|
begin
|
|
result := m_onCallBack(mfrceONEVENT, S_OK, dwStreamIndex, 0, 0, nil, pEvent);
|
|
end;
|
|
|
|
|
|
// TIEMediaFoundationSourceReaderCallback
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// TIEMediaFoundationSourceReader
|
|
|
|
constructor TIEMediaFoundationSourceReader.Create();
|
|
begin
|
|
inherited Create();
|
|
|
|
m_source := nil;
|
|
m_sourceReader := nil;
|
|
m_selectedActivate := nil;
|
|
m_streams := nil;
|
|
m_selectedMediaType := nil;
|
|
m_duration := 0;
|
|
m_videoInputs := nil;
|
|
m_notifyReceivers := nil;
|
|
m_capturing := false;
|
|
m_receivedSamples := nil;
|
|
m_delayFramePost := false;
|
|
m_frameRequested := 0;
|
|
m_videoProcessor := nil;
|
|
m_samplesBufferSize := 1;
|
|
m_discardAudioSamples := true;
|
|
|
|
m_IsAvailable := IEMFStartup();
|
|
|
|
if m_IsAvailable then
|
|
begin
|
|
m_lock := TCriticalSection.Create();
|
|
|
|
m_streams := TObjectList.Create();
|
|
m_selectedMediaType := TObjectList.Create();
|
|
m_videoInputs := TIEMFDeviceList.Create();
|
|
m_notifyReceivers := TInterfaceList.Create();
|
|
m_receivedSamples := TObjectList.Create();
|
|
end;
|
|
end;
|
|
|
|
|
|
destructor TIEMediaFoundationSourceReader.Destroy();
|
|
begin
|
|
if m_IsAvailable then
|
|
begin
|
|
PauseCapture();
|
|
Flush();
|
|
|
|
FreeAndNil(m_selectedMediaType);
|
|
FreeAndNil(m_streams);
|
|
|
|
FreeAndNil(m_notifyReceivers);
|
|
m_selectedActivate := nil;
|
|
m_source := nil;
|
|
m_sourceReader := nil;
|
|
|
|
FreeAndNil(m_videoInputs);
|
|
|
|
ClearReceivedSamples();
|
|
FreeAndNil(m_receivedSamples);
|
|
|
|
FreeAndNil(m_videoProcessor);
|
|
|
|
IEMFShutdown();
|
|
|
|
FreeAndNil(m_lock);
|
|
end;
|
|
inherited;
|
|
end;
|
|
|
|
|
|
procedure TIEMediaFoundationSourceReader.Lock();
|
|
begin
|
|
m_lock.Enter();
|
|
end;
|
|
|
|
|
|
procedure TIEMediaFoundationSourceReader.Unlock();
|
|
begin
|
|
m_lock.Leave();
|
|
end;
|
|
|
|
|
|
function TIEMediaFoundationSourceReader.SetInput(activate: IE_IMFActivate): boolean;
|
|
var
|
|
attributes: IE_IMFAttributes;
|
|
begin
|
|
result := false;
|
|
|
|
m_sourceReader := nil;
|
|
m_source := nil;
|
|
m_streams.Clear();
|
|
|
|
m_selectedActivate := activate;
|
|
|
|
// create media source
|
|
if not SUCCEEDED(activate.ActivateObject(IE_IMFMediaSource_GUID, m_source)) then
|
|
exit;
|
|
activate.DetachObject(); // this allows to reuse the activate object
|
|
|
|
// setup source reader attributes
|
|
attributes := nil;
|
|
MFCreateAttributes(attributes, 3);
|
|
// support callback?
|
|
if IsAsyncMode() then
|
|
attributes.SetUnknown(MF_SOURCE_READER_ASYNC_CALLBACK, TIEMediaFoundationSourceReaderCallback.Create(SourceReaderCallback));
|
|
// this is needed in order to convert among mediatypes automatically
|
|
attributes.SetUINT32(MF_SOURCE_READER_ENABLE_VIDEO_PROCESSING, DWORD(true));
|
|
// enable hardware transforms
|
|
attributes.SetUINT32(MF_READWRITE_ENABLE_HARDWARE_TRANSFORMS, DWORD(true));
|
|
|
|
// create source reader
|
|
result := SUCCEEDED(MFCreateSourceReaderFromMediaSource(m_source, attributes, m_sourceReader));
|
|
|
|
if result then
|
|
begin
|
|
m_duration := GetDuration();
|
|
PopulateStreams();
|
|
end;
|
|
end;
|
|
|
|
|
|
{!!
|
|
<FS>TIEMediaFoundationSourceReader.SetVideoInput
|
|
|
|
<FM>Declaration<FC>
|
|
function SetVideoInput(index: Integer): boolean;
|
|
function SetVideoInput(name: WideString): boolean;
|
|
|
|
<FM>Description<FN>
|
|
Select one of the <A TIEMediaFoundationSourceReader.VideoInputs> devices as the video source.
|
|
|
|
<TABLE>
|
|
<R> <H>Parameter</H> <H>Description</H> </R>
|
|
<R> <C><FC>index<FN></C> <C>Index of the video input device. Ranges from 0 up to <A TIEMediaFoundationSourceReader.VideoInputs>.Count - 1</C> </R>
|
|
<R> <C><FC>name<FN></C> <C>Name of the video input device. Must be one of <A TIEMediaFoundationSourceReader.VideoInputs> values</C> </R>
|
|
</TABLE>
|
|
|
|
<FM>Example<FC>
|
|
// Select first video input (first webcam)
|
|
ImageEnView1.IO.MediaFoundationSourceReader.SetVideoInput(0);
|
|
|
|
<FM>See Also<FN>
|
|
- <A TIEMediaFoundationSourceReader.VideoInputs>
|
|
- <A TIEMediaFoundationSourceReader.SetFileInput>
|
|
- <A TIEMediaFoundationSourceReader.SetURLInput>
|
|
!!}
|
|
function TIEMediaFoundationSourceReader.SetVideoInput(index: integer): boolean;
|
|
begin
|
|
CheckVideoInputIndex(index);
|
|
m_delayFramePost := false;
|
|
result := SetInput(m_videoInputs.GetDevice(index));
|
|
end;
|
|
|
|
|
|
function TIEMediaFoundationSourceReader.SetVideoInput(name: WideString): boolean;
|
|
begin
|
|
result := SetVideoInput(m_videoInputs.getNames().IndexOf(name));
|
|
end;
|
|
|
|
|
|
{!!
|
|
<FS>TIEMediaFoundationSourceReader.SetFileInput
|
|
|
|
<FM>Declaration<FC>
|
|
function SetFileInput(filename: WideString): boolean;
|
|
|
|
<FM>Description<FN>
|
|
Specifies a file as the video/audio source.
|
|
|
|
<TABLE>
|
|
<R> <H>Parameter</H> <H>Description</H> </R>
|
|
<R> <C><FC>filename<FN></C> <C>Full path of the input file</C> </R>
|
|
</TABLE>
|
|
|
|
<FM>Example<FC>
|
|
// Set 'input.mp4' as the video/audio source
|
|
ImageEnView1.IO.MediaFoundationSourceReader.SetFileInput('D:\input.mp4');
|
|
|
|
<FM>See Also<FN>
|
|
- <A TIEMediaFoundationSourceReader.SetVideoInput>
|
|
- <A TIEMediaFoundationSourceReader.SetURLInput>
|
|
!!}
|
|
function TIEMediaFoundationSourceReader.SetFileInput(filename: WideString): boolean;
|
|
var
|
|
byteStream: IE_IMFByteStream;
|
|
attributes: IE_IMFAttributes;
|
|
begin
|
|
result := false;
|
|
|
|
m_sourceReader := nil;
|
|
m_source := nil;
|
|
m_streams.Clear();
|
|
|
|
m_selectedActivate := nil;
|
|
m_delayFramePost := true;
|
|
|
|
byteStream := nil;
|
|
if not SUCCEEDED(MFCreateFile(MF_ACCESSMODE_READ, MF_OPENMODE_FAIL_IF_NOT_EXIST, MF_FILEFLAGS_NONE, @filename[1], byteStream)) then
|
|
exit;
|
|
|
|
// setup source reader attributes
|
|
attributes := nil;
|
|
MFCreateAttributes(attributes, 3);
|
|
// support callback?
|
|
if IsAsyncMode() then
|
|
attributes.SetUnknown(MF_SOURCE_READER_ASYNC_CALLBACK, TIEMediaFoundationSourceReaderCallback.Create(SourceReaderCallback));
|
|
// this is needed in order to convert among mediatypes automatically
|
|
attributes.SetUINT32(MF_SOURCE_READER_ENABLE_VIDEO_PROCESSING, DWORD(true));
|
|
// enable hardware transforms
|
|
attributes.SetUINT32(MF_READWRITE_ENABLE_HARDWARE_TRANSFORMS, DWORD(true));
|
|
|
|
// create source reader
|
|
result := SUCCEEDED(MFCreateSourceReaderFromByteStream(byteStream, attributes, m_sourceReader));
|
|
|
|
if result then
|
|
begin
|
|
m_duration := GetDuration();
|
|
PopulateStreams();
|
|
end;
|
|
end;
|
|
|
|
|
|
{!!
|
|
<FS>TIEMediaFoundationSourceReader.SetURLInput
|
|
|
|
<FM>Declaration<FC>
|
|
function SetURLInput(URL: WideString): boolean;
|
|
|
|
<FM>Description<FN>
|
|
Specifies a URL as the video/audio source.
|
|
|
|
<TABLE>
|
|
<R> <H>Parameter</H> <H>Description</H> </R>
|
|
<R> <C><FC>URL<FN></C> <C>Web link to a video/audio source</C> </R>
|
|
</TABLE>
|
|
|
|
<FM>Example<FC>
|
|
ImageEnView1.IO.MediaFoundationSourceReader.SetURLInput('http://avideos.5min.com//29/5181029/518102846_4.mp4');
|
|
|
|
<FM>See Also<FN>
|
|
- <A TIEMediaFoundationSourceReader.SetVideoInput>
|
|
- <A TIEMediaFoundationSourceReader.SetFileInput>
|
|
!!}
|
|
function TIEMediaFoundationSourceReader.SetURLInput(URL: WideString): boolean;
|
|
var
|
|
attributes: IE_IMFAttributes;
|
|
begin
|
|
m_sourceReader := nil;
|
|
m_source := nil;
|
|
m_streams.Clear();
|
|
|
|
m_selectedActivate := nil;
|
|
m_delayFramePost := true;
|
|
|
|
// setup source reader attributes
|
|
attributes := nil;
|
|
MFCreateAttributes(attributes, 3);
|
|
// support callback?
|
|
if IsAsyncMode() then
|
|
attributes.SetUnknown(MF_SOURCE_READER_ASYNC_CALLBACK, TIEMediaFoundationSourceReaderCallback.Create(SourceReaderCallback));
|
|
// this is needed in order to convert among mediatypes automatically
|
|
attributes.SetUINT32(MF_SOURCE_READER_ENABLE_VIDEO_PROCESSING, DWORD(true));
|
|
// enable hardware transforms
|
|
attributes.SetUINT32(MF_READWRITE_ENABLE_HARDWARE_TRANSFORMS, DWORD(true));
|
|
|
|
// create source reader
|
|
result := SUCCEEDED(MFCreateSourceReaderFromURL(@URL[1], attributes, m_sourceReader));
|
|
|
|
if result then
|
|
begin
|
|
m_duration := GetDuration();
|
|
PopulateStreams();
|
|
end;
|
|
end;
|
|
|
|
|
|
{!!
|
|
<FS>TIEMediaFoundationSourceReader.Duration
|
|
|
|
<FM>Declaration<FC>
|
|
property Duration: int64;
|
|
|
|
<FM>Description<FN>
|
|
Returns the duration of a source media file, in 100 nanosecond units (There are 1 billion nanoseconds to a second).
|
|
|
|
<FM>Example 1<FC>
|
|
// Get the source duration as a 'HH:MM:SS:DD' string
|
|
duration := IEMediaFoundationTimeToStr(ImageEnView1.IO.MediaFoundationSourceReader.Duration);
|
|
|
|
<FM>Example 2<FC>
|
|
// Display length in seconds
|
|
if IEMediaFoundationTimeToSec(ImageEnView1.IO.MediaFoundationSourceReader.Duration) < 1 then
|
|
lblLength.Caption := '< 1 Sec.'
|
|
else
|
|
lblLength.Caption := format('%d Sec.', [Round(IEMediaFoundationTimeToSec(ImageEnView1.IO.MediaFoundationSourceReader.Duration))]);
|
|
|
|
<FM>See Also<FN>
|
|
- <A IEMediaFoundationTimeToStr>
|
|
- <A IEMediaFoundationTimeToSec>
|
|
!!}
|
|
function TIEMediaFoundationSourceReader.GetDuration(): int64;
|
|
var
|
|
prop: PROPVARIANT;
|
|
begin
|
|
result := 0;
|
|
if assigned(m_sourceReader) and SUCCEEDED(m_sourceReader.GetPresentationAttribute(MF_SOURCE_READER_MEDIASOURCE, MF_PD_DURATION, prop)) then
|
|
result := prop.uhVal.QuadPart;
|
|
end;
|
|
|
|
|
|
procedure TIEMediaFoundationSourceReader.PopulateStreams();
|
|
var
|
|
streamIndex: integer;
|
|
mediaTypeIndex: integer;
|
|
mediaType: IE_IMFMediaType;
|
|
mediaTypes: TObjectList;
|
|
begin
|
|
m_streams.Clear();
|
|
streamIndex := 0;
|
|
mediaTypeIndex := 0;
|
|
while SUCCEEDED( m_sourceReader.GetNativeMediaType(streamIndex, mediaTypeIndex, mediaType) ) do
|
|
begin
|
|
mediaTypes := TObjectList.Create();
|
|
m_streams.Add(mediaTypes); // add new stream
|
|
mediaTypes.Add(IECreateDictionaryFromMediaType(mediaType)); // add first mediatype to the stream
|
|
inc(mediaTypeIndex);
|
|
while SUCCEEDED( m_sourceReader.GetNativeMediaType(streamIndex, mediaTypeIndex, mediaType) ) do
|
|
begin
|
|
mediaTypes.Add(IECreateDictionaryFromMediaType(mediaType)); // add other mediatypes to the stream
|
|
inc(mediaTypeIndex);
|
|
end;
|
|
inc(streamIndex);
|
|
mediaTypeIndex := 0;
|
|
end;
|
|
end;
|
|
|
|
|
|
// assumes m_streams is populated (to get number of streams)
|
|
procedure TIEMediaFoundationSourceReader.PopulateSelectedMediaType();
|
|
var
|
|
i: integer;
|
|
mediaType: IE_IMFMediaType;
|
|
begin
|
|
m_selectedMediaType.Clear();
|
|
for i := 0 to StreamCount - 1 do
|
|
begin
|
|
m_sourceReader.GetCurrentMediaType(i, mediaType);
|
|
m_selectedMediaType.Add(IECreateDictionaryFromMediaType(mediaType));
|
|
end;
|
|
end;
|
|
|
|
|
|
{!!
|
|
<FS>TIEMediaFoundationSourceReader.GetCurrentMediaType
|
|
|
|
<FM>Declaration<FC>
|
|
function GetCurrentMediaType(streamIndex: integer): <A TIEDictionary>;
|
|
function GetCurrentMediaType(streamType: WideString): <A TIEDictionary>;
|
|
|
|
<FM>Description<FN>
|
|
Returns the actual media type for the specified stream.
|
|
Applications should call GetCurrentMediaType to check the actual selected media type after a call to SetMediaTypeXXX or SelectMediaType.
|
|
See <A TIEMediaFoundationSourceReader.GetMediaType> for the list of keys in the resulting dictionary.
|
|
|
|
<TABLE>
|
|
<R> <H>Parameter</H> <H>Description</H> </R>
|
|
<R> <C><FC>streamIndex<FN></C> <C>Index of the stream, in the range of 0 to <A TIEMediaFoundationSourceReader.StreamCount> - 1</C> </R>
|
|
<R> <C><FC>streamType<FN></C> <C>A string representing the stream type. Only the first stream of this type will be considered. Can be any one of the values accepted by <A TIEMediaFoundationSourceReader.GetStreamType></C> </R>
|
|
</TABLE>
|
|
|
|
<FM>Example<FC>
|
|
// Get the actual video format (ie MJPEG may be converted to YUY2)
|
|
with ImageEnView1.IO.MediaFoundationSourceReader.GetCurrentMediaType(mmf_VIDEO_STREAM) do
|
|
begin
|
|
Label4.Caption := Format('Actual video format: %d x %d %.1f fps %s',
|
|
[GetInteger(IEFRAMEWIDTH_DICT_KEY), // width
|
|
GetInteger(IEFRAMEHEIGHT_DICT_KEY), // height
|
|
GetDouble(IEFRAMERATE_DICT_KEY), // frame rate
|
|
GetString(IESUBTYPE_DICT_KEY) // subtype = color space
|
|
]);
|
|
end;
|
|
|
|
<FM>See Also<FN>
|
|
- <A TIEMediaFoundationSourceReader.GetMediaType>
|
|
- <A TIEMediaFoundationSourceReader.GetMediaTypesCount>
|
|
- <A TIEMediaFoundationSourceReader.SelectMediaType>
|
|
- <A TIEMediaFoundationSourceReader.SetMediaTypeAudio>
|
|
- <A TIEMediaFoundationSourceReader.SetMediaTypeCustom>
|
|
- <A TIEMediaFoundationSourceReader.SetMediaTypeVideo>
|
|
!!}
|
|
function TIEMediaFoundationSourceReader.GetCurrentMediaType(streamIndex: integer): TIEDictionary;
|
|
begin
|
|
result := nil;
|
|
if streamIndex < m_selectedMediaType.Count then
|
|
result := m_selectedMediaType[streamIndex] as TIEDictionary;
|
|
end;
|
|
|
|
|
|
function TIEMediaFoundationSourceReader.GetCurrentMediaType(streamType: WideString): TIEDictionary;
|
|
var
|
|
streamIndex: integer;
|
|
begin
|
|
result := nil;
|
|
streamIndex := IndexOfFirstStream(streamType);
|
|
if streamIndex > -1 then
|
|
result := GetCurrentMediaType(streamIndex);
|
|
end;
|
|
|
|
|
|
function TIEMediaFoundationSourceReader.GetCurrentMediaTypeIntf(streamIndex: integer): IE_IMFMediaType;
|
|
begin
|
|
result := nil;
|
|
m_sourceReader.GetCurrentMediaType(streamIndex, result);
|
|
end;
|
|
|
|
|
|
function TIEMediaFoundationSourceReader.GetCurrentMediaTypeIntf(streamType: WideString): IE_IMFMediaType;
|
|
var
|
|
streamIndex: integer;
|
|
begin
|
|
result := nil;
|
|
streamIndex := IndexOfFirstStream(streamType);
|
|
if streamIndex > -1 then
|
|
m_sourceReader.GetCurrentMediaType(streamIndex, result);
|
|
end;
|
|
|
|
|
|
{!!
|
|
<FS>TIEMediaFoundationSourceReader.StreamCount
|
|
|
|
<FM>Declaration<FC>
|
|
property StreamCount: integer;
|
|
|
|
<FM>Description<FN>
|
|
Returns the number of streams for the selected source.
|
|
|
|
<FM>Example<FC>
|
|
var
|
|
i: integer;
|
|
mediaType: TIEDictionary;
|
|
begin
|
|
// Fill streams listbox
|
|
ListBoxStreams.Clear();
|
|
with ImageEnView1.IO.MediaFoundationSourceReader do
|
|
begin
|
|
for i := 0 to StreamCount - 1 do
|
|
begin
|
|
mediaType := GetMediaType(i, 0);
|
|
ListBoxStreams.Items.Add(Format('%s', [mediaType.GetString(IEMAJORTYPE_DICT_KEY)]));
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
<FM>See Also<FN>
|
|
- <A TIEMediaFoundationSourceReader.GetStreamType>
|
|
- <A TIEMediaFoundationSourceReader.SetSelectedStreams>
|
|
!!}
|
|
function TIEMediaFoundationSourceReader.GetStreamCount(): integer;
|
|
begin
|
|
result := m_streams.Count;
|
|
end;
|
|
|
|
|
|
{!!
|
|
<FS>TIEMediaFoundationSourceReader.GetStreamType
|
|
|
|
<FM>Declaration<FC>
|
|
function GetStreamType(streamIndex: integer): WideString;
|
|
|
|
<FM>Description<FN>
|
|
Returns a string representing the type of the specified stream.
|
|
|
|
<TABLE>
|
|
<R> <H>Parameter</H> <H>Description</H> </R>
|
|
<R> <C><FC>streamIndex<FN></C> <C>Index of the stream, in the range of 0 to <A TIEMediaFoundationSourceReader.StreamCount> - 1</C> </R>
|
|
</TABLE>
|
|
|
|
Stream type can be one of the following values:
|
|
<TABLE>
|
|
<R> <H>Return value</H> <H>Description</H> <H>Const</H> </R>
|
|
<R> <C><FC>'Audio'<FN></C> <C>Audio stream</C> <FC>mmf_AUDIO_STREAM<FN> </R>
|
|
<R> <C><FC>'Video'<FN></C> <C>Video stream</C> <FC>mmf_VIDEO_STREAM<FN> </R>
|
|
<R> <C><FC>'Protected'<FN></C> <C>Protected media</C> <FC>mmf_PROTECTED_STREAM<FN> </R>
|
|
<R> <C><FC>'SAMI'<FN></C> <C>Synchronized Accessible Media Interchange (SAMI) captions</C> <FC>mmf_SAMI_STREAM<FN> </R>
|
|
<R> <C><FC>'Script'<FN></C> <C>Script stream</C> <FC>mmf_SCRIPT_STREAM<FN> </R>
|
|
<R> <C><FC>'Image'<FN></C> <C>Still image stream</C> <FC>mmf_IMAGE_STREAM<FN> </R>
|
|
<R> <C><FC>'HTML'<FN></C> <C>HTML stream</C> <FC>mmf_HTML_STREAM<FN> </R>
|
|
<R> <C><FC>'Binary'<FN></C> <C>Binary stream</C> <FC>mmf_BINARY_STREAM<FN> </R>
|
|
<R> <C><FC>'FileTransfer'<FN></C> <C>A stream that contains data files</C> <FC><FN> </R>
|
|
<R> <C><FC>'Unknown'<FN></C> <C>None of the above</C> <FC>mmf_FILETRANSFER_STREAM<FN> </R>
|
|
</TABLE>
|
|
|
|
<FM>See Also<FN>
|
|
- <A TIEMediaFoundationSourceReader.StreamCount>
|
|
!!}
|
|
function TIEMediaFoundationSourceReader.GetStreamType(streamIndex: integer): WideString;
|
|
begin
|
|
result := GetMediaType(streamIndex, 0).GetString(IEMAJORTYPE_DICT_KEY);
|
|
end;
|
|
|
|
|
|
{!!
|
|
<FS>TIEMediaFoundationSourceReader.IndexOfFirstStream
|
|
|
|
<FM>Declaration<FC>
|
|
function IndexOfFirstStream(streamType: WideString): integer;
|
|
|
|
<FM>Description<FN>
|
|
Returns the index of first stream of the specified type, or -1 if the stream type is not found.
|
|
|
|
<TABLE>
|
|
<R> <H>Parameter</H> <H>Description</H> </R>
|
|
<R> <C><FC>streamType<FN></C> <C>A string representing the stream type. Can be any one of the values accepted by <A TIEMediaFoundationSourceReader.GetStreamType></C> </R>
|
|
</TABLE>
|
|
|
|
<FM>Example<FC>
|
|
// Search for audio stream and enables audio renderer for that stream
|
|
audioStreamIndex := ImageEnView1.IO.MediaFoundationSourceReader.IndexOfFirstStream(mmf_AUDIO_STREAM);
|
|
ImageEnView1.IO.MediaFoundationSourceReader.SetSelectedStreams(audioStreamIndex, true);
|
|
ImageEnView1.IO.MediaFoundationSourceReader.SetMediaTypeAudio(audioStreamIndex, 'PCM');
|
|
ImageEnView1.IO.MediaFoundationSourceReader.PushNotifyReceiver( TIEMediaFoundationAudioRenderer.Create(audioStreamIndex) );
|
|
|
|
<FM>See Also<FN>
|
|
- <A TIEMediaFoundationSourceReader.GetStreamType>
|
|
- <A TIEMediaFoundationSourceReader.StreamCount>
|
|
!!}
|
|
// ret -1 = not found
|
|
function TIEMediaFoundationSourceReader.IndexOfFirstStream(streamType: WideString): integer;
|
|
begin
|
|
for result := 0 to StreamCount - 1 do
|
|
if SameText(GetStreamType(result), streamType) then
|
|
exit; // found
|
|
result := -1; // not found
|
|
end;
|
|
|
|
|
|
{!!
|
|
<FS>TIEMediaFoundationSourceReader.GetMediaTypesCount
|
|
|
|
<FM>Declaration<FC>
|
|
function GetMediaTypesCount(streamIndex: integer): integer;
|
|
function GetMediaTypesCount(streamType: WideString): integer;
|
|
|
|
<FM>Description<FN>
|
|
Returns the number of media types for the specified stream.
|
|
|
|
<TABLE>
|
|
<R> <H>Parameter</H> <H>Description</H> </R>
|
|
<R> <C><FC>streamIndex<FN></C> <C>Index of the stream, in the range of 0 to <A TIEMediaFoundationSourceReader.StreamCount> - 1</C> </R>
|
|
<R> <C><FC>streamType<FN></C> <C>A string representing the stream type. Only the first stream of this type will be considered. Can be any one of the values accepted by <A TIEMediaFoundationSourceReader.GetStreamType></C> </R>
|
|
</TABLE>
|
|
|
|
<FM>See Also<FN>
|
|
- <A TIEMediaFoundationSourceReader.StreamCount>
|
|
- <A TIEMediaFoundationSourceReader.GetMediaType>
|
|
!!}
|
|
function TIEMediaFoundationSourceReader.GetMediaTypesCount(streamIndex: integer): integer;
|
|
begin
|
|
result := (m_streams[streamIndex] as TObjectList).Count;
|
|
end;
|
|
|
|
|
|
// get "first" stream of specified type
|
|
function TIEMediaFoundationSourceReader.GetMediaTypesCount(streamType: WideString): integer;
|
|
var
|
|
streamIndex: integer;
|
|
begin
|
|
result := 0;
|
|
streamIndex := IndexOfFirstStream(streamType);
|
|
if streamIndex > -1 then
|
|
result := GetMediaTypesCount(streamIndex);
|
|
end;
|
|
|
|
|
|
{!!
|
|
<FS>TIEMediaFoundationSourceReader.GetMediaType
|
|
|
|
<FM>Declaration<FC>
|
|
function GetMediaType(streamIndex: integer; mediaTypeIndex: integer): <A TIEDictionary>;
|
|
function GetMediaType(streamType: WideString; mediaTypeIndex: integer): <A TIEDictionary>;
|
|
|
|
<FM>Description<FN>
|
|
Returns the media type for the specified stream and media type index.
|
|
Each source stream can support several media types (ie. frame size, frame format, etc..) so GetMediaType provides details about them.
|
|
|
|
<TABLE>
|
|
<R> <H>Parameter</H> <H>Description</H> </R>
|
|
<R> <C><FC>streamIndex<FN></C> <C>Index of the stream, in the range of 0 to <A TIEMediaFoundationSourceReader.StreamCount> - 1</C> </R>
|
|
<R> <C><FC>streamType<FN></C> <C>A string representing the stream type. Only the first stream of this type will be considered. Can be any one of the values accepted by <A TIEMediaFoundationSourceReader.GetStreamType></C> </R>
|
|
<R> <C><FC>mediaTypeIndex<FN></C> <C>Index of the media type, in the range of 0 to <A TIEMediaFoundationSourceReader.GetMediaTypesCount> - 1</C> </R>
|
|
</TABLE>
|
|
|
|
The resulting object is a dictionary which contains following media type attributes:
|
|
<TABLE>
|
|
<R> <H>Dictionary key</H> <H>Type</H> <H>Description</H> </R>
|
|
<R> <C><FC>IEMAJORTYPE_DICT_KEY<FN></C> <C>string</C> <C>Contains major stream type. See <A TIEMediaFoundationSourceReader.GetStreamType> for a list of stream types. The Media Foundation Type is MF_MT_MAJOR_TYPE</C> </R>
|
|
<R> <C><FC>IESUBTYPE_DICT_KEY<FN></C> <C>string</C> <C>Contains the media sub type. See below for a list of common values. The Media Foundation Type is MF_MT_SUBTYPE</C> </R>
|
|
<R> <C><FC>IECOMPRESSED_DICT_KEY<FN></C> <C>boolean</C> <C>If this attribute is True, the media type is a compressed format. The Media Foundation Type is MF_MT_COMPRESSED</C> </R>
|
|
<R> <C><FC>IEAVGBITRATE_DICT_KEY<FN></C> <C>integer</C> <C>Approximate data rate of the video stream, in bits per second. The Media Foundation Type is MF_MT_AVG_BITRATE</C> </R>
|
|
<R> <C><FC>IEDEFAULTSTRIDE_DICT_KEY<FN></C> <C>integer</C> <C>The number of bytes needed to go from one row of pixels to the next. The Media Foundation Type is MF_MT_DEFAULT_STRIDE</C> </R>
|
|
<R> <C><FC>IEFRAMERATE_DICT_KEY<FN></C> <C>double</C> <C>Frame rate of a video media type, in frames per second. The Media Foundation Type is MF_MT_FRAME_RATE</C> </R>
|
|
<R> <C><FC>IEFRAMERATEMAX_DICT_KEY<FN></C> <C>double</C> <C>The maximum frame rate that is supported by a video capture device, in frames per second. The Media Foundation Type is MF_MT_FRAME_RATE_RANGE_MAX</C> </R>
|
|
<R> <C><FC>IEFRAMERATEMIN_DICT_KEY<FN></C> <C>double</C> <C>The minimum frame rate that is supported by a video capture device, in frames per second. The Media Foundation Type is MF_MT_FRAME_RATE_RANGE_MIN</C> </R>
|
|
<R> <C><FC>IEFRAMEWIDTH_DICT_KEY<FN></C> <C>integer</C> <C>Width of a video frame, in pixels. The Media Foundation Type is MF_MT_FRAME_SIZE (high dword)</C> </R>
|
|
<R> <C><FC>IEFRAMEHEIGHT_DICT_KEY<FN></C> <C>integer</C> <C>Height of a video frame, in pixels. The Media Foundation Type is MF_MT_FRAME_SIZE (low dword)</C> </R>
|
|
<R> <C><FC>IEINTERLACEMODE_DICT_KEY<FN></C> <C>string</C> <C>Describes how the frames in a video media type are interlaced. The Media Foundation Type is MF_MT_INTERLACE_MODE</C> </R>
|
|
<R> <C><FC>IEVIDEOLIGHTING_DICT_KEY<FN></C> <C>string</C> <C>Specifies the optimal lighting conditions for a video media type. Allowed values are: 'Bright', 'Office', 'Dim' and 'Dark'. The Media Foundation Type is MF_MT_VIDEO_LIGHTING</C> </R>
|
|
<R> <C><FC>IEAUDIOBITSPERSAMPLE_DICT_KEY<FN></C> <C>integer</C> <C>Number of bits per audio sample in an audio media type. The Media Foundation Type is MF_MT_AUDIO_BITS_PER_SAMPLE</C> </R>
|
|
<R> <C><FC>IEAUDIOFLOATSAMPLESPERSECOND_DICT_KEY<FN></C> <C>double</C> <C>Number of audio samples per second. The Media Foundation Type is MF_MT_AUDIO_FLOAT_SAMPLES_PER_SECOND</C> </R>
|
|
<R> <C><FC>IEAUDIONUMCHANNELS_DICT_KEY<FN></C> <C>integer</C> <C>Number of audio channels. The Media Foundation Type is MF_MT_AUDIO_NUM_CHANNELS</C> </R>
|
|
<R> <C><FC>IEAUDIOSAMPLESPERSECOND_DICT_KEY<FN></C> <C>integer</C> <C>Number of audio samples per second. The Media Foundation Type is MF_MT_AUDIO_SAMPLES_PER_SECOND</C> </R>
|
|
<R> <C><FC>IEAUDIOBLOCKALIGNMENT_DICT_KEY<FN></C> <C>integer</C> <C>Block alignment, in bytes. For PCM audio formats, the block alignment is equal to the number of audio channels multiplied by the number of bytes per audio sample. The Media Foundation Type is MF_MT_AUDIO_BLOCK_ALIGNMENT</C> </R>
|
|
<R> <C><FC>IEALLSAMPLESINDEPENDENT_DICT_KEY<FN></C> <C>boolean</C> <C>Specifies for a media type whether each sample is independent of the other samples. The Media Foundation Type is MF_MT_ALL_SAMPLES_INDEPENDENT</C> </R>
|
|
<R> <C><FC>IEAUDIOAVGBYTESPERSECOND_DICT_KEY<FN></C> <C>integer</C> <C>Average number of bytes per second. The Media Foundation Type is MF_MT_AUDIO_AVG_BYTES_PER_SECOND</C> </R>
|
|
</TABLE>
|
|
|
|
The Video media sub types (IESUBTYPE_DICT_KEY) are: 'RGB8', 'RGB555', 'RGB565', 'RGB24', 'RGB32', 'ARGB32', 'AI44', 'AYUV', 'YUY2', 'YVYU', 'YVU9', 'UYVY', 'NV11', 'NV12', 'YV12', 'I420', 'IYUV', 'Y210', 'Y216',
|
|
'Y410', 'Y416', 'Y41P', 'Y41T', 'Y42T', 'P210', 'P216', 'P010', 'P016', 'v210', 'v216', 'v410', 'MP43', 'MP4S', 'M4S2', 'MP4V', 'WMV1', 'WMV2', 'WMV3', 'WVC1', 'MSS1', 'MSS2',
|
|
'MPG1', 'dvsl', 'dvsd', 'dvhd', 'dv25', 'dv50', 'dvh1', 'dvc ', 'H264', 'MJPG'.
|
|
|
|
The Audio media sub types (IESUBTYPE_DICT_KEY) are: 'PCM', 'Float', 'DTS', 'Dolby_AC3_SPDIF', 'DRM', 'WMAudioV8', 'WMAudioV9', 'WMAudio_Lossless', 'WMASPDIF', 'MSP1', 'MP3', 'MPEG', 'AAC', 'ADTS'.
|
|
|
|
The interlace modes (IEINTERLACEMODE_DICT_KEY) are: 'Progressive', 'FieldInterleavedUpperFirst', 'FieldInterleavedLowerFirst', 'FieldSingleUpper', 'FieldSingleLower', 'MixedInterlaceOrProgressive'.
|
|
|
|
<FM>Example<FC>
|
|
// Fill supported formats listbox
|
|
ListBox1.Clear();
|
|
with ImageEnView1.IO.MediaFoundationSourceReader do
|
|
begin
|
|
SetVideoInput(ComboBox1.ItemIndex);
|
|
for i := 0 to GetMediaTypesCount(mmf_VIDEO_STREAM) - 1 do
|
|
begin
|
|
mediaType := GetMediaType(mmf_VIDEO_STREAM, i);
|
|
ListBox1.Items.Add(Format('%d x %d %.1f fps (min fps: %.1f max fps: %.1f) %s',
|
|
[mediaType.GetInteger(IEFRAMEWIDTH_DICT_KEY), // width
|
|
mediaType.GetInteger(IEFRAMEHEIGHT_DICT_KEY), // height
|
|
mediaType.GetDouble(IEFRAMERATE_DICT_KEY), // default frame rate
|
|
mediaType.GetDouble(IEFRAMERATEMIN_DICT_KEY), // minimum frame rate
|
|
mediaType.GetDouble(IEFRAMERATEMAX_DICT_KEY), // maximum frame rate
|
|
mediaType.GetString(IESUBTYPE_DICT_KEY) // subtype = color space
|
|
]));
|
|
end;
|
|
end;
|
|
|
|
<FM>See Also<FN>
|
|
- <A TIEMediaFoundationSourceReader.StreamCount>
|
|
- <A TIEMediaFoundationSourceReader.GetMediaTypesCount>
|
|
!!}
|
|
function TIEMediaFoundationSourceReader.GetMediaType(streamIndex: integer; mediaTypeIndex: integer): TIEDictionary;
|
|
begin
|
|
result := (m_streams[streamIndex] as TObjectList)[mediaTypeIndex] as TIEDictionary;
|
|
end;
|
|
|
|
|
|
// get mediatype of "first" stream of specified type
|
|
function TIEMediaFoundationSourceReader.GetMediaType(streamType: WideString; mediaTypeIndex: integer): TIEDictionary;
|
|
var
|
|
streamIndex: integer;
|
|
begin
|
|
result := nil;
|
|
streamIndex := IndexOfFirstStream(streamType);
|
|
if streamIndex > -1 then
|
|
result := GetMediaType(streamIndex, mediaTypeIndex);
|
|
end;
|
|
|
|
|
|
{!!
|
|
<FS>TIEMediaFoundationSourceReader.SetSelectedStreams
|
|
|
|
<FM>Declaration<FC>
|
|
procedure SetSelectedStreams(streamIndex: integer; selected: boolean);
|
|
procedure SetSelectedStreams(streamType: WideString; selected: boolean);
|
|
|
|
<FM>Description<FN>
|
|
Specifies which streams are enabled. An enabled stream sends samples to the receiver (i.e. to the <A TImageEnView.OnMediaFoundationNotify> event).
|
|
|
|
<TABLE>
|
|
<R> <H>Parameter</H> <H>Description</H> </R>
|
|
<R> <C><FC>streamIndex<FN></C> <C>Index of the stream, in the range of 0 to <A TIEMediaFoundationSourceReader.StreamCount> - 1</C> </R>
|
|
<R> <C><FC>streamType<FN></C> <C>A string representing the stream type. Only the first stream of this type will be considered. Can be any one of the values accepted by <A TIEMediaFoundationSourceReader.GetStreamType></C> </R>
|
|
<R> <C><FC>selected<FN></C> <C>Must be True in order to select the stream</C> </R>
|
|
</TABLE>
|
|
|
|
<FM>Example<FC>
|
|
// Enable both audio and video streams (first streams of these types)
|
|
ImageEnView1.IO.MediaFoundationSourceReader.SetSelectedStreams(mmf_AUDIO_STREAM, true);
|
|
ImageEnView1.IO.MediaFoundationSourceReader.SetSelectedStreams(mmf_VIDEO_STREAM, true);
|
|
|
|
<FM>See Also<FN>
|
|
- <A TIEMediaFoundationSourceReader.GetStreamType>
|
|
- <A TIEMediaFoundationSourceReader.StreamCount>
|
|
!!}
|
|
procedure TIEMediaFoundationSourceReader.SetSelectedStreams(streamIndex: integer; selected: boolean);
|
|
begin
|
|
m_sourceReader.SetStreamSelection(streamIndex, selected);
|
|
end;
|
|
|
|
|
|
procedure TIEMediaFoundationSourceReader.SetSelectedStreams(streamType: WideString; selected: boolean);
|
|
var
|
|
streamIndex: integer;
|
|
begin
|
|
streamIndex := IndexOfFirstStream(streamType);
|
|
if streamIndex > -1 then
|
|
SetSelectedStreams(streamIndex, selected);
|
|
end;
|
|
|
|
|
|
{!!
|
|
<FS>TIEMediaFoundationSourceReader.SelectMediaType
|
|
|
|
<FM>Declaration<FC>
|
|
function SelectMediaType(streamIndex: integer; mediaTypeIndex: integer): boolean;
|
|
function SelectMediaType(streamType: WideString; mediaTypeIndex: integer): boolean;
|
|
|
|
<FM>Description<FN>
|
|
Select one of the native media types of the specified stream.
|
|
If the media type is not natively supported by ImageEn a compatible one is automatically selected (e.g. 'MJPG->YUY2').
|
|
Returns False if the media type is not accepted (or a suitable conversion is not available).
|
|
|
|
<TABLE>
|
|
<R> <H>Parameter</H> <H>Description</H> </R>
|
|
<R> <C><FC>streamIndex<FN></C> <C>Index of the stream, in the range of 0 to <A TIEMediaFoundationSourceReader.StreamCount> - 1</C> </R>
|
|
<R> <C><FC>streamType<FN></C> <C>A string representing the stream type. Only the first stream of this type will be considered. Can be any one of the values accepted by <A TIEMediaFoundationSourceReader.GetStreamType></C> </R>
|
|
<R> <C><FC>mediaTypeIndex<FN></C> <C>Index of native media type to select</C> </R>
|
|
</TABLE>
|
|
|
|
<FM>Example<FC>
|
|
ImageEnView1.IO.MediaFoundationSourceReader.SelectMediaType(mmf_VIDEO_STREAM, ListBox1.ItemIndex);
|
|
|
|
<FM>See Also<FN>
|
|
- <A TIEMediaFoundationSourceReader.GetMediaType>
|
|
- <A TIEMediaFoundationSourceReader.GetMediaTypesCount>
|
|
- <A TIEMediaFoundationSourceReader.SetMediaTypeAudio>
|
|
- <A TIEMediaFoundationSourceReader.SetMediaTypeCustom>
|
|
- <A TIEMediaFoundationSourceReader.SetMediaTypeVideo>
|
|
- <A TIEMediaFoundationSourceReader.GetCurrentMediaType>
|
|
!!}
|
|
function TIEMediaFoundationSourceReader.SelectMediaType(streamIndex: integer; mediaTypeIndex: integer): boolean;
|
|
var
|
|
mediaType: IE_IMFMediaType;
|
|
mediaTypeDict: TIEDictionary;
|
|
subTypeStr: WideString;
|
|
i: integer;
|
|
begin
|
|
result := false;
|
|
|
|
if streamIndex < 0 then
|
|
exit;
|
|
|
|
Lock();
|
|
mediaTypeDict := nil;
|
|
try
|
|
mediaType := nil;
|
|
m_sourceReader.GetNativeMediaType(streamIndex, mediaTypeIndex, mediaType);
|
|
mediaTypeDict := IECreateDictionaryFromMediaType(mediaType);
|
|
if mediaTypeDict.GetString(IEMAJORTYPE_DICT_KEY) = mmf_VIDEO_STREAM then
|
|
begin
|
|
// check direct match with supported subtypes
|
|
for i := 0 to IEMediaFoundationGetVideoSampleDecoders().Count - 1 do
|
|
begin
|
|
if (IEMediaFoundationGetVideoSampleDecoders()[i] as TIEMediaFoundationVideoSampleDecoder).GetSubType() = mediaTypeDict.GetString(IESUBTYPE_DICT_KEY) then
|
|
begin
|
|
// can use directly this media type
|
|
result := SUCCEEDED(m_sourceReader.SetCurrentMediaType(streamIndex, nil, mediaType));
|
|
break;
|
|
end;
|
|
end;
|
|
if not result then
|
|
begin
|
|
// try conversion to supported subtypes
|
|
for i := 0 to IEMediaFoundationGetVideoSampleDecoders().Count - 1 do
|
|
begin
|
|
subTypeStr := (IEMediaFoundationGetVideoSampleDecoders()[i] as TIEMediaFoundationVideoSampleDecoder).GetSubType();
|
|
mediaType.SetGUID(MF_MT_SUBTYPE, IEConvertStringToSubType(subTypeStr));
|
|
result := SUCCEEDED(m_sourceReader.SetCurrentMediaType(streamIndex, nil, mediaType));
|
|
if result then
|
|
break; // subtype conversion accepted!
|
|
end;
|
|
end;
|
|
end
|
|
else
|
|
result := SUCCEEDED(m_sourceReader.SetCurrentMediaType(streamIndex, nil, mediaType));
|
|
PopulateSelectedMediaType();
|
|
finally
|
|
mediaTypeDict.Free();
|
|
Unlock();
|
|
end;
|
|
end;
|
|
|
|
|
|
function TIEMediaFoundationSourceReader.SelectMediaType(streamType: WideString; mediaTypeIndex: integer): boolean;
|
|
var
|
|
streamIndex: integer;
|
|
begin
|
|
result := false;
|
|
streamIndex := IndexOfFirstStream(streamType);
|
|
if streamIndex > -1 then
|
|
result := SelectMediaType(streamIndex, mediaTypeIndex);
|
|
end;
|
|
|
|
|
|
{!!
|
|
<FS>TIEMediaFoundationSourceReader.SetMediaTypeCustom
|
|
|
|
<FM>Declaration<FC>
|
|
function SetMediaTypeCustom(streamIndex: integer; jsonDescription: WideString): boolean;
|
|
function SetMediaTypeCustom(streamType: WideString; jsonDescription: WideString): boolean;
|
|
|
|
<FM>Description<FN>
|
|
Creates and selects a new audio/video media type. Media Foundation will provide a decoder to convert from native media type.
|
|
Returns False if the media type is not accepted (or a suitable conversion is not available).
|
|
|
|
<TABLE>
|
|
<R> <H>Parameter</H> <H>Description</H> </R>
|
|
<R> <C><FC>streamIndex<FN></C> <C>Index of the stream, in the range of 0 to <A TIEMediaFoundationSourceReader.StreamCount> - 1</C> </R>
|
|
<R> <C><FC>streamType<FN></C> <C>A string representing the stream type. Only the first stream of this type will be considered. Can be any one of the values accepted by <A TIEMediaFoundationSourceReader.GetStreamType></C> </R>
|
|
<R> <C><FC>jsonDescription<FN></C> <C>JSON description of the media type</C> </R>
|
|
</TABLE>
|
|
|
|
<FM>See Also<FN>
|
|
- <A TIEMediaFoundationSourceReader.GetMediaType>
|
|
- <A TIEMediaFoundationSourceReader.GetMediaTypesCount>
|
|
- <A TIEMediaFoundationSourceReader.SetMediaTypeVideo>
|
|
- <A TIEMediaFoundationSourceReader.SetMediaTypeAudio>
|
|
- <A TIEMediaFoundationSourceReader.SelectMediaType>
|
|
- <A TIEMediaFoundationSourceReader.GetCurrentMediaType>
|
|
!!}
|
|
function TIEMediaFoundationSourceReader.SetMediaTypeCustom(streamIndex: integer; jsonDescription: WideString): boolean;
|
|
var
|
|
newMediaTypeDict: TIEDictionary;
|
|
begin
|
|
newMediaTypeDict := TIEDictionary.Create();
|
|
Lock();
|
|
try
|
|
newMediaTypeDict.Parse(jsonDescription);
|
|
|
|
// copy majortype from first native mediatype (maybe overwrite what specified in jsonDescription!)
|
|
newMediaTypeDict.Insert(IEMAJORTYPE_DICT_KEY, GetMediaType(streamIndex, 0).GetString(IEMAJORTYPE_DICT_KEY));
|
|
|
|
// creates actual media type from dictionary and set it as current mediatype for specified stream
|
|
result := SUCCEEDED( m_sourceReader.SetCurrentMediaType(streamIndex, nil, IECreateMediaTypeFromDictionary(newMediaTypeDict)) );
|
|
|
|
PopulateSelectedMediaType();
|
|
|
|
finally
|
|
Unlock();
|
|
newMediaTypeDict.Free();
|
|
end;
|
|
end;
|
|
|
|
|
|
// set mediatype of "first" stream of specified type
|
|
function TIEMediaFoundationSourceReader.SetMediaTypeCustom(streamType: WideString; jsonDescription: WideString): boolean;
|
|
var
|
|
streamIndex: integer;
|
|
begin
|
|
result := false;
|
|
streamIndex := IndexOfFirstStream(streamType);
|
|
if streamIndex > -1 then
|
|
result := SetMediaTypeCustom(streamIndex, jsonDescription);
|
|
end;
|
|
|
|
|
|
{!!
|
|
<FS>TIEMediaFoundationSourceReader.SetMediaTypeVideo
|
|
|
|
<FM>Declaration<FC>
|
|
function SetMediaTypeVideo(streamIndex: integer; subTypeStr: WideString; frameWidth: integer; frameHeight: integer; frameRate: double; videoLighting: WideString): boolean;
|
|
function SetMediaTypeVideo(subTypeStr: WideString; frameWidth: integer; frameHeight: integer; frameRate: double; videoLighting: WideString): boolean;
|
|
|
|
<FM>Description<FN>
|
|
Creates and selects a new video media type. Media Foundation will provide a decoder to convert from native media type.
|
|
Returns False if the media type is not accepted (or a suitable conversion is not available).
|
|
|
|
<TABLE>
|
|
<R> <H>Parameter</H> <H>Description</H> </R>
|
|
<R> <C><FC>streamIndex<FN></C> <C>Index of the stream, in the range of 0 to <A TIEMediaFoundationSourceReader.StreamCount> - 1</C> </R>
|
|
<R> <C><FC>streamType<FN></C> <C>A string representing the stream type. Only the first stream of this type will be considered. Can be any one of the values accepted by <A TIEMediaFoundationSourceReader.GetStreamType></C> </R>
|
|
<R> <C><FC>subTypeStr<FN></C> <C>Specifies the video subtype</C> </R>
|
|
<R> <C><FC>frameWidth<FN></C> <C>Width of a video frame, in pixels</C> </R>
|
|
<R> <C><FC>frameHeight<FN></C> <C>Height of a video frame, in pixels</C> </R>
|
|
<R> <C><FC>frameRate<FN></C> <C>Frame rate of a video media type, in frames per second</C> </R>
|
|
<R> <C><FC>videoLighting<FN></C> <C>Specifies the optimal lighting conditions for a video media type. Allowed values are: 'Bright', 'Office', 'Dim' and 'Dark'</C> </R>
|
|
</TABLE>
|
|
|
|
The Video media sub types (IESUBTYPE_DICT_KEY) are: 'RGB8', 'RGB555', 'RGB565', 'RGB24', 'RGB32', 'ARGB32', 'AI44', 'AYUV', 'YUY2', 'YVYU', 'YVU9', 'UYVY', 'NV11', 'NV12', 'YV12', 'I420', 'IYUV', 'Y210', 'Y216',
|
|
'Y410', 'Y416', 'Y41P', 'Y41T', 'Y42T', 'P210', 'P216', 'P010', 'P016', 'v210', 'v216', 'v410', 'MP43', 'MP4S', 'M4S2', 'MP4V', 'WMV1', 'WMV2', 'WMV3', 'WVC1', 'MSS1', 'MSS2',
|
|
'MPG1', 'dvsl', 'dvsd', 'dvhd', 'dv25', 'dv50', 'dvh1', 'dvc ', 'H264', 'MJPG'.
|
|
|
|
<FM>Example<FC>
|
|
ImageEnView1.IO.MediaFoundationSourceReader.SetMediaTypeVideo('RGB32', 640, 480, 30);
|
|
|
|
<FM>See Also<FN>
|
|
- <A TIEMediaFoundationSourceReader.GetMediaType>
|
|
- <A TIEMediaFoundationSourceReader.GetMediaTypesCount>
|
|
- <A TIEMediaFoundationSourceReader.SetMediaTypeCustom>
|
|
- <A TIEMediaFoundationSourceReader.SetMediaTypeAudio>
|
|
- <A TIEMediaFoundationSourceReader.SelectMediaType>
|
|
- <A TIEMediaFoundationSourceReader.GetCurrentMediaType>
|
|
!!}
|
|
function TIEMediaFoundationSourceReader.SetMediaTypeVideo(streamIndex: integer; subTypeStr: WideString; frameWidth: integer; frameHeight: integer; frameRate: double; videoLighting: WideString): boolean;
|
|
var
|
|
newMediaTypeDict: TIEDictionary;
|
|
begin
|
|
newMediaTypeDict := TIEDictionary.Create();
|
|
try
|
|
newMediaTypeDict.Insert(IEMAJORTYPE_DICT_KEY, mmf_VIDEO_STREAM);
|
|
|
|
// set subtype
|
|
newMediaTypeDict.Insert(IESUBTYPE_DICT_KEY, subTypeStr);
|
|
|
|
// set frameWidth and frameHeight
|
|
if frameWidth <> 0 then
|
|
newMediaTypeDict.Insert(IEFRAMEWIDTH_DICT_KEY, frameWidth);
|
|
if frameHeight <> 0 then
|
|
newMediaTypeDict.Insert(IEFRAMEHEIGHT_DICT_KEY, frameHeight);
|
|
|
|
// set framerate
|
|
if frameRate > 0.0 then
|
|
newMediaTypeDict.Insert(IEFRAMERATE_DICT_KEY, frameRate);
|
|
|
|
// set video lighting
|
|
if videoLighting <> '' then
|
|
newMediaTypeDict.Insert(IEVIDEOLIGHTING_DICT_KEY, videoLighting);
|
|
|
|
result := SetMediaTypeCustom(streamIndex, newMediaTypeDict.Dump(ieplJSON));
|
|
|
|
finally
|
|
newMediaTypeDict.Free();
|
|
end;
|
|
end;
|
|
|
|
|
|
// set mediatype of "first" video stream
|
|
function TIEMediaFoundationSourceReader.SetMediaTypeVideo(subTypeStr: WideString; frameWidth: integer; frameHeight: integer; frameRate: double; videoLighting: WideString): boolean;
|
|
var
|
|
streamIndex: integer;
|
|
begin
|
|
result := false;
|
|
streamIndex := IndexOfFirstStream(mmf_VIDEO_STREAM);
|
|
if streamIndex > -1 then
|
|
result := SetMediaTypeVideo(streamIndex, subTypeStr, frameWidth, frameHeight, frameRate, videoLighting);
|
|
end;
|
|
|
|
|
|
{!!
|
|
<FS>TIEMediaFoundationSourceReader.SetMediaTypeAudio
|
|
|
|
<FM>Declaration<FC>
|
|
function SetMediaTypeAudio(streamIndex: integer; subTypeStr: WideString): boolean;
|
|
function SetMediaTypeAudio(subTypeStr: WideString): boolean;
|
|
|
|
<FM>Description<FN>
|
|
Creates and selects a new audio media type. Media Foundation will provide a decoder to convert from native media type.
|
|
Returns False if the media type is not accepted (or a suitable conversion is not available).
|
|
|
|
<TABLE>
|
|
<R> <H>Parameter</H> <H>Description</H> </R>
|
|
<R> <C><FC>streamIndex<FN></C> <C>Index of the stream, in the range of 0 to <A TIEMediaFoundationSourceReader.StreamCount> - 1</C> </R>
|
|
<R> <C><FC>streamType<FN></C> <C>A string representing the stream type. Only the first stream of this type will be considered. Can be any one of the values accepted by <A TIEMediaFoundationSourceReader.GetStreamType></C> </R>
|
|
<R> <C><FC>subTypeStr<FN></C> <C>Specifies the audio subtype</C> </R>
|
|
</TABLE>
|
|
|
|
Audio subtypes are: 'PCM', 'Float', 'DTS', 'Dolby_AC3_SPDIF', 'DRM', 'WMAudioV8', 'WMAudioV9', 'WMAudio_Lossless', 'WMASPDIF', 'MSP1', 'MP3', 'MPEG', 'AAC', 'ADTS'
|
|
|
|
<FM>Example<FC>
|
|
audioStreamIndex := ImageEnView1.IO.MediaFoundationSourceReader.IndexOfFirstStream(mmf_AUDIO_STREAM);
|
|
ImageEnView1.IO.MediaFoundationSourceReader.SetSelectedStreams(audioStreamIndex, true);
|
|
ImageEnView1.IO.MediaFoundationSourceReader.SetMediaTypeAudio(audioStreamIndex, 'PCM');
|
|
ImageEnView1.IO.MediaFoundationSourceReader.PushNotifyReceiver( TIEMediaFoundationAudioRenderer.Create(audioStreamIndex) );
|
|
|
|
<FM>See Also<FN>
|
|
- <A TIEMediaFoundationSourceReader.GetMediaType>
|
|
- <A TIEMediaFoundationSourceReader.GetMediaTypesCount>
|
|
- <A TIEMediaFoundationSourceReader.SetMediaTypeCustom>
|
|
- <A TIEMediaFoundationSourceReader.SetMediaTypeVideo>
|
|
- <A TIEMediaFoundationSourceReader.SelectMediaType>
|
|
- <A TIEMediaFoundationSourceReader.GetCurrentMediaType>
|
|
!!}
|
|
function TIEMediaFoundationSourceReader.SetMediaTypeAudio(streamIndex: integer; subTypeStr: WideString): boolean;
|
|
var
|
|
newMediaTypeDict: TIEDictionary;
|
|
begin
|
|
newMediaTypeDict := TIEDictionary.Create();
|
|
try
|
|
newMediaTypeDict.Insert(IEMAJORTYPE_DICT_KEY, mmf_AUDIO_STREAM);
|
|
|
|
// set subtype
|
|
newMediaTypeDict.Insert(IESUBTYPE_DICT_KEY, subTypeStr);
|
|
|
|
result := SetMediaTypeCustom(streamIndex, newMediaTypeDict.Dump(ieplJSON));
|
|
|
|
finally
|
|
newMediaTypeDict.Free();
|
|
end;
|
|
end;
|
|
|
|
|
|
function TIEMediaFoundationSourceReader.SetMediaTypeAudio(subTypeStr: WideString): boolean;
|
|
var
|
|
streamIndex: integer;
|
|
begin
|
|
result := false;
|
|
streamIndex := IndexOfFirstStream(mmf_AUDIO_STREAM);
|
|
if streamIndex > -1 then
|
|
result := SetMediaTypeVideo(streamIndex, subTypeStr);
|
|
end;
|
|
|
|
|
|
procedure TIEMediaFoundationSourceReader.DrainSamples();
|
|
var
|
|
actualStreamIndex: DWORD;
|
|
streamFlags: DWORD;
|
|
timeStamp: int64;
|
|
sample: IE_IMFSample;
|
|
begin
|
|
Lock();
|
|
try
|
|
repeat
|
|
sample := nil;
|
|
m_sourceReader.ReadSample(MF_SOURCE_READER_ANY_STREAM, MF_SOURCE_READER_CONTROLF_DRAIN, actualStreamIndex, streamFlags, timeStamp, sample);
|
|
until sample = nil;
|
|
finally
|
|
Unlock();
|
|
end;
|
|
end;
|
|
|
|
|
|
// discard a sample for sync mode or request a sample for async mode
|
|
function TIEMediaFoundationSourceReader.ReadSample(streamIndex: DWORD): boolean;
|
|
var
|
|
actualStreamIndex: ^DWORD;
|
|
streamFlags: ^DWORD;
|
|
timeStamp: ^int64;
|
|
sample: ^IE_IMFSample;
|
|
flags: DWORD;
|
|
begin
|
|
actualStreamIndex := nil;
|
|
streamFlags := nil;
|
|
timeStamp := nil;
|
|
sample := nil;
|
|
flags := 0;
|
|
|
|
Lock();
|
|
try
|
|
result := SUCCEEDED(m_sourceReader.ReadSample(streamIndex, flags, actualStreamIndex^, streamFlags^, timeStamp^, sample^));
|
|
if result and IsAsyncMode() then
|
|
inc(m_frameRequested);
|
|
finally
|
|
Unlock();
|
|
end;
|
|
end;
|
|
|
|
|
|
// streamType: 'Audio' or 'Video' or 'Any' or index ex: '0', '1'
|
|
function TIEMediaFoundationSourceReader.ReadSample(streamType: WideString): TIEMFReceivedSample;
|
|
var
|
|
streamIndex: DWORD;
|
|
streamFlags: DWORD;
|
|
actualStreamIndex: DWORD;
|
|
timeStamp: int64;
|
|
sample: IE_IMFSample;
|
|
flags: DWORD;
|
|
hr: HRESULT;
|
|
mediaType: IE_IMFMediaType;
|
|
begin
|
|
if streamType = mmf_AUDIO_STREAM then
|
|
streamIndex := MF_SOURCE_READER_FIRST_AUDIO_STREAM
|
|
else
|
|
if streamType = mmf_VIDEO_STREAM then
|
|
streamIndex := MF_SOURCE_READER_FIRST_VIDEO_STREAM
|
|
else
|
|
if streamType = mmf_ANY_STREAM then
|
|
streamIndex := MF_SOURCE_READER_ANY_STREAM
|
|
else
|
|
streamIndex := IEStrToIntDef(AnsiString(streamType), 0);
|
|
flags := 0;
|
|
sample := nil;
|
|
hr := m_sourceReader.ReadSample(streamindex, flags, actualStreamIndex, streamFlags, timeStamp, sample);
|
|
if SUCCEEDED(hr) and ((streamFlags and MF_SOURCE_READERF_ERROR) = 0) then
|
|
begin
|
|
mediaType := nil;
|
|
m_sourceReader.GetCurrentMediaType(actualStreamIndex, mediaType);
|
|
DoVideoProcessing(mediaType, sample);
|
|
result := TIEMFReceivedSample.Create(sample, actualStreamIndex, streamFlags, timeStamp, mediaType);
|
|
end
|
|
else
|
|
result := TIEMFReceivedSample.Create(nil, streamIndex, 0, 0, nil); // return empty sample container
|
|
end;
|
|
|
|
|
|
{!!
|
|
<FS>TIEMediaFoundationSourceReader.Flush
|
|
|
|
<FM>Declaration<FC>
|
|
procedure Flush();
|
|
|
|
<FM>Description<FN>
|
|
Discards all received samples. After this the next call to <A TIEMediaFoundationSourceReader.GetNextSample> will fail.
|
|
!!}
|
|
procedure TIEMediaFoundationSourceReader.Flush();
|
|
begin
|
|
ClearReceivedSamples();
|
|
end;
|
|
|
|
|
|
{!!
|
|
<FS>TIEMediaFoundationSourceReader.SetPosition
|
|
|
|
<FM>Declaration<FC>
|
|
procedure SetPosition(position: int64);
|
|
|
|
<FM>Description<FN>
|
|
Seeks a new position in the media source.
|
|
|
|
<TABLE>
|
|
<R> <H>Parameter</H> <H>Description</H> </R>
|
|
<R> <C><FC>position<FN></C><C>The Media Foundation position in 100 nanosecond units</C> </R>
|
|
</TABLE>
|
|
|
|
<FM>Example 1<FC>
|
|
var
|
|
duration: int64;
|
|
begin
|
|
duration := ImageEnView1.IO.MediaFoundationSourceReader.Duration;
|
|
ImageEnView1.IO.MediaFoundationSourceReader.SetPosition( trunc(duration / ScrollBarPosition.Max * ScrollBarPosition.Position) );
|
|
end;
|
|
|
|
<FM>Example 2<FC>
|
|
// Move one minute into the sample
|
|
ImageEnView1.IO.MediaFoundationSourceReader.SetPosition( IESecToMediaFoundationTime(60) );
|
|
|
|
<FM>See Also<FN>
|
|
- <A TIEMediaFoundationSourceReader.Duration>
|
|
- <A IESecToMediaFoundationTime>
|
|
!!}
|
|
procedure TIEMediaFoundationSourceReader.SetPosition(position: int64);
|
|
var
|
|
lcap: boolean;
|
|
varPosition: PROPVARIANT;
|
|
begin
|
|
// SetCapture works only if no frame has been requested, so we must wait
|
|
lcap := PauseCapture();
|
|
Flush();
|
|
varPosition.vt := VT_I8;
|
|
varPosition.uhVal.QuadPart := position;
|
|
m_sourceReader.SetCurrentPosition(GUID_NULL, varPosition);
|
|
if lcap then
|
|
ResumeCapture();
|
|
end;
|
|
|
|
|
|
{!!
|
|
<FS>TIEMediaFoundationSourceReader.PushNotifyReceiver
|
|
|
|
<FM>Declaration<FC>
|
|
procedure PushNotifyReceiver(notifyReceiver: <A IIEMediaFoundationReaderNotifyReceiver>);
|
|
|
|
<FM>Description<FN>
|
|
Adds a notify receiver. A notify receiver receives notifications like "start capturing", "new frame", "end of stream".
|
|
|
|
Applications can use this method to add an audio renderer before capture begins.
|
|
|
|
Note: <A TImageEnView> is setup as receiver of TIEMediaFoundationSourceReader in order to deliver <A TImageEnView.OnMediaFoundationNotify> events.
|
|
|
|
<FM>Example<FC>
|
|
// Add the audio renderer
|
|
audioStreamindex := ImageEnView1.IO.MediaFoundationSourceReader.IndexOfFirstStream(mmf_AUDIO_STREAM);
|
|
ImageEnView1.IO.MediaFoundationSourceReader.PushNotifyReceiver( TIEMediaFoundationAudioRenderer.Create(audioStreamIndex) );
|
|
ImageEnView1.IO.MediaFoundationSourceReader.StartCapture();
|
|
|
|
// Remove the audio renderer
|
|
ImageEnView1.IO.MediaFoundationSourceReader.StopCapture();
|
|
ImageEnView1.IO.MediaFoundationSourceReader.PopNotifyReceiver();
|
|
|
|
<FM>See Also<FN>
|
|
- <A TIEMediaFoundationSourceReader.PopNotifyReceiver>
|
|
- <A TIEMediaFoundationSourceReader.PushNotifyReceiver>
|
|
- <A TIEMediaFoundationAudioRenderer>
|
|
!!}
|
|
procedure TIEMediaFoundationSourceReader.PushNotifyReceiver(notifyReceiver: IIEMediaFoundationReaderNotifyReceiver);
|
|
begin
|
|
Lock();
|
|
try
|
|
if m_notifyReceivers.IndexOf(notifyReceiver) = -1 then
|
|
m_notifyReceivers.Add(notifyReceiver);
|
|
finally
|
|
Unlock();
|
|
end;
|
|
end;
|
|
|
|
|
|
{!!
|
|
<FS>TIEMediaFoundationSourceReader.PopNotifyReceiver
|
|
|
|
<FM>Declaration<FC>
|
|
procedure PopNotifyReceiver();
|
|
|
|
<FM>Description<FN>
|
|
Removes the last added notify receiver.
|
|
|
|
Applications can use this method to remove the audio renderer after capture ends.
|
|
|
|
<FM>Example<FC>
|
|
// Add the audio renderer
|
|
audioStreamindex := ImageEnView1.IO.MediaFoundationSourceReader.IndexOfFirstStream(mmf_AUDIO_STREAM);
|
|
ImageEnView1.IO.MediaFoundationSourceReader.PushNotifyReceiver( TIEMediaFoundationAudioRenderer.Create(audioStreamIndex) );
|
|
ImageEnView1.IO.MediaFoundationSourceReader.StartCapture();
|
|
|
|
// Remove the audio renderer
|
|
ImageEnView1.IO.MediaFoundationSourceReader.StopCapture();
|
|
ImageEnView1.IO.MediaFoundationSourceReader.PopNotifyReceiver();
|
|
|
|
<FM>See Also<FN>
|
|
- <A TIEMediaFoundationSourceReader.ClearNotifyReceivers>
|
|
- <A TIEMediaFoundationSourceReader.PushNotifyReceiver>
|
|
- <A TIEMediaFoundationAudioRenderer>
|
|
!!}
|
|
procedure TIEMediaFoundationSourceReader.PopNotifyReceiver();
|
|
begin
|
|
Lock();
|
|
try
|
|
if m_notifyReceivers.Count > 0 then
|
|
m_notifyReceivers.Delete(m_notifyReceivers.Count - 1);
|
|
finally
|
|
Unlock();
|
|
end;
|
|
end;
|
|
|
|
|
|
{!!
|
|
<FS>TIEMediaFoundationSourceReader.ClearNotifyReceivers
|
|
|
|
<FM>Declaration<FC>
|
|
procedure ClearNotifyReceivers();
|
|
|
|
<FM>Description<FN>
|
|
Removes all notify receivers.
|
|
|
|
<FM>See Also<FN>
|
|
- <A TIEMediaFoundationSourceReader.PopNotifyReceiver>
|
|
- <A TIEMediaFoundationSourceReader.PushNotifyReceiver>
|
|
!!}
|
|
procedure TIEMediaFoundationSourceReader.ClearNotifyReceivers();
|
|
begin
|
|
Lock();
|
|
try
|
|
m_notifyReceivers.Clear();
|
|
finally
|
|
Unlock();
|
|
end;
|
|
end;
|
|
|
|
|
|
{!!
|
|
<FS>TIEMediaFoundationSourceReader.UpdateVideoInputs
|
|
|
|
<FM>Declaration<FC>
|
|
procedure UpdateVideoInputs();
|
|
|
|
<FM>Description<FN>
|
|
Reloads the video input list.
|
|
|
|
This method is automatically called the first time the <A TIEMediaFoundationSourceReader.VideoInputs> property is read. Applications should call UpdateVideoInputs() whenever a new device is added or removed.
|
|
|
|
<FM>See Also<FN>
|
|
- <A TIEMediaFoundationSourceReader.VideoInputs>
|
|
!!}
|
|
procedure TIEMediaFoundationSourceReader.UpdateVideoInputs();
|
|
begin
|
|
m_videoInputs.Populate();
|
|
end;
|
|
|
|
|
|
procedure TIEMediaFoundationSourceReader.CheckVideoInputsPopulated();
|
|
begin
|
|
if not m_videoInputs.Populated then
|
|
UpdateVideoInputs();
|
|
end;
|
|
|
|
|
|
procedure TIEMediaFoundationSourceReader.CheckVideoInputIndex(index: integer);
|
|
begin
|
|
CheckVideoInputsPopulated();
|
|
if (Index < 0) or (Index >= m_videoInputs.GetCount()) then
|
|
raise EIEException.Create('Invalid video input index');
|
|
end;
|
|
|
|
|
|
{!!
|
|
<FS>TIEMediaFoundationSourceReader.VideoInputs
|
|
|
|
<FM>Declaration<FC>
|
|
property VideoInputs: TStringList;
|
|
|
|
<FM>Description<FN>
|
|
Contains a list of video input device names.
|
|
|
|
Applications can refresh this list by calling <A TIEMediaFoundationSourceReader.UpdateVideoInputs>.
|
|
|
|
<FM>Example<FC>
|
|
// Fill ComboBoxVideoInputs with the list of video inputs
|
|
ComboBoxVideoInputs.Items.Assign(ImageEnView1.IO.MediaFoundationSourceReader.VideoInputs);
|
|
|
|
<FM>See Also<FN>
|
|
- <A TIEMediaFoundationSourceReader.UpdateVideoInputs>
|
|
!!}
|
|
function TIEMediaFoundationSourceReader.GetVideoInputs(): TStringList;
|
|
begin
|
|
CheckVideoInputsPopulated();
|
|
result := m_videoInputs.GetNames();
|
|
end;
|
|
|
|
|
|
function TIEMediaFoundationSourceReader.IsAsyncMode(): boolean;
|
|
begin
|
|
result := m_notifyReceivers.Count > 0;
|
|
end;
|
|
|
|
|
|
{!!
|
|
<FS>TIEMediaFoundationSourceReader.StartCapture
|
|
|
|
<FM>Declaration<FC>
|
|
function StartCapture(): boolean;
|
|
|
|
<FM>Description<FN>
|
|
Starts capturing of the sample. Applications can stop capturing by calling <A TIEMediaFoundationSourceReader.StopCapture>.
|
|
Returns True on success.
|
|
|
|
<FM>See Also<FN>
|
|
- <A TIEMediaFoundationSourceReader.Capturing>
|
|
- <A TIEMediaFoundationSourceReader.PauseCapture>
|
|
- <A TIEMediaFoundationSourceReader.ResumeCapture>
|
|
- <A TIEMediaFoundationSourceReader.StartCapture>
|
|
- <A TIEMediaFoundationSourceReader.StopCapture>
|
|
!!}
|
|
function TIEMediaFoundationSourceReader.StartCapture(): boolean;
|
|
begin
|
|
SetupVideoProcessing();
|
|
m_firstTimeStamp := -1;
|
|
SetPosition(0);
|
|
m_capturing := true;
|
|
result := ReadSample(MF_SOURCE_READER_ANY_STREAM);
|
|
end;
|
|
|
|
|
|
{!!
|
|
<FS>TIEMediaFoundationSourceReader.StopCapture
|
|
|
|
<FM>Declaration<FC>
|
|
procedure StopCapture();
|
|
|
|
<FM>Description<FN>
|
|
Terminates capturing of the sample. Applications can start capturing by calling <A TIEMediaFoundationSourceReader.StartCapture>.
|
|
|
|
<FM>See Also<FN>
|
|
- <A TIEMediaFoundationSourceReader.Capturing>
|
|
- <A TIEMediaFoundationSourceReader.PauseCapture>
|
|
- <A TIEMediaFoundationSourceReader.ResumeCapture>
|
|
- <A TIEMediaFoundationSourceReader.StartCapture>
|
|
- <A TIEMediaFoundationSourceReader.StopCapture>
|
|
!!}
|
|
procedure TIEMediaFoundationSourceReader.StopCapture();
|
|
begin
|
|
PauseCapture();
|
|
Flush();
|
|
FinalizeVideoProcessing();
|
|
|
|
Lock();
|
|
try
|
|
if assigned(m_selectedActivate) then
|
|
SetInput(m_selectedActivate);
|
|
finally
|
|
Unlock();
|
|
end;
|
|
end;
|
|
|
|
|
|
{!!
|
|
<FS>TIEMediaFoundationSourceReader.ResumeCapture
|
|
|
|
<FM>Declaration<FC>
|
|
procedure ResumeCapture();
|
|
|
|
<FM>Description<FN>
|
|
Resumes capturing of the sample. Call <A TIEMediaFoundationSourceReader.PauseCapture> to pause capturing.
|
|
|
|
<FM>See Also<FN>
|
|
- <A TIEMediaFoundationSourceReader.Capturing>
|
|
- <A TIEMediaFoundationSourceReader.PauseCapture>
|
|
- <A TIEMediaFoundationSourceReader.ResumeCapture>
|
|
- <A TIEMediaFoundationSourceReader.StartCapture>
|
|
- <A TIEMediaFoundationSourceReader.StopCapture>
|
|
!!}
|
|
procedure TIEMediaFoundationSourceReader.ResumeCapture();
|
|
begin
|
|
Lock();
|
|
try
|
|
m_firstTimeStamp := -1;
|
|
m_capturing := true;
|
|
ReadSample(MF_SOURCE_READER_ANY_STREAM);
|
|
finally
|
|
Unlock();
|
|
end;
|
|
end;
|
|
|
|
|
|
{!!
|
|
<FS>TIEMediaFoundationSourceReader.Capturing
|
|
|
|
<FM>Declaration<FC>
|
|
property Capturing: boolean;
|
|
|
|
<FM>Description<FN>
|
|
Returns True if capturing is underway.
|
|
Capturing is True after <A TIEMediaFoundationSourceReader.ResumeCapture> or <A TIEMediaFoundationSourceReader.StartCapture> is called.
|
|
Capturing is False after <A TIEMediaFoundationSourceReader.PauseCapture> or <A TIEMediaFoundationSourceReader.StopCapture> is called.
|
|
|
|
This property is read-only.
|
|
|
|
<FM>See Also<FN>
|
|
- <A TIEMediaFoundationSourceReader.PauseCapture>
|
|
- <A TIEMediaFoundationSourceReader.ResumeCapture>
|
|
- <A TIEMediaFoundationSourceReader.StartCapture>
|
|
- <A TIEMediaFoundationSourceReader.StopCapture>
|
|
!!}
|
|
function TIEMediaFoundationSourceReader.GetCapturing(): boolean;
|
|
begin
|
|
Lock();
|
|
result := m_capturing;
|
|
Unlock();
|
|
end;
|
|
|
|
|
|
{!!
|
|
<FS>TIEMediaFoundationSourceReader.PauseCapture
|
|
|
|
<FM>Declaration<FC>
|
|
function PauseCapture(): boolean;
|
|
|
|
<FM>Description<FN>
|
|
Suspends capturing of sample. Call <A TIEMediaFoundationSourceReader.ResumeCapture> to restart capturing.
|
|
Returns the capture state before pausing (True = was capturing, False = was not capturing).
|
|
|
|
<FM>See Also<FN>
|
|
- <A TIEMediaFoundationSourceReader.Capturing>
|
|
- <A TIEMediaFoundationSourceReader.PauseCapture>
|
|
- <A TIEMediaFoundationSourceReader.ResumeCapture>
|
|
- <A TIEMediaFoundationSourceReader.StartCapture>
|
|
- <A TIEMediaFoundationSourceReader.StopCapture>
|
|
!!}
|
|
// pause capture and wait for ReadSample() finishes and flush
|
|
// ret. True if was on Capture state before pause
|
|
function TIEMediaFoundationSourceReader.PauseCapture(): boolean;
|
|
const
|
|
TIMEOUT = 1000;
|
|
var
|
|
waitTime: DWORD;
|
|
begin
|
|
// pause capture
|
|
Lock();
|
|
result := m_capturing;
|
|
m_capturing := false;
|
|
Unlock();
|
|
|
|
// wait for ReadSample() completes (callback responds)
|
|
waitTime := GetTickCount();
|
|
while GetTickCount() - waitTime < TIMEOUT do
|
|
begin
|
|
Lock();
|
|
try
|
|
if m_frameRequested = 0 then
|
|
break;
|
|
finally
|
|
Unlock();
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
|
|
function TIEMediaFoundationSourceReader.AddReceivedSample(sample: TIEMFReceivedSample): TIEMFReceivedSample;
|
|
begin
|
|
Lock();
|
|
try
|
|
while m_receivedSamples.Count >= m_samplesBufferSize do
|
|
m_receivedSamples.Delete(0);
|
|
m_receivedSamples.Add(sample);
|
|
result := sample;
|
|
finally
|
|
Unlock();
|
|
end;
|
|
end;
|
|
|
|
|
|
function TIEMediaFoundationSourceReader.PopReceivedSample(streamIndex: DWORD): TIEMFReceivedSample;
|
|
var
|
|
i: integer;
|
|
begin
|
|
Lock();
|
|
try
|
|
result := nil;
|
|
if m_receivedSamples.Count > 0 then
|
|
begin
|
|
for i := 0 to m_receivedSamples.Count - 1 do
|
|
if (streamIndex = MF_SOURCE_READER_ANY_STREAM) or ((m_receivedSamples[i] as TIEMFReceivedSample).StreamIndex = streamIndex) then
|
|
begin
|
|
result := m_receivedSamples[i] as TIEMFReceivedSample;
|
|
m_receivedSamples.Extract(result); // detach from objects list
|
|
break;
|
|
end;
|
|
end;
|
|
if result = nil then
|
|
result := TIEMFReceivedSample.Create(nil, streamIndex, 0, 0, nil); // return empty sample container
|
|
finally
|
|
Unlock();
|
|
end;
|
|
end;
|
|
|
|
|
|
procedure TIEMediaFoundationSourceReader.ClearReceivedSamples();
|
|
begin
|
|
Lock();
|
|
try
|
|
m_receivedSamples.Clear();
|
|
finally
|
|
Unlock();
|
|
end;
|
|
end;
|
|
|
|
|
|
{!!
|
|
<FS>TIEMediaFoundationSourceReader.GetNextSample
|
|
|
|
<FM>Declaration<FC>
|
|
function GetNextSample(): <A TIEMFReceivedSample>;
|
|
|
|
<FM>Description<FN>
|
|
Retrieve the next sample from the samples buffer.
|
|
|
|
Note: Applications should free the received sample.
|
|
|
|
<FM>Example<FC>
|
|
// Handler for TImageEnView.OnMediaFoundatioNotify event
|
|
procedure TForm1.ImageEnVect1MediaFoundationNotify(Sender, MediaFoundationObject: TObject; NotifyType: TIEMediaFountationNotifyType);
|
|
var
|
|
sample: TIEMFReceivedSample;
|
|
begin
|
|
if NotifyType = iemfnFRAME then // is this a frame?
|
|
begin
|
|
sample := ImageEnView1.IO.MediaFoundationSourceReader.GetNextSample(); // retrieve frame sample
|
|
try
|
|
sample.DecodeSample(ImageEnView1.IEBitmap); // convert frame sample to bitmap
|
|
ImageEnView1.Update(); // update TImageEnView to show the new bitmap
|
|
finally
|
|
sample.Free(); // free the sample
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
<FM>See Also<FN>
|
|
- <A TIEMediaFoundationSourceReader.Capturing>
|
|
- <A TIEMediaFoundationSourceReader.StartCapture>
|
|
- <A TIEMediaFoundationSourceReader.StopCapture>
|
|
!!}
|
|
// read a sample from samples list (m_receivedSamples) on async mode or directly on sync mode
|
|
// applications must free returned TIEMFReceivedSample object
|
|
function TIEMediaFoundationSourceReader.GetNextSample(): TIEMFReceivedSample;
|
|
begin
|
|
if IsAsyncMode() then
|
|
// Async mode
|
|
result := PopReceivedSample(MF_SOURCE_READER_ANY_STREAM)
|
|
else
|
|
// Sync mode
|
|
result := ReadSample(mmf_ANY_STREAM);
|
|
end;
|
|
|
|
|
|
{!!
|
|
<FS>TIEMediaFoundationSourceReader.SamplesBufferSize
|
|
|
|
<FM>Declaration<FC>
|
|
property SamplesBufferSize: integer;
|
|
|
|
<FM>Description<FN>
|
|
Specifies how many samples can be stored waiting to be displayed or processed.
|
|
|
|
Default: 30
|
|
!!}
|
|
procedure TIEMediaFoundationSourceReader.SetSamplesBufferSize(value: integer);
|
|
begin
|
|
Lock();
|
|
m_samplesBufferSize := value;
|
|
UnLock();
|
|
end;
|
|
|
|
|
|
procedure TIEMediaFoundationSourceReader.SendNotify(notifyType: TIEMediaFountationNotifyType; dwStreamIndex: DWORD; dwStreamFlags: DWORD; llTimestamp: int64; pSample: IE_IMFSample; mediaType: IE_IMFMediaType; pEvent: IE_IMFMediaEvent);
|
|
var
|
|
i: integer;
|
|
notifyReceiver: IIEMediaFoundationReaderNotifyReceiver;
|
|
begin
|
|
for i := 0 to m_notifyReceivers.Count - 1 do
|
|
begin
|
|
notifyReceiver := IIEMediaFoundationReaderNotifyReceiver(m_notifyReceivers[i]);
|
|
notifyReceiver.ReceiveNotify(self, notifyType, dwStreamIndex, dwStreamFlags, llTimestamp, pSample, mediaType, pEvent);
|
|
end;
|
|
end;
|
|
|
|
|
|
function TIEMediaFoundationSourceReader.SourceReaderCallback(event: TIEMediaFoundationSourceReaderCallbackEventType; hrStatus: HRESULT; dwStreamIndex: DWORD; dwStreamFlags: DWORD; llTimestamp: int64; pSample: IE_IMFSample; pEvent: IE_IMFMediaEvent): HRESULT;
|
|
var
|
|
timeDiff: int64;
|
|
systemTime: int64;
|
|
mediaType: IE_IMFMediaType;
|
|
begin
|
|
result := S_OK;
|
|
|
|
case event of
|
|
|
|
mfrceONREADSAMPLE:
|
|
begin
|
|
|
|
if not Capturing then
|
|
exit;
|
|
|
|
mediaType := GetCurrentMediaTypeIntf(dwStreamIndex);
|
|
|
|
// wait for the sample time
|
|
systemTime := MFGetSystemTime();
|
|
if (m_firstTimeStamp = -1) then
|
|
begin
|
|
m_firstTimeStamp := systemTime - llTimestamp;
|
|
// send start capture notify
|
|
SendNotify(iemfnSTARTINGCAPTURE, dwStreamIndex, dwStreamFlags, llTimestamp, pSample, mediaType, pEvent);
|
|
end;
|
|
|
|
if m_delayFramePost and (IEGetMediaTypeMajorTypeStr(mediaType) = mmf_VIDEO_STREAM) then
|
|
begin
|
|
timeDiff := llTimestamp - (systemTime - m_firstTimeStamp);
|
|
if timeDiff > 0 then
|
|
sleep(timeDiff div 10000);
|
|
end;
|
|
|
|
Lock();
|
|
try
|
|
dec(m_frameRequested);
|
|
if Capturing then
|
|
begin
|
|
|
|
// add sample to the samples list
|
|
if assigned(pSample) then
|
|
begin
|
|
DoVideoProcessing(mediaType, pSample);
|
|
if (m_discardAudioSamples = false) or (IEGetMediaTypeMajorTypeStr(mediaType) <> mmf_AUDIO_STREAM) then
|
|
AddReceivedSample(TIEMFReceivedSample.Create(pSample, dwStreamIndex, dwStreamFlags, llTimestamp, mediaType));
|
|
// send frame notify
|
|
SendNotify(iemfnFRAME, dwStreamIndex, dwStreamFlags, llTimestamp, pSample, mediaType, pEvent);
|
|
end;
|
|
|
|
// notify end of stream
|
|
if (dwStreamFlags and MF_SOURCE_READERF_ENDOFSTREAM) <> 0 then
|
|
SendNotify(iemfnENDOFSTREAM, dwStreamIndex, dwStreamFlags, llTimestamp, pSample, mediaType, pEvent);
|
|
|
|
// request another sample
|
|
if ((dwStreamFlags and MF_SOURCE_READERF_ERROR) = 0) and ((dwStreamFlags and MF_SOURCE_READERF_ENDOFSTREAM) = 0) then
|
|
ReadSample(MF_SOURCE_READER_ANY_STREAM);
|
|
end;
|
|
|
|
finally
|
|
Unlock();
|
|
end;
|
|
|
|
end;
|
|
|
|
mfrceONFLUSH:
|
|
begin
|
|
// nothing to do
|
|
end;
|
|
|
|
mfrceONEVENT:
|
|
begin
|
|
// nothing to do
|
|
end;
|
|
|
|
end;
|
|
end;
|
|
|
|
|
|
{!!
|
|
<FS>TIEMediaFoundationSourceReader.VideoProcessor
|
|
|
|
<FM>Declaration<FC>
|
|
property VideoProcessor: <A TIEMediaFoundationVideoProcessor>;
|
|
|
|
<FM>Description<FN>
|
|
Use this property to setup the Media Foundation Video Processor. Applications can set rotations, mirrors, source and destination rectangles.
|
|
|
|
This property is read-only.
|
|
Only for Windows 8 and newer, or Windows 2012 Server.
|
|
|
|
<FM>Example<FC>
|
|
// setup horizontal flip and automatic rotation
|
|
ImageEnView1.IO.MediaFoundationSourceReader.VideoProcessor.SetMirror(mfpmHorizontal);
|
|
ImageEnView1.IO.MediaFoundationSourceReader.VideoProcessor.SetRotation(mfprNormal);
|
|
!!}
|
|
function TIEMediaFoundationSourceReader.GetVideoProcessor(): TIEMediaFoundationVideoProcessor;
|
|
begin
|
|
if not assigned(m_videoProcessor) then
|
|
m_videoProcessor := TIEMediaFoundationVideoProcessor.Create();
|
|
result := m_videoProcessor;
|
|
end;
|
|
|
|
|
|
procedure TIEMediaFoundationSourceReader.SetupVideoProcessing();
|
|
var
|
|
mt: TIEDictionary;
|
|
begin
|
|
if assigned(m_videoProcessor) and m_videoProcessor.IsAvailable then
|
|
begin
|
|
// RGB32 is supported by the video processor
|
|
mt := GetCurrentMediaType(mmf_VIDEO_STREAM);
|
|
mt.Insert(IESUBTYPE_DICT_KEY, mmf_VideoFormat_RGB32);
|
|
SetMediaTypeCustom(mmf_VIDEO_STREAM, mt.Dump(ieplJSON));
|
|
end;
|
|
end;
|
|
|
|
|
|
procedure TIEMediaFoundationSourceReader.FinalizeVideoProcessing();
|
|
begin
|
|
if assigned(m_videoProcessor) and m_videoProcessor.IsAvailable then
|
|
m_videoProcessor.Stop();
|
|
end;
|
|
|
|
|
|
procedure TIEMediaFoundationSourceReader.DoVideoProcessing(var mediaType: IE_IMFMediaType; var sample: IE_IMFSample);
|
|
var
|
|
mediaRotation: DWORD;
|
|
wantedRotation: DWORD;
|
|
begin
|
|
if assigned(m_videoProcessor) and m_videoProcessor.IsAvailable and (IEGetMediaTypeMajorTypeStr(mediaType) = mmf_VIDEO_STREAM) then
|
|
begin
|
|
if not m_videoProcessor.Started then
|
|
begin
|
|
m_videoProcessor.SetInputMediaType(mediaType);
|
|
//mediaType.SetGUID(MF_MT_SUBTYPE, IEConvertStringToSubType(mmf_VideoFormat_RGB24)); // output of video processor will be RGB24 (for faster TIEBitmap conversion) (NOT WORK ON SOME WEBCAMS!!)
|
|
m_videoProcessor.SetOutputMediaType(mediaType);
|
|
m_videoProcessor.Start();
|
|
end;
|
|
|
|
mediaRotation := 0;
|
|
mediaType.GetUINT32(MF_MT_VIDEO_ROTATION, mediaRotation);
|
|
wantedRotation := 360 - IEGetDisplayOrientation();
|
|
if wantedRotation <> mediaRotation then
|
|
begin
|
|
mediaType.SetUINT32(MF_MT_VIDEO_ROTATION, wantedRotation);
|
|
m_videoProcessor.SetInputMediaType(mediaType);
|
|
end;
|
|
mediaType := m_videoProcessor.GetOutputMediaType();
|
|
|
|
m_videoProcessor.PushSample(sample);
|
|
sample := m_videoProcessor.GetSample();
|
|
end;
|
|
end;
|
|
|
|
|
|
// TIEMediaFoundationSourceReader
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// TIEMediaFoundationAudioResampler
|
|
|
|
constructor TIEMediaFoundationAudioResampler.Create();
|
|
var
|
|
props: IE_IWMResamplerProps;
|
|
begin
|
|
inherited Create();
|
|
|
|
m_outputBufferSize := 0;
|
|
|
|
m_transform := nil;
|
|
CoCreateInstance(CLSID_CResamplerMediaObject, nil, CLSCTX_INPROC_SERVER, IE_IMFTransform_GUID, m_transform);
|
|
if not assigned(m_transform) then
|
|
exit;
|
|
|
|
// set conversion quality
|
|
props := nil;
|
|
m_transform.QueryInterface(IE_IWMResamplerProps_GUID, props);
|
|
props.SetHalfFilterLength(60);
|
|
end;
|
|
|
|
|
|
destructor TIEMediaFoundationAudioResampler.Destroy();
|
|
begin
|
|
Stop();
|
|
m_transform := nil;
|
|
inherited;
|
|
end;
|
|
|
|
|
|
function TIEMediaFoundationAudioResampler.SetInputMediaType(mediaType: IE_IMFMediaType): boolean;
|
|
begin
|
|
result := SUCCEEDED(m_transform.SetInputType(0, mediaType, 0));
|
|
end;
|
|
|
|
|
|
function TIEMediaFoundationAudioResampler.SetOutputMediaType(mediaType: IE_IMFMediaType): boolean;
|
|
var
|
|
streamInfo: IE_MFT_OUTPUT_STREAM_INFO;
|
|
samplesPerSecond: DWORD;
|
|
numChannels: DWORD;
|
|
begin
|
|
result := SUCCEEDED(m_transform.SetOutputType(0, mediaType, 0));
|
|
|
|
m_transform.GetOutputStreamInfo(0, streamInfo);
|
|
mediaType.GetUINT32(MF_MT_AUDIO_SAMPLES_PER_SECOND, samplesPerSecond);
|
|
mediaType.GetUINT32(MF_MT_AUDIO_NUM_CHANNELS, numChannels);
|
|
m_outputBufferSize := streamInfo.cbSize * samplesPerSecond;
|
|
end;
|
|
|
|
|
|
procedure TIEMediaFoundationAudioResampler.Start();
|
|
begin
|
|
m_transform.ProcessMessage(MFT_MESSAGE_COMMAND_FLUSH, 0);
|
|
m_transform.ProcessMessage(MFT_MESSAGE_NOTIFY_BEGIN_STREAMING, 0);
|
|
m_transform.ProcessMessage(MFT_MESSAGE_NOTIFY_START_OF_STREAM, 0);
|
|
end;
|
|
|
|
|
|
procedure TIEMediaFoundationAudioResampler.Stop();
|
|
begin
|
|
m_transform.ProcessMessage(MFT_MESSAGE_NOTIFY_END_OF_STREAM, 0);
|
|
m_transform.ProcessMessage(MFT_MESSAGE_COMMAND_DRAIN, 0);
|
|
m_transform.ProcessMessage(MFT_MESSAGE_NOTIFY_END_STREAMING, 0);
|
|
end;
|
|
|
|
|
|
function TIEMediaFoundationAudioResampler.PushSample(sample: IE_IMFSample): boolean;
|
|
var
|
|
hr: HRESULT;
|
|
begin
|
|
hr := m_transform.ProcessInput(0, sample, 0);
|
|
result := SUCCEEDED(hr);
|
|
end;
|
|
|
|
|
|
function TIEMediaFoundationAudioResampler.GetSample(): IE_IMFSample;
|
|
var
|
|
outputDataBuffer: IE_MFT_OUTPUT_DATA_BUFFER;
|
|
status: DWORD;
|
|
hr: HRESULT;
|
|
mediaBuffer: IE_IMFMediaBuffer;
|
|
begin
|
|
result := nil;
|
|
|
|
MFCreateSample(result);
|
|
MFCreateMemoryBuffer(m_outputBufferSize, mediaBuffer);
|
|
result.AddBuffer(mediaBuffer);
|
|
outputDataBuffer.dwStreamID := 0;
|
|
outputDataBuffer.pSample := result;
|
|
outputDataBuffer.dwStatus := 0;
|
|
outputDataBuffer.pEvents := nil;
|
|
|
|
hr := m_transform.ProcessOutput(0, 1, @outputDataBuffer, status);
|
|
if DWORD(hr) = MF_E_TRANSFORM_NEED_MORE_INPUT then
|
|
begin
|
|
result := nil;
|
|
end;
|
|
end;
|
|
|
|
|
|
// TIEMediaFoundationAudioResampler
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// TIEMediaFoundationAudioRenderer
|
|
|
|
constructor TIEMediaFoundationAudioRenderer.Create(streamIndex: DWORD; role: TIEMediaFoundationAudioRendererRole);
|
|
var
|
|
attributes: IE_IMFAttributes;
|
|
timeSource: IE_IMFPresentationTimeSource;
|
|
begin
|
|
inherited Create();
|
|
|
|
m_streamIndex := streamIndex;
|
|
m_resampler := nil;
|
|
|
|
if IEMFStartup() then
|
|
begin
|
|
attributes := nil;
|
|
MFCreateAttributes(attributes, 1);
|
|
attributes.SetUINT32(MF_AUDIO_RENDERER_ATTRIBUTE_ENDPOINT_ROLE, DWORD(0));
|
|
|
|
m_mediaSink := nil;
|
|
MFCreateAudioRenderer(attributes, m_mediaSink);
|
|
|
|
m_streamSink := nil;
|
|
m_mediaSink.GetStreamSinkByIndex(0, m_streamSink);
|
|
|
|
timeSource := nil;
|
|
m_mediaSink.QueryInterface(IE_IMFPresentationTimeSource_GUID, timeSource);
|
|
|
|
m_presentationClock := nil;
|
|
MFCreatePresentationClock(m_presentationClock);
|
|
m_presentationClock.SetTimeSource(timeSource);
|
|
|
|
m_mediaSink.SetPresentationClock(m_presentationClock);
|
|
end;
|
|
end;
|
|
|
|
|
|
destructor TIEMediaFoundationAudioRenderer.Destroy();
|
|
begin
|
|
FreeAndNil(m_resampler);
|
|
|
|
m_streamSink := nil;
|
|
m_mediaSink := nil;
|
|
m_presentationClock := nil;
|
|
|
|
IEMFShutdown();
|
|
|
|
inherited;
|
|
end;
|
|
|
|
|
|
// Audio renderer supports only PCM or Float media types
|
|
function TIEMediaFoundationAudioRenderer.SetMediaType(mediaType: IE_IMFMediaType): boolean;
|
|
var
|
|
mediaTypeHandler: IE_IMFMediaTypeHandler;
|
|
hr: HRESULT;
|
|
samplesPerSecond: DWORD;
|
|
begin
|
|
FreeAndNil(m_resampler);
|
|
|
|
mediaType.GetUINT32(MF_MT_AUDIO_SAMPLES_PER_SECOND, samplesPerSecond);
|
|
if samplesPerSecond <> 44100 then
|
|
begin
|
|
// a resampler is necessary
|
|
m_resampler := TIEMediaFoundationAudioResampler.Create();
|
|
m_resampler.SetInputMediaType(mediaType);
|
|
mediaType := IECreateMediaTypeFromDictionary('{"MajorType":"Audio", "SubType":"PCM", "AudioSamplesPerSecond":44100, "AudioBitsPerSample":16, "AudioNumChannels":2, "AudioBlockAlignment":4, "AudioAvgBytesPerSecond":176400}');
|
|
m_resampler.SetOutputMediaType(mediaType);
|
|
end;
|
|
|
|
mediaTypeHandler := nil;
|
|
m_streamSink.GetMediaTypeHandler(mediaTypeHandler);
|
|
hr := mediaTypeHandler.SetCurrentMediaType(mediaType);
|
|
result := SUCCEEDED(hr);
|
|
end;
|
|
|
|
|
|
procedure TIEMediaFoundationAudioRenderer.ReceiveNotify(sender: TObject; notifyType: TIEMediaFountationNotifyType; dwStreamIndex: DWORD; dwStreamFlags: DWORD; llTimestamp: int64; pSample: IE_IMFSample; mediaType: IE_IMFMediaType; pEvent: IE_IMFMediaEvent);
|
|
var
|
|
rSample: IE_IMFSample;
|
|
begin
|
|
if dwStreamIndex = m_streamIndex then
|
|
begin
|
|
case notifyType of
|
|
iemfnSTARTINGCAPTURE:
|
|
begin
|
|
// setup audio renderer media type
|
|
SetMediaType(mediaType);
|
|
// start clock
|
|
m_presentationClock.Start(llTimestamp);
|
|
// start resampler if exists
|
|
if assigned(m_resampler) then
|
|
m_resampler.Start();
|
|
end;
|
|
iemfnFRAME:
|
|
begin
|
|
if assigned(m_resampler) then
|
|
begin
|
|
m_resampler.PushSample(pSample);
|
|
rSample := m_resampler.GetSample();
|
|
if assigned(rSample) then
|
|
m_streamSink.ProcessSample(rSample);
|
|
end
|
|
else
|
|
m_streamSink.ProcessSample(pSample);
|
|
end;
|
|
iemfnENDOFSTREAM:
|
|
begin
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
|
|
// TIEMediaFoundationAudioRenderer
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// TIEMediaFoundationVideoProcessor
|
|
// Windows 8 and newer only!!
|
|
|
|
constructor TIEMediaFoundationVideoProcessor.Create();
|
|
begin
|
|
inherited;
|
|
|
|
if IEMFStartup() then
|
|
begin
|
|
m_started := false;
|
|
|
|
m_transform := nil;
|
|
CoCreateInstance(CLSID_VideoProcessorMFT, nil, CLSCTX_INPROC_SERVER, IE_IMFTransform_GUID, m_transform);
|
|
if not assigned(m_transform) then
|
|
exit;
|
|
m_control := nil;
|
|
m_transform.QueryInterface(IE_IMFVideoProcessorControl_GUID, m_control);
|
|
|
|
m_mediaBuffer := nil;
|
|
end;
|
|
end;
|
|
|
|
|
|
destructor TIEMediaFoundationVideoProcessor.Destroy();
|
|
begin
|
|
if IsAvailable then
|
|
Stop();
|
|
|
|
m_control := nil;
|
|
m_transform := nil;
|
|
m_mediaBuffer := nil;
|
|
|
|
IEMFShutdown();
|
|
|
|
inherited;
|
|
end;
|
|
|
|
|
|
{!!
|
|
<FS>TIEMediaFoundationVideoProcessor.IsAvailable
|
|
|
|
<FM>Declaration<FC>
|
|
property IsAvailable: boolean;
|
|
|
|
<FM>Description<FN>
|
|
This property is true when Media Foundation Video Processor is available. This should always be true on Windows 8 and newer, or Windows 2012 Server.
|
|
!!}
|
|
function TIEMediaFoundationVideoProcessor.GetIsAvailable(): boolean;
|
|
begin
|
|
result := m_control <> nil;
|
|
end;
|
|
|
|
|
|
{!!
|
|
<FS>TIEMediaFoundationVideoProcessor.SetSourceRectangle
|
|
|
|
<FM>Declaration<FC>
|
|
procedure SetSourceRectangle(rect: TRect);
|
|
|
|
<FM>Description<FN>
|
|
Sets the source rectangle. The source rectangle is the portion of the input frame that is blitted to the destination surface.
|
|
!!}
|
|
procedure TIEMediaFoundationVideoProcessor.SetSourceRectangle(rect: TRect);
|
|
var
|
|
r: IE_MFRECT;
|
|
begin
|
|
if IsAvailable then
|
|
begin
|
|
r.left := rect.Left;
|
|
r.top := rect.Top;
|
|
r.right := rect.Right;
|
|
r.bottom := rect.Bottom;
|
|
m_control.SetSourceRectangle(r);
|
|
end;
|
|
end;
|
|
|
|
|
|
{!!
|
|
<FS>TIEMediaFoundationVideoProcessor.SetDestinationRectangle
|
|
|
|
<FM>Declaration<FC>
|
|
procedure SetDestinationRectangle(rect: TRect);
|
|
|
|
<FM>Description<FN>
|
|
Sets the destination rectangle. The destination rectangle is the portion of the output surface where the source rectangle is blitted.
|
|
!!}
|
|
procedure TIEMediaFoundationVideoProcessor.SetDestinationRectangle(rect: TRect);
|
|
var
|
|
r: IE_MFRECT;
|
|
begin
|
|
if IsAvailable then
|
|
begin
|
|
r.left := rect.Left;
|
|
r.top := rect.Top;
|
|
r.right := rect.Right;
|
|
r.bottom := rect.Bottom;
|
|
m_control.SetDestinationRectangle(r);
|
|
end;
|
|
end;
|
|
|
|
|
|
{!!
|
|
<FS>TIEMediaFoundationVideoProcessor.SetMirror
|
|
|
|
<FM>Declaration<FC>
|
|
procedure SetMirror(mirror: <A TIEMediaFoundationVideoProcessorMirror>);
|
|
|
|
<FM>Description<FN>
|
|
Specifies whether to flip the video image.
|
|
!!}
|
|
procedure TIEMediaFoundationVideoProcessor.SetMirror(mirror: TIEMediaFoundationVideoProcessorMirror);
|
|
begin
|
|
if IsAvailable then
|
|
m_control.SetMirror(DWORD(mirror));
|
|
end;
|
|
|
|
|
|
{!!
|
|
<FS>TIEMediaFoundationVideoProcessor.SetRotation
|
|
|
|
<FM>Declaration<FC>
|
|
procedure SetRotation(rotation: <A TIEMediaFoundationVideoProcessorRotation>);
|
|
|
|
<FM>Description<FN>
|
|
Specifies whether to rotate the video to the correct orientation.
|
|
!!}
|
|
procedure TIEMediaFoundationVideoProcessor.SetRotation(rotation: TIEMediaFoundationVideoProcessorRotation);
|
|
begin
|
|
if IsAvailable then
|
|
m_control.SetRotation(DWORD(rotation));
|
|
end;
|
|
|
|
|
|
function TIEMediaFoundationVideoProcessor.SetInputMediaType(mediaType: IE_IMFMediaType): boolean;
|
|
begin
|
|
result := SUCCEEDED(m_transform.SetInputType(0, mediaType, 0));
|
|
end;
|
|
|
|
|
|
function TIEMediaFoundationVideoProcessor.GetOutputMediaType(): IE_IMFMediaType;
|
|
begin
|
|
result := nil;
|
|
m_transform.GetOutputCurrentType(0, result);
|
|
end;
|
|
|
|
|
|
function TIEMediaFoundationVideoProcessor.SetOutputMediaType(mediaType: IE_IMFMediaType): boolean;
|
|
var
|
|
streamInfo: IE_MFT_OUTPUT_STREAM_INFO;
|
|
begin
|
|
result := SUCCEEDED(m_transform.SetOutputType(0, mediaType, 0));
|
|
|
|
m_transform.GetOutputStreamInfo(0, streamInfo);
|
|
m_outputBufferSize := streamInfo.cbSize;
|
|
end;
|
|
|
|
|
|
procedure TIEMediaFoundationVideoProcessor.Start();
|
|
begin
|
|
m_transform.ProcessMessage(MFT_MESSAGE_COMMAND_FLUSH, 0);
|
|
m_transform.ProcessMessage(MFT_MESSAGE_NOTIFY_BEGIN_STREAMING, 0);
|
|
m_transform.ProcessMessage(MFT_MESSAGE_NOTIFY_START_OF_STREAM, 0);
|
|
m_started := true;
|
|
m_mediaBuffer := nil;
|
|
end;
|
|
|
|
|
|
procedure TIEMediaFoundationVideoProcessor.Stop();
|
|
begin
|
|
m_transform.ProcessMessage(MFT_MESSAGE_NOTIFY_END_OF_STREAM, 0);
|
|
m_transform.ProcessMessage(MFT_MESSAGE_COMMAND_DRAIN, 0);
|
|
m_transform.ProcessMessage(MFT_MESSAGE_NOTIFY_END_STREAMING, 0);
|
|
m_started := false;
|
|
m_mediaBuffer := nil;
|
|
end;
|
|
|
|
|
|
function TIEMediaFoundationVideoProcessor.PushSample(sample: IE_IMFSample): boolean;
|
|
var
|
|
hr: HRESULT;
|
|
begin
|
|
hr := m_transform.ProcessInput(0, sample, 0);
|
|
result := SUCCEEDED(hr);
|
|
end;
|
|
|
|
|
|
function TIEMediaFoundationVideoProcessor.PushSample(buffer: pointer; bufferLen: integer): boolean;
|
|
var
|
|
sample: IE_IMFSample;
|
|
maxLen, curLen: DWORD;
|
|
destBuffer: pbyte;
|
|
begin
|
|
MFCreateSample(sample);
|
|
if m_mediaBuffer = nil then
|
|
MFCreateMemoryBuffer(bufferLen, m_mediaBuffer);
|
|
m_mediaBuffer.SetCurrentLength(bufferLen);
|
|
m_mediaBuffer.Lock(destBuffer, maxLen, curLen);
|
|
CopyMemory(destBuffer, buffer, bufferLen);
|
|
m_mediaBuffer.Unlock();
|
|
sample.AddBuffer(m_mediaBuffer);
|
|
result := PushSample(sample);
|
|
end;
|
|
|
|
|
|
function TIEMediaFoundationVideoProcessor.GetSample(): IE_IMFSample;
|
|
var
|
|
outputDataBuffer: IE_MFT_OUTPUT_DATA_BUFFER;
|
|
status: DWORD;
|
|
hr: HRESULT;
|
|
begin
|
|
result := nil;
|
|
|
|
MFCreateSample(result);
|
|
if m_mediaBuffer = nil then
|
|
MFCreateMemoryBuffer(m_outputBufferSize, m_mediaBuffer);
|
|
result.AddBuffer(m_mediaBuffer);
|
|
outputDataBuffer.dwStreamID := 0;
|
|
outputDataBuffer.pSample := result;
|
|
outputDataBuffer.dwStatus := 0;
|
|
outputDataBuffer.pEvents := nil;
|
|
|
|
hr := m_transform.ProcessOutput(0, 1, @outputDataBuffer, status);
|
|
if DWORD(hr) = MF_E_TRANSFORM_NEED_MORE_INPUT then
|
|
begin
|
|
result := nil;
|
|
m_mediaBuffer := nil;
|
|
end;
|
|
m_transform.ProcessMessage(MFT_MESSAGE_COMMAND_FLUSH, 0);
|
|
end;
|
|
|
|
|
|
procedure TIEMediaFoundationVideoProcessor.GetSample(destBuffer: pointer);
|
|
var
|
|
sample: IE_IMFSample;
|
|
mediaBuffer: IE_IMFMediaBuffer;
|
|
srcBuffer: pbyte;
|
|
maxLen, curLen: DWORD;
|
|
begin
|
|
sample := GetSample();
|
|
if assigned(sample) then
|
|
begin
|
|
sample.ConvertToContiguousBuffer(mediaBuffer);
|
|
mediaBuffer.Lock(srcBuffer, maxLen, curLen);
|
|
CopyMemory(destBuffer, srcBuffer, maxLen);
|
|
mediaBuffer.Unlock();
|
|
end;
|
|
end;
|
|
|
|
|
|
// TIEMediaFoundationVideoProcessor
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// Initialization / finalization
|
|
|
|
|
|
procedure IEMediaFoundationSetupDefaultVideoSampleDecoders();
|
|
begin
|
|
IEMediaFoundationGetVideoSampleDecoders().Add(TIEMediaFoundationVideoSampleDecoder_RGB24.Create());
|
|
IEMediaFoundationGetVideoSampleDecoders().Add(TIEMediaFoundationVideoSampleDecoder_YUY2.Create());
|
|
IEMediaFoundationGetVideoSampleDecoders().Add(TIEMediaFoundationVideoSampleDecoder_I420.Create());
|
|
IEMediaFoundationGetVideoSampleDecoders().Add(TIEMediaFoundationVideoSampleDecoder_NV12.Create());
|
|
IEMediaFoundationGetVideoSampleDecoders().Add(TIEMediaFoundationVideoSampleDecoder_RGB32.Create());
|
|
end;
|
|
|
|
|
|
initialization
|
|
// nothing to do
|
|
|
|
|
|
finalization
|
|
IEMFUnloadLibrary();
|
|
|
|
|
|
// Initialization / finalization
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
{$else} // not IEINCLUDEMEDIAFOUNDATION
|
|
|
|
interface
|
|
implementation
|
|
|
|
{$endif}
|
|
|
|
end.
|
|
|