Avoid MF_E_SINK_NO_SAMPLES_PROCESSED (0xC00D4A44) error?

Dec 7, 2014 at 8:27 PM
in NAudio I read about a way to avoid 0xC00D4A44 in stead of catching it: delay the finalize until the sinkwriter has emptied it's buffers. I guess that it solves a problem someone once posed, that a recording is a little bit shorter than expected.
Is there a way in (for instance) the RecordToWma program to access the statistics of the underlying sinkwriter and wait here? or has the wait to be placed inside the CSCore class that actually finalizes?

Note. Je mehr ich Ihre Arbeit verwende (und anfange zu verstehen), desto mehr denke ich "Hut ab" für das, was Sie uns bieten!
Coordinator
Dec 7, 2014 at 8:33 PM
If I got you right, you would like to wait until the SinkWriter processed all bytes. Well I am actually already doing that:
                    while (_sinkWriter.GetStatistics(_streamIndex).DwByteCountQueued > 0)
                    {
                        _sinkWriter.Flush(_streamIndex);
                        Thread.Sleep(50);
                    }
Or what do you mean?
Dec 7, 2014 at 8:41 PM
I don't know what to answer, as it is exactly what NAudio specifies to do. I guess that there is something wrong in the reporting of the DwByteCountQueued, as in reality there are no bytes written by the sinkwriter, after I sent 2 second sound samples to write. Which means that the DwByteCountQueued must be > 0.
I will try to get some more information about the case, so you might have a clue of where things go wrong.
Dec 8, 2014 at 2:09 PM
Edited Dec 8, 2014 at 2:10 PM
I'm playing my sound with VLC, that produces alternating samples of 7168 and 3584 bytes. Average 5376.

First I viewed the statistics just before and in the while loop.
The DwByteCountQueued indicated a number between 0.2 (50000 bytes) and 0.9 (250000 bytes) seconds of sound yet to be processed. I ran it about 15 times to get some idea. After the first Flush inside the while, that number becomes 0.
FinalizeWriting then finishes off the file, but the flushed part is missing.

I omitted the while loop and the flush after the loop and added the statistics just before and after the finalize.
I record 0,569 seconds of sound (as measured by Goldwave when opening the resulting file) and see in the Sinkwriter statistics:
before FinalizeWriting
DwByteCountQueued 189952
QwNumSamplesReceived 36
QwNumSamplesEncoded 0
QwNumSamplesProcessed 0
QwByteCountProcessed 0

after FinalizeWriting
DwByteCountQueued 0
QwNumSamplesReceived 36
QwNumSamplesEncoded 2
QwNumSamplesProcessed 2
QwByteCountProcessed 17834

0,569 * 189952 = 333834 bytes in a 1 second sound / 44100 : 8 bytes per sample

Obviously the samplesize of QwNumSamplesReceived and of QwNumSamplesEncoded is not the same!


Old source:
                if (_sinkWriter != null)
                {
                    while (_sinkWriter.GetStatistics(_streamIndex).DwByteCountQueued > 0)
                    {
                        _sinkWriter.Flush(_streamIndex);
                        Thread.Sleep(50);
                    }
                    _sinkWriter.Flush(_streamIndex);
                    try
                    {
                        _sinkWriter.FinalizeWriting();
                    }
                    catch (MediaFoundationException exception)
                    {
                        if (exception.ErrorCode != unchecked((int)0xc00d4a44)) //catch MF_E_SINK_NO_SAMPLES_PROCESSED
                            throw;
                    }
                    _sinkWriter.Dispose();
                    _sinkWriter = null;
                }
New source:
                if (_sinkWriter != null)
                {
                    MFSinkWriterStatistics st = _sinkWriter.GetStatistics(_streamIndex);
                    if ( st.DwByteCountQueued > 0 || st.QwNumSamplesReceived > 0)
                        _sinkWriter.FinalizeWriting();
                    _sinkWriter.Dispose();
                    _sinkWriter = null;
                }
My conclusion:
  1. Flush(stream) really flushes the contents of the pipeline.
  2. FinalizeWriting waits for the pipeline to be emptied, before closing the file.
  3. There is no need to wait also before calling FinalizeWriting as with a Flush data is lost, and without it, the number DwByteCountQueued does not decrease (but don't ask me why the parallel process is waiting; the NAudio solution does not include a flush, but somehow the count decreases)
  4. There is no need to catch 00d4a44 as it does not occur in normal circumstances. Calling FinalizeWriting only if DwByteCountQueued > 0 || QwNumSamplesReceived > 0 then avoids the exception on creating an empty file. Note that the resulting wma file in that case has an invalid format.
Verified with all cases known to me.
Marked as answer by filoe on 12/9/2014 at 1:59 PM
Coordinator
Dec 9, 2014 at 8:58 PM
Wow. Thanks a lot for your great work. I've updated the source code. It works perfectly!
There is some kind of a "thank you comment" inside of the code file. Did you use NAudio? If yes I would also need to mention NAudio there :).
Dec 10, 2014 at 6:32 AM
No need to thank me, It's a grain of sand on a beach! I did not use NAudio: someone had a similar problem in NAudio, I found their solution which I proposed to you, but you had it coded in that way. Probably the NAudio solution is not correct, but it's up to the users to find that out and correct it. Not knowing NAudio, I have not the time to find out all details necessary!