2 * Copyright 2006 BBC and Fluendo S.A.
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.
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/.
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
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.
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.
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.
39 * Unless otherwise indicated, Source Code is licensed under MIT license.
40 * See further explanation attached in License Statement (distributed in the file
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:
50 * The above copyright notice and this permission notice shall be included in all
51 * copies or substantial portions of the Software.
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
61 * SPDX-License-Identifier: MPL-1.1 OR MIT OR LGPL-2.0-or-later
70 #include <gst/mpegts/mpegts.h>
73 #include "tsmuxstream.h"
75 #define GST_CAT_DEFAULT gst_base_ts_mux_debug
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
83 #define TSMUX_SECTION_HDR_SIZE 8
85 #define TSMUX_DEFAULT_NETWORK_ID 0x0001
86 #define TSMUX_DEFAULT_TS_ID 0x0001
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
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.
95 #define TSMUX_PCR_OFFSET (TSMUX_CLOCK_FREQ / 8)
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)
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,
108 static gboolean tsmux_write_ts_header (TsMux * mux, guint8 * buf,
109 TsMuxPacketInfo * pi, guint stream_avail, guint * payload_len_out,
110 guint * payload_offset_out);
113 tsmux_section_free (TsMuxSection * section)
115 gst_mpegts_section_unref (section->section);
116 g_slice_free (TsMuxSection, section);
120 tsmux_new_stream_default (guint16 pid, guint stream_type, gpointer user_data)
122 return tsmux_stream_new (pid, stream_type);
128 * Create a new muxer session.
130 * Returns: A new #TsMux object.
137 mux = g_slice_new0 (TsMux);
139 mux->transport_id = TSMUX_DEFAULT_TS_ID;
141 mux->next_pgm_no = TSMUX_START_PROGRAM_ID;
142 mux->next_pmt_pid = TSMUX_START_PMT_PID;
143 mux->next_stream_pid = TSMUX_START_ES_PID;
145 mux->pat_changed = TRUE;
146 mux->next_pat_pcr = -1;
147 mux->pat_interval = TSMUX_DEFAULT_PAT_INTERVAL;
149 mux->si_changed = TRUE;
150 mux->si_interval = TSMUX_DEFAULT_SI_INTERVAL;
152 mux->pcr_interval = TSMUX_DEFAULT_PCR_INTERVAL;
154 mux->next_si_pcr = -1;
156 mux->si_sections = g_hash_table_new_full (g_direct_hash, g_direct_equal,
157 NULL, (GDestroyNotify) tsmux_section_free);
159 mux->new_stream_func = tsmux_new_stream_default;
160 mux->new_stream_data = NULL;
162 mux->first_pcr_ts = G_MININT64;
168 * tsmux_set_write_func:
170 * @func: a user callback function
171 * @user_data: user data passed to @func
173 * Set the callback function and user data to be called when @mux has output to
174 * produce. @user_data will be passed as user data in @func.
177 tsmux_set_write_func (TsMux * mux, TsMuxWriteFunc func, void *user_data)
179 g_return_if_fail (mux != NULL);
181 mux->write_func = func;
182 mux->write_func_data = user_data;
186 * tsmux_set_alloc_func:
188 * @func: a user callback function
189 * @user_data: user data passed to @func
191 * Set the callback function and user data to be called when @mux needs
192 * a new buffer to write a packet into.
193 * @user_data will be passed as user data in @func.
196 tsmux_set_alloc_func (TsMux * mux, TsMuxAllocFunc func, void *user_data)
198 g_return_if_fail (mux != NULL);
200 mux->alloc_func = func;
201 mux->alloc_func_data = user_data;
205 * tsmux_set_new_stream_func:
207 * @func: a user callback function
208 * @user_data: user data passed to @func
210 * Set the callback function and user data to be called when @mux needs
211 * to create a new stream.
212 * @user_data will be passed as user data in @func.
215 tsmux_set_new_stream_func (TsMux * mux, TsMuxNewStreamFunc func,
218 g_return_if_fail (mux != NULL);
220 mux->new_stream_func = func;
221 mux->new_stream_data = user_data;
225 * tsmux_set_pat_interval:
227 * @freq: a new PAT interval
229 * Set the interval (in cycles of the 90kHz clock) for writing out the PAT table.
231 * Many transport stream clients might have problems if the PAT table is not
232 * inserted in the stream at regular intervals, especially when initially trying
233 * to figure out the contents of the stream.
236 tsmux_set_pat_interval (TsMux * mux, guint freq)
238 g_return_if_fail (mux != NULL);
240 mux->pat_interval = freq;
244 * tsmux_set_pcr_interval:
246 * @freq: a new PCR interval
248 * Set the interval (in cycles of the 90kHz clock) for writing the PCR.
251 tsmux_set_pcr_interval (TsMux * mux, guint freq)
253 g_return_if_fail (mux != NULL);
255 mux->pcr_interval = freq;
259 * tsmux_get_pat_interval:
262 * Get the configured PAT interval. See also tsmux_set_pat_interval().
264 * Returns: the configured PAT interval
267 tsmux_get_pat_interval (TsMux * mux)
269 g_return_val_if_fail (mux != NULL, 0);
271 return mux->pat_interval;
278 * Resends the PAT before the next stream packet.
281 tsmux_resend_pat (TsMux * mux)
283 g_return_if_fail (mux != NULL);
285 mux->next_pat_pcr = -1;
289 * tsmux_set_si_interval:
291 * @freq: a new SI table interval
293 * Set the interval (in cycles of the 90kHz clock) for writing out the SI tables.
297 tsmux_set_si_interval (TsMux * mux, guint freq)
299 g_return_if_fail (mux != NULL);
301 mux->si_interval = freq;
305 * tsmux_get_si_interval:
308 * Get the configured SI table interval. See also tsmux_set_si_interval().
310 * Returns: the configured SI interval
313 tsmux_get_si_interval (TsMux * mux)
315 g_return_val_if_fail (mux != NULL, 0);
317 return mux->si_interval;
324 * Resends the SI tables before the next stream packet.
328 tsmux_resend_si (TsMux * mux)
330 g_return_if_fail (mux != NULL);
332 mux->next_si_pcr = -1;
336 * tsmux_add_mpegts_si_section:
338 * @section: (transfer full): a #GstMpegtsSection to add
340 * Add a Service Information #GstMpegtsSection to the stream
342 * Returns: %TRUE on success, %FALSE otherwise
345 tsmux_add_mpegts_si_section (TsMux * mux, GstMpegtsSection * section)
347 TsMuxSection *tsmux_section;
349 g_return_val_if_fail (mux != NULL, FALSE);
350 g_return_val_if_fail (section != NULL, FALSE);
351 g_return_val_if_fail (mux->si_sections != NULL, FALSE);
353 tsmux_section = g_slice_new0 (TsMuxSection);
355 GST_DEBUG ("Adding mpegts section with type %d to mux",
356 section->section_type);
358 tsmux_section->section = section;
359 tsmux_section->pi.pid = section->pid;
361 g_hash_table_insert (mux->si_sections,
362 GINT_TO_POINTER (section->section_type), tsmux_section);
364 mux->si_changed = TRUE;
374 * Free all resources associated with @mux. After calling this function @mux can
375 * not be used anymore.
378 tsmux_free (TsMux * mux)
382 g_return_if_fail (mux != NULL);
384 /* Free PAT section */
385 if (mux->pat.section)
386 gst_mpegts_section_unref (mux->pat.section);
388 /* Free all programs */
389 for (cur = mux->programs; cur; cur = cur->next) {
390 TsMuxProgram *program = (TsMuxProgram *) cur->data;
392 tsmux_program_free (program);
394 g_list_free (mux->programs);
396 /* Free all streams */
397 for (cur = mux->streams; cur; cur = cur->next) {
398 TsMuxStream *stream = (TsMuxStream *) cur->data;
400 tsmux_stream_free (stream);
402 g_list_free (mux->streams);
404 /* Free SI table sections */
405 g_hash_table_unref (mux->si_sections);
407 g_slice_free (TsMux, mux);
411 tsmux_program_compare (TsMuxProgram * program, gint * needle)
413 return (program->pgm_number - *needle);
420 * Create a new program in the missing session @mux.
422 * Returns: a new #TsMuxProgram or %NULL when the maximum number of programs has
426 tsmux_program_new (TsMux * mux, gint prog_id)
428 TsMuxProgram *program;
430 g_return_val_if_fail (mux != NULL, NULL);
432 /* Ensure we have room for another program */
433 if (mux->nb_programs == TSMUX_MAX_PROGRAMS)
436 program = g_slice_new0 (TsMuxProgram);
438 program->pmt_changed = TRUE;
439 program->pmt_interval = TSMUX_DEFAULT_PMT_INTERVAL;
441 program->next_pmt_pcr = -1;
444 program->pgm_number = mux->next_pgm_no++;
445 while (g_list_find_custom (mux->programs, &program->pgm_number,
446 (GCompareFunc) tsmux_program_compare) != NULL) {
447 program->pgm_number = mux->next_pgm_no++;
450 program->pgm_number = prog_id;
451 while (g_list_find_custom (mux->programs, &program->pgm_number,
452 (GCompareFunc) tsmux_program_compare) != NULL) {
453 program->pgm_number++;
457 program->pmt_pid = mux->next_pmt_pid++;
458 program->pcr_stream = NULL;
460 /* SCTE35 is disabled by default */
461 program->scte35_pid = 0;
462 program->scte35_null_interval = TSMUX_DEFAULT_SCTE_35_NULL_INTERVAL;
463 program->next_scte35_pcr = -1;
465 /* mux->streams owns the streams */
466 program->streams = g_ptr_array_new_full (1, NULL);
468 mux->programs = g_list_prepend (mux->programs, program);
470 mux->pat_changed = TRUE;
476 tsmux_program_delete (TsMux * mux, TsMuxProgram * program)
478 g_return_val_if_fail (mux != NULL, FALSE);
480 if (mux->nb_programs == 0)
486 mux->programs = g_list_remove (mux->programs, program);
488 mux->pat_changed = TRUE;
489 tsmux_program_free ((TsMuxProgram *) program);
495 * tsmux_set_pmt_interval:
496 * @program: a #TsMuxProgram
497 * @freq: a new PMT interval
499 * Set the interval (in cycles of the 90kHz clock) for writing out the PMT table.
501 * Many transport stream clients might have problems if the PMT table is not
502 * inserted in the stream at regular intervals, especially when initially trying
503 * to figure out the contents of the stream.
506 tsmux_set_pmt_interval (TsMuxProgram * program, guint freq)
508 g_return_if_fail (program != NULL);
510 program->pmt_interval = freq;
514 * tsmux_get_pmt_interval:
515 * @program: a #TsMuxProgram
517 * Get the configured PMT interval. See also tsmux_set_pmt_interval().
519 * Returns: the configured PMT interval
522 tsmux_get_pmt_interval (TsMuxProgram * program)
524 g_return_val_if_fail (program != NULL, 0);
526 return program->pmt_interval;
530 * tsmux_program_set_scte35_interval:
531 * @program: a #TsMuxProgram
532 * @freq: a new SCTE-35 NULL interval
534 * Set the interval (in cycles of the 90kHz clock) for sending out the SCTE-35
535 * NULL command. This is only effective is the SCTE-35 PID is not 0.
538 tsmux_program_set_scte35_interval (TsMuxProgram * program, guint interval)
540 g_return_if_fail (program != NULL);
542 program->scte35_null_interval = interval;
547 * @program: a #TsMuxProgram
549 * Resends the PMT before the next stream packet.
552 tsmux_resend_pmt (TsMuxProgram * program)
554 g_return_if_fail (program != NULL);
556 program->next_pmt_pcr = -1;
560 * tsmux_program_set_scte35_pid:
561 * @program: a #TsMuxProgram
562 * @pid: The pid to use, or 0 to deactivate usage.
564 * Set the @pid to use for sending SCTE-35 packets on the given
567 * This needs to be called as early as possible if SCTE-35 sections
568 * are even going to be used with the given @program so that the PMT
569 * can be properly configured.
572 tsmux_program_set_scte35_pid (TsMuxProgram * program, guint16 pid)
574 TsMuxSection *section;
575 GstMpegtsSCTESIT *sit;
576 g_return_if_fail (program != NULL);
578 program->scte35_pid = pid;
579 /* Create/Update the section */
580 if (program->scte35_null_section) {
581 tsmux_section_free (program->scte35_null_section);
582 program->scte35_null_section = NULL;
585 program->scte35_null_section = section = g_slice_new0 (TsMuxSection);
586 section->pi.pid = pid;
587 sit = gst_mpegts_scte_null_new ();
588 section->section = gst_mpegts_section_from_scte_sit (sit, pid);
593 * tsmux_program_get_scte35_pid:
594 * @program: a #TsMuxProgram
596 * Get the PID configured for sending SCTE-35 packets.
598 * Returns: the configured SCTE-35 PID, or 0 if not active.
601 tsmux_program_get_scte35_pid (TsMuxProgram * program)
603 g_return_val_if_fail (program != NULL, 0);
605 return program->scte35_pid;
609 * tsmux_program_add_stream:
610 * @program: a #TsMuxProgram
611 * @stream: a #TsMuxStream
613 * Add @stream to @program.
616 tsmux_program_add_stream (TsMuxProgram * program, TsMuxStream * stream)
620 gint pmt_index, array_index = -1 /* append */ ;
623 g_return_if_fail (program != NULL);
624 g_return_if_fail (stream != NULL);
626 streams = program->streams;
627 pmt_index = stream->pmt_index;
628 pid = tsmux_stream_get_pid (stream);
630 if (pmt_index >= 0) {
631 /* Insert into streams with known indices */
632 for (i = 0; i < streams->len; i++) {
633 TsMuxStream *s = g_ptr_array_index (streams, i);
635 if (s->pmt_index < 0 || pmt_index < s->pmt_index) {
637 GST_DEBUG ("PID 0x%04x: Using known-order index %d/%u",
638 pid, array_index, streams->len);
643 /* Insert after streams with known indices, sorted by PID */
644 for (i = 0; i < streams->len; i++) {
645 TsMuxStream *s = g_ptr_array_index (streams, i);
647 if (s->pmt_index < 0 && pid < tsmux_stream_get_pid (s)) {
649 GST_DEBUG ("PID 0x%04x: Using PID-order index %d/%u",
650 pid, array_index, streams->len);
656 g_ptr_array_insert (streams, array_index, stream);
657 program->pmt_changed = TRUE;
661 * tsmux_program_set_pcr_stream:
662 * @program: a #TsMuxProgram
663 * @stream: a #TsMuxStream
665 * Set @stream as the PCR stream for @program, overwriting the previously
666 * configured PCR stream. When @stream is NULL, program will have no PCR stream
670 tsmux_program_set_pcr_stream (TsMuxProgram * program, TsMuxStream * stream)
672 g_return_if_fail (program != NULL);
674 if (program->pcr_stream == stream)
677 if (program->pcr_stream != NULL)
678 tsmux_stream_pcr_unref (program->pcr_stream);
680 tsmux_stream_pcr_ref (stream);
681 program->pcr_stream = stream;
683 program->pmt_changed = TRUE;
690 * Get a new free PID.
692 * Returns: a new free PID.
695 tsmux_get_new_pid (TsMux * mux)
697 g_return_val_if_fail (mux != NULL, -1);
699 /* make sure this PID is free
700 * (and not taken by a specific earlier request) */
702 mux->next_stream_pid++;
703 } while (tsmux_find_stream (mux, mux->next_stream_pid));
705 return mux->next_stream_pid;
709 * tsmux_create_stream:
711 * @stream_type: the stream type
712 * @pid: the PID of the new stream.
714 * Create a new stream of @stream_type in the muxer session @mux.
716 * When @pid is set to #TSMUX_PID_AUTO, a new free PID will automatically
717 * be allocated for the new stream.
719 * Returns: a new #TsMuxStream.
722 tsmux_create_stream (TsMux * mux, guint stream_type, guint16 pid,
728 g_return_val_if_fail (mux != NULL, NULL);
729 g_return_val_if_fail (mux->new_stream_func != NULL, NULL);
731 if (pid == TSMUX_PID_AUTO) {
732 new_pid = tsmux_get_new_pid (mux);
734 new_pid = pid & 0x1FFF;
737 /* Ensure we're not creating a PID collision */
738 if (tsmux_find_stream (mux, new_pid))
741 stream = mux->new_stream_func (new_pid, stream_type, mux->new_stream_data);
743 mux->streams = g_list_prepend (mux->streams, stream);
747 strncpy (stream->language, language, 4);
748 stream->language[3] = 0;
750 stream->language[0] = 0;
759 * @pid: the PID to find.
761 * Find the stream associated with PID.
763 * Returns: a #TsMuxStream with @pid or NULL when the stream was not found.
766 tsmux_find_stream (TsMux * mux, guint16 pid)
768 TsMuxStream *found = NULL;
771 g_return_val_if_fail (mux != NULL, NULL);
773 for (cur = mux->streams; cur; cur = cur->next) {
774 TsMuxStream *stream = (TsMuxStream *) cur->data;
776 if (tsmux_stream_get_pid (stream) == pid) {
785 tsmux_program_remove_stream (TsMuxProgram * program, TsMuxStream * stream)
787 GPtrArray *streams = program->streams;
789 if (!g_ptr_array_remove (streams, stream)) {
790 g_warn_if_reached ();
794 return streams->len == 0;
799 tsmux_remove_stream (TsMux * mux, guint16 pid, TsMuxProgram * program)
802 gboolean ret = FALSE;
804 g_return_val_if_fail (mux != NULL, FALSE);
806 for (cur = mux->streams; cur; cur = cur->next) {
807 TsMuxStream *stream = (TsMuxStream *) cur->data;
809 if (tsmux_stream_get_pid (stream) == pid) {
810 ret = tsmux_program_remove_stream (program, stream);
811 mux->streams = g_list_remove (mux->streams, stream);
812 tsmux_stream_free (stream);
818 tsmux_program_delete (mux, program);
824 tsmux_get_buffer (TsMux * mux, GstBuffer ** buf)
826 g_return_val_if_fail (buf, FALSE);
828 if (G_UNLIKELY (!mux->alloc_func))
831 mux->alloc_func (buf, mux->alloc_func_data);
836 g_assert (gst_buffer_get_size (*buf) == TSMUX_PACKET_LENGTH);
841 tsmux_packet_out (TsMux * mux, GstBuffer * buf, gint64 pcr)
843 g_return_val_if_fail (buf, FALSE);
845 if (G_UNLIKELY (mux->write_func == NULL)) {
846 gst_buffer_unref (buf);
851 GST_BUFFER_PTS (buf) =
852 gst_util_uint64_scale (mux->n_bytes * 8, GST_SECOND, mux->bitrate);
854 /* Check and insert a PCR observation for each program if needed,
855 * but only for programs that have written their SI at least once,
856 * so the stream starts with PAT/PMT */
857 if (mux->first_pcr_ts != G_MININT64) {
860 for (cur = mux->programs; cur; cur = cur->next) {
861 TsMuxProgram *program = (TsMuxProgram *) cur->data;
862 TsMuxStream *stream = program->pcr_stream;
863 gint64 cur_pcr, next_pcr, new_pcr;
865 if (!program->wrote_si)
868 cur_pcr = get_current_pcr (mux, 0);
869 next_pcr = get_next_pcr (mux, 0);
870 new_pcr = write_new_pcr (mux, stream, cur_pcr, next_pcr);
873 GstBuffer *pcr_buf = NULL;
876 if (!tsmux_get_buffer (mux, &pcr_buf)) {
880 gst_buffer_map (pcr_buf, &map, GST_MAP_WRITE);
881 tsmux_write_ts_header (mux, map.data, &stream->pi, 0, NULL, NULL);
882 gst_buffer_unmap (pcr_buf, &map);
884 stream->pi.flags &= TSMUX_PACKET_FLAG_PES_FULL_HEADER;
885 if (!tsmux_packet_out (mux, pcr_buf, new_pcr))
892 mux->n_bytes += gst_buffer_get_size (buf);
894 return mux->write_func (buf, mux->write_func_data, pcr);
897 gst_buffer_unref (buf);
902 * adaptation_field() {
903 * adaptation_field_length 8 uimsbf
904 * if(adaptation_field_length >0) {
905 * discontinuity_indicator 1 bslbf
906 * random_access_indicator 1 bslbf
907 * elementary_stream_priority_indicator 1 bslbf
910 * splicing_point_flag 1 bslbf
911 * transport_private_data_flag 1 bslbf
912 * adaptation_field_extension_flag 1 bslbf
913 * if(PCR_flag == '1') {
914 * program_clock_reference_base 33 uimsbf
916 * program_clock_reference_extension 9 uimsbf
918 * if(OPCR_flag == '1') {
919 * original_program_clock_reference_base 33 uimsbf
921 * original_program_clock_reference_extension 9 uimsbf
923 * if (splicing_point_flag == '1') {
924 * splice_countdown 8 tcimsbf
926 * if(transport_private_data_flag == '1') {
927 * transport_private_data_length 8 uimsbf
928 * for (i=0; i<transport_private_data_length;i++){
929 * private_data_byte 8 bslbf
932 * if (adaptation_field_extension_flag == '1' ) {
933 * adaptation_field_extension_length 8 uimsbf
935 * piecewise_rate_flag 1 bslbf
936 * seamless_splice_flag 1 bslbf
938 * if (ltw_flag == '1') {
939 * ltw_valid_flag 1 bslbf
940 * ltw_offset 15 uimsbf
942 * if (piecewise_rate_flag == '1') {
944 * piecewise_rate 22 uimsbf
946 * if (seamless_splice_flag == '1'){
947 * splice_type 4 bslbf
948 * DTS_next_AU[32..30] 3 bslbf
950 * DTS_next_AU[29..15] 15 bslbf
952 * DTS_next_AU[14..0] 15 bslbf
955 * for ( i=0;i<N;i++) {
960 * stuffing_byte 8 bslbf
966 tsmux_write_adaptation_field (guint8 * buf,
967 TsMuxPacketInfo * pi, guint8 min_length, guint8 * written)
972 g_assert (min_length <= TSMUX_PAYLOAD_LENGTH);
974 /* Write out all the fields from the packet info only if the
975 * user set the flag to request the adaptation field - if the flag
976 * isn't set, we're just supposed to write stuffing bytes */
977 if (pi->flags & TSMUX_PACKET_FLAG_ADAPTATION) {
978 TS_DEBUG ("writing adaptation fields");
979 if (pi->flags & TSMUX_PACKET_FLAG_DISCONT)
981 if (pi->flags & TSMUX_PACKET_FLAG_RANDOM_ACCESS)
983 if (pi->flags & TSMUX_PACKET_FLAG_PRIORITY)
985 if (pi->flags & TSMUX_PACKET_FLAG_WRITE_PCR) {
989 pcr_base = (pi->pcr / 300);
990 pcr_ext = (pi->pcr % 300);
993 TS_DEBUG ("Writing PCR %" G_GUINT64_FORMAT " + ext %u", pcr_base,
995 buf[pos++] = (pcr_base >> 25) & 0xff;
996 buf[pos++] = (pcr_base >> 17) & 0xff;
997 buf[pos++] = (pcr_base >> 9) & 0xff;
998 buf[pos++] = (pcr_base >> 1) & 0xff;
999 buf[pos++] = ((pcr_base << 7) & 0x80) | 0x7e | ((pcr_ext >> 8) & 0x01); /* set 6 reserve bits to 1 */
1000 buf[pos++] = (pcr_ext) & 0xff;
1002 if (pi->flags & TSMUX_PACKET_FLAG_WRITE_OPCR) {
1006 opcr_base = (pi->opcr / 300);
1007 opcr_ext = (pi->opcr % 300);
1010 TS_DEBUG ("Writing OPCR");
1011 buf[pos++] = (opcr_base >> 25) & 0xff;
1012 buf[pos++] = (opcr_base >> 17) & 0xff;
1013 buf[pos++] = (opcr_base >> 9) & 0xff;
1014 buf[pos++] = (opcr_base >> 1) & 0xff;
1015 buf[pos++] = ((opcr_base << 7) & 0x80) | 0x7e | ((opcr_ext >> 8) & 0x01); /* set 6 reserve bits to 1 */
1016 buf[pos++] = (opcr_ext) & 0xff;
1018 if (pi->flags & TSMUX_PACKET_FLAG_WRITE_SPLICE) {
1020 buf[pos++] = pi->splice_countdown;
1022 if (pi->private_data_len > 0) {
1024 /* Private data to write, ensure we have enough room */
1025 if ((1 + pi->private_data_len) > (TSMUX_PAYLOAD_LENGTH - pos))
1027 buf[pos++] = pi->private_data_len;
1028 memcpy (&(buf[pos]), pi->private_data, pi->private_data_len);
1029 pos += pi->private_data_len;
1030 TS_DEBUG ("%u bytes of private data", pi->private_data_len);
1032 if (pi->flags & TSMUX_PACKET_FLAG_WRITE_ADAPT_EXT) {
1034 TS_DEBUG ("FIXME: write Adaptation extension");
1035 /* Write an empty extension for now */
1037 buf[pos++] = 0x1f; /* lower 5 bits are reserved, and should be all 1 */
1040 /* Write the flags at the start */
1043 /* Stuffing bytes if needed */
1044 while (pos < min_length)
1047 /* Write the adaptation field length, which doesn't include its own byte */
1057 tsmux_write_ts_header (TsMux * mux, guint8 * buf, TsMuxPacketInfo * pi,
1058 guint stream_avail, guint * payload_len_out, guint * payload_offset_out)
1061 guint8 adaptation_flag = 0;
1062 guint8 adapt_min_length = 0;
1063 guint8 adapt_len = 0;
1065 gboolean write_adapt = FALSE;
1068 buf[0] = TSMUX_SYNC_BYTE;
1070 TS_DEBUG ("PID 0x%04x, counter = 0x%01x, %u bytes avail", pi->pid,
1071 mux->pid_packet_counts[pi->pid] & 0x0f, stream_avail);
1074 * transport_error_indicator
1075 * payload_unit_start_indicator
1076 * transport_priority: (00)
1080 if (pi->packet_start_unit_indicator) {
1081 tsmux_put16 (&tmp, 0x4000 | pi->pid);
1083 tsmux_put16 (&tmp, pi->pid);
1085 /* 2 bits: scrambling_control (NOT SUPPORTED) (00)
1086 * 2 bits: adaptation field control (1x has_adaptation_field | x1 has_payload)
1087 * 4 bits: continuity counter (xxxx)
1090 if (pi->flags & TSMUX_PACKET_FLAG_ADAPTATION) {
1094 if (stream_avail < TSMUX_PAYLOAD_LENGTH) {
1095 /* Need an adaptation field regardless for stuffing */
1096 adapt_min_length = TSMUX_PAYLOAD_LENGTH - stream_avail;
1103 /* Flag the adaptation field presence */
1104 adaptation_flag |= 0x20;
1105 res = tsmux_write_adaptation_field (buf + TSMUX_HEADER_LENGTH,
1106 pi, adapt_min_length, &adapt_len);
1107 if (G_UNLIKELY (res == FALSE))
1110 /* Should have written at least the number of bytes we requested */
1111 g_assert (adapt_len >= adapt_min_length);
1114 /* The amount of packet data we wrote is the remaining space after
1115 * the adaptation field */
1116 payload_len = TSMUX_PAYLOAD_LENGTH - adapt_len;
1118 if (payload_len_out)
1119 *payload_len_out = payload_len;
1121 g_assert (payload_len == 0);
1123 if (payload_offset_out)
1124 *payload_offset_out = TSMUX_HEADER_LENGTH + adapt_len;
1126 /* Now if we are going to write out some payload, flag that fact */
1127 if (payload_len > 0 && stream_avail > 0) {
1128 /* Flag the presence of a payload */
1129 adaptation_flag |= 0x10;
1131 /* We must have enough data to fill the payload, or some calculation
1133 g_assert (payload_len <= stream_avail);
1135 /* Packet with payload, increment the continuity counter */
1136 mux->pid_packet_counts[pi->pid]++;
1139 adaptation_flag |= mux->pid_packet_counts[pi->pid] & 0x0f;
1141 /* Write the byte of transport_scrambling_control, adaptation_field_control
1142 * + continuity counter out */
1143 buf[3] = adaptation_flag;
1147 TS_DEBUG ("Adaptation field of size >= %d + %d bytes payload",
1148 adapt_len, payload_len);
1150 TS_DEBUG ("Payload of %d bytes only", payload_len);
1157 tsmux_section_write_packet (TsMux * mux, TsMuxSection * section)
1161 guint payload_written = 0;
1162 gboolean ret = FALSE;
1164 g_return_val_if_fail (section != NULL, FALSE);
1165 g_return_val_if_fail (mux != NULL, FALSE);
1167 data = gst_mpegts_section_packetize (section->section, &data_size);
1169 GST_WARNING ("Could not packetize section");
1173 /* Mark the start of new PES unit */
1174 section->pi.packet_start_unit_indicator = TRUE;
1176 /* Mark payload data size */
1177 section->pi.stream_avail = data_size;
1179 while (section->pi.stream_avail > 0) {
1184 if (!tsmux_get_buffer (mux, &buf))
1187 if (!gst_buffer_map (buf, &map, GST_MAP_WRITE)) {
1188 gst_buffer_unref (buf);
1192 if (section->pi.packet_start_unit_indicator) {
1193 /* We need room for a pointer byte */
1194 if (!tsmux_write_ts_header (mux, map.data, §ion->pi,
1195 section->pi.stream_avail + 1, &len, &offset)) {
1196 gst_buffer_unmap (buf, &map);
1197 gst_buffer_unref (buf);
1201 /* Write the pointer byte */
1202 map.data[offset++] = 0x00;
1204 } else if (!tsmux_write_ts_header (mux, map.data, §ion->pi,
1205 section->pi.stream_avail, &len, &offset)) {
1206 gst_buffer_unmap (buf, &map);
1207 gst_buffer_unref (buf);
1211 GST_DEBUG ("Creating section packet for offset %u with length %u; %u bytes"
1212 " remaining", payload_written, len, section->pi.stream_avail - len);
1214 memcpy (map.data + offset, data + payload_written, len);
1215 gst_buffer_unmap (buf, &map);
1217 /* Push the packet without PCR */
1218 if (G_UNLIKELY (!tsmux_packet_out (mux, buf, -1)))
1221 section->pi.stream_avail -= len;
1222 payload_written += len;
1223 section->pi.packet_start_unit_indicator = FALSE;
1233 * tsmux_send_section:
1235 * @section: (transfer full): a #GstMpegtsSection to add
1237 * Send a @section immediately on the stream.
1239 * Returns: %TRUE on success, %FALSE otherwise
1242 tsmux_send_section (TsMux * mux, GstMpegtsSection * section)
1245 TsMuxSection tsmux_section;
1247 g_return_val_if_fail (mux != NULL, FALSE);
1248 g_return_val_if_fail (section != NULL, FALSE);
1250 memset (&tsmux_section, 0, sizeof (tsmux_section));
1252 GST_DEBUG ("Sending mpegts section with type %d to mux",
1253 section->section_type);
1255 tsmux_section.section = section;
1256 tsmux_section.pi.pid = section->pid;
1258 ret = tsmux_section_write_packet (mux, &tsmux_section);
1259 gst_mpegts_section_unref (section);
1265 tsmux_write_si_foreach (gpointer key, gpointer value, gpointer user_data)
1267 GstMpegtsSectionType section_type = GPOINTER_TO_INT (key);
1268 TsMuxSection *section = value;
1269 TsMux *mux = user_data;
1271 if (!tsmux_section_write_packet (mux, section))
1272 GST_WARNING ("Failed to send SI section (type %d)", section_type);
1276 tsmux_write_si (TsMux * mux)
1278 g_hash_table_foreach (mux->si_sections, tsmux_write_si_foreach, mux);
1279 mux->si_changed = FALSE;
1284 tsmux_write_null_ts_header (guint8 * buf)
1286 *buf++ = TSMUX_SYNC_BYTE;
1293 ts_to_pcr (gint64 ts)
1295 if (ts == G_MININT64) {
1299 return (ts - TSMUX_PCR_OFFSET) * (TSMUX_SYS_CLOCK_FREQ / TSMUX_CLOCK_FREQ);
1302 /* Calculate the PCR to write into the current packet */
1304 get_current_pcr (TsMux * mux, gint64 cur_ts)
1307 return ts_to_pcr (cur_ts);
1309 if (mux->first_pcr_ts == G_MININT64) {
1310 g_assert (cur_ts != G_MININT64);
1311 mux->first_pcr_ts = cur_ts;
1312 GST_DEBUG ("First PCR offset is %" G_GUINT64_FORMAT, cur_ts);
1315 return ts_to_pcr (mux->first_pcr_ts) +
1316 gst_util_uint64_scale ((mux->n_bytes + PCR_BYTE_OFFSET) * 8,
1317 TSMUX_SYS_CLOCK_FREQ, mux->bitrate);
1320 /* Predict the PCR at the next packet if possible */
1322 get_next_pcr (TsMux * mux, gint64 cur_ts)
1325 return ts_to_pcr (cur_ts);
1327 if (mux->first_pcr_ts == G_MININT64) {
1328 g_assert (cur_ts != G_MININT64);
1329 mux->first_pcr_ts = cur_ts;
1330 GST_DEBUG ("First PCR offset is %" G_GUINT64_FORMAT, cur_ts);
1333 return ts_to_pcr (mux->first_pcr_ts) +
1334 gst_util_uint64_scale ((mux->n_bytes + TSMUX_PACKET_LENGTH +
1335 PCR_BYTE_OFFSET) * 8, TSMUX_SYS_CLOCK_FREQ, mux->bitrate);
1339 write_new_pcr (TsMux * mux, TsMuxStream * stream, gint64 cur_pcr,
1342 if (stream->next_pcr == -1 || next_pcr > stream->next_pcr) {
1344 TSMUX_PACKET_FLAG_ADAPTATION | TSMUX_PACKET_FLAG_WRITE_PCR;
1345 stream->pi.pcr = cur_pcr;
1347 if (mux->bitrate && stream->next_pcr != -1 && cur_pcr >= stream->next_pcr) {
1348 GST_WARNING ("Writing PCR %" G_GUINT64_FORMAT " missed the target %"
1349 G_GUINT64_FORMAT " by %f ms", cur_pcr, stream->next_pcr,
1350 (double) (cur_pcr - stream->next_pcr) / 27000.0);
1352 /* Next PCR deadline is now plus the scheduled interval */
1353 stream->next_pcr = cur_pcr + mux->pcr_interval * 300;
1362 rewrite_si (TsMux * mux, gint64 cur_ts)
1369 next_pcr = get_next_pcr (mux, cur_ts);
1371 /* check if we need to rewrite pat */
1372 if (mux->next_pat_pcr == -1 || mux->pat_changed)
1374 else if (next_pcr > mux->next_pat_pcr)
1380 if (mux->next_pat_pcr == -1)
1381 mux->next_pat_pcr = next_pcr + mux->pat_interval * 300;
1383 mux->next_pat_pcr += mux->pat_interval * 300;
1385 if (!tsmux_write_pat (mux))
1388 next_pcr = get_next_pcr (mux, cur_ts);
1391 /* check if we need to rewrite sit */
1392 if (mux->next_si_pcr == -1 || mux->si_changed)
1394 else if (next_pcr > mux->next_si_pcr)
1400 if (mux->next_si_pcr == -1)
1401 mux->next_si_pcr = next_pcr + mux->si_interval * 300;
1403 mux->next_si_pcr += mux->si_interval * 300;
1405 if (!tsmux_write_si (mux))
1408 next_pcr = get_current_pcr (mux, cur_ts);
1411 /* check if we need to rewrite any of the current pmts */
1412 for (cur = mux->programs; cur; cur = cur->next) {
1413 TsMuxProgram *program = (TsMuxProgram *) cur->data;
1416 if (program->next_pmt_pcr == -1 || program->pmt_changed)
1418 else if (next_pcr > program->next_pmt_pcr)
1424 if (program->next_pmt_pcr == -1)
1425 program->next_pmt_pcr = next_pcr + program->pmt_interval * 300;
1427 program->next_pmt_pcr += program->pmt_interval * 300;
1429 if (!tsmux_write_pmt (mux, program))
1432 next_pcr = get_current_pcr (mux, cur_ts);
1435 if (program->scte35_pid != 0) {
1436 gboolean write_scte_null = FALSE;
1437 if (program->next_scte35_pcr == -1)
1438 write_scte_null = TRUE;
1439 else if (next_pcr > program->next_scte35_pcr)
1440 write_scte_null = TRUE;
1442 if (write_scte_null) {
1443 GST_DEBUG ("next scte35 pcr %" G_GINT64_FORMAT,
1444 program->next_scte35_pcr);
1445 if (program->next_scte35_pcr == -1)
1446 program->next_scte35_pcr =
1447 next_pcr + program->scte35_null_interval * 300;
1449 program->next_scte35_pcr += program->scte35_null_interval * 300;
1450 GST_DEBUG ("next scte35 NOW pcr %" G_GINT64_FORMAT,
1451 program->next_scte35_pcr);
1453 if (!tsmux_write_scte_null (mux, program))
1456 next_pcr = get_current_pcr (mux, cur_ts);
1460 program->wrote_si = TRUE;
1467 pad_stream (TsMux * mux, TsMuxStream * stream, gint64 cur_ts)
1470 GstBuffer *buf = NULL;
1472 gboolean ret = TRUE;
1473 GstClockTimeDiff diff;
1474 guint64 start_n_bytes;
1479 if (!GST_CLOCK_STIME_IS_VALID (cur_ts))
1482 if (!GST_CLOCK_STIME_IS_VALID (stream->first_ts))
1483 stream->first_ts = cur_ts;
1485 diff = GST_CLOCK_DIFF (stream->first_ts, cur_ts);
1490 start_n_bytes = mux->n_bytes;
1492 GST_LOG ("Transport stream bitrate: %" G_GUINT64_FORMAT " over %"
1493 G_GUINT64_FORMAT " bytes, duration %" GST_TIME_FORMAT,
1494 gst_util_uint64_scale (mux->n_bytes * 8, TSMUX_CLOCK_FREQ, diff),
1495 mux->n_bytes, GST_TIME_ARGS (diff * GST_SECOND / TSMUX_CLOCK_FREQ));
1497 /* calculate what the overall bitrate will be if we add 1 more packet */
1499 gst_util_uint64_scale ((mux->n_bytes + TSMUX_PACKET_LENGTH) * 8,
1500 TSMUX_CLOCK_FREQ, diff);
1502 if (bitrate <= mux->bitrate) {
1505 if (!tsmux_get_buffer (mux, &buf))
1508 if (!gst_buffer_map (buf, &map, GST_MAP_WRITE)) {
1509 gst_buffer_unref (buf);
1513 new_pcr = write_new_pcr (mux, stream, get_current_pcr (mux, cur_ts),
1514 get_next_pcr (mux, cur_ts));
1515 if (new_pcr != -1) {
1516 GST_LOG ("Writing PCR-only packet on PID 0x%04x", stream->pi.pid);
1517 tsmux_write_ts_header (mux, map.data, &stream->pi, 0, NULL, NULL);
1519 GST_LOG ("Writing null stuffing packet");
1520 if (!rewrite_si (mux, cur_ts)) {
1521 gst_buffer_unmap (buf, &map);
1522 gst_buffer_unref (buf);
1525 tsmux_write_null_ts_header (map.data);
1526 memset (map.data + TSMUX_HEADER_LENGTH, 0xFF, TSMUX_PAYLOAD_LENGTH);
1529 gst_buffer_unmap (buf, &map);
1531 stream->pi.flags &= TSMUX_PACKET_FLAG_PES_FULL_HEADER;
1532 if (!tsmux_packet_out (mux, buf, new_pcr))
1535 } while (bitrate < mux->bitrate);
1537 if (mux->n_bytes != start_n_bytes) {
1538 GST_LOG ("Finished padding the mux");
1548 * tsmux_write_stream_packet:
1550 * @stream: a #TsMuxStream
1552 * Write a packet of @stream.
1554 * Returns: TRUE if the packet could be written.
1557 tsmux_write_stream_packet (TsMux * mux, TsMuxStream * stream)
1559 guint payload_len, payload_offs;
1560 TsMuxPacketInfo *pi = &stream->pi;
1562 gint64 new_pcr = -1;
1563 GstBuffer *buf = NULL;
1566 g_return_val_if_fail (mux != NULL, FALSE);
1567 g_return_val_if_fail (stream != NULL, FALSE);
1569 if (tsmux_stream_is_pcr (stream)) {
1570 gint64 cur_ts = CLOCK_BASE;
1571 if (tsmux_stream_get_dts (stream) != G_MININT64)
1572 cur_ts += tsmux_stream_get_dts (stream);
1574 cur_ts += tsmux_stream_get_pts (stream);
1576 if (!rewrite_si (mux, cur_ts))
1579 if (!pad_stream (mux, stream, cur_ts))
1583 write_new_pcr (mux, stream, get_current_pcr (mux, cur_ts),
1584 get_next_pcr (mux, cur_ts));
1587 pi->packet_start_unit_indicator = tsmux_stream_at_pes_start (stream);
1588 if (pi->packet_start_unit_indicator) {
1589 tsmux_stream_initialize_pes_packet (stream);
1590 if (stream->dts != G_MININT64)
1591 stream->dts += CLOCK_BASE;
1592 if (stream->pts != G_MININT64)
1593 stream->pts += CLOCK_BASE;
1595 pi->stream_avail = tsmux_stream_bytes_avail (stream);
1598 if (!tsmux_get_buffer (mux, &buf))
1601 gst_buffer_map (buf, &map, GST_MAP_WRITE);
1603 if (!tsmux_write_ts_header (mux, map.data, pi, pi->stream_avail, &payload_len,
1608 if (!tsmux_stream_get_data (stream, map.data + payload_offs, payload_len))
1611 gst_buffer_unmap (buf, &map);
1613 GST_DEBUG ("Writing PES of size %d", (int) gst_buffer_get_size (buf));
1614 res = tsmux_packet_out (mux, buf, new_pcr);
1616 /* Reset all dynamic flags */
1617 stream->pi.flags &= TSMUX_PACKET_FLAG_PES_FULL_HEADER;
1625 gst_buffer_unmap (buf, &map);
1626 gst_buffer_unref (buf);
1633 * tsmux_program_free:
1634 * @program: a #TsMuxProgram
1636 * Free the resources of @program. After this call @program can not be used
1640 tsmux_program_free (TsMuxProgram * program)
1642 g_return_if_fail (program != NULL);
1644 /* Free PMT section */
1645 if (program->pmt.section)
1646 gst_mpegts_section_unref (program->pmt.section);
1647 if (program->scte35_null_section)
1648 tsmux_section_free (program->scte35_null_section);
1650 g_ptr_array_free (program->streams, TRUE);
1651 g_slice_free (TsMuxProgram, program);
1655 * tsmux_program_set_pmt_pid:
1656 * @program: A #TsmuxProgram
1657 * @pmt_pid: PID to write PMT for this program
1660 tsmux_program_set_pmt_pid (TsMuxProgram * program, guint16 pmt_pid)
1662 program->pmt_pid = pmt_pid;
1666 compare_program_number (gconstpointer a, gconstpointer b)
1668 const GstMpegtsPatProgram *pgm1 = *(const GstMpegtsPatProgram * const *) a;
1669 const GstMpegtsPatProgram *pgm2 = *(const GstMpegtsPatProgram * const *) b;
1670 gint num1 = pgm1->program_number, num2 = pgm2->program_number;
1676 tsmux_write_pat (TsMux * mux)
1679 if (mux->pat_changed) {
1680 /* program_association_section ()
1681 * for (i = 0; i < N; i++) {
1682 * program_number 16 uimsbf
1684 * network_PID_or_program_map_PID 13 uimbsf
1691 pat = gst_mpegts_pat_new ();
1693 for (cur = mux->programs; cur; cur = cur->next) {
1694 GstMpegtsPatProgram *pat_pgm;
1695 TsMuxProgram *program = (TsMuxProgram *) cur->data;
1697 pat_pgm = gst_mpegts_pat_program_new ();
1698 pat_pgm->program_number = program->pgm_number;
1699 pat_pgm->network_or_program_map_PID = program->pmt_pid;
1701 g_ptr_array_add (pat, pat_pgm);
1704 g_ptr_array_sort (pat, compare_program_number);
1706 if (mux->pat.section)
1707 gst_mpegts_section_unref (mux->pat.section);
1709 mux->pat.section = gst_mpegts_section_from_pat (pat, mux->transport_id);
1711 mux->pat.section->version_number = mux->pat_version++;
1713 TS_DEBUG ("PAT has %d programs", mux->nb_programs);
1714 mux->pat_changed = FALSE;
1717 return tsmux_section_write_packet (mux, &mux->pat);
1721 tsmux_write_pmt (TsMux * mux, TsMuxProgram * program)
1724 if (program->pmt_changed) {
1725 /* program_association_section ()
1729 * program_info_length 12 uimsbf
1730 * for (i = 0; i < N; i++)
1733 * for (i = 0; i < N1; i++) {
1734 * stream_type 8 uimsbf
1736 * elementary_PID 13 uimbsf
1738 * ES_info_length 12 uimbsf
1739 * for (i = 0; i < N1; i++) {
1744 GstMpegtsDescriptor *descriptor;
1747 /* See note about bluray descriptors below */
1748 guint8 desc[] = { 0x0F, 0xFF, 0xFC, 0xFC };
1752 pmt = gst_mpegts_pmt_new ();
1754 if (program->pcr_stream == NULL)
1755 pmt->pcr_pid = 0x1FFF;
1757 pmt->pcr_pid = tsmux_stream_get_pid (program->pcr_stream);
1760 /* FIXME : These two descriptors should not be added in all PMT
1761 * but only in "bluray-compatible" mpeg-ts output. I even have my
1762 * doubt whether the DTCP descriptor is even needed */
1763 descriptor = gst_mpegts_descriptor_from_registration ("HDMV", NULL, 0);
1764 g_ptr_array_add (pmt->descriptors, descriptor);
1766 /* DTCP descriptor, see
1767 * http://www.dtcp.com/documents/dtcp/info-20150204-dtcp-v1-rev%201-71.pdf */
1768 descriptor = gst_mpegts_descriptor_from_custom (0x88, desc, 4);
1769 g_ptr_array_add (pmt->descriptors, descriptor);
1772 /* Will SCTE-35 be potentially used ? */
1773 if (program->scte35_pid != 0) {
1774 descriptor = gst_mpegts_descriptor_from_registration ("CUEI", NULL, 0);
1775 g_ptr_array_add (pmt->descriptors, descriptor);
1778 /* Write out the entries */
1779 for (i = 0; i < program->streams->len; i++) {
1780 GstMpegtsPMTStream *pmt_stream;
1781 TsMuxStream *stream = g_ptr_array_index (program->streams, i);
1783 pmt_stream = gst_mpegts_pmt_stream_new ();
1785 /* FIXME: Use API to retrieve this from the stream */
1786 pmt_stream->stream_type = stream->stream_type;
1787 pmt_stream->pid = tsmux_stream_get_pid (stream);
1789 /* Write any ES descriptors needed */
1790 tsmux_stream_get_es_descrs (stream, pmt_stream);
1791 g_ptr_array_add (pmt->streams, pmt_stream);
1794 /* Will SCTE-35 be potentially used ? */
1795 if (program->scte35_pid != 0) {
1796 GstMpegtsPMTStream *pmt_stream = gst_mpegts_pmt_stream_new ();
1797 pmt_stream->stream_type = GST_MPEGTS_STREAM_TYPE_SCTE_SIT;
1798 pmt_stream->pid = program->scte35_pid;
1799 g_ptr_array_add (pmt->streams, pmt_stream);
1802 TS_DEBUG ("PMT for program %d has %d streams",
1803 program->pgm_number, program->streams->len);
1805 pmt->program_number = program->pgm_number;
1807 program->pmt.pi.pid = program->pmt_pid;
1808 program->pmt_changed = FALSE;
1810 if (program->pmt.section)
1811 gst_mpegts_section_unref (program->pmt.section);
1813 program->pmt.section = gst_mpegts_section_from_pmt (pmt, program->pmt_pid);
1814 program->pmt.section->version_number = program->pmt_version++;
1817 return tsmux_section_write_packet (mux, &program->pmt);
1821 tsmux_write_scte_null (TsMux * mux, TsMuxProgram * program)
1823 /* SCTE-35 NULL section is created when PID is set */
1824 GST_LOG ("Writing SCTE NULL packet");
1825 return tsmux_section_write_packet (mux, program->scte35_null_section);
1829 tsmux_set_bitrate (TsMux * mux, guint64 bitrate)
1831 mux->bitrate = bitrate;