ffmpeg 工程avcodec_decode_video2() 解码fail

leo_wdls 2014-09-16 09:41:49
初学ffmpeg, 写个demon. 想法是用ffmpeg解码, 然后讲一帧图像转换为RGB24, 保存为bmp格式的图片。

遇到的问题:
avcodec_decode_video2(AVCodecContext *avctx, AVFrame *picture, int *got_picture_ptr,const AVPacket *avpkt) 调用失败。got_picture_ptr 为0.

贴下关键代码,请大家指教

int main(int argc, char *argv[])
{

int err;
int i, j;
int byte_cnt;
int got_frame = 0;
unsigned int video_stream = -1;
unsigned char *buffer;
char path[256];
unsigned int index = 0;



AVFormatContext *pFormatCtx = NULL;

AVCodecContext *pCodecCtx = NULL;

AVFrame *pFrame = NULL;

AVFrame *pFrameRgb = NULL;

AVCodec *pCodec = NULL;

AVPacket packet = {0}, out_pkt;

AVCodecParserContext *pCodecParserCtx = NULL;

struct SwsContext *pSwsCtx = NULL;

av_log_set_level(AV_LOG_DEBUG);

if (argc != 2) {
av_info_log("argument number err!\n");
return -1;
}

// register all format of video file, and codec
av_info_log("av register!\n");
av_register_all();

// open video file, get head info from file
av_info_log("open input media file!\n");
err = avformat_open_input(&pFormatCtx, argv[1], NULL, NULL);
if (err<0) {
av_err_log("avformat_open_input open %s fail, err=%d\n",argv[1], err);
return -1;
}

// get stream info(AVFormatContext)
av_info_log("get stream info!\n");
err = avformat_find_stream_info(pFormatCtx, NULL);
if (err<0) {
av_err_log("can not find codec parameter!\n");
goto err1;
}

// Dump information about file onto standard error
av_dump_format(pFormatCtx, 0, argv[1], 0);

av_info_log("nb_streams = %d\n", pFormatCtx->nb_streams);

// get video stream
for (i=0; i<pFormatCtx->nb_streams; i++) {
if (pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
video_stream = i;
break;
}

}

if (video_stream == -1) {
av_err_log("not find video stream!\n");
goto err1;
}

// get AVCodecContext(codec info)
pCodecCtx = pFormatCtx->streams[video_stream]->codec;

// get AVCodec(get codec)
pCodec = avcodec_find_decoder(pCodecCtx->codec_id);
if (!pCodec) {
av_err_log("%s codec not support!\n", avcodec_get_name(pCodecCtx->codec_id));
goto err1;
}

av_info_log("find video decoder sucess! name=\"%s\",id=%d\n", avcodec_get_name(pCodecCtx->codec_id), pCodecCtx->codec_id);

// open codec
err = avcodec_open2(pCodecCtx, pCodec, NULL);
if (err < 0) {
av_err_log("open %s(id=%d) codec fail!\n", avcodec_get_name(pCodecCtx->codec_id), pCodecCtx->codec_id);
goto err1;
}
av_info_log("open video codec sucess!\n");


//pFrame = avcodec_alloc_frame();
//if (!pFrame) {
// printf("alloc frame faild! at %d\n", __LINE__);
// goto err1;
//}

pFrame = av_frame_alloc();
if (!pFrame) {
av_err_log("alloc frame fail at %d\n", __LINE__);
goto err1;
}

pFrameRgb = av_frame_alloc();
if (!pFrameRgb) {
av_err_log("alloc frame fail at %d\n", __LINE__);
goto err2;
}

// caculate picture size
byte_cnt = avpicture_get_size(AV_PIX_FMT_RGB24, pCodecCtx->width, pCodecCtx->height);

av_info_log("a frame(RGB24) image size is %d\n", byte_cnt);

// alloc a size memrry of picture
buffer = (unsigned char *)av_malloc(byte_cnt * sizeof(unsigned char));
if (!buffer) {
av_err_log("alloc frame fail at %d\n", __LINE__);
goto err2;
}

avpicture_fill((AVPicture *)pFrameRgb, buffer, AV_PIX_FMT_RGB24, pCodecCtx->width, pCodecCtx->height);
//av_info_log("avpicture fill!\n");

// init AVCodecParsetContext struct
pCodecParserCtx = av_parser_init(pCodecCtx->codec_id);


do {

unsigned char *p_out_buf = NULL, *p_in_buf = NULL;
unsigned int in_size = 0, out_size = 0, length = 0;


//av_init_packet(&packet);
av_free_packet(&packet);

if (av_read_frame(pFormatCtx, &packet)<0) {
av_err_log("av_read_frame fail!\n");
break;
}

p_in_buf = packet.data;
in_size = packet.size;
p_out_buf = NULL;
out_size = 0;

do {
length = av_parser_parse2(pCodecParserCtx, pCodecCtx->codec,
&p_out_buf, &out_size,
p_in_buf, in_size,
AV_NOPTS_VALUE, AV_NOPTS_VALUE, AV_NOPTS_VALUE);

if (p_out_buf && (out_size!=0)) {
av_info_log("av_paraser_parse2 seperate a frame as a packet: size=%dK(%dByte)\n", out_size/1024, out_size);
}

av_info_log("p_out_buf=0x%x, out_size=%d, length=%d\n", p_out_buf, out_size, length);

if (length <= 0) {
av_info_log("av_parser_parse2 return <=0, continue!\n");
continue;

} else {
av_init_packet(&out_pkt);
out_pkt.data = p_out_buf;
out_pkt.size = out_size;
p_in_buf += length;
in_size -= length;

}

if (pFormatCtx->streams[packet.stream_index]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
err = avcodec_decode_video2(pCodecCtx, pFrame, &got_frame, &out_pkt);
if (err < 0) {
av_err_log("video decode fail!\n");
goto err3;
}

if (got_frame) {
//create SW scale context
av_info_log("decode a frame finished!\n");
av_info_log("the one line data of the frame:\n");

printf("\n");
pSwsCtx = sws_getCachedContext(pSwsCtx, pCodecCtx->width, pCodecCtx->height, pCodecCtx->pix_fmt,
pCodecCtx->width, pCodecCtx->height, AVMEDIA_TYPE_VIDEO,
SWS_BICUBIC, NULL, NULL, NULL);
sws_scale(pSwsCtx, (const unsigned char* const *)pFrame->data[0], pFrame->linesize, 0, pCodecCtx->height, pFrameRgb->data, pFrameRgb->linesize);
av_info_log("cover img format finish!\n");

} else {
av_info_log("decode a frame fail!\n");
break;

}

}
} while (in_size!=0);

break;

} while (1);


av_free_packet(&packet);

av_free(buffer);
av_frame_free(&pFrame);
avformat_close_input(&pFormatCtx);
return 0;

err3:
av_frame_free(&pFrame);
av_free_packet(&packet);
av_free(buffer);

err2:
av_frame_free(&pFrame);

err1:
avformat_close_input(&pFormatCtx);
return -1;
}
...全文
9261 9 打赏 收藏 转发到动态 举报
写回复
用AI写文章
9 条回复
切换为时间正序
请发表友善的回复…
发表回复
小猪_sun 2017-03-23
  • 打赏
  • 举报
