Qt基于FFmpeg播放本地 H.264(H264)文件(灿哥哥的博客)

时间:2023-12-11 18:31:21

最近在弄H264的硬件编解码,基于DM3730,但是为了调试方便,在小红帽上用FFmpeg实现了H264的软件编解码。现在弄了一个Windows的例子,给需要的同学参考一下,如果大家觉得有帮助,可以小手一抖,帮我点个赞Qt基于FFmpeg播放本地 H.264(H264)文件(灿哥哥的博客)

这个例子是Qt Mingw版本的,FFmpeg可以去官网下载,也可以自己编译,编译方法可以参考我的博文。

Windows 7(Win7)下MinGW+msys编译ffmpeg,并加入H264编码支持

linux下交叉编译ffmpeg,并加入H264编码支持

linux下编译ffmpeg,并加入H264编码支持

下面是H264解码类

ch264decoder.h

  1. #ifndef CH264DECODER_H
  2. #define CH264DECODER_H
  3. #include <string.h>
  4. //C++引用C语言的头文件
  5. extern "C"
  6. {
  7. #include "libavformat/avformat.h"
  8. #include "libswresample/swresample.h"
  9. #include "libavutil/opt.h"
  10. #include "libavutil/channel_layout.h"
  11. #include "libavutil/parseutils.h"
  12. #include "libavutil/samplefmt.h"
  13. #include "libavutil/fifo.h"
  14. #include "libavutil/intreadwrite.h"
  15. #include "libavutil/dict.h"
  16. #include "libavutil/mathematics.h"
  17. #include "libavutil/pixdesc.h"
  18. #include "libavutil/avstring.h"
  19. #include "libavutil/imgutils.h"
  20. #include "libavcodec/avcodec.h"
  21. #include "libavfilter/avfilter.h"
  22. #include "libavfilter/buffersrc.h"
  23. #include "libavfilter/buffersink.h"
  24. }
  25. class CH264Decoder
  26. {
  27. public:
  28. CH264Decoder();
  29. ~CH264Decoder();
  30. /*************************************************
  31. Function:initial
  32. Description:初始化
  33. Input:无
  34. Output:无
  35. Return:错误代码
  36. Others:无
  37. *************************************************/
  38. int initial();
  39. /*************************************************
  40. Function:decode
  41. Description:解码
  42. Input:pDataIn-待解码数据,nInSize-待解码数据长度
  43. Output:pDataOut-解码后的数据,nWidth-解码后的图像宽度,nHeight-解码后的图像高度
  44. Return:错误代码
  45. Others:解码后的数据为RGB16格式
  46. *************************************************/
  47. int decode(uint8_t *pDataIn, int nInSize, uint8_t *pDataOut, int *nWidth, int *nHeight);
  48. /*************************************************
  49. Function:unInitial
  50. Description:销毁
  51. Input:无
  52. Output:无
  53. Return:无
  54. Others:无
  55. *************************************************/
  56. void unInitial();
  57. private:
  58. void deleteYUVTab();
  59. void createYUVTab_16();
  60. void displayYUV_16(unsigned int *pdst, unsigned char *y, unsigned char *u,unsigned char *v,
  61. int width, int height, int src_ystride, int src_uvstride, int dst_ystride);
  62. private:
  63. int *colortab;
  64. int *u_b_tab;
  65. int *u_g_tab;
  66. int *v_g_tab;
  67. int *v_r_tab;
  68. unsigned int *rgb_2_pix;
  69. unsigned int *r_2_pix;
  70. unsigned int *g_2_pix;
  71. unsigned int *b_2_pix;
  72. AVCodec *codec;
  73. AVCodecContext *context;
  74. AVFrame *frame;
  75. AVPacket packet;
  76. };
  77. #endif // CH264DECODER_H

