https://www.bbsmax.com/A/n2d9pVjQ5D/
前面一篇博客介绍在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 <stdint.h>
- #include <x264.h>
- #include <stdio.h>
- #include <unistd.h>
- #include <fcntl.h>
- #include <stdlib.h>
- #include <string.h>
- #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_nal<encoder->nal+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 <stdio.h>
- #include <string.h>
- #include <stdlib.h>
- #include <fcntl.h>
- #include <unistd.h>
- #include <libavcodec/avcodec.h>
- #include <libavformat/avformat.h>
- #include <libavutil/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/9203239
2、http://www.cnblogs.com/fojian/archive/2012/09/01/2666627.html
3、http://stackoverflow.com/questions/2940671/how-does-one-encode-a-series-of-images-into-h264-using-the-x264-c-api
4、http://blog.yikuyiku.com/?p=3486