vdr-plugin-softhddevice-drm-gles 1.6.2
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 "event.h"
16#include "logger.h"
17#include "pipreceiver.h"
18#include "softhddevice.h"
19
27/*****************************************************************************
28 * cPipReceiver class
29 ****************************************************************************/
30
38 : cReceiver(NULL, MINPRIORITY),
39 m_pDevice(device)
40{
41 LOGDEBUG("pipreceiver: %s", __FUNCTION__);
42 AddPid(channel->Vpid());
43}
44
49{
50 LOGDEBUG("pipreceiver: %s", __FUNCTION__);
51 Detach();
52}
53
60{
61 LOGDEBUG("pipreceiver: %s %s", __FUNCTION__, on ? "on" : "off");
62 m_pTsToPesVideo.Reset();
63}
64
65#define MAXRETRIES 20 // max. number of retries for a single TS packet
66#define RETRYWAITMS 5 // time between two retries
67#define ERRORDELTASEC 60 // seconds before reporting lost packages again
73void cPipReceiver::Receive(const uchar *data, int size)
74{
75 for (int i = 0; i < MAXRETRIES; i++) {
76 if (ParseTs(data, size) > 0)
77 return;
78 cCondWait::SleepMs(RETRYWAITMS);
79 }
80 m_numLostPackets++;
81 if (cTimeMs::Now() - m_lastErrorReport > ERRORDELTASEC) {
82 LOGWARNING("pipreceiver: %d TS packet(s) not accepted in pip stream", m_numLostPackets);
83 m_numLostPackets = 0;
84 m_lastErrorReport = cTimeMs::Now();
85 }
86}
87
93int cPipReceiver::ParseTs(const uchar *data, int size)
94{
95 int played = 0;
96
97 if (!data) {
98 LOGWARNING("pipreceiver: %s null data received, reset pes buffer!", __FUNCTION__);
99 m_pTsToPesVideo.Reset();
100 return 0;
101 }
102
103 if (size < TS_SIZE) {
104 LOGWARNING("pipreceiver: %s TS fragment received!", __FUNCTION__);
105 return size;
106 }
107
108 while (size >= TS_SIZE) {
109 if (int skipped = TS_SYNC(data, size)) {
110 LOGWARNING("pipreceiver: %s TS stream not in sync!", __FUNCTION__);
111 return played + skipped;
112 }
113
114 if (TsHasPayload(data)) {
115 int payloadOffset = TsPayloadOffset(data);
116 if (payloadOffset < TS_SIZE) {
117 int w = PlayTs(data, TS_SIZE);
118 if (w < 0)
119 return played ? played : w;
120 if (w == 0)
121 break;
122 }
123 }
124
125 played += TS_SIZE;
126 size -= TS_SIZE;
127 data += TS_SIZE;
128 }
129
130 return played;
131}
132
138int cPipReceiver::PlayTs(const uchar *data, int size)
139{
140 if (TsPayloadStart(data)) {
141 int length;
142 while (const uchar *pes = m_pTsToPesVideo.GetPes(length)) {
143 int w = m_pDevice->PlayPipVideo(pes, length);
144 if (w <= 0) {
145 m_pTsToPesVideo.SetRepeatLast();
146 return w;
147 }
148 }
149 m_pTsToPesVideo.Reset();
150 }
151 m_pTsToPesVideo.PutTs(data, size);
152
153 return size;
154}
155
156/*****************************************************************************
157 * cPipHandler class
158 ****************************************************************************/
159
161 : m_pDevice(device),
162 m_pEventReceiver(device)
163{
164}
165
167{
168 Stop();
169}
170
171/*****************************************************************************
172 * Handle events
173 *
174 * The following functions are called from within the state change and must
175 * not trigger any new events. Otherwise we end up in a dead lock!
176 ****************************************************************************/
177
182{
183 switch (event) {
184 case PIPSTART:
185 HandleEnable(true);
186 break;
187 case PIPSTOP:
188 HandleEnable(false);
189 break;
190 case PIPTOGGLE:
192 break;
193 case PIPCHANUP:
195 break;
196 case PIPCHANDOWN:
198 break;
199 case PIPCHANSWAP:
200 Stop();
201 Start(0);
202 break;
203 case PIPSIZECHANGE:
205 break;
206 case PIPSWAPPOSITION:
209 break;
210 default:
211 break;
212 }
213}
214
227{
228 if (!channelNum)
229 channelNum = m_pDevice->CurrentChannel();
230
232 const cChannel *channel;
233 cDevice *device;
235
236 if (channelNum && (channel = Channels->GetByNumber(channelNum)) &&
237 (device = m_pDevice->GetDevice(channel, 0, false, false))) {
238 Stop();
239 device->SwitchChannel(channel, false);
241 device->AttachReceiver(receiver);
245
246 LOGDEBUG("piphandler: %s: New receiver for channel (%d) %s", __FUNCTION__, channel->Number(), channel->Name());
247
248 m_active = true;
249 return 0;
250 }
251
252 LOGERROR("piphandler: %s: No receiver for channel num %d available", __FUNCTION__, channelNum);
253 return -1;
254}
255
266{
267 m_active = false;
268
269 if (!m_pPipReceiver)
270 return;
271
272 LOGDEBUG("piphandler: %s: deleting receiver for channel (%d) %s", __FUNCTION__, m_pPipChannel->Number(), m_pPipChannel->Name());
273
275
276 delete m_pPipReceiver;
277 m_pPipReceiver = nullptr;
278 m_pPipChannel = nullptr;
279}
280
289{
290 if (on && m_active) {
291 LOGDEBUG("piphandler: %s: pip is already enabled", __FUNCTION__);
292 } else if (on && !m_active) {
293 LOGDEBUG("piphandler: %s: enabling pip (channel %d)", __FUNCTION__, m_pipChannelNum);
294 if (!Start(0))
296 } else if (!on && !m_active) {
297 LOGDEBUG("piphandler: %s: pip is already disabled", __FUNCTION__);
298 } else if (!on && m_active){
299 LOGDEBUG("piphandler: %s: disabling pip", __FUNCTION__);
301 Stop();
302 }
303}
304
313{
314 if (!m_active)
315 return;
316
317 const cChannel *channel;
318 const cChannel *first;
319
321 first = channel;
322
323 Stop();
324
326 while (channel) {
327 bool ndr;
328 cDevice *device;
329
330 channel = direction > 0 ? Channels->Next(channel) : Channels->Prev(channel);
331 if (!channel && Setup.ChannelsWrap)
332 channel = direction > 0 ? Channels->First() : Channels->Last();
333
334 if (channel && !channel->GroupSep() && (device = cDevice::GetDevice(channel, 0, false, true)) &&
335 device->ProvidesChannel(channel, 0, &ndr) && !ndr) {
336 Start(channel->Number());
337 return;
338 }
339
340 if (channel == first) {
341 Skins.Message(mtError, tr("Channel not available!"));
342 break;
343 }
344 }
345}
346
347/*****************************************************************************
348 * Trigger events
349 *
350 * These (public) functions are wrapped by cSoftHdDevice and can be called
351 * to trigger a pip event.
352 ****************************************************************************/
353
358{
359 if (m_active)
360 return;
361
363}
364
369{
370 if (!m_active)
371 return;
372
374}
375
383
399
409{
410 if (!m_active)
411 return;
412
414 if (!channel)
415 return;
416
417 if (closePip)
419 else
420 m_pEventReceiver->OnEventReceived(PipEvent{PIPCHANSWAP}); // resets the pip channel to the current channel
421
423 LOGDEBUG("piphandler: %s: switch main stream to %d", __FUNCTION__, channel->Number());
424 Channels->SwitchTo(channel->Number());
425}
426
434
442
virtual void OnEventReceived(const Event &)=0
cPipReceiver * m_pPipReceiver
pointer to pip receiver
Definition pipreceiver.h:69
const cChannel * m_pPipChannel
current pip channel
Definition pipreceiver.h:71
IEventReceiver * m_pEventReceiver
pointer to event receiver
Definition pipreceiver.h:68
bool m_active
true, if pip is active
Definition pipreceiver.h:72
int m_pipChannelNum
current pip channel number
Definition pipreceiver.h:70
cSoftHdDevice * m_pDevice
pointer to device
Definition pipreceiver.h:67
Receiver for PiP Stream.
Definition pipreceiver.h:29
cTsToPes m_pTsToPesVideo
TS to PES converter.
Definition pipreceiver.h:40
cSoftHdDevice * m_pDevice
pointer to device
Definition pipreceiver.h:39
Output Device Implementation.
void ToggleRenderPipPosition(void)
State Machine and Event Header File.
PipState
Definition event.h:30
@ PIPSTOP
Definition event.h:32
@ PIPSWAPPOSITION
Definition event.h:38
@ PIPCHANSWAP
Definition event.h:36
@ PIPTOGGLE
Definition event.h:33
@ PIPCHANUP
Definition event.h:34
@ PIPSTART
Definition event.h:31
@ PIPSIZECHANGE
Definition event.h:37
@ PIPCHANDOWN
Definition event.h:35
void SetRenderPipSize(void)
Wrapper functions for cVideoRender and cPipHandler.
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.
#define LOGDEBUG
log to LOG_DEBUG
Definition logger.h:40
#define LOGERROR
log to LOG_ERR
Definition logger.h:34
#define LOGWARNING
log to LOG_WARN
Definition logger.h:36
void ChannelChange(int)
Change the pip channel.
void SwapPosition(void)
Swap pip between normal and alternative position.
#define ERRORDELTASEC
void HandleEnable(bool)
Enable/ disable picture-in-picture.
void Toggle(void)
Toggle picture-in-picture.
virtual ~cPipReceiver(void)
Detach the pip receiver.
int PlayTs(const uchar *, int)
Get the pes payload and send it to the player.
void HandleChannelChange(int)
Change the pip channel.
virtual ~cPipHandler(void)
int Start(int)
Create a new pip receiver and render the pip stream.
void HandleEvent(enum PipState)
Handle a pip event.
virtual void Activate(bool)
Called before the receiver gets attached or after it got detached.
void Disable(void)
Stop picture-in-picture.
void ChannelSwap(bool)
Swap the pip channel with main live channel.
int ParseTs(const uchar *, int)
Parse the ts stream and send it to the pes player.
#define MAXRETRIES
#define RETRYWAITMS
cPipReceiver(const cChannel *, cSoftHdDevice *)
Create a new receiver for the pip stream handling only video pid.
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.
Logger Header File.
PiP (Picture-in-Picture) Interface Header File.
Output Device Header File.