vdr-plugin-softhddevice-drm-gles 1.6.7
pipreceiver.cpp
Go to the documentation of this file.
1// SPDX-License-Identifier: AGPL-3.0-or-later
2
12#include <vdr/remux.h>
13#include <vdr/skins.h>
14
15#include "logger.h"
16#include "pipreceiver.h"
17#include "softhddevice.h"
18
19/*****************************************************************************
20 * cPipReceiver class
21 ****************************************************************************/
22
32 : cReceiver(NULL, MINPRIORITY),
33 m_pDevice(device)
34{
35 LOGDEBUG("pipreceiver: %s", __FUNCTION__);
36 AddPid(channel->Vpid());
37}
38
43{
44 LOGDEBUG("pipreceiver: %s, try detach", __FUNCTION__);
45 Detach();
46}
47
54{
55 LOGDEBUG("pipreceiver: %s %s", __FUNCTION__, on ? "on" : "off");
56 m_pTsToPesVideo.Reset();
57}
58
66void cPipReceiver::Receive(const uchar *data, int size)
67{
68 const int MAXRETRIES = 20; // max. number of retries for a single TS packet
69 const int RETRYWAITMS = 5; // time between two retries
70 const int ERRORDELTASEC = 60; // seconds before reporting lost packages again
71
72 for (int i = 0; i < MAXRETRIES; i++) {
73 if (ParseTs(data, size) > 0)
74 return;
75 cCondWait::SleepMs(RETRYWAITMS);
76 }
79 if (cTimeMs::Now() - m_lastErrorReport > ERRORDELTASEC) {
80 LOGWARNING("pipreceiver: %d TS packet(s) not accepted in pip stream", m_numLostPackets);
82 m_lastErrorReport = cTimeMs::Now();
83 }
84}
85
91int cPipReceiver::ParseTs(const uchar *data, int size)
92{
93 int played = 0;
94
95 if (!data) {
96 LOGWARNING("pipreceiver: %s null data received, reset pes buffer!", __FUNCTION__);
97 m_pTsToPesVideo.Reset();
98 return 0;
99 }
100
101 if (size < TS_SIZE) {
102 LOGWARNING("pipreceiver: %s TS fragment received!", __FUNCTION__);
103 return size;
104 }
105
106 while (size >= TS_SIZE) {
107 if (int skipped = TS_SYNC(data, size)) {
108 LOGWARNING("pipreceiver: %s TS stream not in sync!", __FUNCTION__);
109 return played + skipped;
110 }
111
112 if (TsHasPayload(data)) {
113 int payloadOffset = TsPayloadOffset(data);
114 if (payloadOffset < TS_SIZE) {
115 int w = PlayTs(data, TS_SIZE);
116 if (w < 0)
117 return played ? played : w;
118 if (w == 0)
119 break;
120 }
121 }
122
123 played += TS_SIZE;
124 size -= TS_SIZE;
125 data += TS_SIZE;
126 }
127
128 return played;
129}
130
136int cPipReceiver::PlayTs(const uchar *data, int size)
137{
138 if (TsPayloadStart(data)) {
139 int length;
140 while (const uchar *pes = m_pTsToPesVideo.GetPes(length)) {
141 int w = m_pDevice->PlayPipVideo(pes, length);
142 if (w <= 0) {
143 m_pTsToPesVideo.SetRepeatLast();
144 return w;
145 }
146 }
147 m_pTsToPesVideo.Reset();
148 }
149 m_pTsToPesVideo.PutTs(data, size);
150
151 return size;
152}
153
154/*****************************************************************************
155 * cPipHandler class
156 ****************************************************************************/
157
159 : m_pDevice(device)
160{
161}
162
164{
165 Stop();
166}
167
178{
179 if (!channelNum)
180 channelNum = m_pDevice->CurrentChannel();
181
182 const cChannel *channel;
183 cDevice *device;
185
186 {
188 channel = Channels->GetByNumber(channelNum);
189 }
190
191 device = m_pDevice->GetDevice(channel, 0, false);
192
193 if (channelNum && channel && device) {
194 Stop();
195 device->SwitchChannel(channel, false);
197 device->AttachReceiver(receiver);
201
202 LOGDEBUG("piphandler: %s: New receiver for channel (%d) %s", __FUNCTION__, channel->Number(), channel->Name());
203
204 m_active = true;
205 return 0;
206 }
207
208 LOGERROR("piphandler: %s: No receiver for channel num %d available", __FUNCTION__, channelNum);
209 return -1;
210}
211
220{
221 m_active = false;
222
223 if (!m_pPipReceiver)
224 return;
225
226 LOGDEBUG("piphandler: %s: deleting receiver for channel (%d) %s", __FUNCTION__, m_pPipChannel->Number(), m_pPipChannel->Name());
227
228 // both, PiP decoding and render thread are halted and resumed in ResetPipStream
230
231 delete m_pPipReceiver;
232 m_pPipReceiver = nullptr;
233 m_pPipChannel = nullptr;
234}
235
242{
243 if (on && m_active) {
244 LOGDEBUG("piphandler: %s: pip is already enabled", __FUNCTION__);
245 } else if (on && !m_active) {
246 LOGDEBUG("piphandler: %s: enabling pip (channel %d)", __FUNCTION__, m_pipChannelNum);
247 if (!Start(0))
249 } else if (!on && !m_active) {
250 LOGDEBUG("piphandler: %s: pip is already disabled", __FUNCTION__);
251 } else if (!on && m_active){
252 LOGDEBUG("piphandler: %s: disabling pip", __FUNCTION__);
253 Stop();
255 }
256}
257
264{
265 if (!m_active)
266 return;
267
270
271 Stop();
272
273 while (channel) {
274 bool ndr;
275
276 {
278 channel = direction > 0 ? Channels->Next(channel) : Channels->Prev(channel);
279 if (!channel && Setup.ChannelsWrap)
280 channel = direction > 0 ? Channels->First() : Channels->Last();
281 }
282
283 cDevice *device = m_pDevice->GetDevice(channel, 0, false, true);
284
285 if (channel && !channel->GroupSep() && device && device->ProvidesChannel(channel, 0, &ndr) && !ndr) {
286 Start(channel->Number());
287 return;
288 }
289
290 if (channel == first) {
291 Skins.Message(mtError, tr("Channel not available!"));
292 break;
293 }
294 }
295}
296
297/*****************************************************************************
298 * PiP handler public API
299 *
300 * These (public) functions are wrapped by cSoftHdDevice.
301 ****************************************************************************/
302
307{
308 if (m_active)
309 return;
310
311 HandleEnable(true);
312}
313
318{
319 if (!m_active)
320 return;
321
322 HandleEnable(false);
323}
324
329{
331}
332
339{
340 if (!m_active)
341 return;
342
343 if (direction > 0)
345 else
347}
348
355{
356 if (!m_active)
357 return;
358
360 if (!channel)
361 return;
362
363 Stop();
364 if (!closePip)
365 Start(0); // resets the pip channel to the current channel
366
367 LOGDEBUG("piphandler: %s: switch main stream to %d", __FUNCTION__, channel->Number());
368 {
370 Channels->SwitchTo(channel->Number());
371 }
372}
373
381
void ChannelChange(int)
Change the pip channel.
void SwapPosition(void)
Swap pip between normal and alternative position.
void HandleEnable(bool)
Enable/ disable picture-in-picture.
cPipReceiver * m_pPipReceiver
pointer to pip receiver
Definition pipreceiver.h:72
void Toggle(void)
Toggle picture-in-picture.
std::atomic< bool > m_active
true, if pip is active
Definition pipreceiver.h:75
void HandleChannelChange(int)
Change the pip channel.
const cChannel * m_pPipChannel
current pip channel
Definition pipreceiver.h:74
virtual ~cPipHandler(void)
int Start(int)
Create a new pip receiver and render the pip stream.
void Disable(void)
Stop picture-in-picture.
void ChannelSwap(bool)
Swap the pip channel with main live channel.
int m_pipChannelNum
current pip channel number
Definition pipreceiver.h:73
void Stop(void)
Delete the pip receiver, clear decoder and display buffers and disable rendering the pip window.
cPipHandler(cSoftHdDevice *)
void Enable(void)
Start picture-in-picture.
void SetSize(void)
Set size and position for the pip window.
cSoftHdDevice * m_pDevice
pointer to device
Definition pipreceiver.h:71
Receiver for PiP Stream.
Definition pipreceiver.h:31
cTsToPes m_pTsToPesVideo
TS to PES converter.
Definition pipreceiver.h:42
virtual ~cPipReceiver(void)
Detach the pip receiver.
int PlayTs(const uchar *, int)
Get the pes payload and send it to the player.
uint64_t m_lastErrorReport
tracks time since last error report
Definition pipreceiver.h:43
virtual void Activate(bool)
Called before the receiver gets attached or after it got detached.
int ParseTs(const uchar *, int)
Parse the ts stream and send it to the pes player.
virtual void Receive(const uchar *, int)
Receive data from the receiver.
cSoftHdDevice * m_pDevice
pointer to device
Definition pipreceiver.h:41
cPipReceiver(const cChannel *, cSoftHdDevice *)
Create a new receiver for the pip stream.
int m_numLostPackets
tracks lost packets
Definition pipreceiver.h:44
Output Device Implementation.
void SetRenderPipSize(void)
void SetRenderPipActive(bool)
void ResetPipStream(void)
Resets pip stream and render pipeline.
int PlayPipVideo(const uchar *, int)
Play a video packet of the pip videostream.
void ToggleRenderPipPosition(void)
#define LOGDEBUG
log to LOG_DEBUG
Definition logger.h:45
#define LOGERROR
log to LOG_ERR
Definition logger.h:39
#define LOGWARNING
log to LOG_WARN
Definition logger.h:41
Logger Header File.
PiP (Picture-in-Picture) Interface Header File.
Output Device Header File.