查看完整版本: [-- 不用SDL的QT+FFMPEG  播放器 --]

QTCN开发网 -> Qt代码秀 -> 不用SDL的QT+FFMPEG  播放器 [打印本页] 登录 -> 注册 -> 回复主题 -> 发表主题

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

藏锋 2011-02-21 03:58
你好厉害

藏锋 2011-02-21 03:58
牛人

cycloneii 2011-02-21 09:46
很好奇,如果不用SDL的话,ffmpeg解码出来的是yuv吧,当然你可以软件转换成rgb,然后用drawImage之类的函数画上去?可是如果这样的话,你进行了yuv转rgb和缩放两次运算,一旦原始图像和显示控件的大小相差太大,CPU占用率甚至有可能达到100%!
或者说你·采用的是其他方法,能说来听听吗?

lvguowei 2013-03-18 16:03
能把工程源码附上看看吗?

toby520 2013-04-14 21:05
表示关注

pbe_sedm 2013-05-03 22:26
可惜没有源码啊,楼主不是要炫耀技术的吧。

duduqq 2013-05-14 17:30
这楼主是要收钱的

jay860222 2013-05-16 19:01
敢放上源文件吗?只炫耀技术的话那就别发这种帖子了

neverdizzy 2013-08-15 10:15
音视频编解码 ffmpeg

cangyuegui 2013-09-16 18:28
您好 我现在做界面开发 虽然你的这个程序用的技术看起来不是很NB

但是起到了异常好的作用 尤其是那个图标我很喜欢

我现在刚刚重操旧业做起开发 很不是很上手 界面源代码您能否给我观摩一下呢

我的qq 1020607979 邮箱 cangyuegui@163.com
如果可以 谢谢您 不可以 也没有关系
谢谢

13592502109 2014-08-20 16:00
没有源码放这干嘛


查看完整版本: [-- 不用SDL的QT+FFMPEG  播放器 --] [-- top --]



Powered by phpwind v8.7 Code ©2003-2011 phpwind
Gzip disabled