基于qt,msvc2017-64bits,ffmpeg.opengl的播放器
zhangmeng
2021-03-03 4a6d9312cc1c9d62d66c4def71246d9faae29edb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
/**
 * 叶海辉
 * QQ群121376426
 * http://blog.yundiantech.com/
 */
 
#ifndef VIDEOPLAYER_H
#define VIDEOPLAYER_H
 
#include <QObject>
#include <QImage>
 
#include <thread>
#include <list>
 
extern "C"
{
    #include <libavcodec/avcodec.h>
    #include <libavformat/avformat.h>
    #include <libavutil/time.h>
    #include <libavutil/pixfmt.h>
    #include <libswscale/swscale.h>
    #include <libswresample/swresample.h>
    #include <libavutil/imgutils.h>
 
    #include <SDL.h>
    #include <SDL_audio.h>
    #include <SDL_types.h>
    #include <SDL_name.h>
    #include <SDL_main.h>
    #include <SDL_config.h>
}
 
#include "types.h"
#include "Mutex/Cond.h"
#include "EventHandle/VideoPlayerEventHandle.h"
 
#define SDL_AUDIO_BUFFER_SIZE 1024
#define AVCODEC_MAX_AUDIO_FRAME_SIZE 192000 // 1 second of 48khz 32bit audio
 
#define MAX_AUDIO_SIZE (50 * 20)
#define MAX_VIDEO_SIZE (25 * 20)
 
#define FLUSH_DATA "FLUSH"
 
/**
 * @brief The VideoPlayer class
 * 用到了c++11的语法,需要编译器开启c++11支持
 * 播放器类,纯c++实现,方便移植,与界面的交互通过回调函数的方式实现
 */
 
class VideoPlayer
{
public:
    virtual ~VideoPlayer(){}
 
    //获取视频总时间,单位微秒
    virtual int64_t getTotalTime();
    //开始播放,传入视频地址和视频厂家类型
    virtual bool startPlay(const std::string &filePath, int videoType = 0);
 
    bool initPlayer();//初始化播放器(必需要调用一次)
    bool replay(); //重新播放
    bool play(); //播放(用于暂停后,重新开始播放)
    bool pause(); //暂停播放
    bool stop(bool isWait = false); //停止播放-参数表示是否等待所有的线程执行完毕再返回
    void seek(int64_t pos); //单位是微秒
 
    void setMute(bool isMute);
    void setVolume(float value);
    float getVolume();
 
    double getCurrentTime();
    //setVideoPlayerCallBack 设置播放器回调函数
    void setVideoPlayerCallBack(VideoPlayerCallBack *pointer);
protected:
    virtual void decodeVideoThread();
private:
    virtual void readVideoFile(); //读取视频文件
    virtual int decodeAudioFrame(bool isBlock = false);
 
    static void sdlAudioCallBackFunc(void *userdata, Uint8 *stream, int len);
    void sdlAudioCallBack(Uint8 *stream, int len);
 
protected:
    std::string mFilePath; //视频文件路径
 
    VideoPlayerState mPlayerState; //播放状态
 
    ///音量相关变量
    bool  mIsMute;
    float mVolume; //音量 0~1 超过1 表示放大倍数
 
    /// 跳转相关的变量
    int             seek_req; //跳转标志
    int64_t         seek_pos; //跳转的位置 -- 微秒
    int             seek_flag_audio;//跳转标志 -- 用于音频线程中
    int             seek_flag_video;//跳转标志 -- 用于视频线程中
    double          seek_time; //跳转的时间(秒)  值和seek_pos是一样的
 
    ///播放控制相关
    bool mIsNeedPause; //暂停后跳转先标记此变量
    bool mIsPause;  //暂停标志
    bool mIsQuit;   //停止
    bool mIsReadFinished; //文件读取完毕
    bool mIsReadThreadFinished;
    bool mIsVideoThreadFinished; //视频解码线程
    bool mIsAudioThreadFinished; //音频播放线程
 
    ///音视频同步相关
    uint64_t mVideoStartTime; //开始播放视频的时间
    uint64_t mPauseStartTime; //暂停开始的时间
    double audio_clock; ///音频时钟
    double video_clock; ///<pts of last decoded frame / predicted pts of next decoded frame
    AVStream *mVideoStream; //视频流
    AVStream *mAudioStream; //音频流
 
    ///视频相关
    AVFormatContext *pFormatCtx;
    AVCodecContext *pCodecCtx;
    AVCodec *pCodec;
 
    ///音频相关
    AVCodecContext *aCodecCtx;
    AVCodec *aCodec;
    AVFrame *aFrame;
 
    ///以下变量用于音频重采样
    /// 由于ffmpeg解码出来后的pcm数据有可能是带平面的pcm,因此这里统一做重采样处理,
    /// 重采样成44100的16 bits 双声道数据(AV_SAMPLE_FMT_S16)
    AVFrame *aFrame_ReSample;
    SwrContext *swrCtx;
 
    enum AVSampleFormat in_sample_fmt; //输入的采样格式
    enum AVSampleFormat out_sample_fmt;//输出的采样格式 16bit PCM
    int in_sample_rate;//输入的采样率
    int out_sample_rate;//输出的采样率
    int audio_tgt_channels; ///av_get_channel_layout_nb_channels(out_ch_layout);
    unsigned int audio_buf_size;
    unsigned int audio_buf_index;
    DECLARE_ALIGNED(16,uint8_t,audio_buf) [AVCODEC_MAX_AUDIO_FRAME_SIZE * 4];
 
 
    ///视频帧队列
    Cond *mConditon_Video;
    std::list<AVPacket> mVideoPacktList;
    bool inputVideoQuene(const AVPacket &pkt);
    void clearVideoQuene();
 
    ///音频帧队列
    Cond *mConditon_Audio;
    std::list<AVPacket> mAudioPacktList;
    bool inputAudioQuene(const AVPacket &pkt);
    void clearAudioQuene();
 
    ///本播放器中SDL仅用于播放音频,不用做别的用途
    ///SDL播放音频相关
    SDL_AudioDeviceID mAudioID;
    int openSDL();
    void closeSDL();
 
    ///回调函数相关,主要用于输出信息给界面
protected:
    ///回调函数
    VideoPlayerCallBack *mVideoPlayerCallBack;
 
    ///打开文件失败
    void doOpenVideoFileFailed(const int &code = 0);
 
    ///打开sdl失败的时候回调此函数
    void doOpenSdlFailed(const int &code);
 
    ///获取到视频时长的时候调用此函数
    void doTotalTimeChanged(const int64_t &uSec);
 
    ///播放器状态改变的时候回调此函数
    void doPlayerStateChanged(const VideoPlayerState &state, const bool &hasVideo, const bool &hasAudio);
 
    ///显示视频数据,此函数不宜做耗时操作,否则会影响播放的流畅性。
    void doDisplayVideo(const uint8_t *yuv420Buffer, const int &width, const int &height);
 
};
 
 
#endif // VIDEOPLAYER_H