A big problem with encoding an MP4 file
-
Friday, May 11, 2012 2:27 AM
I modified the sample (Transcode) provided by Windows SDK and encoded a MP4 file. But this MP4 file can not be correctly played by IPAD2. The duration of this MP4 is 20min30s, but the video stopped at 6min11min when it is played on IPAD2.
1) I analyzed the MP4 file, in Movie Head box(MVHD), the duration is 54253720, the timeScale is 44100, so duration/timeScale is 1230s(i.e 20min30s); in media head box(MDHD), the duration is 8911156, the time scale is 24000, so duration/timescale is 371s(i.e 6min11s). So For mp4 file encoded by transcode API, is there something wrong with duration in MDHD?
2) I tested some files, I found that if the duration of mp4 file is larger than 429s, the file can not be played correctly, the video will be stopped in a time point(<429s).
3) The following is the code I modified.
//-------------------------------------------------------------------
// ConfigureAudioOutput
//
// Configures the audio stream attributes.
// These values are stored in the transcode profile.
//
//-------------------------------------------------------------------
HRESULT
CTranscoder::ConfigureAudioOutput()
{
assert (m_pProfile);
HRESULT hr = S_OK;
DWORD dwMTCount = 0;
IMFCollection *pAvailableTypes = NULL;
IUnknown *pUnkAudioType = NULL;
IMFMediaType *pAudioType = NULL;
IMFAttributes *pAudioAttrs = NULL;
// Get the list of output formats supported by the Windows Media
// audio encoder.
hr = MFTranscodeGetAudioOutputAvailableTypes(
MFAudioFormat_AAC,//MFAudioFormat_WMAudioV9,
MFT_ENUM_FLAG_ALL,
NULL,
&
pAvailableTypes
);
// Get the number of elements in the list.
if (SUCCEEDED(hr))
{
hr = pAvailableTypes->GetElementCount( &dwMTCount );
if (dwMTCount == 0)
{
hr = E_UNEXPECTED;
}
}
// In this simple case, use the first media type in the collection.
if (SUCCEEDED(hr))
{
hr = pAvailableTypes->GetElement(0, &pUnkAudioType);
}
if (SUCCEEDED(hr))
{
hr = pUnkAudioType->QueryInterface(IID_PPV_ARGS(&pAudioType));
}
// Create a copy of the attribute store so that we can modify it safely.
if (SUCCEEDED(hr))
{
hr = MFCreateAttributes(&pAudioAttrs, 0);
}
if (SUCCEEDED(hr))
{
hr = pAudioType->CopyAllItems(pAudioAttrs);
}
// Set the encoder to be Windows Media audio encoder, so that the
// appropriate MFTs are added to the topology.
if (SUCCEEDED(hr))
{
hr = pAudioAttrs->SetGUID(MF_MT_SUBTYPE, MFAudioFormat_AAC/*MFAudioFormat_WMAudioV9*/);
}
// Set the attribute store on the transcode profile.
if (SUCCEEDED(hr))
{
hr = m_pProfile->SetAudioAttributes( pAudioAttrs );
}
SafeRelease(&pAvailableTypes);
SafeRelease(&pAudioType);
SafeRelease(&pUnkAudioType);
SafeRelease(&pAudioAttrs);
return hr;
}
//-------------------------------------------------------------------
// ConfigureVideoOutput
//
// Configures the Video stream attributes.
// These values are stored in the transcode profile.
//
//-------------------------------------------------------------------
HRESULT
CTranscoder::ConfigureVideoOutput()
{
assert (m_pProfile);
HRESULT hr = S_OK;
IMFAttributes* pVideoAttrs = NULL;
// Configure the video stream
// Create a new attribute store.
if (SUCCEEDED(hr))
{
hr = MFCreateAttributes( &pVideoAttrs, 5 );
}
// Set the encoder to be Windows Media video encoder, so that the appropriate MFTs are added to the topology.
if (SUCCEEDED(hr))
{
hr = pVideoAttrs->SetGUID(MF_MT_SUBTYPE, MFVideoFormat_H264);
}
// Set the frame rate.
if (SUCCEEDED(hr))
{
hr = MFSetAttributeRatio(pVideoAttrs, MF_MT_FRAME_RATE, 24, 1);
}
//Set the frame size.
if (SUCCEEDED(hr))
{
hr = MFSetAttributeSize(pVideoAttrs, MF_MT_FRAME_SIZE, 320, 240);
}
//Set the pixel aspect ratio
if (SUCCEEDED(hr))
{
hr = MFSetAttributeRatio(pVideoAttrs, MF_MT_PIXEL_ASPECT_RATIO, 1, 1);
}
// Set the bit rate.
if (SUCCEEDED(hr))
{
hr = pVideoAttrs->SetUINT32(MF_MT_AVG_BITRATE, 500000);
}
// Set the attribute store on the transcode profile.
if (SUCCEEDED(hr))
{
hr = m_pProfile->SetVideoAttributes( pVideoAttrs );
}
SafeRelease(&pVideoAttrs);
return hr;
}
//-------------------------------------------------------------------
// ConfigureContainer
//
// Configures the container attributes.
// These values are stored in the transcode profile.
//
// Note: Setting the container type does not insert the required
// MFT node in the transcode topology. The MFT node is based on the
// stream settings stored in the transcode profile.
//-------------------------------------------------------------------
HRESULT
CTranscoder::ConfigureContainer()
{
assert (m_pProfile);
HRESULT hr = S_OK;
IMFAttributes* pContainerAttrs = NULL;
//Set container attributes
hr = MFCreateAttributes( &pContainerAttrs, 1 );
//Set the output container to be ASF type
if (SUCCEEDED(hr))
{
hr = pContainerAttrs->SetGUID(
MF_TRANSCODE_CONTAINERTYPE,
MFTranscodeContainerType_MPEG4//MFTranscodeContainerType_ASF
);
}
// Use the default setting. Media Foundation will use the stream
// settings set in ConfigureAudioOutput and ConfigureVideoOutput.
if (SUCCEEDED(hr))
{
hr = pContainerAttrs->SetUINT32(
MF_TRANSCODE_ADJUST_PROFILE,
MF_TRANSCODE_ADJUST_PROFILE_USE_SOURCE_ATTRIBUTES
);
}
//Set the attribute store on the transcode profile.
if (SUCCEEDED(hr))
{
hr = m_pProfile->SetContainerAttributes(pContainerAttrs);
}
SafeRelease(&pContainerAttrs);
return hr;
}
All Replies
-
Friday, May 11, 2012 3:29 AM
Let me just start by saying that I hate Quicktime. It's the most intollerant player on the market. Your encoded MP4 files will not playback at all or freeze after a while under the following conditions with most versions of Quicktime player:
-The file is over 1GB in size. Don't ask me why this is an issue. I just know it to be true on all platforms.
-If you are using H.264 as the video codec and the H.264 Profile is set to High. Quicktime has shocking support for anything other than Baseline or Main.
It's mostly to do with atom structure support. Media Foundation places the MVHD atom at the end of the file when you call SinkWriter->Finalize(). With some versions of Quicktime, the player will actually seek through the file, byte-by-byte looking for the MVHD atom and this can take a long time if the file is large. When this is the case, the screen might stay black forever and it will never begin playback.
With the issue of stopping playback part-way through, this is a combination of file size and how the sample chunk table is defined. I've compared MOV files generated by Quicktime Pro and MP4 files generated by MF and found that the sample chunk tables defined by Quicktime are fairly random. They're supposed to optimise sample seeking but I can't figure the logic of it out. Either way, the method Media Foundation uses can break the multimedia pipeline in Quicktime. It's not random either, it will always stop playback at EXACTLY the same place for a particular MP4 file.
The way I got around it was writing my own MOV file sink. Media Foundation supports MOV files but only for media sources. If you go down this path yourself, all you have to do is make sure the track header, sample offsets and sample chuck tables appear before the MDAT atom. To be safe, just place the MDAT atom(movie data) at the back of the file, after everything else(except maybe before the metadata atom for compatibility)
Welcome to the road of chronic dissapointment =(.
- Proposed As Answer by Matt AndrewsMicrosoft Employee, Moderator Friday, June 15, 2012 11:43 PM
-
Friday, May 11, 2012 6:52 AM
I forgot to mention that there's some nifty tools out there to combat incompatibility issues with file structures. I originally used Atom Viewer when learning about the MOV/MP4 file formats. The author of that software made a juiced up version of it called Atom Box Studio. The professional version of it can adjust your MP4 files so that it falls in line with Apple MOV/MP4 accepted atom structures/layouts.
Unfortunately, the author is in europe somewhere hence the cost is in euros and rediculously expensive.


