1 /*
2 * Copyright 2006 BBC and Fluendo S.A.
3 *
4 * This library is licensed under 3 different licenses and you
5 * can choose to use it under the terms of any one of them. The
6 * three licenses are the MPL 1.1, the LGPL, and the MIT license.
7 *
8 * MPL:
9 *
10 * The contents of this file are subject to the Mozilla Public License
11 * Version 1.1 (the "License"); you may not use this file except in
12 * compliance with the License. You may obtain a copy of the License at
13 * http://www.mozilla.org/MPL/.
14 *
15 * Software distributed under the License is distributed on an "AS IS"
16 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
17 * License for the specific language governing rights and limitations
18 * under the License.
19 *
20 * LGPL:
21 *
22 * This library is free software; you can redistribute it and/or
23 * modify it under the terms of the GNU Library General Public
24 * License as published by the Free Software Foundation; either
25 * version 2 of the License, or (at your option) any later version.
26 *
27 * This library is distributed in the hope that it will be useful,
28 * but WITHOUT ANY WARRANTY; without even the implied warranty of
29 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
30 * Library General Public License for more details.
31 *
32 * You should have received a copy of the GNU Library General Public
33 * License along with this library; if not, write to the
34 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
35 * Boston, MA 02110-1301, USA.
36 *
37 * MIT:
38 *
39 * Unless otherwise indicated, Source Code is licensed under MIT license.
40 * See further explanation attached in License Statement (distributed in the file
41 * LICENSE).
42 *
43 * Permission is hereby granted, free of charge, to any person obtaining a copy of
44 * this software and associated documentation files (the "Software"), to deal in
45 * the Software without restriction, including without limitation the rights to
46 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
47 * of the Software, and to permit persons to whom the Software is furnished to do
48 * so, subject to the following conditions:
49 *
50 * The above copyright notice and this permission notice shall be included in all
51 * copies or substantial portions of the Software.
52 *
53 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
54 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
55 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
56 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
57 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
58 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
59 * SOFTWARE.
60 *
61 * SPDX-License-Identifier: MPL-1.1 OR MIT OR LGPL-2.0-or-later
62 */
63
64 #ifdef HAVE_CONFIG_H
65 #include "config.h"
66 #endif
67
68 #include <string.h>
69
70 #include <gst/mpegts/mpegts.h>
71
72 #include "tsmux.h"
73 #include "tsmuxstream.h"
74
75 #define GST_CAT_DEFAULT gst_base_ts_mux_debug
76
77 /* Maximum total data length for a PAT section is 1024 bytes, minus an
78 * 8 byte header, then the length of each program entry is 32 bits,
79 * then finally a 32 bit CRC. Thus the maximum number of programs in this mux
80 * is (1024 - 8 - 4) / 4 = 253 because it only supports single section PATs */
81 #define TSMUX_MAX_PROGRAMS 253
82
83 #define TSMUX_SECTION_HDR_SIZE 8
84
85 #define TSMUX_DEFAULT_NETWORK_ID 0x0001
86 #define TSMUX_DEFAULT_TS_ID 0x0001
87
88 /* The last byte of the PCR in the header defines the byte position
89 * at which PCR should be calculated */
90 #define PCR_BYTE_OFFSET 11
91
92 /* HACK: We use a fixed buffering offset for the PCR at the moment -
93 * this is the amount 'in advance' of the stream that the PCR sits.
94 * 1/8 second atm */
95 #define TSMUX_PCR_OFFSET (TSMUX_CLOCK_FREQ / 8)
96
97 /* Base for all written PCR and DTS/PTS,
98 * so we have some slack to go backwards */
99 #define CLOCK_BASE (TSMUX_CLOCK_FREQ * 10 * 360)
100
101 static gboolean tsmux_write_pat (TsMux * mux);
102 static gboolean tsmux_write_pmt (TsMux * mux, TsMuxProgram * program);
103 static gboolean tsmux_write_scte_null (TsMux * mux, TsMuxProgram * program);
104 static gint64 get_next_pcr (TsMux * mux, gint64 cur_ts);
105 static gint64 get_current_pcr (TsMux * mux, gint64 cur_ts);
106 static gint64 write_new_pcr (TsMux * mux, TsMuxStream * stream, gint64 cur_pcr,
107 gint64 next_pcr);
108 static gboolean tsmux_write_ts_header (TsMux * mux, guint8 * buf,
109 TsMuxPacketInfo * pi, guint * payload_len_out, guint * payload_offset_out,
110 guint stream_avail);
111
112 static void
tsmux_section_free(TsMuxSection * section)113 tsmux_section_free (TsMuxSection * section)
114 {
115 gst_mpegts_section_unref (section->section);
116 g_slice_free (TsMuxSection, section);
117 }
118
119 /**
120 * tsmux_new:
121 *
122 * Create a new muxer session.
123 *
124 * Returns: A new #TsMux object.
125 */
126 TsMux *
tsmux_new(void)127 tsmux_new (void)
128 {
129 TsMux *mux;
130
131 mux = g_slice_new0 (TsMux);
132
133 mux->transport_id = TSMUX_DEFAULT_TS_ID;
134
135 mux->next_pgm_no = TSMUX_START_PROGRAM_ID;
136 mux->next_pmt_pid = TSMUX_START_PMT_PID;
137 mux->next_stream_pid = TSMUX_START_ES_PID;
138
139 mux->pat_changed = TRUE;
140 mux->next_pat_pcr = -1;
141 mux->pat_interval = TSMUX_DEFAULT_PAT_INTERVAL;
142
143 mux->si_changed = TRUE;
144 mux->si_interval = TSMUX_DEFAULT_SI_INTERVAL;
145
146 mux->pcr_interval = TSMUX_DEFAULT_PCR_INTERVAL;
147
148 mux->next_si_pcr = -1;
149
150 mux->si_sections = g_hash_table_new_full (g_direct_hash, g_direct_equal,
151 NULL, (GDestroyNotify) tsmux_section_free);
152
153 mux->new_stream_func = (TsMuxNewStreamFunc) tsmux_stream_new;
154 mux->new_stream_data = NULL;
155
156 mux->first_pcr_ts = G_MININT64;
157
158 return mux;
159 }
160
161 /**
162 * tsmux_set_write_func:
163 * @mux: a #TsMux
164 * @func: a user callback function
165 * @user_data: user data passed to @func
166 *
167 * Set the callback function and user data to be called when @mux has output to
168 * produce. @user_data will be passed as user data in @func.
169 */
170 void
tsmux_set_write_func(TsMux * mux,TsMuxWriteFunc func,void * user_data)171 tsmux_set_write_func (TsMux * mux, TsMuxWriteFunc func, void *user_data)
172 {
173 g_return_if_fail (mux != NULL);
174
175 mux->write_func = func;
176 mux->write_func_data = user_data;
177 }
178
179 /**
180 * tsmux_set_alloc_func:
181 * @mux: a #TsMux
182 * @func: a user callback function
183 * @user_data: user data passed to @func
184 *
185 * Set the callback function and user data to be called when @mux needs
186 * a new buffer to write a packet into.
187 * @user_data will be passed as user data in @func.
188 */
189 void
tsmux_set_alloc_func(TsMux * mux,TsMuxAllocFunc func,void * user_data)190 tsmux_set_alloc_func (TsMux * mux, TsMuxAllocFunc func, void *user_data)
191 {
192 g_return_if_fail (mux != NULL);
193
194 mux->alloc_func = func;
195 mux->alloc_func_data = user_data;
196 }
197
198 /**
199 * tsmux_set_new_stream_func:
200 * @mux: a #TsMux
201 * @func: a user callback function
202 * @user_data: user data passed to @func
203 *
204 * Set the callback function and user data to be called when @mux needs
205 * to create a new stream.
206 * @user_data will be passed as user data in @func.
207 */
208 void
tsmux_set_new_stream_func(TsMux * mux,TsMuxNewStreamFunc func,void * user_data)209 tsmux_set_new_stream_func (TsMux * mux, TsMuxNewStreamFunc func,
210 void *user_data)
211 {
212 g_return_if_fail (mux != NULL);
213
214 mux->new_stream_func = func;
215 mux->new_stream_data = user_data;
216 }
217
218 /**
219 * tsmux_set_pat_interval:
220 * @mux: a #TsMux
221 * @freq: a new PAT interval
222 *
223 * Set the interval (in cycles of the 90kHz clock) for writing out the PAT table.
224 *
225 * Many transport stream clients might have problems if the PAT table is not
226 * inserted in the stream at regular intervals, especially when initially trying
227 * to figure out the contents of the stream.
228 */
229 void
tsmux_set_pat_interval(TsMux * mux,guint freq)230 tsmux_set_pat_interval (TsMux * mux, guint freq)
231 {
232 g_return_if_fail (mux != NULL);
233
234 mux->pat_interval = freq;
235 }
236
237 /**
238 * tsmux_set_pcr_interval:
239 * @mux: a #TsMux
240 * @freq: a new PCR interval
241 *
242 * Set the interval (in cycles of the 90kHz clock) for writing the PCR.
243 */
244 void
tsmux_set_pcr_interval(TsMux * mux,guint freq)245 tsmux_set_pcr_interval (TsMux * mux, guint freq)
246 {
247 g_return_if_fail (mux != NULL);
248
249 mux->pcr_interval = freq;
250 }
251
252 /**
253 * tsmux_get_pat_interval:
254 * @mux: a #TsMux
255 *
256 * Get the configured PAT interval. See also tsmux_set_pat_interval().
257 *
258 * Returns: the configured PAT interval
259 */
260 guint
tsmux_get_pat_interval(TsMux * mux)261 tsmux_get_pat_interval (TsMux * mux)
262 {
263 g_return_val_if_fail (mux != NULL, 0);
264
265 return mux->pat_interval;
266 }
267
268 /**
269 * tsmux_resend_pat:
270 * @mux: a #TsMux
271 *
272 * Resends the PAT before the next stream packet.
273 */
274 void
tsmux_resend_pat(TsMux * mux)275 tsmux_resend_pat (TsMux * mux)
276 {
277 g_return_if_fail (mux != NULL);
278
279 mux->next_pat_pcr = -1;
280 }
281
282 /**
283 * tsmux_set_si_interval:
284 * @mux: a #TsMux
285 * @freq: a new SI table interval
286 *
287 * Set the interval (in cycles of the 90kHz clock) for writing out the SI tables.
288 *
289 */
290 void
tsmux_set_si_interval(TsMux * mux,guint freq)291 tsmux_set_si_interval (TsMux * mux, guint freq)
292 {
293 g_return_if_fail (mux != NULL);
294
295 mux->si_interval = freq;
296 }
297
298 /**
299 * tsmux_get_si_interval:
300 * @mux: a #TsMux
301 *
302 * Get the configured SI table interval. See also tsmux_set_si_interval().
303 *
304 * Returns: the configured SI interval
305 */
306 guint
tsmux_get_si_interval(TsMux * mux)307 tsmux_get_si_interval (TsMux * mux)
308 {
309 g_return_val_if_fail (mux != NULL, 0);
310
311 return mux->si_interval;
312 }
313
314 /**
315 * tsmux_resend_si:
316 * @mux: a #TsMux
317 *
318 * Resends the SI tables before the next stream packet.
319 *
320 */
321 void
tsmux_resend_si(TsMux * mux)322 tsmux_resend_si (TsMux * mux)
323 {
324 g_return_if_fail (mux != NULL);
325
326 mux->next_si_pcr = -1;
327 }
328
329 /**
330 * tsmux_add_mpegts_si_section:
331 * @mux: a #TsMux
332 * @section: (transfer full): a #GstMpegtsSection to add
333 *
334 * Add a Service Information #GstMpegtsSection to the stream
335 *
336 * Returns: %TRUE on success, %FALSE otherwise
337 */
338 gboolean
tsmux_add_mpegts_si_section(TsMux * mux,GstMpegtsSection * section)339 tsmux_add_mpegts_si_section (TsMux * mux, GstMpegtsSection * section)
340 {
341 TsMuxSection *tsmux_section;
342
343 g_return_val_if_fail (mux != NULL, FALSE);
344 g_return_val_if_fail (section != NULL, FALSE);
345 g_return_val_if_fail (mux->si_sections != NULL, FALSE);
346
347 tsmux_section = g_slice_new0 (TsMuxSection);
348
349 GST_DEBUG ("Adding mpegts section with type %d to mux",
350 section->section_type);
351
352 tsmux_section->section = section;
353 tsmux_section->pi.pid = section->pid;
354
355 g_hash_table_insert (mux->si_sections,
356 GINT_TO_POINTER (section->section_type), tsmux_section);
357
358 mux->si_changed = TRUE;
359
360 return TRUE;
361 }
362
363
364 /**
365 * tsmux_free:
366 * @mux: a #TsMux
367 *
368 * Free all resources associated with @mux. After calling this function @mux can
369 * not be used anymore.
370 */
371 void
tsmux_free(TsMux * mux)372 tsmux_free (TsMux * mux)
373 {
374 GList *cur;
375
376 g_return_if_fail (mux != NULL);
377
378 /* Free PAT section */
379 if (mux->pat.section)
380 gst_mpegts_section_unref (mux->pat.section);
381
382 /* Free all programs */
383 for (cur = mux->programs; cur; cur = cur->next) {
384 TsMuxProgram *program = (TsMuxProgram *) cur->data;
385
386 tsmux_program_free (program);
387 }
388 g_list_free (mux->programs);
389
390 /* Free all streams */
391 for (cur = mux->streams; cur; cur = cur->next) {
392 TsMuxStream *stream = (TsMuxStream *) cur->data;
393
394 tsmux_stream_free (stream);
395 }
396 g_list_free (mux->streams);
397
398 /* Free SI table sections */
399 g_hash_table_unref (mux->si_sections);
400
401 g_slice_free (TsMux, mux);
402 }
403
404 static gint
tsmux_program_compare(TsMuxProgram * program,gint * needle)405 tsmux_program_compare (TsMuxProgram * program, gint * needle)
406 {
407 return (program->pgm_number - *needle);
408 }
409
410 /**
411 * tsmux_program_new:
412 * @mux: a #TsMux
413 *
414 * Create a new program in the missing session @mux.
415 *
416 * Returns: a new #TsMuxProgram or %NULL when the maximum number of programs has
417 * been reached.
418 */
419 TsMuxProgram *
tsmux_program_new(TsMux * mux,gint prog_id)420 tsmux_program_new (TsMux * mux, gint prog_id)
421 {
422 TsMuxProgram *program;
423
424 g_return_val_if_fail (mux != NULL, NULL);
425
426 /* Ensure we have room for another program */
427 if (mux->nb_programs == TSMUX_MAX_PROGRAMS)
428 return NULL;
429
430 program = g_slice_new0 (TsMuxProgram);
431
432 program->pmt_changed = TRUE;
433 program->pmt_interval = TSMUX_DEFAULT_PMT_INTERVAL;
434
435 program->next_pmt_pcr = -1;
436
437 if (prog_id == 0) {
438 program->pgm_number = mux->next_pgm_no++;
439 while (g_list_find_custom (mux->programs, &program->pgm_number,
440 (GCompareFunc) tsmux_program_compare) != NULL) {
441 program->pgm_number = mux->next_pgm_no++;
442 }
443 } else {
444 program->pgm_number = prog_id;
445 while (g_list_find_custom (mux->programs, &program->pgm_number,
446 (GCompareFunc) tsmux_program_compare) != NULL) {
447 program->pgm_number++;
448 }
449 }
450
451 program->pmt_pid = mux->next_pmt_pid++;
452 program->pcr_stream = NULL;
453
454 /* SCTE35 is disabled by default */
455 program->scte35_pid = 0;
456 program->scte35_null_interval = TSMUX_DEFAULT_SCTE_35_NULL_INTERVAL;
457 program->next_scte35_pcr = -1;
458
459 /* mux->streams owns the streams */
460 program->streams = g_ptr_array_new_full (1, NULL);
461
462 mux->programs = g_list_prepend (mux->programs, program);
463 mux->nb_programs++;
464 mux->pat_changed = TRUE;
465
466 return program;
467 }
468
469 gboolean
tsmux_program_delete(TsMux * mux,TsMuxProgram * program)470 tsmux_program_delete (TsMux * mux, TsMuxProgram * program)
471 {
472 g_return_val_if_fail (mux != NULL, FALSE);
473
474 if (mux->nb_programs == 0)
475 return FALSE;
476
477 if (!program)
478 return FALSE;
479
480 mux->programs = g_list_remove (mux->programs, program);
481 mux->nb_programs--;
482 mux->pat_changed = TRUE;
483 tsmux_program_free ((TsMuxProgram *) program);
484
485 return TRUE;
486 }
487
488 /**
489 * tsmux_set_pmt_interval:
490 * @program: a #TsMuxProgram
491 * @freq: a new PMT interval
492 *
493 * Set the interval (in cycles of the 90kHz clock) for writing out the PMT table.
494 *
495 * Many transport stream clients might have problems if the PMT table is not
496 * inserted in the stream at regular intervals, especially when initially trying
497 * to figure out the contents of the stream.
498 */
499 void
tsmux_set_pmt_interval(TsMuxProgram * program,guint freq)500 tsmux_set_pmt_interval (TsMuxProgram * program, guint freq)
501 {
502 g_return_if_fail (program != NULL);
503
504 program->pmt_interval = freq;
505 }
506
507 /**
508 * tsmux_get_pmt_interval:
509 * @program: a #TsMuxProgram
510 *
511 * Get the configured PMT interval. See also tsmux_set_pmt_interval().
512 *
513 * Returns: the configured PMT interval
514 */
515 guint
tsmux_get_pmt_interval(TsMuxProgram * program)516 tsmux_get_pmt_interval (TsMuxProgram * program)
517 {
518 g_return_val_if_fail (program != NULL, 0);
519
520 return program->pmt_interval;
521 }
522
523 /**
524 * tsmux_program_set_scte35_interval:
525 * @program: a #TsMuxProgram
526 * @freq: a new SCTE-35 NULL interval
527 *
528 * Set the interval (in cycles of the 90kHz clock) for sending out the SCTE-35
529 * NULL command. This is only effective is the SCTE-35 PID is not 0.
530 */
531 void
tsmux_program_set_scte35_interval(TsMuxProgram * program,guint interval)532 tsmux_program_set_scte35_interval (TsMuxProgram * program, guint interval)
533 {
534 g_return_if_fail (program != NULL);
535
536 program->scte35_null_interval = interval;
537 }
538
539 /**
540 * tsmux_resend_pmt:
541 * @program: a #TsMuxProgram
542 *
543 * Resends the PMT before the next stream packet.
544 */
545 void
tsmux_resend_pmt(TsMuxProgram * program)546 tsmux_resend_pmt (TsMuxProgram * program)
547 {
548 g_return_if_fail (program != NULL);
549
550 program->next_pmt_pcr = -1;
551 }
552
553 /**
554 * tsmux_program_set_scte35_pid:
555 * @program: a #TsMuxProgram
556 * @pid: The pid to use, or 0 to deactivate usage.
557 *
558 * Set the @pid to use for sending SCTE-35 packets on the given
559 * @program.
560 *
561 * This needs to be called as early as possible if SCTE-35 sections
562 * are even going to be used with the given @program so that the PMT
563 * can be properly configured.
564 */
565 void
tsmux_program_set_scte35_pid(TsMuxProgram * program,guint16 pid)566 tsmux_program_set_scte35_pid (TsMuxProgram * program, guint16 pid)
567 {
568 TsMuxSection *section;
569 GstMpegtsSCTESIT *sit;
570 g_return_if_fail (program != NULL);
571
572 program->scte35_pid = pid;
573 /* Create/Update the section */
574 if (program->scte35_null_section) {
575 tsmux_section_free (program->scte35_null_section);
576 program->scte35_null_section = NULL;
577 }
578 if (pid != 0) {
579 program->scte35_null_section = section = g_slice_new0 (TsMuxSection);
580 section->pi.pid = pid;
581 sit = gst_mpegts_scte_null_new ();
582 section->section = gst_mpegts_section_from_scte_sit (sit, pid);
583 }
584 }
585
586 /**
587 * tsmux_program_get_scte35_pid:
588 * @program: a #TsMuxProgram
589 *
590 * Get the PID configured for sending SCTE-35 packets.
591 *
592 * Returns: the configured SCTE-35 PID, or 0 if not active.
593 */
594 guint16
tsmux_program_get_scte35_pid(TsMuxProgram * program)595 tsmux_program_get_scte35_pid (TsMuxProgram * program)
596 {
597 g_return_val_if_fail (program != NULL, 0);
598
599 return program->scte35_pid;
600 }
601
602 /**
603 * tsmux_program_add_stream:
604 * @program: a #TsMuxProgram
605 * @stream: a #TsMuxStream
606 *
607 * Add @stream to @program.
608 */
609 void
tsmux_program_add_stream(TsMuxProgram * program,TsMuxStream * stream)610 tsmux_program_add_stream (TsMuxProgram * program, TsMuxStream * stream)
611 {
612 GPtrArray *streams;
613 guint i;
614 gint pmt_index, array_index = -1 /* append */ ;
615 guint16 pid;
616
617 g_return_if_fail (program != NULL);
618 g_return_if_fail (stream != NULL);
619
620 streams = program->streams;
621 pmt_index = stream->pmt_index;
622 pid = tsmux_stream_get_pid (stream);
623
624 if (pmt_index >= 0) {
625 /* Insert into streams with known indices */
626 for (i = 0; i < streams->len; i++) {
627 TsMuxStream *s = g_ptr_array_index (streams, i);
628
629 if (s->pmt_index < 0 || pmt_index < s->pmt_index) {
630 array_index = i;
631 GST_DEBUG ("PID 0x%04x: Using known-order index %d/%u",
632 pid, array_index, streams->len);
633 break;
634 }
635 }
636 } else {
637 /* Insert after streams with known indices, sorted by PID */
638 for (i = 0; i < streams->len; i++) {
639 TsMuxStream *s = g_ptr_array_index (streams, i);
640
641 if (s->pmt_index < 0 && pid < tsmux_stream_get_pid (s)) {
642 array_index = i;
643 GST_DEBUG ("PID 0x%04x: Using PID-order index %d/%u",
644 pid, array_index, streams->len);
645 break;
646 }
647 }
648 }
649
650 g_ptr_array_insert (streams, array_index, stream);
651 program->pmt_changed = TRUE;
652 }
653
654 /**
655 * tsmux_program_set_pcr_stream:
656 * @program: a #TsMuxProgram
657 * @stream: a #TsMuxStream
658 *
659 * Set @stream as the PCR stream for @program, overwriting the previously
660 * configured PCR stream. When @stream is NULL, program will have no PCR stream
661 * configured.
662 */
663 void
tsmux_program_set_pcr_stream(TsMuxProgram * program,TsMuxStream * stream)664 tsmux_program_set_pcr_stream (TsMuxProgram * program, TsMuxStream * stream)
665 {
666 g_return_if_fail (program != NULL);
667
668 if (program->pcr_stream == stream)
669 return;
670
671 if (program->pcr_stream != NULL)
672 tsmux_stream_pcr_unref (program->pcr_stream);
673 if (stream)
674 tsmux_stream_pcr_ref (stream);
675 program->pcr_stream = stream;
676
677 program->pmt_changed = TRUE;
678 }
679
680 /**
681 * tsmux_get_new_pid:
682 * @mux: a #TsMux
683 *
684 * Get a new free PID.
685 *
686 * Returns: a new free PID.
687 */
688 guint16
tsmux_get_new_pid(TsMux * mux)689 tsmux_get_new_pid (TsMux * mux)
690 {
691 g_return_val_if_fail (mux != NULL, -1);
692
693 /* make sure this PID is free
694 * (and not taken by a specific earlier request) */
695 do {
696 mux->next_stream_pid++;
697 } while (tsmux_find_stream (mux, mux->next_stream_pid));
698
699 return mux->next_stream_pid;
700 }
701
702 /**
703 * tsmux_create_stream:
704 * @mux: a #TsMux
705 * @stream_type: the stream type
706 * @pid: the PID of the new stream.
707 *
708 * Create a new stream of @stream_type in the muxer session @mux.
709 *
710 * When @pid is set to #TSMUX_PID_AUTO, a new free PID will automatically
711 * be allocated for the new stream.
712 *
713 * Returns: a new #TsMuxStream.
714 */
715 TsMuxStream *
tsmux_create_stream(TsMux * mux,guint stream_type,guint16 pid,gchar * language)716 tsmux_create_stream (TsMux * mux, guint stream_type, guint16 pid,
717 gchar * language)
718 {
719 TsMuxStream *stream;
720 guint16 new_pid;
721
722 g_return_val_if_fail (mux != NULL, NULL);
723 g_return_val_if_fail (mux->new_stream_func != NULL, NULL);
724
725 if (pid == TSMUX_PID_AUTO) {
726 new_pid = tsmux_get_new_pid (mux);
727 } else {
728 new_pid = pid & 0x1FFF;
729 }
730
731 /* Ensure we're not creating a PID collision */
732 if (tsmux_find_stream (mux, new_pid))
733 return NULL;
734
735 stream = mux->new_stream_func (new_pid, stream_type, mux->new_stream_data);
736
737 mux->streams = g_list_prepend (mux->streams, stream);
738 mux->nb_streams++;
739
740 if (language) {
741 strncpy (stream->language, language, 4);
742 stream->language[3] = 0;
743 } else {
744 stream->language[0] = 0;
745 }
746
747 return stream;
748 }
749
750 /**
751 * tsmux_find_stream:
752 * @mux: a #TsMux
753 * @pid: the PID to find.
754 *
755 * Find the stream associated with PID.
756 *
757 * Returns: a #TsMuxStream with @pid or NULL when the stream was not found.
758 */
759 TsMuxStream *
tsmux_find_stream(TsMux * mux,guint16 pid)760 tsmux_find_stream (TsMux * mux, guint16 pid)
761 {
762 TsMuxStream *found = NULL;
763 GList *cur;
764
765 g_return_val_if_fail (mux != NULL, NULL);
766
767 for (cur = mux->streams; cur; cur = cur->next) {
768 TsMuxStream *stream = (TsMuxStream *) cur->data;
769
770 if (tsmux_stream_get_pid (stream) == pid) {
771 found = stream;
772 break;
773 }
774 }
775 return found;
776 }
777
778 static gboolean
tsmux_program_remove_stream(TsMuxProgram * program,TsMuxStream * stream)779 tsmux_program_remove_stream (TsMuxProgram * program, TsMuxStream * stream)
780 {
781 GPtrArray *streams = program->streams;
782
783 if (!g_ptr_array_remove (streams, stream)) {
784 g_warn_if_reached ();
785 return FALSE;
786 }
787
788 return streams->len == 0;
789 }
790
791
792 gboolean
tsmux_remove_stream(TsMux * mux,guint16 pid,TsMuxProgram * program)793 tsmux_remove_stream (TsMux * mux, guint16 pid, TsMuxProgram * program)
794 {
795 GList *cur;
796 gboolean ret = FALSE;
797
798 g_return_val_if_fail (mux != NULL, FALSE);
799
800 for (cur = mux->streams; cur; cur = cur->next) {
801 TsMuxStream *stream = (TsMuxStream *) cur->data;
802
803 if (tsmux_stream_get_pid (stream) == pid) {
804 ret = tsmux_program_remove_stream (program, stream);
805 mux->streams = g_list_remove (mux->streams, stream);
806 tsmux_stream_free (stream);
807 break;
808 }
809 }
810
811 if (ret)
812 tsmux_program_delete (mux, program);
813
814 return ret;
815 }
816
817 static gboolean
tsmux_get_buffer(TsMux * mux,GstBuffer ** buf)818 tsmux_get_buffer (TsMux * mux, GstBuffer ** buf)
819 {
820 g_return_val_if_fail (buf, FALSE);
821
822 if (G_UNLIKELY (!mux->alloc_func))
823 return FALSE;
824
825 mux->alloc_func (buf, mux->alloc_func_data);
826
827 if (!*buf)
828 return FALSE;
829
830 g_assert (gst_buffer_get_size (*buf) == TSMUX_PACKET_LENGTH);
831 return TRUE;
832 }
833
834 static gboolean
tsmux_packet_out(TsMux * mux,GstBuffer * buf,gint64 pcr)835 tsmux_packet_out (TsMux * mux, GstBuffer * buf, gint64 pcr)
836 {
837 if (G_UNLIKELY (mux->write_func == NULL)) {
838 if (buf)
839 gst_buffer_unref (buf);
840 return TRUE;
841 }
842
843 if (mux->bitrate) {
844 GST_BUFFER_PTS (buf) =
845 gst_util_uint64_scale (mux->n_bytes * 8, GST_SECOND, mux->bitrate);
846
847 /* Check and insert a PCR observation for each program if needed,
848 * but only for programs that have written their SI at least once,
849 * so the stream starts with PAT/PMT */
850 if (mux->first_pcr_ts != G_MININT64) {
851 GList *cur;
852
853 for (cur = mux->programs; cur; cur = cur->next) {
854 TsMuxProgram *program = (TsMuxProgram *) cur->data;
855 TsMuxStream *stream = program->pcr_stream;
856 gint64 cur_pcr, next_pcr, new_pcr;
857
858 if (!program->wrote_si)
859 continue;
860
861 cur_pcr = get_current_pcr (mux, 0);
862 next_pcr = get_next_pcr (mux, 0);
863 new_pcr = write_new_pcr (mux, stream, cur_pcr, next_pcr);
864
865 if (new_pcr != -1) {
866 GstBuffer *buf = NULL;
867 GstMapInfo map;
868 guint payload_len, payload_offs;
869
870 if (!tsmux_get_buffer (mux, &buf)) {
871 goto error;
872 }
873
874 gst_buffer_map (buf, &map, GST_MAP_READ);
875 tsmux_write_ts_header (mux, map.data, &stream->pi, &payload_len,
876 &payload_offs, 0);
877 gst_buffer_unmap (buf, &map);
878
879 stream->pi.flags &= TSMUX_PACKET_FLAG_PES_FULL_HEADER;
880 if (!tsmux_packet_out (mux, buf, new_pcr))
881 goto error;
882 }
883 }
884 }
885 }
886
887 mux->n_bytes += gst_buffer_get_size (buf);
888
889 return mux->write_func (buf, mux->write_func_data, pcr);
890
891 error:
892 return FALSE;
893 }
894
895 /*
896 * adaptation_field() {
897 * adaptation_field_length 8 uimsbf
898 * if(adaptation_field_length >0) {
899 * discontinuity_indicator 1 bslbf
900 * random_access_indicator 1 bslbf
901 * elementary_stream_priority_indicator 1 bslbf
902 * PCR_flag 1 bslbf
903 * OPCR_flag 1 bslbf
904 * splicing_point_flag 1 bslbf
905 * transport_private_data_flag 1 bslbf
906 * adaptation_field_extension_flag 1 bslbf
907 * if(PCR_flag == '1') {
908 * program_clock_reference_base 33 uimsbf
909 * reserved 6 bslbf
910 * program_clock_reference_extension 9 uimsbf
911 * }
912 * if(OPCR_flag == '1') {
913 * original_program_clock_reference_base 33 uimsbf
914 * reserved 6 bslbf
915 * original_program_clock_reference_extension 9 uimsbf
916 * }
917 * if (splicing_point_flag == '1') {
918 * splice_countdown 8 tcimsbf
919 * }
920 * if(transport_private_data_flag == '1') {
921 * transport_private_data_length 8 uimsbf
922 * for (i=0; i<transport_private_data_length;i++){
923 * private_data_byte 8 bslbf
924 * }
925 * }
926 * if (adaptation_field_extension_flag == '1' ) {
927 * adaptation_field_extension_length 8 uimsbf
928 * ltw_flag 1 bslbf
929 * piecewise_rate_flag 1 bslbf
930 * seamless_splice_flag 1 bslbf
931 * reserved 5 bslbf
932 * if (ltw_flag == '1') {
933 * ltw_valid_flag 1 bslbf
934 * ltw_offset 15 uimsbf
935 * }
936 * if (piecewise_rate_flag == '1') {
937 * reserved 2 bslbf
938 * piecewise_rate 22 uimsbf
939 * }
940 * if (seamless_splice_flag == '1'){
941 * splice_type 4 bslbf
942 * DTS_next_AU[32..30] 3 bslbf
943 * marker_bit 1 bslbf
944 * DTS_next_AU[29..15] 15 bslbf
945 * marker_bit 1 bslbf
946 * DTS_next_AU[14..0] 15 bslbf
947 * marker_bit 1 bslbf
948 * }
949 * for ( i=0;i<N;i++) {
950 * reserved 8 bslbf
951 * }
952 * }
953 * for (i=0;i<N;i++){
954 * stuffing_byte 8 bslbf
955 * }
956 * }
957 * }
958 */
959 static gboolean
tsmux_write_adaptation_field(guint8 * buf,TsMuxPacketInfo * pi,guint8 min_length,guint8 * written)960 tsmux_write_adaptation_field (guint8 * buf,
961 TsMuxPacketInfo * pi, guint8 min_length, guint8 * written)
962 {
963 guint8 pos = 2;
964 guint8 flags = 0;
965
966 g_assert (min_length <= TSMUX_PAYLOAD_LENGTH);
967
968 /* Write out all the fields from the packet info only if the
969 * user set the flag to request the adaptation field - if the flag
970 * isn't set, we're just supposed to write stuffing bytes */
971 if (pi->flags & TSMUX_PACKET_FLAG_ADAPTATION) {
972 TS_DEBUG ("writing adaptation fields");
973 if (pi->flags & TSMUX_PACKET_FLAG_DISCONT)
974 flags |= 0x80;
975 if (pi->flags & TSMUX_PACKET_FLAG_RANDOM_ACCESS)
976 flags |= 0x40;
977 if (pi->flags & TSMUX_PACKET_FLAG_PRIORITY)
978 flags |= 0x20;
979 if (pi->flags & TSMUX_PACKET_FLAG_WRITE_PCR) {
980 guint64 pcr_base;
981 guint32 pcr_ext;
982
983 pcr_base = (pi->pcr / 300);
984 pcr_ext = (pi->pcr % 300);
985
986 flags |= 0x10;
987 TS_DEBUG ("Writing PCR %" G_GUINT64_FORMAT " + ext %u", pcr_base,
988 pcr_ext);
989 buf[pos++] = (pcr_base >> 25) & 0xff;
990 buf[pos++] = (pcr_base >> 17) & 0xff;
991 buf[pos++] = (pcr_base >> 9) & 0xff;
992 buf[pos++] = (pcr_base >> 1) & 0xff;
993 buf[pos++] = ((pcr_base << 7) & 0x80) | 0x7e | ((pcr_ext >> 8) & 0x01); /* set 6 reserve bits to 1 */
994 buf[pos++] = (pcr_ext) & 0xff;
995 }
996 if (pi->flags & TSMUX_PACKET_FLAG_WRITE_OPCR) {
997 guint64 opcr_base;
998 guint32 opcr_ext;
999
1000 opcr_base = (pi->opcr / 300);
1001 opcr_ext = (pi->opcr % 300);
1002
1003 flags |= 0x08;
1004 TS_DEBUG ("Writing OPCR");
1005 buf[pos++] = (opcr_base >> 25) & 0xff;
1006 buf[pos++] = (opcr_base >> 17) & 0xff;
1007 buf[pos++] = (opcr_base >> 9) & 0xff;
1008 buf[pos++] = (opcr_base >> 1) & 0xff;
1009 buf[pos++] = ((opcr_base << 7) & 0x80) | 0x7e | ((opcr_ext >> 8) & 0x01); /* set 6 reserve bits to 1 */
1010 buf[pos++] = (opcr_ext) & 0xff;
1011 }
1012 if (pi->flags & TSMUX_PACKET_FLAG_WRITE_SPLICE) {
1013 flags |= 0x04;
1014 buf[pos++] = pi->splice_countdown;
1015 }
1016 if (pi->private_data_len > 0) {
1017 flags |= 0x02;
1018 /* Private data to write, ensure we have enough room */
1019 if ((1 + pi->private_data_len) > (TSMUX_PAYLOAD_LENGTH - pos))
1020 return FALSE;
1021 buf[pos++] = pi->private_data_len;
1022 memcpy (&(buf[pos]), pi->private_data, pi->private_data_len);
1023 pos += pi->private_data_len;
1024 TS_DEBUG ("%u bytes of private data", pi->private_data_len);
1025 }
1026 if (pi->flags & TSMUX_PACKET_FLAG_WRITE_ADAPT_EXT) {
1027 flags |= 0x01;
1028 TS_DEBUG ("FIXME: write Adaptation extension");
1029 /* Write an empty extension for now */
1030 buf[pos++] = 1;
1031 buf[pos++] = 0x1f; /* lower 5 bits are reserved, and should be all 1 */
1032 }
1033 }
1034 /* Write the flags at the start */
1035 buf[1] = flags;
1036
1037 /* Stuffing bytes if needed */
1038 while (pos < min_length)
1039 buf[pos++] = 0xff;
1040
1041 /* Write the adaptation field length, which doesn't include its own byte */
1042 buf[0] = pos - 1;
1043
1044 if (written)
1045 *written = pos;
1046
1047 return TRUE;
1048 }
1049
1050 static gboolean
tsmux_write_ts_header(TsMux * mux,guint8 * buf,TsMuxPacketInfo * pi,guint * payload_len_out,guint * payload_offset_out,guint stream_avail)1051 tsmux_write_ts_header (TsMux * mux, guint8 * buf, TsMuxPacketInfo * pi,
1052 guint * payload_len_out, guint * payload_offset_out, guint stream_avail)
1053 {
1054 guint8 *tmp;
1055 guint8 adaptation_flag = 0;
1056 guint8 adapt_min_length = 0;
1057 guint8 adapt_len = 0;
1058 guint payload_len;
1059 gboolean write_adapt = FALSE;
1060
1061 /* Sync byte */
1062 buf[0] = TSMUX_SYNC_BYTE;
1063
1064 TS_DEBUG ("PID 0x%04x, counter = 0x%01x, %u bytes avail", pi->pid,
1065 mux->pid_packet_counts[pi->pid] & 0x0f, stream_avail);
1066
1067 /* 3 bits:
1068 * transport_error_indicator
1069 * payload_unit_start_indicator
1070 * transport_priority: (00)
1071 * 13 bits: PID
1072 */
1073 tmp = buf + 1;
1074 if (pi->packet_start_unit_indicator) {
1075 tsmux_put16 (&tmp, 0x4000 | pi->pid);
1076 } else
1077 tsmux_put16 (&tmp, pi->pid);
1078
1079 /* 2 bits: scrambling_control (NOT SUPPORTED) (00)
1080 * 2 bits: adaptation field control (1x has_adaptation_field | x1 has_payload)
1081 * 4 bits: continuity counter (xxxx)
1082 */
1083
1084 if (pi->flags & TSMUX_PACKET_FLAG_ADAPTATION) {
1085 write_adapt = TRUE;
1086 }
1087
1088 if (stream_avail < TSMUX_PAYLOAD_LENGTH) {
1089 /* Need an adaptation field regardless for stuffing */
1090 adapt_min_length = TSMUX_PAYLOAD_LENGTH - stream_avail;
1091 write_adapt = TRUE;
1092 }
1093
1094 if (write_adapt) {
1095 gboolean res;
1096
1097 /* Flag the adaptation field presence */
1098 adaptation_flag |= 0x20;
1099 res = tsmux_write_adaptation_field (buf + TSMUX_HEADER_LENGTH,
1100 pi, adapt_min_length, &adapt_len);
1101 if (G_UNLIKELY (res == FALSE))
1102 return FALSE;
1103
1104 /* Should have written at least the number of bytes we requested */
1105 g_assert (adapt_len >= adapt_min_length);
1106 }
1107
1108 /* The amount of packet data we wrote is the remaining space after
1109 * the adaptation field */
1110 *payload_len_out = payload_len = TSMUX_PAYLOAD_LENGTH - adapt_len;
1111 *payload_offset_out = TSMUX_HEADER_LENGTH + adapt_len;
1112
1113 /* Now if we are going to write out some payload, flag that fact */
1114 if (payload_len > 0 && stream_avail > 0) {
1115 /* Flag the presence of a payload */
1116 adaptation_flag |= 0x10;
1117
1118 /* We must have enough data to fill the payload, or some calculation
1119 * went wrong */
1120 g_assert (payload_len <= stream_avail);
1121
1122 /* Packet with payload, increment the continuity counter */
1123 mux->pid_packet_counts[pi->pid]++;
1124 }
1125
1126 adaptation_flag |= mux->pid_packet_counts[pi->pid] & 0x0f;
1127
1128 /* Write the byte of transport_scrambling_control, adaptation_field_control
1129 * + continuity counter out */
1130 buf[3] = adaptation_flag;
1131
1132
1133 if (write_adapt) {
1134 TS_DEBUG ("Adaptation field of size >= %d + %d bytes payload",
1135 adapt_len, payload_len);
1136 } else {
1137 TS_DEBUG ("Payload of %d bytes only", payload_len);
1138 }
1139
1140 return TRUE;
1141 }
1142
1143 /* The unused_arg is needed for g_hash_table_foreach() */
1144 static gboolean
tsmux_section_write_packet(gpointer unused_arg,TsMuxSection * section,TsMux * mux)1145 tsmux_section_write_packet (gpointer unused_arg,
1146 TsMuxSection * section, TsMux * mux)
1147 {
1148 GstBuffer *section_buffer;
1149 GstBuffer *packet_buffer = NULL;
1150 GstMemory *mem;
1151 guint8 *packet;
1152 guint8 *data;
1153 gsize data_size = 0;
1154 gsize payload_written;
1155 guint len = 0, offset = 0, payload_len = 0;
1156 guint extra_alloc_bytes = 0;
1157
1158 g_return_val_if_fail (section != NULL, FALSE);
1159 g_return_val_if_fail (mux != NULL, FALSE);
1160
1161 /* Mark the start of new PES unit */
1162 section->pi.packet_start_unit_indicator = TRUE;
1163
1164 data = gst_mpegts_section_packetize (section->section, &data_size);
1165
1166 if (!data) {
1167 TS_DEBUG ("Could not packetize section");
1168 return FALSE;
1169 }
1170
1171 /* Mark payload data size */
1172 section->pi.stream_avail = data_size;
1173 payload_written = 0;
1174
1175 /* Wrap section data in a buffer without free function.
1176 The data will be freed when the GstMpegtsSection is destroyed. */
1177 section_buffer = gst_buffer_new_wrapped_full (GST_MEMORY_FLAG_READONLY,
1178 data, data_size, 0, data_size, NULL, NULL);
1179
1180 TS_DEBUG ("Section buffer with size %" G_GSIZE_FORMAT " created",
1181 gst_buffer_get_size (section_buffer));
1182
1183 while (section->pi.stream_avail > 0) {
1184
1185 packet = g_malloc (TSMUX_PACKET_LENGTH);
1186
1187 if (section->pi.packet_start_unit_indicator) {
1188 /* Wee need room for a pointer byte */
1189 section->pi.stream_avail++;
1190
1191 if (!tsmux_write_ts_header (mux, packet, §ion->pi, &len, &offset,
1192 section->pi.stream_avail))
1193 goto fail;
1194
1195 /* Write the pointer byte */
1196 packet[offset++] = 0x00;
1197 payload_len = len - 1;
1198
1199 } else {
1200 if (!tsmux_write_ts_header (mux, packet, §ion->pi, &len, &offset,
1201 section->pi.stream_avail))
1202 goto fail;
1203 payload_len = len;
1204 }
1205
1206 /* Wrap the TS header and adaption field in a GstMemory */
1207 mem = gst_memory_new_wrapped (GST_MEMORY_FLAG_READONLY,
1208 packet, TSMUX_PACKET_LENGTH, 0, offset, packet, g_free);
1209
1210 TS_DEBUG ("Creating packet buffer at offset "
1211 "%" G_GSIZE_FORMAT " with length %u", payload_written, payload_len);
1212
1213 /* If in M2TS mode, we will need to resize to 4 bytes after the end
1214 of the buffer. For performance reasons, we will now try to include
1215 4 extra bytes from the source buffer, then resize down, to avoid
1216 having an extra 4 byte GstMemory appended. If the source buffer
1217 does not have enough data for this, a new GstMemory will be used */
1218 if (gst_buffer_get_size (section_buffer) - (payload_written +
1219 payload_len) >= 4) {
1220 /* enough space */
1221 extra_alloc_bytes = 4;
1222 } else {
1223 extra_alloc_bytes = 0;
1224 }
1225 packet_buffer = gst_buffer_copy_region (section_buffer, GST_BUFFER_COPY_ALL,
1226 payload_written, payload_len + extra_alloc_bytes);
1227
1228 /* Prepend the header to the section data */
1229 gst_buffer_prepend_memory (packet_buffer, mem);
1230
1231 /* add an extra 4 bytes if it could not be reserved already */
1232 if (extra_alloc_bytes == 4) {
1233 /* we allocated those already, resize */
1234 gst_buffer_set_size (packet_buffer,
1235 gst_buffer_get_size (packet_buffer) - extra_alloc_bytes);
1236 } else {
1237 void *ptr = g_malloc (4);
1238 GstMemory *extra =
1239 gst_memory_new_wrapped (GST_MEMORY_FLAG_READONLY, ptr, 4, 0, 0, ptr,
1240 g_free);
1241 gst_buffer_append_memory (packet_buffer, extra);
1242 }
1243
1244 TS_DEBUG ("Writing %d bytes to section. %d bytes remaining",
1245 len, section->pi.stream_avail - len);
1246
1247 /* Push the packet without PCR */
1248 if (G_UNLIKELY (!tsmux_packet_out (mux, packet_buffer, -1))) {
1249 /* Buffer given away */
1250 packet_buffer = NULL;
1251 goto fail;
1252 }
1253
1254 packet_buffer = NULL;
1255 section->pi.stream_avail -= len;
1256 payload_written += payload_len;
1257 section->pi.packet_start_unit_indicator = FALSE;
1258 }
1259
1260 gst_buffer_unref (section_buffer);
1261
1262 return TRUE;
1263
1264 fail:
1265 g_free (packet);
1266 if (section_buffer)
1267 gst_buffer_unref (section_buffer);
1268 return FALSE;
1269 }
1270
1271 /**
1272 * tsmux_send_section:
1273 * @mux: a #TsMux
1274 * @section: (transfer full): a #GstMpegtsSection to add
1275 *
1276 * Send a @section immediately on the stream.
1277 *
1278 * Returns: %TRUE on success, %FALSE otherwise
1279 */
1280 gboolean
tsmux_send_section(TsMux * mux,GstMpegtsSection * section)1281 tsmux_send_section (TsMux * mux, GstMpegtsSection * section)
1282 {
1283 gboolean ret;
1284 TsMuxSection tsmux_section;
1285
1286 g_return_val_if_fail (mux != NULL, FALSE);
1287 g_return_val_if_fail (section != NULL, FALSE);
1288
1289 memset (&tsmux_section, 0, sizeof (tsmux_section));
1290
1291 GST_DEBUG ("Sending mpegts section with type %d to mux",
1292 section->section_type);
1293
1294 tsmux_section.section = section;
1295 tsmux_section.pi.pid = section->pid;
1296
1297 ret = tsmux_section_write_packet (NULL, &tsmux_section, mux);
1298 gst_mpegts_section_unref (section);
1299
1300 return ret;
1301 }
1302
1303 static gboolean
tsmux_write_si(TsMux * mux)1304 tsmux_write_si (TsMux * mux)
1305 {
1306 g_hash_table_foreach (mux->si_sections,
1307 (GHFunc) tsmux_section_write_packet, mux);
1308
1309 mux->si_changed = FALSE;
1310
1311 return TRUE;
1312
1313 }
1314
1315 static void
tsmux_write_null_ts_header(guint8 * buf)1316 tsmux_write_null_ts_header (guint8 * buf)
1317 {
1318 *buf++ = TSMUX_SYNC_BYTE;
1319 *buf++ = 0x1f;
1320 *buf++ = 0xff;
1321 *buf++ = 0x10;
1322 }
1323
1324 static gint64
ts_to_pcr(gint64 ts)1325 ts_to_pcr (gint64 ts)
1326 {
1327 if (ts == G_MININT64) {
1328 return 0;
1329 }
1330
1331 return (ts - TSMUX_PCR_OFFSET) * (TSMUX_SYS_CLOCK_FREQ / TSMUX_CLOCK_FREQ);
1332 }
1333
1334 /* Calculate the PCR to write into the current packet */
1335 static gint64
get_current_pcr(TsMux * mux,gint64 cur_ts)1336 get_current_pcr (TsMux * mux, gint64 cur_ts)
1337 {
1338 if (!mux->bitrate)
1339 return ts_to_pcr (cur_ts);
1340
1341 if (mux->first_pcr_ts == G_MININT64) {
1342 g_assert (cur_ts != G_MININT64);
1343 mux->first_pcr_ts = cur_ts;
1344 GST_DEBUG ("First PCR offset is %" G_GUINT64_FORMAT, cur_ts);
1345 }
1346
1347 return ts_to_pcr (mux->first_pcr_ts) +
1348 gst_util_uint64_scale ((mux->n_bytes + PCR_BYTE_OFFSET) * 8,
1349 TSMUX_SYS_CLOCK_FREQ, mux->bitrate);
1350 }
1351
1352 /* Predict the PCR at the next packet if possible */
1353 static gint64
get_next_pcr(TsMux * mux,gint64 cur_ts)1354 get_next_pcr (TsMux * mux, gint64 cur_ts)
1355 {
1356 if (!mux->bitrate)
1357 return ts_to_pcr (cur_ts);
1358
1359 if (mux->first_pcr_ts == G_MININT64) {
1360 g_assert (cur_ts != G_MININT64);
1361 mux->first_pcr_ts = cur_ts;
1362 GST_DEBUG ("First PCR offset is %" G_GUINT64_FORMAT, cur_ts);
1363 }
1364
1365 return ts_to_pcr (mux->first_pcr_ts) +
1366 gst_util_uint64_scale ((mux->n_bytes + TSMUX_PACKET_LENGTH +
1367 PCR_BYTE_OFFSET) * 8, TSMUX_SYS_CLOCK_FREQ, mux->bitrate);
1368 }
1369
1370 static gint64
write_new_pcr(TsMux * mux,TsMuxStream * stream,gint64 cur_pcr,gint64 next_pcr)1371 write_new_pcr (TsMux * mux, TsMuxStream * stream, gint64 cur_pcr,
1372 gint64 next_pcr)
1373 {
1374 if (stream->next_pcr == -1 || next_pcr > stream->next_pcr) {
1375 stream->pi.flags |=
1376 TSMUX_PACKET_FLAG_ADAPTATION | TSMUX_PACKET_FLAG_WRITE_PCR;
1377 stream->pi.pcr = cur_pcr;
1378
1379 if (mux->bitrate && stream->next_pcr != -1 && cur_pcr >= stream->next_pcr) {
1380 GST_WARNING ("Writing PCR %" G_GUINT64_FORMAT " missed the target %"
1381 G_GUINT64_FORMAT " by %f ms", cur_pcr, stream->next_pcr,
1382 (double) (cur_pcr - stream->next_pcr) / 27000.0);
1383 }
1384 /* Next PCR deadline is now plus the scheduled interval */
1385 stream->next_pcr = cur_pcr + mux->pcr_interval * 300;
1386 } else {
1387 cur_pcr = -1;
1388 }
1389
1390 return cur_pcr;
1391 }
1392
1393 static gboolean
rewrite_si(TsMux * mux,gint64 cur_ts)1394 rewrite_si (TsMux * mux, gint64 cur_ts)
1395 {
1396 gboolean write_pat;
1397 gboolean write_si;
1398 GList *cur;
1399 gint64 next_pcr;
1400
1401 next_pcr = get_next_pcr (mux, cur_ts);
1402
1403 /* check if we need to rewrite pat */
1404 if (mux->next_pat_pcr == -1 || mux->pat_changed)
1405 write_pat = TRUE;
1406 else if (next_pcr > mux->next_pat_pcr)
1407 write_pat = TRUE;
1408 else
1409 write_pat = FALSE;
1410
1411 if (write_pat) {
1412 if (mux->next_pat_pcr == -1)
1413 mux->next_pat_pcr = next_pcr + mux->pat_interval * 300;
1414 else
1415 mux->next_pat_pcr += mux->pat_interval * 300;
1416
1417 if (!tsmux_write_pat (mux))
1418 return FALSE;
1419
1420 next_pcr = get_next_pcr (mux, cur_ts);
1421 }
1422
1423 /* check if we need to rewrite sit */
1424 if (mux->next_si_pcr == -1 || mux->si_changed)
1425 write_si = TRUE;
1426 else if (next_pcr > mux->next_si_pcr)
1427 write_si = TRUE;
1428 else
1429 write_si = FALSE;
1430
1431 if (write_si) {
1432 if (mux->next_si_pcr == -1)
1433 mux->next_si_pcr = next_pcr + mux->si_interval * 300;
1434 else
1435 mux->next_si_pcr += mux->si_interval * 300;
1436
1437 if (!tsmux_write_si (mux))
1438 return FALSE;
1439
1440 next_pcr = get_current_pcr (mux, cur_ts);
1441 }
1442
1443 /* check if we need to rewrite any of the current pmts */
1444 for (cur = mux->programs; cur; cur = cur->next) {
1445 TsMuxProgram *program = (TsMuxProgram *) cur->data;
1446 gboolean write_pmt;
1447
1448 if (program->next_pmt_pcr == -1 || program->pmt_changed)
1449 write_pmt = TRUE;
1450 else if (next_pcr > program->next_pmt_pcr)
1451 write_pmt = TRUE;
1452 else
1453 write_pmt = FALSE;
1454
1455 if (write_pmt) {
1456 if (program->next_pmt_pcr == -1)
1457 program->next_pmt_pcr = next_pcr + program->pmt_interval * 300;
1458 else
1459 program->next_pmt_pcr += program->pmt_interval * 300;
1460
1461 if (!tsmux_write_pmt (mux, program))
1462 return FALSE;
1463
1464 next_pcr = get_current_pcr (mux, cur_ts);
1465 }
1466
1467 if (program->scte35_pid != 0) {
1468 gboolean write_scte_null = FALSE;
1469 if (program->next_scte35_pcr == -1)
1470 write_scte_null = TRUE;
1471 else if (next_pcr > program->next_scte35_pcr)
1472 write_scte_null = TRUE;
1473
1474 if (write_scte_null) {
1475 GST_DEBUG ("next scte35 pcr %" G_GINT64_FORMAT,
1476 program->next_scte35_pcr);
1477 if (program->next_scte35_pcr == -1)
1478 program->next_scte35_pcr =
1479 next_pcr + program->scte35_null_interval * 300;
1480 else
1481 program->next_scte35_pcr += program->scte35_null_interval * 300;
1482 GST_DEBUG ("next scte35 NOW pcr %" G_GINT64_FORMAT,
1483 program->next_scte35_pcr);
1484
1485 if (!tsmux_write_scte_null (mux, program))
1486 return FALSE;
1487
1488 next_pcr = get_current_pcr (mux, cur_ts);
1489 }
1490 }
1491
1492 program->wrote_si = TRUE;
1493 }
1494
1495 return TRUE;
1496 }
1497
1498 static gboolean
pad_stream(TsMux * mux,TsMuxStream * stream,gint64 cur_ts)1499 pad_stream (TsMux * mux, TsMuxStream * stream, gint64 cur_ts)
1500 {
1501 guint64 bitrate;
1502 GstBuffer *buf = NULL;
1503 GstMapInfo map;
1504 gboolean ret = TRUE;
1505 GstClockTimeDiff diff;
1506 guint64 start_n_bytes;
1507
1508 if (!mux->bitrate)
1509 goto done;
1510
1511 if (!GST_CLOCK_STIME_IS_VALID (cur_ts))
1512 goto done;
1513
1514 if (!GST_CLOCK_STIME_IS_VALID (stream->first_ts))
1515 stream->first_ts = cur_ts;
1516
1517 diff = GST_CLOCK_DIFF (stream->first_ts, cur_ts);
1518 if (diff == 0)
1519 goto done;
1520
1521 start_n_bytes = mux->n_bytes;
1522 do {
1523 GST_LOG ("Transport stream bitrate: %" G_GUINT64_FORMAT " over %"
1524 G_GUINT64_FORMAT " bytes, duration %" GST_TIME_FORMAT,
1525 gst_util_uint64_scale (mux->n_bytes * 8, TSMUX_CLOCK_FREQ, diff),
1526 mux->n_bytes, GST_TIME_ARGS (diff * GST_SECOND / TSMUX_CLOCK_FREQ));
1527
1528 /* calculate what the overall bitrate will be if we add 1 more packet */
1529 bitrate =
1530 gst_util_uint64_scale ((mux->n_bytes + TSMUX_PACKET_LENGTH) * 8,
1531 TSMUX_CLOCK_FREQ, diff);
1532
1533 if (bitrate <= mux->bitrate) {
1534 gint64 new_pcr;
1535 guint payload_len, payload_offs;
1536
1537 if (!tsmux_get_buffer (mux, &buf)) {
1538 ret = FALSE;
1539 goto done;
1540 }
1541
1542 gst_buffer_map (buf, &map, GST_MAP_READ);
1543
1544 if ((new_pcr =
1545 write_new_pcr (mux, stream, get_current_pcr (mux,
1546 cur_ts), get_next_pcr (mux, cur_ts)) != -1)) {
1547 GST_LOG ("Writing PCR-only packet on PID 0x%04x", stream->pi.pid);
1548 tsmux_write_ts_header (mux, map.data, &stream->pi, &payload_len,
1549 &payload_offs, 0);
1550 } else {
1551 GST_LOG ("Writing null stuffing packet");
1552 if (!rewrite_si (mux, cur_ts)) {
1553 ret = FALSE;
1554 goto done;
1555 }
1556 tsmux_write_null_ts_header (map.data);
1557 }
1558
1559 gst_buffer_unmap (buf, &map);
1560
1561 stream->pi.flags &= TSMUX_PACKET_FLAG_PES_FULL_HEADER;
1562
1563 if (!(ret = tsmux_packet_out (mux, buf, new_pcr)))
1564 goto done;
1565 }
1566 } while (bitrate < mux->bitrate);
1567
1568 if (mux->n_bytes != start_n_bytes) {
1569 GST_LOG ("Finished padding the mux");
1570 }
1571
1572 done:
1573 return ret;
1574 }
1575
1576 /**
1577 * tsmux_write_stream_packet:
1578 * @mux: a #TsMux
1579 * @stream: a #TsMuxStream
1580 *
1581 * Write a packet of @stream.
1582 *
1583 * Returns: TRUE if the packet could be written.
1584 */
1585 gboolean
tsmux_write_stream_packet(TsMux * mux,TsMuxStream * stream)1586 tsmux_write_stream_packet (TsMux * mux, TsMuxStream * stream)
1587 {
1588 guint payload_len, payload_offs;
1589 TsMuxPacketInfo *pi = &stream->pi;
1590 gboolean res;
1591 gint64 new_pcr = -1;
1592 GstBuffer *buf = NULL;
1593 GstMapInfo map;
1594
1595 g_return_val_if_fail (mux != NULL, FALSE);
1596 g_return_val_if_fail (stream != NULL, FALSE);
1597
1598 if (tsmux_stream_is_pcr (stream)) {
1599 gint64 cur_ts = CLOCK_BASE;
1600 if (tsmux_stream_get_dts (stream) != G_MININT64)
1601 cur_ts += tsmux_stream_get_dts (stream);
1602 else
1603 cur_ts += tsmux_stream_get_pts (stream);
1604
1605 if (!rewrite_si (mux, cur_ts))
1606 goto fail;
1607
1608 if (!pad_stream (mux, stream, cur_ts))
1609 goto fail;
1610
1611 new_pcr =
1612 write_new_pcr (mux, stream, get_current_pcr (mux, cur_ts),
1613 get_next_pcr (mux, cur_ts));
1614 }
1615
1616 pi->packet_start_unit_indicator = tsmux_stream_at_pes_start (stream);
1617 if (pi->packet_start_unit_indicator) {
1618 tsmux_stream_initialize_pes_packet (stream);
1619 if (stream->dts != G_MININT64)
1620 stream->dts += CLOCK_BASE;
1621 if (stream->pts != G_MININT64)
1622 stream->pts += CLOCK_BASE;
1623 }
1624 pi->stream_avail = tsmux_stream_bytes_avail (stream);
1625
1626 /* obtain buffer */
1627 if (!tsmux_get_buffer (mux, &buf))
1628 return FALSE;
1629
1630 gst_buffer_map (buf, &map, GST_MAP_READ);
1631
1632 if (!tsmux_write_ts_header (mux, map.data, pi, &payload_len, &payload_offs,
1633 pi->stream_avail))
1634 goto fail;
1635
1636
1637 if (!tsmux_stream_get_data (stream, map.data + payload_offs, payload_len))
1638 goto fail;
1639
1640 gst_buffer_unmap (buf, &map);
1641
1642 GST_DEBUG ("Writing PES of size %d", (int) gst_buffer_get_size (buf));
1643 res = tsmux_packet_out (mux, buf, new_pcr);
1644
1645 /* Reset all dynamic flags */
1646 stream->pi.flags &= TSMUX_PACKET_FLAG_PES_FULL_HEADER;
1647
1648 return res;
1649
1650 /* ERRORS */
1651 fail:
1652 {
1653 if (buf) {
1654 gst_buffer_unmap (buf, &map);
1655 gst_buffer_unref (buf);
1656 }
1657 return FALSE;
1658 }
1659 }
1660
1661 /**
1662 * tsmux_program_free:
1663 * @program: a #TsMuxProgram
1664 *
1665 * Free the resources of @program. After this call @program can not be used
1666 * anymore.
1667 */
1668 void
tsmux_program_free(TsMuxProgram * program)1669 tsmux_program_free (TsMuxProgram * program)
1670 {
1671 g_return_if_fail (program != NULL);
1672
1673 /* Free PMT section */
1674 if (program->pmt.section)
1675 gst_mpegts_section_unref (program->pmt.section);
1676 if (program->scte35_null_section)
1677 tsmux_section_free (program->scte35_null_section);
1678
1679 g_ptr_array_free (program->streams, TRUE);
1680 g_slice_free (TsMuxProgram, program);
1681 }
1682
1683 /**
1684 * tsmux_program_set_pmt_pid:
1685 * @program: A #TsmuxProgram
1686 * @pmt_pid: PID to write PMT for this program
1687 */
1688 void
tsmux_program_set_pmt_pid(TsMuxProgram * program,guint16 pmt_pid)1689 tsmux_program_set_pmt_pid (TsMuxProgram * program, guint16 pmt_pid)
1690 {
1691 program->pmt_pid = pmt_pid;
1692 }
1693
1694 static gint
compare_program_number(gconstpointer a,gconstpointer b)1695 compare_program_number (gconstpointer a, gconstpointer b)
1696 {
1697 const GstMpegtsPatProgram *pgm1 = *(const GstMpegtsPatProgram * const *) a;
1698 const GstMpegtsPatProgram *pgm2 = *(const GstMpegtsPatProgram * const *) b;
1699 gint num1 = pgm1->program_number, num2 = pgm2->program_number;
1700
1701 return num1 - num2;
1702 }
1703
1704 static gboolean
tsmux_write_pat(TsMux * mux)1705 tsmux_write_pat (TsMux * mux)
1706 {
1707
1708 if (mux->pat_changed) {
1709 /* program_association_section ()
1710 * for (i = 0; i < N; i++) {
1711 * program_number 16 uimsbf
1712 * reserved 3 bslbf
1713 * network_PID_or_program_map_PID 13 uimbsf
1714 * }
1715 * CRC_32 32 rbchof
1716 */
1717 GList *cur;
1718 GPtrArray *pat;
1719
1720 pat = gst_mpegts_pat_new ();
1721
1722 for (cur = mux->programs; cur; cur = cur->next) {
1723 GstMpegtsPatProgram *pat_pgm;
1724 TsMuxProgram *program = (TsMuxProgram *) cur->data;
1725
1726 pat_pgm = gst_mpegts_pat_program_new ();
1727 pat_pgm->program_number = program->pgm_number;
1728 pat_pgm->network_or_program_map_PID = program->pmt_pid;
1729
1730 g_ptr_array_add (pat, pat_pgm);
1731 }
1732
1733 g_ptr_array_sort (pat, compare_program_number);
1734
1735 if (mux->pat.section)
1736 gst_mpegts_section_unref (mux->pat.section);
1737
1738 mux->pat.section = gst_mpegts_section_from_pat (pat, mux->transport_id);
1739
1740 mux->pat.section->version_number = mux->pat_version++;
1741
1742 TS_DEBUG ("PAT has %d programs", mux->nb_programs);
1743 mux->pat_changed = FALSE;
1744 }
1745
1746 return tsmux_section_write_packet (NULL, &mux->pat, mux);
1747 }
1748
1749 static gboolean
tsmux_write_pmt(TsMux * mux,TsMuxProgram * program)1750 tsmux_write_pmt (TsMux * mux, TsMuxProgram * program)
1751 {
1752
1753 if (program->pmt_changed) {
1754 /* program_association_section ()
1755 * reserved 3 bslbf
1756 * PCR_PID 13 uimsbf
1757 * reserved 4 bslbf
1758 * program_info_length 12 uimsbf
1759 * for (i = 0; i < N; i++)
1760 * descriptor ()
1761 *
1762 * for (i = 0; i < N1; i++) {
1763 * stream_type 8 uimsbf
1764 * reserved 3 bslbf
1765 * elementary_PID 13 uimbsf
1766 * reserved 4 bslbf
1767 * ES_info_length 12 uimbsf
1768 * for (i = 0; i < N1; i++) {
1769 * descriptor ();
1770 * }
1771 * }
1772 */
1773 GstMpegtsDescriptor *descriptor;
1774 GstMpegtsPMT *pmt;
1775 #if 0
1776 /* See note about bluray descriptors below */
1777 guint8 desc[] = { 0x0F, 0xFF, 0xFC, 0xFC };
1778 #endif
1779 guint i;
1780
1781 pmt = gst_mpegts_pmt_new ();
1782
1783 if (program->pcr_stream == NULL)
1784 pmt->pcr_pid = 0x1FFF;
1785 else
1786 pmt->pcr_pid = tsmux_stream_get_pid (program->pcr_stream);
1787
1788 #if 0
1789 /* FIXME : These two descriptors should not be added in all PMT
1790 * but only in "bluray-compatible" mpeg-ts output. I even have my
1791 * doubt whether the DTCP descriptor is even needed */
1792 descriptor = gst_mpegts_descriptor_from_registration ("HDMV", NULL, 0);
1793 g_ptr_array_add (pmt->descriptors, descriptor);
1794
1795 /* DTCP descriptor, see
1796 * http://www.dtcp.com/documents/dtcp/info-20150204-dtcp-v1-rev%201-71.pdf */
1797 descriptor = gst_mpegts_descriptor_from_custom (0x88, desc, 4);
1798 g_ptr_array_add (pmt->descriptors, descriptor);
1799 #endif
1800
1801 /* Will SCTE-35 be potentially used ? */
1802 if (program->scte35_pid != 0) {
1803 descriptor = gst_mpegts_descriptor_from_registration ("CUEI", NULL, 0);
1804 g_ptr_array_add (pmt->descriptors, descriptor);
1805 }
1806
1807 /* Write out the entries */
1808 for (i = 0; i < program->streams->len; i++) {
1809 GstMpegtsPMTStream *pmt_stream;
1810 TsMuxStream *stream = g_ptr_array_index (program->streams, i);
1811
1812 pmt_stream = gst_mpegts_pmt_stream_new ();
1813
1814 /* FIXME: Use API to retrieve this from the stream */
1815 pmt_stream->stream_type = stream->stream_type;
1816 pmt_stream->pid = tsmux_stream_get_pid (stream);
1817
1818 /* Write any ES descriptors needed */
1819 tsmux_stream_get_es_descrs (stream, pmt_stream);
1820 g_ptr_array_add (pmt->streams, pmt_stream);
1821 }
1822
1823 /* Will SCTE-35 be potentially used ? */
1824 if (program->scte35_pid != 0) {
1825 GstMpegtsPMTStream *pmt_stream = gst_mpegts_pmt_stream_new ();
1826 pmt_stream->stream_type = GST_MPEGTS_STREAM_TYPE_SCTE_SIT;
1827 pmt_stream->pid = program->scte35_pid;
1828 g_ptr_array_add (pmt->streams, pmt_stream);
1829 }
1830
1831 TS_DEBUG ("PMT for program %d has %d streams",
1832 program->pgm_number, program->streams->len);
1833
1834 pmt->program_number = program->pgm_number;
1835
1836 program->pmt.pi.pid = program->pmt_pid;
1837 program->pmt_changed = FALSE;
1838
1839 if (program->pmt.section)
1840 gst_mpegts_section_unref (program->pmt.section);
1841
1842 program->pmt.section = gst_mpegts_section_from_pmt (pmt, program->pmt_pid);
1843 program->pmt.section->version_number = program->pmt_version++;
1844 }
1845
1846 return tsmux_section_write_packet (NULL, &program->pmt, mux);
1847 }
1848
1849 static gboolean
tsmux_write_scte_null(TsMux * mux,TsMuxProgram * program)1850 tsmux_write_scte_null (TsMux * mux, TsMuxProgram * program)
1851 {
1852 /* SCTE-35 NULL section is created when PID is set */
1853 GST_LOG ("Writing SCTE NULL packet");
1854 return tsmux_section_write_packet (NULL, program->scte35_null_section, mux);
1855 }
1856
1857 void
tsmux_set_bitrate(TsMux * mux,guint64 bitrate)1858 tsmux_set_bitrate (TsMux * mux, guint64 bitrate)
1859 {
1860 mux->bitrate = bitrate;
1861 }
1862