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版編譯運行,內存無重大泄露。
作者郵箱 [email protected]
代碼片段(1)
[代碼] cpp代碼
001 |
#ifndef QFFMPEG_H |
002 |
#define QFFMPEG_H |
003 |
004 |
#include <QThreadPool> |
005 |
#include <QRunnable> |
006 |
#include <QWidget> |
007 |
#include <QAudioDeviceInfo> |
008 |
#include <QAudioOutput> |
009 |
#include <QAudioFormat> |
010 |
#include <QThread> |
011 |
#include <QImage> |
012 |
#include <QMutex> |
013 |
#include <QTime> |
014 |
#include <QPainter> |
015 |
#include <QIODevice> |
016 |
#include <QWaitCondition> |
017 |
#include <QSemaphore> |
018 |
#include <QReadWriteLock> |
019 |
#include <QDebug> |
020 |
021 |
022 |
#include <stdlib.h> |
023 |
#include <stdio.h> |
024 |
#include <memory.h>//注意要包含此頭文件與qDebug函數相關 |
025 |
#include <stdint.h> |
026 |
#include <QList> |
027 |
028 |
029 |
extern
"C" |
030 |
{ |
031 |
//ffmpeg相關的頭文件 |
032 |
#include <libavcodec/avcodec.h> |
033 |
#include <libavutil/common.h> |
034 |
#include <libavutil/avstring.h> |
035 |
#include <libavcodec/avcodec.h> |
036 |
#include <libavformat/avformat.h> |
037 |
#include <libswscale/swscale.h> |
038 |
#include <libavcodec/opt.h> |
039 |
#include <libavformat/avio.h> |
040 |
041 |
042 |
043 |
//#include <libavdevice/avdevice.h> |
044 |
045 |
} |
046 |
//播放信息 |
047 |
048 |
#define DEFAULT_IMAGEFMT QImage::Format_RGB32 |
049 |
#define DEFAULT_FRAMEFMT PIX_FMT_RGB32 |
050 |
#define MAX_AUDIO_DIFFTIME 1000000 //音頻時間差,最大值 |
051 |
#define AUDIOBUFFERSIZE (AVCODEC_MAX_AUDIO_FRAME_SIZE * 3) / 2 //音頻緩衝大小 |
052 |
#define MAX_BUFFER 50 |
053 |
054 |
055 |
class
QMasterClock //主時鐘 |
056 |
{ |
057 |
public : |
058 |
QMasterClock(); |
059 |
void
adjusttime( int
us); |
060 |
qint64 getuscurtime(); |
061 |
void
setstarttime(QTime t); |
062 |
protected : |
063 |
QReadWriteLock m; |
064 |
QTime starttime; |
065 |
066 |
}; |
067 |
068 |
class
QDecodecThread : public
QThread |
069 |
{ |
070 |
Q_OBJECT |
071 |
public : |
072 |
QDecodecThread(AVFormatContext *f,AVCodecContext *c,QMasterClock *cl, int
index,QObject *parent=0); |
073 |
~QDecodecThread(); |
074 |
void
run()=0; |
075 |
076 |
void
setstreamindex( const
int index); |
077 |
int
getstreamindex() ; |
078 |
int
getusdtime() ; |
079 |
void
setusdtime( int
dt); |
080 |
void
setisend( const
bool b); |
081 |
void
lockdata(); |
082 |
void
unlockdata(); |
083 |
int
getcount() ; |
084 |
void
putpacket(AVPacket *p); |
085 |
void
free_packet(AVPacket *p); |
086 |
AVPacket* getpacket(); |
087 |
qint64 getus(qint64 t); |
088 |
QSemaphore sempfree; |
089 |
090 |
protected : |
091 |
AVCodecContext *actx;
//解碼器 |
092 |
AVFormatContext *formatctx; |
093 |
int
stream_index; |
094 |
095 |
QMasterClock *masterclock; |
096 |
QSemaphore semp; |
097 |
098 |
bool
isend; |
099 |
100 |
QList <AVPacket*> pkts; |
101 |
102 |
int
usdtime; //時間差值,用於修正主時鐘 |
103 |
QMutex mutex; |
104 |
qint64 basetime; |
105 |
}; |
106 |
107 |
108 |
class
QAudioThread : public
QDecodecThread |
109 |
{ |
110 |
Q_OBJECT |
111 |
public : |
112 |
QAudioThread(AVFormatContext *f,AVCodecContext *c,QMasterClock *cl, int
index,QObject *parent=0); |
113 |
~QAudioThread(); |
114 |
QAudioOutput* getaudio(); |
115 |
void
run(); |
116 |
void
play(); |
117 |
int
ffsampleratetoint( const
SampleFormat sf); |
118 |
qint64 caltime( const
uint64_t pts); |
119 |
public
slots: |
120 |
void
notified(); |
121 |
void
audiostate(QAudio::State state); |
122 |
protected : |
123 |
int
writeaudio( char
*data , const
int size); |
124 |
125 |
QAudioOutput *audio; |
126 |
QIODevice *audioIO; |
127 |
128 |
129 |
}; |
130 |
131 |
class
QVideoThread : public
QDecodecThread |
132 |
{ |
133 |
Q_OBJECT |
134 |
public : |
135 |
QVideoThread(AVFormatContext *f, AVCodecContext *c,QMasterClock *cl, int
index,QObject *parent=0); |
136 |
~QVideoThread(); |
137 |
qint64 getframebuffer( char
*data); |
138 |
int
getwidth() const ; |
139 |
int
getheight() const ; |
140 |
int
getframesize(); |
141 |
void
run(); |
142 |
143 |
protected : |
144 |
SwsContext *m_img_convert_ctx; //圖像轉換設置 |
145 |
146 |
char
*framebuffer; |
147 |
int
framebuffersize; |
148 |
qint64 pts; |
149 |
150 |
QWaitCondition videowait; |
151 |
152 |
153 |
private : |
154 |
AVFrame *yuvframe; |
155 |
AVFrame *rgbframe; |
156 |
}; |
157 |
158 |
class
QSubtitleThread : public
QDecodecThread |
159 |
{ |
160 |
Q_OBJECT |
161 |
public : |
162 |
QSubtitleThread(AVFormatContext *f,AVCodecContext *c,QMasterClock *cl, int
index,QObject *parent=0) |
163 |
:QDecodecThread(f,c,cl,index,parent) |
164 |
{} |
165 |
void
run(){} |
166 |
}; |
167 |
168 |
class
QFfWidget : public
QWidget |
169 |
{ |
170 |
Q_OBJECT |
171 |
172 |
public : |
173 |
explicit
QFfWidget(QWidget *parent = 0); |
174 |
~QFfWidget(); |
175 |
void
setframe(QImage *f); |
176 |
void
lockframe(); |
177 |
void
unlockframe(); |
178 |
private : |
179 |
QImage *frame; |
180 |
QMutex m; |
181 |
protected : |
182 |
void
paintEvent(QPaintEvent *); |
183 |
184 |
}; |
185 |
186 |
class
QFfplay : public
QThread |
187 |
{ |
188 |
Q_OBJECT |
189 |
public : |
190 |
QFfplay(QVideoThread *v,QMasterClock *c, QObject *parent); |
191 |
~QFfplay(); |
192 |
QWidget* getwidget(); |
193 |
protected : |
194 |
void
run(); |
195 |
QVideoThread *video; |
196 |
QMasterClock *masterclock; |
197 |
QImage *frame; |
198 |
char
*framebuffer; |
199 |
QFfWidget *widget; |
200 |
201 |
202 |
}; |
203 |
204 |
class
QFfmpeg : public
QThread |
205 |
{ |
206 |
Q_OBJECT |
207 |
public : |
208 |
explicit
QFfmpeg(QObject *parent); |
209 |
//設置參數 |
210 |
void
seturl(QString url); |
211 |
212 |
bool
open(); |
213 |
void
close(); |
214 |
215 |
bool
play(); |
216 |
void
stop(); |
217 |
218 |
//判斷視頻是否結束 |
219 |
bool
atEnd(); |
220 |
bool
IsOpen(); |
221 |
222 |
QWidget* getwidget(); |
223 |
224 |
225 |
signals: |
226 |
227 |
public
slots: |
228 |
229 |
protected : |
230 |
231 |
void
run(); |
232 |
private : |
233 |
/****解碼相關******************/ |
234 |
char
m_url[255]; |
235 |
SwsContext *m_img_convert_ctx; //圖像轉換設置 |
236 |
237 |
AVFormatContext *m_pFormatctx;
//視頻流 |
238 |
QAudioThread *m_audiocodec;
//音頻解碼器 |
239 |
QVideoThread *m_videocodec;
//視頻解碼器 |
240 |
QSubtitleThread *m_subtitlecodec;
//字幕解碼器 |
241 |
242 |
QMasterClock masterclock; |
243 |
244 |
QImage *m_frame; |
245 |
uint8_t* framebuffer; //圖象存儲區 m_rgbframe m_frame 共享 |
246 |
247 |
QMutex m_mutex; |
248 |
QFfplay *ffplay; |
249 |
bool
m_isopen; |
250 |
251 |
}; |
252 |
253 |
#endif // QFFMPEG_H |