2011-08-21 7 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(). 그것은 정말로 잘못입니다. 출처를 봐. 오디오 또는 비디오와 상관없는 일부 프레임을 디코드하려고 할 때마다 입력 컨텍스트를 열고 코덱 및 기타 여러 번 초기화합니다. 그리고 매번 \ 자유를 닫지 않을 때마다! open \ init을 수정하고 모든 물건을 닫은 후에도 decode()를 호출 할 때마다 동일한 프레임을 얻을 것입니다.이 접근법은 디코딩을 호출 할 때마다 파일 시작 위치를 찾게됩니다().

또한 당신이 av_close_input_stream() 대신 av_close_input_file의()를 호출, 당신은 av_free_packet와 패킷을 읽을 무료로) av_free (할당 프레임을 무료로) avpicture_free (로 할당 된 사진을 무료로) avcodec_close (와 코덱을 닫습니다 잊어(). 또한 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

그들은 가장 일반적인 사용 사례를 설명합니다.

관련 문제