媒体基础框架:Intel 硬件 MFT 中 SPS/PPS 问题

6
我正在使用Intel硬件MFT将NV12帧编码为H264流,然后使用Live555通过RTP在局域网上传输已编码的帧,并在另一端设置ffplay以解码和显示相同的内容。使用软件编码器(SYNC或ASYNC软件MFT)时,设置可以正常工作,但是当使用Intel硬件MFT进行编码时,ffplay会抱怨SPS/PPS不可用,并且只显示混乱的屏幕。我已经发现,Intel硬件编码器在提供初始样本后触发MF_E_TRANSFORM_STREAM_CHANGE事件,并通过MF_MT_MPEG_SEQUENCE_HEADER提供SPS/PPS。我能够捕获MF_E_TRANSFORM_STREAM_CHANGE事件并获取序列头blob。

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

根据我的理解,并进一步查阅其他线程,SPS和PPS分别以00 00 00 01 67和00 00 00 01 68开头。但是,在我从Intel编码器接收到的blob中,我找不到这些序列。

https://github.com/cisco/openh264/issues/756 SPS起始标志: 00 00 00 01 67 PPS起始标志: 00 00 00 01 68

从英特尔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;
            }
        }
    }
}

enter image description here

1个回答

2
根据我的理解,并在其他帖子中进一步查找,SPS和PPS分别以00 00 00 01 67和00 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 Explanation
SPS nalu类型在起始码后的第一个字节的最后5位中定义为7(而不是67)。
PPS nalu类型分别在起始码后的第一个字节的最后5位中定义为8(而不是68)。
注意:起始码只能包含值为0 0 1的3个字节。

2
此信息可能会让一些人感到困惑,并且部分不正确。SPS是类型7,但只有5位而非4位。所以0x27是SPS,但是0x17不是。只有第一个四位数为偶数且以7结尾的才是SPS。PPS也是一样,只是以8结尾。 - szatmary

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接