-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathFFMpegSource.h
224 lines (167 loc) · 5.19 KB
/
FFMpegSource.h
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
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
#pragma once
#include <boost/thread.hpp>
#define __STDC_CONSTANT_MACROS
extern "C"
{
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavutil/avutil.h>
#include <libavutil/time.h>
#include <libavutil/parseutils.h>
#include <libavutil/opt.h>
#include <libswresample/swresample.h>
#include <libswscale/swscale.h>
}
struct FFMpegSourceInfo
{
bool *pCapturing;
XElement **data;
};
#define MAX_AUDIOQ_SIZE (5 * 16 * 1024)
#define MAX_VIDEOQ_SIZE (5 * 256 * 1024)
#define AV_SYNC_THRESHOLD 0.01
#define AUDIO_DIFF_AVG_NB 20
#define VIDEO_PICTURE_QUEUE_SIZE 1
enum {
AV_SYNC_AUDIO_MASTER,
AV_SYNC_VIDEO_MASTER,
AV_SYNC_EXTERNAL_MASTER,
AV_SYNC_DEFAULT = AV_SYNC_EXTERNAL_MASTER
};
struct VideoState;
struct PacketQueue {
PacketQueue()
: first_pkt(NULL), last_pkt(NULL), flushing(false), nb_packets(0), size(0)
{ }
~PacketQueue()
{ clear(); }
AVPacketList *first_pkt, *last_pkt;
volatile bool flushing;
int nb_packets;
int size;
boost::mutex mutex;
boost::condition_variable cond;
void put(AVPacket *pkt);
int get(AVPacket *pkt, VideoState *is);
void flush();
void clear();
};
struct VideoPicture {
VideoPicture() : pts(0.0)
{ }
std::vector<uint8_t> data;
double pts;
};
struct VideoState {
VideoState()
: format_ctx(NULL), av_sync_type(AV_SYNC_DEFAULT)
, external_clock_base(0.0)
, audio_st(NULL)
, video_st(NULL), frame_last_pts(0.0), frame_last_delay(0.0),
video_clock(0.0), sws_context(NULL), rgbaFrame(NULL), pictq_size(0),
pictq_rindex(0), pictq_windex(0)
, refresh_rate_ms(10), refresh(false), quit(false), display_ready(false)
{
// Register all formats and codecs
av_register_all();
}
~VideoState()
{ deinit(); }
int init(String filename);
void deinit();
int stream_open(int stream_index, AVFormatContext *pFormatCtx);
static void audio_thread_loop(VideoState *is);
static void video_thread_loop(VideoState *is);
static void decode_thread_loop(VideoState *is);
bool update(int screen_width, int screen_height);
void video_display();
void video_refresh_timer();
int queue_picture(AVFrame *pFrame, double pts);
double synchronize_video(AVFrame *src_frame, double pts);
static void video_refresh(VideoState *is);
/* TODO: template here get_audio_clock */
double get_audio_clock()
{ return NULL; }
double get_video_clock()
{ return this->frame_last_pts; }
double get_external_clock()
{ return ((uint64_t)av_gettime()-this->external_clock_base) / 1000000.0; }
double get_master_clock()
{
if(this->av_sync_type == AV_SYNC_VIDEO_MASTER)
return this->get_video_clock();
if(this->av_sync_type == AV_SYNC_AUDIO_MASTER)
return this->get_audio_clock();
return this->get_external_clock();
}
AVFormatContext* format_ctx;
int av_sync_type;
uint64_t external_clock_base;
AVStream** audio_st;
PacketQueue audioq;
AVStream** video_st;
double frame_last_pts;
double frame_last_delay;
double audio_clock;
double video_clock; ///<pts of last decoded frame / predicted pts of next decoded frame
PacketQueue videoq;
SwsContext* sws_context;
VideoPicture pictq[VIDEO_PICTURE_QUEUE_SIZE];
AVFrame* rgbaFrame; // used as buffer for the frame converted from its native format to RGBA
int pictq_size, pictq_rindex, pictq_windex;
boost::mutex pictq_mutex;
boost::condition_variable pictq_cond;
boost::thread parse_thread;
boost::thread video_thread;
boost::thread audio_thread;
boost::thread refresh_thread;
volatile int refresh_rate_ms;
volatile bool refresh;
volatile bool quit;
volatile bool display_ready;
Texture *texture;
};
class FFMpegSource;
class FFMpegAudioSource : public AudioSource
{
FFMpegSource *device;
UINT sampleSegmentSize, sampleFrameCount;
HANDLE hAudioMutex;
List<BYTE> sampleBuffer;
List<BYTE> outputBuffer;
protected:
virtual bool GetNextBuffer(void **buffer, UINT *numFrames, QWORD *timestamp);
virtual void ReleaseBuffer();
virtual CTSTR GetDeviceName() const;
public:
bool Initialize(FFMpegSource *parent);
~FFMpegAudioSource();
void writeSample(uint8_t *data, int length);
};
class FFMpegSource : public ImageSource
{
bool bRandom;
bool bRepeat;
UINT renderCX, renderCY;
FFMpegAudioSource *audioOut;
XElement *data;
StringList filesList;
int filesListIndex;
int dedicatedrate;
AVSampleFormat dedicatedformat;
int dedicatedlayout;
struct VideoState *vs;
public:
bool Init(XElement *data);
FFMpegSource();
~FFMpegSource();
void UpdateSettings();
void Preprocess();
void Render(const Vect2 &pos, const Vect2 &size);
void BeginScene();
void EndScene();
void Start();
void Stop();
static HWND hConfigWnd;
Vect2 GetSize() const {return Vect2(float(renderCX), float(renderCY));}
};