利用ffmpeg解码h264裸流并存储成YUV420
2017-07-04 10:18
507 查看
此处用的ffmpeg版本为3.2.2。
例子是在linux下所写的,大致流程如下:
初始化ffmpeg库
创建YUV文件,用于存储解码后的YUV数据
初始化H264解码器
给解码器的一些结构变量赋值
打开解码器
打开H264裸流文件
读取一定数据的h264数据(因为不知道一帧到底有多大)
调用ffmpeg函数,循环分析读取到的数据,每循环一次得到一帧数据,然后调用解码器解码,并存储成YUV420文件。直到分析完读入的数据
释放内存,解码结束
编译命令如下(有些库非必须):
gcc -o codec codec.c -lavdevice -lavformat -lavfilter -lpostproc -lavcodec -lswresample -lswscale -lavutil -lpthread -ldl -lxml2 -lz -lx264 -ldl -lm
具体代码:
例子是在linux下所写的,大致流程如下:
初始化ffmpeg库
创建YUV文件,用于存储解码后的YUV数据
初始化H264解码器
给解码器的一些结构变量赋值
打开解码器
打开H264裸流文件
读取一定数据的h264数据(因为不知道一帧到底有多大)
调用ffmpeg函数,循环分析读取到的数据,每循环一次得到一帧数据,然后调用解码器解码,并存储成YUV420文件。直到分析完读入的数据
释放内存,解码结束
编译命令如下(有些库非必须):
gcc -o codec codec.c -lavdevice -lavformat -lavfilter -lpostproc -lavcodec -lswresample -lswscale -lavutil -lpthread -ldl -lxml2 -lz -lx264 -ldl -lm
具体代码:
#include <libavcodec/avcodec.h> #include <libavformat/avformat.h> #include <libavfilter/avfiltergraph.h> #include <libavfilter/buffersink.h> #include <libavfilter/buffersrc.h> #include <libavutil/opt.h> #include <libavutil/pixdesc.h> #include <sys/time.h> #define INBUF_SIZE 40960000 FILE *yuv_fp = NULL; int main(int argc, int argv) { //解码后,存储的文件,测试文件分辨率是640x480 yuv_fp = fopen("test_640x360.yuv","wb"); if(NULL == yuv_fp) { fprintf(stderr,"Open test.yuv fail\n"); exit(1); } avcodec_register_all(); AVCodec *codec; AVCodecContext *c = NULL; AVFrame *frame; AVCodecParserContext *avParserContext; FILE *f = NULL; int frame_count = 0; //读取264文件后所存储的buf unsigned char * inbuf = (unsigned char*)malloc(INBUF_SIZE + AV_INPUT_BUFFER_PADDING_SIZE); int got_frame; int read_size; memset(inbuf + INBUF_SIZE, 0, AV_INPUT_BUFFER_PADDING_SIZE); codec = avcodec_find_decoder(AV_CODEC_ID_H264); if( NULL == codec ) { fprintf(stderr,"Codec not found\n"); exit(1); } c = avcodec_alloc_context3(codec); if(NULL == c) { fprintf(stderr,"Could not allocate video codec context\n"); exit(1); } //初始化解码器所需要的参数,其实不设置也是可以正常解码的,因为264流中有对应的pps,sps相关结构 //里面包含解码所需要的相关信息 c->width = 640; c->height = 360; c->bit_rate = 1000; c->time_base.num = 1; c->time_base.den = 25; c->codec_id = AV_CODEC_ID_H264; c->codec_type = AVMEDIA_TYPE_VIDEO; avParserContext = av_parser_init(AV_CODEC_ID_H264); if( NULL == avParserContext) { fprintf(stderr,"Could not init avParserContext\n"); exit(1); } if(avcodec_open2(c,codec, NULL) < 0) { fprintf(stderr,"Could not open codec\n"); exit(1); } frame = av_frame_alloc(); if(NULL == frame) { fprintf(stderr,"Could not allocate video frame\n"); exit(1); } f = fopen("test.264","rb"); if( NULL == f ) { fprintf(stderr,"Could not allocate video frame"); exit(1); } for(;;) { //解码还有问题,因为avpkt不是一帧数据,而是有很多帧的数据, //需要增加一个filter,一帧一帧过滤出来 read_size = fread(inbuf, 1,INBUF_SIZE, f); printf("read_size_orig=%d\n",read_size); if(read_size == 0) { break; } while(read_size) { unsigned char *buf = 0; int buf_len = 0; int parse_len = av_parser_parse2(avParserContext, c, &buf, &buf_len, inbuf, read_size, AV_NOPTS_VALUE, AV_NOPTS_VALUE,AV_NOPTS_VALUE); inbuf += parse_len; read_size -= parse_len; //printf("read_size=%d, parse_len=%d, buf_len=%d\n",read_size, parse_len, buf_len); #if 1 if(buf_len != 0) { AVPacket avpkt = {0}; av_init_packet(&avpkt); avpkt.data = buf; avpkt.size = buf_len; time_t start ,end; start = clock(); int decode_len = avcodec_decode_video2(c,frame, &got_frame, &avpkt); end = clock(); printf("decoded frame used %d\n",end - start); if(decode_len < 0) fprintf(stderr,"Error while decoding frame %d\n",frame_count); if(got_frame) { fprintf(stderr,"decode success\n"); int width = frame->width; int height = frame->height; unsigned char* yuv_buf = (unsigned char*)malloc(width * height *1.5);//可以放在while循环外面,这样就不用每次都申请,释放了 int i = 0; //把解码出来的数据存成YUV数据,方便验证解码是否正确 for(i = 0; i < height; i++) { memcpy(yuv_buf + width * i, frame->data[0] + frame->linesize[0]*i, width); if(i < height >> 1) { memcpy(yuv_buf + width * height + width *i / 2, frame->data[1] + frame->linesize[1]*i, width / 2); memcpy(yuv_buf + width * height * 5 /4 + width * i / 2 ,frame->data[2] + frame->linesize[2]*i, width / 2); } } fwrite(yuv_buf, sizeof(unsigned char),width * height * 1.5 ,yuv_fp); free(yuv_buf); frame_count++; } else { fprintf(stderr,"decode fail\n"); } av_packet_unref(&avpkt); } #endif } } //记得释放变量的空间 return 0; }
相关文章推荐
- Live555接收h264使用ffmpeg解码为YUV420 .
- 03 ffmpeg 解码SDK调用 H264转YUV420
- FFmpeg-利用ffplay.c保存视频解码后的数据yuv420
- FFmpeg解码H264为YUV420
- Live555接收h264使用ffmpeg解码为YUV420 .
- Live555接收h264使用ffmpeg解码为YUV420
- Live555接收h264使用ffmpeg解码为YUV420 .
- FFMPEG3.2SDK解码H264保存为YUV420文件
- 通过FFmpeg将多媒体文件解码后保存成Bmp图像(YUV420 RGB32)
- 用ffmpeg把H264数据流解码成YUV420P
- 利用ffmpeg将H264解码为RGB
- Java利用JNI调用FFMpeg对h264码流进行解码
- 用ffmpeg把H264数据流解码成YUV420P
- 用ffmpeg把H264数据流解码成YUV420P
- 利用 ffmpeg x264 编码解码 h264
- FFmpeg解码H264裸流并转换成opencv Mat
- 利用ffmpeg将H264解码为RGB
- linux之x86裁剪移植---ffmpeg的H264解码显示(420、422)
- 用ffmpeg把H264数据流解码成YUV420P
- linux之x86裁剪移植---ffmpeg的H264解码显示(420、422)