2011-08-21 159 views
3

使用libav保存視頻中的幀。libav *錯誤解碼

問題是,如果您調用函數解碼幾次,然後第二,然後不正確處理。

第1次這樣的結論(一切工作正常):

[swscaler @ 0x8b48510]No accelerated colorspace conversion found from yuv420p to bgra. 
good 

2日(找不到流,但這些是相同的):

[mp3 @ 0x8ae5800]Header missing 
Last message repeated 223 times 
[mp3 @ 0x8af31c0]Could not find codec parameters (Audio: mp1, 0 channels, s16) 
[mp3 @ 0x8af31c0]Estimating duration from bitrate, this may be inaccurate 
av_find_stream_info 

你能告訴哪裏出錯發生。

的main.cpp

avcodec_init(); 
avcodec_register_all(); 
av_register_all(); 
char *data; 
int size; 
//fill data and size 
... 
decode(data, size); 
decode(data, size); 

video.cpp

int f_offset = 0; 
int f_length = 0; 
char *f_data = 0; 

int64_t seekp(void *opaque, int64_t offset, int whence) 
{ 
    switch (whence) 
    { 
    case SEEK_SET: 
     if (offset > f_length || offset < 0) 
      return -1; 
     f_offset = offset; 
     return f_offset; 
    case SEEK_CUR: 
     if (f_offset + offset > f_length || f_offset + offset < 0) 
      return -1; 
     f_offset += offset; 
     return f_offset; 
    case SEEK_END: 
     if (offset > 0 || f_length + offset < 0) 
      return -1; 
     f_offset = f_length + offset; 
     return f_offset; 
    case AVSEEK_SIZE: 
     return f_length; 
    } 

    return -1; 
} 
int readp(void *opaque, uint8_t *buf, int buf_size) 
{ 
    if (f_offset == f_length) 
     return 0; 

    int length = buf_size <= (f_length - f_offset) ? buf_size : (f_length - f_offset); 

    memcpy(buf, f_data + f_offset, length); 
    f_offset += length; 

    return length; 
} 

