MythTV master
ts.cpp
Go to the documentation of this file.
1/*
2 * ts.c: MPEG TS functions for replex
3 *
4 *
5 * Copyright (C) 2003 Marcus Metzler <mocm@metzlerbros.de>
6 * Metzler Brothers Systementwicklung GbR
7 * Changes to use MythTV logging
8 * Copyright (C) 2011 Gavin Hurlbut <ghurlbut@mythtv.org>
9 *
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License
12 * as published by the Free Software Foundation; either version 2
13 * of the License, or (at your option) any later version.
14 *
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * General Public License for more details.
20 *
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
25 * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
26 *
27 */
28
29#include <algorithm>
30#include <array>
31#include <cstdint>
32#include <cstdio>
33#include <cstdlib>
34#include <cstring>
35
36#ifdef _WIN32
37#include <winsock2.h>
38#else
39#include <netinet/in.h>
40#endif
41
42#include "ts.h"
43#include "element.h"
44#include "pes.h"
45
47
48uint16_t get_pid(const uint8_t *pid)
49{
50 uint16_t pp = 0;
51
52 pp = (pid[0] & PID_MASK_HI)<<8;
53 pp |= pid[1];
54
55 return pp;
56}
57
58int find_pids_pos(uint16_t *vpid, uint16_t *apid, uint16_t *ac3pid,uint8_t *buf, int len, int *vpos, int *apos, int *ac3pos)
59{
60 int c=0;
61 int found=0;
62
63 if (!vpid || !apid || !ac3pid || !buf || !len) return 0;
64
65 *vpid = 0;
66 *apid = 0;
67 *ac3pid = 0;
68
69 while ( c+TS_SIZE < len){
70 if (buf[c] == buf[c+TS_SIZE]) break;
71 c++;
72 }
73
74 while(found<2 && c < len){
75 if (buf[c+1] & PAY_START) {
76 int off = 4;
77
78 if ( buf[c+3] & ADAPT_FIELD) { // adaptation field?
79 off += buf[c+4] + 1;
80 }
81
82 if (off < TS_SIZE-4){
83 if (!*vpid && (buf[c+off+3] & 0xF0) == 0xE0){
84 *vpid = get_pid(buf+c+1);
85 if (vpos) *vpos = c+off+3;
86 found++;
87 }
88 if (!*ac3pid && buf[c+off+3] == 0xBD){
89 int l=off+4;
90 int f=0;
91
92 while ( l < TS_SIZE && f<2){
93 uint8_t b=buf[c+l];
94 switch(f){
95 case 0:
96 if ( b == 0x0b)
97 f = 1;
98 break;
99
100 case 1:
101 if ( b == 0x77)
102 f = 2;
103 else if ( b != 0x0b)
104 f = 0;
105 }
106 l++;
107 }
108 if (f==2){
109 *ac3pid = get_pid(buf+c+1);
110 if (ac3pos) *ac3pos = c+off+3;
111 found++;
112 }
113 }
114 if (!*apid && ((buf[c+off+3] & 0xF0) == 0xC0 ||
115 (buf[c+off+3] & 0xF0) == 0xD0)){
116 *apid = get_pid(buf+c+1);
117 if (apos) *apos = c+off+3;
118 found++;
119 }
120 }
121 }
122 c+= TS_SIZE;
123 }
124 return found;
125}
126
127
128int find_pids(uint16_t *vpid, uint16_t *apid, uint16_t *ac3pid,uint8_t *buf, int len)
129{
130 return find_pids_pos(vpid, apid, ac3pid, buf, len, nullptr, nullptr, nullptr);
131}
132
133//taken and adapted from libdtv, (c) Rolf Hakenes
134// CRC32 lookup table for polynomial 0x04c11db7
135static const std::array <const uint32_t,256> crc_table {
136 0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc, 0x17c56b6b,
137 0x1a864db2, 0x1e475005, 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61,
138 0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd, 0x4c11db70, 0x48d0c6c7,
139 0x4593e01e, 0x4152fda9, 0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75,
140 0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011, 0x791d4014, 0x7ddc5da3,
141 0x709f7b7a, 0x745e66cd, 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039,
142 0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, 0xbe2b5b58, 0xbaea46ef,
143 0xb7a96036, 0xb3687d81, 0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d,
144 0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49, 0xc7361b4c, 0xc3f706fb,
145 0xceb42022, 0xca753d95, 0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1,
146 0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, 0x34867077, 0x30476dc0,
147 0x3d044b19, 0x39c556ae, 0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072,
148 0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16, 0x018aeb13, 0x054bf6a4,
149 0x0808d07d, 0x0cc9cdca, 0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde,
150 0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02, 0x5e9f46bf, 0x5a5e5b08,
151 0x571d7dd1, 0x53dc6066, 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba,
152 0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, 0xbfa1b04b, 0xbb60adfc,
153 0xb6238b25, 0xb2e29692, 0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6,
154 0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a, 0xe0b41de7, 0xe4750050,
155 0xe9362689, 0xedf73b3e, 0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2,
156 0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683, 0xd1799b34,
157 0xdc3abded, 0xd8fba05a, 0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637,
158 0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb, 0x4f040d56, 0x4bc510e1,
159 0x46863638, 0x42472b8f, 0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53,
160 0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47, 0x36194d42, 0x32d850f5,
161 0x3f9b762c, 0x3b5a6b9b, 0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff,
162 0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, 0xf12f560e, 0xf5ee4bb9,
163 0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b,
164 0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f, 0xc423cd6a, 0xc0e2d0dd,
165 0xcda1f604, 0xc960ebb3, 0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7,
166 0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, 0x9b3660c6, 0x9ff77d71,
167 0x92b45ba8, 0x9675461f, 0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3,
168 0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640, 0x4e8ee645, 0x4a4ffbf2,
169 0x470cdd2b, 0x43cdc09c, 0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8,
170 0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24, 0x119b4be9, 0x155a565e,
171 0x18197087, 0x1cd86d30, 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec,
172 0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, 0x2497d08d, 0x2056cd3a,
173 0x2d15ebe3, 0x29d4f654, 0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0,
174 0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c, 0xe3a1cbc1, 0xe760d676,
175 0xea23f0af, 0xeee2ed18, 0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4,
176 0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0, 0x9abc8bd5, 0x9e7d9662,
177 0x933eb0bb, 0x97ffad0c, 0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668,
178 0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4};
179
180static unsigned int crc32_04c11db7 (const unsigned char *d, int len, unsigned int crc)
181{
182 const unsigned char *u = d; // Saves '& 0xff'
183
184 for (int i=0; i<len; i++)
185 crc = (crc << 8) ^ crc_table[((crc >> 24) ^ *u++)];
186
187 return crc;
188}
189
190static int write_ts_header(uint16_t pid, int payload_start, int count,
191 int64_t SCR, uint8_t *obuf, int stuff)
192{
193 int c = 0;
194
195 obuf[c++] = 0x47;
196 obuf[c++] = (payload_start ? 0x40 : 0x00) | ((pid >> 8) & 0x1f);
197 obuf[c++] = pid & 0xff;
198 obuf[c++] = ((SCR >= 0 || stuff) ? 0x30 : 0x10) | count;
199 if (SCR >= 0|| stuff) {
200 if (stuff)
201 stuff--;
202 int size = stuff;
203 unsigned char flags = 0;
204 if(SCR >= 0) {
205 size = std::max(size, 7);
206 flags |= 0x10;
207 }
208 obuf[c++] = size;
209 if(size) {
210 obuf[c++] = flags;
211 size--;
212 }
213 if(SCR >= 0) {
214 auto lscr = (uint32_t) ((SCR/300ULL) & 0xFFFFFFFFULL);
215 uint8_t bit = (lscr & 0x01) << 7;
216 lscr = htonl(lscr >> 1);
217 auto *scr = (uint8_t *) &lscr;
218 auto scr_ext = (uint16_t) ((SCR%300ULL) & 0x1FFULL);
219 obuf[c++] = scr[0];
220 obuf[c++] = scr[1];
221 obuf[c++] = scr[2];
222 obuf[c++] = scr[3];
223 obuf[c++] = bit | 0x7e | (scr_ext >> 8);
224 obuf[c++] = scr_ext & 0xff;
225 size -= 6;
226 }
227 while(size-- > 0)
228 obuf[c++] = 0xff;
229 }
230 return c;
231}
232
233int write_video_ts(uint64_t vpts, uint64_t vdts, uint64_t SCR, uint8_t *buf,
234 int *vlength, uint8_t ptsdts, ringbuffer *vrbuffer)
235{
236//Unlike program streams, we only do one PES per frame
237 static int s_count = 0;
238 int pos = 0;
239 int stuff = 0;
240 int length = *vlength;
241
242 if (! length) return 0;
243 int p = 4;
244 if ( ptsdts ) {
245 p += PES_H_MIN + 8;
246
247 if ( ptsdts == PTS_ONLY) {
248 p += 5;
249 } else if (ptsdts == PTS_DTS){
250 p += 10;
251 }
252 }
253 if ( length+p >= TS_SIZE){
254 length = TS_SIZE;
255 } else {
256 stuff = TS_SIZE - length - p;
257 length = TS_SIZE;
258 }
259 if(ptsdts) {
260#if 0
261 LOG(VB_GENERAL, LOG_INFO, QString("SCR: %1 PTS: %2 DTS: %3")
262 .arg(SCR / 27000000.0, 0,'f')
263 .arg(vpts / 27000000.0, 0,'f')
264 .arg(vdts / 27000000.0, 0,'f'));
265#endif
266 pos = write_ts_header(TS_VIDPID, 1, s_count, SCR, buf, stuff);
267 // always use length == 0 for video streams
268 pos += write_pes_header( 0xE0, 6, vpts, vdts, buf+pos,
269 0, ptsdts);
270 } else {
271 pos = write_ts_header(TS_VIDPID, 0, s_count, -1, buf, stuff);
272 }
273 s_count = (s_count+1) & 0x0f;
274
275 if (length-pos > *vlength){
276 LOG(VB_GENERAL, LOG_ERR, QString("WHAT THE HELL %1 > %2\n")
277 .arg(length-pos).arg(*vlength));
278 }
279
280 int add = ring_read( vrbuffer, buf+pos, length-pos);
281 *vlength = add;
282 if (add < 0) return -1;
283 pos += add;
284
285 return pos;
286}
287
288int write_audio_ts(int n, uint64_t pts, uint8_t *buf, int *alength,
289 uint8_t ptsdts, ringbuffer *arbuffer)
290{
291 static std::array<int,32> s_count {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
292 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
293 int pos = 0;
294 int stuff = 0;
295 int length = *alength;
296
297 if (!length) return 0;
298 int p = 4;
299
300 if (ptsdts == PTS_ONLY){
301 p += PES_H_MIN + 5;
302 }
303
304 if ( length+p >= TS_SIZE){
305 length = TS_SIZE;
306 } else {
307 stuff = TS_SIZE - length - p;
308 length = TS_SIZE;
309 }
310 if(ptsdts) {
311 pos = write_ts_header(TS_MP2PID+n, 1, s_count[n], -1, buf, stuff);
312 pos += write_pes_header( 0xC0+n, *alength + PES_H_MIN + 5, pts,
313 0, buf+pos, 0, ptsdts);
314 } else {
315 pos = write_ts_header(TS_MP2PID+n, 0, s_count[n], -1, buf, stuff);
316 }
317 s_count[n] = (s_count[n]+1) & 0x0f;
318 int add = ring_read( arbuffer, buf+pos, length-pos);
319 *alength = add;
320 if (add < 0) return -1;
321 pos += add;
322
323 if (pos != TS_SIZE) {
324 LOG(VB_GENERAL, LOG_ERR, QString("apos: %1").arg(pos));
325 exit(1);
326 }
327
328 return pos;
329}
330
331int write_ac3_ts(int n, uint64_t pts, uint8_t *buf, int *alength,
332 uint8_t ptsdts, int nframes, ringbuffer *ac3rbuffer)
333{
334 static std::array<int,32> s_count {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
335 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
336 int pos = 0;
337 int stuff = 0;
338 int length = *alength;
339
340 if (!length) return 0;
341 int p = 4;
342
343 if (ptsdts == PTS_ONLY){
344 p += PES_H_MIN + 5 + 4; //PES header + PTS + PS1
345 }
346
347 if ( length+p >= TS_SIZE){
348 length = TS_SIZE;
349 } else {
350 stuff = TS_SIZE - length - p;
351 length = TS_SIZE;
352 }
353 if(ptsdts) {
354 pos = write_ts_header(TS_AC3PID+n, 1, s_count[n], -1, buf, stuff);
356 *alength + 4 + PES_H_MIN + 5,
357 pts, 0, buf+pos, 0, ptsdts);
358 buf[pos] = 0x80 + n;
359 buf[pos+1] = nframes;
360 buf[pos+2] = 0x00;
361 buf[pos+3] = 0x00;
362 pos += 4;
363 } else {
364 pos = write_ts_header(TS_AC3PID+n, 0, s_count[n], -1, buf, stuff);
365 }
366 s_count[n] = (s_count[n]+1) & 0x0f;
367
368 int add = ring_read( ac3rbuffer, buf+pos, length-pos);
369 *alength = add;
370 if (add < 0) return -1;
371 pos += add;
372
373 if (pos != TS_SIZE) {
374 LOG(VB_GENERAL, LOG_ERR, QString("apos: %1").arg(pos));
375 exit(1);
376 }
377
378 return pos;
379}
380
381void write_ts_patpmt(extdata_t *ext, int extcnt, uint8_t prog_num, uint8_t *buf)
382{
383 static constexpr uint8_t PMTPID { 0x20 };
384 static int s_count = 0;
385 int pmtpos = 13;
386 //PMT Program number = 1
387 //PMT PID = 0x20
388 std::array<uint8_t,17> pat
389 {0x00, 0x00, 0xb0, 0x0d, 0xfe, 0xef, 0xc1, 0x00, 0x00,
390 0x00, 0x00, 0xe0, PMTPID, 0x00, 0x00, 0x00, 0x00};
391 std::array<uint8_t,184> pmt
392 {0x00, 0x02, 0xb0, 0x00, 0x00, 0x00, 0xc1, 0x00, 0x00,
393 0x00, 0x00, 0xf0, 0x00};
394
395 //PAT
396 pat[10] = prog_num;
397 int pos = write_ts_header(0x00, 1, s_count, -1, buf, 0);
398 *(uint32_t *)(pat.data()+13)= htonl(crc32_04c11db7(pat.data()+1, 12, 0xffffffff));
399 memcpy(buf+pos, pat.data(), 17);
400 pos += 17;
401 memset(buf+pos, 0xff, TS_SIZE - pos);
402 pos = TS_SIZE;
403 //PMT
404 pos += write_ts_header(PMTPID, 1, s_count, -1, buf+pos, 0);
405 for(int i = 0; i <= extcnt; i++) {
406 uint8_t type = 0xFF;
407 uint32_t pid = 0x1FFF;
408 int n = ext[i-1].strmnum;
409 if(i == 0) {
410 type = 0x02;
411 pid = TS_VIDPID;
412 } else if(ext[i-1].type == MPEG_AUDIO) {
413 type = 0x04;
414 pid = TS_MP2PID + n;
415 } else if(ext[i-1].type == AC3) {
416 type = 0x81;
417 pid = TS_AC3PID + n;
418 } else {
419 type = 0xff;
420 pid = 0x1fff;
421 }
422 pmt[pmtpos++] = type;
423 pmt[pmtpos++] = 0xe0 | (0xff & (pid >> 8));
424 pmt[pmtpos++] = 0xff & pid;
425 pmt[pmtpos++] = 0xf0;
426 if(strlen(ext[i-1].language) == 3) {
427 pmt[pmtpos++] = 0x06;
428 pmt[pmtpos++] = 0x0a;
429 pmt[pmtpos++] = 0x04;
430 pmt[pmtpos++] = ext[i-1].language[0];
431 pmt[pmtpos++] = ext[i-1].language[1];
432 pmt[pmtpos++] = ext[i-1].language[2];
433 pmt[pmtpos++] = 0x00;
434 } else {
435 pmt[pmtpos++] = 0x00;
436 }
437 }
438 pmt[3] = pmtpos + 4/*crc*/ - 3 - 1/*pointer_field*/;
439 pmt[5] = prog_num;
440 pmt[9] = 0xf0 | (0xff & (TS_VIDPID >> 8));
441 pmt[10] = 0xff & TS_VIDPID;
442 *(uint32_t *)&pmt[pmtpos] = htonl(crc32_04c11db7(&pmt[1], pmtpos -1,
443 0xffffffff));
444 pmtpos+=4;
445 memcpy(buf+pos, pmt.data(), pmtpos);
446 pos += pmtpos;
447 memset(buf+pos, 0xff, (2*TS_SIZE) - pos);
448// pos = 2*TS_SIZE;
449 s_count = (s_count+1) & 0x0f;
450}
@ AC3
Definition: element.h:84
@ MPEG_AUDIO
Definition: element.h:84
static constexpr qint64 TS_SIZE
static const iso6937table * d
unsigned short uint16_t
Definition: iso6937tables.h:3
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
std::chrono::duration< CHRONO_TYPE, std::ratio< 1, 90000 > > pts
Definition: mythchrono.h:55
int write_pes_header(uint8_t id, int length, uint64_t PTS, uint64_t DTS, uint8_t *obuf, int stuffing, uint8_t ptsdts)
Definition: pes.cpp:612
#define PTS_ONLY
Definition: pes.h:46
#define PRIVATE_STREAM1
Definition: pes.h:23
#define PTS_DTS
Definition: pes.h:47
#define PES_H_MIN
Definition: pes.h:16
int ring_read(ringbuffer *rbuf, uint8_t *data, int count)
Definition: ringbuffer.cpp:202
int strmnum
Definition: mpg_common.h:59
char language[4]
Definition: mpg_common.h:61
int write_video_ts(uint64_t vpts, uint64_t vdts, uint64_t SCR, uint8_t *buf, int *vlength, uint8_t ptsdts, ringbuffer *vrbuffer)
Definition: ts.cpp:233
void write_ts_patpmt(extdata_t *ext, int extcnt, uint8_t prog_num, uint8_t *buf)
Definition: ts.cpp:381
int write_audio_ts(int n, uint64_t pts, uint8_t *buf, int *alength, uint8_t ptsdts, ringbuffer *arbuffer)
Definition: ts.cpp:288
uint16_t get_pid(const uint8_t *pid)
Definition: ts.cpp:48
int find_pids_pos(uint16_t *vpid, uint16_t *apid, uint16_t *ac3pid, uint8_t *buf, int len, int *vpos, int *apos, int *ac3pos)
Definition: ts.cpp:58
static unsigned int crc32_04c11db7(const unsigned char *d, int len, unsigned int crc)
Definition: ts.cpp:180
int write_ac3_ts(int n, uint64_t pts, uint8_t *buf, int *alength, uint8_t ptsdts, int nframes, ringbuffer *ac3rbuffer)
Definition: ts.cpp:331
static int write_ts_header(uint16_t pid, int payload_start, int count, int64_t SCR, uint8_t *obuf, int stuff)
Definition: ts.cpp:190
static const std::array< const uint32_t, 256 > crc_table
Definition: ts.cpp:135
int find_pids(uint16_t *vpid, uint16_t *apid, uint16_t *ac3pid, uint8_t *buf, int len)
Definition: ts.cpp:128
static constexpr uint16_t TS_VIDPID
Definition: ts.h:61
static constexpr uint8_t PID_MASK_HI
Definition: ts.h:37
static constexpr uint16_t TS_MP2PID
Definition: ts.h:62
static constexpr uint8_t ADAPT_FIELD
Definition: ts.h:42
static constexpr uint16_t TS_AC3PID
Definition: ts.h:63
static constexpr uint8_t PAY_START
Definition: ts.h:35