1#ifndef ENGINE_CLIENT_VIDEO_H
2#define ENGINE_CLIENT_VIDEO_H
3
4#include <base/lock.h>
5
6extern "C" {
7#include <libavcodec/avcodec.h>
8#include <libavformat/avformat.h>
9};
10
11#include <engine/shared/video.h>
12
13#include <atomic>
14#include <condition_variable>
15#include <mutex>
16#include <thread>
17#include <vector>
18#define ALEN 2048
19
20class CGraphics_Threaded;
21class ISound;
22class IStorage;
23
24extern CLock g_WriteLock;
25
26// a wrapper around a single output AVStream
27struct OutputStream
28{
29 AVStream *pSt = nullptr;
30 AVCodecContext *pEnc = nullptr;
31
32 /* pts of the next frame that will be generated */
33 int64_t NextPts = 0;
34 int64_t m_SamplesCount = 0;
35 int64_t m_SamplesFrameCount = 0;
36
37 std::vector<AVFrame *> m_vpFrames;
38 std::vector<AVFrame *> m_vpTmpFrames;
39
40 std::vector<struct SwsContext *> m_vpSwsCtxs;
41 std::vector<struct SwrContext *> m_vpSwrCtxs;
42};
43
44class CVideo : public IVideo
45{
46public:
47 CVideo(CGraphics_Threaded *pGraphics, ISound *pSound, IStorage *pStorage, int Width, int Height, const char *pName);
48 ~CVideo();
49
50 void Start() override REQUIRES(!g_WriteLock);
51 void Stop() override;
52 void Pause(bool Pause) override;
53 bool IsRecording() override { return m_Recording; }
54
55 void NextVideoFrame() override;
56 void NextVideoFrameThread() override;
57
58 void NextAudioFrame(ISoundMixFunc Mix) override;
59 void NextAudioFrameTimeline(ISoundMixFunc Mix) override;
60
61 static IVideo *Current() { return IVideo::ms_pCurrentVideo; }
62
63 static void Init() { av_log_set_level(AV_LOG_DEBUG); }
64
65private:
66 void RunVideoThread(size_t ParentThreadIndex, size_t ThreadIndex) REQUIRES(!g_WriteLock);
67 void FillVideoFrame(size_t ThreadIndex) REQUIRES(!g_WriteLock);
68 void ReadRGBFromGL(size_t ThreadIndex);
69
70 void RunAudioThread(size_t ParentThreadIndex, size_t ThreadIndex) REQUIRES(!g_WriteLock);
71 void FillAudioFrame(size_t ThreadIndex);
72
73 bool OpenVideo();
74 bool OpenAudio();
75 AVFrame *AllocPicture(enum AVPixelFormat PixFmt, int Width, int Height);
76 AVFrame *AllocAudioFrame(enum AVSampleFormat SampleFmt, uint64_t ChannelLayout, int SampleRate, int NbSamples);
77
78 void WriteFrame(OutputStream *pStream, size_t ThreadIndex) REQUIRES(g_WriteLock);
79 void FinishFrames(OutputStream *pStream);
80 void CloseStream(OutputStream *pStream);
81
82 bool AddStream(OutputStream *pStream, AVFormatContext *pOC, const AVCodec **ppCodec, enum AVCodecID CodecId) const;
83
84 CGraphics_Threaded *m_pGraphics;
85 IStorage *m_pStorage;
86 ISound *m_pSound;
87
88 int m_Width;
89 int m_Height;
90 char m_aName[256];
91 //FILE *m_dbgfile;
92 uint64_t m_VSeq = 0;
93 uint64_t m_ASeq = 0;
94 uint64_t m_Vframe;
95
96 int m_FPS;
97
98 bool m_Started;
99 bool m_Recording;
100
101 size_t m_VideoThreads = 2;
102 size_t m_CurVideoThreadIndex = 0;
103 size_t m_AudioThreads = 2;
104 size_t m_CurAudioThreadIndex = 0;
105
106 struct SVideoRecorderThread
107 {
108 std::thread m_Thread;
109 std::mutex m_Mutex;
110 std::condition_variable m_Cond;
111
112 bool m_Started = false;
113 bool m_Finished = false;
114 bool m_HasVideoFrame = false;
115
116 std::mutex m_VideoFillMutex;
117 std::condition_variable m_VideoFillCond;
118 uint64_t m_VideoFrameToFill = 0;
119 };
120
121 std::vector<std::unique_ptr<SVideoRecorderThread>> m_vVideoThreads;
122
123 struct SAudioRecorderThread
124 {
125 std::thread m_Thread;
126 std::mutex m_Mutex;
127 std::condition_variable m_Cond;
128
129 bool m_Started = false;
130 bool m_Finished = false;
131 bool m_HasAudioFrame = false;
132
133 std::mutex m_AudioFillMutex;
134 std::condition_variable m_AudioFillCond;
135 uint64_t m_AudioFrameToFill = 0;
136 int64_t m_SampleCountStart = 0;
137 };
138
139 std::vector<std::unique_ptr<SAudioRecorderThread>> m_vAudioThreads;
140
141 std::atomic<int32_t> m_ProcessingVideoFrame;
142 std::atomic<int32_t> m_ProcessingAudioFrame;
143
144 bool m_HasAudio;
145
146 struct SVideoSoundBuffer
147 {
148 int16_t m_aBuffer[ALEN * 2];
149 };
150 std::vector<SVideoSoundBuffer> m_vBuffer;
151 std::vector<std::vector<uint8_t>> m_vPixelHelper;
152
153 OutputStream m_VideoStream;
154 OutputStream m_AudioStream;
155
156 const AVCodec *m_pVideoCodec;
157 const AVCodec *m_pAudioCodec;
158
159 AVDictionary *m_pOptDict;
160
161 AVFormatContext *m_pFormatContext;
162 const AVOutputFormat *m_pFormat;
163};
164
165#endif
166