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
19class IGraphics;
20class ISound;
21class IStorage;
22
23extern CLock g_WriteLock;
24
25// a wrapper around a single output AVStream
26class COutputStream
27{
28public:
29 AVStream *m_pStream = nullptr;
30 AVCodecContext *m_pCodecContext = nullptr;
31
32 /* pts of the next frame that will be generated */
33 int64_t m_SamplesCount = 0;
34 int64_t m_SamplesFrameCount = 0;
35
36 std::vector<AVFrame *> m_vpFrames;
37 std::vector<AVFrame *> m_vpTmpFrames;
38
39 std::vector<struct SwsContext *> m_vpSwsContexts;
40 std::vector<struct SwrContext *> m_vpSwrContexts;
41};
42
43class CVideo : public IVideo
44{
45public:
46 CVideo(IGraphics *pGraphics, ISound *pSound, IStorage *pStorage, int Width, int Height, const char *pName);
47 ~CVideo();
48
49 bool Start() override REQUIRES(!g_WriteLock);
50 void Stop() override;
51 void Pause(bool Pause) override;
52 bool IsRecording() override { return m_Recording; }
53
54 void NextVideoFrame() override;
55 void NextVideoFrameThread() override;
56
57 void NextAudioFrame(ISoundMixFunc Mix) override;
58 void NextAudioFrameTimeline(ISoundMixFunc Mix) override;
59
60 static IVideo *Current() { return IVideo::ms_pCurrentVideo; }
61
62 static void Init();
63
64private:
65 void RunVideoThread(size_t ParentThreadIndex, size_t ThreadIndex) REQUIRES(!g_WriteLock);
66 void FillVideoFrame(size_t ThreadIndex) REQUIRES(!g_WriteLock);
67 void UpdateVideoBufferFromGraphics(size_t ThreadIndex);
68
69 void RunAudioThread(size_t ParentThreadIndex, size_t ThreadIndex) REQUIRES(!g_WriteLock);
70 void FillAudioFrame(size_t ThreadIndex);
71
72 bool OpenVideo();
73 bool OpenAudio();
74 AVFrame *AllocPicture(enum AVPixelFormat PixFmt, int Width, int Height);
75 AVFrame *AllocAudioFrame(enum AVSampleFormat SampleFmt, uint64_t ChannelLayout, int SampleRate, int NbSamples);
76
77 void WriteFrame(COutputStream *pStream, size_t ThreadIndex) REQUIRES(g_WriteLock);
78 void FinishFrames(COutputStream *pStream);
79 void CloseStream(COutputStream *pStream);
80
81 bool AddStream(COutputStream *pStream, AVFormatContext *pFormatContext, const AVCodec **ppCodec, enum AVCodecID CodecId) const;
82
83 IGraphics *m_pGraphics;
84 IStorage *m_pStorage;
85 ISound *m_pSound;
86
87 int m_Width;
88 int m_Height;
89 char m_aName[256];
90 uint64_t m_VideoFrameIndex = 0;
91 uint64_t m_AudioFrameIndex = 0;
92
93 int m_FPS;
94
95 bool m_Started;
96 bool m_Stopped;
97 bool m_Recording;
98
99 size_t m_VideoThreads = 2;
100 size_t m_CurVideoThreadIndex = 0;
101 size_t m_AudioThreads = 2;
102 size_t m_CurAudioThreadIndex = 0;
103
104 class CVideoRecorderThread
105 {
106 public:
107 std::thread m_Thread;
108 std::mutex m_Mutex;
109 std::condition_variable m_Cond;
110
111 bool m_Started = false;
112 bool m_Finished = false;
113 bool m_HasVideoFrame = false;
114
115 std::mutex m_VideoFillMutex;
116 std::condition_variable m_VideoFillCond;
117 uint64_t m_VideoFrameToFill = 0;
118 };
119
120 std::vector<std::unique_ptr<CVideoRecorderThread>> m_vpVideoThreads;
121
122 class CAudioRecorderThread
123 {
124 public:
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<CAudioRecorderThread>> m_vpAudioThreads;
140
141 std::atomic<int32_t> m_ProcessingVideoFrame;
142 std::atomic<int32_t> m_ProcessingAudioFrame;
143
144 bool m_HasAudio;
145
146 class CVideoBuffer
147 {
148 public:
149 std::vector<uint8_t> m_vBuffer;
150 };
151 std::vector<CVideoBuffer> m_vVideoBuffers;
152 class CAudioBuffer
153 {
154 public:
155 int16_t m_aBuffer[4096];
156 };
157 std::vector<CAudioBuffer> m_vAudioBuffers;
158
159 COutputStream m_VideoStream;
160 COutputStream m_AudioStream;
161
162 const AVCodec *m_pVideoCodec;
163 const AVCodec *m_pAudioCodec;
164
165 AVDictionary *m_pOptDict;
166
167 AVFormatContext *m_pFormatContext;
168 const AVOutputFormat *m_pFormat;
169};
170
171#endif
172