forked from zillevdr/vdr-plugin-softhddevice-drm
-
Notifications
You must be signed in to change notification settings - Fork 6
Expand file tree
/
Copy pathsofthddevice.h
More file actions
338 lines (289 loc) · 11.1 KB
/
softhddevice.h
File metadata and controls
338 lines (289 loc) · 11.1 KB
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
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
// SPDX-License-Identifier: AGPL-3.0-or-later
/**
* @file softhddevice.h
* Output Device Header File
*
* @copyright 2011 - 2015 by Johns. All Rights Reserved.
* @copyright 2025 - 2026 by Andreas Baierl. All Rights Reserved.
*
* @license{AGPL-3.0-or-later}
*/
#ifndef __SOFTHDDEVICE_H
#define __SOFTHDDEVICE_H
#if __cplusplus < 201703L
#error "C++17 or higher is required"
#endif
#include <atomic>
#include <mutex>
extern "C"
{
#include <libavcodec/avcodec.h>
}
#include <vdr/device.h>
#include <vdr/osd.h>
#include <vdr/status.h>
#include <vdr/thread.h>
#include "config.h"
#include "event.h"
#include "hardwaredevice.h"
#include "jittertracker.h"
#include "pes.h"
class cAudioDecoder;
class cDvbSpuDecoder;
class cPipHandler;
class cPipReceiver;
class cSpuDecoder;
class cSoftHdAudio;
class cSoftHdDevice;
class cSoftHdGrab;
class cSoftOsdProvider;
class cVideoRender;
class cVideoStream;
/**
* Output Device Implementation
* @defgroup device Device
*/
/**
* @addtogroup device
* @{
*/
// State machine definitions
// Implementing C++17 visitor pattern
template<class... Ts>
struct overload : Ts... { using Ts::operator()...; };
template<class... Ts> overload(Ts...) -> overload<Ts...>;
enum State {
STOP,
BUFFERING,
PLAY,
TRICK_SPEED,
DETACHED
};
inline const char* EventToString(const Event& e) {
return std::visit(overload{
[](const PlayEvent&) -> const char* { return "PlayEvent"; },
[](const PauseEvent&) -> const char* { return "PauseEvent"; },
[](const StopEvent&) -> const char* { return "StopEvent"; },
[](const TrickSpeedEvent&) -> const char* { return "TrickSpeedEvent"; },
[](const StillPictureEvent&) -> const char* { return "StillPictureEvent"; },
[](const DetachEvent&) -> const char* { return "DetachEvent"; },
[](const AttachEvent&) -> const char* { return "AttachEvent"; },
[](const BufferUnderrunEvent& e) -> const char* { return e.type == AUDIO ? "BufferUnderrunEvent: Audio" : "BufferUnderrunEvent: Video"; },
[](const BufferingThresholdReachedEvent&) -> const char* { return "BufferingThresholdReachedEvent"; },
[](const PipEvent&) -> const char* { return "PipEvent"; },
[](const ScheduleResyncAtPtsMsEvent&) -> const char* { return "ScheduleResyncAtPtsMsEvent"; },
[](const ResyncEvent&) -> const char* { return "ResyncEvent"; },
[](const DisplayChangeEvent&) -> const char* { return "DisplayChangeEvent"; },
}, e);
}
inline const char* StateToString(State s) {
switch(s) {
case State::STOP: return "STOP";
case State::BUFFERING: return "BUFFERING";
case State::PLAY: return "PLAY";
case State::TRICK_SPEED: return "TRICK_SPEED";
case State::DETACHED: return "DETACHED";
}
return "Unknown";
}
enum PlaybackMode {
NONE,
AUDIO_AND_VIDEO,
AUDIO_ONLY,
VIDEO_ONLY
};
/** @} */
/**
* Event handler thread
*
* Queues events and sends them to cSoftHdDevice as the final event receiver
*/
class cEventHandler : public cThread {
public:
cEventHandler(cSoftHdDevice *);
virtual ~cEventHandler(void);
void AddEvent(Event);
protected:
virtual void Action(void) override;
private:
cSoftHdDevice *m_pDevice; ///< pointer to device
std::mutex m_mutex; ///< queue mutex
std::vector<Event> m_eventQueue; ///< event fifo queue
IEventReceiver *m_pEventReceiver; ///< pointer to event receiver
};
/**
* Output Device Implementation
*
* @ingroup device
*/
class cSoftHdDevice : public cDevice, public IEventReceiver, public cStatus {
public:
cSoftHdDevice(cSoftHdConfig *);
virtual ~cSoftHdDevice(void);
//
// virtual cDevice
//
protected:
virtual void MakePrimaryDevice(bool);
virtual void ChannelSwitch(const cDevice *, int, bool);
public:
virtual cString DeviceName(void) const { return "softhddevice-drm-gles"; }
virtual bool HasDecoder(void) const;
// SPU facilities
virtual cSpuDecoder * GetSpuDecoder(void);
// player facilities
virtual bool CanReplay(void) const;
virtual bool SetPlayMode(ePlayMode);
virtual int PlayVideo(const uchar *, int);
virtual int PlayAudio(const uchar *, int, uchar);
virtual int64_t GetSTC(void);
virtual cRect CanScaleVideo(const cRect &, int taCenter);
virtual void ScaleVideo(const cRect & = cRect::Null);
virtual void TrickSpeed(int, bool);
virtual void Clear(void);
virtual void Play(void);
virtual void Freeze(void);
virtual void StillPicture(const uchar *, int);
virtual bool Poll(cPoller &, int = 0);
virtual bool Flush(int = 0);
// Image Grab facilities
virtual uchar *GrabImage(int &, bool, int, int, int);
// video format facilities
virtual void SetVideoDisplayFormat(eVideoDisplayFormat);
virtual void SetVideoFormat(bool);
virtual void GetVideoSize(int &, int &, double &);
virtual void GetOsdSize(int &, int &, double &);
// track facilities
virtual void SetAudioTrackDevice(eTrackType);
// audio facilities
virtual int GetAudioChannelDevice(void);
virtual void SetAudioChannelDevice(int);
virtual void SetVolumeDevice(int);
virtual void SetDigitalAudioDevice(bool);
//
// wrapped by cPluginSoftHdDevice
//
bool Initialize(void);
int Start(void);
void Stop(void);
//
// cSoftHdDevice public methods
//
cSoftHdConfig *Config(void) { return m_pConfig; };
cVideoStream *VideoStream(void) { return m_pVideoStream; };
cVideoRender *Render(void) { return m_pRender; };
cSoftHdAudio *Audio(void) { return m_pAudio; };
void SetDisableDeint(void);
void SetDecoderNeedsIFrame(void);
void SetParseH264Dimensions(void);
void SetDecoderFallbackToSw(bool);
void SetEnableHdr(bool);
void SetDisplayMode(int);
// osd
#ifdef USE_GLES
int MaxSizeGPUImageCache(void);
int OglOsdIsDisabled(void);
void SetDisableOglOsd(void);
void SetEnableOglOsd(void);
#endif
void OsdClose(void);
void OsdDrawARGB(int, int, int, int, int, const uint8_t *, int, int);
void SetOsdSize(int, int);
void SetScreenSize(int, int);
// audio
int GetVideoAudioDelayMs(void) { return m_pConfig->ConfigVideoAudioDelayMs; };
int GetMinBufferFillLevelThresholdMs(void) { return MIN_BUFFER_FILL_LEVEL_THRESHOLD_MS; };
void SetPassthroughMask(int);
void ResetChannelId(void);
// Logging, statistics
void GetStats(int *, int *, int *);
std::chrono::steady_clock::time_point GetChannelSwitchStartTime(void) { return m_channelSwitchStartTime; };
std::chrono::steady_clock::time_point GetChannelSwitchFirstPacketTime(void) { return m_dataReceivedTime; };
// Mediaplayer
void SetAudioCodec(enum AVCodecID, AVCodecParameters *, AVRational);
void SetVideoCodec(enum AVCodecID, AVCodecParameters *, AVRational);
int PlayAudioPkts(AVPacket *);
int PlayVideoPkts(AVPacket *);
// detach/ attach
void Detach(void);
void Attach(void);
bool IsDetached(void) const;
void ResetOsdProvider(void) { m_pOsdProvider = nullptr; }
bool IsOsdProviderSet(void) const { return m_pOsdProvider != nullptr; }
void SetStartDetached(void) { m_forceDetached = true; };
bool IsBufferingThresholdReached(void);
bool IsVideoOnlyPlayback(void) { return m_playbackMode == VIDEO_ONLY; };
// pip wrapper functions
void SetDisablePip(void) { m_disablePip = true; };
bool PipIsEnabled(void);
void PipEnable(void);
void PipDisable(void);
void PipToggle(void);
void PipChannelChange(int);
void PipChannelSwap(bool);
void PipSwapPosition(void);
void PipSetSize(void);
void SetRenderPipSize(void);
void SetRenderPipActive(bool);
// pip functions
int PlayPipVideo(const uchar *, int);
void SetDrmCanDisplayPip(bool canDisplay) { m_drmCanDisplayPip = canDisplay; };
bool UsePip(void) { return m_drmCanDisplayPip && !m_disablePip && m_pPipHandler; };
void ResetPipStream(void);
void ToggleRenderPipPosition(void) { m_pipUseAlt = !m_pipUseAlt; };
private:
static constexpr int MIN_BUFFER_FILL_LEVEL_THRESHOLD_MS = 450; ///< min buffering threshold in ms
std::atomic<State> m_state = DETACHED; ///< current plugin state, normal plugin start sets detached state
std::mutex m_eventMutex; ///< mutex to protect event queue
bool m_needsMakePrimary = false;
cDvbSpuDecoder *m_pSpuDecoder; ///< pointer to spu decoder
cSoftHdConfig *m_pConfig; ///< pointer to cSoftHdConfig object
cVideoRender *m_pRender; ///< pointer to cVideoRender object
cVideoStream *m_pVideoStream; ///< pointer to main video stream
cSoftHdAudio *m_pAudio; ///< pointer to cSoftHdAudio object
cAudioDecoder *m_pAudioDecoder = nullptr; ///< pointer to cAudioDecoder object
cSoftOsdProvider *m_pOsdProvider = nullptr; ///< pointer to cSoftOsdProvider object
cHardwareDevice *m_pHardwareDevice; ///< pointer to hardware device description
cEventHandler *m_pEventHandler; ///< event handler thread
cReassemblyBufferVideo m_videoReassemblyBuffer; ///< video pes reassembly buffer
cReassemblyBufferAudio m_audioReassemblyBuffer; ///< audio pes reassembly buffer
cJitterTracker m_audioJitterTracker{"audio"}; ///< audio jitter tracker
cJitterTracker m_videoJitterTracker{"video"}; ///< video jitter tracker
std::chrono::steady_clock::time_point m_channelSwitchStartTime; ///< timestamp, when VDR triggered a channel switch
std::chrono::steady_clock::time_point m_dataReceivedTime; ///< timestamp, when the first audio or video data after a channel switch arrives in Play*()
std::atomic<PlaybackMode> m_playbackMode = NONE; ///< current playback mode
int m_audioChannelID = -1; ///< current audio channel ID
cSoftHdGrab *m_pGrab; ///< pointer to grabber object
cVideoStream *m_pPipStream; ///< pointer to pip video stream
cReassemblyBufferVideo m_pipReassemblyBuffer; ///< pip pes reassembly buffer
cPipHandler *m_pPipHandler = nullptr; ///< pointer to pip handler
mutable std::mutex m_mutex; ///< mutex to lock the state machine
std::mutex m_sizeMutex; ///< mutex to lock screen size (which is accessed by different threads)
std::atomic<bool> m_receivedAudio = false; ///< flag if audio packets have been received
std::atomic<bool> m_receivedVideo = false; ///< flag if video packets have been received
std::atomic<bool> m_receivedValidAudio = false; ///< flag if valid audio packets have been received
std::atomic<bool> m_receivedValidVideo = false; ///< flag if valid video packets have been received
bool m_pipUseAlt; ///< use alternative pip position
bool m_drmCanDisplayPip = true; ///< true, if the drm device is able to display a pip video
bool m_disablePip = false; ///< true, if pip was disabled by the user
int m_volume = 0; ///< track the volume in the device (for attach)
int m_osdWidth;
int m_osdHeight;
int m_screenWidth;
int m_screenHeight;
bool m_forceDetached = false; ///< start the plugin in detached state
bool m_externalPlayerActive = false; ///< true, if we detached for an external player
int PlayVideoInternal(cVideoStream *, cReassemblyBufferVideo *, const uchar *, int, bool);
void FlushAudio(void);
void OnEventReceived(const Event&);
void HandleStillPicture(const uchar *data, int size);
void HandleDisplayModeChange(const sDrmMode &);
int64_t GetFirstAudioPtsMsToPlay();
int64_t GetFirstVideoPtsMsToPlay();
int GetBufferFillLevelThresholdMs();
// State machine
void SetState(State);
void OnEnteringState(State);
void OnLeavingState(State);
};
#endif