利用ffmpeg实现视频播放QT界面如何实现音频视频同步

0 471
索鸟 2021-03-16
需要:0索币

#ifndef QFFMPEG_H
#define QFFMPEG_H
/*
write by :lbwave@sina.com
QT+ffmpeg
1、不用SDL的理由
   SDL是为游戏开发的,大量的依赖硬件加速。不用sdl是为了能方便的将程序移植到其他的平台 。
   本人受条件限制未向其他系统移植。但由于没采用QT(ffmpeg)之外的其他第三方代码,相信
   移植是个很小的问题。本人曾经做过arm920+qt+linux(fambuffer)的开发。
   本程序仅用了Qwideg来显示,就是为了移植方便。ffmpeg用C写的可以向多种平台移植。
2、如何实现音频视频同步
    本范例采用系统时钟作为主时钟,用音频时钟校正主时钟。
3、如何实现多趋缓冲
    本范例采用多线程处理机制。
    1、QFfmpeg :主要负责读取数据包,存入QList列表.压缩前的数据占用空间小。缓冲大小可设,按视频帧数和声卡缓冲大小决定
    2、QAudioThread:音频解码
    3、QVideoThread:视频解码
    4、QFfPlay :播放 (没有用定时器,定时器误差太大)
4、本范例实现QT+ffmpeg播放器的基本功能,仅出于爱好开发,未进行系统排错,用于大家参考交流。
    在开发期间参考了ffplay 。
  5、实现在QT4.6 QT4.7forwindows版编译运行,内存无重大泄露。


*/
#include <QThreadPool>
#include <QRunnable>
#include <QWidget>
#include <QAudioDeviceInfo>
#include <QAudioOutput>
#include <QAudioFormat>
#include <QThread>
#include <QImage>
#include <QMutex>
#include <QTime>
#include <QPainter>
#include <QIODevice>
#include <QWaitCondition>
#include <QSemaphore>
#include <QReadWriteLock>
#include <QDebug>


#include <stdlib.h>
#include <stdio.h>
#include <memory.h>//注意要包含此头文件与qDebug函数相关
#include <stdint.h>
#include <QList>


extern "C"
{
//ffmpeg相关的头文件
#include <libavcodec/avcodec.h>
#include <libavutil/common.h>
#include <libavutil/avstring.h>
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libswscale/swscale.h>
#include <libavcodec/opt.h>
#include <libavformat/avio.h>



//#include <libavdevice/avdevice.h>

}
//播放信息

#define DEFAULT_IMAGEFMT QImage::Format_RGB32
#define DEFAULT_FRAMEFMT PIX_FMT_RGB32
#define MAX_AUDIO_DIFFTIME 1000000  //音频时间差,最大值
#define AUDIOBUFFERSIZE (AVCODEC_MAX_AUDIO_FRAME_SIZE * 3) / 2 //音频缓冲大小
#define MAX_BUFFER 50


class QMasterClock //主时钟
{
public:
    QMasterClock();
    void adjusttime(int us);
    qint64 getuscurtime();
    void setstarttime(QTime t);
protected:
    QReadWriteLock m;
    QTime starttime;

};

class QDecodecThread : public QThread
{
    Q_OBJECT
public:
    QDecodecThread(AVFormatContext *f,AVCodecContext *c,QMasterClock *cl,int index,QObject *parent=0);
    ~QDecodecThread();
    void run()=0;

    void setstreamindex(const int index);
    int getstreamindex() ;
    int getusdtime() ;
    void setusdtime(int dt);
    void setisend(const bool b);
    void lockdata();
    void unlockdata();
    int getcount() ;
    void putpacket(AVPacket *p);
    void free_packet(AVPacket *p);
    AVPacket* getpacket();
    qint64 getus(qint64 t);
    QSemaphore sempfree;

protected:
    AVCodecContext *actx; //解码器
    AVFormatContext  *formatctx;
    int stream_index;

    QMasterClock *masterclock;
    QSemaphore semp;

    bool isend;

    QList <AVPacket*> pkts;

    int usdtime;//时间差值,用于修正主时钟
    QMutex mutex;
    qint64 basetime;
};


class QAudioThread : public QDecodecThread
{
    Q_OBJECT
public:
    QAudioThread(AVFormatContext *f,AVCodecContext *c,QMasterClock *cl,int index,QObject *parent=0);
    ~QAudioThread();
    QAudioOutput* getaudio();
    void run();
    void play();
    int ffsampleratetoint(const SampleFormat sf);
    qint64 caltime(const uint64_t pts);
public slots:
  void notified();
  void audiostate(QAudio::State state);
protected:
   int writeaudio(char *data ,const int size);

