媒体基金会:英特尔硬件MFT的SPS / PPS问题

Ram*_*san 5 rtp video-streaming mft live555 ms-media-foundation

我使用Intel硬件MFT将NV12帧编码为H264流,并使用Live555通过LAN上的RTP通过流传输编码的帧,并在另一端进行ffplay设置以解码和显示它们。该设置可以与软件编码器(SYNC或ASYNC软件MFT)配合使用,但是ffplay抱怨当在Intel硬件MFT中完成编码时,SPS / PPS不可用,并且仅显示一个乱码。我发现英特尔硬件编码器在馈入初始样本并通过MF_MT_MPEG_SEQUENCE_HEADER使SPS / PPS可用之后触发MF_E_TRANSFORM_STREAM_CHANGE事件。我能够捕获该MF_E_TRANSFORM_STREAM_CHANGE事件并获取序列标头blob。

问题是,Live555需要分别设置SPS和PPS。但是,我对于从MF_MT_MPEG_SEQUENCE_HEADER blob中提取SPS和PPS感到非常困惑。

根据我的理解以及在其他线程中的进一步查找,SPS和PPS分别以00 00 00 01 67和0 00 00 01 68开头。但是,我在从英特尔编码器收到的Blob中找不到任何序列。

https://github.com/cisco/openh264/issues/756 SPS的开始:00 00 00 01 67 PPS的开始:00 00 00 01 68

从intel MFT获得的序列头

序列头大小50

冒号头:0 0 1 27 64 0 28 ac 2b 40 3c 1 13 f2 e0 22 0 0 3 0 2 0 0 3 0 79 d0 80 f 42 0 3 d0 93 7b df 7 68 70 ca 80 0 0 0 1 28 ee 3c b0 0

vector<byte> sequenceHeaderData;
UINT32 sequenceHeaderDataSize = 0;

MFT_OUTPUT_DATA_BUFFER _outputDataBuffer;
memset(&_outputDataBuffer, 0, sizeof _outputDataBuffer);
_outputDataBuffer.dwStreamID = outputStreamID;
_outputDataBuffer.dwStatus = 0;
_outputDataBuffer.pEvents = nullptr;
_outputDataBuffer.pSample = nullptr;

HRESULT mftProcessOutput = _pEncoder->ProcessOutput(0, 1, &_outputDataBuffer, &processOutputStatus);

if (MF_E_TRANSFORM_STREAM_CHANGE == mftProcessOutput) 
{
    // some encoders want to renegotiate the output format. 
    if (_outputDataBuffer.dwStatus & MFT_OUTPUT_DATA_BUFFER_FORMAT_CHANGE)
    {
        CComPtr<IMFMediaType> pNewOutputMediaType = nullptr;
        HRESULT res = _pEncoder->GetOutputAvailableType(outputStreamID, 1, &pNewOutputMediaType);

        res = _pEncoder->SetOutputType(outputStreamID, pNewOutputMediaType, 0);//setting the type again
        CHECK_HR(res, "Failed to set output type during stream change");

        {
            CComPtr<IMFMediaType> pCurOutputMediaType = nullptr;
            HRESULT res = _pEncoder->GetOutputAvailableType(outputStreamID, 1, &pCurOutputMediaType);

            res = pCurOutputMediaType->GetBlobSize(MF_MT_MPEG_SEQUENCE_HEADER, &sequenceHeaderDataSize);

            if (SUCCEEDED(res) && sequenceHeaderDataSize > 0) 
            {
                sequenceHeaderData.resize(sequenceHeaderDataSize);

                pCurOutputMediaType->GetBlob(MF_MT_MPEG_SEQUENCE_HEADER, sequenceHeaderData.data(), sequenceHeaderDataSize, NULL);

                cout << "Sequence header size " << sequenceHeaderDataSize << std::endl;
            }
            else 
            {
                cout << "Sequence header is not available" << std::endl;
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

在此处输入图片说明

VuV*_*irt 2

根据我的理解,并在其他线程中进一步查找,SPS和PPS分别以00 00 00 01 67和0 00 00 01 68开头。

你假设错了。

从您的示例标题:

这是SPS:0 0 1 27 64 0 28 ac 2b 40 3c 1 13 f2 e0 22 0 0 3 0 2 0 0 3 0 79 d0 80 f 42 0 3 d0 93 7b df 7 68 70 ca 80

这是 PPS:0 0 0 1 28 ee 3c b0 0

解释

SPS nalu类型被定义为第一个字节的最后5位中的7,在起始码之后。(不是 67)。

PPS nalu 类型在第一个字节的最后 5 位(起始码之后)分别为 8(不是 68)。

注意:起始码只能包含 3 个字节,值分别为:0 0 1。

  • 此信息可能会让某些人感到困惑,并且部分不正确。SPS 是类型 7,但是 5 位,而不是 4 位。因此 0x27 是 SPS,但 0x17 不是。只有第一个半字节中的偶数为 7 才是 SPS。PPS 也是如此,只不过是 8。 (2认同)