2 * Copyright 2006, 2007, 2008, 2009, 2010 Fluendo S.A.
3 * Authors: Jan Schmidt <jan@fluendo.com>
4 * Kapil Agrawal <kapil@fluendo.com>
5 * Julien Moutte <julien@fluendo.com>
7 * Copyright (C) 2011 Jan Schmidt <thaytan@noraisin.net>
9 * This library is licensed under 3 different licenses and you
10 * can choose to use it under the terms of any one of them. The
11 * three licenses are the MPL 1.1, the LGPL and the MIT license.
15 * The contents of this file are subject to the Mozilla Public License
16 * Version 1.1 (the "License"); you may not use this file except in
17 * compliance with the License. You may obtain a copy of the License at
18 * http://www.mozilla.org/MPL/.
20 * Software distributed under the License is distributed on an "AS IS"
21 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
22 * License for the specific language governing rights and limitations
27 * This library is free software; you can redistribute it and/or
28 * modify it under the terms of the GNU Library General Public
29 * License as published by the Free Software Foundation; either
30 * version 2 of the License, or (at your option) any later version.
32 * This library is distributed in the hope that it will be useful,
33 * but WITHOUT ANY WARRANTY; without even the implied warranty of
34 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
35 * Library General Public License for more details.
37 * You should have received a copy of the GNU Library General Public
38 * License along with this library; if not, write to the
39 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
40 * Boston, MA 02110-1301, USA.
44 * Unless otherwise indicated, Source Code is licensed under MIT license.
45 * See further explanation attached in License Statement (distributed in the file
48 * Permission is hereby granted, free of charge, to any person obtaining a copy of
49 * this software and associated documentation files (the "Software"), to deal in
50 * the Software without restriction, including without limitation the rights to
51 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
52 * of the Software, and to permit persons to whom the Software is furnished to do
53 * so, subject to the following conditions:
55 * The above copyright notice and this permission notice shall be included in all
56 * copies or substantial portions of the Software.
58 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
59 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
60 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
61 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
62 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
63 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
66 * SPDX-License-Identifier: MPL-1.1 OR MIT OR LGPL-2.0-or-later
72 #include <gst/tag/tag.h>
73 #include <gst/video/video.h>
74 #include <gst/mpegts/mpegts.h>
75 #include <gst/pbutils/pbutils.h>
76 #include <gst/videoparsers/gstjpeg2000parse.h>
77 #include <gst/video/video-color.h>
79 #include "gstbasetsmux.h"
80 #include "gstbasetsmuxaac.h"
81 #include "gstbasetsmuxttxt.h"
82 #include "gstbasetsmuxopus.h"
83 #include "gstbasetsmuxjpeg2000.h"
85 GST_DEBUG_CATEGORY (gst_base_ts_mux_debug);
86 #define GST_CAT_DEFAULT gst_base_ts_mux_debug
90 G_DEFINE_TYPE (GstBaseTsMuxPad, gst_base_ts_mux_pad, GST_TYPE_AGGREGATOR_PAD);
95 gst_base_ts_mux_pad_reset (GstBaseTsMuxPad * pad)
97 pad->dts = GST_CLOCK_STIME_NONE;
101 pad->free_func (pad->prepare_data);
102 pad->prepare_data = NULL;
103 pad->prepare_func = NULL;
104 pad->free_func = NULL;
107 gst_buffer_replace (&pad->codec_data, NULL);
109 /* reference owned elsewhere */
114 g_free (pad->language);
115 pad->language = NULL;
119 /* GstAggregatorPad implementation */
122 gst_base_ts_mux_pad_flush (GstAggregatorPad * agg_pad, GstAggregator * agg)
125 GstBaseTsMux *mux = GST_BASE_TS_MUX (agg);
127 /* Send initial segments again after a flush-stop, and also resend the
131 /* output PAT, SI tables */
132 tsmux_resend_pat (mux->tsmux);
133 tsmux_resend_si (mux->tsmux);
135 /* output PMT for each program */
136 for (cur = mux->tsmux->programs; cur; cur = cur->next) {
137 TsMuxProgram *program = (TsMuxProgram *) cur->data;
139 tsmux_resend_pmt (program);
145 /* GObject implementation */
148 gst_base_ts_mux_pad_dispose (GObject * obj)
150 GstBaseTsMuxPad *ts_pad = GST_BASE_TS_MUX_PAD (obj);
152 gst_base_ts_mux_pad_reset (ts_pad);
154 G_OBJECT_CLASS (gst_base_ts_mux_pad_parent_class)->dispose (obj);
158 gst_base_ts_mux_pad_class_init (GstBaseTsMuxPadClass * klass)
160 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
161 GstAggregatorPadClass *gstaggpad_class = GST_AGGREGATOR_PAD_CLASS (klass);
163 gobject_class->dispose = gst_base_ts_mux_pad_dispose;
164 gstaggpad_class->flush = gst_base_ts_mux_pad_flush;
166 gst_type_mark_as_plugin_api (GST_TYPE_BASE_TS_MUX, 0);
170 gst_base_ts_mux_pad_init (GstBaseTsMuxPad * vaggpad)
187 PROP_SCTE_35_NULL_INTERVAL
190 #define DEFAULT_SCTE_35_PID 0
192 #define BASETSMUX_DEFAULT_ALIGNMENT -1
194 #define CLOCK_BASE 9LL
195 #define CLOCK_FREQ (CLOCK_BASE * 10000) /* 90 kHz PTS clock */
196 #define CLOCK_FREQ_SCR (CLOCK_FREQ * 300) /* 27 MHz SCR clock */
197 #define TS_MUX_CLOCK_BASE (TSMUX_CLOCK_FREQ * 10 * 360)
199 #define GSTTIME_TO_MPEGTIME(time) \
200 (((time) > 0 ? (gint64) 1 : (gint64) -1) * \
201 (gint64) gst_util_uint64_scale (ABS(time), CLOCK_BASE, GST_MSECOND/10))
202 /* 27 MHz SCR conversions: */
203 #define MPEG_SYS_TIME_TO_GSTTIME(time) (gst_util_uint64_scale ((time), \
204 GST_USECOND, CLOCK_FREQ_SCR / 1000000))
205 #define GSTTIME_TO_MPEG_SYS_TIME(time) (gst_util_uint64_scale ((time), \
206 CLOCK_FREQ_SCR / 1000000, GST_USECOND))
208 #define DEFAULT_PROG_ID 0
210 static GstStaticPadTemplate gst_base_ts_mux_src_factory =
211 GST_STATIC_PAD_TEMPLATE ("src",
214 GST_STATIC_CAPS ("video/mpegts, "
215 "systemstream = (boolean) true, " "packetsize = (int) { 188, 192} ")
224 G_DEFINE_TYPE_WITH_CODE (GstBaseTsMux, gst_base_ts_mux, GST_TYPE_AGGREGATOR,
225 gst_mpegts_initialize ());
229 /* Takes over the ref on the buffer */
231 stream_data_new (GstBuffer * buffer)
233 StreamData *res = g_new (StreamData, 1);
234 res->buffer = buffer;
235 gst_buffer_map (buffer, &(res->map_info), GST_MAP_READ);
241 stream_data_free (StreamData * data)
244 gst_buffer_unmap (data->buffer, &data->map_info);
245 gst_buffer_unref (data->buffer);
250 #define parent_class gst_base_ts_mux_parent_class
253 gst_base_ts_mux_set_header_on_caps (GstBaseTsMux * mux)
256 GstStructure *structure;
257 GValue array = { 0 };
258 GValue value = { 0 };
261 caps = gst_pad_get_current_caps (GST_AGGREGATOR_SRC_PAD (mux));
263 /* If we have no caps, we are possibly shutting down */
267 caps = gst_caps_make_writable (caps);
268 structure = gst_caps_get_structure (caps, 0);
270 g_value_init (&array, GST_TYPE_ARRAY);
272 GST_LOG_OBJECT (mux, "setting %u packets into streamheader",
273 g_queue_get_length (&mux->streamheader));
275 while ((buf = GST_BUFFER (g_queue_pop_head (&mux->streamheader)))) {
276 g_value_init (&value, GST_TYPE_BUFFER);
277 gst_value_take_buffer (&value, buf);
278 gst_value_array_append_value (&array, &value);
279 g_value_unset (&value);
282 gst_structure_set_value (structure, "streamheader", &array);
283 gst_aggregator_set_src_caps (GST_AGGREGATOR (mux), caps);
284 g_value_unset (&array);
285 gst_caps_unref (caps);
289 steal_si_section (GstMpegtsSectionType * type, TsMuxSection * section,
292 g_hash_table_insert (mux->si_sections, type, section);
298 gst_base_ts_mux_reset (GstBaseTsMux * mux, gboolean alloc)
301 GstBaseTsMuxClass *klass = GST_BASE_TS_MUX_GET_CLASS (mux);
302 GHashTable *si_sections = NULL;
306 mux->last_flow_ret = GST_FLOW_OK;
308 mux->is_delta = TRUE;
309 mux->is_header = FALSE;
311 mux->streamheader_sent = FALSE;
312 mux->pending_key_unit_ts = GST_CLOCK_TIME_NONE;
313 gst_event_replace (&mux->force_key_unit_event, NULL);
315 if (mux->out_adapter)
316 gst_adapter_clear (mux->out_adapter);
317 mux->output_ts_offset = GST_CLOCK_TIME_NONE;
320 if (mux->tsmux->si_sections)
321 si_sections = g_hash_table_ref (mux->tsmux->si_sections);
323 tsmux_free (mux->tsmux);
328 g_hash_table_destroy (mux->programs);
330 mux->programs = g_hash_table_new (g_direct_hash, g_direct_equal);
332 while ((buf = GST_BUFFER (g_queue_pop_head (&mux->streamheader))))
333 gst_buffer_unref (buf);
335 gst_event_replace (&mux->force_key_unit_event, NULL);
336 gst_buffer_replace (&mux->out_buffer, NULL);
338 GST_OBJECT_LOCK (mux);
340 for (l = GST_ELEMENT (mux)->sinkpads; l; l = l->next) {
341 gst_base_ts_mux_pad_reset (GST_BASE_TS_MUX_PAD (l->data));
344 GST_OBJECT_UNLOCK (mux);
347 g_assert (klass->create_ts_mux);
349 mux->tsmux = klass->create_ts_mux (mux);
351 /* Preserve user-specified sections across resets */
353 g_hash_table_foreach_steal (si_sections, (GHRFunc) steal_si_section,
358 g_hash_table_unref (si_sections);
360 mux->last_scte35_event_seqnum = GST_SEQNUM_INVALID;
367 release_buffer_cb (guint8 * data, void *user_data)
369 stream_data_free ((StreamData *) user_data);
373 gst_base_ts_mux_create_or_update_stream (GstBaseTsMux * mux,
374 GstBaseTsMuxPad * ts_pad, GstCaps * caps)
377 guint st = TSMUX_ST_RESERVED;
379 const GValue *value = NULL;
380 GstBuffer *codec_data = NULL;
381 guint8 opus_channel_config_code = 0;
382 guint16 profile = GST_JPEG2000_PARSE_PROFILE_NONE;
383 guint8 main_level = 0;
384 guint32 max_rate = 0;
385 guint8 color_spec = 0;
386 const gchar *stream_format = NULL;
387 const char *interlace_mode = NULL;
389 GST_DEBUG_OBJECT (ts_pad,
390 "%s stream with PID 0x%04x for caps %" GST_PTR_FORMAT,
391 ts_pad->stream ? "Recreating" : "Creating", ts_pad->pid, caps);
393 s = gst_caps_get_structure (caps, 0);
395 mt = gst_structure_get_name (s);
396 value = gst_structure_get_value (s, "codec_data");
398 codec_data = gst_value_get_buffer (value);
400 g_clear_pointer (&ts_pad->codec_data, gst_buffer_unref);
401 ts_pad->prepare_func = NULL;
403 stream_format = gst_structure_get_string (s, "stream-format");
405 if (strcmp (mt, "video/x-dirac") == 0) {
406 st = TSMUX_ST_VIDEO_DIRAC;
407 } else if (strcmp (mt, "audio/x-ac3") == 0) {
408 st = TSMUX_ST_PS_AUDIO_AC3;
409 } else if (strcmp (mt, "audio/x-dts") == 0) {
410 st = TSMUX_ST_PS_AUDIO_DTS;
411 } else if (strcmp (mt, "audio/x-lpcm") == 0) {
412 st = TSMUX_ST_PS_AUDIO_LPCM;
413 } else if (strcmp (mt, "video/x-h264") == 0) {
414 st = TSMUX_ST_VIDEO_H264;
415 } else if (strcmp (mt, "video/x-h265") == 0) {
416 st = TSMUX_ST_VIDEO_HEVC;
417 } else if (strcmp (mt, "audio/mpeg") == 0) {
420 if (!gst_structure_get_int (s, "mpegversion", &mpegversion)) {
421 GST_ERROR_OBJECT (ts_pad, "caps missing mpegversion");
425 switch (mpegversion) {
427 int mpegaudioversion = 1; /* Assume mpegaudioversion=1 for backwards compatibility */
428 (void) gst_structure_get_int (s, "mpegaudioversion", &mpegaudioversion);
430 if (mpegaudioversion == 1)
431 st = TSMUX_ST_AUDIO_MPEG1;
433 st = TSMUX_ST_AUDIO_MPEG2;
437 /* mpegversion=2 in GStreamer refers to MPEG-2 Part 7 audio, */
439 st = TSMUX_ST_AUDIO_AAC;
441 /* Check the stream format. If raw, make dummy internal codec data from the caps */
442 if (g_strcmp0 (stream_format, "raw") == 0) {
444 gst_base_ts_mux_aac_mpeg2_make_codec_data (mux, caps);
445 ts_pad->prepare_func = gst_base_ts_mux_prepare_aac_mpeg2;
446 if (ts_pad->codec_data == NULL) {
447 GST_ERROR_OBJECT (mux, "Invalid or incomplete caps for MPEG-2 AAC");
455 st = TSMUX_ST_AUDIO_AAC;
457 /* Check the stream format. We need codec_data with RAW streams and mpegversion=4 */
458 if (g_strcmp0 (stream_format, "raw") == 0) {
460 GST_DEBUG_OBJECT (ts_pad,
461 "we have additional codec data (%" G_GSIZE_FORMAT " bytes)",
462 gst_buffer_get_size (codec_data));
463 ts_pad->codec_data = gst_buffer_ref (codec_data);
464 ts_pad->prepare_func = gst_base_ts_mux_prepare_aac_mpeg4;
466 ts_pad->codec_data = NULL;
467 GST_ERROR_OBJECT (mux, "Need codec_data for raw MPEG-4 AAC");
470 } else if (codec_data) {
471 ts_pad->codec_data = gst_buffer_ref (codec_data);
473 ts_pad->codec_data = NULL;
478 GST_WARNING_OBJECT (ts_pad, "unsupported mpegversion %d", mpegversion);
481 } else if (strcmp (mt, "video/mpeg") == 0) {
484 if (!gst_structure_get_int (s, "mpegversion", &mpegversion)) {
485 GST_ERROR_OBJECT (ts_pad, "caps missing mpegversion");
489 switch (mpegversion) {
491 st = TSMUX_ST_VIDEO_MPEG1;
494 st = TSMUX_ST_VIDEO_MPEG2;
497 st = TSMUX_ST_VIDEO_MPEG4;
500 GST_WARNING_OBJECT (ts_pad, "unsupported mpegversion %d", mpegversion);
503 } else if (strcmp (mt, "subpicture/x-dvb") == 0) {
504 st = TSMUX_ST_PS_DVB_SUBPICTURE;
505 } else if (strcmp (mt, "application/x-teletext") == 0) {
506 st = TSMUX_ST_PS_TELETEXT;
507 /* needs a particularly sized layout */
508 ts_pad->prepare_func = gst_base_ts_mux_prepare_teletext;
509 } else if (strcmp (mt, "audio/x-opus") == 0) {
510 guint8 channels, mapping_family, stream_count, coupled_count;
511 guint8 channel_mapping[256];
513 if (!gst_codec_utils_opus_parse_caps (caps, NULL, &channels,
514 &mapping_family, &stream_count, &coupled_count, channel_mapping)) {
515 GST_ERROR_OBJECT (ts_pad, "Incomplete Opus caps");
519 if (channels <= 2 && mapping_family == 0) {
520 opus_channel_config_code = channels;
521 } else if (channels == 2 && mapping_family == 255 && stream_count == 1
522 && coupled_count == 1) {
524 opus_channel_config_code = 0;
525 } else if (channels >= 2 && channels <= 8 && mapping_family == 1) {
526 static const guint8 coupled_stream_counts[9] = {
527 1, 0, 1, 1, 2, 2, 2, 3, 3
529 static const guint8 channel_map_a[8][8] = {
536 {0, 4, 1, 2, 3, 5, 6},
537 {0, 6, 1, 2, 3, 4, 5, 7},
539 static const guint8 channel_map_b[8][8] = {
546 {0, 1, 2, 3, 4, 5, 6},
547 {0, 1, 2, 3, 4, 5, 6, 7},
551 if (stream_count == channels - coupled_stream_counts[channels] &&
552 coupled_count == coupled_stream_counts[channels] &&
553 memcmp (channel_mapping, channel_map_a[channels - 1],
555 opus_channel_config_code = channels;
556 } else if (stream_count == channels - coupled_stream_counts[channels] &&
557 coupled_count == coupled_stream_counts[channels] &&
558 memcmp (channel_mapping, channel_map_b[channels - 1],
560 opus_channel_config_code = channels | 0x80;
562 GST_FIXME_OBJECT (ts_pad, "Opus channel mapping not handled");
567 st = TSMUX_ST_PS_OPUS;
568 ts_pad->prepare_func = gst_base_ts_mux_prepare_opus;
569 } else if (strcmp (mt, "meta/x-klv") == 0) {
570 st = TSMUX_ST_PS_KLV;
571 } else if (strcmp (mt, "image/x-jpc") == 0) {
573 * See this document for more details on standard:
575 * https://www.itu.int/rec/T-REC-H.222.0-201206-S/en
576 * Annex S describes J2K details
577 * Page 104 of this document describes J2k video descriptor
580 const GValue *vProfile = gst_structure_get_value (s, "profile");
581 const GValue *vMainlevel = gst_structure_get_value (s, "main-level");
582 const GValue *vFramerate = gst_structure_get_value (s, "framerate");
583 const GValue *vColorimetry = gst_structure_get_value (s, "colorimetry");
584 j2k_private_data *private_data;
586 /* for now, we relax the condition that profile must exist and equal
587 * GST_JPEG2000_PARSE_PROFILE_BC_SINGLE */
589 profile = g_value_get_int (vProfile);
590 if (profile != GST_JPEG2000_PARSE_PROFILE_BC_SINGLE) {
591 GST_LOG_OBJECT (ts_pad, "Invalid JPEG 2000 profile %d", profile);
592 /* goto not_negotiated; */
595 /* for now, we will relax the condition that the main level must be present */
597 main_level = g_value_get_uint (vMainlevel);
598 if (main_level > 11) {
599 GST_ERROR_OBJECT (ts_pad, "Invalid main level %d", main_level);
602 if (main_level >= 6) {
603 max_rate = 2 ^ (main_level - 6) * 1600 * 1000000;
605 switch (main_level) {
610 max_rate = 200 * 1000000;
613 max_rate = 400 * 1000000;
616 max_rate = 800 * 1000000;
623 /* GST_ERROR_OBJECT (ts_pad, "Missing main level");
624 * goto not_negotiated; */
627 /* We always mux video in J2K-over-MPEG-TS non-interlaced mode */
628 private_data = g_new0 (j2k_private_data, 1);
629 private_data->interlace = FALSE;
630 private_data->den = 0;
631 private_data->num = 0;
632 private_data->max_bitrate = max_rate;
633 private_data->color_spec = 1;
634 /* these two fields are not used, since we always mux as non-interlaced */
635 private_data->Fic = 1;
636 private_data->Fio = 0;
639 if (vFramerate != NULL) {
640 /* Data for ELSM header */
641 private_data->num = gst_value_get_fraction_numerator (vFramerate);
642 private_data->den = gst_value_get_fraction_denominator (vFramerate);
644 /* Get Colorimetry */
646 const char *colorimetry = g_value_get_string (vColorimetry);
647 color_spec = GST_MPEGTS_JPEG2000_COLORSPEC_SRGB; /* RGB as default */
648 if (g_str_equal (colorimetry, GST_VIDEO_COLORIMETRY_BT601)) {
649 color_spec = GST_MPEGTS_JPEG2000_COLORSPEC_REC601;
651 if (g_str_equal (colorimetry, GST_VIDEO_COLORIMETRY_BT709)
652 || g_str_equal (colorimetry, GST_VIDEO_COLORIMETRY_SMPTE240M)) {
653 color_spec = GST_MPEGTS_JPEG2000_COLORSPEC_REC709;
656 private_data->color_spec = color_spec;
658 GST_ERROR_OBJECT (ts_pad, "Colorimetry not present in caps");
659 g_free (private_data);
662 st = TSMUX_ST_VIDEO_JP2K;
663 ts_pad->prepare_func = gst_base_ts_mux_prepare_jpeg2000;
664 ts_pad->prepare_data = private_data;
665 ts_pad->free_func = gst_base_ts_mux_free_jpeg2000;
667 GstBaseTsMuxClass *klass = GST_BASE_TS_MUX_GET_CLASS (mux);
669 if (klass->handle_media_type) {
670 st = klass->handle_media_type (mux, mt, ts_pad);
674 if (st == TSMUX_ST_RESERVED) {
675 GST_ERROR_OBJECT (ts_pad, "Failed to determine stream type");
679 if (ts_pad->stream && st != ts_pad->stream->stream_type) {
680 GST_ELEMENT_ERROR (mux, STREAM, MUX,
681 ("Stream type change from %02x to %02x not supported",
682 ts_pad->stream->stream_type, st), NULL);
686 if (ts_pad->stream == NULL) {
688 tsmux_create_stream (mux->tsmux, st, ts_pad->pid, ts_pad->language);
689 if (ts_pad->stream == NULL)
693 interlace_mode = gst_structure_get_string (s, "interlace-mode");
694 gst_structure_get_int (s, "rate", &ts_pad->stream->audio_sampling);
695 gst_structure_get_int (s, "channels", &ts_pad->stream->audio_channels);
696 gst_structure_get_int (s, "bitrate", &ts_pad->stream->audio_bitrate);
699 gst_structure_get_fraction (s, "framerate", &ts_pad->stream->num,
700 &ts_pad->stream->den);
703 ts_pad->stream->interlace_mode = FALSE;
704 if (interlace_mode) {
705 ts_pad->stream->interlace_mode =
706 g_str_equal (interlace_mode, "interleaved");
709 /* Width and Height */
710 gst_structure_get_int (s, "width", &ts_pad->stream->horizontal_size);
711 gst_structure_get_int (s, "height", &ts_pad->stream->vertical_size);
713 ts_pad->stream->color_spec = color_spec;
714 ts_pad->stream->max_bitrate = max_rate;
715 ts_pad->stream->profile_and_level = profile | main_level;
717 ts_pad->stream->opus_channel_config_code = opus_channel_config_code;
719 tsmux_stream_set_buffer_release_func (ts_pad->stream, release_buffer_cb);
725 return GST_FLOW_NOT_NEGOTIATED;
728 return GST_FLOW_ERROR;
732 is_valid_pmt_pid (guint16 pmt_pid)
734 if (pmt_pid < 0x0010 || pmt_pid > 0x1ffe)
740 gst_base_ts_mux_create_stream (GstBaseTsMux * mux, GstBaseTsMuxPad * ts_pad)
742 GstCaps *caps = gst_pad_get_current_caps (GST_PAD (ts_pad));
746 GST_DEBUG_OBJECT (ts_pad, "Sink pad caps were not set before pushing");
747 return GST_FLOW_NOT_NEGOTIATED;
750 ret = gst_base_ts_mux_create_or_update_stream (mux, ts_pad, caps);
751 gst_caps_unref (caps);
753 if (ret == GST_FLOW_OK) {
754 tsmux_program_add_stream (ts_pad->prog, ts_pad->stream);
761 gst_base_ts_mux_create_pad_stream (GstBaseTsMux * mux, GstPad * pad)
763 GstBaseTsMuxPad *ts_pad = GST_BASE_TS_MUX_PAD (pad);
766 GstFlowReturn ret = GST_FLOW_OK;
768 if (ts_pad->prog_id == -1) {
769 name = GST_PAD_NAME (pad);
770 if (mux->prog_map != NULL && gst_structure_has_field (mux->prog_map, name)) {
772 gboolean ret = gst_structure_get_int (mux->prog_map, name, &idx);
774 GST_ELEMENT_ERROR (mux, STREAM, MUX,
775 ("Reading program map failed. Assuming default"), (NULL));
776 idx = DEFAULT_PROG_ID;
779 GST_DEBUG_OBJECT (mux, "Program number %d associate with pad %s less "
780 "than zero; DEFAULT_PROGRAM = %d is used instead",
781 idx, name, DEFAULT_PROG_ID);
782 idx = DEFAULT_PROG_ID;
784 ts_pad->prog_id = idx;
786 ts_pad->prog_id = DEFAULT_PROG_ID;
791 (TsMuxProgram *) g_hash_table_lookup (mux->programs,
792 GINT_TO_POINTER (ts_pad->prog_id));
793 if (ts_pad->prog == NULL) {
794 ts_pad->prog = tsmux_program_new (mux->tsmux, ts_pad->prog_id);
795 if (ts_pad->prog == NULL)
797 tsmux_set_pmt_interval (ts_pad->prog, mux->pmt_interval);
798 tsmux_program_set_scte35_pid (ts_pad->prog, mux->scte35_pid);
799 tsmux_program_set_scte35_interval (ts_pad->prog, mux->scte35_null_interval);
800 g_hash_table_insert (mux->programs, GINT_TO_POINTER (ts_pad->prog_id),
803 /* Check for user-specified PMT PID */
804 prop_name = g_strdup_printf ("PMT_%d", ts_pad->prog->pgm_number);
805 if (mux->prog_map && gst_structure_has_field (mux->prog_map, prop_name)) {
808 if (gst_structure_get_uint (mux->prog_map, prop_name, &pmt_pid)) {
809 if (is_valid_pmt_pid (pmt_pid)) {
810 GST_DEBUG_OBJECT (mux, "User specified pid=%u as PMT for "
811 "program (prog_id = %d)", pmt_pid, ts_pad->prog->pgm_number);
812 tsmux_program_set_pmt_pid (ts_pad->prog, pmt_pid);
814 GST_ELEMENT_WARNING (mux, LIBRARY, SETTINGS,
815 ("User specified PMT pid %u for program %d is not valid.",
816 pmt_pid, ts_pad->prog->pgm_number), (NULL));
823 if (ts_pad->stream == NULL) {
824 ret = gst_base_ts_mux_create_stream (mux, ts_pad);
825 if (ret != GST_FLOW_OK)
829 if (ts_pad->prog->pcr_stream == NULL) {
830 /* Take the first stream of the program for the PCR */
831 GST_DEBUG_OBJECT (ts_pad,
832 "Use stream (pid=%d) from pad as PCR for program (prog_id = %d)",
833 ts_pad->pid, ts_pad->prog_id);
835 tsmux_program_set_pcr_stream (ts_pad->prog, ts_pad->stream);
838 /* Check for user-specified PCR PID */
839 prop_name = g_strdup_printf ("PCR_%d", ts_pad->prog->pgm_number);
840 if (mux->prog_map && gst_structure_has_field (mux->prog_map, prop_name)) {
841 const gchar *sink_name =
842 gst_structure_get_string (mux->prog_map, prop_name);
844 if (!g_strcmp0 (name, sink_name)) {
845 GST_DEBUG_OBJECT (mux, "User specified stream (pid=%d) as PCR for "
846 "program (prog_id = %d)", ts_pad->pid, ts_pad->prog->pgm_number);
847 tsmux_program_set_pcr_stream (ts_pad->prog, ts_pad->stream);
857 GST_ELEMENT_ERROR (mux, STREAM, MUX,
858 ("Could not create new program"), (NULL));
859 return GST_FLOW_ERROR;
863 GST_ELEMENT_ERROR (mux, STREAM, MUX,
864 ("Could not create handler for stream"), (NULL));
870 gst_base_ts_mux_create_pad_stream_func (GstElement * element, GstPad * pad,
873 GstFlowReturn *ret = user_data;
875 *ret = gst_base_ts_mux_create_pad_stream (GST_BASE_TS_MUX (element), pad);
877 return *ret == GST_FLOW_OK;
881 gst_base_ts_mux_create_streams (GstBaseTsMux * mux)
883 GstFlowReturn ret = GST_FLOW_OK;
885 gst_element_foreach_sink_pad (GST_ELEMENT_CAST (mux),
886 gst_base_ts_mux_create_pad_stream_func, &ret);
892 new_packet_common_init (GstBaseTsMux * mux, GstBuffer * buf, guint8 * data,
895 /* Packets should be at least 188 bytes, but check anyway */
896 g_assert (len >= 2 || !data);
898 if (!mux->streamheader_sent && data) {
899 guint pid = ((data[1] & 0x1f) << 8) | data[2];
900 /* if it's a PAT or a PMT */
901 if (pid == 0x00 || (pid >= TSMUX_START_PMT_PID && pid < TSMUX_START_ES_PID)) {
905 hbuf = gst_buffer_new_and_alloc (len);
906 gst_buffer_fill (hbuf, 0, data, len);
908 hbuf = gst_buffer_copy (buf);
911 "Collecting packet with pid 0x%04x into streamheaders", pid);
913 g_queue_push_tail (&mux->streamheader, hbuf);
914 } else if (!g_queue_is_empty (&mux->streamheader)) {
915 gst_base_ts_mux_set_header_on_caps (mux);
916 mux->streamheader_sent = TRUE;
921 if (mux->is_header) {
922 GST_LOG_OBJECT (mux, "marking as header buffer");
923 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_HEADER);
926 GST_LOG_OBJECT (mux, "marking as delta unit");
927 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
929 GST_DEBUG_OBJECT (mux, "marking as non-delta unit");
930 mux->is_delta = TRUE;
936 gst_base_ts_mux_push_packets (GstBaseTsMux * mux, gboolean force)
938 GstBufferList *buffer_list;
939 gint align = mux->alignment;
940 gint av, packet_size;
942 packet_size = mux->packet_size;
945 align = mux->automatic_alignment;
947 av = gst_adapter_available (mux->out_adapter);
948 GST_LOG_OBJECT (mux, "align %d, av %d", align, av);
953 /* no alignment, just push all available data */
955 buffer_list = gst_adapter_take_buffer_list (mux->out_adapter, av);
956 return gst_aggregator_finish_buffer_list (GST_AGGREGATOR (mux),
960 align *= packet_size;
962 if (!force && align > av)
965 buffer_list = gst_buffer_list_new_sized ((av / align) + 1);
967 GST_LOG_OBJECT (mux, "aligning to %d bytes", align);
968 while (align <= av) {
972 pts = gst_adapter_prev_pts (mux->out_adapter, NULL);
973 buf = gst_adapter_take_buffer (mux->out_adapter, align);
975 GST_BUFFER_PTS (buf) = pts;
977 gst_buffer_list_add (buffer_list, buf);
981 if (av > 0 && force) {
989 GST_LOG_OBJECT (mux, "handling %d leftover bytes", av);
991 pts = gst_adapter_prev_pts (mux->out_adapter, NULL);
992 buf = gst_buffer_new_and_alloc (align);
994 GST_BUFFER_PTS (buf) = pts;
996 gst_buffer_map (buf, &map, GST_MAP_READ);
999 gst_adapter_copy (mux->out_adapter, data, 0, av);
1000 gst_adapter_clear (mux->out_adapter);
1003 header = GST_READ_UINT32_BE (data - packet_size);
1005 dummy = (map.size - av) / packet_size;
1006 GST_LOG_OBJECT (mux, "adding %d null packets", dummy);
1008 for (; dummy > 0; dummy--) {
1011 if (packet_size > GST_BASE_TS_MUX_NORMAL_PACKET_LENGTH) {
1012 GST_WRITE_UINT32_BE (data, header);
1013 /* simply increase header a bit and never mind too much */
1019 GST_WRITE_UINT8 (data + offset, TSMUX_SYNC_BYTE);
1020 /* null packet PID */
1021 GST_WRITE_UINT16_BE (data + offset + 1, 0x1FFF);
1022 /* no adaptation field exists | continuity counter undefined */
1023 GST_WRITE_UINT8 (data + offset + 3, 0x10);
1025 memset (data + offset + 4, 0, GST_BASE_TS_MUX_NORMAL_PACKET_LENGTH - 4);
1026 data += packet_size;
1029 gst_buffer_unmap (buf, &map);
1030 gst_buffer_list_add (buffer_list, buf);
1033 return gst_aggregator_finish_buffer_list (GST_AGGREGATOR (mux), buffer_list);
1036 static GstFlowReturn
1037 gst_base_ts_mux_collect_packet (GstBaseTsMux * mux, GstBuffer * buf)
1039 GST_LOG_OBJECT (mux, "collecting packet size %" G_GSIZE_FORMAT,
1040 gst_buffer_get_size (buf));
1041 gst_adapter_push (mux->out_adapter, buf);
1047 check_pending_key_unit_event (GstEvent * pending_event, GstSegment * segment,
1048 GstClockTime timestamp, guint flags, GstClockTime pending_key_unit_ts)
1050 GstClockTime running_time, stream_time;
1051 gboolean all_headers;
1053 GstEvent *event = NULL;
1055 g_assert (segment != NULL);
1057 if (pending_event == NULL)
1060 if (GST_CLOCK_TIME_IS_VALID (pending_key_unit_ts) &&
1061 timestamp == GST_CLOCK_TIME_NONE)
1064 running_time = timestamp;
1066 GST_INFO ("now %" GST_TIME_FORMAT " wanted %" GST_TIME_FORMAT,
1067 GST_TIME_ARGS (running_time), GST_TIME_ARGS (pending_key_unit_ts));
1068 if (GST_CLOCK_TIME_IS_VALID (pending_key_unit_ts) &&
1069 running_time < pending_key_unit_ts)
1072 if (flags & GST_BUFFER_FLAG_DELTA_UNIT) {
1073 GST_INFO ("pending force key unit, waiting for keyframe");
1077 stream_time = gst_segment_to_stream_time (segment,
1078 GST_FORMAT_TIME, timestamp);
1080 if (GST_EVENT_TYPE (pending_event) == GST_EVENT_CUSTOM_DOWNSTREAM) {
1081 gst_video_event_parse_downstream_force_key_unit (pending_event,
1082 NULL, NULL, NULL, &all_headers, &count);
1084 gst_video_event_parse_upstream_force_key_unit (pending_event, NULL,
1085 &all_headers, &count);
1089 gst_video_event_new_downstream_force_key_unit (timestamp, stream_time,
1090 running_time, all_headers, count);
1091 gst_event_set_seqnum (event, gst_event_get_seqnum (pending_event));
1097 /* Called when the TsMux has prepared a packet for output. Return FALSE
1100 new_packet_cb (GstBuffer * buf, void *user_data, gint64 new_pcr)
1102 GstBaseTsMux *mux = (GstBaseTsMux *) user_data;
1103 GstAggregator *agg = GST_AGGREGATOR (mux);
1104 GstBaseTsMuxClass *klass = GST_BASE_TS_MUX_GET_CLASS (mux);
1106 GstSegment *agg_segment = &GST_AGGREGATOR_PAD (agg->srcpad)->segment;
1108 g_assert (klass->output_packet);
1110 gst_buffer_map (buf, &map, GST_MAP_READWRITE);
1112 if (!GST_CLOCK_TIME_IS_VALID (GST_BUFFER_PTS (buf))) {
1113 /* tsmux isn't generating timestamps. Use the input times */
1114 GST_BUFFER_PTS (buf) = mux->last_ts;
1117 if (GST_CLOCK_TIME_IS_VALID (GST_BUFFER_PTS (buf))) {
1118 if (!GST_CLOCK_TIME_IS_VALID (mux->output_ts_offset)) {
1119 GstClockTime output_start_time = agg_segment->position;
1120 if (agg_segment->position == -1
1121 || agg_segment->position < agg_segment->start) {
1122 output_start_time = agg_segment->start;
1125 mux->output_ts_offset =
1126 GST_CLOCK_DIFF (GST_BUFFER_PTS (buf), output_start_time);
1128 GST_DEBUG_OBJECT (mux, "New output ts offset %" GST_STIME_FORMAT,
1129 GST_STIME_ARGS (mux->output_ts_offset));
1132 if (GST_CLOCK_TIME_IS_VALID (mux->output_ts_offset)) {
1133 GST_BUFFER_PTS (buf) += mux->output_ts_offset;
1137 if (GST_CLOCK_TIME_IS_VALID (GST_BUFFER_PTS (buf))) {
1138 agg_segment->position = GST_BUFFER_PTS (buf);
1141 /* do common init (flags and streamheaders) */
1142 new_packet_common_init (mux, buf, map.data, map.size);
1144 gst_buffer_unmap (buf, &map);
1146 return klass->output_packet (mux, buf, new_pcr);
1149 /* called when TsMux needs new packet to write into */
1151 alloc_packet_cb (GstBuffer ** buf, void *user_data)
1153 GstBaseTsMux *mux = (GstBaseTsMux *) user_data;
1154 GstBaseTsMuxClass *klass = GST_BASE_TS_MUX_GET_CLASS (mux);
1156 g_assert (klass->allocate_packet);
1158 klass->allocate_packet (mux, buf);
1161 static GstFlowReturn
1162 gst_base_ts_mux_aggregate_buffer (GstBaseTsMux * mux,
1163 GstAggregatorPad * agg_pad, GstBuffer * buf)
1165 GstFlowReturn ret = GST_FLOW_OK;
1166 GstBaseTsMuxPad *best = GST_BASE_TS_MUX_PAD (agg_pad);
1168 gint64 pts = GST_CLOCK_STIME_NONE;
1169 gint64 dts = GST_CLOCK_STIME_NONE;
1170 gboolean delta = TRUE, header = FALSE;
1171 StreamData *stream_data;
1172 GstMpegtsSection *scte_section = NULL;
1174 GST_DEBUG_OBJECT (mux, "Pads collected");
1176 if (buf && gst_buffer_get_size (buf) == 0
1177 && GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_GAP)) {
1178 gst_buffer_unref (buf);
1182 if (G_UNLIKELY (mux->first)) {
1183 ret = gst_base_ts_mux_create_streams (mux);
1184 if (G_UNLIKELY (ret != GST_FLOW_OK)) {
1186 gst_buffer_unref (buf);
1197 gst_base_ts_mux_create_pad_stream (mux, GST_PAD (best));
1198 tsmux_resend_pat (mux->tsmux);
1199 tsmux_resend_si (mux->tsmux);
1201 g_assert_nonnull (prog);
1203 /* output PMT for each program */
1204 for (cur = mux->tsmux->programs; cur; cur = cur->next) {
1205 TsMuxProgram *program = (TsMuxProgram *) cur->data;
1207 tsmux_resend_pmt (program);
1211 g_assert (buf != NULL);
1213 if (best->prepare_func) {
1216 tmp = best->prepare_func (buf, best, mux);
1218 gst_buffer_unref (buf);
1222 if (mux->force_key_unit_event != NULL && best->stream->is_video_stream) {
1225 event = check_pending_key_unit_event (mux->force_key_unit_event,
1226 &agg_pad->segment, GST_BUFFER_PTS (buf),
1227 GST_BUFFER_FLAGS (buf), mux->pending_key_unit_ts);
1229 GstClockTime running_time;
1233 mux->pending_key_unit_ts = GST_CLOCK_TIME_NONE;
1234 gst_event_replace (&mux->force_key_unit_event, NULL);
1236 gst_video_event_parse_downstream_force_key_unit (event,
1237 NULL, NULL, &running_time, NULL, &count);
1239 GST_INFO_OBJECT (mux, "pushing downstream force-key-unit event %d "
1240 "%" GST_TIME_FORMAT " count %d", gst_event_get_seqnum (event),
1241 GST_TIME_ARGS (running_time), count);
1242 gst_pad_push_event (GST_AGGREGATOR_SRC_PAD (mux), event);
1244 /* output PAT, SI tables */
1245 tsmux_resend_pat (mux->tsmux);
1246 tsmux_resend_si (mux->tsmux);
1248 /* output PMT for each program */
1249 for (cur = mux->tsmux->programs; cur; cur = cur->next) {
1250 TsMuxProgram *program = (TsMuxProgram *) cur->data;
1252 tsmux_resend_pmt (program);
1257 if (G_UNLIKELY (prog->pcr_stream == NULL)) {
1258 /* Take the first data stream for the PCR */
1259 GST_DEBUG_OBJECT (best,
1260 "Use stream (pid=%d) from pad as PCR for program (prog_id = %d)",
1261 best->pid, best->prog_id);
1263 /* Set the chosen PCR stream */
1264 tsmux_program_set_pcr_stream (prog, best->stream);
1267 GST_DEBUG_OBJECT (best, "Chose stream for output (PID: 0x%04x)", best->pid);
1269 GST_OBJECT_LOCK (mux);
1270 scte_section = mux->pending_scte35_section;
1271 mux->pending_scte35_section = NULL;
1272 GST_OBJECT_UNLOCK (mux);
1273 if (G_UNLIKELY (scte_section)) {
1274 GST_DEBUG_OBJECT (mux, "Sending pending SCTE section");
1275 if (!tsmux_send_section (mux->tsmux, scte_section))
1276 GST_ERROR_OBJECT (mux, "Error sending SCTE section !");
1279 if (GST_CLOCK_TIME_IS_VALID (GST_BUFFER_PTS (buf))) {
1280 pts = GSTTIME_TO_MPEGTIME (GST_BUFFER_PTS (buf));
1281 GST_DEBUG_OBJECT (mux, "Buffer has PTS %" GST_TIME_FORMAT " pts %"
1282 G_GINT64_FORMAT "%s", GST_TIME_ARGS (GST_BUFFER_PTS (buf)), pts,
1283 !GST_BUFFER_FLAG_IS_SET (buf,
1284 GST_BUFFER_FLAG_DELTA_UNIT) ? " (keyframe)" : "");
1287 if (GST_CLOCK_STIME_IS_VALID (best->dts)) {
1288 dts = GSTTIME_TO_MPEGTIME (best->dts);
1289 GST_DEBUG_OBJECT (mux, "Buffer has DTS %" GST_STIME_FORMAT " dts %"
1290 G_GINT64_FORMAT, GST_STIME_ARGS (best->dts), dts);
1293 /* should not have a DTS without PTS */
1294 if (!GST_CLOCK_STIME_IS_VALID (pts) && GST_CLOCK_STIME_IS_VALID (dts)) {
1295 GST_DEBUG_OBJECT (mux, "using DTS for unknown PTS");
1299 if (best->stream->is_video_stream) {
1300 delta = GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
1301 header = GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_HEADER);
1304 if (best->stream->is_meta && gst_buffer_get_size (buf) > (G_MAXUINT16 - 3)) {
1305 GST_WARNING_OBJECT (mux, "KLV meta unit too big, splitting not supported");
1307 gst_buffer_unref (buf);
1311 GST_DEBUG_OBJECT (mux, "delta: %d", delta);
1313 stream_data = stream_data_new (buf);
1314 tsmux_stream_add_data (best->stream, stream_data->map_info.data,
1315 stream_data->map_info.size, stream_data, pts, dts, !delta);
1317 /* outgoing ts follows ts of PCR program stream */
1318 if (prog->pcr_stream == best->stream) {
1319 /* prefer DTS if present for PCR as it should be monotone */
1321 GST_CLOCK_TIME_IS_VALID (GST_BUFFER_DTS (buf)) ?
1322 GST_BUFFER_DTS (buf) : GST_BUFFER_PTS (buf);
1325 mux->is_delta = delta;
1326 mux->is_header = header;
1327 while (tsmux_stream_bytes_in_buffer (best->stream) > 0) {
1328 if (!tsmux_write_stream_packet (mux->tsmux, best->stream)) {
1329 /* Failed writing data for some reason. Set appropriate error */
1330 GST_DEBUG_OBJECT (mux, "Failed to write data packet");
1331 GST_ELEMENT_ERROR (mux, STREAM, MUX,
1332 ("Failed writing output data to stream %04x", best->stream->id),
1337 /* flush packet cache */
1338 return gst_base_ts_mux_push_packets (mux, FALSE);
1343 return mux->last_flow_ret;
1347 /* GstElement implementation */
1349 gst_base_ts_mux_has_pad_with_pid (GstBaseTsMux * mux, guint16 pid)
1352 gboolean res = FALSE;
1354 GST_OBJECT_LOCK (mux);
1356 for (l = GST_ELEMENT_CAST (mux)->sinkpads; l; l = l->next) {
1357 GstBaseTsMuxPad *tpad = GST_BASE_TS_MUX_PAD (l->data);
1359 if (tpad->pid == pid) {
1365 GST_OBJECT_UNLOCK (mux);
1370 gst_base_ts_mux_request_new_pad (GstElement * element, GstPadTemplate * templ,
1371 const gchar * name, const GstCaps * caps)
1373 GstBaseTsMux *mux = GST_BASE_TS_MUX (element);
1376 gchar *free_name = NULL;
1378 if (name != NULL && sscanf (name, "sink_%d", &pid) == 1) {
1379 if (tsmux_find_stream (mux->tsmux, pid))
1381 /* Make sure we don't use reserved PID.
1382 * FIXME : This should be extended to other variants (ex: ATSC) reserved PID */
1383 if (pid < TSMUX_START_ES_PID)
1384 goto invalid_stream_pid;
1387 pid = tsmux_get_new_pid (mux->tsmux);
1388 } while (gst_base_ts_mux_has_pad_with_pid (mux, pid));
1390 /* Name the pad correctly after the selected pid */
1391 name = free_name = g_strdup_printf ("sink_%d", pid);
1395 GST_ELEMENT_CLASS (parent_class)->request_new_pad (element,
1398 gst_base_ts_mux_pad_reset (GST_BASE_TS_MUX_PAD (pad));
1399 GST_BASE_TS_MUX_PAD (pad)->pid = pid;
1408 GST_ELEMENT_ERROR (element, STREAM, MUX, ("Duplicate PID requested"),
1415 GST_ELEMENT_ERROR (element, STREAM, MUX,
1416 ("Invalid Elementary stream PID (0x%02u < 0x40)", pid), (NULL));
1422 gst_base_ts_mux_release_pad (GstElement * element, GstPad * pad)
1424 GstBaseTsMux *mux = GST_BASE_TS_MUX (element);
1428 GstBaseTsMuxPad *ts_pad = GST_BASE_TS_MUX_PAD (pad);
1429 gint pid = ts_pad->pid;
1432 if (ts_pad->prog->pcr_stream == ts_pad->stream) {
1433 tsmux_program_set_pcr_stream (ts_pad->prog, NULL);
1435 if (tsmux_remove_stream (mux->tsmux, pid, ts_pad->prog)) {
1436 g_hash_table_remove (mux->programs, GINT_TO_POINTER (ts_pad->prog_id));
1440 tsmux_resend_pat (mux->tsmux);
1441 tsmux_resend_si (mux->tsmux);
1443 /* output PMT for each program */
1444 for (cur = mux->tsmux->programs; cur; cur = cur->next) {
1445 TsMuxProgram *program = (TsMuxProgram *) cur->data;
1447 tsmux_resend_pmt (program);
1451 GST_ELEMENT_CLASS (parent_class)->release_pad (element, pad);
1454 /* GstAggregator implementation */
1457 request_keyframe (GstBaseTsMux * mux, GstClockTime running_time)
1460 GST_OBJECT_LOCK (mux);
1462 for (l = GST_ELEMENT_CAST (mux)->sinkpads; l; l = l->next) {
1463 gst_pad_push_event (GST_PAD (l->data),
1464 gst_video_event_new_upstream_force_key_unit (running_time, TRUE, 0));
1467 GST_OBJECT_UNLOCK (mux);
1470 static const guint32 crc_tab[256] = {
1471 0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc, 0x17c56b6b,
1472 0x1a864db2, 0x1e475005, 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61,
1473 0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd, 0x4c11db70, 0x48d0c6c7,
1474 0x4593e01e, 0x4152fda9, 0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75,
1475 0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011, 0x791d4014, 0x7ddc5da3,
1476 0x709f7b7a, 0x745e66cd, 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039,
1477 0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, 0xbe2b5b58, 0xbaea46ef,
1478 0xb7a96036, 0xb3687d81, 0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d,
1479 0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49, 0xc7361b4c, 0xc3f706fb,
1480 0xceb42022, 0xca753d95, 0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1,
1481 0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, 0x34867077, 0x30476dc0,
1482 0x3d044b19, 0x39c556ae, 0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072,
1483 0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16, 0x018aeb13, 0x054bf6a4,
1484 0x0808d07d, 0x0cc9cdca, 0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde,
1485 0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02, 0x5e9f46bf, 0x5a5e5b08,
1486 0x571d7dd1, 0x53dc6066, 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba,
1487 0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, 0xbfa1b04b, 0xbb60adfc,
1488 0xb6238b25, 0xb2e29692, 0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6,
1489 0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a, 0xe0b41de7, 0xe4750050,
1490 0xe9362689, 0xedf73b3e, 0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2,
1491 0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683, 0xd1799b34,
1492 0xdc3abded, 0xd8fba05a, 0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637,
1493 0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb, 0x4f040d56, 0x4bc510e1,
1494 0x46863638, 0x42472b8f, 0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53,
1495 0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47, 0x36194d42, 0x32d850f5,
1496 0x3f9b762c, 0x3b5a6b9b, 0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff,
1497 0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, 0xf12f560e, 0xf5ee4bb9,
1498 0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b,
1499 0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f, 0xc423cd6a, 0xc0e2d0dd,
1500 0xcda1f604, 0xc960ebb3, 0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7,
1501 0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, 0x9b3660c6, 0x9ff77d71,
1502 0x92b45ba8, 0x9675461f, 0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3,
1503 0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640, 0x4e8ee645, 0x4a4ffbf2,
1504 0x470cdd2b, 0x43cdc09c, 0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8,
1505 0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24, 0x119b4be9, 0x155a565e,
1506 0x18197087, 0x1cd86d30, 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec,
1507 0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, 0x2497d08d, 0x2056cd3a,
1508 0x2d15ebe3, 0x29d4f654, 0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0,
1509 0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c, 0xe3a1cbc1, 0xe760d676,
1510 0xea23f0af, 0xeee2ed18, 0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4,
1511 0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0, 0x9abc8bd5, 0x9e7d9662,
1512 0x933eb0bb, 0x97ffad0c, 0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668,
1513 0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4
1517 _calc_crc32 (const guint8 * data, guint datalen)
1520 guint32 crc = 0xffffffff;
1522 for (i = 0; i < datalen; i++) {
1523 crc = (crc << 8) ^ crc_tab[((crc >> 24) ^ *data++) & 0xff];
1528 #define MPEGTIME_TO_GSTTIME(t) ((t) * (guint64)100000 / 9)
1530 static GstMpegtsSCTESpliceEvent *
1531 copy_splice (GstMpegtsSCTESpliceEvent * splice)
1533 return g_boxed_copy (GST_TYPE_MPEGTS_SCTE_SPLICE_EVENT, splice);
1537 free_splice (GstMpegtsSCTESpliceEvent * splice)
1539 g_boxed_free (GST_TYPE_MPEGTS_SCTE_SPLICE_EVENT, splice);
1542 /* FIXME: get rid of this when depending on glib >= 2.62 */
1545 _g_ptr_array_copy (GPtrArray * array,
1546 GCopyFunc func, GFreeFunc free_func, gpointer user_data)
1548 GPtrArray *new_array;
1550 g_return_val_if_fail (array != NULL, NULL);
1552 new_array = g_ptr_array_new_with_free_func (free_func);
1554 g_ptr_array_set_size (new_array, array->len);
1559 for (i = 0; i < array->len; i++)
1560 new_array->pdata[i] = func (array->pdata[i], user_data);
1561 } else if (array->len > 0) {
1562 memcpy (new_array->pdata, array->pdata,
1563 array->len * sizeof (*array->pdata));
1566 new_array->len = array->len;
1571 static GstMpegtsSCTESIT *
1572 deep_copy_sit (const GstMpegtsSCTESIT * sit)
1574 GstMpegtsSCTESIT *sit_copy = g_boxed_copy (GST_TYPE_MPEGTS_SCTE_SIT, sit);
1575 GPtrArray *splices_copy =
1576 _g_ptr_array_copy (sit_copy->splices, (GCopyFunc) copy_splice,
1577 (GFreeFunc) free_splice, NULL);
1579 g_ptr_array_unref (sit_copy->splices);
1580 sit_copy->splices = splices_copy;
1585 /* Takes ownership of @section.
1587 * This function is a bit complex because the SCTE sections can
1588 * have various origins:
1590 * * Sections created by the application with the gst_mpegts_scte_*_new()
1591 * API. The splice times / durations contained by these are expressed
1592 * in the GStreamer running time domain, and must be translated to
1593 * our local PES time domain. In this case, we will packetize the section
1596 * * Sections passed through from tsdemux: this case is complicated as
1597 * splice times in the incoming stream may be encrypted, with pts_adjustment
1598 * being the only timing field guaranteed *not* to be encrypted. In this
1599 * case, the original binary data (section->data) will be reinjected as is
1600 * in the output stream, with pts_adjustment adjusted. tsdemux provides us
1601 * with the pts_offset it introduces, the difference between the original
1602 * PES PTSs and the running times it outputs.
1604 * Additionally, in either of these cases when the splice times aren't encrypted
1605 * we want to make use of those to request keyframes. For the passthrough case,
1606 * as the splice times are left untouched tsdemux provides us with the running
1607 * times the section originally referred to. We cannot calculate it locally
1608 * because we would need to have access to the information that the timestamps
1609 * in the original PES domain have wrapped around, and how many times they have
1610 * done so. While we could probably make educated guesses, tsdemux (more specifically
1611 * mpegtspacketizer) already keeps track of that, and it seemed more logical to
1612 * perform the calculation there and forward it alongside the downstream events.
1614 * Finally, while we can't request keyframes at splice points in the encrypted
1615 * case, if the input stream was compliant in that regard and no reencoding took
1616 * place the splice times will still match with valid splice points, it is up
1617 * to the application to ensure that that is the case.
1620 handle_scte35_section (GstBaseTsMux * mux, GstEvent * event,
1621 GstMpegtsSection * section, guint64 mpeg_pts_offset,
1622 GstStructure * rtime_map)
1624 GstMpegtsSCTESIT *sit;
1626 gboolean forward = TRUE;
1628 guint8 *section_data;
1630 gboolean translate = FALSE;
1632 sit = (GstMpegtsSCTESIT *) gst_mpegts_section_get_scte_sit (section);
1634 /* When the application injects manually constructed splice events,
1635 * their time domain is the GStreamer running time, we receive them
1636 * unpacketized and translate the fields in the SIT to local PTS.
1638 * We make a copy of the SIT in order to make sure we can rewrite it.
1640 if (sit->is_running_time) {
1641 sit = deep_copy_sit (sit);
1645 switch (sit->splice_command_type) {
1646 case GST_MTS_SCTE_SPLICE_COMMAND_NULL:
1647 /* We implement heartbeating ourselves */
1650 case GST_MTS_SCTE_SPLICE_COMMAND_SCHEDULE:
1651 /* No need to request keyframes at this point, splice_insert
1652 * messages will precede the future splice points and we
1653 * can request keyframes then. Only translate if needed.
1656 for (i = 0; i < sit->splices->len; i++) {
1657 GstMpegtsSCTESpliceEvent *sevent =
1658 g_ptr_array_index (sit->splices, i);
1660 if (sevent->program_splice_time_specified)
1661 sevent->program_splice_time =
1662 GSTTIME_TO_MPEGTIME (sevent->program_splice_time) +
1665 if (sevent->duration_flag)
1666 sevent->break_duration =
1667 GSTTIME_TO_MPEGTIME (sevent->break_duration);
1671 case GST_MTS_SCTE_SPLICE_COMMAND_INSERT:
1672 /* We want keyframes at splice points */
1673 if (sit->fully_parsed && (rtime_map || translate)) {
1675 for (i = 0; i < sit->splices->len; i++) {
1676 guint64 running_time = GST_CLOCK_TIME_NONE;
1678 GstMpegtsSCTESpliceEvent *sevent =
1679 g_ptr_array_index (sit->splices, i);
1680 if (sevent->program_splice_time_specified) {
1682 gchar *field_name = g_strdup_printf ("event-%u-splice-time",
1683 sevent->splice_event_id);
1684 if (gst_structure_get_uint64 (rtime_map, field_name,
1686 GST_DEBUG_OBJECT (mux,
1687 "Requesting keyframe for splice point at %" GST_TIME_FORMAT,
1688 GST_TIME_ARGS (running_time));
1689 request_keyframe (mux, running_time);
1691 g_free (field_name);
1693 g_assert (translate == TRUE);
1694 running_time = sevent->program_splice_time;
1695 GST_DEBUG_OBJECT (mux,
1696 "Requesting keyframe for splice point at %" GST_TIME_FORMAT,
1697 GST_TIME_ARGS (running_time));
1698 request_keyframe (mux, running_time);
1699 sevent->program_splice_time =
1700 GSTTIME_TO_MPEGTIME (running_time) + TS_MUX_CLOCK_BASE;
1703 GST_DEBUG_OBJECT (mux,
1704 "Requesting keyframe for immediate splice point");
1705 request_keyframe (mux, GST_CLOCK_TIME_NONE);
1708 if (sevent->duration_flag) {
1710 sevent->break_duration =
1711 GSTTIME_TO_MPEGTIME (sevent->break_duration);
1714 /* Even if auto_return is FALSE, when a break_duration is specified it
1715 * is intended as a redundancy mechanism in case the follow-up
1716 * splice insert goes missing.
1718 * Schedule a keyframe at that point (if we can calculate its position
1721 if (GST_CLOCK_TIME_IS_VALID (running_time)) {
1722 running_time += MPEGTIME_TO_GSTTIME (sevent->break_duration);
1723 GST_DEBUG_OBJECT (mux,
1724 "Requesting keyframe for end of break at %" GST_TIME_FORMAT,
1725 GST_TIME_ARGS (running_time));
1726 request_keyframe (mux, running_time);
1732 case GST_MTS_SCTE_SPLICE_COMMAND_TIME:{
1733 /* Adjust timestamps and potentially request keyframes */
1734 gboolean do_request_keyframes = FALSE;
1736 /* TODO: we can probably be a little more fine-tuned about determining
1737 * whether a keyframe is actually needed, but this at least takes care
1738 * of the requirement in 10.3.4 that a keyframe should not be created
1739 * when the signal contains only a time_descriptor.
1741 if (sit->fully_parsed && (rtime_map || translate)) {
1742 for (i = 0; i < sit->descriptors->len; i++) {
1743 GstMpegtsDescriptor *descriptor =
1744 g_ptr_array_index (sit->descriptors, i);
1746 switch (descriptor->tag) {
1747 case GST_MTS_SCTE_DESC_AVAIL:
1748 case GST_MTS_SCTE_DESC_DTMF:
1749 case GST_MTS_SCTE_DESC_SEGMENTATION:
1750 do_request_keyframes = TRUE;
1752 case GST_MTS_SCTE_DESC_TIME:
1753 case GST_MTS_SCTE_DESC_AUDIO:
1757 if (do_request_keyframes)
1761 if (sit->splice_time_specified) {
1762 GstClockTime running_time = GST_CLOCK_TIME_NONE;
1765 if (do_request_keyframes
1766 && gst_structure_get_uint64 (rtime_map, "splice-time",
1768 GST_DEBUG_OBJECT (mux,
1769 "Requesting keyframe for time signal at %" GST_TIME_FORMAT,
1770 GST_TIME_ARGS (running_time));
1771 request_keyframe (mux, running_time);
1774 g_assert (translate);
1775 running_time = sit->splice_time;
1777 GSTTIME_TO_MPEGTIME (running_time) + TS_MUX_CLOCK_BASE;
1778 if (do_request_keyframes) {
1779 GST_DEBUG_OBJECT (mux,
1780 "Requesting keyframe for time signal at %" GST_TIME_FORMAT,
1781 GST_TIME_ARGS (running_time));
1782 request_keyframe (mux, running_time);
1785 } else if (do_request_keyframes) {
1786 GST_DEBUG_OBJECT (mux,
1787 "Requesting keyframe for immediate time signal");
1788 request_keyframe (mux, GST_CLOCK_TIME_NONE);
1793 case GST_MTS_SCTE_SPLICE_COMMAND_BANDWIDTH:
1794 case GST_MTS_SCTE_SPLICE_COMMAND_PRIVATE:
1795 /* Just let those go through untouched, none of our business */
1802 gst_mpegts_section_unref (section);
1807 g_assert (section->data);
1808 /* Calculate the final adjustment, as a sum of:
1809 * - The adjustment in the original packet
1810 * - The offset introduced between the original local PTS
1811 * and the GStreamer PTS output by tsdemux
1812 * - Our own 1-hour offset
1814 pts_adjust = sit->pts_adjustment + mpeg_pts_offset + TS_MUX_CLOCK_BASE;
1816 /* Account for offsets potentially introduced between the demuxer and us */
1818 GSTTIME_TO_MPEGTIME (gst_event_get_running_time_offset (event));
1820 pts_adjust &= 0x1ffffffff;
1821 section_data = g_memdup (section->data, section->section_length);
1822 section_data[4] |= pts_adjust >> 32;
1823 section_data[5] = pts_adjust >> 24;
1824 section_data[6] = pts_adjust >> 16;
1825 section_data[7] = pts_adjust >> 8;
1826 section_data[8] = pts_adjust;
1828 /* Now rewrite our checksum */
1829 crc = section_data + section->section_length - 4;
1830 GST_WRITE_UINT32_BE (crc, _calc_crc32 (section_data, crc - section_data));
1832 GST_OBJECT_LOCK (mux);
1833 GST_DEBUG_OBJECT (mux, "Storing SCTE section");
1834 if (mux->pending_scte35_section)
1835 gst_mpegts_section_unref (mux->pending_scte35_section);
1836 mux->pending_scte35_section =
1837 gst_mpegts_section_new (mux->scte35_pid, section_data,
1838 section->section_length);
1839 GST_OBJECT_UNLOCK (mux);
1841 gst_mpegts_section_unref (section);
1843 GST_OBJECT_LOCK (mux);
1844 GST_DEBUG_OBJECT (mux, "Storing SCTE section");
1845 gst_mpegts_section_unref (section);
1846 if (mux->pending_scte35_section)
1847 gst_mpegts_section_unref (mux->pending_scte35_section);
1848 mux->pending_scte35_section =
1849 gst_mpegts_section_from_scte_sit (sit, mux->scte35_pid);;
1850 GST_OBJECT_UNLOCK (mux);
1855 gst_base_ts_mux_send_event (GstElement * element, GstEvent * event)
1857 GstMpegtsSection *section;
1858 GstBaseTsMux *mux = GST_BASE_TS_MUX (element);
1860 section = gst_event_parse_mpegts_section (event);
1863 GST_DEBUG ("Received event with mpegts section");
1865 if (section->section_type == GST_MPEGTS_SECTION_SCTE_SIT) {
1866 handle_scte35_section (mux, event, section, 0, NULL);
1868 /* TODO: Check that the section type is supported */
1869 tsmux_add_mpegts_si_section (mux->tsmux, section);
1872 gst_event_unref (event);
1877 return GST_ELEMENT_CLASS (parent_class)->send_event (element, event);
1880 /* GstAggregator implementation */
1883 gst_base_ts_mux_sink_event (GstAggregator * agg, GstAggregatorPad * agg_pad,
1886 GstAggregatorClass *agg_class = GST_AGGREGATOR_CLASS (parent_class);
1887 GstBaseTsMux *mux = GST_BASE_TS_MUX (agg);
1888 GstBaseTsMuxPad *ts_pad = GST_BASE_TS_MUX_PAD (agg_pad);
1889 gboolean res = FALSE;
1890 gboolean forward = TRUE;
1892 switch (GST_EVENT_TYPE (event)) {
1893 case GST_EVENT_CAPS:
1899 if (ts_pad->stream == NULL)
1904 gst_event_parse_caps (event, &caps);
1905 if (!caps || !gst_caps_is_fixed (caps))
1908 ret = gst_base_ts_mux_create_or_update_stream (mux, ts_pad, caps);
1909 if (ret != GST_FLOW_OK)
1912 mux->tsmux->pat_changed = TRUE;
1913 mux->tsmux->si_changed = TRUE;
1914 tsmux_resend_pat (mux->tsmux);
1915 tsmux_resend_si (mux->tsmux);
1917 /* output PMT for each program */
1918 for (cur = mux->tsmux->programs; cur; cur = cur->next) {
1919 TsMuxProgram *program = (TsMuxProgram *) cur->data;
1921 program->pmt_changed = TRUE;
1922 tsmux_resend_pmt (program);
1928 case GST_EVENT_CUSTOM_DOWNSTREAM:
1930 GstClockTime timestamp, stream_time, running_time;
1931 gboolean all_headers;
1933 const GstStructure *s;
1935 s = gst_event_get_structure (event);
1937 if (gst_structure_has_name (s, "scte-sit") && mux->scte35_pid != 0) {
1939 /* When operating downstream of tsdemux, tsdemux will send out events
1940 * on all its source pads for each splice table it encounters. If we
1941 * are remuxing multiple streams it has demuxed, this means we could
1942 * unnecessarily repeat the same table multiple times, we avoid that
1943 * by deduplicating thanks to the event sequm
1945 if (gst_event_get_seqnum (event) != mux->last_scte35_event_seqnum) {
1946 GstMpegtsSection *section;
1948 gst_structure_get (s, "section", GST_TYPE_MPEGTS_SECTION, §ion,
1951 guint64 mpeg_pts_offset = 0;
1952 GstStructure *rtime_map = NULL;
1954 gst_structure_get (s, "running-time-map", GST_TYPE_STRUCTURE,
1956 gst_structure_get_uint64 (s, "mpeg-pts-offset", &mpeg_pts_offset);
1958 handle_scte35_section (mux, event, section, mpeg_pts_offset,
1961 gst_structure_free (rtime_map);
1962 mux->last_scte35_event_seqnum = gst_event_get_seqnum (event);
1964 GST_WARNING_OBJECT (ts_pad,
1965 "Ignoring scte-sit event without a section");
1968 GST_DEBUG_OBJECT (ts_pad, "Ignoring duplicate scte-sit event");
1975 if (!gst_video_event_is_force_key_unit (event))
1981 gst_video_event_parse_downstream_force_key_unit (event,
1982 ×tamp, &stream_time, &running_time, &all_headers, &count);
1983 GST_INFO_OBJECT (ts_pad, "have downstream force-key-unit event, "
1984 "seqnum %d, running-time %" GST_TIME_FORMAT " count %d",
1985 gst_event_get_seqnum (event), GST_TIME_ARGS (running_time), count);
1987 if (mux->force_key_unit_event != NULL) {
1988 GST_INFO_OBJECT (mux, "skipping downstream force key unit event "
1989 "as an upstream force key unit is already queued");
1996 mux->pending_key_unit_ts = running_time;
1997 gst_event_replace (&mux->force_key_unit_event, event);
2000 case GST_EVENT_TAG:{
2004 GST_DEBUG_OBJECT (mux, "received tag event");
2005 gst_event_parse_tag (event, &list);
2007 /* Matroska wants ISO 639-2B code, taglist most likely contains 639-1 */
2008 if (gst_tag_list_get_string (list, GST_TAG_LANGUAGE_CODE, &lang)) {
2009 const gchar *lang_code;
2011 lang_code = gst_tag_get_language_code_iso_639_2B (lang);
2013 GST_DEBUG_OBJECT (ts_pad, "Setting language to '%s'", lang_code);
2015 g_free (ts_pad->language);
2016 ts_pad->language = g_strdup (lang_code);
2018 GST_WARNING_OBJECT (ts_pad, "Did not get language code for '%s'",
2024 /* handled this, don't want collectpads to forward it downstream */
2026 forward = gst_tag_list_get_scope (list) == GST_TAG_SCOPE_GLOBAL;
2029 case GST_EVENT_STREAM_START:{
2030 GstStreamFlags flags;
2032 gst_event_parse_stream_flags (event, &flags);
2034 /* Don't wait for data on sparse inputs like metadata streams */
2036 if ((flags & GST_STREAM_FLAG_SPARSE)) {
2037 GST_COLLECT_PADS_STATE_UNSET (data, GST_COLLECT_PADS_STATE_LOCKED);
2038 gst_collect_pads_set_waiting (pads, data, FALSE);
2039 GST_COLLECT_PADS_STATE_SET (data, GST_COLLECT_PADS_STATE_LOCKED);
2050 gst_event_unref (event);
2052 res = agg_class->sink_event (agg, agg_pad, event);
2058 gst_base_ts_mux_src_event (GstAggregator * agg, GstEvent * event)
2060 GstAggregatorClass *agg_class = GST_AGGREGATOR_CLASS (parent_class);
2061 GstBaseTsMux *mux = GST_BASE_TS_MUX (agg);
2062 gboolean res = TRUE, forward = TRUE;
2064 switch (GST_EVENT_TYPE (event)) {
2065 case GST_EVENT_CUSTOM_UPSTREAM:
2068 GValue sinkpad_value = G_VALUE_INIT;
2069 GstClockTime running_time;
2070 gboolean all_headers, done = FALSE, res = FALSE;
2073 if (!gst_video_event_is_force_key_unit (event))
2078 gst_video_event_parse_upstream_force_key_unit (event,
2079 &running_time, &all_headers, &count);
2081 GST_INFO_OBJECT (mux, "received upstream force-key-unit event, "
2082 "seqnum %d running_time %" GST_TIME_FORMAT " all_headers %d count %d",
2083 gst_event_get_seqnum (event), GST_TIME_ARGS (running_time),
2084 all_headers, count);
2089 mux->pending_key_unit_ts = running_time;
2090 gst_event_replace (&mux->force_key_unit_event, event);
2092 iter = gst_element_iterate_sink_pads (GST_ELEMENT_CAST (mux));
2095 switch (gst_iterator_next (iter, &sinkpad_value)) {
2096 case GST_ITERATOR_OK:{
2097 GstPad *sinkpad = g_value_get_object (&sinkpad_value);
2100 GST_INFO_OBJECT (GST_AGGREGATOR_SRC_PAD (agg), "forwarding");
2101 tmp = gst_pad_push_event (sinkpad, gst_event_ref (event));
2102 GST_INFO_OBJECT (mux, "result %d", tmp);
2103 /* succeed if at least one pad succeeds */
2107 case GST_ITERATOR_DONE:
2110 case GST_ITERATOR_RESYNC:
2111 gst_iterator_resync (iter);
2113 case GST_ITERATOR_ERROR:
2114 g_assert_not_reached ();
2117 g_value_reset (&sinkpad_value);
2119 g_value_unset (&sinkpad_value);
2120 gst_iterator_free (iter);
2128 res = agg_class->src_event (agg, event);
2130 gst_event_unref (event);
2136 gst_base_ts_mux_clip (GstAggregator * agg,
2137 GstAggregatorPad * agg_pad, GstBuffer * buf)
2139 GstBaseTsMuxPad *pad = GST_BASE_TS_MUX_PAD (agg_pad);
2146 time = GST_BUFFER_PTS (buf);
2148 /* invalid left alone and passed */
2149 if (G_LIKELY (GST_CLOCK_TIME_IS_VALID (time))) {
2151 gst_segment_to_running_time (&agg_pad->segment, GST_FORMAT_TIME, time);
2152 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (time))) {
2153 GST_DEBUG_OBJECT (pad, "clipping buffer on pad outside segment");
2154 gst_buffer_unref (buf);
2158 GST_LOG_OBJECT (pad, "buffer pts %" GST_TIME_FORMAT " -> %"
2159 GST_TIME_FORMAT " running time",
2160 GST_TIME_ARGS (GST_BUFFER_PTS (buf)), GST_TIME_ARGS (time));
2161 buf = ret = gst_buffer_make_writable (buf);
2162 GST_BUFFER_PTS (ret) = time;
2167 time = GST_BUFFER_DTS (buf);
2169 /* invalid left alone and passed */
2170 if (G_LIKELY (GST_CLOCK_TIME_IS_VALID (time))) {
2174 sign = gst_segment_to_running_time_full (&agg_pad->segment, GST_FORMAT_TIME,
2178 dts = (gint64) time;
2180 dts = -((gint64) time);
2182 GST_LOG_OBJECT (pad, "buffer dts %" GST_TIME_FORMAT " -> %"
2183 GST_STIME_FORMAT " running time", GST_TIME_ARGS (GST_BUFFER_DTS (buf)),
2184 GST_STIME_ARGS (dts));
2186 if (GST_CLOCK_STIME_IS_VALID (pad->dts) && dts < pad->dts) {
2187 /* Ignore DTS going backward */
2188 GST_WARNING_OBJECT (pad, "ignoring DTS going backward");
2192 ret = gst_buffer_make_writable (buf);
2194 GST_BUFFER_DTS (ret) = time;
2196 GST_BUFFER_DTS (ret) = GST_CLOCK_TIME_NONE;
2200 pad->dts = GST_CLOCK_STIME_NONE;
2207 static GstFlowReturn
2208 gst_base_ts_mux_update_src_caps (GstAggregator * agg, GstCaps * caps,
2211 GstBaseTsMux *mux = GST_BASE_TS_MUX (agg);
2214 *ret = gst_caps_copy (caps);
2215 s = gst_caps_get_structure (*ret, 0);
2216 gst_structure_set (s, "packetsize", G_TYPE_INT, mux->packet_size, NULL);
2221 static GstBaseTsMuxPad *
2222 gst_base_ts_mux_find_best_pad (GstAggregator * aggregator)
2224 GstBaseTsMuxPad *best = NULL;
2225 GstClockTime best_ts = GST_CLOCK_TIME_NONE;
2228 GST_OBJECT_LOCK (aggregator);
2230 for (l = GST_ELEMENT_CAST (aggregator)->sinkpads; l; l = l->next) {
2231 GstBaseTsMuxPad *tpad = GST_BASE_TS_MUX_PAD (l->data);
2232 GstAggregatorPad *apad = GST_AGGREGATOR_PAD_CAST (tpad);
2235 buffer = gst_aggregator_pad_peek_buffer (apad);
2238 if (best_ts == GST_CLOCK_TIME_NONE) {
2240 best_ts = GST_BUFFER_DTS_OR_PTS (buffer);
2241 } else if (GST_BUFFER_DTS_OR_PTS (buffer) != GST_CLOCK_TIME_NONE) {
2242 GstClockTime t = GST_BUFFER_DTS_OR_PTS (buffer);
2248 gst_buffer_unref (buffer);
2252 gst_object_ref (best);
2254 GST_OBJECT_UNLOCK (aggregator);
2256 GST_DEBUG_OBJECT (aggregator,
2257 "Best pad found with %" GST_TIME_FORMAT ": %" GST_PTR_FORMAT,
2258 GST_TIME_ARGS (best_ts), best);
2264 gst_base_ts_mux_are_all_pads_eos (GstBaseTsMux * mux)
2267 gboolean ret = TRUE;
2269 GST_OBJECT_LOCK (mux);
2271 for (l = GST_ELEMENT_CAST (mux)->sinkpads; l; l = l->next) {
2272 GstBaseTsMuxPad *pad = GST_BASE_TS_MUX_PAD (l->data);
2274 if (!gst_aggregator_pad_is_eos (GST_AGGREGATOR_PAD (pad))) {
2280 GST_OBJECT_UNLOCK (mux);
2286 static GstFlowReturn
2287 gst_base_ts_mux_aggregate (GstAggregator * agg, gboolean timeout)
2289 GstBaseTsMux *mux = GST_BASE_TS_MUX (agg);
2290 GstFlowReturn ret = GST_FLOW_OK;
2291 GstBaseTsMuxPad *best = gst_base_ts_mux_find_best_pad (agg);
2296 buffer = gst_aggregator_pad_pop_buffer (GST_AGGREGATOR_PAD (best));
2298 /* We might have gotten a flush event after we picked the pad */
2303 gst_base_ts_mux_aggregate_buffer (GST_BASE_TS_MUX (agg),
2304 GST_AGGREGATOR_PAD (best), buffer);
2306 gst_object_unref (best);
2308 if (ret != GST_FLOW_OK)
2312 if (gst_base_ts_mux_are_all_pads_eos (mux)) {
2313 GstBaseTsMuxClass *klass = GST_BASE_TS_MUX_GET_CLASS (mux);
2314 /* drain some possibly cached data */
2317 gst_base_ts_mux_push_packets (mux, TRUE);
2327 gst_base_ts_mux_start (GstAggregator * agg)
2329 gst_base_ts_mux_reset (GST_BASE_TS_MUX (agg), TRUE);
2335 gst_base_ts_mux_stop (GstAggregator * agg)
2337 gst_base_ts_mux_reset (GST_BASE_TS_MUX (agg), TRUE);
2342 /* GObject implementation */
2345 gst_base_ts_mux_dispose (GObject * object)
2347 GstBaseTsMux *mux = GST_BASE_TS_MUX (object);
2349 gst_base_ts_mux_reset (mux, FALSE);
2351 if (mux->out_adapter) {
2352 g_object_unref (mux->out_adapter);
2353 mux->out_adapter = NULL;
2355 if (mux->prog_map) {
2356 gst_structure_free (mux->prog_map);
2357 mux->prog_map = NULL;
2359 if (mux->programs) {
2360 g_hash_table_destroy (mux->programs);
2361 mux->programs = NULL;
2363 GST_CALL_PARENT (G_OBJECT_CLASS, dispose, (object));
2367 gst_base_ts_mux_constructed (GObject * object)
2369 GstBaseTsMux *mux = GST_BASE_TS_MUX (object);
2372 gst_base_ts_mux_reset (mux, TRUE);
2376 gst_base_ts_mux_set_property (GObject * object, guint prop_id,
2377 const GValue * value, GParamSpec * pspec)
2379 GstBaseTsMux *mux = GST_BASE_TS_MUX (object);
2385 const GstStructure *s = gst_value_get_structure (value);
2386 if (mux->prog_map) {
2387 gst_structure_free (mux->prog_map);
2390 mux->prog_map = gst_structure_copy (s);
2392 mux->prog_map = NULL;
2395 case PROP_PAT_INTERVAL:
2396 mux->pat_interval = g_value_get_uint (value);
2398 tsmux_set_pat_interval (mux->tsmux, mux->pat_interval);
2400 case PROP_PMT_INTERVAL:
2401 mux->pmt_interval = g_value_get_uint (value);
2402 GST_OBJECT_LOCK (mux);
2403 for (l = GST_ELEMENT_CAST (mux)->sinkpads; l; l = l->next) {
2404 GstBaseTsMuxPad *ts_pad = GST_BASE_TS_MUX_PAD (l->data);
2406 tsmux_set_pmt_interval (ts_pad->prog, mux->pmt_interval);
2408 GST_OBJECT_UNLOCK (mux);
2410 case PROP_ALIGNMENT:
2411 mux->alignment = g_value_get_int (value);
2413 case PROP_SI_INTERVAL:
2414 mux->si_interval = g_value_get_uint (value);
2415 tsmux_set_si_interval (mux->tsmux, mux->si_interval);
2418 mux->bitrate = g_value_get_uint64 (value);
2420 tsmux_set_bitrate (mux->tsmux, mux->bitrate);
2422 case PROP_PCR_INTERVAL:
2423 mux->pcr_interval = g_value_get_uint (value);
2425 tsmux_set_pcr_interval (mux->tsmux, mux->pcr_interval);
2427 case PROP_SCTE_35_PID:
2428 mux->scte35_pid = g_value_get_uint (value);
2430 case PROP_SCTE_35_NULL_INTERVAL:
2431 mux->scte35_null_interval = g_value_get_uint (value);
2434 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
2440 gst_base_ts_mux_get_property (GObject * object, guint prop_id,
2441 GValue * value, GParamSpec * pspec)
2443 GstBaseTsMux *mux = GST_BASE_TS_MUX (object);
2447 gst_value_set_structure (value, mux->prog_map);
2449 case PROP_PAT_INTERVAL:
2450 g_value_set_uint (value, mux->pat_interval);
2452 case PROP_PMT_INTERVAL:
2453 g_value_set_uint (value, mux->pmt_interval);
2455 case PROP_ALIGNMENT:
2456 g_value_set_int (value, mux->alignment);
2458 case PROP_SI_INTERVAL:
2459 g_value_set_uint (value, mux->si_interval);
2462 g_value_set_uint64 (value, mux->bitrate);
2464 case PROP_PCR_INTERVAL:
2465 g_value_set_uint (value, mux->pcr_interval);
2467 case PROP_SCTE_35_PID:
2468 g_value_set_uint (value, mux->scte35_pid);
2470 case PROP_SCTE_35_NULL_INTERVAL:
2471 g_value_set_uint (value, mux->scte35_null_interval);
2474 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
2479 /* Default vmethods implementation */
2482 gst_base_ts_mux_default_create_ts_mux (GstBaseTsMux * mux)
2484 TsMux *tsmux = tsmux_new ();
2485 tsmux_set_write_func (tsmux, new_packet_cb, mux);
2486 tsmux_set_alloc_func (tsmux, alloc_packet_cb, mux);
2487 tsmux_set_pat_interval (tsmux, mux->pat_interval);
2488 tsmux_set_si_interval (tsmux, mux->si_interval);
2489 tsmux_set_bitrate (tsmux, mux->bitrate);
2490 tsmux_set_pcr_interval (tsmux, mux->pcr_interval);
2496 gst_base_ts_mux_default_allocate_packet (GstBaseTsMux * mux,
2497 GstBuffer ** buffer)
2501 buf = gst_buffer_new_and_alloc (mux->packet_size);
2507 gst_base_ts_mux_default_output_packet (GstBaseTsMux * mux, GstBuffer * buffer,
2510 gst_base_ts_mux_collect_packet (mux, buffer);
2518 gst_base_ts_mux_set_packet_size (GstBaseTsMux * mux, gsize size)
2520 mux->packet_size = size;
2524 gst_base_ts_mux_set_automatic_alignment (GstBaseTsMux * mux, gsize alignment)
2526 mux->automatic_alignment = alignment;
2530 gst_base_ts_mux_class_init (GstBaseTsMuxClass * klass)
2532 GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
2533 GstAggregatorClass *gstagg_class = GST_AGGREGATOR_CLASS (klass);
2534 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
2536 GST_DEBUG_CATEGORY_INIT (gst_base_ts_mux_debug, "basetsmux", 0,
2537 "MPEG Transport Stream muxer");
2539 gst_element_class_set_static_metadata (gstelement_class,
2540 "MPEG Transport Stream Muxer", "Codec/Muxer",
2541 "Multiplexes media streams into an MPEG Transport Stream",
2542 "Fluendo <contact@fluendo.com>");
2544 gobject_class->set_property =
2545 GST_DEBUG_FUNCPTR (gst_base_ts_mux_set_property);
2546 gobject_class->get_property =
2547 GST_DEBUG_FUNCPTR (gst_base_ts_mux_get_property);
2548 gobject_class->dispose = gst_base_ts_mux_dispose;
2549 gobject_class->constructed = gst_base_ts_mux_constructed;
2551 gstelement_class->request_new_pad = gst_base_ts_mux_request_new_pad;
2552 gstelement_class->release_pad = gst_base_ts_mux_release_pad;
2553 gstelement_class->send_event = gst_base_ts_mux_send_event;
2555 gstagg_class->update_src_caps = gst_base_ts_mux_update_src_caps;
2556 gstagg_class->aggregate = gst_base_ts_mux_aggregate;
2557 gstagg_class->clip = gst_base_ts_mux_clip;
2558 gstagg_class->sink_event = gst_base_ts_mux_sink_event;
2559 gstagg_class->src_event = gst_base_ts_mux_src_event;
2560 gstagg_class->start = gst_base_ts_mux_start;
2561 gstagg_class->stop = gst_base_ts_mux_stop;
2563 klass->create_ts_mux = gst_base_ts_mux_default_create_ts_mux;
2564 klass->allocate_packet = gst_base_ts_mux_default_allocate_packet;
2565 klass->output_packet = gst_base_ts_mux_default_output_packet;
2567 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_PROG_MAP,
2568 g_param_spec_boxed ("prog-map", "Program map",
2569 "A GstStructure specifies the mapping from elementary streams to programs",
2571 (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
2573 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_PAT_INTERVAL,
2574 g_param_spec_uint ("pat-interval", "PAT interval",
2575 "Set the interval (in ticks of the 90kHz clock) for writing out the PAT table",
2576 1, G_MAXUINT, TSMUX_DEFAULT_PAT_INTERVAL,
2577 (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
2579 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_PMT_INTERVAL,
2580 g_param_spec_uint ("pmt-interval", "PMT interval",
2581 "Set the interval (in ticks of the 90kHz clock) for writing out the PMT table",
2582 1, G_MAXUINT, TSMUX_DEFAULT_PMT_INTERVAL,
2583 (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
2585 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_ALIGNMENT,
2586 g_param_spec_int ("alignment", "packet alignment",
2587 "Number of packets per buffer (padded with dummy packets on EOS) "
2588 "(-1 = auto, 0 = all available packets, 7 for UDP streaming)",
2589 -1, G_MAXINT, BASETSMUX_DEFAULT_ALIGNMENT,
2590 (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
2592 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_SI_INTERVAL,
2593 g_param_spec_uint ("si-interval", "SI interval",
2594 "Set the interval (in ticks of the 90kHz clock) for writing out the Service"
2595 "Information tables", 1, G_MAXUINT, TSMUX_DEFAULT_SI_INTERVAL,
2596 (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
2598 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_BITRATE,
2599 g_param_spec_uint64 ("bitrate", "Bitrate (in bits per second)",
2600 "Set the target bitrate, will insert null packets as padding "
2601 " to achieve multiplex-wide constant bitrate (0 means no padding)",
2602 0, G_MAXUINT64, TSMUX_DEFAULT_BITRATE,
2603 (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
2605 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_PCR_INTERVAL,
2606 g_param_spec_uint ("pcr-interval", "PCR interval",
2607 "Set the interval (in ticks of the 90kHz clock) for writing PCR",
2608 1, G_MAXUINT, TSMUX_DEFAULT_PCR_INTERVAL,
2609 (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
2611 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_SCTE_35_PID,
2612 g_param_spec_uint ("scte-35-pid", "SCTE-35 PID",
2613 "PID to use for inserting SCTE-35 packets (0: unused)",
2614 0, G_MAXUINT, DEFAULT_SCTE_35_PID,
2615 (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
2617 g_object_class_install_property (G_OBJECT_CLASS (klass),
2618 PROP_SCTE_35_NULL_INTERVAL, g_param_spec_uint ("scte-35-null-interval",
2619 "SCTE-35 NULL packet interval",
2620 "Set the interval (in ticks of the 90kHz clock) for writing SCTE-35 NULL (heartbeat) packets."
2621 " (only valid if scte-35-pid is different from 0)", 1, G_MAXUINT,
2622 TSMUX_DEFAULT_SCTE_35_NULL_INTERVAL,
2623 (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
2625 gst_element_class_add_static_pad_template_with_gtype (gstelement_class,
2626 &gst_base_ts_mux_src_factory, GST_TYPE_AGGREGATOR_PAD);
2628 gst_type_mark_as_plugin_api (GST_TYPE_BASE_TS_MUX_PAD, 0);
2632 gst_base_ts_mux_init (GstBaseTsMux * mux)
2634 mux->out_adapter = gst_adapter_new ();
2637 mux->pat_interval = TSMUX_DEFAULT_PAT_INTERVAL;
2638 mux->pmt_interval = TSMUX_DEFAULT_PMT_INTERVAL;
2639 mux->si_interval = TSMUX_DEFAULT_SI_INTERVAL;
2640 mux->pcr_interval = TSMUX_DEFAULT_PCR_INTERVAL;
2641 mux->prog_map = NULL;
2642 mux->alignment = BASETSMUX_DEFAULT_ALIGNMENT;
2643 mux->bitrate = TSMUX_DEFAULT_BITRATE;
2644 mux->scte35_pid = DEFAULT_SCTE_35_PID;
2645 mux->scte35_null_interval = TSMUX_DEFAULT_SCTE_35_NULL_INTERVAL;
2647 mux->packet_size = GST_BASE_TS_MUX_NORMAL_PACKET_LENGTH;
2648 mux->automatic_alignment = 0;