qt+FFMPEG(不需要SDL)

来源:互联网 发布:windows上pdf阅读器 编辑:程序博客网 时间:2024/06/06 18:56

#ifndef QFFMPEG_H
#define QFFMPEG_H
/*
 write by :lbwave@sina.com
 QT+ffmpeg
 大名顶顶的QT ffmpeg 我就不用说了。看看影音风暴、qq影音等现在的播放器动态库,你可以发现ffmpeg使用如此广泛。

 解决视频播放的步骤如下:
 1、流媒体的读入。
    视频流媒体大多都是音频和视频流混合。ffmpeg在读入流媒体后实际上已经把音频流和视频六分开了。详细解说见程序对AVFormatContext说明
 2、解码
 3、音频播放
 4、视频播放
 5、音视频同步

 解决了以上问题,你可以轻松的写一个播放器了。

 另外ffmpeg还支持读写功能的扩展、视频解码的扩展。本人在阅读ffmpeg部分源码后有很深的感触。一个用c写出来的程序,竟有如此好的结构。只能大叫佩服!!佩服!!...


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版编译运行,内存无重大泄露。

  本人愿提供源码和本人的研究感想,见
  http://item.taobao.com/item.htm?id=8177265819

 */
#define __STDC_CONSTANT_MACROS

#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 <QMessageBox>


#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;
    AVRational 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;
   qint64 lastpts;
};

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);
    ~QFfmpeg();
    //设置参数
    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

原创粉丝点击