2016-07-25 13 views
1

私は、in2のストリームからフレームを保存する小さなアプリケーションを作成しようとしています。 私は、例としてtestRTSP programmをとり、DummySink::afterGettingFrame関数をいくつか変更して、ffmpegライブラリの助けを借りてフレームをデコードしました。 私がframeSizeから理解しているように、最初の2つのフレームはSPSユニットなので、3番目のフレームと連結してから、新しい大きなフレームをffmpegデコーダに送ります。しかし、それは動作しません。 ffmpegは、私の最初のフレームがSPSにとって大きすぎることを教えてくれますし、フレームがないことを私に伝えています...私はここで何を変更する必要があるのか​​分かりません。LIVE555 ffmpeg用のnalユニットを得るためのh264フレーマークラスの使い方

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(); 

答えて

2

私の問題の解決策が見つかりました。

live555の "testRTSP"の例には、void DummySink::afterGettingFrame(...)の機能があります。

[start_code sps pps start_code frame_data]

frame_dataは、この時点でfReceiveBufferです: は私がする必要があるたすべての機能がフレームを得たときに組み立て私のフレーム毎回です。 start_codeはchar配列[0,0,0,1]です。

とffmpegのデコーダに新しいデータをプッシュ:decoderContextため

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を使用して、1つの大きな配列のデータを結合しました。 memcpy(frameBuf、startCode、4); frameBufSize + = 4;私が見つけたいくつかの時間後に

:あなたはUPDATE 1

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

(詳細な例または "H264orH264FileSink.h" のための "openRTSP" をご確認ください)サブセッションからSPSとPPSのデータを取得することができます

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; 

ffmpegへの私のアプローチの誤り。場合によっては、fsmpegデコーダは、spsとpps単位でエクストラデータ情報を供給しないとH264ストリームで動作しません。したがって、あなたは毎回spsとppsデータをフレームに供給する必要はなく、開始コードだけが必要です。

0

コードにはコーデックの初期化方法は表示されませんが、SPSとPPSはパケットに入れないでください。代わりに、初期化時にAVCodecContextextradataフィールドを介してコーデックに渡す必要があります。そして、デコードされた画像を得るために、実際のフレームNALをデコーダに渡すだけです。

IDは、DESCRIBEに応答して、最初のSPSの受信時にデコーダを初期化するか、SDPデータからイベントを初期化することを提案しています。

+0

SPSおよびPPSのデータは、50および4バイトサイズですか?多分これは私の最初の2つの "フレーム"ですか?そして、私は「エクストラデータ」で2つの異なる変数をどのように参照できますか? – Aleksey

+0

spsとppsのサイズは固定されていないので、削除された答えではサイズに基づいて何も仮定することはできません。実際のNALタイプ(NALユニットの最初のバイトの右端5ビット)を確認する必要があります。'extradata'については、私のメモリが正しい場合は、すでに使用している接頭辞コードで区切られた単一のバッファにそれらを渡し、それに応じて' extradata_size'を設定します。 Btw、ffmpegでストリームをデコードするには、RTSP処理にもffmpeg(avio_open)を使用してください。それで、あなたはこれを気にする必要はなく、すべては内部的に行われます。 –

関連する問題