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