2016-11-28 30 views
0

私の目標は、ファイルにデコードするフレームを書き込むことです。私はそれが私のSDLの再生に表示されるので、私はそれをキャプチャすることを知っていると私は後で何の問題もなくそれをエンコードします。しかし、私はフレームに正しくファイルを書き込むことができないようだ。コードは次のとおりです。YUVフレームをffmpegから.yuvファイルに書き込めません

#define PIXFMT AV_PIX_FMT_YUV420P 
#define WIDTH 1280 
#define HEIGHT 720 
// initialize SWS context for software scaling 

sws_ctx = sws_getContext(pCodecCtx->width, 
    pCodecCtx->height, 
    pCodecCtx->pix_fmt, 
    WIDTH, 
    HEIGHT, 
    PIXFMT, 
    SWS_LANCZOS, 
    NULL, 
    NULL, 
    NULL 
); 

FfmpegEncoder enc("rtsp://127.0.0.1:1935/live/myStream", pParser); 
//SetPixelArray(); 

i = 0; 
enc.FillYuvImage(pFrameRGB, 0, this->pCodecCtx->width, this->pCodecCtx->height); 
FILE *pFile; 
while (av_read_frame(pFormatCtx, &packet) >= 0 && !exit) { 
    if (packet.stream_index == videoindex) { 
     // Decode video frame 
     avcodec_decode_video2(pCodecCtx, pFrame, &frameFinished, &packet); 

     if (frameFinished) { 

      i++; 
      sws_scale(sws_ctx, (uint8_t const * const *)pFrame->data, pFrame->linesize, 0, pCodecCtx->height, pFrameRGB->data, pFrameRGB->linesize); 
      if (i < 500) 
      { 
       pFile = fopen(std::string("./screenshots/screen.yuv").c_str(), "a+"); 
       for (int y = 0; y < pCodecCtx->height; y++) 
       { 
        fwrite(pFrame->data[0] + y * pFrame->linesize[0], 1, pCodecCtx->width * pCodecCtx->height, pFile); 
        fwrite(pFrame->data[1] + y * pFrame->linesize[1], 1, pCodecCtx->width * pCodecCtx->height/4, pFile); 
        fwrite(pFrame->data[2] + y * pFrame->linesize[2], 1, pCodecCtx->width * pCodecCtx->height/4, pFile); 
       } 
       fclose(pFile); 
      } 
      enc.encodeFrame(pFrameRGB); 
     } 
    } 
    // Free the packet that was allocated by av_read_frame 
    av_free_packet(&packet); 
} 

フレームを書き込もうとするとプログラムがクラッシュします。

+0

fopenが正常に実行されているかどうかを確認します。 – MayurK

答えて

0

まず、あなたのコメントと回答ありがとう!

while (av_read_frame(pFormatCtx, &packet) >= 0 && !exit && i < 1000) { 
    if (packet.stream_index == videoindex) { 
     // Decode video frame 
     avcodec_decode_video2(pCodecCtx, pFrame, &frameFinished, &packet); 

     if (frameFinished) { 

      i++; 
      sws_scale(sws_ctx, (uint8_t const * const *)pFrame->data, pFrame->linesize, 0, pCodecCtx->height, pFrameRGB->data, pFrameRGB->linesize); 
      if ((pFile = fopen(std::string("./screenshots/screen.yuv").c_str(), "ab")) == NULL) 
       continue; 
      fwrite(pFrameRGB->data[0], 1, pCodecCtx->width * pCodecCtx->height, pFile); 
      fwrite(pFrameRGB->data[1], 1, pCodecCtx->width * pCodecCtx->height/4, pFile); 
      fwrite(pFrameRGB->data[2], 1, pCodecCtx->width * pCodecCtx->height/4, pFile); 
      fclose(pFile); 
      enc.encodeFrame(pFrameRGB); 
     } 
    } 
    // Free the packet that was allocated by av_read_frame 
    av_free_packet(&packet); 
} 

私は前に間違ったフレームを使用していた、aswellとして間違ったデータとサイズ: は、ここに固定されたコードです。

+0

これは間違った結果を生む可能性があります。プレーン内の個々の行は連続していることが保証されていないため、それらを単一のデータブロックとして書き込むことはできません。 IIRC libavutilは、各行が32バイトに整列するように、割り当てられたピクチャを「パッド」します。 1280x720でも動作しますが、解像度が異なると失敗する可能性があります(258x142などの「奇妙な」サイズのビデオを試してみてください)。 –

0

コメントに記載されているとおり、fopenが正常に実行されているかどうかを確認する必要があります。

しかし、私はあなたがバッファに存在するものよりも多くを書いていると思います。私はyuvに関する知識を知っています。私はあなたが次のことをするべきだと思います。これは、シングルフレームYUV420画像からの私の理解に基づいて、this pageの画像に基づいています。

abcfor (int y = 0; y < pCodecCtx->height; y++) //plane 0: same width and height 
{ 
    fwrite(pFrame->data[0] + y * pFrame->linesize[0], 1, pCodecCtx->width, pFile); 
} 


for (int y = 0; y < pCodecCtx->height/4; y++) //plane1: Same width and quarter height. 
{ 
    fwrite(pFrame->data[1] + y * pFrame->linesize[1], 1, pCodecCtx->width, pFile); 
} 

for (int y = 0; y < pCodecCtx->height/4; y++) //plane2: Same width and quarter height. 
{ 
    fwrite(pFrame->data[2] + y * pFrame->linesize[2], 1, pCodecCtx->width, pFile); 
} 

注意書きの順序は、カラーフォーマットによって異なります。ループ反復回数と各反復でのfwrite()のバイト数に注目してください。

+1

YUV420Pは、平面0に対してはそれぞれ '幅'幅を有し、平面1および2に対しては '幅' /幅2の幅を有する '高さ'ラインを有する。しかし、 '.yuv'拡張は、通常、YUV444Pピクセルフォーマットを意味する... YUV420Pであっても、おそらくプレーナであり、ラインインターリーブされた彩度ではありません。 –

+0

あなたが意味するのは、plane1とplane2の場合、forループは0から高さ/ 2までで、fwrite幅/ 2バイトですか? – MayurK

+0

はい。平面1と平面2は、各方向の平面0のサイズの半分です。 –

関連する問題