使用FFMPEG将YUV编码为H.264

本文介绍一个如何使用FFmpeg实现YUV420P的像素数据编码为H.264的压缩编码数据。

项目十分简单,没有多少代码在其中。弄清楚了该项目的代码也就基本弄清楚了FFMPEG的编码流程。

本程序使用的FFmpeg版本为2.2.2(版本较新),开发平台为VC2008(VC2010估计很多人都用不了)。

相关配置已经完成,只需下载源码运行即可。

下面直接上代码:

 
  1. /*

  2. *将YUV420P进行H264编码压缩

  3. *码术 codemanship

  4. *邮箱: [email protected]

  5. *http://blog.csdn.net/codemanship

  6. *微信公众号: codemanship

  7. *本程序实现了YUV420P的像素数据编码为H.264的压缩编码数据

  8. *是最简单的FFmpeg视频编码方面的教程。

  9. *通过学习本例子可以了解FFmpeg的图片压缩过程。

  10. */

  11. #ifndef INT64_C

  12. #define INT64_C

  13. #define UINT64_C

  14. #endif

  15. extern "C"

  16. {

  17. #include "libavcodec/avcodec.h"

  18. #include "libavutil/imgutils.h"

  19. #include "libavutil/parseutils.h"

  20. #include "libswscale/swscale.h"

  21. #include "libavformat/avformat.h"

  22. };

  23. #pragma comment(lib,"avcodec.lib")

  24. #pragma comment(lib,"avformat.lib")

  25. #pragma comment(lib,"swscale.lib")

  26. #pragma comment(lib,"avutil.lib")

  27.  
  28. #define FrameCount 50

  29. static void fill_yuv_image(uint8_t *data[4], int linesize[4],

  30. int width, int height, int frame_index)

  31. {

  32. int x, y;

  33.  
  34. /* Y */

  35. for (y = 0; y < height; y++)

  36. for (x = 0; x < width; x++)

  37. data[0][y * linesize[0] + x] = x + y + frame_index * 3;

  38.  
  39. /* Cb and Cr */

  40. for (y = 0; y < height / 2; y++) {

  41. for (x = 0; x < width / 2; x++) {

  42. data[1][y * linesize[1] + x] = 128 + y + frame_index * 2;

  43. data[2][y * linesize[2] + x] = 64 + x + frame_index * 5;

  44. }

  45. }

  46. }

  47.  
  48.  
  49.  
  50. int main(int argc, char **argv)

  51. {

  52. AVFormatContext* pFormatCtx;

  53. AVOutputFormat* fmt;

  54. AVStream* video_st;

  55. AVCodecContext* pCodecCtx;

  56. AVCodec* pCodec;

  57. AVFrame* srcFrame;

  58. int size;

  59.  
  60. int width=640,height=480;

  61. const char* outfilename = "out_640x480.h264";

  62.  
  63. av_register_all();

  64. pFormatCtx = avformat_alloc_context();

  65. fmt = av_guess_format(NULL, outfilename, NULL);

  66. pFormatCtx->oformat = fmt;

  67.  
  68. if (avio_open(&pFormatCtx->pb,outfilename, AVIO_FLAG_READ_WRITE) < 0)

  69. {

  70. printf("open file failed.");

  71. exit(1);

  72. }

  73.  
  74. video_st = av_new_stream(pFormatCtx, 0);

  75. if (video_st==NULL)

  76. {

  77. exit(1);

  78. }

  79. pCodecCtx = video_st->codec;

  80. pCodecCtx->codec_id = fmt->video_codec;

  81. pCodecCtx->codec_type = AVMEDIA_TYPE_VIDEO;

  82. pCodecCtx->pix_fmt = PIX_FMT_YUV420P;

  83. pCodecCtx->width = width;

  84. pCodecCtx->height = height;

  85. pCodecCtx->time_base.num = 1;

  86. pCodecCtx->time_base.den = 25;

  87. pCodecCtx->bit_rate = 40000;

  88. pCodecCtx->gop_size=10;

  89. pCodecCtx->qmin = 10;

  90. pCodecCtx->qmax = 30;

  91.  
  92. //输出格式信息

  93. av_dump_format(pFormatCtx, 0, outfilename, 1);

  94.  
  95. pCodec = avcodec_find_encoder(pCodecCtx->codec_id);

  96. if (!pCodec)

  97. {

  98. fprintf(stderr, "Codec not found\n");

  99. exit(1);

  100. }

  101. //设置X264编码的参数,减小延迟

  102. AVDictionary *opts = NULL;

  103. av_dict_set(&opts, "profile", "baseline", 0);

  104. av_dict_set(&opts, "preset", "fast", 0);

  105. av_dict_set(&opts, "tune", "zerolatency", 0);

  106. if (avcodec_open2(pCodecCtx, pCodec,&opts) < 0)

  107. {

  108. fprintf(stderr, "Could not open codec\n");

  109. exit(1);

  110. }

  111. srcFrame = av_frame_alloc();

  112. size = avpicture_get_size(pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height);

  113. /* allocate source and destination image buffers */

  114. if ((av_image_alloc(srcFrame->data, srcFrame->linesize,

  115. width, height, PIX_FMT_YUV420P, 16)) < 0) {

  116. fprintf(stderr, "Could not allocate source image\n");

  117. exit(1);

  118. }

  119. //写文件头

  120. avformat_write_header(pFormatCtx,NULL);

  121.  
  122. AVPacket pkt;

  123. int y_size = pCodecCtx->width * pCodecCtx->height;

  124. av_new_packet(&pkt,y_size*3);

  125.  
  126. for (int i=0; i<FrameCount; i++){

  127. /* generate synthetic video */

  128. fill_yuv_image(srcFrame->data,srcFrame->linesize,width,height,i);

  129. /*设置pts*/

  130. srcFrame->pts=i;

  131. int got_picture=0;

  132. /*编码*/

  133. int ret = avcodec_encode_video2(pCodecCtx, &pkt,srcFrame, &got_picture);

  134. if(ret < 0)

  135. {

  136. fprintf(stderr, "Error encoding frame\n");

  137. return -1;

  138. }

  139. if (got_picture==1)

  140. {

  141. printf("Write frame %3d (size=%5d)\n", i, pkt.size);

  142. pkt.stream_index = video_st->index;

  143. ret = av_write_frame(pFormatCtx, &pkt);

  144. av_free_packet(&pkt);

  145. }

  146. }

  147.  
  148. //写文件尾

  149. av_write_trailer(pFormatCtx);

  150. //清理

  151. if (video_st)

  152. {

  153. avcodec_close(video_st->codec);

  154. av_freep(srcFrame);

  155. }

  156. avio_close(pFormatCtx->pb);

  157. avformat_free_context(pFormatCtx);

  158. return 0;

  159. }

猜你喜欢

转载自blog.csdn.net/weixin_37897683/article/details/81267638