vdr-plugin-softhddevice-drm-gles 1.5.9-20e15de
pipreceiver.cpp
Go to the documentation of this file.
1
20#include <vdr/remux.h>
21#include <vdr/skins.h>
22
23#include "event.h"
24#include "logger.h"
25#include "pipreceiver.h"
26#include "softhddevice.h"
27
28/*****************************************************************************
29 * cPipReceiver class
30 ****************************************************************************/
31
35cPipReceiver::cPipReceiver(const cChannel *channel, cSoftHdDevice *device)
36 : cReceiver(NULL, MINPRIORITY),
37 m_pDevice(device)
38{
39 LOGDEBUG("pipreceiver: %s", __FUNCTION__);
40 AddPid(channel->Vpid());
41}
42
47{
48 LOGDEBUG("pipreceiver: %s", __FUNCTION__);
49 Detach();
50}
51
56{
57 LOGDEBUG("pipreceiver: %s %s", __FUNCTION__, on ? "on" : "off");
58 m_pTsToPesVideo.Reset();
59}
60
61#define MAXRETRIES 20 // max. number of retries for a single TS packet
62#define RETRYWAITMS 5 // time between two retries
63#define ERRORDELTASEC 60 // seconds before reporting lost packages again
69void cPipReceiver::Receive(const uchar *data, int size)
70{
71 for (int i = 0; i < MAXRETRIES; i++) {
72 if (ParseTs(data, size) > 0)
73 return;
74 cCondWait::SleepMs(RETRYWAITMS);
75 }
76 m_numLostPackets++;
77 if (cTimeMs::Now() - m_lastErrorReport > ERRORDELTASEC) {
78 LOGWARNING("pipreceiver: %d TS packet(s) not accepted in pip stream", m_numLostPackets);
79 m_numLostPackets = 0;
80 m_lastErrorReport = cTimeMs::Now();
81 }
82}
83
89int cPipReceiver::ParseTs(const uchar *data, int size)
90{
91 int played = 0;
92
93 if (!data) {
94 LOGWARNING("pipreceiver: %s null data received, reset pes buffer!", __FUNCTION__);
95 m_pTsToPesVideo.Reset();
96 return 0;
97 }
98
99 if (size < TS_SIZE) {
100 LOGWARNING("pipreceiver: %s TS fragment received!", __FUNCTION__);
101 return size;
102 }
103
104 while (size >= TS_SIZE) {
105 if (int skipped = TS_SYNC(data, size)) {
106 LOGWARNING("pipreceiver: %s TS stream not in sync!", __FUNCTION__);
107 return played + skipped;
108 }
109
110 if (TsHasPayload(data)) {
111 int payloadOffset = TsPayloadOffset(data);
112 if (payloadOffset < TS_SIZE) {
113 int w = PlayTs(data, TS_SIZE);
114 if (w < 0)
115 return played ? played : w;
116 if (w == 0)
117 break;
118 }
119 }
120
121 played += TS_SIZE;
122 size -= TS_SIZE;
123 data += TS_SIZE;
124 }
125
126 return played;
127}
128
134int cPipReceiver::PlayTs(const uchar *data, int size)
135{
136 if (TsPayloadStart(data)) {
137 int length;
138 while (const uchar *pes = m_pTsToPesVideo.GetPes(length)) {
139 int w = m_pDevice->PlayPipVideo(pes, length);
140 if (w <= 0) {
141 m_pTsToPesVideo.SetRepeatLast();
142 return w;
143 }
144 }
145 m_pTsToPesVideo.Reset();
146 }
147 m_pTsToPesVideo.PutTs(data, size);
148
149 return size;
150}
151
152/*****************************************************************************
153 * cPipHandler class
154 ****************************************************************************/
155
160 : m_pDevice(device),
161 m_pEventReceiver(device)
162{
163}
164
166{
167 Stop();
168}
169
170/*****************************************************************************
171 * Handle events
172 *
173 * The following functions are called from within the state change and must
174 * not trigger any new events. Otherwise we end up in a dead lock!
175 ****************************************************************************/
176
181{
182 switch (event) {
183 case PIPSTART:
184 HandleEnable(true);
185 break;
186 case PIPSTOP:
187 HandleEnable(false);
188 break;
189 case PIPTOGGLE:
191 break;
192 case PIPCHANUP:
194 break;
195 case PIPCHANDOWN:
197 break;
198 case PIPCHANSWAP:
199 Stop();
200 Start(0);
201 break;
202 case PIPSIZECHANGE:
204 break;
205 case PIPSWAPPOSITION:
208 break;
209 default:
210 break;
211 }
212}
213
225int cPipHandler::Start(int channelNum)
226{
227 if (!channelNum)
228 channelNum = m_pDevice->CurrentChannel();
229
230 LOCK_CHANNELS_READ;
231 const cChannel *channel;
232 cDevice *device;
233 cPipReceiver *receiver;
234
235 if (channelNum && (channel = Channels->GetByNumber(channelNum)) &&
236 (device = m_pDevice->GetDevice(channel, 0, false, false))) {
237 Stop();
238 device->SwitchChannel(channel, false);
239 receiver = new cPipReceiver(channel, m_pDevice);
240 device->AttachReceiver(receiver);
241 m_pPipReceiver = receiver;
242 m_pPipChannel = channel;
243 m_pipChannelNum = channelNum;
244
245 LOGDEBUG("piphandler: %s: New receiver for channel (%d) %s", __FUNCTION__, channel->Number(), channel->Name());
246
247 m_active = true;
248 return 0;
249 }
250
251 LOGERROR("piphandler: %s: No receiver for channel num %d available", __FUNCTION__, channelNum);
252 return -1;
253}
254
265{
266 m_active = false;
267
268 if (!m_pPipReceiver)
269 return;
270
271 LOGDEBUG("piphandler: %s: deleting receiver for channel (%d) %s", __FUNCTION__, m_pPipChannel->Number(), m_pPipChannel->Name());
272
274
275 delete m_pPipReceiver;
276 m_pPipReceiver = nullptr;
277 m_pPipChannel = nullptr;
278}
279
288{
289 if (on && m_active) {
290 LOGDEBUG("piphandler: %s: pip is already enabled", __FUNCTION__);
291 } else if (on && !m_active) {
292 LOGDEBUG("piphandler: %s: enabling pip (channel %d)", __FUNCTION__, m_pipChannelNum);
293 if (!Start(0))
295 } else if (!on && !m_active) {
296 LOGDEBUG("piphandler: %s: pip is already disabled", __FUNCTION__);
297 } else if (!on && m_active){
298 LOGDEBUG("piphandler: %s: disabling pip", __FUNCTION__);
300 Stop();
301 }
302}
303
312{
313 if (!m_active)
314 return;
315
316 const cChannel *channel;
317 const cChannel *first;
318
319 channel = m_pPipChannel;
320 first = channel;
321
322 Stop();
323
324 LOCK_CHANNELS_READ;
325 while (channel) {
326 bool ndr;
327 cDevice *device;
328
329 channel = direction > 0 ? Channels->Next(channel) : Channels->Prev(channel);
330 if (!channel && Setup.ChannelsWrap)
331 channel = direction > 0 ? Channels->First() : Channels->Last();
332
333 if (channel && !channel->GroupSep() && (device = cDevice::GetDevice(channel, 0, false, true)) &&
334 device->ProvidesChannel(channel, 0, &ndr) && !ndr) {
335 Start(channel->Number());
336 return;
337 }
338
339 if (channel == first) {
340 Skins.Message(mtError, tr("Channel not available!"));
341 break;
342 }
343 }
344}
345
346/*****************************************************************************
347 * Trigger events
348 *
349 * These (public) functions are wrapped by cSoftHdDevice and can be called
350 * to trigger a pip event.
351 ****************************************************************************/
352
357{
358 if (m_active)
359 return;
360
362}
363
368{
369 if (!m_active)
370 return;
371
373}
374
382
388void cPipHandler::ChannelChange(int direction)
389{
390 if (!m_active)
391 return;
392
393 if (direction > 0)
395 else
397}
398
407void cPipHandler::ChannelSwap(bool closePip)
408{
409 if (!m_active)
410 return;
411
412 const cChannel *channel = m_pPipChannel;
413 if (!channel)
414 return;
415
416 if (closePip)
418 else
419 m_pEventReceiver->OnEventReceived(PipEvent{PIPCHANSWAP}); // resets the pip channel to the current channel
420
421 LOCK_CHANNELS_READ;
422 LOGDEBUG("piphandler: %s: switch main stream to %d", __FUNCTION__, channel->Number());
423 Channels->SwitchTo(channel->Number());
424}
425
433
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:74
void Toggle(void)
Toggle picture-in-picture.
void HandleChannelChange(int)
Change the pip channel.
const cChannel * m_pPipChannel
current pip channel
Definition pipreceiver.h:76
virtual ~cPipHandler(void)
int Start(int)
Create a new pip receiver and render the pip stream.
void HandleEvent(enum PipState)
Handle the 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:73
bool m_active
true, if pip is active
Definition pipreceiver.h:77
int m_pipChannelNum
current pip channel number
Definition pipreceiver.h:75
void Stop(void)
Delete the pip receiver, clear decoder and display buffers and disable rendering the pip window.
cPipHandler(cSoftHdDevice *)
cPipHandler constructor
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:72
cPipReceiver - receiver class for pip
Definition pipreceiver.h:33
cTsToPes m_pTsToPesVideo
Definition pipreceiver.h:44
virtual ~cPipReceiver(void)
pip receiver class destructor
int PlayTs(const uchar *, int)
Get the pes payload and send it to the player.
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.
cSoftHdDevice * m_pDevice
Definition pipreceiver.h:43
cPipReceiver(const cChannel *, cSoftHdDevice *)
pip receiver class constructor
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.
PipState
Definition event.h:29
@ PIPSTOP
Definition event.h:31
@ PIPSWAPPOSITION
Definition event.h:37
@ PIPCHANSWAP
Definition event.h:35
@ PIPTOGGLE
Definition event.h:32
@ PIPCHANUP
Definition event.h:33
@ PIPSTART
Definition event.h:30
@ PIPSIZECHANGE
Definition event.h:36
@ PIPCHANDOWN
Definition event.h:34
Logger class header file.
#define LOGDEBUG
Definition logger.h:44
#define LOGERROR
Definition logger.h:41
#define LOGWARNING
Definition logger.h:42
#define ERRORDELTASEC
#define MAXRETRIES
#define RETRYWAITMS
Pip receiver header file.
Device class header file.