回复
视频解码需要知道关键帧,才能根据关键帧解出来后面的P,B帧,前面几帧不是关键帧,解码器找不到参考的数据,所以没法解码
乱侃521 2016-11-14
  • 打赏
  • 举报
回复
我的一直一直都是0 诶,问题究竟在哪
haitaoyu0703 2016-11-05
  • 打赏
  • 举报
回复
引用 6 楼 souvis 的回复:
应该是因为你解码时第一帧给的不是关键帧,例如h264,第一帧输入需要是SPS、PPS、SEI和IDR帧,如果是先给的P帧或B帧数据就会导致解码失败。跳过几帧后就成功了是因为遇到关键帧了。
在调试模式下,一直返回0,我都不知错哪了,然后看到您这个我茅塞顿开,取消掉所有断点,就好了,感谢
souvis 2016-09-23
  • 打赏
  • 举报
回复
应该是因为你解码时第一帧给的不是关键帧,例如h264,第一帧输入需要是SPS、PPS、SEI和IDR帧,如果是先给的P帧或B帧数据就会导致解码失败。跳过几帧后就成功了是因为遇到关键帧了。
Trump_zhai 2016-08-11
  • 打赏
  • 举报
回复
开始几个视频帧会出现调用avcodec_decode_video2()fail的情况,我也遇到了,请问解决了没有?
leo_wdls 2014-10-15
  • 打赏
  • 举报
回复
引用 3 楼 a13728843352 的回复:
借问这位朋友 avcodec_decode_video2 , av_read_frame等函数内部是怎么处理的,知道吗?在哪个c文件能找到源代码?
av_parser_parse2()保证packet里的frame count是整数。av_read_frame()会call av_parser_parse2(). 至于在哪个.c,根据函数名找应该很轻松。
  • 打赏
  • 举报
回复
借问这位朋友 avcodec_decode_video2 , av_read_frame等函数内部是怎么处理的,知道吗?在哪个c文件能找到源代码?
leo_wdls 2014-09-29
  • 打赏
  • 举报
回复
by the way ffmpeg version is 2.3, av_read_frame()读取的packet里面帧数一定是整数
leo_wdls 2014-09-29
  • 打赏
  • 举报
回复
结贴: ffmpeg version is 2.3 问题原因: 开始几个视频帧会出现调用avcodec_decode_video2()fail的情况,跳过后,后面视频帧解码就很顺利。 疑惑:为什么开始的几帧解码会失败,其内容是什么? (这几帧不影响到视频的播放)

2,275

社区成员

发帖
与我相关
我的任务
社区描述
多媒体/设计/Flash/Silverlight 开发 Flash流媒体开发
社区管理员
  • Flash流媒体开发社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