lbwave |
2010-10-21 13:05 |
不用SDL的QT+FFMPEG 播放器
#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
|
|