#include "qffmpeg.h"
|
#include <QDateTime>
|
#include <QDebug>
|
|
QFFmpeg::QFFmpeg(QObject *parent) :
|
QObject(parent)
|
{
|
videoStreamIndex=-1;
|
av_register_all();//注册库中所有可用的文件格式和解码器
|
avformat_network_init();//初始化网络流格式,使用RTSP网络流时必须先执行
|
pAVFormatContext = avformat_alloc_context();//申请一个AVFormatContext结构的内存,并进行简单初始化
|
pAVFrame=av_frame_alloc();
|
}
|
|
QFFmpeg::~QFFmpeg()
|
{
|
if (pAVFormatContext) {
|
avformat_close_input(&pAVFormatContext);
|
avformat_free_context(pAVFormatContext);
|
}
|
if (pAVFrame) {
|
av_frame_free(&pAVFrame);
|
}
|
if (pSwsContext) {
|
sws_freeContext(pSwsContext);
|
}
|
}
|
|
bool QFFmpeg::Init()
|
{
|
//打开视频流
|
int result=avformat_open_input(&pAVFormatContext, url.toStdString().c_str(),NULL,NULL);
|
if (result<0){
|
qDebug()<<"打开视频流失败";
|
return false;
|
}
|
|
//获取视频流信息
|
result=avformat_find_stream_info(pAVFormatContext,NULL);
|
if (result<0){
|
qDebug()<<"获取视频流信息失败";
|
avformat_close_input(&pAVFormatContext);
|
return false;
|
}
|
|
//获取视频流索引
|
videoStreamIndex = -1;
|
for (uint i = 0; i < pAVFormatContext->nb_streams; i++) {
|
if (pAVFormatContext->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
|
videoStreamIndex = i;
|
break;
|
}
|
}
|
|
if (videoStreamIndex==-1){
|
qDebug()<<"获取视频流索引失败";
|
avformat_close_input(&pAVFormatContext);
|
return false;
|
}
|
|
//获取视频流的分辨率大小
|
pAVCodecContext = pAVFormatContext->streams[videoStreamIndex]->codec;
|
videoWidth=pAVCodecContext->width;
|
videoHeight=pAVCodecContext->height;
|
|
AVCodec *pAVCodec;
|
|
//获取视频流解码器
|
pAVCodec = avcodec_find_decoder(pAVCodecContext->codec_id);
|
pSwsContext = sws_getContext(videoWidth,videoHeight,AV_PIX_FMT_YUV420P,videoWidth,videoHeight,AV_PIX_FMT_RGB24,SWS_BICUBIC,0,0,0);
|
|
//打开对应解码器
|
result=avcodec_open2(pAVCodecContext,pAVCodec,NULL);
|
if (result<0){
|
qDebug()<<"打开解码器失败";
|
sws_freeContext(pSwsContext);
|
avformat_close_input(&pAVFormatContext);
|
return false;
|
}
|
|
qDebug()<<"初始化视频流成功";
|
return true;
|
}
|
|
void QFFmpeg::Play()
|
{
|
AVPacket packet;
|
int frameFinished;
|
int videoStreamIndex = -1;
|
|
// 打开视频文件
|
if (avformat_open_input(&pAVFormatContext, url.toStdString().c_str(), NULL, NULL) != 0)
|
return;
|
|
// 获取流信息
|
avformat_find_stream_info(pAVFormatContext, NULL);
|
|
// 找到视频流索引
|
for (uint i = 0; i < pAVFormatContext->nb_streams; i++) {
|
if (pAVFormatContext->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
|
videoStreamIndex = i;
|
break;
|
}
|
}
|
|
// 获取解码器
|
AVCodec *codec = avcodec_find_decoder(pAVFormatContext->streams[videoStreamIndex]->codec->codec_id);
|
if (!codec) {
|
qDebug() << "未找到解码器";
|
return;
|
}
|
|
if (avcodec_open2(pAVCodecContext, codec, NULL) < 0) {
|
qDebug() << "打开解码器失败";
|
return;
|
}
|
|
// 初始化帧
|
pAVFrame = av_frame_alloc();
|
AVFrame *pFrameRGB = av_frame_alloc();
|
uint8_t *buffer = (uint8_t *)av_malloc(avpicture_get_size(AV_PIX_FMT_RGB24, pAVCodecContext->width, pAVCodecContext->height));
|
avpicture_fill((AVPicture *)pFrameRGB, buffer, AV_PIX_FMT_RGB24, pAVCodecContext->width, pAVCodecContext->height);
|
|
// 初始化缩放上下文
|
struct SwsContext *sws_ctx = sws_getContext(pAVCodecContext->width,
|
pAVCodecContext->height,
|
pAVCodecContext->pix_fmt,
|
pAVCodecContext->width,
|
pAVCodecContext->height,
|
AV_PIX_FMT_RGB24,
|
SWS_BILINEAR,
|
NULL,
|
NULL,
|
NULL);
|
|
while (av_read_frame(pAVFormatContext, &packet) >= 0) {
|
if (packet.stream_index == videoStreamIndex) {
|
avcodec_send_packet(pAVCodecContext, &packet);
|
|
while (avcodec_receive_frame(pAVCodecContext, pAVFrame) == 0) {
|
sws_scale(sws_ctx,
|
(const uint8_t **)pAVFrame->data,
|
pAVFrame->linesize,
|
0,
|
pAVCodecContext->height,
|
pFrameRGB->data,
|
pFrameRGB->linesize);
|
|
QImage img(pFrameRGB->data[0],
|
pAVCodecContext->width,
|
pAVCodecContext->height,
|
QImage::Format_RGB888);
|
|
emit GetImage(img, 0);
|
}
|
}
|
av_packet_unref(&packet);
|
}
|
|
avformat_close_input(&pAVFormatContext);
|
av_frame_free(&pAVFrame);
|
av_frame_free(&pFrameRGB);
|
av_free(buffer);
|
sws_freeContext(sws_ctx);
|
}
|