使用X264编码yuv格式的视频帧使用ffmpeg解码h264视频帧

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平台分辨播放了三个文件,画面看不出差别。

以下是代码"

 

 
  1. /*File : yuvTO264.c
  2. *Auth : sjin
  3. *Date : 20141115
  4. *Mail : [email protected]
  5. */
  6.  
  7. /*利用x264库将YUV文件编码为h264文件
  8. *
  9. */
  10.  
  11. #include
  12. #include
  13. #include
  14. #include
  15. #include
  16. #include
  17. #include
  18.  
  19. #define CLEAR(x) (memset((&x),0,sizeof(x)))
  20. #define IMAGE_WIDTH 176
  21. #define IMAGE_HEIGHT 144
  22. #define ENCODER_PRESET "veryfast"
  23.  
  24. /*配置參数
  25. * 使用默认參数,在这里使用了zerolatency的选项,使用这个选项之后,就不会有
  26. * delayed_frames,假设你使用不是这个的话,还须要在编码完毕之后得到缓存的
  27. * 编码帧
  28. */
  29. #define ENCODER_TUNE "zerolatency"
  30. #define ENCODER_PROFILE "baseline"
  31. #define ENCODER_COLORSPACE X264_CSP_I420
  32.  
  33. typedef struct my_x264_encoder{
  34. x264_param_t * x264_parameter;
  35. char parameter_preset[20];
  36. char parameter_tune[20];
  37. char parameter_profile[20];
  38. x264_t * x264_encoder;
  39. x264_picture_t * yuv420p_picture;
  40. long colorspace;
  41. unsigned char *yuv;
  42. x264_nal_t * nal;
  43. } my_x264_encoder;
  44.  
  45. char *read_filename="yuv420p.yuv";
  46. char *write_filename="encode.h264";
  47.  
  48. int main(int argc ,char **argv)
  49. {
  50. int ret;
  51. int fd_read,fd_write;
  52. my_x264_encoder * encoder = (my_x264_encoder *)malloc(sizeof(my_x264_encoder));
  53. if(!encoder){
  54. printf("cannot malloc my_x264_encoder !\n");
  55. exit(EXIT_FAILURE);
  56. }
  57. CLEAR(*encoder);
  58.  
  59. /****************************************************************************
  60. * Advanced parameter handling functions
  61. ****************************************************************************/
  62.  
  63. /* These functions expose the full power of x264's preset-tune-profile system for
  64. * easy adjustment of large numbers //free(encoder->yuv420p_picture);of internal parameters.
  65. *
  66. * In order to replicate x264CLI's option handling, these functions MUST be called
  67. * in the following order:
  68. * 1) x264_param_default_preset
  69. * 2) Custom user options (via param_parse or directly assigned variables)
  70. * 3) x264_param_apply_fastfirstpass
  71. * 4) x264_param_apply_profile
  72. *
  73. * Additionally, x264CLI does not apply step 3 if the preset chosen is "placebo"
  74. * or --slow-firstpass is set. */
  75. strcpy(encoder->parameter_preset,ENCODER_PRESET);
  76. strcpy(encoder->parameter_tune,ENCODER_TUNE);
  77.  
  78. encoder->x264_parameter = (x264_param_t *)malloc(sizeof(x264_param_t));
  79. if(!encoder->x264_parameter){
  80. printf("malloc x264_parameter error!\n");
  81. exit(EXIT_FAILURE);
  82. }
  83.  
  84. /*初始化编码器*/
  85. CLEAR(*(encoder->x264_parameter));
  86. x264_param_default(encoder->x264_parameter);
  87.  
  88. if((ret = x264_param_default_preset(encoder->x264_parameter,encoder->parameter_preset,encoder->parameter_tune))<0){
  89. printf("x264_param_default_preset error!\n");
  90. exit(EXIT_FAILURE);
  91. }
  92.  
  93. /*cpuFlags 去空缓冲区继续使用不死锁保证*/
  94. encoder->x264_parameter->i_threads =X264_SYNC_LOOKAHEAD_AUTO;
  95. /*视频选项*/
  96. encoder->x264_parameter->i_width =IMAGE_WIDTH;//要编码的图像的宽度
  97. encoder->x264_parameter->i_height =IMAGE_HEIGHT;//要编码的图像的高度
  98. encoder->x264_parameter->i_frame_total =0;//要编码的总帧数,不知道用0
  99. encoder->x264_parameter->i_keyint_max =25;
  100. /*流參数*/
  101. encoder->x264_parameter->i_bframe =5;
  102. encoder->x264_parameter->b_open_gop =0;
  103. encoder->x264_parameter->i_bframe_pyramid=0;
  104. encoder->x264_parameter->i_bframe_adaptive=X264_B_ADAPT_TRELLIS;
  105.  
  106. /*log參数,不须要打印编码信息时直接凝视掉*/
  107. encoder->x264_parameter->i_log_level =X264_LOG_DEBUG;
  108.  
  109. encoder->x264_parameter->i_fps_den =1;//码率分母
  110. encoder->x264_parameter->i_fps_num =25;//码率分子
  111. encoder->x264_parameter->b_intra_refresh =1;
  112. encoder->x264_parameter->b_annexb =1;
  113.  
  114. strcpy(encoder->parameter_profile,ENCODER_PROFILE);
  115. if((ret=x264_param_apply_profile(encoder->x264_parameter,encoder->parameter_profile))<0){
  116. printf("x264_param_apply_profile error!\n");
  117. exit(EXIT_FAILURE);
  118. }
  119. /*打开编码器*/
  120. encoder->x264_encoder = x264_encoder_open(encoder->x264_parameter);
  121. encoder->colorspace = ENCODER_COLORSPACE;
  122.  
  123. /*初始化pic*/
  124. encoder->yuv420p_picture = (x264_picture_t *)malloc(sizeof(x264_picture_t ));
  125. if(!encoder->yuv420p_picture){
  126. printf("malloc encoder->yuv420p_picture error!\n");
  127. exit(EXIT_FAILURE);
  128. }
  129. if((ret = x264_picture_alloc(encoder->yuv420p_picture,encoder->colorspace,IMAGE_WIDTH,IMAGE_HEIGHT))<0){
  130. printf("ret=%d\n",ret);
  131. printf("x264_picture_alloc error!\n");
  132. exit(EXIT_FAILURE);
  133. }
  134.  
  135. encoder->yuv420p_picture->img.i_csp = encoder->colorspace;
  136. encoder->yuv420p_picture->img.i_plane = 3;
  137. encoder->yuv420p_picture->i_type = X264_TYPE_AUTO;
  138.  
  139. /*申请YUV buffer*/
  140. encoder->yuv = (uint8_t *)malloc(IMAGE_WIDTH*IMAGE_HEIGHT*3/2);
  141. if(!encoder->yuv){
  142. printf("malloc yuv error!\n");
  143. exit(EXIT_FAILURE);
  144. }
  145. CLEAR(*(encoder->yuv));
  146. encoder->yuv420p_picture->img.plane[0] = encoder->yuv;
  147. encoder->yuv420p_picture->img.plane[1] = encoder->yuv+IMAGE_WIDTH*IMAGE_HEIGHT;
  148. encoder->yuv420p_picture->img.plane[2] = encoder->yuv+IMAGE_WIDTH*IMAGE_HEIGHT+IMAGE_WIDTH*IMAGE_HEIGHT/4;
  149.  
  150. if((fd_read = open(read_filename,O_RDONLY))<0){
  151. printf("cannot open input file!\n");
  152. exit(EXIT_FAILURE);
  153. }
  154.  
  155. if((fd_write = open(write_filename,O_WRONLY | O_APPEND | O_CREAT,0777))<0){
  156. printf("cannot open output file!\n");
  157. exit(EXIT_FAILURE);
  158. }
  159.  
  160. int n_nal = 0;
  161. x264_picture_t pic_out;
  162. x264_nal_t *my_nal;
  163. encoder->nal = (x264_nal_t *)malloc(sizeof(x264_nal_t ));
  164. if(!encoder->nal){
  165. printf("malloc x264_nal_t error!\n");
  166. exit(EXIT_FAILURE);
  167. }
  168. CLEAR(*(encoder->nal));
  169.  
  170. /*编码*/
  171. while(read(fd_read,encoder->yuv,IMAGE_WIDTH*IMAGE_HEIGHT*3/2)>0){
  172. encoder->yuv420p_picture->i_pts++;
  173. if((ret = x264_encoder_encode(encoder->x264_encoder,&encoder->nal,&n_nal,encoder->yuv420p_picture,&pic_out))<0){
  174. printf("x264_encoder_encode error!\n");
  175. exit(EXIT_FAILURE);
  176. }
  177.  
  178. for(my_nal = encoder->nal; my_nalnal+n_nal; ++my_nal){
  179. write(fd_write,my_nal->p_payload,my_nal->i_payload);
  180. }
  181. }
  182.  
  183. free(encoder->yuv);
  184. free(encoder->yuv420p_picture);
  185. free(encoder->x264_parameter);
  186. x264_encoder_close(encoder->x264_encoder);
  187. free(encoder);
  188. close(fd_read);
  189. close(fd_write);
  190.  
  191. return 0;
  192. }

 

 
  1. /*File : decode_h264.c
  2. *Auth : sjin
  3. *Date : 20141115
  4. *Mail : [email protected]
  5. */
  6.  
  7. /*将h264解码为yuv文件*/
  8.  
  9. #include
  10. #include
  11. #include
  12. #include
  13. #include
  14. #include
  15. #include
  16. #include
  17.  
  18. #define DECODED_OUTPUT_FORMAT AV_PIX_FMT_YUV420P
  19. #define INPUT_FILE_NAME "encode.h264"
  20. #define OUTPUT_FILE_NAME "decode.yuv"
  21. /*h264文件的宽度和高度,必须和实际的宽度和高度一致
  22. *否则将出错
  23. * */
  24. #define IMAGE_WIDTH 176
  25. #define IMAGE_HEIGHT 144
  26.  
  27. void error_handle(const char *errorInfo )
  28. {
  29. printf("%s error!\n",errorInfo);
  30. exit(EXIT_FAILURE);
  31. }
  32.  
  33. int main(int argc,char ** argv)
  34. {
  35. int write_fd,ret,videoStream;
  36. AVFormatContext * formatContext=NULL;
  37. AVCodec * codec;
  38. AVCodecContext * codecContext;
  39. AVFrame * decodedFrame;
  40. AVPacket packet;
  41. uint8_t *decodedBuffer;
  42. unsigned int decodedBufferSize;
  43. int finishedFrame;
  44.  
  45. //初始化环境
  46. av_register_all();
  47.  
  48. write_fd = open(OUTPUT_FILE_NAME,O_RDWR | O_CREAT,0666);
  49. if(write_fd<0){
  50. perror("open");
  51. exit(1);
  52. }
  53.  
  54. ret = avformat_open_input(&formatContext, INPUT_FILE_NAME, NULL,NULL);
  55. if(ret<0)
  56. error_handle("avformat_open_input error");
  57.  
  58. ret = avformat_find_stream_info(formatContext,NULL);
  59. if(ret<0)
  60. error_handle("av_find_stream_info");
  61.  
  62. //打印输入文件的具体信息
  63. av_dump_format(formatContext,0,INPUT_FILE_NAME,0);
  64.  
  65. videoStream = 0;
  66. codecContext = formatContext->streams[videoStream]->codec;
  67.  
  68. codec = avcodec_find_decoder(AV_CODEC_ID_H264);
  69. if(codec == NULL)
  70. error_handle("avcodec_find_decoder error!\n");
  71.  
  72. ret = avcodec_open2(codecContext,codec,NULL);
  73. if(ret<0)
  74. error_handle("avcodec_open2");
  75.  
  76. //分配保存视频帧的空间
  77. decodedFrame = avcodec_alloc_frame();
  78. if(!decodedFrame)
  79. error_handle("avcodec_alloc_frame!");
  80.  
  81. //分配解码后视频帧的空间
  82. decodedBufferSize = avpicture_get_size(DECODED_OUTPUT_FORMAT,IMAGE_WIDTH,IMAGE_HEIGHT);
  83. decodedBuffer = (uint8_t *)malloc(decodedBufferSize);
  84. if(!decodedBuffer)
  85. error_handle("malloc decodedBuffer error!");
  86.  
  87. av_init_packet(&packet);
  88. while(av_read_frame(formatContext,&packet)>=0){
  89. ret = avcodec_decode_video2(codecContext,decodedFrame,&finishedFrame,&packet);
  90. if(ret<0)
  91. error_handle("avcodec_decode_video2 error!");
  92. if(finishedFrame){
  93. avpicture_layout((AVPicture*)decodedFrame,DECODED_OUTPUT_FORMAT,IMAGE_WIDTH,IMAGE_HEIGHT,decodedBuffer,decodedBufferSize);
  94. ret = write(write_fd,decodedBuffer,decodedBufferSize);
  95. if(ret<0)
  96. error_handle("write yuv stream error!");
  97. }
  98.  
  99. av_free_packet(&packet);
  100. }
  101.  
  102. /*防止视频解码完毕后丢帧的情况*/
  103. while(1){
  104. packet.data = NULL;
  105. packet.size = 0;
  106. ret = avcodec_decode_video2(codecContext,decodedFrame,&finishedFrame,&packet);
  107. if(ret<=0 && (finishedFrame<=0))
  108. break;
  109. if(finishedFrame){
  110. avpicture_layout((AVPicture*)decodedFrame,DECODED_OUTPUT_FORMAT,IMAGE_WIDTH,IMAGE_HEIGHT,decodedBuffer,decodedBufferSize);
  111. ret = write(write_fd,decodedBuffer,decodedBufferSize);
  112. if(ret<0)
  113. error_handle("write yuv stream error!");
  114. }
  115.  
  116. av_free_packet(&packet);
  117. }
  118.  
  119. avformat_close_input(&formatContext);
  120. free(decodedBuffer);
  121. av_free(decodedFrame);
  122. avcodec_close(codecContext);
  123.  
  124. return 0;
  125. }

Makefile:

 
  1. # use pkg-config for getting CFLAGS and LDLIBS
  2. FFMPEG_LIBS= libavdevice \
  3. libavformat \
  4. libavfilter \
  5. libavcodec \
  6. libswresample \
  7. libswscale \
  8. libavutil \
  9.  
  10. CFLAGS += -Wall -O2 -g
  11. CFLAGS := $(shell pkg-config --cflags $(FFMPEG_LIBS)) $(CFLAGS)
  12. LDLIBS := $(shell pkg-config --libs $(FFMPEG_LIBS)) $(LDLIBS)
  13.  
  14. EXAMPLES= decode_h264 yuvTO264
  15.  
  16. OBJS=$(addsuffix .o,$(EXAMPLES))
  17.  
  18. # the following examples make explicit use of the math library
  19. LDLIBS += -lx264 -m32 -pthread -lm -ldl
  20.  
  21. .phony:all clean
  22.  
  23. all: $(OBJS) $(EXAMPLES)
  24.  
  25. clean:
  26. 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

你可能感兴趣的:(video)