summaryrefslogtreecommitdiff
path: root/receiver.c
blob: a0c49f2327c9f244b19dd91b1c07cc0eee5bbc7c (plain)
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
/*
 * OSD Picture in Picture plugin for the Video Disk Recorder
 *
 * See the README file for copyright information and how to reach the author.
 */

#include "receiver.h"
#include "pes.h"
#include "setup.h"
#if VDRVERSNUM > 10703
#include "remux.h"
#endif

#include <vdr/channels.h>
#if VDRVERSNUM <= 10703
#include <vdr/remux.h>
#endif
#include <vdr/ringbuffer.h>

cOsdPipReceiver::cOsdPipReceiver(const cChannel *Channel,
    cRingBufferFrame *ESBuffer):
#if (APIVERSNUM < 10500)
    cReceiver(Channel->Ca(), 0, Channel->Vpid()),
#else
    cReceiver(Channel->GetChannelID(), 0, Channel->Vpid()),
#endif
    cThread("osdpip_receiver")
{
    m_TSBuffer = new cRingBufferLinear(MEGABYTE(3), TS_SIZE * 2, true);
    m_TSBuffer->SetTimeouts(0, 100);
    m_ESBuffer = ESBuffer;
#if VDRVERSNUM > 10703
    m_Remux = new cRemuxPIP(Channel->Vpid(), NULL, NULL, NULL, true);
#else
    m_Remux = new cRemux(Channel->Vpid(), NULL, NULL, NULL, true);
#endif
    m_Active = false;
}

cOsdPipReceiver::~cOsdPipReceiver()
{
    Detach();
    delete m_Remux;
    delete m_TSBuffer;
}

void cOsdPipReceiver::Activate(bool On)
{
    if (On)
        Start();
    else if (m_Active) {
        m_Active = false;
        Cancel(3);
    }
}

void cOsdPipReceiver::Receive(uchar *Data, int Length)
{
    int put = m_TSBuffer->Put(Data, Length);
    if (put != Length)
        m_TSBuffer->ReportOverflow(Length - put);
}

void cOsdPipReceiver::Action(void)
{
    dsyslog("osdpip: receiver thread started (pid=%d)", getpid());

    m_Active = true;

    unsigned char NewPictureType = NO_PICTURE;
    unsigned char CurPictureType = NO_PICTURE;
    unsigned char VideoBuffer[200000];
    int VideoBufferPos = 0;

    while (m_Active) {
        int r;
        const uchar *b = m_TSBuffer->Get(r);
        if (b) {
            int Count = m_Remux->Put(b, r);
            if (Count)
                m_TSBuffer->Del(Count);
        }

        int Result;
        uchar *p = m_Remux->Get(Result, &NewPictureType);
        if (p) {
            if (NewPictureType != NO_PICTURE) {
                if ((OsdPipSetup.FrameMode == kFrameModeI && CurPictureType == I_FRAME) ||
                    (OsdPipSetup.FrameMode == kFrameModeIP && (CurPictureType == I_FRAME || CurPictureType == P_FRAME)) ||
                    (OsdPipSetup.FrameMode == kFrameModeIPB))
                {
                    cFrame * frame = new cFrame(VideoBuffer, VideoBufferPos, ftVideo, CurPictureType);
                    if (!m_ESBuffer->Put(frame))
                    {
                        delete frame;
                    }
                }
                CurPictureType = NewPictureType;
                VideoBufferPos = 0;
            }

            int pos = 0;
            while (pos + 6 < Result)
            {
                cPESPacket Packet(p + pos, Result - pos);
                if (pos + 6 + Packet.PacketLength() > Result)
                    break;
                int PayloadLength = 0;
                unsigned char * PayloadData = Packet.Payload(PayloadLength);
                if ((Packet.StreamId() & 0xF0) == 0xE0) { // video packet
                    memcpy(&VideoBuffer[VideoBufferPos], PayloadData, PayloadLength);
                    VideoBufferPos += PayloadLength;
                }
                pos += Packet.PacketLength() + 6;
            }
            m_Remux->Del(pos);
        }
    }

    dsyslog("osdpip: receiver thread ended (pid=%d)", getpid());
}