簡體   English   中英

使用媒體基礎從h.264字節流創建MP4容器(附件B)?

[英]Creating an MP4 container from an h.264 byte stream (Annex B), using media foundation?

基本上,我有一個簡潔的H.264字節流,形式為I和P樣本。 我可以使用MediaStreamSource和MediaElement播放這些樣本,它們可以很好地播放。 我還需要將它們保存為MP4文件,以便以后可以使用Media Element或VLC播放。 這就是我嘗試使用Media Foundation的方式; 我從MFCreateMPEG4MediaSink創建了一個IMFMediaSink; 這是我的代碼:

IMFMediaType *pMediaType = NULL;
IMFByteStream *pByteStream = NULL;
HRESULT hr = S_OK;
if (SUCCEEDED(hr))
{
    hr = MFCreateMediaType(&pMediaType);
}

pSeqHdr = reinterpret_cast<UINT8 *>(mSamplesQueue.SequenceHeader());
if (SUCCEEDED(hr))
{
    hr = pMediaType->SetBlob(MF_MT_MPEG_SEQUENCE_HEADER, pSeqHdr, 35);
}
UINT32 pcbBlobSize = {0};
hr = pMediaType->GetBlobSize(MF_MT_MPEG_SEQUENCE_HEADER, &pcbBlobSize);

/*if (SUCCEEDED(hr))
{
    hr = pMediaType->SetUINT32(MF_MPEG4SINK_SPSPPS_PASSTHROUGH, TRUE);
}*/
if (SUCCEEDED(hr))
{
    hr = pMediaType->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Video);
}
if (SUCCEEDED(hr))
{
    hr = pMediaType->SetGUID(MF_MT_SUBTYPE, VIDEO_INPUT_FORMAT);
}
if (SUCCEEDED(hr))
{
    hr = MFSetAttributeRatio(pMediaType, MF_MT_FRAME_RATE, VIDEO_FPS, 1);
}
if (SUCCEEDED(hr))
{
    hr = pMediaType->SetUINT32(MF_MT_AVG_BITRATE, VIDEO_BIT_RATE);
}
if (SUCCEEDED(hr))
{
    hr = pMediaType->SetUINT32(MF_MT_INTERLACE_MODE, MFVideoInterlace_Progressive);
}
if (SUCCEEDED(hr))
{
    hr = MFSetAttributeSize(pMediaType, MF_MT_FRAME_SIZE, VIDEO_WIDTH, VIDEO_HEIGHT);
}
if (SUCCEEDED(hr))
{
    // Pixel aspect ratio
    hr = MFSetAttributeRatio(pMediaType, MF_MT_PIXEL_ASPECT_RATIO, 1, 1);
}
if (SUCCEEDED(hr))
{
    hr = MFCreateFile(
        MF_ACCESSMODE_READWRITE,
        MF_OPENMODE_DELETE_IF_EXIST,
        MF_FILEFLAGS_NONE,
        L"output1.mp4",
        &pByteStream);
}
if (SUCCEEDED(hr))
{
    hr = MFCreateMPEG4MediaSink(
        pByteStream,
        pMediaType,
        NULL,
        &pMediaSink);
}

然后我使用MFCreateSinkWriterFromMediaSink從這個媒體接收器創建一個IMFSinkWriter; 這是我的代碼:

if (SUCCEEDED(hr))
{
    hr = MFCreateSinkWriterFromMediaSink(pMediaSink, NULL, &pSinkWriter);
}
// Tell the sink writer to start accepting data.
if (SUCCEEDED(hr))
{
    hr = pSinkWriter->BeginWriting();
}

if (SUCCEEDED(hr))
{
    pSinkWriter->AddRef();
}

然后我用IMFSinkWriter :: WriteSample(0,IMFSample)將每個樣本寫入接收器編寫器; 這是我的代碼:IMFSample * pSample = NULL; IMFMediaBuffer * pBuffer = NULL;

const DWORD cbBuffer = mSamplesQueue.GetNextSampleSize();
UINT32 isIDR = mSamplesQueue.GetNextSampleIsIDR();
BYTE *pData = NULL;

// Create a new memory buffer.
HRESULT hr = MFCreateMemoryBuffer(cbBuffer, &pBuffer);

// Lock the buffer and copy the video frame to the buffer.
if (SUCCEEDED(hr))
{
    DWORD buffLen = cbBuffer;
    hr = pBuffer->Lock(&pData, &buffLen, 0);
}
if (SUCCEEDED(hr))
{
    hr = mSamplesQueue.Dequeu(&pData);
}
if (pBuffer)
{
    pBuffer->Unlock();
}

// Set the data length of the buffer.
if (SUCCEEDED(hr))
{
    hr = pBuffer->SetCurrentLength(cbBuffer);
}

// Create a media sample and add the buffer to the sample.
if (SUCCEEDED(hr))
{
    hr = MFCreateSample(&pSample);
}
if (SUCCEEDED(hr))
{
    hr = pSample->AddBuffer(pBuffer);
}

// Set the time stamp and the duration.
if (SUCCEEDED(hr))
{
    hr = pSample->SetSampleTime(rtStart);
}
if (SUCCEEDED(hr))
{
    hr = pSample->SetSampleDuration(rtDuration);
}
if (SUCCEEDED(hr))
{
    hr = pSample->SetUINT32(MFSampleExtension_CleanPoint, isIDR);
}
//pSample->
// Send the sample to the Sink Writer.
if (SUCCEEDED(hr))
{
    hr = pSinkWriter->WriteSample(0, pSample);
}

SafeRelease(&pSample);
SafeRelease(&pBuffer);

樣本的編寫是一個迭代代碼,從我擁有的每個樣本調用(我用1k I和P樣本進行測試)。 現在,當我調用IMFSinkWriter :: Finalize()時,它告訴我“0xc00d4a45:Sink無法創建有效的輸出文件,因為未向接收器提供所需的標頭。”。 它確實創建了一個非常有效的MP4文件(對於我的1k樣本,4.6 MB)。 這是來自MFTrace的跟蹤鏈接。 如果它要求MF_MT_MPEG_SEQUENCE_HEADER然后我用IMFMediaType :: SetBlob(MF_MT_MPEG_SEQUENCE_HEADER,BYTE [],UINT32)設置它們我用Elecard視頻格式分析器檢查了文件並且標題似乎不完整。 我可以幫助找出我缺少的東西,或者是否有更好的/其他方式來做我想要實現的目標? 謝謝!

對我來說問題是MF_MT_MPEG_SEQUENCE_HEADER blob的格式。

與dwSequenceHeader和H.264上的MSDN文檔相反,SPS和PPS應該加上起始碼(0x00,0x00,0x01)而不是2字節長度字段。

http://msdn.microsoft.com/en-us/library/dd757808%28VS.85%29.aspx

不確定,但不應該:

hr = pMediaType->SetGUID(MF_MT_SUBTYPE, VIDEO_ENCODING_FORMAT);

而不是:

hr = pMediaType->SetGUID(MF_MT_SUBTYPE, VIDEO_INPUT_FORMAT);

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM