2016-12-08 7 views
-1

Я пытаюсь декодировать поток H264 с помощью FFMPeg.Неисправность декодирования H264 Кадры с FFMpeg

У меня есть сохраненное видео и побежал в FFMpeg с помощью команды:

ffmpeg -i 20161201-090322.264 -pixel_format yuv420p -filter:v fps=fps=600/60 $filename%03d.raw 

И успешно получили кадры из видео. Затем я начал пытаться декодировать прямой поток (именно контент, который сохраняется в этих видео).

Я инициализация FFmpeg, как это:

cam->ffmpegCodec = avcodec_find_decoder(AV_CODEC_ID_H264); 
    cam->ffmpgContext = avcodec_alloc_context3(cam->ffmpegCodec); 
    cam->ffmpgContext->width = cam->Width; 
    cam->ffmpgContext->height = cam->Height; 
    cam->ffmpgContext->pix_fmt = AV_PIX_FMT_YUV420P; 

    cam->ffmpegFrame = av_frame_alloc(); 
    cam->ffmpegParser = av_parser_init(AV_CODEC_ID_H264); 

    if(!cam->ffmpegParser) 
    { 
     sprintf(msg, "Error, initializing parser"); 
     libLogCtx(msg, MODULE_NAME, PLogFileRelease, true); 
    } 

    int res = avcodec_open2(cam->ffmpgContext, cam->ffmpegCodec, 0); 
    if(res != 0) 
    { 
     sprintf(msg, "Error, openning codec [%d]", res); 
     libLogCtx(msg, MODULE_NAME, PLogFileRelease, true); 
    } 

В то время как это мои объявления внутри конструкция распредвала:

AVCodecContext *ffmpgContext; 
AVCodec   *ffmpegCodec; 
AVFrame   *ffmpegFrame; 
AVCodecParserContext *ffmpegParser; 

Когда я получаю содержание потока, я сделать следующие шаги:

/// Copy the received data to buffer 
memcpy(cam->imageBuffer + cam->imageBufferSz, pBuffer, dwBufSize); 
cam->imageBufferSz += dwBufSize; 

/// If there's some data, 
if(cam->imageBufferSz > 0) 
{ 
    /// Try to parse 
    uint8_t* data = NULL; 
    int size = 0; 
    int len = av_parser_parse2(cam->ffmpegParser, cam->ffmpgContext, &data, &size, 
     cam->imageBuffer, cam->imageBufferSz, 0, 0, AV_NOPTS_VALUE); 

    if(size > 0 && len >= 0) 
    { 
     /// Fill the packet and decode 
     AVPacket pkt; 
     av_init_packet(&pkt); 
     pkt.data = cam->imageBuffer; 
     pkt.size = cam->imageBufferSz; 
     int frameFinished = 0; 

     int nres = avcodec_decode_video2(cam->ffmpgContext, cam->ffmpegFrame, &frameFinished, &pkt); 
     /// If decoding was successfully, Save only the Y to file (i'm just testing). 
     if(frameFinished) 
     { 
      char fnm[255]; 
      sprintf(fnm, "C:\\Users\\Black_Spiders\\Desktop\\Rls\\test%d.raw", n); 
      n++; 
      FILE* f = (FILE*)fopen(fnm, "w"); 

      for (int y = 0; y < cam->ffmpegFrame->height; y++) 
      { 
       fwrite(cam->ffmpegFrame->data[0] + y*cam->ffmpegFrame->linesize[0], 1, cam->ffmpegFrame->width, f); 
      } 

      fclose(f); 
     } 
    } 


} 

Несмотря на то, что мой код выглядит довольно хорошо (время, оставшееся некоторое время в Интернете), я ха Винг этот результат:

Original

Result

Может кто-нибудь дать мне какой-нибудь совет?

С наилучшими пожеланиями,

+0

Я не знаю правильного использования API-анализатора парсера, но ваш кажется неправильным. Разве вы не должны каким-то образом использовать 'len' и' data' и 'size'? И должен быть цикл вокруг 'av_parser_parse2' вызова/потребления. –

+0

@AndreyTurkin Это обратный вызов, вызываемый DVR, с которым я работаю. Вот почему av_parser_parse2 не находится в цикле (он вызывается каждый раз, когда у DVR есть данные). Что касается использования len, данных и размера, я не испытываю h264 и ffmpeg, и я попытался следовать этому руководству: [link] (http://roxlu.com/2014/039/decoding-h264-and- yuv420p-воспроизведение). Кстати, этот учебник использует этот метод, кажется, что цель состоит в том, чтобы проверить, достаточно ли данных для использования avcodec_decode_video2. Я пытался использовать 'len' как мой размер pkt, но все тот же результат. –

ответ

0

Вот пример кода прямо из FFmpeg документации:

while(in_len) { 
    len = av_parser_parse2(myparser, AVCodecContext, &data, &size, 
           in_data, in_len, 
           pts, dts, pos); 
    in_data += len; 
    in_len -= len; 
    if(size) 
     decode_frame(data, size); 
} 

Таким образом, идея заключается в том, чтобы вызвать эту функцию, и она будет возвращать:

1) указатель и размер кодированного кадра для передачи в декодер; обратите внимание на использование размера в указанном вами примере (но они не использовали указатель, который является неправильным, им повезло из-за природы потока H264 и их использования в буфере)

2) длина обрабатываемой части вход. Ввод может содержать, вероятно, несколько кадров или неполные части кадров. Вы должны снова вызвать эту функцию с остальной частью ввода (и снова и снова, пока весь блок данных не будет разобран). Если вы внимательно проверите свой пример, вы увидите, что он делает это, а ваш код - нет.

Также вам, вероятно, не нужно буферизовать входящие данные, потому что парсер должен буферизовать неполные кадры внутри.

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

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