您的位置:首页 > 编程语言 > Qt开发

Qt基于FFmpeg播放本地 H.264(H264)文件

2016-07-19 11:06 603 查看
最近在弄H264的硬件编解码,基于DM3730,但是为了调试方便,在小红帽上用FFmpeg实现了H264的软件编解码。现在弄了一个Windows的例子,给需要的同学参考一下,如果大家觉得有帮助,可以小手一抖,帮我点个赞



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

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

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

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

下面是H264解码类

ch264decoder.h

#ifndef CH264DECODER_H
#define CH264DECODER_H

#include <string.h>
//C++引用C语言的头文件
extern "C"
{
#include "libavformat/avformat.h"
#include "libswresample/swresample.h"
#include "libavutil/opt.h"
#include "libavutil/channel_layout.h"
#include "libavutil/parseutils.h"
#include "libavutil/samplefmt.h"
#include "libavutil/fifo.h"
#include "libavutil/intreadwrite.h"
#include "libavutil/dict.h"
#include "libavutil/mathematics.h"
#include "libavutil/pixdesc.h"
#include "libavutil/avstring.h"
#include "libavutil/imgutils.h"
#include "libavcodec/avcodec.h"
#include "libavfilter/avfilter.h"
#include "libavfilter/buffersrc.h"
#include "libavfilter/buffersink.h"
}

class CH264Decoder
{
public:
CH264Decoder();
~CH264Decoder();
/*************************************************
Function:initial
Description:初始化
Input:无
Output:无
Return:错误代码
Others:无
*************************************************/
int initial();
/*************************************************
Function:decode
Description:解码
Input:pDataIn-待解码数据,nInSize-待解码数据长度
Output:pDataOut-解码后的数据,nWidth-解码后的图像宽度,nHeight-解码后的图像高度
Return:错误代码
Others:解码后的数据为RGB16格式
*************************************************/
int decode(uint8_t *pDataIn, int nInSize, uint8_t *pDataOut, int *nWidth, int *nHeight);
/*************************************************
Function:unInitial
Description:销毁
Input:无
Output:无
Return:无
Others:无
*************************************************/
void unInitial();

private:
void deleteYUVTab();
void createYUVTab_16();
void 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);
private:
int *colortab;
int *u_b_tab;
int *u_g_tab;
int *v_g_tab;
int *v_r_tab;

unsigned int *rgb_2_pix;
unsigned int *r_2_pix;
unsigned int *g_2_pix;
unsigned int *b_2_pix;

AVCodec *codec;
AVCodecContext *context;
AVFrame *frame;
AVPacket packet;
};

#endif // CH264DECODER_H
ch264decoder.cpp
#include "ch264decoder.h"
#include <QDebug>

CH264Decoder::CH264Decoder()
{
createYUVTab_16();
}

CH264Decoder::~CH264Decoder()
{
deleteYUVTab();
}

void CH264Decoder::deleteYUVTab()
{
av_free(colortab);
av_free(rgb_2_pix);
}