bool decode(char *data, int length) 
{ 
    f_offset = 0; 
    f_length = length; 
    f_data = data; 

    int buffer_read_size = FF_MIN_BUFFER_SIZE; 
    uchar *buffer_read = (uchar *) av_mallocz(buffer_read_size + FF_INPUT_BUFFER_PADDING_SIZE); 

    AVProbeData pd; 
    pd.filename = ""; 
    pd.buf_size = 4096 < f_length ? 4096 : f_length; 
    pd.buf = (uchar *) av_mallocz(pd.buf_size + AVPROBE_PADDING_SIZE); 
    memcpy(pd.buf, f_data, pd.buf_size); 

    AVInputFormat *pAVInputFormat = av_probe_input_format(&pd, 1); 
    if (pAVInputFormat == NULL) 
    { 
     std::cerr << "AVIF"; 
     return false; 
    } 
    pAVInputFormat->flags |= AVFMT_NOFILE; 

    ByteIOContext ByteIOCtx; 
    if (init_put_byte(&ByteIOCtx, buffer_read, buffer_read_size, 0, NULL, readp, NULL, seekp) < 0) 
    { 
     std::cerr << "init_put_byte"; 
     return false; 
    } 

    AVFormatContext *pFormatCtx; 
    if (av_open_input_stream(&pFormatCtx, &ByteIOCtx, "", pAVInputFormat, NULL) < 0) 
    { 
     std::cerr << "av_open_stream"; 
     return false; 
    } 

    if (av_find_stream_info(pFormatCtx) < 0) 
    { 
     std::cerr << "av_find_stream_info"; 
     return false; 
    } 

    int video_stream; 
    video_stream = -1; 
    for (uint i = 0; i < pFormatCtx->nb_streams; ++i) 
     if (pFormatCtx->streams[i]->codec->codec_type == CODEC_TYPE_VIDEO) 
     { 
      video_stream = i; 
      break; 
     } 
    if (video_stream == -1) 
    { 
     std::cerr << "video_stream == -1"; 
     return false; 
    } 

    AVCodecContext *pCodecCtx; 
    pCodecCtx = pFormatCtx->streams[video_stream]->codec; 

    AVCodec *pCodec; 
    pCodec = avcodec_find_decoder(pCodecCtx->codec_id); 
    if (pCodec == NULL) 
    { 
     std::cerr << "pCodec == NULL"; 
     return false; 
    } 

    if (avcodec_open(pCodecCtx, pCodec) < 0) 
    { 
     std::cerr << "avcodec_open"; 
     return false; 
    } 

    AVFrame *pFrame; 
    pFrame = avcodec_alloc_frame(); 
    if (pFrame == NULL) 
    { 
     std::cerr << "pFrame == NULL"; 
     return false; 
    } 
    AVFrame *pFrameRGB; 
    pFrameRGB = avcodec_alloc_frame(); 
    if (pFrameRGB == NULL) 
    { 
     std::cerr << "pFrameRGB == NULL"; 
     return false; 
    } 

    int numBytes; 
    numBytes = avpicture_get_size(PIX_FMT_RGB32, pCodecCtx->width, pCodecCtx->height); 
    uint8_t *buffer; 
    buffer = (uint8_t *) av_malloc(numBytes * sizeof(uint8_t)); 
    if (buffer == NULL) 
    { 
     std::cerr << "buffer == NULL"; 
     return false; 
    } 

    // Assign appropriate parts of buffer to image planes in pFrameRGB 
    // Note that pFrameRGB is an AVFrame, but AVFrame is a superset 
    // of AVPicture 
    avpicture_fill((AVPicture *) pFrameRGB, buffer, PIX_FMT_RGB32, pCodecCtx->width, pCodecCtx->height); 

    SwsContext *swsctx; 
    swsctx = sws_getContext(
       pCodecCtx->width, pCodecCtx->height, pCodecCtx->pix_fmt, 
       pCodecCtx->width, pCodecCtx->height, PIX_FMT_RGB32, 
       SWS_BILINEAR, NULL, NULL, NULL); 
    if (swsctx == NULL) 
    { 
     std::cerr << "swsctx == NULL"; 
     return false; 
    } 

    AVPacket packet; 
    while (av_read_frame(pFormatCtx, &packet) >= 0) 
    { 
     if (packet.stream_index == video_stream) 
     { 
      int frame_finished; 
      avcodec_decode_video2(pCodecCtx, pFrame, &frame_finished, &packet); 

      if (frame_finished) 
      { 
       sws_scale(swsctx, pFrame->data, pFrame->linesize, 0, pCodecCtx->height, pFrameRGB->data, pFrameRGB->linesize); 

       std::cerr << "good"; 
       av_close_input_stream(pFormatCtx); 

       return true; 
      } 
      else 
       std::cerr << "frame_finished == 0"; 
     } 
    } 

    std::cerr << "av_read_frame < 0"; 
    return false; 
} 

的ffmpeg -version

FFmpeg 0.6.2-4:0.6.2-1ubuntu1 
libavutil  50.15. 1/50.15. 1 
libavcodec 52.72. 2/52.72. 2 
libavformat 52.64. 2/52.64. 2 
libavdevice 52. 2. 0/52. 2. 0 
libavfilter 1.19. 0/1.19. 0 
libswscale  0.11. 0/0.11. 0 
libpostproc 51. 2. 0/51. 2. 0 

回答

4

你可能已經看過一些libav教程,並簡單地複製\粘貼幾乎所有代碼你的函數decode()。這真的是錯誤的。看看源代碼。每次你想解碼一些幀 - 無論音頻還是視頻都無關緊要時,你可以打開輸入上下文,初始化編解碼器等多次。每次你不關閉\免費!請記住,即使您更正了打開\ init並關閉了所有內容,每次調用decode()時都會得到相同的幀,因此每次調用decode時,這種方法都會導致文件開始位置()。您忘記關閉使用avcodec_close()的編解碼器,使用avpicture_free()釋放分配的圖片,使用av_free()釋放分配的幀,使用av_free_packet()釋放讀取的數據包,然後您調用av_close_input_stream()而不是av_close_input_file ()。另外你的函數seekp()和readp()也可能是錯誤的。

還有一個建議 - func sws_getContext()現在已被棄用,您應該使用sws_getCachedContext()來代替。根據你的情況下的函數名(多次調用sws_getContext;但它仍然是錯誤的),它會更快。

請再次閱讀有關libav的一些教程。他們似乎都過時了,但你可以用新的,你可以在官方的libav doxygen文檔中找到它,而不是將其中已棄用或刪除的功能。這裏有一些鏈接:

http://www.inb.uni-luebeck.de/~boehme/using_libavcodec.html
http://dranger.com/ffmpeg/ffmpeg.html

你會發現實例是最新的libav的官方API文檔。

http://libav.org/doxygen/master/examples.html

他們解釋最常見的用例。