簡體   English   中英

LIVE555如何使用h264成幀器類獲取ffmpeg的最終單位

[英]LIVE555 how to use h264 framer class to get nal units for ffmpeg

我正在嘗試創建一個小型應用程序,該程序將保存不受h264流影響的幀。 我以一個testRTSP程序為例,在DummySink::afterGettingFrame函數中進行了幾處更改,以借助ffmpeg庫對幀進行解碼。 從frameSize可以理解,我的前兩個幀是SPS單元,因此我將它們與第三個幀連接在一起,然后將新的大幀發送到ffmpeg解碼器。 但這不起作用。 ffmpeg告訴我我的第一幀對於SPS太大,然后告訴我沒有幀...我不知道我需要在這里更改什么。

void DummySink::afterGettingFrame(unsigned frameSize, unsigned numTruncatedBytes,
struct timeval presentationTime, unsigned /*durationInMicroseconds*/)
{
u_int8_t start_code[4] = { 0x00, 0x00, 0x00, 0x01 };
int stCodeLen = 4;

if (frameSize == 50)
{
    //add start code
    memcpy(bufferWithStartCode, start_code, stCodeLen);
    shiftPtr += stCodeLen;
    memcpy(bufferWithStartCode + shiftPtr, fReceiveBuffer, frameSize);
    shiftPtr += frameSize;
}
else if (frameSize == 4)
{
    memcpy(bufferWithStartCode + shiftPtr, fReceiveBuffer, frameSize);
    shiftPtr += frameSize;
}
else
{
    if (shiftPtr == 0)
    {
        memcpy(bufferWithStartCode, start_code, stCodeLen);
        shiftPtr += stCodeLen;
    }
    memcpy(bufferWithStartCode + shiftPtr, fReceiveBuffer, frameSize);
    avpkt.size = frameSize + shiftPtr;
    avpkt.data = bufferWithStartCode;
    shiftPtr = 0;
    if (!avcodec_send_packet(cContext, &avpkt))
    {
        envir() << "error sending to decoder";

    }
    if (!avcodec_receive_frame(cContext, picture))
    {
        envir() << "error rx from decoder";
    }
    if (picture)
    {
        FILE *f;
        char buffer[32]; // The filename buffer.
        snprintf(buffer, sizeof(char) * 32, "file%i.txt", frame_num);
        f = fopen(buffer, "w");
        fprintf(f, "P5\n%d %d\n%d\n", fSubsession.videoWidth(), fSubsession.videoHeight(), 255);
        for (int i = 0;i < fSubsession.videoHeight();i++)
            fwrite(picture->data[0] + i * (picture->linesize[0]), 1, fSubsession.videoWidth(), f);
        fclose(f);
    }
}

envir() << frameSize << "\n";


frame_num++;

// Then continue, to request the next frame of data:
continuePlaying();

我已經找到解決問題的方法。

void DummySink::afterGettingFrame(...) “ testRTSP”示例中有函數void DummySink::afterGettingFrame(...) 我需要做的就是每次函數獲得框架時都組裝框架:

[start_code sps pps start_code frame_data]

此時frame_data是fReceiveBuffer start_code是char數組[0,0,0,1]。

並將新數據推送到ffmpeg解碼器:

m_packet.size = frameBufSize + frameSize; // size of assembled frame
m_packet.data = frameBuf; // assembled frame

if (avcodec_send_packet(m_decoderContext, &m_packet) != 0)
{
    envir() << "error in sending packet to decoder" << "\n";
}
if (avcodec_receive_frame(m_decoderContext, pFrame) == 0)

沒有額外的解碼器設置設置! 只需像教程中一樣初始化所有內容( http://dranger.com/ffmpeg/-這是ffmpeg c ++庫的最新教程),就可以了。 我使用memcpy將數據memcpy為一個大數組。 memcpy(frameBuf,startCode,4); frameBufSize + = 4;

for (int i = 0; i < numSPropRecords; i++)
{
    memcpy(frameBuf + frameBufSize, sPropRecords[i].sPropBytes, sPropRecords[i].sPropLength);
    frameBufSize += sPropRecords[i].sPropLength;
}

memcpy(frameBuf + frameBufSize, startCode, 4);
frameBufSize += 4;
memcpy(frameBuf + frameBufSize, fReceiveBuffer, frameSize);

m_packet.size = frameBufSize + frameSize;
m_packet.data = frameBuf;

您可以從子會話中獲取sps和pps數據(查看“ openRTSP”以獲取詳細示例或“ H264orH264FileSink.h”)

spsppsunits = subsession.fmtp_spropparametersets();
sPropRecords = parseSPropParameterSets(spsppsunits, numSPropRecords);

更新1:

一段時間后,我發現使用ffmpeg的方法出錯。 如果您不提供帶有sps和pps單位的額外數據信息,則ffmpeg解碼器有時無法與H264流一起使用。 所以,

m_decoderContext->extradata =  (uint8_t*)av_malloc(100 + AV_INPUT_BUFFER_PADDING_SIZE);
int extraDataSize = 0;
for (int i = 0; i < numSPropRecords; i++)
{
    memcpy(m_decoderContext->extradata + extraDataSize, startCode, 4);
    extraDataSize += 4;
    memcpy(m_decoderContext->extradata + extraDataSize, sPropRecords[i].sPropBytes, sPropRecords[i].sPropLength);
    extraDataSize += sPropRecords[i].sPropLength;
}
m_decoderContext->extradata_size = extraDataSize;

之后,您不需要每次都向框架提供sps和pps數據,只需要起始代碼。

您的代碼未顯示如何初始化編解碼器,但SPS和PPS不應進入數據包。 相反,他們應該通過傳遞給編解碼器extradata的領域AVCodecContext在初始化。 然后,您只需將實際幀NAL傳遞給解碼器即可獲得解碼圖片。

建議您在接收到第一個SPS時初始化解碼器,或者響應DESCRIBE從SDP數據中獲取事件。

暫無
暫無

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

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