void CH264Decoder::createYUVTab_16()
{
int i;
int u, v;

colortab = (int *)av_malloc(4*256*sizeof(int));
u_b_tab = &colortab[0*256];
u_g_tab = &colortab[1*256];
v_g_tab = &colortab[2*256];
v_r_tab = &colortab[3*256];

for (i=0; i<256; i++)
{
u = v = (i-128);

u_b_tab[i] = (int) ( 1.772 * u);
u_g_tab[i] = (int) ( 0.34414 * u);
v_g_tab[i] = (int) ( 0.71414 * v);
v_r_tab[i] = (int) ( 1.402 * v);
}

rgb_2_pix = (unsigned int *)av_malloc(3*768*sizeof(unsigned int));

r_2_pix = &rgb_2_pix[0*768];
g_2_pix = &rgb_2_pix[1*768];
b_2_pix = &rgb_2_pix[2*768];

for(i=0; i<256; i++)
{
r_2_pix[i] = 0;
g_2_pix[i] = 0;
b_2_pix[i] = 0;
}

for(i=0; i<256; i++)
{
r_2_pix[i+256] = (i & 0xF8) << 8;
g_2_pix[i+256] = (i & 0xFC) << 3;
b_2_pix[i+256] = (i ) >> 3;
}

for(i=0; i<256; i++)
{
r_2_pix[i+512] = 0xF8 << 8;
g_2_pix[i+512] = 0xFC << 3;
b_2_pix[i+512] = 0x1F;
}

r_2_pix += 256;
g_2_pix += 256;
b_2_pix += 256;
}

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)
{
int i, j;
int r, g, b, rgb;

int yy, ub, ug, vg, vr;

unsigned char* yoff;
unsigned char* uoff;
unsigned char* voff;

int width2 = width/2;
int height2 = height/2;

for(j=0; j<height2; j++)
{
yoff = y + j * 2 * src_ystride;
uoff = u + j * src_uvstride;
voff = v + j * src_uvstride;

for(i=0; i<width2; i++)
{
yy  = *(yoff+(i<<1));
ub = u_b_tab[*(uoff+i)];
ug = u_g_tab[*(uoff+i)];
vg = v_g_tab[*(voff+i)];
vr = v_r_tab[*(voff+i)];

b = yy + ub;
g = yy - ug - vg;
r = yy + vr;

rgb = r_2_pix[r] + g_2_pix[g] + b_2_pix[b];

yy = *(yoff+(i<<1)+1);
b = yy + ub;
g = yy - ug - vg;
r = yy + vr;

pdst[(j*dst_ystride+i)] = (rgb)+((r_2_pix[r] + g_2_pix[g] + b_2_pix[b])<<16);

yy = *(yoff+(i<<1)+src_ystride);
b = yy + ub;
g = yy - ug - vg;
r = yy + vr;

rgb = r_2_pix[r] + g_2_pix[g] + b_2_pix[b];

yy = *(yoff+(i<<1)+src_ystride+1);
b = yy + ub;
g = yy - ug - vg;
r = yy + vr;

pdst [((2*j+1)*dst_ystride+i*2)>>1] = (rgb)+((r_2_pix[r] + g_2_pix[g] + b_2_pix[b])<<16);
}
}
}
int CH264Decoder::initial()
{
avcodec_register_all();
av_init_packet(&packet);

codec = avcodec_find_decoder(AV_CODEC_ID_H264);
if (!codec)
{
printf("avcodec_find_encoder failed");
return -1;
}

context = avcodec_alloc_context3(codec);
if (!context)
{
printf("avcodec_alloc_context3 failed");
return -2;
}

context->codec_type = AVMEDIA_TYPE_VIDEO;
context->pix_fmt = AV_PIX_FMT_YUV420P;

if (avcodec_open2(context, codec, NULL) < 0)
{
printf("avcodec_open2 failed");
return -3;
}

frame = av_frame_alloc();
if (!frame)
{
return -4;
}

return 0;
}

void CH264Decoder::unInitial()
{
avcodec_close(context);
av_free(context);
av_frame_free(&frame);
}

int CH264Decoder::decode(uint8_t *pDataIn, int nInSize, uint8_t *pDataOut,int *nWidth, int *nHeight)
{
av_init_packet(&packet);
packet.size = nInSize;
packet.data = pDataIn;

if (packet.size > 0)
{
int got_picture=0;
int ret= avcodec_decode_video2(context, frame, &got_picture, &packet);
if (ret < 0)
{
printf("avcodec_encode_video2 failed");
return -2;
}

if (got_picture)
{
*nWidth = context->width;
*nHeight = context->height;

displayYUV_16((unsigned int*)pDataOut, frame->data[0], frame->data[1],frame->data[2],
*nWidth,*nHeight,frame->linesize[0],frame->linesize[2],*nWidth);
}
}
else
{
printf("no data to decode");
return -1;
}

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

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

下图是播放效果:



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

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

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  ffmpeg h264 Qt h.264