]> git.vomp.tv Git - vompclient.git/blob - stream.cc
Fix black background for 16:9 live TV on 4:3 screen
[vompclient.git] / stream.cc
1 /*
2     Copyright 2005-2006 Mark Calderbank
3
4     This file is part of VOMP.
5
6     VOMP is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10
11     VOMP is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15
16     You should have received a copy of the GNU General Public License
17     along with VOMP; if not, write to the Free Software
18     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
19 */
20
21 #include <stdlib.h>
22 #include <string.h>
23
24 #include "log.h"
25 #include "stream.h"
26
27 Stream::~Stream()
28 {
29   shutdown();
30 }
31
32 void Stream::shutdown()
33 {
34   if (initted) free(outbuf);
35   initted = 0;
36 }
37
38 int Stream::init(DrainTarget* tdt, int bufsize)
39 {
40   outbuf = (UCHAR*)malloc(bufsize);
41   if (!outbuf) return 0;
42   draintarget = tdt;
43   bufferSize = bufsize;
44   initted = 1;
45   return 1;
46 }
47
48 void Stream::flush()
49 {
50   mutex.lock();
51   mediapackets.clear();
52   cur_packet_pos = 0;
53   mutex.unlock();
54
55   if (draintarget) draintarget->ResetTimeOffsets();
56 }
57
58 int Stream::put(const UCHAR* inbuf, int len, UCHAR type,unsigned int index)
59 {
60   int ret = 0;
61   if (!draintarget) return 0;
62   MediaPacket newPacket;
63   newPacket.length = len;
64   newPacket.pos_buffer = 0;
65   newPacket.type = type;
66   newPacket.pts=0;
67   newPacket.dts=0;
68   newPacket.synched=false;
69   newPacket.index=index;
70   newPacket.disconti=false;
71   newPacket.presentation_time=0;
72
73   if (type!=MPTYPE_MPEG_AUDIO_LAYER3) {//no PES
74     //Extract the pts...
75       bool hasdts=false;
76     if ((inbuf[7] & 0x80) && len>14 ) {
77         newPacket.synched=true;
78         newPacket.pts=((ULLONG)(inbuf[9] & 0x0E) << 29 ) |
79                     ( (ULLONG)(inbuf[10])        << 22 ) |
80                     ( (ULLONG)(inbuf[11] & 0xFE) << 14 ) |
81                      ( (ULLONG)(inbuf[12])        <<  7 ) |
82                      ( (ULLONG)(inbuf[13] & 0xFE) >>  1 );
83         if ((inbuf[7] & 0x40) && len>19) {
84             newPacket.dts=((ULLONG)(inbuf[14] & 0x0E) << 29 ) |
85                     ( (ULLONG)(inbuf[15])        << 22 ) |
86                     ( (ULLONG)(inbuf[16] & 0xFE) << 14 ) |
87                      ( (ULLONG)(inbuf[17])        <<  7 ) |
88                      ( (ULLONG)(inbuf[18] & 0xFE) >>  1 );
89             hasdts=true;
90         }
91         //ok we have the pts now convert it to a continously time code in 100ns units
92         if (hasdts && draintarget->dtsTimefix()) newPacket.presentation_time=(ULLONG)(newPacket.dts*10000LL/90LL);
93         else newPacket.presentation_time=(ULLONG)(newPacket.pts*10000LL/90LL);
94
95         //newPacket.presentation_time-=draintarget->SetStartOffset((ULLONG)(newPacket.pts*10000LL/90LL),&newPacket.disconti);
96         newPacket.presentation_time-=draintarget->SetStartOffset((ULLONG)(newPacket.pts*10000LL/90LL),&newPacket.disconti);
97     }
98   }
99
100   mutex.lock();
101   int front, back;
102   if (mediapackets.empty())
103   {
104     back = 0; front = bufferSize;
105   }
106   else
107   {
108     front = mediapackets.front().pos_buffer;
109     back = mediapackets.back().pos_buffer + mediapackets.back().length;
110     if (back == bufferSize) back = 0;
111   }
112   mutex.unlock();
113
114   if (back <= front)
115   {
116     // The free space (if any) is in one continuous chunk.
117     if (len <= front - back) ret = len; // Is there enough of it?
118   }
119   else if (len <= bufferSize - back)
120   {
121     // There is enough space at the end of the buffer
122     ret = len;
123   }
124   else if (len <= front)
125   {
126     // There is enough space at the start of the buffer
127     back = 0;
128     ret = len;
129   }
130
131   if (ret) // Nonzero if we managed to find room for the packet
132   {
133     memcpy(outbuf + back, inbuf, len);
134     newPacket.pos_buffer = back;
135     mutex.lock();
136     mediapackets.push_back(newPacket);
137     mutex.unlock();
138   } else {
139      // Log::getInstance()->log("Stream", Log::DEBUG, "We are full %d!",bufferSize);
140   }
141
142   return ret;
143 }
144
145 bool Stream::drain(bool * dataavail)
146 {
147   bool ret = false;
148   if (dataavail) *dataavail = false;
149   if (draintarget->DrainTargetBufferFull()) return false; //We are full, no need to do something else
150   mutex.lock();
151   UINT listlength = mediapackets.size();
152   if (listlength != 0)
153   {
154     draintarget->PrepareMediaSample(mediapackets, cur_packet_pos);
155     mutex.unlock();
156     if (dataavail && draintarget->DrainTargetReady()) *dataavail = true;
157     UINT consumed = draintarget->DeliverMediaSample(outbuf, &cur_packet_pos);
158     mutex.lock();
159     if (consumed != 0) ret = true;
160     if (consumed > listlength) consumed = listlength;
161     while (consumed--) 
162     {
163         mediapackets.pop_front();
164     }
165   }
166   mutex.unlock();
167   return ret;
168 }