Quantcast
Channel: Media Foundation Development for Windows Desktop forum
Viewing all 1079 articles
Browse latest View live

Sample timestamps in custom live source

$
0
0

Hi,

I'm developing a custom media foundation source that captures video and/or audio from some capture device. According to the instructions provided in MSDN (https://msdn.microsoft.com/en-us/library/windows/desktop/ms700134(v=vs.85).aspx) a live source should start with a timestamp of zero - 

"The first sample should have a time stamp of zero."

However, from what I'm seeing, the media sources that are built in to media foundation (e.g. when I capture from my laptop webcam or microphone) are sending timestamps that seem more like GetTickCount64() * 10000. On some environments / devices, using this value for the initial timestamp is working well for me, but on some I'm seeing considerable differences (few minutes).

Since I would like to use my source in conjunction with standard sources (e.g. capture video using my custom source with audio from the standard microphone source) it is important for me to have aligned timestamps. 

Can you please let me know how to set the timestamps correctly so that they will match the builtin sources ?

Thank you !

Eran


Add a new source after start.

$
0
0

I used 'MFCreateAggregateSource' to play multiple videos at the same time.

After I played multiple videos, I want to add more videos to this topology.

I want to use only one sink (which is already added to topology), so it is impossible to use sequencer source. since each segment has each own sink. Is that right?

If there is a way to add new source, please let me know it.

Thank you in advance.



About Sequencer source

$
0
0

Hello, I'm wondered how sequencer source can be used in the following way.

  • Play streams from multiple sources simultaneously; for example, play the audio from one file with the video from another.

