IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    [原]利用X264编码yuv格式视频帧,利用ffmpeg解码h264视频帧

    jsh13417发表于 2014-11-16 11:04:24
    love 0
    前面一篇博客介绍在centos上搭建点击打开链接ffmpeg及x264开发环境。下面就来问个例子: 1、利用x264库将YUV格式视频文件编码为h264格式视频文件 2、利用ffmpeh库将h264格式的视频文件解码为yuv格式视频文件 解码和编码前后对文件大小进行比较,如图: 其中yuv420p.yuv为原始文件,大小77M encode.h264为H264编码后的视频文件,大小1.4M decode.yuv为ffmpeg解码后的视频文件,大小77M。从文件的大小很明显可以看出h264压缩率。在Windows平台分辨播放了三个文件,画面看不出区别。下面是代码"/*File : yuvTO264.c *Auth : sjin *Date : 20141115 *Mail : 413977243@qq.com */ /*利用x264库将YUV文件编码为h264文件 * */ #include #include #include #include #include #include #include #define CLEAR(x) (memset((&x;),0,sizeof(x))) #define IMAGE_WIDTH 176 #define IMAGE_HEIGHT 144 #define ENCODER_PRESET "veryfast" /*配置参数 * 使用默认参数,在这里使用了zerolatency的选项,使用这个选项之后,就不会有 * delayed_frames,如果你使用不是这个的话,还需要在编码完成之后得到缓存的 * 编码帧 */ #define ENCODER_TUNE "zerolatency" #define ENCODER_PROFILE "baseline" #define ENCODER_COLORSPACE X264_CSP_I420 typedef struct my_x264_encoder{ x264_param_t * x264_parameter; char parameter_preset[20]; char parameter_tune[20]; char parameter_profile[20]; x264_t * x264_encoder; x264_picture_t * yuv420p_picture; long colorspace; unsigned char *yuv; x264_nal_t * nal; } my_x264_encoder; char *read_filename="yuv420p.yuv"; char *write_filename="encode.h264"; int main(int argc ,char **argv) { int ret; int fd_read,fd_write; my_x264_encoder * encoder = (my_x264_encoder *)malloc(sizeof(my_x264_encoder)); if(!encoder){ printf("cannot malloc my_x264_encoder !\n"); exit(EXIT_FAILURE); } CLEAR(*encoder); /**************************************************************************** * Advanced parameter handling functions ****************************************************************************/ /* These functions expose the full power of x264's preset-tune-profile system for * easy adjustment of large numbers //free(encoder->yuv420p_picture);of internal parameters. * * In order to replicate x264CLI's option handling, these functions MUST be called * in the following order: * 1) x264_param_default_preset * 2) Custom user options (via param_parse or directly assigned variables) * 3) x264_param_apply_fastfirstpass * 4) x264_param_apply_profile * * Additionally, x264CLI does not apply step 3 if the preset chosen is "placebo" * or --slow-firstpass is set. */ strcpy(encoder->parameter_preset,ENCODER_PRESET); strcpy(encoder->parameter_tune,ENCODER_TUNE); encoder->x264_parameter = (x264_param_t *)malloc(sizeof(x264_param_t)); if(!encoder->x264_parameter){ printf("malloc x264_parameter error!\n"); exit(EXIT_FAILURE); } /*初始化编码器*/ CLEAR(*(encoder->x264_parameter)); x264_param_default(encoder->x264_parameter); if((ret = x264_param_default_preset(encoder->x264_parameter,encoder->parameter_preset,encoder->parameter_tune))<0){ printf("x264_param_default_preset error!\n"); exit(EXIT_FAILURE); } /*cpuFlags 去空缓冲区继续使用不死锁保证*/ encoder->x264_parameter->i_threads =X264_SYNC_LOOKAHEAD_AUTO; /*视频选项*/ encoder->x264_parameter->i_width =IMAGE_WIDTH;//要编码的图像的宽度 encoder->x264_parameter->i_height =IMAGE_HEIGHT;//要编码的图像的高度 encoder->x264_parameter->i_frame_total =0;//要编码的总帧数,不知道用0 encoder->x264_parameter->i_keyint_max =25; /*流参数*/ encoder->x264_parameter->i_bframe =5; encoder->x264_parameter->b_open_gop =0; encoder->x264_parameter->i_bframe_pyramid=0; encoder->x264_parameter->i_bframe_adaptive=X264_B_ADAPT_TRELLIS; /*log参数,不需要打印编码信息时直接注释掉*/ encoder->x264_parameter->i_log_level =X264_LOG_DEBUG; encoder->x264_parameter->i_fps_den =1;//码率分母 encoder->x264_parameter->i_fps_num =25;//码率分子 encoder->x264_parameter->b_intra_refresh =1; encoder->x264_parameter->b_annexb =1; strcpy(encoder->parameter_profile,ENCODER_PROFILE); if((ret=x264_param_apply_profile(encoder->x264_parameter,encoder->parameter_profile))<0){ printf("x264_param_apply_profile error!\n"); exit(EXIT_FAILURE); } /*打开编码器*/ encoder->x264_encoder = x264_encoder_open(encoder->x264_parameter); encoder->colorspace = ENCODER_COLORSPACE; /*初始化pic*/ encoder->yuv420p_picture = (x264_picture_t *)malloc(sizeof(x264_picture_t )); if(!encoder->yuv420p_picture){ printf("malloc encoder->yuv420p_picture error!\n"); exit(EXIT_FAILURE); } if((ret = x264_picture_alloc(encoder->yuv420p_picture,encoder->colorspace,IMAGE_WIDTH,IMAGE_HEIGHT))<0){ printf("ret=%d\n",ret); printf("x264_picture_alloc error!\n"); exit(EXIT_FAILURE); } encoder->yuv420p_picture->img.i_csp = encoder->colorspace; encoder->yuv420p_picture->img.i_plane = 3; encoder->yuv420p_picture->i_type = X264_TYPE_AUTO; /*申请YUV buffer*/ encoder->yuv = (uint8_t *)malloc(IMAGE_WIDTH*IMAGE_HEIGHT*3/2); if(!encoder->yuv){ printf("malloc yuv error!\n"); exit(EXIT_FAILURE); } CLEAR(*(encoder->yuv)); encoder->yuv420p_picture->img.plane[0] = encoder->yuv; encoder->yuv420p_picture->img.plane[1] = encoder->yuv+IMAGE_WIDTH*IMAGE_HEIGHT; encoder->yuv420p_picture->img.plane[2] = encoder->yuv+IMAGE_WIDTH*IMAGE_HEIGHT+IMAGE_WIDTH*IMAGE_HEIGHT/4; if((fd_read = open(read_filename,O_RDONLY))<0){ printf("cannot open input file!\n"); exit(EXIT_FAILURE); } if((fd_write = open(write_filename,O_WRONLY | O_APPEND | O_CREAT,0777))<0){ printf("cannot open output file!\n"); exit(EXIT_FAILURE); } int n_nal = 0; x264_picture_t pic_out; x264_nal_t *my_nal; encoder->nal = (x264_nal_t *)malloc(sizeof(x264_nal_t )); if(!encoder->nal){ printf("malloc x264_nal_t error!\n"); exit(EXIT_FAILURE); } CLEAR(*(encoder->nal)); /*编码*/ while(read(fd_read,encoder->yuv,IMAGE_WIDTH*IMAGE_HEIGHT*3/2)>0){ encoder->yuv420p_picture->i_pts++; if((ret = x264_encoder_encode(encoder->x264_encoder,&encoder-;>nal,&n;_nal,encoder->yuv420p_picture,&pic;_out))<0){ printf("x264_encoder_encode error!\n"); exit(EXIT_FAILURE); } for(my_nal = encoder->nal; my_nalnal+n_nal; ++my_nal){ write(fd_write,my_nal->p_payload,my_nal->i_payload); } } free(encoder->yuv); free(encoder->yuv420p_picture); free(encoder->x264_parameter); x264_encoder_close(encoder->x264_encoder); free(encoder); close(fd_read); close(fd_write); return 0; } /*File : decode_h264.c *Auth : sjin *Date : 20141115 *Mail : 413977243@qq.com */ /*将h264解码为yuv文件*/ #include #include #include #include #include #include avcodec.h> #include <libavformatavformat.h> #include mathematics.h> #define DECODED_OUTPUT_FORMAT AV_PIX_FMT_YUV420P #define INPUT_FILE_NAME "encode.h264" #define OUTPUT_FILE_NAME "decode.yuv" *h264文件的宽度和高度,必须和实际的宽度和高度一致 *否则将出错 * */ #define IMAGE_WIDTH 176 #define IMAGE_HEIGHT 144 void error_handle(const char *errorInfo ) { printf("%s error!\n",errorInfo); exit(EXIT_FAILURE); } int main(int argc,char ** argv) { int write_fd,ret,videoStream; AVFormatContext * formatContext=NULL; AVCodec * codec; AVCodecContext * codecContext; AVFrame * decodedFrame; AVPacket packet; uint8_t *decodedBuffer; unsigned int decodedBufferSize; int finishedFrame; //初始化环境 av_register_all(); write_fd = open(OUTPUT_FILE_NAME,O_RDWR | O_CREAT,0666); if(write_fd<0){ perror("open"); exit(1); } ret = avformat_open_input(&formatContext;, INPUT_FILE_NAME, NULL,NULL); if(ret<0) error_handle("avformat_open_input error"); ret = avformat_find_stream_info(formatContext,NULL); if(ret<0) error_handle("av_find_stream_info"); //打印输入文件的详细信息 av_dump_format(formatContext,0,INPUT_FILE_NAME,0); videoStream = 0; codecContext = formatContext->streams[videoStream]->codec; codec = avcodec_find_decoder(AV_CODEC_ID_H264); if(codec == NULL) error_handle("avcodec_find_decoder error!\n"); ret = avcodec_open2(codecContext,codec,NULL); if(ret<0) error_handle("avcodec_open2"); //分配保存视频帧的空间 decodedFrame = avcodec_alloc_frame(); if(!decodedFrame) error_handle("avcodec_alloc_frame!"); //分配解码后视频帧的空间 decodedBufferSize = avpicture_get_size(DECODED_OUTPUT_FORMAT,IMAGE_WIDTH,IMAGE_HEIGHT); decodedBuffer = (uint8_t *)malloc(decodedBufferSize); if(!decodedBuffer) error_handle("malloc decodedBuffer error!"); av_init_packet(&packet;); while(av_read_frame(formatContext,&packet;)>=0){ ret = avcodec_decode_video2(codecContext,decodedFrame,&finishedFrame;,&packet;); if(ret<0) error_handle("avcodec_decode_video2 error!"); if(finishedFrame){ avpicture_layout((AVPicture*)decodedFrame,DECODED_OUTPUT_FORMAT,IMAGE_WIDTH,IMAGE_HEIGHT,decodedBuffer,decodedBufferSize); ret = write(write_fd,decodedBuffer,decodedBufferSize); if(ret<0) error_handle("write yuv stream error!"); } av_free_packet(&packet;); } /*防止视频解码完毕后丢帧的情况*/ while(1){ packet.data = NULL; packet.size = 0; ret = avcodec_decode_video2(codecContext,decodedFrame,&finishedFrame;,&packet;); if(ret<=0 && (finishedFrame<=0)) break; if(finishedFrame){ avpicture_layout((AVPicture*)decodedFrame,DECODED_OUTPUT_FORMAT,IMAGE_WIDTH,IMAGE_HEIGHT,decodedBuffer,decodedBufferSize); ret = write(write_fd,decodedBuffer,decodedBufferSize); if(ret<0) error_handle("write yuv stream error!"); } av_free_packet(&packet;); } avformat_close_input(&formatContext;); free(decodedBuffer); av_free(decodedFrame); avcodec_close(codecContext); return 0; }Makefile:# use pkg-config for getting CFLAGS and LDLIBS FFMPEG_LIBS= libavdevice \ libavformat \ libavfilter \ libavcodec \ libswresample \ libswscale \ libavutil \ CFLAGS += -Wall -O2 -g CFLAGS := $(shell pkg-config --cflags $(FFMPEG_LIBS)) $(CFLAGS) LDLIBS := $(shell pkg-config --libs $(FFMPEG_LIBS)) $(LDLIBS) EXAMPLES= decode_h264 yuvTO264 OBJS=$(addsuffix .o,$(EXAMPLES)) # the following examples make explicit use of the math library LDLIBS += -lx264 -m32 -pthread -lm -ldl .phony:all clean all: $(OBJS) $(EXAMPLES) clean: rm $(EXAMPLES) $(OBJS)参考资料:参考资料1、http://blog.csdn.net/liushu1231/article/details/92032392、http://www.cnblogs.com/fojian/archive/2012/09/01/2666627.html3、http://stackoverflow.com/questions/2940671/how-does-one-encode-a-series-of-images-into-h264-using-the-x264-c-api4、http://blog.yikuyiku.com/?p=3486 live555搭建的rtsp服务器发送当前屏幕(x264)


沪ICP备19023445号-2号
友情链接