编码MP4文件的一个大问题 [英] A big problem with encoding an MP4 file

查看:119
本文介绍了编码MP4文件的一个大问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我修改了Windows SDK提供的样本(Transcode)并编码了MP4文件。但是IPAD2无法正确播放此MP4文件。这个MP4的持续时间是20分30秒,但视频在IPAD2上播放时在6分11秒时停止。 

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)我在电影头部分析了MV4文件(MVHD) ),持续时间为54253720,timeScale为44100,因此持续时间/时间刻度为1230s(即20分30秒);在媒体头箱(MDHD)中,持续时间为8911156,时间刻度为24000,因此持续时间/时间刻度为
371s(即6分11秒)。那么对于由转码API编码的mp4文件,MDHD中的持续时间是否有问题?

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)我测试了一些文件,我发现如果mp4文件的持续时间大于429s ,文件无法正常播放,视频将在某个时间点停止(< 429s)。

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)以下是我修改过的代码。

3) The following is the code I modified.

// ---- -------------------------------------------------- -------------

//-------------------------------------------------------------------

//  ConfigureAudioOutput

//  ConfigureAudioOutput

//       

//       

// 配置音频流属性。 

//  Configures the audio stream attributes. 

// 这些值存储在转码配置文件中。

//  These values are stored in the transcode profile.

//

// --------------- -------------------------------------------------- -

//-------------------------------------------------------------------

HRESULT

CTranscoder :: ConfigureAudioOutput ()

{

   

   

断言 m_pProfile );

   

   

HRESULT
< span style ="color:#010001; font-size:small"> hr =
S_OK ;

   

   

DWORD
< span style ="color:#010001; font-size:small"> dwMTCount = 0;

   

   

IMFCollection    * pAvailableTypes
=
NULL ;

   

   

IUnknown         * pUnkAudioType
=
NULL ;

   

   

IMFMediaType     * pAudioType
=
NULL ;

   

   

IMFAttributes    * pAudioAttrs
=
NULL ;

   

   

//获取Windows Media支持的输出格式列表

   

   

//音频编码器。

&NBSP;&NBSP;&NBSP;

   

hr =
MFTranscodeGetAudioOutputAvailableTypes

       

       

MFAudioFormat_AAC // MFAudioFormat_WMAudioV9 ,

MFAudioFormat_AAC,//MFAudioFormat_WMAudioV9,

        

       

MFT_ENUM_FLAG_ALL

       

       

NULL

       &

        &

< span style ="color:#010001; font-size:small"> pAvailableTypes

        );

        );

   

   

//获取列表中元素的数量。

   

   

if SUCCEEDED hr ))

    {

    {

  ;      

       

hr =
pAvailableTypes - > GetElementCount
&
dwMTCount );

       

       

if dwMTCount
== 0)

        {

        {

           

           

hr =
E_UNEXPECTED ;

       }

        }

   }

    }

   

   

//在这个简单的例子中,使用集合中的第一个媒体类型。

   

   

if SUCCEEDED hr ))

    {

    {

  ;      

       

hr =
pAvailableTypes - > GetElement (0,
&
pUnkAudioType );    

   }

    }

   

   

if SUCCEEDED hr ))

    {

    {

  ;      

       

hr =
pUnkAudioType - > QueryInterface IID_PPV_ARGS (& pAudioType ));

hr = pUnkAudioType->QueryInterface(IID_PPV_ARGS(&pAudioType));

   }

    }

   

   

//创建属性存储的副本,以便我们可以安全地修改它。

   

   

if SUCCEEDED hr ))

    {

    {

  ;      

       

hr =
MFCreateAttributes (& pAudioAttrs
0);     

   }

    }

   

   

if SUCCEEDED hr ))

    {

    {

  ;      

       

hr =
pAudioType - > CopyAllItems pAudioAttrs );

   }

    }

   

   

//将编码器设置为Windows Media音频编码器,以便

   

   

//将适当的MFT添加到拓扑中。

   

   

if SUCCEEDED hr ))

    {

    {

  ;      

       

hr =
pAudioAttrs - > SetGUID MF_MT_SUBTYPE
MFAudioFormat_AAC / * MFAudioFormat_WMAudioV9 * / ) ;

hr = pAudioAttrs->SetGUID(MF_MT_SUBTYPE, MFAudioFormat_AAC/*MFAudioFormat_WMAudioV9*/);

   }

    }

   

   

   

   

//在转码配置文件中设置属性存储。

   

   

if SUCCEEDED hr ))

    {

    {

  ;      

       

hr =
m_pProfile - > SetAudioAttributes
pAudioAttrs );

   }

    }

   

   

SafeRelease (& pAvailableTypes );

   

   

SafeRelease (& pAudioType );

   

   

SafeRelease (& pUnkAudioType );

   

   

SafeRelease (& pAudioAttrs );

   

   

return
hr ;

}

// ---------------------------------- ---------------------------------

//-------------------------------------------------------------------

//  ConfigureVideoOutput

//  ConfigureVideoOutput

//       

//       

// 配置视频流属性。 

//  Configures the Video stream attributes. 

// 这些值存储在转码配置文件中。

//  These values are stored in the transcode profile.

//

// - -------------------------------------------------- ----------------

//-------------------------------------------------------------------

HRESULT

CTranscoder :: ConfigureVideoOutput ()

{

   

   

断言 m_pProfile );

   

   

HRESULT
hr =
S_OK ;

   

   

IMFAttributes *
pVideoAttrs =
NULL ;

   

   

//配置视频流

   

   

//创建一个新的属性存储。

   

   

if SUCCEEDED hr ))

    {

    {

  ;      

       

hr =
MFCreateAttributes (& pVideoAttrs
5);

   }

    }

    ; 

   

//将编码器设置为Windows Media视频编码器,以便将相应的MFT添加到拓扑中。

   

   

if SUCCEEDED hr ))

    {

    {

  ;      

       

hr =
pVideoAttrs - > SetGUID MF_MT_SUBTYPE
MFVideoFormat_H264 );

hr = pVideoAttrs->SetGUID(MF_MT_SUBTYPE, MFVideoFormat_H264);

   }

    }

   

   

//设置帧速率。

   

   

if SUCCEEDED hr ))

    {

    {

  ;      

       

hr =
MFSetAttributeRatio pVideoAttrs
MF_MT_FRAME_RATE ,24,1);

   }

    }

   

   

//设置帧大小。

   

   

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

//  ConfigureContainer

//       

//       

//  Configures the container attributes. 

//  Configures the container attributes. 

//  These values are stored in the transcode profile.

//  These values are stored in the transcode profile.

// 

//  Note: Setting the container type does not insert the required

//  Note: Setting the container type does not insert the required

//  MFT node in the transcode topology. The MFT node is based on the

//  MFT node in the transcode topology. The MFT node is based on the

//  stream settings stored in the transcode profile.

//  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

     &nbs磷;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP; );

            );

    }

    }

   

   

// 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;

}

推荐答案

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:

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.

-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.

-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 loo king 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.

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.

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)

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 =(.

Welcome to the road of chronic dissapointment =(.


这篇关于编码MP4文件的一个大问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