]> git.vomp.tv Git - vompclient.git/blob - src/stream.cc
Tweaks to telemetry. Load IP/port from config
[vompclient.git] / src / 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 "oldlog.h"
25
26 #include "telem.h"
27
28 #include "stream.h"
29
30 int Stream::which{};
31
32 Stream::Stream()
33 {
34   localWhich = which++;
35 }
36
37 Stream::~Stream()
38 {
39   shutdown();
40 }
41
42 void Stream::shutdown()
43 {
44   if (initted) free(outbuf);
45
46   initted = 0;
47 }
48
49 int Stream::init(DrainTarget* tdt, int bufsize)
50 {
51   outbuf = static_cast<u1*>(malloc(bufsize));
52
53   if (!outbuf) return 0;
54
55   draintarget = tdt;
56   bufferSize = bufsize;
57   initted = 1;
58   return 1;
59 }
60
61 void Stream::flush()
62 {
63   mutex.lock();
64   mediapackets.clear();
65   cur_packet_pos = 0;
66   mutex.unlock();
67
68   if (draintarget) draintarget->ResetTimeOffsets();
69 }
70
71 int Stream::put(const u1* inbuf, int len, u1 type, unsigned int index)
72 {
73   int ret = 0;
74
75   if (!draintarget) return 0;
76
77   MediaPacket newPacket;
78   newPacket.length = len;
79   newPacket.pos_buffer = 0;
80   newPacket.type = type;
81   newPacket.pts = 0;
82   newPacket.dts = 0;
83   newPacket.synched = false;
84   newPacket.index = index;
85   newPacket.disconti = false;
86   newPacket.presentation_time = 0;
87
88   if (type != MPTYPE_MPEG_AUDIO_LAYER3) //no PES
89   {
90     //Extract the pts...
91     bool hasdts = false;
92
93     if ((inbuf[7] & 0x80) && len > 14 )
94     {
95       newPacket.synched = true;
96       newPacket.pts = ( static_cast<u8>(inbuf[9] & 0x0E)  << 29 ) |
97                       ( static_cast<u8>(inbuf[10])        << 22 ) |
98                       ( static_cast<u8>(inbuf[11] & 0xFE) << 14 ) |
99                       ( static_cast<u8>(inbuf[12])        <<  7 ) |
100                       ( static_cast<u8>(inbuf[13] & 0xFE) >>  1 );
101
102       if ((inbuf[7] & 0x40) && len > 19)
103       {
104         newPacket.dts = ( static_cast<u8>(inbuf[14] & 0x0E) << 29 ) |
105                         ( static_cast<u8>(inbuf[15])        << 22 ) |
106                         ( static_cast<u8>(inbuf[16] & 0xFE) << 14 ) |
107                         ( static_cast<u8>(inbuf[17])        <<  7 ) |
108                         ( static_cast<u8>(inbuf[18] & 0xFE) >>  1 );
109         hasdts = true;
110       }
111
112       TELEM((localWhich ? 10 : 4), newPacket.pts);
113       TELEM((localWhich ? 11 : 5), newPacket.dts);
114
115       //ok we have the pts now convert it to a continously time code in 100ns units
116       if (hasdts && draintarget->dtsTimefix()) newPacket.presentation_time = static_cast<u8>(newPacket.dts * 10000LL / 90LL); // Windows only
117       else                                     newPacket.presentation_time = static_cast<u8>(newPacket.pts * 10000LL / 90LL);
118
119       TELEM((localWhich ? 12 : 6), newPacket.presentation_time);
120
121       // now PTS & DTS are original, presentation_time is OMX ticks. If it's rolled, it's rolled!
122
123       //newPacket.presentation_time-=draintarget->SetStartOffset(static_cast<u8>(newPacket.pts*10000LL/90LL),&newPacket.disconti);
124       //newPacket.presentation_time -= draintarget->SetStartOffset(static_cast<u8>(newPacket.pts * 10000LL / 90LL), &newPacket.disconti);
125       long long returnedStartOffset = draintarget->SetStartOffset(static_cast<u8>(newPacket.pts * 10000LL / 90LL), &newPacket.disconti);
126       TELEM((localWhich ? 13 : 7), returnedStartOffset);
127
128       newPacket.presentation_time -= returnedStartOffset;
129       //LogNT::getInstance()->debug("MP", "draintarget {} PTSmod {} disconti {} rso: {}", (void*)draintarget, newPacket.presentation_time, newPacket.disconti, returnedStartOffset);
130
131       TELEM((localWhich ? 14 : 8), newPacket.presentation_time);
132     }
133   }
134
135   mutex.lock();
136   int front, back;
137
138   if (mediapackets.empty())
139   {
140     back = 0; front = bufferSize;
141   }
142   else
143   {
144     front = mediapackets.front().pos_buffer;
145     back = mediapackets.back().pos_buffer + mediapackets.back().length;
146
147     if (back == bufferSize) back = 0;
148   }
149
150   mutex.unlock();
151
152   if (back <= front)
153   {
154     // The free space (if any) is in one continuous chunk.
155     if (len <= front - back) ret = len; // Is there enough of it?
156   }
157   else if (len <= bufferSize - back)
158   {
159     // There is enough space at the end of the buffer
160     ret = len;
161   }
162   else if (len <= front)
163   {
164     // There is enough space at the start of the buffer
165     back = 0;
166     ret = len;
167   }
168
169   if (ret) // Nonzero if we managed to find room for the packet
170   {
171     memcpy(outbuf + back, inbuf, len);
172     newPacket.pos_buffer = back;
173     mutex.lock();
174     mediapackets.push_back(newPacket);
175     mutex.unlock();
176   }
177   else
178   {
179     // Log::getInstance()->log("Stream", Log::DEBUG, "We are full %d!",bufferSize);
180   }
181
182   return ret;
183 }
184
185 bool Stream::drain(bool* dataavail)
186 {
187   bool ret = false;
188
189   if (dataavail) *dataavail = false;
190
191   if (draintarget->DrainTargetBufferFull()) return false; //We are full, no need to do something else
192
193   mutex.lock();
194   u4 listlength = mediapackets.size();
195
196   if (listlength != 0)
197   {
198     draintarget->PrepareMediaSample(mediapackets, cur_packet_pos);
199     mutex.unlock();
200
201     if (dataavail && draintarget->DrainTargetReady()) *dataavail = true;
202
203     u4 consumed = draintarget->DeliverMediaSample(outbuf, &cur_packet_pos);
204     mutex.lock();
205
206     if (consumed != 0) ret = true;
207
208     if (consumed > listlength) consumed = listlength;
209
210     while (consumed--)
211     {
212       mediapackets.pop_front();
213     }
214   }
215
216   mutex.unlock();
217   return ret;
218 }