UI
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include <QObject>
#include <QEvent>
#include <QString>
#include <QFileDialog>
#include <QImage>
namespace Ui {
class Widget;
}
class Widget : public QWidget
{
Q_OBJECT
public:
explicit Widget(QWidget *parent = 0);
~Widget();
bool eventFilter(QObject *obj, QEvent *event);
private:
Ui::Widget *ui;
QString filePath_;
private slots:
void OpenFile();
void Play();
void render(const QImage&);
void resizeImage(int w,int h);
void updateFinishLable();
};
#endif
#include "widget.h"
#include "ui_widget.h"
#include <QDebug>
#include <QMouseEvent>
#include <QPixmap>
#include <QImage>
#include <QListView>
#include <classl.h>
#include "ffmpegplay.h"
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
connect(ui->bt_choose,SIGNAL(clicked()),this,SLOT(OpenFile()));
connect(ui->bt_play,SIGNAL(clicked()),this,SLOT(Play()));
}
bool Widget::eventFilter(QObject *target, QEvent *event){
return false;
}
Widget::~Widget()
{
delete ui;
}
void Widget::OpenFile(){
QString filter = tr("mp4 file(*.mp4);;rmvb file(*.rmvb);;avi file(*.avi);;h264 file(*.h264)");
filePath_ = QFileDialog::getOpenFileName(this,tr("打开文件"),QString(),NULL);
int l = filePath_.lastIndexOf("/",-1);
ui->file_name->setText(filePath_.mid(l+1).prepend("将播放"));
}
void Widget::Play(){
int l = filePath_.lastIndexOf("/",-1);
ui->file_name->setText(filePath_.mid(l+1).prepend("正在播放"));
FFmpegPLay *ffmpegPLay = new FFmpegPLay(this,filePath_);
connect(ffmpegPLay,SIGNAL(calSize(int,int)),this, SLOT(resizeImage(int,int)));
connect(ffmpegPLay,SIGNAL(genImage(QImage)),this, SLOT(render(QImage)));
connect(ffmpegPLay,SIGNAL(palyFinished()),this,SLOT(updateFinishLable()));
ffmpegPLay->play();
}
void Widget::render(const QImage& img){
ui->video_surface->setPixmap(QPixmap::fromImage(img));
}
void Widget::resizeImage(int w,int h){
ui->video_surface->setStyleSheet("QLabel{background:#000000;}");
ui->video_surface->setAlignment(Qt::AlignCenter);
ui->video_surface->resize(w+10,h+5);
}
void Widget::updateFinishLable(){
int l = filePath_.lastIndexOf("/",-1);
ui->file_name->setText(filePath_.mid(l+1).append("已播完"));
}
解码与渲染
FFmpegPLay.h
#ifndef FFMPEGPLAY_H
#define FFMPEGPLAY_H
#ifdef __cplusplus
#include <QString>
#include <QMessageBox>
#include <QDebug>
#include <QObject>
#include <QImage>
#include <QTime>
#include <QCoreApplication>
extern "C" {
#endif
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavutil/imgutils.h>
#include <libswresample/swresample.h>
#include <libswscale/swscale.h>
#ifdef __cplusplus
}
#endif
class FFmpegPLay : public QObject
{
Q_OBJECT
public:
explicit FFmpegPLay(QObject *parent,QString& h264File);
void play();
static void* render(void *);
public:
QString filePath_;
private:
void playInternal();
signals:
void calSize(int w,int h);
void genImage(const QImage &img);
void palyFinished();
};
#endif
FFmpegPLay.cpp
FFmpegPLay::FFmpegPLay(QObject *parent,QString& h264File): QObject(parent)
{
filePath_ = h264File
}
void* FFmpegPLay::render(void *argp){
FFmpegPLay *p = static_cast<FFmpegPLay*>(argp)
p->playInternal()
}
void FFmpegPLay::play()
{
pthread_t tid
pthread_create(&tid,NULL,render,this)
}
void FFmpegPLay::playInternal()
{
if (filePath_.isEmpty())
{
QMessageBox::warning(nullptr,"warn","未选择文件",QMessageBox::Ok)
return
}
std::string input_file=filePath_.toStdString()
av_register_all()
AVFormatContext *pFormatCtx = avformat_alloc_context()
if (avformat_open_input(&pFormatCtx,input_file.c_str(),nullptr,nullptr) < 0)
{
qDebug() << "fail to find the stream\n"
return
}
if (avformat_find_stream_info(pFormatCtx,NULL) < 0)
{
qDebug() << "fail to find the stream info\n"
return
}
// av_dump_format(pFormatCtx,0,input_file.c_str(),0)
int video_stream_index = -1
for (size_t i =0
{
if (pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO)
{
video_stream_index = i
break
}
}
if (video_stream_index == -1)
{
qDebug() << "fail to find the video stream"
return
}
AVCodecContext *pCodecCtx = pFormatCtx->streams[video_stream_index]->codec
AVCodec *pCodec = avcodec_find_decoder(pCodecCtx->codec_id)
if (pCodec == NULL)
{
qDebug() << "fail to find the decoder\n"
return
}
if (avcodec_open2(pCodecCtx,pCodec,nullptr) < 0 )
{
qDebug() << "fail to open the decodec\n"
return
}
AVFrame *pFrame = av_frame_alloc()
AVFrame *pframeRGB = av_frame_alloc()
unsigned char *out_buffer = (unsigned char*)av_malloc(av_image_get_buffer_size(AV_PIX_FMT_RGB32,pCodecCtx->width,pCodecCtx->height,1))
av_image_fill_arrays(pframeRGB->data,pframeRGB->linesize,out_buffer,AV_PIX_FMT_RGB32,pCodecCtx->width,pCodecCtx->height,1)
AVPacket *pkt = av_packet_alloc()
av_init_packet(pkt)
SwsContext *pSwsCtx = sws_alloc_context()
emit calSize(pCodecCtx->width,pCodecCtx->height)
pSwsCtx = sws_getContext(pCodecCtx->width,pCodecCtx->height,pCodecCtx->pix_fmt,
pCodecCtx->width,pCodecCtx->height,AV_PIX_FMT_RGB32,
SWS_BICUBIC,nullptr,nullptr,nullptr)
int got_frame = 0
while(av_read_frame(pFormatCtx,pkt) >= 0)
{
if (pkt->stream_index == video_stream_index){
int ret = avcodec_decode_video2(pCodecCtx,pFrame,&got_frame,pkt)
if (ret < 0)
{
qDebug() << "fail to decode video\n"
return
}
if (got_frame > 0)
{
sws_scale(pSwsCtx,(const unsigned char* const*)pFrame->data,pFrame->linesize,0,pCodecCtx->height,pframeRGB->data,pframeRGB->linesize)
QImage image = QImage((unsigned char*)pframeRGB->data[0],pCodecCtx->width,pCodecCtx->height,QImage::Format_RGB32,nullptr,nullptr)
emit genImage(image)
usleep(30000)
}
}
av_packet_unref(pkt)
}
sws_freeContext(pSwsCtx)
av_packet_free(&pkt)
avformat_close_input(&pFormatCtx)
avformat_free_context(pFormatCtx)
emit palyFinished()
}
测试结果
