不用SDL 的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版编译运行,内存无重大泄露
cpp代码
- #ifndef QFFMPEG_H
- #define QFFMPEG_H
- #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 //音频时间差,最大值
- 1 #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
以上是代码实现。
【编辑推荐】