2016-11-28 5 views
0

Моя цель - записать кадр, который я декодирую в файл. Я знаю, что я хорошо его понимаю, потому что это проявляется в моем воспроизведении SDL, и после этого я кодирую его без каких-либо проблем. Тем не менее кажется, что я не могу правильно записать фрейм в файл. Вот код:Невозможно записать YUV Frame из 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); 
} 

Я использовал неправильную рамку перед тем, как хорошо, как неправильные данные и размер.

+0

Это может привести к неправильным результатам; отдельные линии в плоскостях не гарантируют непрерывности, поэтому вы не можете записать их как единый блок данных. IIRC libavutil будет «размещать» выделенное изображение, чтобы каждая строка была выровнена до 32 байтов. Он будет работать на 1280x720, но может выйти из строя для разных разрешений (попробуйте видео с некоторыми «нечетными» размерами, такими как 258x142). –

0

Как я уже упоминал в комментарии, вам нужно проверить, успешно ли fopen.

Но я думаю, что проблема заключается в том, что вы пишете больше, чем то, что присутствует в буфере. Я знаю ограниченные знания о yuv. Я думаю, вы должны сделать следующее. Это основано на моем понимании от Single Frame 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 имеет линии 'height' шириной' width' для плоскости 0 и 'height'/2 строки для каждой ширины ширины/2 для плоскостей 1 и 2. Но расширение' .yuv' обычно означает формат изображения YUV444P ... И даже в YUV420P, вероятно, это была бы плоскостная, а не линейная чередование. –

+0

Вы имеете в виду, что для plane1 и plane2 для цикла от 0 до высоты/2 и сделать fwrite width/2 bytes? – MayurK

+0

Да точно. Самолеты 1 и 2 составляют половину размера плоскости 0 в каждом направлении. –

 Смежные вопросы

  • Нет связанных вопросов^_^