vdr-plugin-softhddevice-drm-gles 1.6.4-d0291bb
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
20/*****************************************************************************
21 * cPipReceiver class
22 ****************************************************************************/
23
31 : cReceiver(NULL, MINPRIORITY),
32 m_pDevice(device)
33{
34 LOGDEBUG("pipreceiver: %s", __FUNCTION__);
35 AddPid(channel->Vpid());
36}
37
42{
43 LOGDEBUG("pipreceiver: %s", __FUNCTION__);
44 Detach();
45}
46
53{
54 LOGDEBUG("pipreceiver: %s %s", __FUNCTION__, on ? "on" : "off");
55 m_pTsToPesVideo.Reset();
56}
57
63void cPipReceiver::Receive(const uchar *data, int size)
64{
65 const int MAXRETRIES = 20; // max. number of retries for a single TS packet
66 const int RETRYWAITMS = 5; // time between two retries
67 const int ERRORDELTASEC = 60; // seconds before reporting lost packages again
68
69 for (int i = 0; i < MAXRETRIES; i++) {
70 if (ParseTs(data, size) > 0)
71 return;
72 cCondWait::SleepMs(RETRYWAITMS);
73 }
75 if (cTimeMs::Now() - m_lastErrorReport > ERRORDELTASEC) {
76 LOGWARNING("pipreceiver: %d TS packet(s) not accepted in pip stream", m_numLostPackets);
78 m_lastErrorReport = cTimeMs::Now();
79 }
80}
81
87int cPipReceiver::ParseTs(const uchar *data, int size)
88{
89 int played = 0;
90
91 if (!data) {
92 LOGWARNING("pipreceiver: %s null data received, reset pes buffer!", __FUNCTION__);
93 m_pTsToPesVideo.Reset();
94 return 0;
95 }
96
97 if (size < TS_SIZE) {
98 LOGWARNING("pipreceiver: %s TS fragment received!", __FUNCTION__);
99 return size;
100 }
101
102 while (size >= TS_SIZE) {
103 if (int skipped = TS_SYNC(data, size)) {
104 LOGWARNING("pipreceiver: %s TS stream not in sync!", __FUNCTION__);
105 return played + skipped;
106 }
107
108 if (TsHasPayload(data)) {
109 int payloadOffset = TsPayloadOffset(data);
110 if (payloadOffset < TS_SIZE) {
111 int w = PlayTs(data, TS_SIZE);
112 if (w < 0)
113 return played ? played : w;
114 if (w == 0)
115 break;
116 }
117 }
118
119 played += TS_SIZE;
120 size -= TS_SIZE;
121 data += TS_SIZE;
122 }
123
124 return played;
125}
126
132int cPipReceiver::PlayTs(const uchar *data, int size)
133{
134 if (TsPayloadStart(data)) {
135 int length;
136 while (const uchar *pes = m_pTsToPesVideo.GetPes(length)) {
137 int w = m_pDevice->PlayPipVideo(pes, length);
138 if (w <= 0) {
139 m_pTsToPesVideo.SetRepeatLast();
140 return w;
141 }
142 }
143 m_pTsToPesVideo.Reset();
144 }
145 m_pTsToPesVideo.PutTs(data, size);
146
147 return size;
148}
149
150/*****************************************************************************
151 * cPipHandler class
152 ****************************************************************************/
153
155 : m_pDevice(device),
156 m_pEventReceiver(device)
157{
158}
159
161{
162 Stop();
163}
164
165/*****************************************************************************
166 * Handle events
167 *
168 * The following functions are called from within the state change and must
169 * not trigger any new events. Otherwise we end up in a dead lock!
170 ****************************************************************************/
171
176{
177 switch (event) {
178 case PIPSTART:
179 HandleEnable(true);
180 break;
181 case PIPSTOP:
182 HandleEnable(false);
183 break;
184 case PIPTOGGLE:
186 break;
187 case PIPCHANUP:
189 break;
190 case PIPCHANDOWN:
192 break;
193 case PIPCHANSWAP:
194 Stop();
195 Start(0);
196 break;
197 case PIPSIZECHANGE:
199 break;
200 case PIPSWAPPOSITION:
203 break;
204 default:
205 break;
206 }
207}
208
221{
222 if (!channelNum)
223 channelNum = m_pDevice->CurrentChannel();
224
226 const cChannel *channel;
227 cDevice *device;
229
230 if (channelNum && (channel = Channels->GetByNumber(channelNum)) &&
231 (device = m_pDevice->GetDevice(channel, 0, false, false))) {
232 Stop();
233 device->SwitchChannel(channel, false);
235 device->AttachReceiver(receiver);
239
240 LOGDEBUG("piphandler: %s: New receiver for channel (%d) %s", __FUNCTION__, channel->Number(), channel->Name());
241
242 m_active = true;
243 return 0;
244 }
245
246 LOGERROR("piphandler: %s: No receiver for channel num %d available", __FUNCTION__, channelNum);
247 return -1;
248}
249
260{
261 m_active = false;
262
263 if (!m_pPipReceiver)
264 return;
265
266 LOGDEBUG("piphandler: %s: deleting receiver for channel (%d) %s", __FUNCTION__, m_pPipChannel->Number(), m_pPipChannel->Name());
267
269
270 delete m_pPipReceiver;
271 m_pPipReceiver = nullptr;
272 m_pPipChannel = nullptr;
273}
274
283{
284 if (on && m_active) {
285 LOGDEBUG("piphandler: %s: pip is already enabled", __FUNCTION__);
286 } else if (on && !m_active) {
287 LOGDEBUG("piphandler: %s: enabling pip (channel %d)", __FUNCTION__, m_pipChannelNum);
288 if (!Start(0))
290 } else if (!on && !m_active) {
291 LOGDEBUG("piphandler: %s: pip is already disabled", __FUNCTION__);
292 } else if (!on && m_active){
293 LOGDEBUG("piphandler: %s: disabling pip", __FUNCTION__);
295 Stop();
296 }
297}
298
307{
308 if (!m_active)
309 return;
310
311 const cChannel *channel;
312 const cChannel *first;
313
315 first = channel;
316
317 Stop();
318
320 while (channel) {
321 bool ndr;
322 cDevice *device;
323
324 channel = direction > 0 ? Channels->Next(channel) : Channels->Prev(channel);
325 if (!channel && Setup.ChannelsWrap)
326 channel = direction > 0 ? Channels->First() : Channels->Last();
327
328 if (channel && !channel->GroupSep() && (device = cDevice::GetDevice(channel, 0, false, true)) &&
329 device->ProvidesChannel(channel, 0, &ndr) && !ndr) {
330 Start(channel->Number());
331 return;
332 }
333
334 if (channel == first) {
335 Skins.Message(mtError, tr("Channel not available!"));
336 break;
337 }
338 }
339}
340
341/*****************************************************************************
342 * Trigger events
343 *
344 * These (public) functions are wrapped by cSoftHdDevice and can be called
345 * to trigger a pip event.
346 ****************************************************************************/
347
352{
353 if (m_active)
354 return;
355
357}
358
363{
364 if (!m_active)
365 return;
366
368}
369
377
393
403{
404 if (!m_active)
405 return;
406
408 if (!channel)
409 return;
410
411 if (closePip)
413 else
414 m_pEventReceiver->OnEventReceived(PipEvent{PIPCHANSWAP}); // resets the pip channel to the current channel
415
417 LOGDEBUG("piphandler: %s: switch main stream to %d", __FUNCTION__, channel->Number());
418 Channels->SwitchTo(channel->Number());
419}
420
428
virtual void OnEventReceived(const Event &)=0
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:73
void Toggle(void)
Toggle picture-in-picture.
void HandleChannelChange(int)
Change the pip channel.
const cChannel * m_pPipChannel
current pip channel
Definition pipreceiver.h:75
virtual ~cPipHandler(void)
int Start(int)
Create a new pip receiver and render the pip stream.
void HandleEvent(enum PipState)
Handle a pip event.
void Disable(void)
Stop picture-in-picture.
void ChannelSwap(bool)
Swap the pip channel with main live channel.
IEventReceiver * m_pEventReceiver
pointer to event receiver
Definition pipreceiver.h:72
bool m_active
true, if pip is active
Definition pipreceiver.h:76
int m_pipChannelNum
current pip channel number
Definition pipreceiver.h:74
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 handling only video pid.
int m_numLostPackets
tracks lost packets
Definition pipreceiver.h:44
Output Device Implementation.
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.
void ToggleRenderPipPosition(void)
State Machine and Event Header File.
#define LOGDEBUG
log to LOG_DEBUG
Definition logger.h:45
#define LOGERROR
log to LOG_ERR
Definition logger.h:39
PipState
Definition event.h:32
#define LOGWARNING
log to LOG_WARN
Definition logger.h:41
@ PIPSTOP
Definition event.h:34
@ PIPSWAPPOSITION
Definition event.h:40
@ PIPCHANSWAP
Definition event.h:38
@ PIPTOGGLE
Definition event.h:35
@ PIPCHANUP
Definition event.h:36
@ PIPSTART
Definition event.h:33
@ PIPSIZECHANGE
Definition event.h:39
@ PIPCHANDOWN
Definition event.h:37
Logger Header File.
PiP (Picture-in-Picture) Interface Header File.
Output Device Header File.