ddnet/src/engine/client/video.h

164 lines
4 KiB
C
Raw Normal View History

2016-08-27 15:51:23 +00:00
#ifndef ENGINE_CLIENT_VIDEO_H
#define ENGINE_CLIENT_VIDEO_H
2021-04-30 22:42:37 +00:00
#include <base/system.h>
extern "C" {
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libswresample/swresample.h>
#include <libswscale/swscale.h>
2016-08-27 15:51:23 +00:00
};
#include <engine/shared/video.h>
2022-03-20 17:03:25 +00:00
#include <atomic>
2022-03-02 08:32:51 +00:00
#include <condition_variable>
#include <mutex>
#include <thread>
2022-03-20 17:03:25 +00:00
#include <vector>
#define ALEN 2048
extern LOCK g_WriteLock;
2016-08-27 19:10:27 +00:00
// a wrapper around a single output AVStream
typedef struct OutputStream
{
2022-03-02 08:32:51 +00:00
AVStream *pSt = nullptr;
AVCodecContext *pEnc = nullptr;
2016-08-27 19:10:27 +00:00
/* pts of the next frame that will be generated */
2022-03-02 08:32:51 +00:00
int64_t NextPts = 0;
int64_t m_SamplesCount = 0;
int64_t m_SamplesFrameCount = 0;
2016-08-27 19:10:27 +00:00
2022-03-02 08:32:51 +00:00
std::vector<AVFrame *> m_vpFrames;
std::vector<AVFrame *> m_vpTmpFrames;
2016-08-27 19:10:27 +00:00
2022-03-02 08:32:51 +00:00
std::vector<struct SwsContext *> m_vpSwsCtxs;
std::vector<struct SwrContext *> m_vpSwrCtxs;
2016-08-27 19:10:27 +00:00
} OutputStream;
2016-08-27 15:51:23 +00:00
class CVideo : public IVideo
2016-08-27 15:51:23 +00:00
{
public:
2022-03-02 08:32:51 +00:00
CVideo(class CGraphics_Threaded *pGraphics, class ISound *pSound, class IStorage *pStorage, class IConsole *pConsole, int width, int height, const char *name);
2016-08-27 15:51:23 +00:00
~CVideo();
void Start() override REQUIRES(!g_WriteLock);
void Stop() override;
void Pause(bool Pause) override;
bool IsRecording() override { return m_Recording; }
void NextVideoFrame() override;
void NextVideoFrameThread() override;
2016-08-27 15:51:23 +00:00
void NextAudioFrame(ISoundMixFunc Mix) override;
void NextAudioFrameTimeline(ISoundMixFunc Mix) override;
2016-08-27 15:51:23 +00:00
static IVideo *Current() { return IVideo::ms_pCurrentVideo; }
2016-08-27 15:51:23 +00:00
2019-11-12 13:41:30 +00:00
static void Init() { av_log_set_level(AV_LOG_DEBUG); }
2016-08-27 19:10:27 +00:00
2016-08-27 15:51:23 +00:00
private:
void RunVideoThread(size_t ParentThreadIndex, size_t ThreadIndex) REQUIRES(!g_WriteLock);
void FillVideoFrame(size_t ThreadIndex) REQUIRES(!g_WriteLock);
2022-03-02 08:32:51 +00:00
void ReadRGBFromGL(size_t ThreadIndex);
2016-08-27 19:10:27 +00:00
void RunAudioThread(size_t ParentThreadIndex, size_t ThreadIndex) REQUIRES(!g_WriteLock);
2022-03-02 08:32:51 +00:00
void FillAudioFrame(size_t ThreadIndex);
bool OpenVideo();
bool OpenAudio();
AVFrame *AllocPicture(enum AVPixelFormat PixFmt, int Width, int Height);
2021-06-23 05:05:49 +00:00
AVFrame *AllocAudioFrame(enum AVSampleFormat SampleFmt, uint64_t ChannelLayout, int SampleRate, int NbSamples);
2016-08-27 19:10:27 +00:00
2022-03-02 08:32:51 +00:00
void WriteFrame(OutputStream *pStream, size_t ThreadIndex) REQUIRES(g_WriteLock);
void FinishFrames(OutputStream *pStream);
void CloseStream(OutputStream *pStream);
2016-08-27 19:10:27 +00:00
2022-01-17 23:30:34 +00:00
bool AddStream(OutputStream *pStream, AVFormatContext *pOC, const AVCodec **ppCodec, enum AVCodecID CodecId);
2016-08-27 15:51:23 +00:00
class CGraphics_Threaded *m_pGraphics;
class IStorage *m_pStorage;
2022-03-02 08:32:51 +00:00
class ISound *m_pSound;
2016-08-27 15:51:23 +00:00
int m_Width;
int m_Height;
char m_Name[256];
2019-10-31 14:01:12 +00:00
//FILE *m_dbgfile;
2022-03-02 08:32:51 +00:00
uint64_t m_VSeq = 0;
uint64_t m_ASeq = 0;
uint64_t m_Vframe;
2016-08-27 15:51:23 +00:00
int m_FPS;
bool m_Started;
2016-08-27 15:51:23 +00:00
bool m_Recording;
2022-03-02 08:32:51 +00:00
size_t m_VideoThreads = 2;
size_t m_CurVideoThreadIndex = 0;
size_t m_AudioThreads = 2;
size_t m_CurAudioThreadIndex = 0;
struct SVideoRecorderThread
{
std::thread m_Thread;
std::mutex m_Mutex;
std::condition_variable m_Cond;
bool m_Started = false;
bool m_Finished = false;
bool m_HasVideoFrame = false;
std::mutex m_VideoFillMutex;
std::condition_variable m_VideoFillCond;
uint64_t m_VideoFrameToFill = 0;
};
std::vector<std::unique_ptr<SVideoRecorderThread>> m_vVideoThreads;
struct SAudioRecorderThread
{
std::thread m_Thread;
std::mutex m_Mutex;
std::condition_variable m_Cond;
bool m_Started = false;
bool m_Finished = false;
bool m_HasAudioFrame = false;
std::mutex m_AudioFillMutex;
std::condition_variable m_AudioFillCond;
uint64_t m_AudioFrameToFill = 0;
int64_t m_SampleCountStart = 0;
};
std::vector<std::unique_ptr<SAudioRecorderThread>> m_vAudioThreads;
std::atomic<int32_t> m_ProcessingVideoFrame;
std::atomic<int32_t> m_ProcessingAudioFrame;
2016-08-27 19:10:27 +00:00
bool m_HasAudio;
2022-03-02 08:32:51 +00:00
struct SVideoSoundBuffer
{
int16_t m_aBuffer[ALEN * 2];
};
std::vector<SVideoSoundBuffer> m_vBuffer;
std::vector<std::vector<uint8_t>> m_vPixelHelper;
2016-08-27 15:51:23 +00:00
2016-08-27 19:10:27 +00:00
OutputStream m_VideoStream;
OutputStream m_AudioStream;
const AVCodec *m_pVideoCodec;
const AVCodec *m_pAudioCodec;
2016-08-27 19:10:27 +00:00
AVDictionary *m_pOptDict;
2016-08-27 19:10:27 +00:00
AVFormatContext *m_pFormatContext;
2022-01-17 23:30:34 +00:00
const AVOutputFormat *m_pFormat;
2016-08-27 15:51:23 +00:00
};
#endif