ch264decoder.cpp

  1. #include "ch264decoder.h"
  2. #include <QDebug>
  3. CH264Decoder::CH264Decoder()
  4. {
  5. createYUVTab_16();
  6. }
  7. CH264Decoder::~CH264Decoder()
  8. {
  9. deleteYUVTab();
  10. }
  11. void CH264Decoder::deleteYUVTab()
  12. {
  13. av_free(colortab);
  14. av_free(rgb_2_pix);
  15. }
  16. void CH264Decoder::createYUVTab_16()
  17. {
  18. int i;
  19. int u, v;
  20. colortab = (int *)av_malloc(4*256*sizeof(int));
  21. u_b_tab = &colortab[0*256];
  22. u_g_tab = &colortab[1*256];
  23. v_g_tab = &colortab[2*256];
  24. v_r_tab = &colortab[3*256];
  25. for (i=0; i<256; i++)
  26. {
  27. u = v = (i-128);
  28. u_b_tab[i] = (int) ( 1.772 * u);
  29. u_g_tab[i] = (int) ( 0.34414 * u);
  30. v_g_tab[i] = (int) ( 0.71414 * v);
  31. v_r_tab[i] = (int) ( 1.402 * v);
  32. }
  33. rgb_2_pix = (unsigned int *)av_malloc(3*768*sizeof(unsigned int));
  34. r_2_pix = &rgb_2_pix[0*768];
  35. g_2_pix = &rgb_2_pix[1*768];
  36. b_2_pix = &rgb_2_pix[2*768];
  37. for(i=0; i<256; i++)
  38. {
  39. r_2_pix[i] = 0;
  40. g_2_pix[i] = 0;
  41. b_2_pix[i] = 0;
  42. }
  43. for(i=0; i<256; i++)
  44. {
  45. r_2_pix[i+256] = (i & 0xF8) << 8;
  46. g_2_pix[i+256] = (i & 0xFC) << 3;
  47. b_2_pix[i+256] = (i ) >> 3;
  48. }
  49. for(i=0; i<256; i++)
  50. {
  51. r_2_pix[i+512] = 0xF8 << 8;
  52. g_2_pix[i+512] = 0xFC << 3;
  53. b_2_pix[i+512] = 0x1F;
  54. }
  55. r_2_pix += 256;
  56. g_2_pix += 256;
  57. b_2_pix += 256;
  58. }
  59. void CH264Decoder::displayYUV_16(unsigned int *pdst, unsigned char *y, unsigned char *u, unsigned char *v, int width, int height, int src_ystride, int src_uvstride, int dst_ystride)
  60. {
  61. int i, j;
  62. int r, g, b, rgb;
  63. int yy, ub, ug, vg, vr;
  64. unsigned char* yoff;
  65. unsigned char* uoff;
  66. unsigned char* voff;
  67. int width2 = width/2;
  68. int height2 = height/2;
  69. for(j=0; j<height2; j++)
  70. {
  71. yoff = y + j * 2 * src_ystride;
  72. uoff = u + j * src_uvstride;
  73. voff = v + j * src_uvstride;
  74. for(i=0; i<width2; i++)
  75. {
  76. yy  = *(yoff+(i<<1));
  77. ub = u_b_tab[*(uoff+i)];
  78. ug = u_g_tab[*(uoff+i)];
  79. vg = v_g_tab[*(voff+i)];
  80. vr = v_r_tab[*(voff+i)];
  81. b = yy + ub;
  82. g = yy - ug - vg;
  83. r = yy + vr;
  84. rgb = r_2_pix[r] + g_2_pix[g] + b_2_pix[b];
  85. yy = *(yoff+(i<<1)+1);
  86. b = yy + ub;
  87. g = yy - ug - vg;
  88. r = yy + vr;
  89. pdst[(j*dst_ystride+i)] = (rgb)+((r_2_pix[r] + g_2_pix[g] + b_2_pix[b])<<16);
  90. yy = *(yoff+(i<<1)+src_ystride);
  91. b = yy + ub;
  92. g = yy - ug - vg;
  93. r = yy + vr;
  94. rgb = r_2_pix[r] + g_2_pix[g] + b_2_pix[b];
  95. yy = *(yoff+(i<<1)+src_ystride+1);
  96. b = yy + ub;
  97. g = yy - ug - vg;
  98. r = yy + vr;
  99. pdst [((2*j+1)*dst_ystride+i*2)>>1] = (rgb)+((r_2_pix[r] + g_2_pix[g] + b_2_pix[b])<<16);
  100. }
  101. }
  102. }
  103. int CH264Decoder::initial()
  104. {
  105. avcodec_register_all();
  106. av_init_packet(&packet);
  107. codec = avcodec_find_decoder(AV_CODEC_ID_H264);
  108. if (!codec)
  109. {
  110. printf("avcodec_find_encoder failed");
  111. return -1;
  112. }
  113. context = avcodec_alloc_context3(codec);
  114. if (!context)
  115. {
  116. printf("avcodec_alloc_context3 failed");
  117. return -2;
  118. }
  119. context->codec_type = AVMEDIA_TYPE_VIDEO;
  120. context->pix_fmt = AV_PIX_FMT_YUV420P;
  121. if (avcodec_open2(context, codec, NULL) < 0)
  122. {
  123. printf("avcodec_open2 failed");
  124. return -3;
  125. }
  126. frame = av_frame_alloc();
  127. if (!frame)
  128. {
  129. return -4;
  130. }
  131. return 0;
  132. }
  133. void CH264Decoder::unInitial()
  134. {
  135. avcodec_close(context);
  136. av_free(context);
  137. av_frame_free(&frame);
  138. }
  139. int CH264Decoder::decode(uint8_t *pDataIn, int nInSize, uint8_t *pDataOut,int *nWidth, int *nHeight)
  140. {
  141. av_init_packet(&packet);
  142. packet.size = nInSize;
  143. packet.data = pDataIn;
  144. if (packet.size > 0)
  145. {
  146. int got_picture=0;
  147. int ret= avcodec_decode_video2(context, frame, &got_picture, &packet);
  148. if (ret < 0)
  149. {
  150. printf("avcodec_encode_video2 failed");
  151. return -2;
  152. }
  153. if (got_picture)
  154. {
  155. *nWidth = context->width;
  156. *nHeight = context->height;
  157. displayYUV_16((unsigned int*)pDataOut, frame->data[0], frame->data[1],frame->data[2],
  158. *nWidth,*nHeight,frame->linesize[0],frame->linesize[2],*nWidth);
  159. }
  160. }
  161. else
  162. {
  163. printf("no data to decode");
  164. return -1;
  165. }
  166. return 0;
  167. }

使用方法,先调用initial()进行初始化,然后读取本地H264文件,调用decode()函数进行解码,退出时调用unInitial()函数释放资源。

需要注意的是,解码后的数据是RGB16格式,转换为QImage时,最后一个参数要用QImage::Format_RGB16,例如QImage image= QImage(outBuf, width, height, QImage::Format_RGB16);

下图是播放效果:

Qt基于FFmpeg播放本地 H.264(H264)文件(灿哥哥的博客)

演示用的H264文件下载链接:http://download.csdn.net/detail/caoshangpa/9492803

源码下载链接:见http://blog.csdn.net/caoshangpa/article/details/51953208的评论

Qt基于FFmpeg播放本地 H.264(H264)文件(灿哥哥的博客)