    QAudioOutput *audio;
    QIODevice *audioIO;


};

class QVideoThread : public QDecodecThread
{
   Q_OBJECT
public:
   QVideoThread(AVFormatContext *f, AVCodecContext *c,QMasterClock *cl,int index,QObject *parent=0);
   ~QVideoThread();
   qint64 getframebuffer(char *data);
   int getwidth() const;
   int getheight() const;
   int getframesize();
   void run();

protected:
   SwsContext *m_img_convert_ctx;//图像转换设置

   char *framebuffer;
   int framebuffersize;
   qint64 pts;

   QWaitCondition videowait;


private:
   AVFrame *yuvframe;
   AVFrame *rgbframe;
};

class QSubtitleThread : public QDecodecThread
{
    Q_OBJECT
public:
    QSubtitleThread(AVFormatContext *f,AVCodecContext *c,QMasterClock *cl,int index,QObject *parent=0)
        :QDecodecThread(f,c,cl,index,parent)
    {}
    void run(){}
};

class QFfWidget : public QWidget
{
    Q_OBJECT

public:
    explicit QFfWidget(QWidget *parent = 0);
    ~QFfWidget();
    void setframe(QImage *f);
    void lockframe();
    void unlockframe();
private:
    QImage *frame;
    QMutex m;
protected:
    void paintEvent(QPaintEvent *);

};

class QFfplay : public QThread
{
    Q_OBJECT
public:
    QFfplay(QVideoThread *v,QMasterClock *c, QObject *parent);
    ~QFfplay();
    QWidget* getwidget();
protected:
    void run();
    QVideoThread *video;
    QMasterClock *masterclock;
    QImage *frame;
    char *framebuffer;
    QFfWidget *widget;


};

class QFfmpeg : public QThread
{
    Q_OBJECT
public:
    explicit QFfmpeg(QObject *parent);
    //设置参数
    void seturl(QString url);

    bool open();
    void close();

    bool play();
    void stop();

    //判断视频是否结束
    bool atEnd();
    bool IsOpen();

    QWidget* getwidget();


signals:

public slots:

protected:

    void run();
private:
    /****解码相关******************/
    char m_url[255];
    SwsContext *m_img_convert_ctx;//图像转换设置

    AVFormatContext *m_pFormatctx; //视频流
    QAudioThread *m_audiocodec; //音频解码器
    QVideoThread *m_videocodec; //视频解码器
    QSubtitleThread *m_subtitlecodec; //字幕解码器

    QMasterClock masterclock;

    QImage *m_frame;
    uint8_t* framebuffer;//图象存储区 m_rgbframe m_frame 共享

    QMutex m_mutex;
    QFfplay *ffplay;
    bool m_isopen;

};

#endif // QFFMPEG_H

回帖
  • 消灭零回复
相关主题
2020年最新最新Kubernetes视频教程(K8s)教程 2
程序员转型之制作网课变现,月入过万告别996 1
索鸟快传2.0发布啦 1
两个不同网络的电脑怎么实现文件的互相访问呢? 1
网盘多账号登录软件 1
Java实战闲云旅游项目基于vue+element-ui 1
单点登录技术解决方案基于OAuth2.0的网关鉴权RSA算法生成令牌 1
QT5获取剪贴板上文本信息QT设置剪贴板内容 1
springboot2实战在线购物系统电商系统 1
python web实战之爱家租房项目 1
windows COM实用入门教程 1
C++游戏开发之C++实现的水果忍者游戏 1
计算机视觉库opencv教程 1
node.js实战图书管理系统express框架实现 1
C++实战教程之远程桌面远程控制实战 1
相关主题
PHP7报A non well formed numeric value encountered 0
Linux系统下关闭mongodb的几种命令分享 0
mongodb删除数据、删除集合、删除数据库的命令 0
Git&Github极速入门与攻坚实战课程 0
python爬虫教程使用Django和scrapy实现 0
libnetsnmpmibs.so.31: cannot open shared object file 0
数据结构和算法视频教程 0
redis的hash结构怎么删除数据呢? 0
C++和LUA解析器的数据交互实战视频 0
mongodb errmsg" : "too many users are authenticated 0
C++基础入门视频教程 0
用30个小时精通C++视频教程可能吗? 0
C++分布式多线程游戏服务器开发视频教程socket tcp boost库 0
C++培训教程就业班教程 0
layui的util工具格式时间戳为字符串 0
C++实战教程之远程桌面远程控制实战 1
网络安全培训视频教程 0
LINUX_C++软件工程师视频教程高级项目实战 0
C++高级数据结构与算法视频教程 0
跨域问题很头疼?通过配置nginx轻松解决ajax跨域问题 0