首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用媒体基础从h.264字节流创建MP4容器(附录B)?

使用媒体基础从h.264字节流创建MP4容器(附录B)?
EN

Stack Overflow用户
提问于 2014-02-27 10:12:31
回答 2查看 3.8K关注 0票数 3

基本上,我有一个整洁的H.264字节流,它以I和P样本的形式存在。我可以使用MediaStreamSource和MediaElement播放这些示例,它们播放得很好。我还需要将它们保存为MP4文件,以便稍后可以使用媒体元素或VLC播放相同的内容。这就是我尝试的方法,使用Media Foundation;我从MFCreateMPEG4MediaSink创建一个IMFMediaSink;这是我的代码:

代码语言:javascript
复制
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;这是我的代码:

代码语言:javascript
复制
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;

代码语言:javascript
复制
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无法创建有效的输出文件,因为所需的头没有提供给sink“。它确实创建了一个大小非常有效的MP4文件(对于我的1k示例,大小为4.6MB)。如果它要求MF_MT_MPEG_SEQUENCE_HEADER,那么我用IMFMediaType::SetBlob(MF_MT_MPEG_SEQUENCE_HEADER,This is the link to the trace from MFTrace.,UINT32设置它们)我用Elecard视频格式分析器检查了文件,但标题似乎不完整。我是否可以得到一些帮助,找出我遗漏了什么,或者是否有更好的/其他方法来实现我想要实现的目标?谢谢!

EN

回答 2

Stack Overflow用户

发布于 2014-04-28 17:14:49

对我来说,问题在于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

票数 4
EN

Stack Overflow用户

发布于 2014-07-17 11:09:51

不确定,但是,不应该是:

代码语言:javascript
复制
hr = pMediaType->SetGUID(MF_MT_SUBTYPE, VIDEO_ENCODING_FORMAT);

而不是:

代码语言:javascript
复制
hr = pMediaType->SetGUID(MF_MT_SUBTYPE, VIDEO_INPUT_FORMAT);
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/22057696

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档