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