(From https://msdn.microsoft.com/en-us/library/windows/desktop/ms694213(v=vs.85).aspx)

How should I construct the topology to implement above one?

Thank you for reply in advance.


Sink Writer Audio Streams Limit

$
0
0

Hi,

I have a question regarding the streams limits of the Sink Writer.
I'm trying to add multiple audio streams to the Sink Writer and it fails after the first one.
I'm using MFCreateSinkWriterFromURL and passing a mp4 file path.
I'm guessing that function creates a mp4 Media sink and I've tried creating a MP4 Media Sink using MFCreateMPEG4MediaSink() but the number of streams are fixed.
The doc says The MP4 media sink supports a maximum of one video stream and one audio stream.

Is there a way to easily achieve this?
How come this does not support multiple audio streams?

Thank you,

Francis


Is the AAC Decoder working in Windows 7?

$
0
0

Hi,

can you tell me if it is possible to use the AAC decoder at Windows 7 successfully? At the moment I can configurate the AAC decoder and I can send IMFSamples to the decoder by ProcessInput. But the ProcessOutput method always returns the error code "MF_E_TRANSFORM_NEED_MORE_INPUT".

I`m using the SourceReader API with the native AAC format to read the AAC frames from a video mp4 file. The file contains raw AAC data with the profile format LC. In a while loop I add all IMFSamples from the video file (AAC) to the AAC decoder by ProcessInput and after that I try to get an IMFSample back (ProcessOutput).  In Win8 as well as Win10 the same code (with the same video file) is working as expected.

Are there any known issues in Windows 7, which are not published by the AAC decoder website (https://msdn.microsoft.com/en-us/library/windows/desktop/dd742784(v=vs.85).aspx)?

best regards

saoirse

How to play video files (avi, wmv, mp4, mpg, etc) with both mciSendCommand and mciSendString functions only

$
0
0
How do I play video files (avi, wmv, mp4, mpg, etc) with both mciSendCommand and mciSendString functionsonly?

SetCurrentMediaType() not triggering MF_SOURCE_READERF_CURRENTMEDIATYPECHANGED

$
0
0
Hi,

Currently using MFC for my application, I would like to change the current MediaType used by my webcam at runtime (dynamically).

These are the steps of my algorithm:

1.) Create a IMFMediaSource and configure it

2.) Create an IMFSourceReader using the IMFMediaSource above

3.) Use SetCurrentMediaType() to select the media format

4.) Use readSample() method to retrieve samples.

Now, I would like to change my video format after few calls of readSample() (when the user select another video format in my GUI for instance).

I call again the SetCurrentMediaType() on the desired video format. On the next call of readSample, I'm expecting to retrieve MF_SOURCE_READERF_CURRENTMEDIATYPECHANGED on the flags, but it never happen.

Finally, I'm able to get a IMFSample, but it is totally broken (image is totally distorted).

The workaround I've found in some code here (http://svn.openrtm.org/ImageProcessing/trunk/ImageProcessing/opencv/components/MFCamera/src/MFCapture.cpp) is to destroy the IMFSourceReader and to recreate another one.

I'm wondering if this is the normal functioning of this API or if I'm missing something.

Thanks in advance, best regards.

Approved file types in Windows Mobile 6.1 and Windows Mobile 6.5?

$
0
0
Make a list of approved file types in Windows Mobile 6.1 and Windows Mobile 6.5.




How to use the MS MFT HEVC decoder after enable the HW acceleration

$
0
0

Hi all:

I'm trying to enable the HW acceleration of MS MFT HEVC decoder.

Windows 10, Intel(R) core(TM) i7-6700K CPU @ 4.00GHz, Intel(R) HD Graphics 530

Using ProcessInput and ProcessOutput, I can get every decoded frame if I don't enable the HW acceleration, but I can only get 14 decoded frames with the HW acceleration. 

HRESULT CreateDX11DevManager()
{
UINT32 dx11_dev_manager_reset_token;
HRESULT hr = MFCreateDXGIDeviceManager(&dx11_dev_manager_reset_token, &d3d11_device_manager_);

D3D_FEATURE_LEVEL feature_levels[] = {
D3D_FEATURE_LEVEL_11_1,
D3D_FEATURE_LEVEL_11_0,
D3D_FEATURE_LEVEL_10_1,
D3D_FEATURE_LEVEL_10_0,
D3D_FEATURE_LEVEL_9_3,
D3D_FEATURE_LEVEL_9_2,
D3D_FEATURE_LEVEL_9_1 };
UINT flags = D3D11_CREATE_DEVICE_VIDEO_SUPPORT;
D3D_FEATURE_LEVEL feature_level_out = D3D_FEATURE_LEVEL_11_0;
hr = D3D11CreateDevice(NULL,
D3D_DRIVER_TYPE_HARDWARE,
NULL,
flags,
feature_levels,
7,
D3D11_SDK_VERSION,
&d3d11_device_,
&feature_level_out,
NULL);

hr = d3d11_device_manager_->ResetDevice(d3d11_device_,
dx11_dev_manager_reset_token);

return hr;
}

HRESULT hr = CoCreateInstance(CLSID_CMSH265DecoderMFT, NULL, CLSCTX_INPROC_SERVER, IID_IMFTransform, (void**)&mft_);

hr = CreateDX11DevManager();
hr = mft_->ProcessMessage(MFT_MESSAGE_SET_D3D_MANAGER, (ULONG_PTR)d3d11_device_manager_);

... ...

MFT_OUTPUT_DATA_BUFFER output_data_buffer = { 0 };
HRESULT mftProcessOutput = mft_->ProcessOutput(0, 1, &output_data_buffer, &processOutputStatus);

if(mftProcessOutput == S_OK)

{
BYTE *pbBuffer;
DWORD cbMaxLength = 0, cbCurrentLength = 0;
IMFMediaBuffer *mediaBuffer = NULL;
//output_data_buffer.pSample->ConvertToContiguousBuffer(&mediaBuffer);
output_data_buffer.pSample->GetBufferByIndex(0, &mediaBuffer);
mediaBuffer->Lock(&pbBuffer, &cbMaxLength, &cbCurrentLength);
...
mediaBuffer->Unlock();
mediaBuffer->Release();
output_data_buffer.pSample->Release();

}

After I get 14 frames from ProcessOutput, the mftProcessOutput will always be 0xc00d6d72 (The transform cannot produce output until it gets more input samples), but I'm calling ProcessInput all the time.

Maybe I haven't release some resource for HW acceleration?

BTW, mediaBuffer->Lock is very slow, how can I get the pixel data more faster?

Thanks

wuchangqing

Audio / Video sync in media foundation

$
0
0

Hi

I'm working on a Windows Media Foundation application, and would like to add the ability to shift the timestamps of either audio or video frames, in order to achieve a perfect sync when using several different input devices.

What is the most recommended way to achieve this ?

I was thinking 3 options, none of them seem ideal:

1. Hook the MF source (by creating my own IMFMediaSource object that calls the original source object) and updates the frame timestamps - this option seems like a lot of work, and also other than the frames themselves there may also be timestamps embedded in events, that will need to be updated as well. The advantage of this approach is that the entire topology sees the updated timestamps.

2. Write some custom MFT that will change the timestamps - this sounds much simpler, however it was tried here stackoverflow.com/questions/16448354/correcting-live-imfmediasource-time-stamps and reported as not working (didn't try it myself)

3. Update the timestamps by hooking the sink - in my case the samples merge in a fragmented MP4 sink, so I could wrap the sink with my code and update it there. The downside here is that if I'll need corrected timestamps in some other sink (e.g. audio/video preview) it will become messy

Is there a better / easier solution to do this ?

Thank you !

Eran

Problems with EVR custom mixer

$
0
0

Can anybody provide accurate details on what the MS EVR Mixer is doing on MFT_MESSAGE_SET_D3D_MANAGER?

I have implemented a custom mixer and handled all APIs specified in the Custom Mixers article, but the mixer fails to build properly in DirectShow graph or MF topology.

If I create an MFVideoMixer9 instance and pass ProcessMessage(MFT_MESSAGE_SET_D3D_MANAGER, ...), SetInputType(...), SetOutputType(...) to the IMFTransform interface; and InitServicePointers(...), ReleaseServicePointers() to the IMFTopologyServiceLookupClient interface, the custom mixer works fine.

It appears that the difference happens as a result of the ProcessMessage(MFT_MESSAGE_SET_D3D_MANAGER, ...) call.


Larry

WMAV2 MFT encoder

$
0
0

Hi, I'm trying to use WMA8 encoder in MFT to encode audio data. The whole duration of audio is 10 seconds, and ProcessInput and ProcessOut both run correctly/successfully. The time stamps of encoded audio data are also correct. The problem is, the encoded audio, after written into the file (with my own muxer) seems incorrect.

There's one thing I've noticed, from the output of mftrace, the output type seems to have a strange alignment and bytes per second. Below is the encoder setup code and output of mftrace.     

CLSID* pCLSIDs = NULL;   // Pointer to an array of CLISDs.       UINT32 nCount = 0;     

MFT_REGISTER_TYPE_INFO encoderInfo;      encoderInfo.guidMajorType = MFMediaType_Audio;      encoderInfo.guidSubtype = MFAudioFormat_WMAudioV8;      HRESULT hr = fpMFTEnum(MFT_CATEGORY_AUDIO_ENCODER, 0, NULL, &encoderInfo, NULL, &pCLSIDs, &nCount);      if (nCount == 0) { LFTRACE("Can't enumerate Audio encoders, returned encoder amount = 0");      } ciEncoder.CreateObject(pCLSIDs[0], IID_IMFTransform);      if (ciEncoder.IsInvalid()) {        LFDEBUG("ciEncoder.CreateObject failed");        break; }      // encoder created now       // to set input      LComObject<IMFMediaType> ciInputType;  // Input media type of the encoder      hr = fpMFCreateMediaType((IMFMediaType**)(ciInputType.GetAssignablePtrRef()));      hr = ciInputType->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio);      hr = ciInputType->SetGUID(MF_MT_SUBTYPE, MFAudioFormat_PCM);      hr = ciInputType->SetUINT32(MF_MT_AUDIO_BITS_PER_SAMPLE, 16); // bits per sample      hr = ciInputType->SetUINT32(MF_MT_AUDIO_SAMPLES_PER_SECOND, 22050); // input sample rate      hr = ciInputType->SetUINT32(MF_MT_AUDIO_NUM_CHANNELS, 2); // channels      //alignment = uint16_t(pwfx->nChannels * uint16_t((BitsPerSample <= 8) ? 1 : ((BitsPerSample <= 16) ? 2 : 4)));      hr = ciInputType->SetUINT32(MF_MT_AUDIO_BLOCK_ALIGNMENT, 4);      hr = ciInputType->SetUINT32(MF_MT_AUDIO_AVG_BYTES_PER_SECOND, 22050 * 4); // sample rate * alignment      hr = ciEncoder->SetInputType(0, ciInputType.get(), 0);     

LComInterface<IMFMediaType> ciOutPutType;      hr = ciEncoder->GetOutputAvailableType(0, 1, (IMFMediaType**)ciOutPutType.GetAssignablePtrRef());      hr = ciEncoder->SetOutputType(0, ciOutPutType.get(), 0);   

hr = ciEncoder->ProcessMessage(MFT_MESSAGE_NOTIFY_BEGIN_STREAMING, NULL);

4276,B78 04:27:33.76791 CMFTransformDetours::SetInputType @09A36E70 Succeeded MT: MF_MT_AUDIO_AVG_BYTES_PER_SECOND=88200;MF_MT_AUDIO_BLOCK_ALIGNMENT=4;MF_MT_AUDIO_NUM_CHANNELS=2;MF_MT_MAJOR_TYPE=MEDIATYPE_Audio;MF_MT_AUDIO_SAMPLES_PER_SECOND=22050;MF_MT_AUDIO_BITS_PER_SAMPLE=16;MF_MT_SUBTYPE=MFAudioFormat_PCM
4276,B78 04:27:33.76795 CMFTransformDetours::SetOutputType @09A36E70 Succeeded MT: MF_MT_AUDIO_AVG_BYTES_PER_SECOND=2751;MF_MT_AUDIO_BLOCK_ALIGNMENT=1022;MF_MT_AUDIO_NUM_CHANNELS=2;MF_MT_MAJOR_TYPE=MEDIATYPE_Audio;MF_MT_AUDIO_SAMPLES_PER_SECOND=22050;MF_MT_AUDIO_PREFER_WAVEFORMATEX=1;MF_MT_USER_DATA=00 44 00 00 0f 00 00 00 00 00 ;MF_MT_FIXED_SIZE_SAMPLES=1;MF_MT_ALL_SAMPLES_INDEPENDENT=1;MF_MT_AUDIO_BITS_PER_SAMPLE=16;MF_MT_SUBTYPE=MFAudioFormat_WMAudioV8
4276,B78 04:27:33.76796 CMFTransformDetours::ProcessMessage @09A36E70 Message type=0x10000000 MFT_MESSAGE_NOTIFY_BEGIN_STREAMING, param=00000000

from the trace you can set audio output type has block alignment of 1022, and bytes per second = 2751. The output sample rate is 22050, does that mean each sample only has 0.1byte?

from the trace, the encoded audio samples have correct time stamp. can anyone give a hint where the problem is? (by the way, do I need to feed the encoder with fixed amount of samples every time I can ProcessIput()? )

4276,B78 04:27:33.80126 CMFTransformDetours::ProcessOutput @09A36E70 Stream ID 0, Sample @085C0568, Time 0ms, Duration 232ms, Buffers 1, Size 1022B, MFSampleExtension_CleanPoint=1
4276,B78 04:27:33.80130 CMFTransformDetours::ProcessOutput @09A36E70 Stream ID 0, Sample @085C0568, Time 232ms, Duration 232ms, Buffers 1, Size 1022B, MFSampleExtension_CleanPoint=1
4276,B78 04:27:33.80134 CMFTransformDetours::ProcessOutput @09A36E70 Stream ID 0, Sample @085C0568, Time 464ms, Duration 278ms, Buffers 1, Size 1022B, MFSampleExtension_CleanPoint=1
4276,B78 04:27:33.81006 CMFTransformDetours::ProcessOutput @09A36E70 Stream ID 0, Sample @085C0568, Time 743ms, Duration 278ms, Buffers 1, Size 1022B, MFSampleExtension_CleanPoint=1
4276,B78 04:27:33.81010 CMFTransformDetours::ProcessOutput @09A36E70 Stream ID 0, Sample @085C0568, Time 1021ms, Duration 278ms, Buffers 1, Size 1022B, MFSampleExtension_CleanPoint=1
4276,B78 04:27:33.81012 CMFTransformDetours::ProcessOutput @09A36E70 Stream ID 0, Sample @085C0568, Time 1300ms, Duration 278ms, Buffers 1, Size 1022B, MFSampleExtension_CleanPoint=1
4276,B78 04:27:33.82536 CMFTransformDetours::ProcessOutput @09A36E70 Stream ID 0, Sample @085C0568, Time 1578ms, Duration 325ms, Buffers 1, Size 1022B, MFSampleExtension_CleanPoint=1
4276,B78 04:27:33.82540 CMFTransformDetours::ProcessOutput @09A36E70 Stream ID 0, Sample @085C0568, Time 1904ms, Duration 278ms, Buffers 1, Size 1022B, MFSampleExtension_CleanPoint=1
4276,B78 04:27:33.82541 CMFTransformDetours::ProcessOutput @09A36E70 Stream ID 0, Sample @085C0568, Time 2182ms, Duration 278ms, Buffers 1, Size 1022B, MFSampleExtension_CleanPoint=1
4276,B78 04:27:33.83379 CMFTransformDetours::ProcessOutput @09A36E70 Stream ID 0, Sample @085C0568, Time 2461ms, Duration 325ms, Buffers 1, Size 1022B, MFSampleExtension_CleanPoint=1
4276,B78 04:27:33.83383 CMFTransformDetours::ProcessOutput @09A36E70 Stream ID 0, Sample @085C0568, Time 2786ms, Duration 336ms, Buffers 1, Size 1022B, MFSampleExtension_CleanPoint=1
4276,B78 04:27:33.84831 CMFTransformDetours::ProcessOutput @09A36E70 Stream ID 0, Sample @085C0568, Time 3123ms, Duration 313ms, Buffers 1, Size 1022B, MFSampleExtension_CleanPoint=1
4276,B78 04:27:33.84835 CMFTransformDetours::ProcessOutput @09A36E70 Stream ID 0, Sample @085C0568, Time 3436ms, Duration 371ms, Buffers 1, Size 1022B, MFSampleExtension_CleanPoint=1
4276,B78 04:27:33.85838 CMFTransformDetours::ProcessOutput @09A36E70 Stream ID 0, Sample @085C0568, Time 3808ms, Duration 371ms, Buffers 1, Size 1022B, MFSampleExtension_CleanPoint=1
4276,B78 04:27:33.85842 CMFTransformDetours::ProcessOutput @09A36E70 Stream ID 0, Sample @085C0568, Time 4179ms, Duration 371ms, Buffers 1, Size 1022B, MFSampleExtension_CleanPoint=1
4276,B78 04:27:33.87418 CMFTransformDetours::ProcessOutput @09A36E70 Stream ID 0, Sample @085C0568, Time 4551ms, Duration 371ms, Buffers 1, Size 1022B, MFSampleExtension_CleanPoint=1
4276,B78 04:27:33.87425 CMFTransformDetours::ProcessOutput @09A36E70 Stream ID 0, Sample @085C0568, Time 4922ms, Duration 325ms, Buffers 1, Size 1022B, MFSampleExtension_CleanPoint=1
4276,B78 04:27:33.88375 CMFTransformDetours::ProcessOutput @09A36E70 Stream ID 0, Sample @085C0568, Time 5247ms, Duration 371ms, Buffers 1, Size 1022B, MFSampleExtension_CleanPoint=1
4276,B78 04:27:33.88379 CMFTransformDetours::ProcessOutput @09A36E70 Stream ID 0, Sample @085C0568, Time 5619ms, Duration 371ms, Buffers 1, Size 1022B, MFSampleExtension_CleanPoint=1
4276,B78 04:27:33.89730 CMFTransformDetours::ProcessOutput @09A36E70 Stream ID 0, Sample @085C0568, Time 5990ms, Duration 417ms, Buffers 1, Size 1022B, MFSampleExtension_CleanPoint=1
4276,B78 04:27:33.89734 CMFTransformDetours::ProcessOutput @09A36E70 Stream ID 0, Sample @085C0568, Time 6408ms, Duration 371ms, Buffers 1, Size 1022B, MFSampleExtension_CleanPoint=1
4276,B78 04:27:33.90466 CMFTransformDetours::ProcessOutput @09A36E70 Stream ID 0, Sample @085C0568, Time 6780ms, Duration 417ms, Buffers 1, Size 1022B, MFSampleExtension_CleanPoint=1
4276,B78 04:27:33.90470 CMFTransformDetours::ProcessOutput @09A36E70 Stream ID 0, Sample @085C0568, Time 7198ms, Duration 371ms, Buffers 1, Size 1022B, MFSampleExtension_CleanPoint=1
4276,B78 04:27:33.91802 CMFTransformDetours::ProcessOutput @09A36E70 Stream ID 0, Sample @085C0568, Time 7569ms, Duration 325ms, Buffers 1, Size 1022B, MFSampleExtension_CleanPoint=1
4276,B78 04:27:33.91806 CMFTransformDetours::ProcessOutput @09A36E70 Stream ID 0, Sample @085C0568, Time 7894ms, Duration 371ms, Buffers 1, Size 1022B, MFSampleExtension_CleanPoint=1
4276,B78 04:27:33.93442 CMFTransformDetours::ProcessOutput @09A36E70 Stream ID 0, Sample @085C0568, Time 8266ms, Duration 464ms, Buffers 1, Size 1022B, MFSampleExtension_CleanPoint=1
4276,B78 04:27:33.93447 CMFTransformDetours::ProcessOutput @09A36E70 Stream ID 0, Sample @085C0568, Time 8730ms, Duration 417ms, Buffers 1, Size 1022B, MFSampleExtension_CleanPoint=1
4276,B78 04:27:33.93449 CMFTransformDetours::ProcessOutput @09A36E70 Stream ID 0, Sample @085C0568, Time 9148ms, Duration 417ms, Buffers 1, Size 1022B, MFSampleExtension_CleanPoint=1
4276,B78 04:27:33.93451 CMFTransformDetours::ProcessOutput @09A36E70 Stream ID 0, Sample @085C0568, Time 9566ms, Duration 278ms, Buffers 1, Size 1022B, MFSampleExtension_CleanPoint=1
4276,B78 04:27:33.93453 CMFTransformDetours::ProcessOutput @09A36E70 Stream ID 0, Sample @085C0568, Time 9845ms, Duration 150ms, Buffers 1, Size 1022B, MFSampleExtension_CleanPoint=1

Thanks



Windows 10 - Seeking in Session while Stopped or Paused.- MFPlayer sample does not work.

$
0
0

I have been trying for two weeks to get seeking to work properly, and have just come to the conclusion that it does not work. 

I would be happy if someone could point me to an updated player sample that actually works correctly. (Able to single step frames, and seek while paused or stopped). 

Since I noticed in the Chromium source code that they play videos by interacting with a topology directly (e.g. use a timer to create playback, not using the Session, I am thinking that might be the way to go).

So, what have I done? First: I have reviewed the following references exhaustively:

MSDN Samples:

Relevant Posts from this Forum:

Concepts in the PlayerSeeking Object:

The player seeking object is confusing to me.  It conflates 'commands' with 'state', and uses a 'request' and a 'pending' variable. 
Nearly as I can tell:

  • "Pending" means we have started an async operation and are waiting for its completion event. 
  • "request" means an operation that will be completed after the pending completes.
  • For the actual seek (m_pSession->Start(null, &varStart) where varStart contains the MFTIME index) we receive MESessionStarted, MESessionScrubSampleComplete, and the session delivers a frame (ONCE and ONLY ONCE )

What Events Do I See Now:

The first attempt to seek succeeds, and goes through the following sequence:

  1. call SetPosition(x) -> Scrub(True) which calls SetRate(0) which calls CommitRate: performs m_pRate->SetRate(false, 0.0)
  2. MESessionRateChanged event = Ok: next performs pending seek = m_pSession->Start(null, &varStart) with correct timestamp.
  3. MESessionStart event occurs
  4. MESessionScrubSampleEvent occurs
  5. Frame is delivered to session

Subsequent attempts to seek do not deliver a frame, regardless of whether I leave the session started, stop, or pause before attempting to seek to the next frame. I have tried various permutations of what to do after the first frame is delivered:

  • Scrub -> Seek(Rate = 0), Start(position) -> processFrame -> Scrub(false) -> SetRate(0) -> Stop()
  • Scrub -> Seek(Rate = 0), Start(position) -> processFrame -> Scrub(false) -> SetRate(0) -> Pause()
  • Scrub -> Seek(Rate = 0), Start(position) -> processFrame -> Scrub(false)
  • Scrub -> Seek(Rate = 0), Start(position) -> processFrame

In each of the above I have tried Scrub(false) in varioius places: 

  • In OnSessionStarted event
  • In ScrubSampleCompleteEvent
  • After Processing frame.

I have been banging my head for two weeks and it just doesn't work. 

Attempts to fix the Player Seeking Object:
I ended up modifying the player seeking object,  replacing the 'pending' state variable with a queue.

Here is my code, it uses a Qt Queue. The queue generally works as designed, although there are currently quite a few problems with it, it gets' into states where it doesn't handle the "updatePendingCommands" code properly (Mostly due to the fact that the frames are never delivered, leaving pending operations on the queue).

Major Modifications:

  • modified SetPosition to call Scrub(true) to handle 'single-click' on toolbar slider.
  • Moved code handling rate changed into OnSessionRateChanged
  • Replaced all direct settings of m_state and m_pending with Setters so that I can do debug logging.
  • If we are in a pending state, additional operations are pushed onto a queue instead of just put into a single variable.  Original code handled the scrubbing in a sliderPressed event, which apparently allowed them to get by with a variable instead of a queue: The scrub(true) pending event was able to complete before the position setting, which seems to work by accident, or because of the way the slider in the sample delivers <g class="gr_ gr_4552 gr-alert gr_spell gr_disable_anim_appear ContextualSpelling" data-gr-id="4552" id="4552">it's</g> events.
  • Modified UpdatePendingCommands to use the queue
  • Modifications to CommitRateChange, and SessionEvent. 
  • Added code in various places to detect if we have a pending call and work around it. These are pretty hacky. 

Really, the complicated parts of this object are CommitRateChange, SessionEvent, and UpdatePendingCommands interaction.

Header File: MFPlayerSeeking.h: 

//-------------------------------------------------------------------------------------------------
/// Microsoft Sample Code (MODIFIED)
///  This is Microsoft Sample code related to media foundation seeking of video playback.
///  See Windows Dev Center article "Seeking, Fast Forward, and Reverse Play in Media Foundation
///  programming guide:
///  https://msdn.microsoft.com/en-us/library/windows/desktop/ee892373?f=255&MSPPError=-2147217396
///
/// \file   Backends\MediaFoundation\MFPlayerSeeking
/// \author Microsoft
/// \date	10/21/2016
/// \brief  Microsoft Media Foundation - Video Playback Seeking, Fast Forward and Reverse Play
//-------------------------------------------------------------------------------------------------
#pragma once
#ifdef _WINDOWS

#include "ZCritSect.h"

#include <mfapi.h>
#include <mfidl.h>
// Forward declarations
//struct IMFMediaSession;
//struct IMFMediaType;
//struct IMFTopology;
//
#include <QQueue>

namespace Video
{
//-------------------------------------------------------------------------------------------------
/// \class MFPlayerSeeking
/// \brief Implements seeking and rate control functionality.
///
/// \li Call SetTopology when you get the MF_TOPOSTATUS_READY session event.
/// \li Call SessionEvent for each session event.
/// \li Call Clear before closing the Media Session.
/// \li To coordinate rate-change requests with transport state, delegate all stop, pause, and play commands to the PlayerSeeking class.
//-------------------------------------------------------------------------------------------------
class MFPlayerSeeking
{
public:

	MFPlayerSeeking();
	virtual ~MFPlayerSeeking();

	HRESULT SetTopology(IMFMediaSession *pSession, IMFTopology *pTopology);
	HRESULT Clear();
	HRESULT SessionEvent(MediaEventType type, HRESULT hrStatus, IMFMediaEvent *pEvent);

	HRESULT CanSeek(BOOL *pbCanSeek);
	HRESULT GetDuration(MFTIME *phnsDuration);
	HRESULT GetCurrentPosition(MFTIME *phnsPosition);
	HRESULT SetPosition(MFTIME hnsPosition);

	HRESULT CanScrub(BOOL *pbCanScrub);
	BOOL	IsScrubbing();
	HRESULT Scrub(BOOL bScrub);
	void	ProcessFrameEvent();

	HRESULT CanFastForward(BOOL *pbCanFF);
	HRESULT CanRewind(BOOL *pbCanRewind);
	HRESULT SetRate(float fRate);
	HRESULT FastForward();
	HRESULT Rewind();

	HRESULT Start();
	HRESULT Pause();
	HRESULT Stop();

private:
	static const int RATE_INVALID = -100.0;
	static const int TIME_INVALID = -1;
	enum Command
	{
		CmdNone = 0,
		CmdStop,
		CmdStart,
		CmdPause,
		CmdSeek,		// Transitory state!
		CmdRate			// Transitory state!
	};

	// Bit flags!
	enum PendState
	{
		PendNone = 0,
		PendCmd  = 0x01,
		PendSeek = 0x02
		//		PendRate = 0x04		// Defined but never referenced in original sample Why??
	};

	HRESULT SetPositionInternal(const MFTIME &hnsPosition);
	HRESULT CommitRateChange(float fRate, BOOL bThin);
	float   GetNominalRate();

	HRESULT OnSessionStart(HRESULT hr);
	HRESULT OnSessionStop(HRESULT hr);
	HRESULT OnSessionPause(HRESULT hr);
	HRESULT OnSessionEnded(HRESULT hr);
	HRESULT OnSessionRateChanged(HRESULT hr, IMFMediaEvent* pEvent);

	HRESULT UpdatePendingCommands();
private:

	/// \class CCmd
	/// \brief Describes the current or requested state, with respect to seeking and playback rate.
	struct CCmd
	{
	public:
		CCmd() : cmd(CmdNone), fRate(0.0), bThin(false), hnsStart(-1) {	}
		CCmd(Command c) : cmd(c), fRate(0.0), bThin(false), hnsStart(-1) { }
		CCmd(Command c, float f, BOOL th, MFTIME t) : cmd(c), fRate(f), bThin(th), hnsStart(t) { }
		~CCmd() {}
		CCmd(const CCmd& other) { cmd = other.cmd; fRate = other.fRate; bThin = other.bThin; hnsStart = other.hnsStart; }
		CCmd& operator=(const CCmd& other) = default;
		Command cmd;
		float   fRate;      // Playback rate
		BOOL    bThin;      // Thinned playback?
		MFTIME  hnsStart;   // Start position
	};
	QString CmdToString(const CCmd& cmd);

	void SetPending(CCmd& cmd);
	void SetState(CCmd& cmd);

	// Command pending means we have started but not yet completed an async operation.
	// This is different than whether there are commands on the queue
	bool IsCommandPending() const { return (m_pending.cmd != CmdNone); }
	QQueue<CCmd>mQueue;
	CCmd   m_state;			// Current nominal state.
	CCmd   m_pending;	    // Pending State

	ZCritSect    m_critsec;      // Protects the seeking and rate-change states.

	DWORD       m_caps;         // Session caps.
	BOOL        m_bCanScrub;    // Does the current session support rate = 0.
	BOOL		m_scrubbing;

	MFTIME      m_hnsDuration;  // Duration of the current presentation.
	float       m_fPrevRate;

	IMFMediaSession         *m_pSession;
	IMFRateControl          *m_pRate;
	IMFRateSupport          *m_pRateSupport;
	IMFPresentationClock    *m_pClock;
};
} // End Name Space Pasco Video

#endif // WINDOWS
//-------------------------------------------------------------------------------------------------
/// Microsoft Sample Code
///  This is Microsoft Sample code related to media foundation seeking of video playback.
///  See Windows Dev Center article "Seeking, Fast Forward, and Reverse Play in Media Foundation
///  programming guide:
///  https://msdn.microsoft.com/en-us/library/windows/desktop/ee892373?f=255&MSPPError=-2147217396
///
/// \file   Backends\MediaFoundation\MFPlayerSeeking.cpp
/// \author Microsoft
/// \date	10/21/2016
/// \brief  Microsoft Media Foundation - Video Playback Seeking, Fast Forward and Reverse Play
//-------------------------------------------------------------------------------------------------
#include "_VideoLibPre.h"   // basically includes windows.h, debug heap, some common definitions
#include "_Tracing.h"       // #defines for debugging.
#include "MFPlayerSeeking.h"
#include "MFHelper.h"      // for MFTime conversions
#ifdef TRACE_VIDEO_EVENTS
#include <QString>
#include <QDebug>
#endif

#ifdef _WINDOWS
#include <assert.h>
#include <mfapi.h>
#include <mfidl.h>
#include <mferror.h>

namespace Video
{

	template <class T> void SafeRelease(T **ppT)
	{
		if (*ppT)
		{
			(*ppT)->Release();
			*ppT = NULL;
		}
	}

//-------------------------------------------------------------------------------------------------
// Internal Methods
//-------------------------------------------------------------------------------------------------
/// \brief Given a topology, returns a pointer to the presentation descriptor.

	HRESULT GetPresentationDescriptorFromTopology(
		IMFTopology *pTopology,
		IMFPresentationDescriptor **ppPD
	)
	{
		HRESULT hr = S_OK;

		IMFCollection *pCollection = NULL;
		IUnknown *pUnk = NULL;
		IMFTopologyNode *pNode = NULL;
		IMFPresentationDescriptor *pPD = NULL;

		// Get the collection of source nodes from the topology.
		hr = pTopology->GetSourceNodeCollection(&pCollection);
		if (FAILED(hr))
		{
			goto done;
		}

		// Any of the source nodes should have the PD, so take the first
		// object in the collection.

		hr = pCollection->GetElement(0, &pUnk);
		if (FAILED(hr))
		{
			goto done;
		}

		hr = pUnk->QueryInterface(IID_PPV_ARGS(&pNode));
		if (FAILED(hr))
		{
			goto done;
		}

		// Get the PD, which is stored as an attribute.
		hr = pNode->GetUnknown(
			MF_TOPONODE_PRESENTATION_DESCRIPTOR, IID_PPV_ARGS(&pPD));
		if (FAILED(hr))
		{
			goto done;
		}

		*ppPD = pPD;
		(*ppPD)->AddRef();

	done:
		SafeRelease(&pCollection);
		SafeRelease(&pUnk);
		SafeRelease(&pNode);
		SafeRelease(&pPD);
		return hr;
	}


	//-------------------------------------------------------------------------------------------------
	// ctor
	//-------------------------------------------------------------------------------------------------
	MFPlayerSeeking::MFPlayerSeeking()
		: m_pClock(NULL),
		m_pSession(NULL),
		m_pRate(NULL),
		m_pRateSupport(NULL),
		m_state(CCmd(CmdNone)),
		m_pending(CCmd(CmdNone)),
		m_caps(0),
		m_bCanScrub(false),
		m_scrubbing(false),
		m_hnsDuration(0),
		m_fPrevRate(0.0)

	{
		Clear();
	}

	//-------------------------------------------------------------------------------------------------
	// dtor
	//-------------------------------------------------------------------------------------------------
	MFPlayerSeeking::~MFPlayerSeeking()
	{
		SafeRelease(&m_pClock);
		SafeRelease(&m_pSession);
		SafeRelease(&m_pRate);
		SafeRelease(&m_pRateSupport);
	}

	//------------------------------------------------------------------------------
	HRESULT MFPlayerSeeking::Clear()
	{
		m_caps = 0;
		m_bCanScrub = FALSE;

		m_hnsDuration = 0;
		m_fPrevRate = 1.0f;


		SafeRelease(&m_pClock);
		SafeRelease(&m_pSession);
		SafeRelease(&m_pRate);
		SafeRelease(&m_pRateSupport);

		// Note that set state and set pending only set the .cmd variable for CmdNone!
		SetState(CCmd(CmdNone));
		m_state.fRate = 1.0;
		m_state.bThin = false;
		m_state.hnsStart = 0;

		SetPending(CCmd(CmdNone, 1.0, false, 0));
		m_pending.fRate = 1.0;
		m_pending.bThin = false;
		m_pending.hnsStart = 0;

		while (!mQueue.isEmpty())
			mQueue.dequeue();

		return S_OK;
	}


	//------------------------------------------------------------------------------
	// SetTopology
	//
	// Called when the full playback topology is ready. (MeSessonTopologyStatus ready)
	//------------------------------------------------------------------------------

	HRESULT MFPlayerSeeking::SetTopology(IMFMediaSession *pSession, IMFTopology *pTopology)
	{
		HRESULT hr = S_OK;
		HRESULT hrTmp = S_OK;   // For non-critical failures.

		IMFClock *pClock = NULL;
		IMFPresentationDescriptor *pPD = NULL;

		Clear();
		// We have just received a new topology: transition from state 'none' to 'stopped'
		SetState(CCmd(CmdStop));

		// Get the session capabilities.
		hr = pSession->GetSessionCapabilities(&m_caps);
		if (FAILED(hr))
		{
			goto done;
		}

		// Get the presentation descriptor from the topology.
		hr = GetPresentationDescriptorFromTopology(pTopology, &pPD);
		if (FAILED(hr))
		{
			goto done;
		}

		// Get the duration from the presentation descriptor (optional)
		(void)pPD->GetUINT64(MF_PD_DURATION, (UINT64*)&m_hnsDuration);

		// Get the presentation clock (optional)
		hrTmp = pSession->GetClock(&pClock);
		if (SUCCEEDED(hrTmp))
		{
			hr = pClock->QueryInterface(IID_PPV_ARGS(&m_pClock));
			if (FAILED(hr))
			{
				goto done;
			}
		}

		// Get the rate control interface (optional)
		hrTmp = MFGetService(
			pSession, MF_RATE_CONTROL_SERVICE, IID_PPV_ARGS(&m_pRate));

		// Get the rate support interface (optional)
		if (SUCCEEDED(hrTmp))
		{
			hrTmp = MFGetService(
				pSession, MF_RATE_CONTROL_SERVICE, IID_PPV_ARGS(&m_pRateSupport));
		}
		if (SUCCEEDED(hrTmp))
		{
			// Check if rate 0 (scrubbing) is supported.
			hrTmp = m_pRateSupport->IsRateSupported(TRUE, 0, NULL);
		}
		if (SUCCEEDED(hrTmp))
		{
			m_bCanScrub = TRUE;
		}

		// if m_pRate is NULL, m_bCanScrub must be FALSE.
		assert(m_pRate || !m_bCanScrub);

		// Cache a pointer to the session.
		m_pSession = pSession;
		m_pSession->AddRef();

		// Seek to position 0 to display first frame of movie.
		//SetPosition(0);
	done:
		SafeRelease(&pPD);
		SafeRelease(&pClock);
		return hr;
	}

	//------------------------------------------------------------------------------
	// SessionEvent
	//
	// Called when media session fires an event.
	//------------------------------------------------------------------------------

	HRESULT MFPlayerSeeking::SessionEvent(
		MediaEventType type,
		HRESULT hrStatus,
		IMFMediaEvent *pEvent
	)
	{
		HRESULT hr = S_OK;
		bool CheckPend = false;
		switch (type)
		{
		case MESessionStarted:
			// if pending is command seek, we do nothing,
			// and wait for ScrubComplete
			if (m_pending.cmd == CmdStart) {
				hr = OnSessionStart(hrStatus);
				CheckPend = true;
			}

			break;

		case MESessionStopped:
			hr = OnSessionStop(hrStatus);
			CheckPend = true;
			break;

		case MESessionPaused:
			hr = OnSessionPause(hrStatus);
			CheckPend = true;
			break;

		case MESessionRateChanged:
			hr = OnSessionRateChanged(hrStatus, pEvent);
			CheckPend = true;
			break;
		case MESessionEnded:
			hr = OnSessionEnded(hrStatus);
			CheckPend = true;
			break;

		case MESessionCapabilitiesChanged:
			// The session capabilities changed. Get the updated capabilities.
			m_caps = MFGetAttributeUINT32(pEvent, MF_EVENT_SESSIONCAPS, m_caps);
			CheckPend = false;
			break;

		case MESessionScrubSampleComplete:
			// We have Started session and waited for scrub sample to complete
			// Now we wait for ProcessFrameEvent
//			if (m_pending.cmd == CmdSeek)
//			{
//				OnSessionStart(S_OK);
//				SetPending(CCmd(CmdNone));
// 				Scrub(false);
 				qDebug() << DNTs("Scrub complete");
//				CheckPend = true;
//			}
			break;
		}
		if (CheckPend)
		{
			UpdatePendingCommands();
		}
 		return S_OK;
	}


	//------------------------------------------------------------------------------
	// Start
	//
	// Starts playback.
	//------------------------------------------------------------------------------
	HRESULT MFPlayerSeeking::Start()
	{
		HRESULT hr = S_OK;
		if (m_state.cmd == CmdStart)
		{
			UpdatePendingCommands();
			return S_OK;
		}
		ZAutoLock lock(m_critsec);

		// If another operation is pending, cache the request.
		// Otherwise, start the media session.
		if (IsCommandPending())
		{
			mQueue.enqueue(CCmd(CmdStart));
		}
		else
		{
#ifdef TRACE_VIDEO_PLAYER_TIMESTAMPS
			qDebug() << DNTs("Async: Start Media Session");
#endif
			PROPVARIANT varStart;
			PropVariantInit(&varStart);

			hr = m_pSession->Start(NULL, &varStart);
			SetPending(CCmd(CmdStart,RATE_INVALID, false, 0));
		}
		return hr;
	}

	//------------------------------------------------------------------------------
	// Pause
	//
	// Pauses playback.
	//------------------------------------------------------------------------------
	HRESULT MFPlayerSeeking::Pause()
	{


		HRESULT hr = S_OK;
		if (m_state.cmd == CmdPause) {
			UpdatePendingCommands();
			return S_OK;
		}
		// HACK ALERT: We cannot transition from Stop to Pause, so we do this haaaacckkk! ACK
		else if (m_state.cmd == CmdStop)
		{
			Start();
			mQueue.enqueue(CCmd(CmdPause));
		}

		ZAutoLock lock(m_critsec);

		// If another operation is pending, cache the request.
		// Otherwise, pause the media session.
		if (IsCommandPending())
		{
			mQueue.enqueue(CCmd(CmdPause));
		}
		else
		{
#ifdef TRACE_VIDEO_PLAYER_TIMESTAMPS
			qDebug() << DNTs("Async: Pause Media Session");
#endif
			hr = m_pSession->Pause();
			SetPending(CCmd(CmdPause));
		}
		return hr;
	}


	//------------------------------------------------------------------------------
	// Stop
	//
	// Stops playback.
	// Note: The Player class delegates Stop calls to the PlayerSeeking class.
	//------------------------------------------------------------------------------

	HRESULT MFPlayerSeeking::Stop()
	{
		HRESULT hr = S_OK;
		if (m_state.cmd == CmdStop)
		{
			UpdatePendingCommands();
			return S_OK;
		}
		if (m_pending.cmd == CmdStop)
		{
			return S_OK;
		}

		ZAutoLock lock(m_critsec);

		// If another operation is pending, cache the request.
		// Otherwise, stop the media session.
		if (IsCommandPending())
		{
			mQueue.enqueue(CCmd(CmdStop));
		}
		else
		{
#ifdef TRACE_VIDEO_PLAYER_TIMESTAMPS
			qDebug() << DNTs("Async: Stop Media Session");
#endif
			hr = m_pSession->Stop();
			SetPending(CCmd(CmdStop));
		}
		return hr;
	}

	//------------------------------------------------------------------------------
	// CanSeek
	//
	// Queries whether the current session supports seeking.
	//------------------------------------------------------------------------------

	HRESULT MFPlayerSeeking::CanSeek(BOOL *pbCanSeek)
	{
		if (pbCanSeek == NULL)
		{
			return E_POINTER;
		}

		// Note: The MFSESSIONCAP_SEEK flag is sufficient for seeking. However, to
		// implement a seek bar, an application also needs the duration (to get
		// the valid range) and a presentation clock (to get the current position).

		*pbCanSeek = (
			((m_caps & MFSESSIONCAP_SEEK) == MFSESSIONCAP_SEEK) &&
			(m_hnsDuration > 0) &&
			(m_pClock != NULL)
			);

		return S_OK;
	}


	//------------------------------------------------------------------------------
	// GetDuration
	//
	// Gets the duration of the current presentation.
	//------------------------------------------------------------------------------

	HRESULT MFPlayerSeeking::GetDuration(MFTIME *phnsDuration)
	{
		if (phnsDuration == NULL)
		{
			return E_POINTER;
		}

		*phnsDuration = m_hnsDuration;

		if (m_hnsDuration == 0)
		{
			return MF_E_NO_DURATION;
		}
		else
		{
			return S_OK;
		}
	}

	//------------------------------------------------------------------------------
	// GetCurrentPosition
	//
	// Gets the current playback position.
	//------------------------------------------------------------------------------

	HRESULT MFPlayerSeeking::GetCurrentPosition(MFTIME *phnsPosition)
	{
		if (phnsPosition == NULL)
		{
			return E_POINTER;
		}

		HRESULT hr = S_OK;

		ZAutoLock lock(m_critsec);

		if (m_pClock == NULL)
		{
			return MF_E_NO_CLOCK;
		}

		// Return, in order:
		// 1. Queued seek position (nominal position).
		// 2. Pending seek operation (nominal position).
		// 3. Presentation time (actual position).
		if (mQueue.size() != 0 && mQueue[0].cmd == CmdSeek)
		{
			*phnsPosition = mQueue[0].hnsStart;
		}
		else if (IsCommandPending() && m_pending.cmd == CmdSeek)
		{
			*phnsPosition = m_pending.hnsStart;
		}
		else
		{
			hr = m_pClock->GetTime(phnsPosition);
			if (SUCCEEDED(hr))
				m_state.hnsStart = *phnsPosition;
		}

		return hr;
	}


	//------------------------------------------------------------------------------
	// SetPosition
	//
	// Sets the current playback position.
	//------------------------------------------------------------------------------
	HRESULT MFPlayerSeeking::SetPosition(MFTIME hnsPosition)
	{
#ifdef TRACE_VIDEO_PLAYER_TIMESTAMPS
		qDebug() << DNTs("=====================================================");
		qDebug() << QString(DNTs("Set Position %1")).arg(MFHelper::MFTimeToReal(hnsPosition), 0, 'f', 3);
#endif
		ZAutoLock lock(m_critsec);
		HRESULT hr = S_OK;

		SetPending(CCmd(CmdNone));
		while (mQueue.size() != 0)
		{
			mQueue.dequeue();
		}

//		Command currentState = m_state.cmd;
		BOOL resetState = (mQueue.isEmpty() && !IsCommandPending());
		BOOL canScrub = false;
		hr = CanScrub(&canScrub);
		if (canScrub)
		{
			Scrub(true);
		}

		// Currently seeking or changing rates, so cache this request.
		if (IsCommandPending())
		{
			if (mQueue.size() != 0 && mQueue[0].cmd == CmdSeek)
				mQueue[0] = CCmd(CmdSeek, RATE_INVALID, false, hnsPosition);
			else
				mQueue.enqueue(CCmd(CmdSeek, RATE_INVALID, false, hnsPosition));
		}
		else
		{
			hr = SetPositionInternal(hnsPosition);
		}

//		if (resetState)
//			mQueue.enqueue(CCmd(currentState));
		return hr;
	}


	//------------------------------------------------------------------------------
	// CanScrub
	//
	// Queries whether the current session supports scrubbing.
	//------------------------------------------------------------------------------

	HRESULT MFPlayerSeeking::CanScrub(BOOL *pbCanScrub)
	{
		if (pbCanScrub == NULL)
		{
			return E_POINTER;
		}
		if (IsScrubbing() )
			*pbCanScrub = false;
		else
			*pbCanScrub = m_bCanScrub;

		return S_OK;
	}

	//------------------------------------------------------------------------------
	// IsScrubbbing
	//
	// Queries whether the current session is scrubbing
	//------------------------------------------------------------------------------
	BOOL MFPlayerSeeking::IsScrubbing()
	{
		BOOL result = m_scrubbing;
		if (m_state.fRate == 0.0)
			result = true;
		return result;
	}

	// ------------------------------------------------------------------------------
	// Scrub
	//
	// Enables or disables scrubbing.
	//------------------------------------------------------------------------------

	HRESULT MFPlayerSeeking::Scrub(BOOL bScrub)
	{
		// Scrubbing is implemented as rate = 0.

		ZAutoLock lock(m_critsec);

		if (!m_pRate)
		{
			return MF_E_INVALIDREQUEST;
		}
		if (!m_bCanScrub)
		{
			return MF_E_INVALIDREQUEST;
		}

		HRESULT hr = S_OK;
		float newRate = 0.0;
		if (bScrub)
		{
			// Enter scrubbing mode. Cache the current rate.
			if (GetNominalRate() != 0)
			{
				m_fPrevRate = m_state.fRate;
			}
			newRate = 0.0;
			hr = SetRate(newRate);
		}
		else
		{
			// Leaving scrubbing mode. Restore the old rate.
			if (GetNominalRate() == 0)
			{
				newRate = m_fPrevRate;
				hr = SetRate(m_fPrevRate);
			}
		}

#ifdef TRACE_VIDEO_PLAYER_TIMESTAMPS
		qDebug() << QString(DNTs("Scrubbing %1, new rate is %2")).arg(bScrub ? DNTs("enabled") : DNTs("disabled")).arg(newRate, 0, 'f', 3);
#endif

		m_scrubbing = bScrub;
		return hr;
	}

	//------------------------------------------------------------------------------
	void MFPlayerSeeking::ProcessFrameEvent()
	{
#ifdef TRACE_VIDEO_PLAYER_TIMESTAMPS
		if (IsScrubbing()) {
			qDebug() << DNTs("   ");
			qDebug() << DNTs("Process Frame Event");
			qDebug() << DNTs("   ");
		}
#endif


		if (m_pending.cmd == CmdSeek)
		{
			OnSessionStart(S_OK);
			SetPending(CCmd(CmdNone));
// We just finished a pending command: we know scrub(false) will immediately begin rate change)
//			if (mQueue.empty()) {
//			Scrub(false);
//			Pause();
			Stop();
//				mQueue.enqueue(CCmd(CmdPause));
//			}
//			UpdatePendingCommands();
		}
#ifdef TRACE_VIDEO_PLAYER_TIMESTAMPS
		if (IsScrubbing())
			qDebug() << DNTs("======================================");
#endif
	}
	//------------------------------------------------------------------------------
	// CanFastForward
	//
	// Queries whether the current session supports fast forward
	//------------------------------------------------------------------------------

	HRESULT MFPlayerSeeking::CanFastForward(BOOL *pbCanFF)
	{
		if (pbCanFF == NULL)
		{
			return E_POINTER;
		}

		*pbCanFF =
			((m_caps & MFSESSIONCAP_RATE_FORWARD) == MFSESSIONCAP_RATE_FORWARD);
		return S_OK;
	}


	//------------------------------------------------------------------------------
	// CanRewind
	//
	// Queries whether the current session supports rewind (reverse play).
	//------------------------------------------------------------------------------

	HRESULT MFPlayerSeeking::CanRewind(BOOL *pbCanRewind)
	{
		if (pbCanRewind == NULL)
		{
			return E_POINTER;
		}

		*pbCanRewind =
			((m_caps & MFSESSIONCAP_RATE_REVERSE) == MFSESSIONCAP_RATE_REVERSE);
		return S_OK;
	}


	//------------------------------------------------------------------------------
	// FastForward
	//
	// Switches to fast-forward playback, as follows:
	// - If the current rate is < 0 (reverse play), switch to 1x speed.
	// - Otherwise, double the current playback rate.
	//
	// Note: This method is just for convenience; the app could call SetRate().
	//------------------------------------------------------------------------------

	HRESULT MFPlayerSeeking::FastForward()
	{
		if (!m_pRate)
		{
			return MF_E_INVALIDREQUEST;
		}

		HRESULT hr = S_OK;
		float   fTarget = GetNominalRate() * 2;

		if (fTarget <= 0.0f)
		{
			fTarget = 1.0f;
		}

		hr = SetRate(fTarget);

		return hr;
	}


	//------------------------------------------------------------------------------
	// Rewind
	//
	// Switches to reverse playback, as follows:
	// - If the current rate is > 0 (forward playback), switch to -1x speed.
	// - Otherwise, double the current (reverse) playback rate.
	//
	// Note: This method is just for convenience; the app could call SetRate().
	//------------------------------------------------------------------------------

	HRESULT MFPlayerSeeking::Rewind()
	{
		if (!m_pRate)
		{
			return MF_E_INVALIDREQUEST;
		}

		HRESULT hr = S_OK;
		float   fTarget = GetNominalRate() * 2;

		if (fTarget >= 0.0f)
		{
			fTarget = -1.0f;
		}

		hr = SetRate(fTarget);

		return hr;
	}


	//------------------------------------------------------------------------------
	// SetRate
	//
	// Sets the playback rate.
	//------------------------------------------------------------------------------

	HRESULT MFPlayerSeeking::SetRate(float fRate)
	{
		HRESULT hr = S_OK;
		BOOL bThin = FALSE;

		ZAutoLock lock(m_critsec);

		if (fRate == GetNominalRate())
		{
			UpdatePendingCommands();
			return S_OK; // no-op
		}

		if (m_pRateSupport == NULL)
		{
			return MF_E_INVALIDREQUEST;
		}

		// Check if this rate is supported. Try non-thinned playback first,
		// then fall back to thinned playback.
		hr = m_pRateSupport->IsRateSupported(FALSE, fRate, NULL);

		if (FAILED(hr))
		{
			bThin = TRUE;
			hr = m_pRateSupport->IsRateSupported(TRUE, fRate, NULL);
		}

		if (FAILED(hr))
		{
			// Unsupported rate.
			return hr;
		}

		// If there is an operation pending, cache the request.
		if (IsCommandPending())
		{
			mQueue.enqueue(CCmd(CmdRate, fRate, bThin, TIME_INVALID));

			// Remember the current transport state (play, paused, etc), so that we
			// can restore it after the rate change, if necessary. However, if
			// another command is already pending, that one takes precedent.
			if (m_state.cmd == CmdPause || m_state.cmd == CmdStart || m_state.cmd == CmdStop)
			{
				mQueue.enqueue(CCmd(m_state.cmd));
			}
		}
		else
		{
			// No pending operation. Commit the new rate.
			hr = CommitRateChange(fRate, bThin);
		}

		return hr;

	}

	/// Protected methods


	//------------------------------------------------------------------------------
	// SetPositionInternal
	//
	// Sets the playback position.
	//------------------------------------------------------------------------------

	HRESULT MFPlayerSeeking::SetPositionInternal(const MFTIME &hnsPosition)
	{
		assert(m_pending.cmd == CmdNone);
		// Caller holds the lock.
#ifdef TRACE_VIDEO
		if (m_state.hnsStart == hnsPosition)
		{
			qDebug() << "Duplicate SetPosition? ";
		}
#endif
		if (m_pSession == NULL)
		{
			return MF_E_INVALIDREQUEST;
		}

#ifdef TRACE_VIDEO_PLAYER_TIMESTAMPS
		qDebug() << QString(DNTs("Async: Start Media Session moving to position %1, rate is:%2")).arg(hnsPosition).arg(m_state.fRate, 0, 'f', 3);
#endif
		HRESULT hr = S_OK;
		PROPVARIANT varStart;
		varStart.vt = VT_I8;
		varStart.hVal.QuadPart = hnsPosition;

		hr = m_pSession->Start(NULL, &varStart);

		if (SUCCEEDED(hr))
		{
			SetPending(CCmd(CmdSeek, RATE_INVALID, false, hnsPosition));
		}
		return hr;
	}

	//------------------------------------------------------------------------------
	// CommitRateChange
	//
	// Sets the playback rate.
	//------------------------------------------------------------------------------

	HRESULT MFPlayerSeeking::CommitRateChange(float fRate, BOOL bThin)
	{
		assert(m_pending.cmd == CmdNone);
		// Caller holds the lock.

		HRESULT hr = S_OK;
		MFTIME  hnsSystemTime = 0;
		MFTIME  hnsClockTime = 0;
		Command currentState = m_state.cmd;

		IMFClock *pClock = NULL;

		// Allowed rate transitions:
		//
		// Positive <-> negative:   Stopped
		// Negative <-> zero:       Stopped
		// Postive <-> zero:        Paused or stopped

		// Positive or Zero to Negative or Vice-Versa
		if ((fRate > 0 && m_state.fRate <= 0) || (fRate < 0 && m_state.fRate >= 0))
		{
			// Playing: Transition to Stop.
			if (currentState == CmdStart)
			{
				// Get the current clock position. This will be the restart time.
				hr = m_pSession->GetClock(&pClock);
				if (FAILED(hr))
					goto done;

				(void)pClock->GetCorrelatedTime(0, &hnsClockTime, &hnsSystemTime);

				assert(hnsSystemTime != 0);

#ifdef TRACE_VIDEO_PLAYER_TIMESTAMPS
				qDebug() << DNTs("Async: Stop, Commit Rate change"); // Was Stop, then Seek");
#endif
				!IsCommandPending() ? Stop() : mQueue.enqueue(CmdStop);
				mQueue.enqueue(CCmd(CmdRate, fRate, false, TIME_INVALID));
// TODO: Handle Rate change while playing...
//				mQueue.enqueue(CCmd(CmdPlay, RATE_INVALID, false, hnsClockTime));
				goto done;
			}
			else if (currentState == CmdPause)
			{
				// The current state is paused.

				// For this rate change, the session must be stopped. However, the
				// session cannot transition back from stopped to paused.
				// Therefore, this rate transition is not supported while paused.
				//qDebug() << DNTs("Error: Commit Rate change: fail while paused!!!");

				//hr = MF_E_UNSUPPORTED_STATE_TRANSITION;
				//// For this rate change, the session must be stopped.
				!IsCommandPending() ? Start() : mQueue.enqueue(CCmd(CmdStart));
				mQueue.enqueue(CCmd(CmdPause));
				mQueue.enqueue(CCmd(CmdRate, fRate, false, TIME_INVALID));
// TODO: Handle Rate change while playing...
//				mQueue.enqueue(CCmd(currentState));
				goto done;
			}
		}
		// Else transition Non-Zero rate to Zero
		else if (fRate == 0 && m_state.fRate != 0)
		{
			// This transition requires the paused state.
			if (currentState ==  CmdStart)
			{
#ifdef TRACE_VIDEO_PLAYER_TIMESTAMPS
				qDebug() << DNTs("Async: Rate change: Playing: Pause, rate change");
#endif
				// Pause and set the rate.
				if (! IsCommandPending())
					Pause();
				else
					mQueue.enqueue(CmdPause);

				mQueue.enqueue(CCmd(CmdRate, fRate, false, TIME_INVALID));
// TODO: Handle Rate change while playing...
//				mQueue.enqueue(CCmd(currentState));
				goto done;
			}
		}

		// Set the rate.
#ifdef TRACE_VIDEO_PLAYER_TIMESTAMPS
		qDebug() << QString(DNTs("Async: Commit Rate change: Set Rate %1")).arg(fRate, 0, 'f', 3);
#endif
		hr = m_pRate->SetRate(bThin, fRate);
		if (FAILED(hr))
		{
			goto done;
		}

		// Adjust our  requested rate.
		SetPending(CCmd(CmdRate, fRate, false, 0));

	done:
		SafeRelease(&pClock);
		return hr;
	}

	//------------------------------------------------------------------------------
	// GetNominalRate
	//
	// Returns the nominal playback rate.
	//------------------------------------------------------------------------------
	float MFPlayerSeeking::GetNominalRate()
	{
		return m_state.fRate;
	}


	//------------------------------------------------------------------------------
	// OnSessionStart
	//
	// Called when playback starts or restarts.
	//------------------------------------------------------------------------------

	HRESULT MFPlayerSeeking::OnSessionStart(HRESULT hrStatus)
	{
		HRESULT hr = S_OK;

		if (FAILED(hrStatus))
		{
			SetPending(CCmd(CmdNone));
			return hrStatus;
		}
		// We can start as a result of a seek command, where we moved to the pending start
		// position, or as a result of a "play" (Start) command, where there is no position
		// info: we keep our current position in that case.
		CCmd startedCmd = CCmd(CmdStart);
		if (m_pending.cmd == CmdSeek && m_pending.hnsStart != 0)
		{
			startedCmd.hnsStart = m_pending.hnsStart;
			// Leave pending command intact until ScrubCompleted event
		}
		else {  // Restarted from current
			startedCmd.hnsStart = m_state.hnsStart;
			SetPending(CCmd(CmdNone));
		}

		SetState(startedCmd);

		return hr;
	}


	//------------------------------------------------------------------------------
	// OnSessionStop
	//
	// Called when playback stops.
	//------------------------------------------------------------------------------

	HRESULT MFPlayerSeeking::OnSessionStop(HRESULT hrStatus)
	{
		SetPending(CCmd(CmdNone));
		if (FAILED(hrStatus))
		{
			return hrStatus;
		}
		SetState(CCmd(CmdStop));
		// The Media Session completed a transition to stopped. This might occur
		// because we are changing playback direction (forward/rewind). Check if
		// there is a pending rate-change request.
		return S_OK;
	}


	//------------------------------------------------------------------------------
	// OnSessionPause
	//
	// Called when playback pauses.
	//------------------------------------------------------------------------------

	HRESULT MFPlayerSeeking::OnSessionPause(HRESULT hrStatus)
	{
		SetPending(CCmd(CmdNone));

		if (FAILED(hrStatus))
		{
			return hrStatus;
		}
		SetState(CCmd(CmdPause));
		return S_OK;
	}


	//------------------------------------------------------------------------------
	// OnSessionEnded
	//
	// Called when the session ends.
	//------------------------------------------------------------------------------

	HRESULT MFPlayerSeeking::OnSessionEnded(HRESULT hr)
	{
		SetState(CCmd(CmdStop));
		SetPending(CCmd(CmdNone));
		// After the session ends, playback starts from position zero. But if the
		// current playback rate is reversed, playback would end immediately
		// (reversing from position 0). Therefore, reset the rate to 1x.

		if (GetNominalRate() < 0.0f)
		{
			hr = CommitRateChange(1.0f, FALSE);
		}
		return hr;
	}

	//------------------------------------------------------------------------------
	HRESULT MFPlayerSeeking::OnSessionRateChanged(HRESULT hr, IMFMediaEvent* pEvent)
	{
		// Don't clear pending status at beginning because we need to get the new rate out of it.

		// If the rate change succeeded, we've already got the rate cached in m_pending
		// If it failed, try to get the actual rate.

		// we will update the rate of our current state.
		CCmd updatedState = m_state;
		updatedState.cmd = CmdRate;

		if (FAILED(hr))
		{
			PROPVARIANT var;
			PropVariantInit(&var);
			hr = pEvent->GetValue(&var);
			if (SUCCEEDED(hr) && (var.vt == VT_R4))
			{
				updatedState.fRate = var.fltVal;
			}
		}
		else
		{
			updatedState.fRate = m_pending.fRate;
		}
#ifdef TRACE_VIDEO_PLAYER_TIMESTAMPS
		qDebug() << QString(DNTs("Player Seeking rate change %1, new rate is %2"))
					.arg("succeeded") // .arg(SUCCEEDED(hr) ? DNTs("succeeded") : DNTs("failed"))
					.arg(updatedState.fRate, 0, 'f', 3);
#endif
		SetState(updatedState);
		SetPending(CCmd(CmdNone));
		return hr;
	}

	//---------------------------------------------
	// Provides a central place to save pending commands, allowing us to do logging.
	QString MFPlayerSeeking::CmdToString(const CCmd& cmd)
	{
		QString cmdStr;
		switch (cmd.cmd) {
		case CmdNone:  cmdStr = DNTs("None"); break;
		case CmdStop:  cmdStr = DNTs("Stop"); break;
		case CmdStart: cmdStr = QString(DNTs("Start, fRate=%1, pos=%2")).arg(cmd.fRate,0, 'f', 3).arg(((qreal)cmd.hnsStart/10000000.0), 0, 'f', 3); break;
		case CmdPause: cmdStr = DNTs("Pause"); break;
		case CmdSeek:  cmdStr = QString(DNTs("Seek, pos=%1")).arg(((qreal)cmd.hnsStart / 10000000.0), 0, 'f', 3); break;
		case CmdRate:  cmdStr = QString(DNTs("Rate, fRate=%1")).arg(cmd.fRate, 0, 'f', 3); break;
		}
		return cmdStr;
	}

	//---------------------------------------------
	void MFPlayerSeeking::SetPending(CCmd& cmd)
	{
#ifdef TRACE_VIDEO_PLAYER_TIMESTAMPS
		qDebug() << DNTs("       Pend:") << CmdToString(cmd);
#endif
		m_pending = cmd;
	}
	//---------------------------------------------
	void MFPlayerSeeking::SetState(CCmd& cmd)
	{
		switch (cmd.cmd)
		{
		case CmdNone:	m_state.cmd = cmd.cmd; break;
		case CmdStop:	m_state.cmd = cmd.cmd; break;
		case CmdStart: {
			m_state.cmd = cmd.cmd;
			if (cmd.hnsStart != 0)						// Start from 0 means restart from current position
				m_state.hnsStart = cmd.hnsStart;		// so only update if starting from non-zero
		}
		break;
		case CmdPause:  m_state.cmd = cmd.cmd; break;
		case CmdSeek:	m_state.cmd = cmd.cmd; m_state.hnsStart = cmd.hnsStart; break;
		case CmdRate:	m_state.fRate = cmd.fRate;
		}
#ifdef TRACE_VIDEO_PLAYER_TIMESTAMPS
			qDebug() << DNTs("       State:") << CmdToString(cmd);
#endif
	}

	//------------------------------------------------------------------------------
	// UpdatePendingCommands
	//
	// Called after an operation completes.
	// This method executes any cached requests.
	//------------------------------------------------------------------------------

	HRESULT MFPlayerSeeking::UpdatePendingCommands()
	{
		HRESULT hr = S_OK;
		if (mQueue.isEmpty())
		{
#ifdef TRACE_VIDEO_PLAYER_TIMESTAMPS
			qDebug() << DNTs("UpdatePendingCommands: queue empty");
#endif
			return S_OK;
		}
		if (IsCommandPending())
		{
#ifdef TRACE_VIDEO_PLAYER_TIMESTAMPS
			qDebug() << DNTs("UpdatePendingCommands: already Pending");
#endif
			return S_OK;
		}
		PROPVARIANT varStart;
		PropVariantInit(&varStart);
		ZAutoLock lock(m_critsec);

		CCmd cmd = mQueue.dequeue();
#ifdef TRACE_VIDEO_EVENTS
		qDebug() << QString(DNTs("UpdatePendingCommands (cmd = %1 / rate = %2, thin=%3, pos=%4), count=%5")).arg(CmdToString(cmd.cmd)).arg(cmd.fRate, 0,'f',3).arg(cmd.bThin).arg(cmd.hnsStart).arg(mQueue.size());
#endif
		// The current pending command has completed.

		switch (cmd.cmd)
		{
		case CmdNone:
			// Nothing to do.
			break;

		case CmdStart:
			Start();
			break;

		case CmdPause:
			Pause();
			break;

		case CmdStop:
			Stop();
			break;

		case CmdSeek:
			if (cmd.fRate != m_state.fRate)
			{
				ZAutoLock lock(m_critsec);
				SetPositionInternal(cmd.hnsStart);
			}
			break;
		case CmdRate:
			if (cmd.fRate != m_state.fRate)
			{
				ZAutoLock lock(m_critsec);
				CommitRateChange(cmd.fRate, cmd.bThin);
			}
			break;
		}

		return hr;
	}

} // End Name space Pasco Video

#endif // Windows


An app default was reset

$
0
0
For the last 2 days everytime i turn my computer on i get the message that an app default was reset and it was reset to Microsoft Edge and i have to sign into Firefox and verify my email and reset my web browser to Firefox but as soon as i switch my machine of and back on again all this is lost and i have to do it all over again. Is there anything i can do to make Firefox stay as my chosen eb browser?

Network Path Broken and 3rd monitor cannot be detected

$
0
0

Update broke my computer...

My computer is the host for all files used in the office.  After this update, no one can log into my computer on the network anymore.  It gives error message that "Network path could not be found"  All of my settings are correct - I have triple checked. 

Also, my 3rd monitor cannot be detected- no matter what I do.  

I was on the phone with Microsoft "help desk" yesterday and they could not help with anything.  

I am very frustrated!  It was bad enough that Windows 10 was "tricked" on me to update to it...and now this.  


Iproperty setting Commit fails for fragmented mp4 files

$
0
0

I am trying to set PKEY_Media_Publisher for mp4 files.

This is how I am doing it (I don't have error checking here.):

IShellItem2 * shellItem = NULL;
IPropertyStore * propStore = NULL;
PROPVARIANT value;

hr = SHCreateItemFromParsingName(wchOutputVideoFile, NULL, IID_PPV_ARGS(&shellItem));

hr = shellItem->GetPropertyStore(GPS_READWRITE, __uuidof(IPropertyStore), (void**)&propStore);

value.vt = VT_LPWSTR;
value.pwszVal = L"My Publisher";

hr = propStore->SetValue(PKEY_Media_Publisher, value);

hr = propStore->Commit();

This works fine for regular mp4 files created with IMFSinkWriter.

However, for mp4 files created with MFCreateFMPEG4MediaSink the "Commit" call fails with E_FAIL.

Does anybody know why this might happen?

Live capture session does not restart after changing media type

$
0
0

Hello,

Inspired by the sample code https://msdn.microsoft.com/en-us/library/windows/desktop/hh184779(v=vs.85).aspx, I could successfully build a program that :
-enumerates the devices and detects my webcam
-creates a topology with the webcam as source and a sample grabber as sink (with a custom SampleGrabber callback)
-associates a media session
-receives and displays samples decoded as images

Now, I want to change the pixel format (because among the supported media types reported by the media source, there are for instance I420 and RGB24 flavours. It should be as simple as https://msdn.microsoft.com/en-us/library/windows/desktop/ff485858(v=vs.85).aspx),
But it does not work : when I restart the camera after changing the media type, I don't get any more samples to process.

It seems to be the same problem (still unresolved) found here : https://social.msdn.microsoft.com/Forums/lync/en-US/cbee3750-0026-42c9-a971-350dfcad2fb0/media-foundation-unable-to-restart-live-capture-session?forum=mediafoundationdevelopment

Honestly, I did things right, here is a list of what is important :

-the workflow works at first run

-I do not try to change the media type direcly, I first Stop() (or Pause()) the media session, then I Start() it again. I don't access to the media source directly, I use the MediaSession methods.

-To change the media type, I use the MediaTypeHandler from the presentation descriptor (like in https://msdn.microsoft.com/en-us/library/windows/desktop/ff485858(v=vs.85).aspx)

-I am under Windows 7, and want to keep W7 compatibility, so I don't know if using methods of IMFCaptureSource (available from W8) would change anything

-I do not send a wrong media type, I send one that is picked up in the available media types of the media source

-No error is raised at all, all calls return S_OK, but after the Start(), the camera just stop sending anything, I do not receive any samples to process

-According to the media source GetCharactersitics(), Pause() is supported (and it is a LIVE source)

-Rather that just Stop()/Start(),  I also tried to shutdown, release and recreate the media session to force a new full topology to be resolved, but it is not enough (see below)

-When I try to use Pause(), Start(), Stop(), SetTopology(), ClearTopologies(), SetTopology()... I always use GetEvent() to wait for the event ensuring that the operation completed (and I can observe that here again, there are no errors, even the asynchronous status get from the event is S_OK).

-I checked that the video stream is stil marked as Selected (and I call SelectStream() again, just to be sure).

-If I release the media session to create a new one, I can see that my SampleGrabber callback is properly deleted (destructor called), and I double checked everything, I should not have memory leaks. All the reference counts are OK and lead to proper object destruction.

-To make it work, I have to delete my media source (eventually using ShutdownObject() from its IMFActivate* activator caught from the device enumeration), and recreate the full workflow again (yes it works, it is rather fast, but what a pain).

-Interestingly, I can notice that the brand new "CurrentMediaType" that I set just before deleting/recreating the media source is lost. I have to save it and restore it after the rebirth of the media source. Then it works, the new mode (pixel fromat, frame size...) is honoured and the samples are sent to the grabber callback.

-If I decide not to use a media session at all, but a source reader instead and call ReadSample() myself, this is quite similar. After a restart, the program hangs on ReadSample().

What could be going on ?  Is this a bug of Media Foundation that does not release resource properly ? I don't think so, becaus eulimately, I would like the media session just to Pause()/Start(), so no resources should be released.
Is this something very special that I should take care of when using SetCurrentMediaType() ?

Any idea ?

Regards


Capturing an image from photo stream, using SourceReader, gives video stream buffer for first still trigger

$
0
0
Hi,

I have developed the desktop camera application using SourceReader technique in MediaFoundation.

The features of application are following:
            1. Video Streaming
            2. Still Capture and 
            3. Video Capture.
The SourceReader is in asynchronous mode, capable of video streaming and capturing an image. But I am facing a major issue while capturing an image from photo stream.

Issue description:
At very first still trigger from photo stream, I am receiving video streaming buffer sample, in OnReadSample Callback, with dwStreamIndex as 0(Zero).
 
(Eg: Video Streaming resolution is 1280 x 720 and Still resolution is1920 x 1080, Received buffer for first still trigger : 1280 x 720)
This issue occurs in following scenarios : 
1. First still trigger after Launch the application.
2. After change in the video resolution and still trigger .

For consecutive still triggers, I'm receiving the sample from photo stream as expected , in OnReadSample callback, with dwStreamIndex as  1(one).
The above issue is recreated only with change in the video resolution and following still trigger. Whereas, not for change in the still resolution.

Why am i receiving video streaming buffer instead of photo stream buffer for the first still trigger? Am I missing something to configure for photo stream ? If yes, help me resolve this issue.

Thanks in advance.

Screen Capture with Media Foundation

$
0
0

Hi,

My first two questions in this forum got zero replies, maybe third time's a charm.

Is there any sample that shows how to perform screen capture with Media Foundation ?

I tried to write a custom source that performs screen capture using DirectX output duplication, however, 
when I use MFCreateDXGISurfaceBuffer to create the samples, it just doesn't work. My topology is very simple - 
the custom screen source is directly connect to an EVR. I also have a more complex topology that uses 
h264 encoder MFT to compress the video and fragmented MP4 sink to write it, but even the simple one doesn't work,
so it's less relevant...

If I hook the buffer returned from MFCreateDXGISurfaceBuffer, and make it return E_NOINTERFACE when asked
for IID_IMFDXGIBuffer, then it does work, but the performance is not optimal (MF uses IMF2DBuffer2 instead)

In general, it seems there is very little documentation about the MF DXGI support.

Any help will be appreciated !

Eran

Encoding float audio input to MP3

$
0
0

I have a float audio source which is 32 bits/sample.  What is the best way to get it into an MP3 format.  The MF MP3 encoder states it can only support PCM 16 bits/sample source


Martin Autry

Viewing all 1079 articles
Browse latest View live