When we implement the conversion of video with Audio sample rate from 16Khz to 44.1 Khz, there was a problem as follows:
- On windows 7, the program worked successful.
- On Windows 10, the program encountered a bug, the output audio is ran faster than the input audio.
Program details as below:
---------------------------------------
#include "stdafx.h"
#include <windows.h>
#include <windowsx.h>
#include <comdef.h>
#include <stdio.h>
#include <mfapi.h>
#include <mfidl.h>
#include <mfreadwrite.h>
#include <Mferror.h>
#include <mfplay.h>
#pragma comment(lib, "ole32")
#pragma comment(lib, "mfplat")
#pragma comment(lib, "mfreadwrite")
#pragma comment(lib, "mfuuid")
int main()
{
HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
hr = MFStartup(MF_VERSION);
IMFMediaType *pMediaType;
IMFMediaType *pMediaTypeOut;
IMFSourceReader *pSourceReader;
IMFAttributes *pAttributes;
IMFSinkWriter *pSinkWriter;
IMFMediaType *pCurrentMediaType;
LONGLONG nDruration = 412800000;
// Load souce file
hr = MFCreateSourceReaderFromURL(
L"input.mp4",
NULL,
&pSourceReader
);
pSourceReader->SetStreamSelection(MF_SOURCE_READER_FIRST_AUDIO_STREAM, TRUE);
// Create a partial media type that specifies uncompressed audio
IMFMediaType *pPartialType;
MFCreateMediaType(&pPartialType);
hr = pPartialType->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio);
hr = pPartialType->SetGUID(MF_MT_SUBTYPE, MFAudioFormat_PCM);
hr = pSourceReader->SetCurrentMediaType(MF_SOURCE_READER_FIRST_AUDIO_STREAM
, nullptr
, pPartialType);
hr = pSourceReader->GetCurrentMediaType(MF_SOURCE_READER_FIRST_AUDIO_STREAM, &pPartialType);
hr = pSourceReader->SetStreamSelection(MF_SOURCE_READER_FIRST_AUDIO_STREAM, TRUE);
// set media type for output file
hr = MFCreateMediaType(&pMediaTypeOut);
// set major type for output file
hr = pMediaTypeOut->SetGUID(
MF_MT_MAJOR_TYPE,
MFMediaType_Audio
);
// Set subtype for output file
hr = pMediaTypeOut->SetGUID(
MF_MT_SUBTYPE,
MFAudioFormat_AAC
);
hr = pMediaTypeOut->SetUINT32(
MF_MT_AUDIO_SAMPLES_PER_SECOND,
44100
);
// set audio number channal for output file
hr = pMediaTypeOut->SetUINT32(
MF_MT_AUDIO_NUM_CHANNELS,
2
);
// set audio bit depth for output file
hr = pMediaTypeOut->SetUINT32(
MF_MT_AUDIO_BITS_PER_SAMPLE,
16
);
hr = pMediaTypeOut->SetUINT32(
MF_MT_AUDIO_AVG_BYTES_PER_SECOND,
12000.5
);
hr = pMediaTypeOut->SetUINT32(
MF_MT_AUDIO_BLOCK_ALIGNMENT,
1
);
pMediaTypeOut->SetUINT32(MF_MT_AAC_AUDIO_PROFILE_LEVEL_INDICATION, 0x29);
DWORD nWriterStreamIndex = -1;
hr = MFCreateSinkWriterFromURL(
L"Output.mp4",
NULL,
NULL,
&pSinkWriter
);
hr = pSinkWriter->AddStream(pMediaTypeOut, &nWriterStreamIndex);
hr = pSinkWriter->BeginWriting();
_com_error err(hr);
LPCTSTR errMsg = err.ErrorMessage();
LONGLONG SampleDuration;
//Sets the input format for a stream on the sink writer.
hr = pSinkWriter->SetInputMediaType(nWriterStreamIndex, pPartialType, NULL);
for (;;)
{
DWORD nStreamIndex, nStreamFlags;
LONGLONG nTime;
IMFSample *pSample;
hr = pSourceReader->ReadSample(
MF_SOURCE_READER_FIRST_AUDIO_STREAM,
0,
&nStreamIndex,
&nStreamFlags,
&nTime,
&pSample);
printf("%d\n", nStreamFlags);
printf("%d\n", nTime);
//Update media type, when current media tye changed.
if (nStreamFlags & MF_SOURCE_READERF_CURRENTMEDIATYPECHANGED) {
pSourceReader->GetNativeMediaType(MF_SOURCE_READER_FIRST_AUDIO_STREAM, MF_SOURCE_READER_CURRENT_TYPE_INDEX, &pCurrentMediaType);
pSourceReader->SetCurrentMediaType(MF_SOURCE_READER_FIRST_AUDIO_STREAM
, nullptr
, pCurrentMediaType);
pSourceReader->SetStreamSelection(MF_SOURCE_READER_FIRST_AUDIO_STREAM, TRUE);
continue;
}
pSample->GetSampleDuration(&SampleDuration);
if (nTime >= nDruration)
{
break;
}
// Calculate new timestamp of sample when this sample is written on output file
if (nTime + SampleDuration >= nDruration)
{
SampleDuration = nDruration - nTime;
pSample->SetSampleDuration(SampleDuration);
}
pSample->SetSampleTime(nTime);
if (FAILED(hr)) {
printf("ReadSample Error...\n");
return 0;
}
//write sample
if (pSample)
{
OutputDebugString(L"Write sample...\n");
hr = pSinkWriter->WriteSample(
nWriterStreamIndex,
pSample
);
if (FAILED(hr)) {
printf("WriteSample Error...\n");
return 0;
}
}
if (nStreamFlags & MF_SOURCE_READERF_ENDOFSTREAM)
{
break;
}
}
hr = pSinkWriter->Finalize();
return 0;
}
-------------------------------
When debugging, we detected the following points:
- After running through the IMFSourceReader::ReadSample funtion. On windows 7, the parameter "nStreamFlags" has resulted in 0.On windows 7, the "nStreamFlags" has resulted in "MF_SOURCE_READERF_CURRENTMEDIATYPECHANGED".
- Bug only appear in the input audio format is AAC, with input audio format is WMA, PCM ... it is not happen.
- When input audio format is AAC, this bug only appear in cases with input audio sample rate is less than 32Khz and converting to 44.1kHz sample rate output.
Q: Can you explain the problem, is there something wrong with the IMFSourceReader::ReadSample funtion?