How to Extract a Still Image from an MP4 at a Specific Time with Media Foundation - A Single .cpp File You Can Paste In
Bottom line
To grab one still image from an MP4 at a specific time, use IMFSourceReader. It is not a simple “seek once, read once, done” - watch out for these pitfalls:
SetCurrentPositiondoes not guarantee an exact seek (it usually lands on a key frame before the target)- Even when
ReadSamplesucceeds,pSamplecan beNULL - Setting the output to
MFVideoFormat_RGB32makes saving easier - The fourth byte of
RGB32is not necessarily alpha, so force it to0xFFbefore saving the PNG - Account for stride and image orientation when repacking into top-down BGRA
The key: seek -> compare timestamps before and after -> copy with stride in mind -> save as PNG. Implement it in that order and it stays stable.
Processing flow
| Step | API | What it does |
|---|---|---|
| Open the MP4 | MFCreateSourceReaderFromURL |
Create a media source from the file |
| Pick video only | SetStreamSelection |
Skip the audio stream |
| Convert to RGB32 | SetCurrentMediaType + video processing |
Switch to a save-friendly format |
| Move to the target time | SetCurrentPosition |
Seek in 100ns units |
| Read a frame | ReadSample |
Get a decoded sample |
| Compare before and after | sample timestamp | Pick the frame closest to the target |
| Save as PNG | WIC | Write the image file |
Frame selection rule
Rules for picking “the frame closest to the target time”:
- After seeking, keep calling
ReadSample - Hold on to the last sample where
timestamp < target - When the first sample with
timestamp >= targetarrives, compare its distance to the target against the held sample’s distance - Take whichever is closer
Pitfalls
1. SetCurrentPosition is not an exact seek
It lands a bit before the requested position - typically on a key frame. Doing only SetCurrentPosition -> one ReadSample -> save will drift considerably for videos with long GOPs. Always compare timestamps before and after.
2. ReadSample can succeed and still hand you a NULL sample
Don’t just check HRESULT. Also inspect flags (MF_SOURCE_READERF_ENDOFSTREAM at the end of stream) and pSample.
3. Stride and orientation
The image buffer is not necessarily a flat width * bytesPerPixel. There may be padding at the end of each row. Use the actual stride returned by IMF2DBuffer::Lock2D, and remember that bottom-up images can have a negative stride.
4. The fourth byte of RGB32
RGB32 is laid out in memory as B, G, R, X (undefined). That X is not necessarily alpha. Save it to PNG as-is and you may end up with a transparent image, so set the fourth byte to 0xFF before saving.
Implementation flow
Creating the Source Reader
MF_SOURCE_READER_ENABLE_VIDEO_PROCESSING = TRUE- Set the output type to
MFVideoFormat_RGB32 - Synchronous mode is fine (you only need a single frame)
Acquiring the frame
- Seek with
SetCurrentPosition - Loop on
ReadSample, comparing timestamps before and after - Pick the sample closest to the target
Buffer reshaping
- Convert to a contiguous buffer with
ConvertToContiguousBuffer - Get the actual stride via
IMF2DBuffer::Lock2D - Copy row by row into a top-down buffer (flip vertically for bottom-up)
- Force alpha to
0xFF
Saving the PNG
- Encode as PNG with WIC (
IWICBitmapEncoder) - Use
GUID_WICPixelFormat32bppBGRAas the pixel format
Field checklist
| Check | If you miss it |
|---|---|
| Compare timestamps before and after the seek | You save a frame well before the target time |
| Look at HRESULT, flags, and pSample together | Crash on a NULL dereference |
| Use the actual stride | Image is corrupted or upside down |
| Force the fourth byte of RGB32 to 0xFF | You get a transparent PNG |
| Verify 0 <= target < duration | Exceptions near the end of the file |
| Reuse the Reader and reseek for batch extraction | Needlessly slow |
How to run it
ExtractFrameFromMp4.exe <input.mp4> <seconds> <output.png>
Example:
ExtractFrameFromMp4.exe C:\work\input.mp4 12.345 C:\work\frame.png
Wrap-up
- Seek is not exact - compare before and after to pick the closest frame
- A successful
ReadSamplecan still give you no sample - Absorb stride and orientation before saving
- Don’t assume the fourth byte of
RGB32is alpha - Drops straight into thumbnail generation, representative-frame capture for surveillance footage, and evidence trails in inspection logs
References
- Microsoft Learn: Using the Source Reader to Process Media Data
- Microsoft Learn:
IMFSourceReader::SetCurrentPosition - Microsoft Learn:
IMFSourceReader::ReadSample - Microsoft Learn:
IMFSourceReader::SetCurrentMediaType - Microsoft Learn:
IMF2DBuffer - Microsoft Learn:
IMF2DBuffer::Lock2D - Microsoft Learn: Uncompressed Video Buffers
- Microsoft Learn: Image Stride
- Microsoft Learn: MF_MT_FRAME_SIZE attribute
- Microsoft Learn: MF_MT_DEFAULT_STRIDE attribute
- Microsoft Learn: Native pixel formats overview (WIC)
- Microsoft Learn: Uncompressed RGB Video Subtypes
Related Articles
Recent articles sharing the same tags. Deepen your understanding with closely related topics.
Burning Images and Text into MP4 Frames with Media Foundation - Source Reader, Drawing, Color Conversion, Sink Writer, and a Single-File C++ Sample
Walk through how to overlay images and text on every frame of an MP4 with Media Foundation and write out a new MP4. The flow is broken in...
Converting YUV Frames to RGB in Media Foundation - Source Reader Auto Conversion vs. Manual Conversion
Two ways to turn the NV12 or YUY2 output of a Media Foundation decoder into RGB. We compare Source Reader auto conversion against manual ...
What Media Foundation Is - Why It Starts to Feel Like COM and Windows Media APIs
A practical map of Media Foundation: what Source Reader, Sink Writer, MFT, and Media Session are for, and where COM concepts like HRESULT...
Shared Memory Pitfalls and Best Practices - Sort Out Synchronization, Visibility, Lifetime, ABI, and Security First
A practical breakdown of the typical pitfalls of shared memory in production - synchronization, visibility, lifetime, ABI, permissions, a...
How to Ship C# as a Native DLL with Native AOT - Calling UnmanagedCallersOnly Exports from C/C++
A practical guide to publishing a C# class library as a native DLL with Native AOT and calling it from C/C++ via UnmanagedCallersOnly — c...
Related Topics
These topic pages place the article in a broader service and decision context.
Windows Technical Topics
Topic hub for KomuraSoft LLC's Windows development, investigation, and legacy-asset articles.
Where This Topic Connects
This article connects naturally to the following service pages.
Windows App Development
We support Windows desktop applications that involve resident processing, device integration, operational logging, and maintainable structure.