Renate Schaaf 81 Posted Thursday at 11:53 AM Ever since I work on my new Win 11 system, mediafoundation is acting up. (I use mfpack). Apparently microsoft is aware of some issues and has promised to fix them. But right now the worst thing is that sometimes a call (IMFSourceReader.ReadSample) just doesn't return. The setup of the reader generates no errors, and it's not possible to see what is causing the hang in the dll (mfReadWrite.dll). I've tried to intercept this by moving the call into a task and generating an exception on timeout. This is of course terrible for performance in a call which is used very often, but now at least I get an error message when it occurs. Still, the application hangs and the only way to solve this is to kill the application in taskmanager. Is there another way to recover from this, or do I just have to tell users "Sorry this file is not supported, go to taskmanager and terminate the application and never use this file again."? Share this post Link to post
Lars Fosdal 1946 Posted Thursday at 12:02 PM Is it possible to delay-load the DLL explicitly - and unload / reload it after an exception? Or walk the system app thread list and request termination of hung sub-threads in the DLL space? (Clumsy description, but I hope you get what I suggest). Share this post Link to post
Renate Schaaf 81 Posted Thursday at 12:12 PM 8 minutes ago, Lars Fosdal said: but I hope you get what I suggest Thanks, I get the general idea, now I have the research the details 🙂 Share this post Link to post
Kas Ob. 160 Posted Thursday at 01:16 PM 1 hour ago, Renate Schaaf said: Is there another way to recover from this, or do I just have to tell users "Sorry this file is not supported, go to taskmanager and terminate the application and never use this file again."? I don't think it is possible to recover from this, specially that i witnessed very similar behavior but without freezing part, it was refusing to initialize even there was nothing is loaded, the only thing that helped is restart the OS, and things returned working fine, in my case it happened after so many exceptions and debugging and stopping the debugged exe in the middle of an operation that was invoking WMF, the result in my opinion is the hardware part connecting it with the display part or the hardware decoder went rouge and left with dangling connections, so it refused in my case, in yours it might be behaved differently as it was waiting for some hardware signal that didn't come. So, first you should confirm if this is the case and it caused by many faulty runs (stopped by exception or debugger), aka not clean exit, and an OS restart helped, and on other hand if you wasn't developing and changing stuff that raises exception and stops the operation without clean exit, then it will work as it should many many times. That what comes to mind in this very case, as for recovery, then no that thread is done and gone, and i doubt creating new thread to resume the frozen one work will help, as it most likely will freeze too. also watch carefully hardware acceleration effect and involvement on this case. Share this post Link to post
Renate Schaaf 81 Posted Thursday at 01:58 PM 32 minutes ago, Kas Ob. said: I don't think it is possible to recover from this It might get fixed, because a file for which ReadSample hangs, sometimes returns an error code on ReadSample, which is MF_E_NOT_AVAILABLE = _HRESULT_TYPEDEF_($C00D36D6) This seems to happen, if mf thinks that the input is protected, when actually it isn't. And that issue has been reported. Also, since you mention hardware acceleration, software encoding now never works. It returns with a sharing violation for a device. No idea what that could be. Being at the mercy of a new operating system almost makes me want to throw away the whole project. There are decoders which are no longer implemented by default (dolby ac-x), they can be downloaded but are very hard to find... Share this post Link to post
Kas Ob. 160 Posted Thursday at 03:51 PM 1 hour ago, Renate Schaaf said: because a file for which ReadSample hangs Well, it is not that simple, as there is few layers between IMFSourceReader.ReadSample and a file on the disk, from the media source which is the main provider for the demuxer, to the codec that will decode passing a transformer for the colors and format (and may be audio too), till returning from ReadSample, so if we are talking about recover from recover hanging thread then no and that is if possible is way harder and will not work long term, if we talking about recover from this case to not happen then it is possible to find a fix, but to fix it you need to pinpoint the cause. 1 hour ago, Renate Schaaf said: Also, since you mention hardware acceleration, software encoding now never works. This is very interesting, and could be a major lead, if the software is failing then the hardware might cause the hang/freeze, so you need to return to fixing the software, find the cause. 1 hour ago, Renate Schaaf said: Being at the mercy of a new operating system almost makes me want to throw away the whole project. There are decoders which are no longer implemented by default (dolby ac-x), they can be downloaded but are very hard to find... And this remind me of something i didn't see since old ages with Windows XP and its media player, did you by any chance installed some of these codec packs, the free ones that comes with modified versions of some thing like MPC-HC or VLC or k-lite codecs, LAV,MadVR ... Because there is many codecs included in these packages with broken implementation or shortcut to bypass some patents, all what they do is trying to work, which they do most the time, but sometimes even cause system crash. So i want you to grab the Autoruns from https://learn.microsoft.com/en-us/sysinternals/downloads/autoruns and see what codec are installed on 32bit and 64bit, if you doubt then delete them !, ( i think Microsoft provided codec are your safest bet for now so leave these installed or lets say active) with Autoruns wait until finish scanning then click on the codecs tab, from there you can use the two options from Options menu "Hide Microsoft entries" and "Hide Windows entries", installing some of these mentioned above might be caused the default codec and its priority to change and might even be changing WMF own setting in Registry, Check what you have and clean them. Share this post Link to post
Remy Lebeau 1668 Posted Thursday at 04:24 PM 4 hours ago, Renate Schaaf said: I've tried to intercept this by moving the call into a task and generating an exception on timeout. This is of course terrible for performance in a call which is used very often, but now at least I get an error message when it occurs. Still, the application hangs and the only way to solve this is to kill the application in taskmanager. Have you considered moving your audio processing into a separate process of its own that your main program can communicate with. If the processing times out then your main program can kill and restart that separate process. That way, you don't have to kill your main program. Share this post Link to post
Renate Schaaf 81 Posted Friday at 08:52 AM 16 hours ago, Kas Ob. said: see what codec are installed on 32bit and 64bit, if you doubt then delete them ! I had k-lite installed, but seeing it didn't contain anything for mf, I deinstalled it right away. The autorun-tool doesn't show anything in codecs, if I filter out microsoft. The ac-4 decoder is available in an appxbundle on microsoft store. For the rest of your comments, I'll have to do some more research. Thanx! Share this post Link to post
Renate Schaaf 81 Posted Friday at 09:03 AM 16 hours ago, Remy Lebeau said: Have you considered moving your audio processing into a separate process of its own that your main program can communicate with. If the processing times out then your main program can kill and restart that separate process. That way, you don't have to kill your main program. That's a good idea. But my project is a utility class which combines pictures and video-clips into a video, so there's no application per se. I could write a helper-procedure for testing an input-file in a separate process, and if that doesn't return, give the user an option to blacklist that file. (Once I figure out how to do that.) Otherwise the logic of what I have to run in a separate process is a bit beyond me 🙂 Thanx! Share this post Link to post
Renate Schaaf 81 Posted Friday at 05:13 PM On 9/25/2025 at 5:51 PM, Kas Ob. said: but to fix it you need to pinpoint the cause. I think I found the setting with the potential for errors and hangs: It's the source-reader attribute MF_SOURCE_READER_ENABLE_ADVANCED_VIDEO_PROCESSING. It allows the source-reader to decode to a new size, change pixel-aspect and framerate. If I change it to MF_SOURCE_READER_ENABLE_VIDEO_PROCESSING, all the videos that worked under Win10 can be processed under Win11 too. And the encoder does framerate-conversion automagically! Problem is, now I have to resize the output myself, which is causing a slowdown. I solved it for the time being by having a slow but safe procedure AddVideo and one which is fast but might fail. I'll also implement the test based on Remy's idea. And then I hope that the next Win-Update will fix the problems. 1 Share this post Link to post
Kas Ob. 160 Posted yesterday at 09:20 AM 15 hours ago, Renate Schaaf said: all the videos that worked under Win10 can be processed under Win11 too. And the encoder does framerate-conversion automagically Nice find, and it will allow deeper diagnose of the problem. 15 hours ago, Renate Schaaf said: now I have to resize the output myself, which is causing a slowdown. So try different path, in other words try to pinpoint the failure cause with using MF_SOURCE_READER_ENABLE_ADVANCED_VIDEO_PROCESSING, from https://learn.microsoft.com/en-us/windows/win32/medfound/mf-source-reader-enable-advanced-video-processing Quote If this attribute is TRUE, the MF_READWRITE_DISABLE_CONVERTERS attribute must be FALSE. The Source Reader looks for video processors that are registered in the MFT_CATEGORY_VIDEO_PROCESSOR category, including MFTs that are registered for the local process. (See MFTRegisterLocal for more information about local registration of MFTs.) The Source Reader uses the Transcode Video Processor (XVP) if no other suitable video processor is found. This arbitrary "looks for video processors" is most likely the culprit, assuming the MF_READWRITE_DISABLE_CONVERTERS is disabled, so try to use see what the difference between the two OSs in selecting the transformer, so, Use MFTEnumEx https://learn.microsoft.com/en-us/windows/win32/api/mfapi/nf-mfapi-mftenumex with MFT_CATEGORY_VIDEO_PROCESSOR also compare how disabling hardware acceleration impacting this enumeration, and MFTGetInfo https://learn.microsoft.com/en-us/windows/win32/api/mfapi/nf-mfapi-mftgetinfo to get more in depth view of the failing or freezing cause, which seems wrong transformer or un-configured (more advanced that need extra settings) transformer. Also you can build your own IMFTransform which is declared in WinApi.MediaFoundationApi.MfTransform and use MFTRegisterLocal to use it with registering the COM itself (as dll), this what got to mind when i asked if there is extra codecs installed and they might be registered them selves as transformers in this case. In other words you are on the correct path now, and highly recommend to continue tweaking and fixing MF_SOURCE_READER_ENABLE_ADVANCED_VIDEO_PROCESSING instead of MF_SOURCE_READER_ENABLE_VIDEO_PROCESSING, if the problem is selecting different transformer then you need to fix that, the one that was/is working for both OSs, the one with high compatibility across WMF in Windows, see it could be as simple as HDR thingy (transformer) which got higher priority in Windows 11 ps; writing IMFTransform might be not an easy job but will greatly enhance you debugging and tweaking. ps2; searching the Internet for something helps in tracing and i found this gem, never used it, but it looks brilliant and what doctor should recommend https://learn.microsoft.com/en-us/windows/win32/medfound/mftrace https://learn.microsoft.com/en-us/windows/win32/medfound/using-mftrace 1 Share this post Link to post
Kas Ob. 160 Posted yesterday at 09:29 AM One more thing, AI should and great helper in writing a passthrrough IMFTransform. additional thing in mind, see, if there is a problem or conflict in codec and transformers for WMF, this it is easy to fix, it should be in the registry, and here is the dilemma, if you fixed it then it will work for you and might fail for many others, so trying to fix the code and making it sturdy before fixing the registry would be better, there is few ways to clean this, but i suggest to leave it to later. Share this post Link to post
Kas Ob. 160 Posted yesterday at 09:44 AM I asked my free Claude with Quote Implement in Delphi a passthrough IMFTransformer, use the mfpack and the declaration from https://github.com/FactoryXCode/MfPack/blob/Master/MfPack/src/WinApi.MediaFoundationApi.MfTransform.pas and the result was Quote I'll help you implement a passthrough IMFTransform in Delphi using the mfpack library. A passthrough transform simply copies input data to output without modification, which is useful as a template for more complex transforms. Delphi IMFTransform Passthrough Implementation Code unit PassthroughTransform; interface uses WinApi.Windows, WinApi.ComBaseApi, WinApi.MediaFoundationApi.MfApi, WinApi.MediaFoundationApi.MfObjects, WinApi.MediaFoundationApi.MfTransform, WinApi.MediaFoundationApi.MfIdl, System.Classes, I've implemented a complete passthrough IMFTransform in Delphi using the mfpack library. Here are the key features of this implementation: Key Components: Class Structure: TPassthroughTransform implements the IMFTransform interface with proper COM reference counting. Stream Configuration: Single input stream (ID 0) Single output stream (ID 0) Fixed stream topology (cannot add/remove streams) Media Type Handling: Accepts most input media types Output type must match input type exactly (passthrough behavior) Proper type validation and error handling Data Processing: ProcessInput: Stores incoming samples ProcessOutput: Copies data from input to output buffer without modification Handles buffer locking/unlocking safely Copies sample attributes and metadata State Management: Tracks whether input is available Handles flush, drain, and streaming messages Proper cleanup and resource management Usage Example: pascal var Transform: IMFTransform; begin Transform := TPassthroughTransform.Create; // Use the transform in your Media Foundation pipeline // Set input/output types, process samples, etc. end; Key Features: Thread-safe: Uses proper COM reference counting Error handling: Comprehensive error checking and appropriate HRESULT returns Memory management: Safe buffer locking/unlocking with exception handling Standards compliant: Follows Media Foundation transform patterns Extensible: Easy to modify for actual data processing instead of passthrough This implementation serves as an excellent foundation for creating custom Media Foundation transforms. You can modify the ProcessOutput method to perform actual data transformation instead of just copying the data. The code itself is unit PassthroughTransform; interface uses WinApi.Windows, WinApi.ComBaseApi, WinApi.MediaFoundationApi.MfApi, WinApi.MediaFoundationApi.MfObjects, WinApi.MediaFoundationApi.MfTransform, WinApi.MediaFoundationApi.MfIdl, System.Classes, System.SysUtils; type TPassthroughTransform = class(TInterfacedObject, IMFTransform) private FRefCount: Integer; FInputMediaType: IMFMediaType; FOutputMediaType: IMFMediaType; FInputSample: IMFSample; FAttributes: IMFAttributes; FStreamLimits: MFT_STREAM_LIMITS; FInputStreamInfo: MFT_INPUT_STREAM_INFO; FOutputStreamInfo: MFT_OUTPUT_STREAM_INFO; // Internal state FHasInput: Boolean; FDraining: Boolean; protected // Helper methods function IsValidInputStream(dwInputStreamID: DWORD): Boolean; function IsValidOutputStream(dwOutputStreamID: DWORD): Boolean; function OnCheckInputType(pmt: IMFMediaType): HResult; function OnSetInputType(pmt: IMFMediaType): HResult; function OnSetOutputType(pmt: IMFMediaType): HResult; public constructor Create; destructor Destroy; override; // IMFTransform methods 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; var pdwInputIDs: DWORD; dwOutputIDArraySize: DWORD; var pdwOutputIDs: DWORD): HResult; stdcall; function GetInputStreamInfo(dwInputStreamID: DWORD; out pStreamInfo: MFT_INPUT_STREAM_INFO): HResult; stdcall; function GetOutputStreamInfo(dwOutputStreamID: DWORD; out pStreamInfo: MFT_OUTPUT_STREAM_INFO): HResult; stdcall; function GetAttributes(out pAttributes: IMFAttributes): HResult; stdcall; function GetInputStreamAttributes(dwInputStreamID: DWORD; out pAttributes: IMFAttributes): HResult; stdcall; function GetOutputStreamAttributes(dwOutputStreamID: DWORD; out pAttributes: IMFAttributes): HResult; stdcall; function DeleteInputStream(dwStreamID: DWORD): HResult; stdcall; function AddInputStreams(cStreams: DWORD; var adwStreamIDs: DWORD): HResult; stdcall; function GetInputAvailableType(dwInputStreamID: DWORD; dwTypeIndex: DWORD; out ppType: IMFMediaType): HResult; stdcall; function GetOutputAvailableType(dwOutputStreamID: DWORD; dwTypeIndex: DWORD; out ppType: IMFMediaType): HResult; stdcall; function SetInputType(dwInputStreamID: DWORD; pType: IMFMediaType; dwFlags: DWORD): HResult; stdcall; function SetOutputType(dwOutputStreamID: DWORD; pType: IMFMediaType; dwFlags: DWORD): HResult; stdcall; function GetInputCurrentType(dwInputStreamID: DWORD; out ppType: IMFMediaType): HResult; stdcall; function GetOutputCurrentType(dwOutputStreamID: DWORD; out ppType: IMFMediaType): HResult; stdcall; function GetInputStatus(dwInputStreamID: DWORD; out pdwFlags: DWORD): HResult; stdcall; function GetOutputStatus(out pdwFlags: DWORD): HResult; stdcall; function SetOutputBounds(hnsLowerBound: LONGLONG; hnsUpperBound: LONGLONG): HResult; stdcall; function ProcessEvent(dwInputStreamID: DWORD; pEvent: IMFMediaEvent): HResult; stdcall; function ProcessMessage(eMessage: MFT_MESSAGE_TYPE; ulParam: ULONG_PTR): HResult; stdcall; function ProcessInput(dwInputStreamID: DWORD; pSample: IMFSample; dwFlags: DWORD): HResult; stdcall; function ProcessOutput(dwFlags: DWORD; cOutputBufferCount: DWORD; var pOutputSamples: MFT_OUTPUT_DATA_BUFFER; out pdwStatus: DWORD): HResult; stdcall; end; implementation { TPassthroughTransform } constructor TPassthroughTransform.Create; begin inherited Create; FRefCount := 0; FHasInput := False; FDraining := False; // Initialize stream limits - single input, single output FStreamLimits.cbSize := SizeOf(MFT_STREAM_LIMITS); FStreamLimits.dwInputMaximum := 1; FStreamLimits.dwInputMinimum := 1; FStreamLimits.dwOutputMaximum := 1; FStreamLimits.dwOutputMinimum := 1; // Initialize stream info FInputStreamInfo.cbSize := SizeOf(MFT_INPUT_STREAM_INFO); FInputStreamInfo.hnsMaxLatency := 0; FInputStreamInfo.dwFlags := 0; // No special requirements FInputStreamInfo.cbMaxLookahead := 0; FInputStreamInfo.cbAlignment := 0; FOutputStreamInfo.cbSize := SizeOf(MFT_OUTPUT_STREAM_INFO); FOutputStreamInfo.dwFlags := MFT_OUTPUT_STREAM_PROVIDES_SAMPLES or MFT_OUTPUT_STREAM_WHOLE_SAMPLES; FOutputStreamInfo.cbAlignment := 0; FOutputStreamInfo.cbSize := 0; // Create attributes store MFCreateAttributes(FAttributes, 0); end; destructor TPassthroughTransform.Destroy; begin FInputMediaType := nil; FOutputMediaType := nil; FInputSample := nil; FAttributes := nil; inherited Destroy; end; function TPassthroughTransform.IsValidInputStream(dwInputStreamID: DWORD): Boolean; begin Result := (dwInputStreamID = 0); end; function TPassthroughTransform.IsValidOutputStream(dwOutputStreamID: DWORD): Boolean; begin Result := (dwOutputStreamID = 0); end; function TPassthroughTransform.OnCheckInputType(pmt: IMFMediaType): HResult; var majorType: TGUID; begin if not Assigned(pmt) then begin Result := E_POINTER; Exit; end; // Get the major type Result := pmt.GetMajorType(majorType); if FAILED(Result) then Exit; // For a passthrough, we accept most media types // You can add specific validation here based on your needs Result := S_OK; end; function TPassthroughTransform.OnSetInputType(pmt: IMFMediaType): HResult; begin FInputMediaType := pmt; Result := S_OK; end; function TPassthroughTransform.OnSetOutputType(pmt: IMFMediaType): HResult; begin FOutputMediaType := pmt; Result := S_OK; end; function TPassthroughTransform.GetStreamLimits(out pdwInputMinimum, pdwInputMaximum, pdwOutputMinimum, pdwOutputMaximum: DWORD): HResult; begin pdwInputMinimum := FStreamLimits.dwInputMinimum; pdwInputMaximum := FStreamLimits.dwInputMaximum; pdwOutputMinimum := FStreamLimits.dwOutputMinimum; pdwOutputMaximum := FStreamLimits.dwOutputMaximum; Result := S_OK; end; function TPassthroughTransform.GetStreamCount(out pcInputStreams, pcOutputStreams: DWORD): HResult; begin pcInputStreams := 1; pcOutputStreams := 1; Result := S_OK; end; function TPassthroughTransform.GetStreamIDs(dwInputIDArraySize: DWORD; var pdwInputIDs: DWORD; dwOutputIDArraySize: DWORD; var pdwOutputIDs: DWORD): HResult; begin // Fixed stream IDs, so this is not needed Result := E_NOTIMPL; end; function TPassthroughTransform.GetInputStreamInfo(dwInputStreamID: DWORD; out pStreamInfo: MFT_INPUT_STREAM_INFO): HResult; begin if not IsValidInputStream(dwInputStreamID) then begin Result := MF_E_INVALIDSTREAMNUMBER; Exit; end; pStreamInfo := FInputStreamInfo; Result := S_OK; end; function TPassthroughTransform.GetOutputStreamInfo(dwOutputStreamID: DWORD; out pStreamInfo: MFT_OUTPUT_STREAM_INFO): HResult; begin if not IsValidOutputStream(dwOutputStreamID) then begin Result := MF_E_INVALIDSTREAMNUMBER; Exit; end; pStreamInfo := FOutputStreamInfo; Result := S_OK; end; function TPassthroughTransform.GetAttributes(out pAttributes: IMFAttributes): HResult; begin pAttributes := FAttributes; if Assigned(pAttributes) then pAttributes._AddRef; Result := S_OK; end; function TPassthroughTransform.GetInputStreamAttributes(dwInputStreamID: DWORD; out pAttributes: IMFAttributes): HResult; begin // No per-stream attributes pAttributes := nil; Result := E_NOTIMPL; end; function TPassthroughTransform.GetOutputStreamAttributes(dwOutputStreamID: DWORD; out pAttributes: IMFAttributes): HResult; begin // No per-stream attributes pAttributes := nil; Result := E_NOTIMPL; end; function TPassthroughTransform.DeleteInputStream(dwStreamID: DWORD): HResult; begin // Cannot delete streams - we have fixed streams Result := E_NOTIMPL; end; function TPassthroughTransform.AddInputStreams(cStreams: DWORD; var adwStreamIDs: DWORD): HResult; begin // Cannot add streams - we have fixed streams Result := E_NOTIMPL; end; function TPassthroughTransform.GetInputAvailableType(dwInputStreamID, dwTypeIndex: DWORD; out ppType: IMFMediaType): HResult; begin // Passthrough accepts any type, so we don't enumerate types ppType := nil; Result := MF_E_NO_MORE_TYPES; end; function TPassthroughTransform.GetOutputAvailableType(dwOutputStreamID, dwTypeIndex: DWORD; out ppType: IMFMediaType): HResult; begin if not IsValidOutputStream(dwOutputStreamID) then begin Result := MF_E_INVALIDSTREAMNUMBER; Exit; end; if not Assigned(FInputMediaType) then begin Result := MF_E_TRANSFORM_TYPE_NOT_SET; Exit; end; if dwTypeIndex > 0 then begin Result := MF_E_NO_MORE_TYPES; Exit; end; // Output type is the same as input type for passthrough Result := MFCreateMediaType(ppType); if SUCCEEDED(Result) then Result := FInputMediaType.CopyAllItems(ppType); end; function TPassthroughTransform.SetInputType(dwInputStreamID: DWORD; pType: IMFMediaType; dwFlags: DWORD): HResult; begin if not IsValidInputStream(dwInputStreamID) then begin Result := MF_E_INVALIDSTREAMNUMBER; Exit; end; if (dwFlags and MFT_SET_TYPE_TEST_ONLY) <> 0 then begin // Just test if we can accept this type Result := OnCheckInputType(pType); Exit; end; // Actually set the type Result := OnCheckInputType(pType); if SUCCEEDED(Result) then Result := OnSetInputType(pType); end; function TPassthroughTransform.SetOutputType(dwOutputStreamID: DWORD; pType: IMFMediaType; dwFlags: DWORD): HResult; begin if not IsValidOutputStream(dwOutputStreamID) then begin Result := MF_E_INVALIDSTREAMNUMBER; Exit; end; if not Assigned(FInputMediaType) then begin Result := MF_E_TRANSFORM_TYPE_NOT_SET; Exit; end; // For passthrough, output type must match input type if not Assigned(pType) then begin FOutputMediaType := nil; Result := S_OK; Exit; end; // Compare types - they should be identical for passthrough Result := pType.IsEqual(FInputMediaType, pdwFlags); if (Result <> S_OK) then begin Result := MF_E_INVALIDMEDIATYPE; Exit; end; if (dwFlags and MFT_SET_TYPE_TEST_ONLY) = 0 then Result := OnSetOutputType(pType) else Result := S_OK; end; function TPassthroughTransform.GetInputCurrentType(dwInputStreamID: DWORD; out ppType: IMFMediaType): HResult; begin if not IsValidInputStream(dwInputStreamID) then begin Result := MF_E_INVALIDSTREAMNUMBER; Exit; end; if not Assigned(FInputMediaType) then begin ppType := nil; Result := MF_E_TRANSFORM_TYPE_NOT_SET; Exit; end; ppType := FInputMediaType; ppType._AddRef; Result := S_OK; end; function TPassthroughTransform.GetOutputCurrentType(dwOutputStreamID: DWORD; out ppType: IMFMediaType): HResult; begin if not IsValidOutputStream(dwOutputStreamID) then begin Result := MF_E_INVALIDSTREAMNUMBER; Exit; end; if not Assigned(FOutputMediaType) then begin ppType := nil; Result := MF_E_TRANSFORM_TYPE_NOT_SET; Exit; end; ppType := FOutputMediaType; ppType._AddRef; Result := S_OK; end; function TPassthroughTransform.GetInputStatus(dwInputStreamID: DWORD; out pdwFlags: DWORD): HResult; begin if not IsValidInputStream(dwInputStreamID) then begin Result := MF_E_INVALIDSTREAMNUMBER; Exit; end; if FHasInput then pdwFlags := 0 // Cannot accept input else pdwFlags := MFT_INPUT_STATUS_ACCEPT_DATA; Result := S_OK; end; function TPassthroughTransform.GetOutputStatus(out pdwFlags: DWORD): HResult; begin if FHasInput then pdwFlags := MFT_OUTPUT_STATUS_SAMPLE_READY else pdwFlags := 0; Result := S_OK; end; function TPassthroughTransform.SetOutputBounds(hnsLowerBound, hnsUpperBound: LONGLONG): HResult; begin // Not implemented for passthrough Result := E_NOTIMPL; end; function TPassthroughTransform.ProcessEvent(dwInputStreamID: DWORD; pEvent: IMFMediaEvent): HResult; begin // Events are not processed in basic passthrough Result := E_NOTIMPL; end; function TPassthroughTransform.ProcessMessage(eMessage: MFT_MESSAGE_TYPE; ulParam: ULONG_PTR): HResult; begin case eMessage of MFT_MESSAGE_COMMAND_FLUSH: begin FInputSample := nil; FHasInput := False; FDraining := False; Result := S_OK; end; MFT_MESSAGE_COMMAND_DRAIN: begin FDraining := True; Result := S_OK; end; MFT_MESSAGE_NOTIFY_BEGIN_STREAMING: Result := S_OK; MFT_MESSAGE_NOTIFY_END_STREAMING: begin FInputSample := nil; FHasInput := False; FDraining := False; Result := S_OK; end; MFT_MESSAGE_SET_D3D_MANAGER: Result := S_OK; // Ignore for passthrough else Result := E_NOTIMPL; end; end; function TPassthroughTransform.ProcessInput(dwInputStreamID: DWORD; pSample: IMFSample; dwFlags: DWORD): HResult; begin if not IsValidInputStream(dwInputStreamID) then begin Result := MF_E_INVALIDSTREAMNUMBER; Exit; end; if not Assigned(pSample) then begin Result := E_POINTER; Exit; end; if not Assigned(FInputMediaType) then begin Result := MF_E_NOTACCEPTING; Exit; end; if FHasInput then begin Result := MF_E_NOTACCEPTING; Exit; end; // Store the input sample FInputSample := pSample; FHasInput := True; Result := S_OK; end; function TPassthroughTransform.ProcessOutput(dwFlags: DWORD; cOutputBufferCount: DWORD; var pOutputSamples: MFT_OUTPUT_DATA_BUFFER; out pdwStatus: DWORD): HResult; var pBuffer: IMFMediaBuffer; pInputBuffer: IMFMediaBuffer; pData, pInputData: PByte; cbData, cbInputData: DWORD; cbMaxLength, cbInputMaxLength: DWORD; begin pdwStatus := 0; if cOutputBufferCount < 1 then begin Result := E_INVALIDARG; Exit; end; if not FHasInput then begin Result := MF_E_TRANSFORM_NEED_MORE_INPUT; Exit; end; if not Assigned(pOutputSamples.pSample) then begin Result := E_INVALIDARG; Exit; end; try // Get the output buffer Result := pOutputSamples.pSample.GetBufferByIndex(0, pBuffer); if FAILED(Result) then Exit; // Get the input buffer Result := FInputSample.GetBufferByIndex(0, pInputBuffer); if FAILED(Result) then Exit; // Lock both buffers Result := pInputBuffer.Lock(pInputData, cbInputMaxLength, cbInputData); if FAILED(Result) then Exit; try Result := pBuffer.Lock(pData, cbMaxLength, cbData); if FAILED(Result) then Exit; try // Ensure output buffer is large enough if cbMaxLength < cbInputData then begin Result := MF_E_BUFFERTOOSMALL; Exit; end; // Copy data (passthrough) if cbInputData > 0 then Move(pInputData^, pData^, cbInputData); // Set the data length Result := pBuffer.SetCurrentLength(cbInputData); if FAILED(Result) then Exit; finally pBuffer.Unlock; end; finally pInputBuffer.Unlock; end; // Copy sample attributes Result := FInputSample.CopyAllItems(pOutputSamples.pSample); if FAILED(Result) then Exit; // Clear input FInputSample := nil; FHasInput := False; pOutputSamples.dwStatus := 0; Result := S_OK; except Result := E_UNEXPECTED; end; end; end. And that is way time saving from going after researching each and every method, this is really nice, anyway, i am sure there is bugs and as always many tweaking is needed but the skeleton is right, also you can ask an AI to go and show how to register as Local instead of global and how to use it. And good luck ! 1 Share this post Link to post
Renate Schaaf 81 Posted yesterday at 02:17 PM 4 hours ago, Kas Ob. said: And good luck ! Well, I'm overwhelmed. Got something to study over the weekend. Thanks a lot, I'll be back with questions for sure, maybe in private mail, I'm not sure the drift this thread has taken is of common interest 🙂 1 Share this post Link to post