最简单的方式是直接使用qlable实现
#ifndef QWIDEGETPLAY_H#define QWIDEGETPLAY_H
#include <QWidget>
#include <QThread>
#include <QImage>
#include <QPainter>
#include <QDebug>
#include <QLabel>
extern "C" {
#pragma comment(lib,"avcodec.lib")
#pragma comment(lib,"avformat.lib")
#pragma comment(lib,"avutil.lib")
#pragma comment(lib,"swscale.lib")
#include "libavutil/avutil.h"
#include "libavformat/avformat.h"
#include "libavcodec/avcodec.h"
#include "libswscale/swscale.h"
#include "libavutil/imgutils.h"
#include "libavutil/opt.h"
}
QStringList ffGetStreamInfo(QString url);
class QWidegetRender : public QThread
{
Q_OBJECT
public:
QWidegetRender(QLabel* toRender,QObject *parent=0);
~QWidegetRender();
void startRender(QString playUrl);
void stopRender();
public slots:
void onImage();
void onFScreen();
signals:
void imageReady();
protected:
bool eventFilter(QObject *obj, QEvent *event);
protected:
virtual void run();
int create_swsContext(int iFFPixFmt);
int decode_packet(int *got_frame, int cached);
int open_codec_context(int *stream_idx, AVFormatContext *fmt_ctx, enum AVMediaType type);
static int ffInterrupt_callback(void* param);
private:
QLabel* m_Widget;
QPainter* painter;
bool m_bFullSrceen;
bool m_bStop;
AVFormatContext *fmt_ctx ;
AVCodecContext *video_dec_ctx ;
AVStream *video_stream ;
QString src_filename ;
SwsContext* sws_cxt;
uint8_t *video_dst_data[4] ;
int video_dst_linesize[4];
int video_dst_bufsize;
int video_stream_idx ;
AVFrame *frame ;
AVPacket pkt;
};
#endif // QWIDEGETPLAY_H
#include "qwidegetplay.h"#include <QEvent>#include "qproxyserver.h"#include <QMessageBox>QWidegetRender::QWidegetRender(QLabel* toRender,QObject *parent) : QThread(parent){ m_bStop = true; m_bFullSrceen = false; painter = new QPainter(toRender); m_Widget = toRender; connect(this,SIGNAL(imageReady()),this,SLOT(onImage()),Qt::BlockingQueuedConnection); //connect(m_Widget,SIGNAL(triggered()),this,SLOT(onFScreen())); //m_Widget->installEventFilter(this); }QWidegetRender::~QWidegetRender(){ if (!m_bStop) { stopRender(); } if (painter) { delete painter; }}void QWidegetRender::startRender(QString playUrl){ CRtspCheck rtspCheck; if (playUrl.isEmpty() || !rtspCheck.openUrl(playUrl)) { QMessageBox::information(NULL,"warnning",QStringLiteral("该链接无法播放")); return ; } src_filename = playUrl; if (!m_bStop) { stopRender(); } m_bStop = false; start();}void QWidegetRender::stopRender(){ disconnect(this,SIGNAL(imageReady()),this,SLOT(onImage())); // 防止wait阻塞主线程时,解码线程imageReady信号得不到处理而阻塞 m_bStop = true; if(isRunning() && !wait(10000)) { qDebug()<<"wait render thread failed"; } qDebug()<<"wait render thread ok"; connect(this,SIGNAL(imageReady()),this,SLOT(onImage()),Qt::BlockingQueuedConnection); QPixmap pixBlack(1,1); pixBlack.fill(Qt::black); m_Widget->setPixmap(pixBlack.scaled(m_Widget->width(),m_Widget->height())); }bool QWidegetRender::eventFilter(QObject *obj, QEvent *event){ if (obj == m_Widget && event->type()==QEvent::MouseButtonDblClick) { onFScreen(); return true; } else { return QObject::eventFilter(obj, event); }}void QWidegetRender::onFScreen(){ if (m_bStop) { return; } static int flags ; if (!m_bFullSrceen) { flags = m_Widget->windowFlags(); m_Widget->setWindowFlags(Qt::Dialog); m_Widget->showFullScreen(); } else { m_Widget->setWindowFlags((Qt::WindowFlags)flags); m_Widget->showNormal(); m_Widget->setGeometry(9,9,431,221); } m_bFullSrceen = !m_bFullSrceen;}struct st_dev_streamInfo{ QString width; QString heigt;};typedef st_dev_streamInfo st_dev_streamInfo;void QWidegetRender::run(){ qDebug()<<"render thread starting"; fmt_ctx = avformat_alloc_context(); video_dec_ctx=NULL ; video_stream=NULL ; sws_cxt=NULL; for (int i =0;i<4;i++) { video_dst_data[i]=NULL; video_dst_linesize[i] = NULL; } video_dst_bufsize = 0; video_stream_idx = 0; frame = NULL; AVInputFormat* fmtInput=NULL ; char deviceBuffer[256] ={0}; int ret = 0, got_frame; AVDictionary* options = NULL; //src_filename = "rtsp://192.168.0.134:8554/Video640x480@60fps"; //src_filename = "rtsp://admin:12345@192.168.0.6:1025/av_stream/ch1/main"; QByteArray arr = src_filename.toLatin1(); const char* playUrl = arr.data(); //QStringList wh = ffGetStreamInfo(src_filename); /* register all formats and codecs */ //av_register_all(); //avformat_network_init(); fmt_ctx->interrupt_callback.callback = QWidegetRender::ffInterrupt_callback; fmt_ctx->interrupt_callback.opaque = this; av_dict_set(&options, "rtsp_transport", "tcp", 0); if (avformat_open_input(&fmt_ctx, playUrl, NULL, &options) < 0) { fprintf(stderr, "Could not open source file %s\n", src_filename); goto end; } //void ** context ; //const AVOption* retOpt = av_opt_find2(&fmt_ctx,"udp","",0,AV_OPT_SEARCH_FAKE_OBJ,0); if (open_codec_context(&video_stream_idx, fmt_ctx, AVMEDIA_TYPE_VIDEO) >= 0) { video_stream = fmt_ctx->streams[video_stream_idx]; video_dec_ctx = video_stream->codec; } /* dump input information to stderr */ av_dump_format(fmt_ctx, 0, playUrl, 0); if (!video_stream) { fprintf(stderr, "Could not find video stream in the input, aborting\n"); ret = 1; goto end; } frame = avcodec_alloc_frame(); if (!frame) { fprintf(stderr, "Could not allocate frame\n"); ret = AVERROR(ENOMEM); goto end; } /* initialize packet, set data to NULL, let the demuxer fill it */ av_init_packet(&pkt); pkt.data = NULL; pkt.size = 0; int skipOneFrame = 0; /* read frames from the file */ while (av_read_frame(fmt_ctx, &pkt) >= 0) { decode_packet(&got_frame, 0); av_free_packet(&pkt); if (m_bStop) { qDebug()<<"render play stop, break loop..."; break; } } qDebug()<<"out of loop..."; /* flush cached frames */ pkt.data = NULL; pkt.size = 0; do { qDebug()<<"flush cached frames"; decode_packet(&got_frame, 1); } while (got_frame);end: qDebug()<<"play end, free resource..."; if (video_dec_ctx) avcodec_close(video_dec_ctx); if(fmt_ctx) avformat_close_input(&fmt_ctx); if(frame) av_free(frame); if(video_dst_data[0]) av_free(video_dst_data[0]); if(sws_cxt){ sws_freeContext(sws_cxt); sws_cxt = NULL; } qDebug()<<"render thread exit"; return ;}int QWidegetRender::create_swsContext(int iFFPixFmt){ int ret = 0; /* allocate image where the decoded image will be put */ ret = av_image_alloc(video_dst_data, video_dst_linesize, video_dec_ctx->width,video_dec_ctx->height, (AVPixelFormat)iFFPixFmt, 4); if (ret < 0) { fprintf(stderr, "Could not allocate raw video buffer\n"); return -1; } video_dst_bufsize = ret; sws_cxt = sws_getContext(video_dec_ctx->width,video_dec_ctx->height,video_dec_ctx->pix_fmt, video_dec_ctx->width,video_dec_ctx->height,(AVPixelFormat)iFFPixFmt,SWS_BILINEAR,NULL,NULL,NULL); return 0;}int QWidegetRender::decode_packet(int *got_frame, int cached){ int ret = 0; if (pkt.stream_index == video_stream_idx) { /* decode video frame */ ret = avcodec_decode_video2(video_dec_ctx, frame, got_frame, &pkt); if (ret < 0) { fprintf(stderr, "Error decoding video frame\n"); return ret; } if (*got_frame) { if(!sws_cxt){ create_swsContext(AV_PIX_FMT_RGB32); } sws_scale(sws_cxt, frame->data,frame->linesize,0,video_dec_ctx->height, video_dst_data,video_dst_linesize); emit imageReady(); } } return ret;}int QWidegetRender::open_codec_context(int *stream_idx, AVFormatContext *fmt_ctx, enum AVMediaType type){ int ret; AVStream *st; AVCodecContext *dec_ctx = NULL; AVCodec *dec = NULL; ret = av_find_best_stream(fmt_ctx, type, -1, -1, NULL, 0); if (ret < 0) { fprintf(stderr, "Could not find %s stream in input file '%s'\n", av_get_media_type_string(type), src_filename); return ret; } else { *stream_idx = ret; st = fmt_ctx->streams[*stream_idx]; /* find decoder for the stream */ dec_ctx = st->codec; dec = avcodec_find_decoder(dec_ctx->codec_id); if (!dec) { fprintf(stderr, "Failed to find %s codec\n", av_get_media_type_string(type)); return ret; } if ((ret = avcodec_open2(dec_ctx, dec, NULL)) < 0) { fprintf(stderr, "Failed to open %s codec\n", av_get_media_type_string(type)); return ret; } } return 0;}void QWidegetRender::onImage(){ //qDebug()<<"onImage()" <<m_Widget->width()<< " " <<m_Widget->height(); QImage image(video_dst_data[0],video_dec_ctx->width,video_dec_ctx->height,QImage::Format_RGB32); QImage destImage = image.scaled(m_Widget->width(),m_Widget->height(),Qt::IgnoreAspectRatio); m_Widget->setPixmap(QPixmap::fromImage(destImage)); //m_Widget->setPixmap(QPixmap::fromImage(image));}int QWidegetRender::ffInterrupt_callback(void* param){ QWidegetRender* pThis = (QWidegetRender*)param; if (pThis) { if (pThis->m_bStop) return 1; else return 0; } return 1;}QStringList ffGetStreamInfo(QString url){ QStringList result; result<<"0"<<"0"; AVFormatContext* fmt_ctx = NULL; AVDictionary* options = NULL; QByteArray arr = url.toLatin1(); const char* playUrl = arr.data(); av_dict_set(&options, "rtsp_transport", "tcp", 0); if (avformat_open_input(&fmt_ctx, playUrl, NULL, &options) < 0) { qDebug()<<"avformat_open_input error!"; return result; } if (avformat_find_stream_info(fmt_ctx,NULL) < 0) { qDebug()<<"avformat_find_stream_info error!"; if(&fmt_ctx) avformat_close_input(&fmt_ctx); return result; } for (int i = 0; i < fmt_ctx->nb_streams;i++) { AVStream* pstream = fmt_ctx->streams[i]; if (pstream) { AVCodecContext* pCodec = pstream->codec; if (pCodec && pCodec->codec_type == AVMEDIA_TYPE_VIDEO) { QString width; QString heigt; width.setNum(pCodec->width); heigt.setNum(pCodec->height); result[0] = width; result[1] = heigt; } } } if(&fmt_ctx) avformat_close_input(&fmt_ctx); return result ;}