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
75 #include <gst/tag/tag.h>
76 #include <gst/video/video.h>
77 #include <gst/mpegts/mpegts.h>
78 #include <gst/pbutils/pbutils.h>
79 #include <gst/videoparsers/gstjpeg2000parse.h>
80 #include <gst/video/video-color.h>
82 #include "gstbasetsmux.h"
83 #include "gstbasetsmuxaac.h"
84 #include "gstbasetsmuxttxt.h"
85 #include "gstbasetsmuxopus.h"
86 #include "gstbasetsmuxjpeg2000.h"
88 GST_DEBUG_CATEGORY (gst_base_ts_mux_debug);
89 #define GST_CAT_DEFAULT gst_base_ts_mux_debug
93 G_DEFINE_TYPE (GstBaseTsMuxPad, gst_base_ts_mux_pad, GST_TYPE_AGGREGATOR_PAD);
98 gst_base_ts_mux_pad_reset (GstBaseTsMuxPad * pad)
100 pad->dts = GST_CLOCK_STIME_NONE;
104 pad->free_func (pad->prepare_data);
105 pad->prepare_data = NULL;
106 pad->prepare_func = NULL;
107 pad->free_func = NULL;
110 gst_buffer_replace (&pad->codec_data, NULL);
112 /* reference owned elsewhere */
117 g_free (pad->language);
118 pad->language = NULL;
122 /* GstAggregatorPad implementation */
125 gst_base_ts_mux_pad_flush (GstAggregatorPad * agg_pad, GstAggregator * agg)
128 GstBaseTsMux *mux = GST_BASE_TS_MUX (agg);
130 /* Send initial segments again after a flush-stop, and also resend the
134 /* output PAT, SI tables */
135 tsmux_resend_pat (mux->tsmux);
136 tsmux_resend_si (mux->tsmux);
138 /* output PMT for each program */
139 for (cur = mux->tsmux->programs; cur; cur = cur->next) {
140 TsMuxProgram *program = (TsMuxProgram *) cur->data;
142 tsmux_resend_pmt (program);
148 /* GObject implementation */
151 gst_base_ts_mux_pad_dispose (GObject * obj)
153 GstBaseTsMuxPad *ts_pad = GST_BASE_TS_MUX_PAD (obj);
155 gst_base_ts_mux_pad_reset (ts_pad);
157 G_OBJECT_CLASS (gst_base_ts_mux_pad_parent_class)->dispose (obj);
161 gst_base_ts_mux_pad_class_init (GstBaseTsMuxPadClass * klass)
163 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
164 GstAggregatorPadClass *gstaggpad_class = GST_AGGREGATOR_PAD_CLASS (klass);
166 gobject_class->dispose = gst_base_ts_mux_pad_dispose;
167 gstaggpad_class->flush = gst_base_ts_mux_pad_flush;
169 gst_type_mark_as_plugin_api (GST_TYPE_BASE_TS_MUX, 0);
173 gst_base_ts_mux_pad_init (GstBaseTsMuxPad * vaggpad)
190 PROP_SCTE_35_NULL_INTERVAL
193 #define DEFAULT_SCTE_35_PID 0
195 #define BASETSMUX_DEFAULT_ALIGNMENT -1
197 #define CLOCK_BASE 9LL
198 #define CLOCK_FREQ (CLOCK_BASE * 10000) /* 90 kHz PTS clock */
199 #define CLOCK_FREQ_SCR (CLOCK_FREQ * 300) /* 27 MHz SCR clock */
200 #define TS_MUX_CLOCK_BASE (TSMUX_CLOCK_FREQ * 10 * 360)
202 #define GSTTIME_TO_MPEGTIME(time) \
203 (((time) > 0 ? (gint64) 1 : (gint64) -1) * \
204 (gint64) gst_util_uint64_scale (ABS(time), CLOCK_BASE, GST_MSECOND/10))
205 /* 27 MHz SCR conversions: */
206 #define MPEG_SYS_TIME_TO_GSTTIME(time) (gst_util_uint64_scale ((time), \
207 GST_USECOND, CLOCK_FREQ_SCR / 1000000))
208 #define GSTTIME_TO_MPEG_SYS_TIME(time) (gst_util_uint64_scale ((time), \
209 CLOCK_FREQ_SCR / 1000000, GST_USECOND))
211 #define DEFAULT_PROG_ID 0
213 static GstStaticPadTemplate gst_base_ts_mux_src_factory =
214 GST_STATIC_PAD_TEMPLATE ("src",
217 GST_STATIC_CAPS ("video/mpegts, "
218 "systemstream = (boolean) true, " "packetsize = (int) { 188, 192} ")
227 G_DEFINE_TYPE_WITH_CODE (GstBaseTsMux, gst_base_ts_mux, GST_TYPE_AGGREGATOR,
228 gst_mpegts_initialize ());
232 /* Takes over the ref on the buffer */
234 stream_data_new (GstBuffer * buffer)
236 StreamData *res = g_new (StreamData, 1);
237 res->buffer = buffer;
238 gst_buffer_map (buffer, &(res->map_info), GST_MAP_READ);
244 stream_data_free (StreamData * data)
247 gst_buffer_unmap (data->buffer, &data->map_info);
248 gst_buffer_unref (data->buffer);
253 #define parent_class gst_base_ts_mux_parent_class
256 gst_base_ts_mux_set_header_on_caps (GstBaseTsMux * mux)
259 GstStructure *structure;
260 GValue array = { 0 };
261 GValue value = { 0 };
264 caps = gst_pad_get_current_caps (GST_AGGREGATOR_SRC_PAD (mux));
266 /* If we have no caps, we are possibly shutting down */
270 caps = gst_caps_make_writable (caps);
271 structure = gst_caps_get_structure (caps, 0);
273 g_value_init (&array, GST_TYPE_ARRAY);
275 GST_LOG_OBJECT (mux, "setting %u packets into streamheader",
276 g_queue_get_length (&mux->streamheader));
278 while ((buf = GST_BUFFER (g_queue_pop_head (&mux->streamheader)))) {
279 g_value_init (&value, GST_TYPE_BUFFER);
280 gst_value_take_buffer (&value, buf);
281 gst_value_array_append_value (&array, &value);
282 g_value_unset (&value);
285 gst_structure_set_value (structure, "streamheader", &array);
286 gst_aggregator_set_src_caps (GST_AGGREGATOR (mux), caps);
287 g_value_unset (&array);
288 gst_caps_unref (caps);
292 steal_si_section (GstMpegtsSectionType * type, TsMuxSection * section,
295 g_hash_table_insert (mux->si_sections, type, section);
301 gst_base_ts_mux_reset (GstBaseTsMux * mux, gboolean alloc)
304 GstBaseTsMuxClass *klass = GST_BASE_TS_MUX_GET_CLASS (mux);
305 GHashTable *si_sections = NULL;
309 mux->last_flow_ret = GST_FLOW_OK;
311 mux->is_delta = TRUE;
312 mux->is_header = FALSE;
314 mux->streamheader_sent = FALSE;
315 mux->pending_key_unit_ts = GST_CLOCK_TIME_NONE;
316 gst_event_replace (&mux->force_key_unit_event, NULL);
318 if (mux->out_adapter)
319 gst_adapter_clear (mux->out_adapter);
320 mux->output_ts_offset = GST_CLOCK_TIME_NONE;
323 if (mux->tsmux->si_sections)
324 si_sections = g_hash_table_ref (mux->tsmux->si_sections);
326 tsmux_free (mux->tsmux);
331 g_hash_table_destroy (mux->programs);
333 mux->programs = g_hash_table_new (g_direct_hash, g_direct_equal);
335 while ((buf = GST_BUFFER (g_queue_pop_head (&mux->streamheader))))
336 gst_buffer_unref (buf);
338 gst_event_replace (&mux->force_key_unit_event, NULL);
339 gst_buffer_replace (&mux->out_buffer, NULL);
341 GST_OBJECT_LOCK (mux);
343 for (l = GST_ELEMENT (mux)->sinkpads; l; l = l->next) {
344 gst_base_ts_mux_pad_reset (GST_BASE_TS_MUX_PAD (l->data));
347 GST_OBJECT_UNLOCK (mux);
350 g_assert (klass->create_ts_mux);
352 mux->tsmux = klass->create_ts_mux (mux);
354 /* Preserve user-specified sections across resets */
356 g_hash_table_foreach_steal (si_sections, (GHRFunc) steal_si_section,
361 g_hash_table_unref (si_sections);
363 mux->last_scte35_event_seqnum = GST_SEQNUM_INVALID;
370 release_buffer_cb (guint8 * data, void *user_data)
372 stream_data_free ((StreamData *) user_data);
376 gst_base_ts_mux_create_or_update_stream (GstBaseTsMux * mux,
377 GstBaseTsMuxPad * ts_pad, GstCaps * caps)
380 guint st = TSMUX_ST_RESERVED;
382 const GValue *value = NULL;
383 GstBuffer *codec_data = NULL;
384 guint8 opus_channel_config_code = 0;
385 guint16 profile = GST_JPEG2000_PARSE_PROFILE_NONE;
386 guint8 main_level = 0;
387 guint32 max_rate = 0;
388 guint8 color_spec = 0;
389 const gchar *stream_format = NULL;
390 const char *interlace_mode = NULL;
392 GST_DEBUG_OBJECT (ts_pad,
393 "%s stream with PID 0x%04x for caps %" GST_PTR_FORMAT,
394 ts_pad->stream ? "Recreating" : "Creating", ts_pad->pid, caps);
396 s = gst_caps_get_structure (caps, 0);
398 mt = gst_structure_get_name (s);
399 value = gst_structure_get_value (s, "codec_data");
401 codec_data = gst_value_get_buffer (value);
403 g_clear_pointer (&ts_pad->codec_data, gst_buffer_unref);
404 ts_pad->prepare_func = NULL;
406 stream_format = gst_structure_get_string (s, "stream-format");
408 if (strcmp (mt, "video/x-dirac") == 0) {
409 st = TSMUX_ST_VIDEO_DIRAC;
410 } else if (strcmp (mt, "audio/x-ac3") == 0) {
411 st = TSMUX_ST_PS_AUDIO_AC3;
412 } else if (strcmp (mt, "audio/x-dts") == 0) {
413 st = TSMUX_ST_PS_AUDIO_DTS;
414 } else if (strcmp (mt, "audio/x-lpcm") == 0) {
415 st = TSMUX_ST_PS_AUDIO_LPCM;
416 } else if (strcmp (mt, "video/x-h264") == 0) {
417 st = TSMUX_ST_VIDEO_H264;
418 } else if (strcmp (mt, "video/x-h265") == 0) {
419 st = TSMUX_ST_VIDEO_HEVC;
420 } else if (strcmp (mt, "audio/mpeg") == 0) {
423 if (!gst_structure_get_int (s, "mpegversion", &mpegversion)) {
424 GST_ERROR_OBJECT (ts_pad, "caps missing mpegversion");
428 switch (mpegversion) {
430 int mpegaudioversion = 1; /* Assume mpegaudioversion=1 for backwards compatibility */
431 (void) gst_structure_get_int (s, "mpegaudioversion", &mpegaudioversion);
433 if (mpegaudioversion == 1)
434 st = TSMUX_ST_AUDIO_MPEG1;
436 st = TSMUX_ST_AUDIO_MPEG2;
440 /* mpegversion=2 in GStreamer refers to MPEG-2 Part 7 audio, */
442 st = TSMUX_ST_AUDIO_AAC;
444 /* Check the stream format. If raw, make dummy internal codec data from the caps */
445 if (g_strcmp0 (stream_format, "raw") == 0) {
447 gst_base_ts_mux_aac_mpeg2_make_codec_data (mux, caps);
448 ts_pad->prepare_func = gst_base_ts_mux_prepare_aac_mpeg2;
449 if (ts_pad->codec_data == NULL) {
450 GST_ERROR_OBJECT (mux, "Invalid or incomplete caps for MPEG-2 AAC");
458 st = TSMUX_ST_AUDIO_AAC;
460 /* Check the stream format. We need codec_data with RAW streams and mpegversion=4 */
461 if (g_strcmp0 (stream_format, "raw") == 0) {
463 GST_DEBUG_OBJECT (ts_pad,
464 "we have additional codec data (%" G_GSIZE_FORMAT " bytes)",
465 gst_buffer_get_size (codec_data));
466 ts_pad->codec_data = gst_buffer_ref (codec_data);
467 ts_pad->prepare_func = gst_base_ts_mux_prepare_aac_mpeg4;
469 ts_pad->codec_data = NULL;
470 GST_ERROR_OBJECT (mux, "Need codec_data for raw MPEG-4 AAC");
473 } else if (codec_data) {
474 ts_pad->codec_data = gst_buffer_ref (codec_data);
476 ts_pad->codec_data = NULL;
481 GST_WARNING_OBJECT (ts_pad, "unsupported mpegversion %d", mpegversion);
484 } else if (strcmp (mt, "video/mpeg") == 0) {
487 if (!gst_structure_get_int (s, "mpegversion", &mpegversion)) {
488 GST_ERROR_OBJECT (ts_pad, "caps missing mpegversion");
492 switch (mpegversion) {
494 st = TSMUX_ST_VIDEO_MPEG1;
497 st = TSMUX_ST_VIDEO_MPEG2;
500 st = TSMUX_ST_VIDEO_MPEG4;
503 GST_WARNING_OBJECT (ts_pad, "unsupported mpegversion %d", mpegversion);
506 } else if (strcmp (mt, "subpicture/x-dvb") == 0) {
507 st = TSMUX_ST_PS_DVB_SUBPICTURE;
508 } else if (strcmp (mt, "application/x-teletext") == 0) {
509 st = TSMUX_ST_PS_TELETEXT;
510 /* needs a particularly sized layout */
511 ts_pad->prepare_func = gst_base_ts_mux_prepare_teletext;
512 } else if (strcmp (mt, "audio/x-opus") == 0) {
513 guint8 channels, mapping_family, stream_count, coupled_count;
514 guint8 channel_mapping[256];
516 if (!gst_codec_utils_opus_parse_caps (caps, NULL, &channels,
517 &mapping_family, &stream_count, &coupled_count, channel_mapping)) {
518 GST_ERROR_OBJECT (ts_pad, "Incomplete Opus caps");
522 if (channels <= 2 && mapping_family == 0) {
523 opus_channel_config_code = channels;
524 } else if (channels == 2 && mapping_family == 255 && stream_count == 1
525 && coupled_count == 1) {
527 opus_channel_config_code = 0;
528 } else if (channels >= 2 && channels <= 8 && mapping_family == 1) {
529 static const guint8 coupled_stream_counts[9] = {
530 1, 0, 1, 1, 2, 2, 2, 3, 3
532 static const guint8 channel_map_a[8][8] = {
539 {0, 4, 1, 2, 3, 5, 6},
540 {0, 6, 1, 2, 3, 4, 5, 7},
542 static const guint8 channel_map_b[8][8] = {
549 {0, 1, 2, 3, 4, 5, 6},
550 {0, 1, 2, 3, 4, 5, 6, 7},
554 if (stream_count == channels - coupled_stream_counts[channels] &&
555 coupled_count == coupled_stream_counts[channels] &&
556 memcmp (channel_mapping, channel_map_a[channels - 1],
558 opus_channel_config_code = channels;
559 } else if (stream_count == channels - coupled_stream_counts[channels] &&
560 coupled_count == coupled_stream_counts[channels] &&
561 memcmp (channel_mapping, channel_map_b[channels - 1],
563 opus_channel_config_code = channels | 0x80;
565 GST_FIXME_OBJECT (ts_pad, "Opus channel mapping not handled");
570 st = TSMUX_ST_PS_OPUS;
571 ts_pad->prepare_func = gst_base_ts_mux_prepare_opus;
572 } else if (strcmp (mt, "meta/x-klv") == 0) {
573 st = TSMUX_ST_PS_KLV;
574 } else if (strcmp (mt, "image/x-jpc") == 0) {
576 * See this document for more details on standard:
578 * https://www.itu.int/rec/T-REC-H.222.0-201206-S/en
579 * Annex S describes J2K details
580 * Page 104 of this document describes J2k video descriptor
583 const GValue *vProfile = gst_structure_get_value (s, "profile");
584 const GValue *vMainlevel = gst_structure_get_value (s, "main-level");
585 const GValue *vFramerate = gst_structure_get_value (s, "framerate");
586 const GValue *vColorimetry = gst_structure_get_value (s, "colorimetry");
587 j2k_private_data *private_data;
589 /* for now, we relax the condition that profile must exist and equal
590 * GST_JPEG2000_PARSE_PROFILE_BC_SINGLE */
592 profile = g_value_get_int (vProfile);
593 if (profile != GST_JPEG2000_PARSE_PROFILE_BC_SINGLE) {
594 GST_LOG_OBJECT (ts_pad, "Invalid JPEG 2000 profile %d", profile);
595 /* goto not_negotiated; */
598 /* for now, we will relax the condition that the main level must be present */
600 main_level = g_value_get_uint (vMainlevel);
601 if (main_level > 11) {
602 GST_ERROR_OBJECT (ts_pad, "Invalid main level %d", main_level);
605 if (main_level >= 6) {
606 max_rate = 2 ^ (main_level - 6) * 1600 * 1000000;
608 switch (main_level) {
613 max_rate = 200 * 1000000;
616 max_rate = 400 * 1000000;
619 max_rate = 800 * 1000000;
626 /* GST_ERROR_OBJECT (ts_pad, "Missing main level");
627 * goto not_negotiated; */
630 /* We always mux video in J2K-over-MPEG-TS non-interlaced mode */
631 private_data = g_new0 (j2k_private_data, 1);
632 private_data->interlace = FALSE;
633 private_data->den = 0;
634 private_data->num = 0;
635 private_data->max_bitrate = max_rate;
636 private_data->color_spec = 1;
637 /* these two fields are not used, since we always mux as non-interlaced */
638 private_data->Fic = 1;
639 private_data->Fio = 0;
642 if (vFramerate != NULL) {
643 /* Data for ELSM header */
644 private_data->num = gst_value_get_fraction_numerator (vFramerate);
645 private_data->den = gst_value_get_fraction_denominator (vFramerate);
647 /* Get Colorimetry */
649 const char *colorimetry = g_value_get_string (vColorimetry);
650 color_spec = GST_MPEGTS_JPEG2000_COLORSPEC_SRGB; /* RGB as default */
651 if (g_str_equal (colorimetry, GST_VIDEO_COLORIMETRY_BT601)) {
652 color_spec = GST_MPEGTS_JPEG2000_COLORSPEC_REC601;
654 if (g_str_equal (colorimetry, GST_VIDEO_COLORIMETRY_BT709)
655 || g_str_equal (colorimetry, GST_VIDEO_COLORIMETRY_SMPTE240M)) {
656 color_spec = GST_MPEGTS_JPEG2000_COLORSPEC_REC709;
659 private_data->color_spec = color_spec;
661 GST_ERROR_OBJECT (ts_pad, "Colorimetry not present in caps");
662 g_free (private_data);
665 st = TSMUX_ST_VIDEO_JP2K;
666 ts_pad->prepare_func = gst_base_ts_mux_prepare_jpeg2000;
667 ts_pad->prepare_data = private_data;
668 ts_pad->free_func = gst_base_ts_mux_free_jpeg2000;
670 GstBaseTsMuxClass *klass = GST_BASE_TS_MUX_GET_CLASS (mux);
672 if (klass->handle_media_type) {
673 st = klass->handle_media_type (mux, mt, ts_pad);
677 if (st == TSMUX_ST_RESERVED) {
678 GST_ERROR_OBJECT (ts_pad, "Failed to determine stream type");
682 if (ts_pad->stream && st != ts_pad->stream->stream_type) {
683 GST_ELEMENT_ERROR (mux, STREAM, MUX,
684 ("Stream type change from %02x to %02x not supported",
685 ts_pad->stream->stream_type, st), NULL);
689 if (ts_pad->stream == NULL) {
691 tsmux_create_stream (mux->tsmux, st, ts_pad->pid, ts_pad->language);
692 if (ts_pad->stream == NULL)
696 interlace_mode = gst_structure_get_string (s, "interlace-mode");
697 gst_structure_get_int (s, "rate", &ts_pad->stream->audio_sampling);
698 gst_structure_get_int (s, "channels", &ts_pad->stream->audio_channels);
699 gst_structure_get_int (s, "bitrate", &ts_pad->stream->audio_bitrate);
702 gst_structure_get_fraction (s, "framerate", &ts_pad->stream->num,
703 &ts_pad->stream->den);
706 ts_pad->stream->interlace_mode = FALSE;
707 if (interlace_mode) {
708 ts_pad->stream->interlace_mode =
709 g_str_equal (interlace_mode, "interleaved");
712 /* Width and Height */
713 gst_structure_get_int (s, "width", &ts_pad->stream->horizontal_size);
714 gst_structure_get_int (s, "height", &ts_pad->stream->vertical_size);
716 ts_pad->stream->color_spec = color_spec;
717 ts_pad->stream->max_bitrate = max_rate;
718 ts_pad->stream->profile_and_level = profile | main_level;
720 ts_pad->stream->opus_channel_config_code = opus_channel_config_code;
722 tsmux_stream_set_buffer_release_func (ts_pad->stream, release_buffer_cb);
728 return GST_FLOW_NOT_NEGOTIATED;
731 return GST_FLOW_ERROR;
735 is_valid_pmt_pid (guint16 pmt_pid)
737 if (pmt_pid < 0x0010 || pmt_pid > 0x1ffe)
743 gst_base_ts_mux_create_stream (GstBaseTsMux * mux, GstBaseTsMuxPad * ts_pad)
745 GstCaps *caps = gst_pad_get_current_caps (GST_PAD (ts_pad));
749 GST_DEBUG_OBJECT (ts_pad, "Sink pad caps were not set before pushing");
750 return GST_FLOW_NOT_NEGOTIATED;
753 ret = gst_base_ts_mux_create_or_update_stream (mux, ts_pad, caps);
754 gst_caps_unref (caps);
756 if (ret == GST_FLOW_OK) {
757 tsmux_program_add_stream (ts_pad->prog, ts_pad->stream);
764 gst_base_ts_mux_create_pad_stream (GstBaseTsMux * mux, GstPad * pad)
766 GstBaseTsMuxPad *ts_pad = GST_BASE_TS_MUX_PAD (pad);
769 GstFlowReturn ret = GST_FLOW_OK;
771 if (ts_pad->prog_id == -1) {
772 name = GST_PAD_NAME (pad);
773 if (mux->prog_map != NULL && gst_structure_has_field (mux->prog_map, name)) {
775 gboolean ret = gst_structure_get_int (mux->prog_map, name, &idx);
777 GST_ELEMENT_ERROR (mux, STREAM, MUX,
778 ("Reading program map failed. Assuming default"), (NULL));
779 idx = DEFAULT_PROG_ID;
782 GST_DEBUG_OBJECT (mux, "Program number %d associate with pad %s less "
783 "than zero; DEFAULT_PROGRAM = %d is used instead",
784 idx, name, DEFAULT_PROG_ID);
785 idx = DEFAULT_PROG_ID;
787 ts_pad->prog_id = idx;
789 ts_pad->prog_id = DEFAULT_PROG_ID;
794 (TsMuxProgram *) g_hash_table_lookup (mux->programs,
795 GINT_TO_POINTER (ts_pad->prog_id));
796 if (ts_pad->prog == NULL) {
797 ts_pad->prog = tsmux_program_new (mux->tsmux, ts_pad->prog_id);
798 if (ts_pad->prog == NULL)
800 tsmux_set_pmt_interval (ts_pad->prog, mux->pmt_interval);
801 tsmux_program_set_scte35_pid (ts_pad->prog, mux->scte35_pid);
802 tsmux_program_set_scte35_interval (ts_pad->prog, mux->scte35_null_interval);
803 g_hash_table_insert (mux->programs, GINT_TO_POINTER (ts_pad->prog_id),
806 /* Check for user-specified PMT PID */
807 prop_name = g_strdup_printf ("PMT_%d", ts_pad->prog->pgm_number);
808 if (mux->prog_map && gst_structure_has_field (mux->prog_map, prop_name)) {
811 if (gst_structure_get_uint (mux->prog_map, prop_name, &pmt_pid)) {
812 if (is_valid_pmt_pid (pmt_pid)) {
813 GST_DEBUG_OBJECT (mux, "User specified pid=%u as PMT for "
814 "program (prog_id = %d)", pmt_pid, ts_pad->prog->pgm_number);
815 tsmux_program_set_pmt_pid (ts_pad->prog, pmt_pid);
817 GST_ELEMENT_WARNING (mux, LIBRARY, SETTINGS,
818 ("User specified PMT pid %u for program %d is not valid.",
819 pmt_pid, ts_pad->prog->pgm_number), (NULL));
826 if (ts_pad->stream == NULL) {
827 ret = gst_base_ts_mux_create_stream (mux, ts_pad);
828 if (ret != GST_FLOW_OK)
832 if (ts_pad->prog->pcr_stream == NULL) {
833 /* Take the first stream of the program for the PCR */
834 GST_DEBUG_OBJECT (ts_pad,
835 "Use stream (pid=%d) from pad as PCR for program (prog_id = %d)",
836 ts_pad->pid, ts_pad->prog_id);
838 tsmux_program_set_pcr_stream (ts_pad->prog, ts_pad->stream);
841 /* Check for user-specified PCR PID */
842 prop_name = g_strdup_printf ("PCR_%d", ts_pad->prog->pgm_number);
843 if (mux->prog_map && gst_structure_has_field (mux->prog_map, prop_name)) {
844 const gchar *sink_name =
845 gst_structure_get_string (mux->prog_map, prop_name);
847 if (!g_strcmp0 (name, sink_name)) {
848 GST_DEBUG_OBJECT (mux, "User specified stream (pid=%d) as PCR for "
849 "program (prog_id = %d)", ts_pad->pid, ts_pad->prog->pgm_number);
850 tsmux_program_set_pcr_stream (ts_pad->prog, ts_pad->stream);
860 GST_ELEMENT_ERROR (mux, STREAM, MUX,
861 ("Could not create new program"), (NULL));
862 return GST_FLOW_ERROR;
866 GST_ELEMENT_ERROR (mux, STREAM, MUX,
867 ("Could not create handler for stream"), (NULL));
873 gst_base_ts_mux_create_pad_stream_func (GstElement * element, GstPad * pad,
876 GstFlowReturn *ret = user_data;
878 *ret = gst_base_ts_mux_create_pad_stream (GST_BASE_TS_MUX (element), pad);
880 return *ret == GST_FLOW_OK;
884 gst_base_ts_mux_create_streams (GstBaseTsMux * mux)
886 GstFlowReturn ret = GST_FLOW_OK;
888 gst_element_foreach_sink_pad (GST_ELEMENT_CAST (mux),
889 gst_base_ts_mux_create_pad_stream_func, &ret);
895 new_packet_common_init (GstBaseTsMux * mux, GstBuffer * buf, guint8 * data,
898 /* Packets should be at least 188 bytes, but check anyway */
899 g_assert (len >= 2 || !data);
901 if (!mux->streamheader_sent && data) {
902 guint pid = ((data[1] & 0x1f) << 8) | data[2];
903 /* if it's a PAT or a PMT */
904 if (pid == 0x00 || (pid >= TSMUX_START_PMT_PID && pid < TSMUX_START_ES_PID)) {
908 hbuf = gst_buffer_new_and_alloc (len);
909 gst_buffer_fill (hbuf, 0, data, len);
911 hbuf = gst_buffer_copy (buf);
914 "Collecting packet with pid 0x%04x into streamheaders", pid);
916 g_queue_push_tail (&mux->streamheader, hbuf);
917 } else if (!g_queue_is_empty (&mux->streamheader)) {
918 gst_base_ts_mux_set_header_on_caps (mux);
919 mux->streamheader_sent = TRUE;
924 if (mux->is_header) {
925 GST_LOG_OBJECT (mux, "marking as header buffer");
926 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_HEADER);
929 GST_LOG_OBJECT (mux, "marking as delta unit");
930 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
932 GST_DEBUG_OBJECT (mux, "marking as non-delta unit");
933 mux->is_delta = TRUE;
939 gst_base_ts_mux_push_packets (GstBaseTsMux * mux, gboolean force)
941 GstBufferList *buffer_list;
942 gint align = mux->alignment;
943 gint av, packet_size;
945 packet_size = mux->packet_size;
948 align = mux->automatic_alignment;
950 av = gst_adapter_available (mux->out_adapter);
951 GST_LOG_OBJECT (mux, "align %d, av %d", align, av);
956 /* no alignment, just push all available data */
958 buffer_list = gst_adapter_take_buffer_list (mux->out_adapter, av);
959 return gst_aggregator_finish_buffer_list (GST_AGGREGATOR (mux),
963 align *= packet_size;
965 if (!force && align > av)
968 buffer_list = gst_buffer_list_new_sized ((av / align) + 1);
970 GST_LOG_OBJECT (mux, "aligning to %d bytes", align);
971 while (align <= av) {
975 pts = gst_adapter_prev_pts (mux->out_adapter, NULL);
976 buf = gst_adapter_take_buffer (mux->out_adapter, align);
978 GST_BUFFER_PTS (buf) = pts;
980 gst_buffer_list_add (buffer_list, buf);
984 if (av > 0 && force) {
992 GST_LOG_OBJECT (mux, "handling %d leftover bytes", av);
994 pts = gst_adapter_prev_pts (mux->out_adapter, NULL);
995 buf = gst_buffer_new_and_alloc (align);
997 GST_BUFFER_PTS (buf) = pts;
999 gst_buffer_map (buf, &map, GST_MAP_READ);
1002 gst_adapter_copy (mux->out_adapter, data, 0, av);
1003 gst_adapter_clear (mux->out_adapter);
1006 header = GST_READ_UINT32_BE (data - packet_size);
1008 dummy = (map.size - av) / packet_size;
1009 GST_LOG_OBJECT (mux, "adding %d null packets", dummy);
1011 for (; dummy > 0; dummy--) {
1014 if (packet_size > GST_BASE_TS_MUX_NORMAL_PACKET_LENGTH) {
1015 GST_WRITE_UINT32_BE (data, header);
1016 /* simply increase header a bit and never mind too much */
1022 GST_WRITE_UINT8 (data + offset, TSMUX_SYNC_BYTE);
1023 /* null packet PID */
1024 GST_WRITE_UINT16_BE (data + offset + 1, 0x1FFF);
1025 /* no adaptation field exists | continuity counter undefined */
1026 GST_WRITE_UINT8 (data + offset + 3, 0x10);
1028 memset (data + offset + 4, 0, GST_BASE_TS_MUX_NORMAL_PACKET_LENGTH - 4);
1029 data += packet_size;
1032 gst_buffer_unmap (buf, &map);
1033 gst_buffer_list_add (buffer_list, buf);
1036 return gst_aggregator_finish_buffer_list (GST_AGGREGATOR (mux), buffer_list);
1039 static GstFlowReturn
1040 gst_base_ts_mux_collect_packet (GstBaseTsMux * mux, GstBuffer * buf)
1042 GST_LOG_OBJECT (mux, "collecting packet size %" G_GSIZE_FORMAT,
1043 gst_buffer_get_size (buf));
1044 gst_adapter_push (mux->out_adapter, buf);
1050 check_pending_key_unit_event (GstEvent * pending_event, GstSegment * segment,
1051 GstClockTime timestamp, guint flags, GstClockTime pending_key_unit_ts)
1053 GstClockTime running_time, stream_time;
1054 gboolean all_headers;
1056 GstEvent *event = NULL;
1058 g_assert (segment != NULL);
1060 if (pending_event == NULL)
1063 if (GST_CLOCK_TIME_IS_VALID (pending_key_unit_ts) &&
1064 timestamp == GST_CLOCK_TIME_NONE)
1067 running_time = timestamp;
1069 GST_INFO ("now %" GST_TIME_FORMAT " wanted %" GST_TIME_FORMAT,
1070 GST_TIME_ARGS (running_time), GST_TIME_ARGS (pending_key_unit_ts));
1071 if (GST_CLOCK_TIME_IS_VALID (pending_key_unit_ts) &&
1072 running_time < pending_key_unit_ts)
1075 if (flags & GST_BUFFER_FLAG_DELTA_UNIT) {
1076 GST_INFO ("pending force key unit, waiting for keyframe");
1080 stream_time = gst_segment_to_stream_time (segment,
1081 GST_FORMAT_TIME, timestamp);
1083 if (GST_EVENT_TYPE (pending_event) == GST_EVENT_CUSTOM_DOWNSTREAM) {
1084 gst_video_event_parse_downstream_force_key_unit (pending_event,
1085 NULL, NULL, NULL, &all_headers, &count);
1087 gst_video_event_parse_upstream_force_key_unit (pending_event, NULL,
1088 &all_headers, &count);
1092 gst_video_event_new_downstream_force_key_unit (timestamp, stream_time,
1093 running_time, all_headers, count);
1094 gst_event_set_seqnum (event, gst_event_get_seqnum (pending_event));
1100 /* Called when the TsMux has prepared a packet for output. Return FALSE
1103 new_packet_cb (GstBuffer * buf, void *user_data, gint64 new_pcr)
1105 GstBaseTsMux *mux = (GstBaseTsMux *) user_data;
1106 GstAggregator *agg = GST_AGGREGATOR (mux);
1107 GstBaseTsMuxClass *klass = GST_BASE_TS_MUX_GET_CLASS (mux);
1109 GstSegment *agg_segment = &GST_AGGREGATOR_PAD (agg->srcpad)->segment;
1111 g_assert (klass->output_packet);
1113 gst_buffer_map (buf, &map, GST_MAP_READWRITE);
1115 if (!GST_CLOCK_TIME_IS_VALID (GST_BUFFER_PTS (buf))) {
1116 /* tsmux isn't generating timestamps. Use the input times */
1117 GST_BUFFER_PTS (buf) = mux->last_ts;
1120 if (GST_CLOCK_TIME_IS_VALID (GST_BUFFER_PTS (buf))) {
1121 if (!GST_CLOCK_TIME_IS_VALID (mux->output_ts_offset)) {
1122 GstClockTime output_start_time = agg_segment->position;
1123 if (agg_segment->position == -1
1124 || agg_segment->position < agg_segment->start) {
1125 output_start_time = agg_segment->start;
1128 mux->output_ts_offset =
1129 GST_CLOCK_DIFF (GST_BUFFER_PTS (buf), output_start_time);
1131 GST_DEBUG_OBJECT (mux, "New output ts offset %" GST_STIME_FORMAT,
1132 GST_STIME_ARGS (mux->output_ts_offset));
1135 if (GST_CLOCK_TIME_IS_VALID (mux->output_ts_offset)) {
1136 GST_BUFFER_PTS (buf) += mux->output_ts_offset;
1140 if (GST_CLOCK_TIME_IS_VALID (GST_BUFFER_PTS (buf))) {
1141 agg_segment->position = GST_BUFFER_PTS (buf);
1144 /* do common init (flags and streamheaders) */
1145 new_packet_common_init (mux, buf, map.data, map.size);
1147 gst_buffer_unmap (buf, &map);
1149 return klass->output_packet (mux, buf, new_pcr);
1152 /* called when TsMux needs new packet to write into */
1154 alloc_packet_cb (GstBuffer ** buf, void *user_data)
1156 GstBaseTsMux *mux = (GstBaseTsMux *) user_data;
1157 GstBaseTsMuxClass *klass = GST_BASE_TS_MUX_GET_CLASS (mux);
1159 g_assert (klass->allocate_packet);
1161 klass->allocate_packet (mux, buf);
1164 static GstFlowReturn
1165 gst_base_ts_mux_aggregate_buffer (GstBaseTsMux * mux,
1166 GstAggregatorPad * agg_pad, GstBuffer * buf)
1168 GstFlowReturn ret = GST_FLOW_OK;
1169 GstBaseTsMuxPad *best = GST_BASE_TS_MUX_PAD (agg_pad);
1171 gint64 pts = GST_CLOCK_STIME_NONE;
1172 gint64 dts = GST_CLOCK_STIME_NONE;
1173 gboolean delta = TRUE, header = FALSE;
1174 StreamData *stream_data;
1175 GstMpegtsSection *scte_section = NULL;
1177 GST_DEBUG_OBJECT (mux, "Pads collected");
1179 if (buf && gst_buffer_get_size (buf) == 0
1180 && GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_GAP)) {
1181 gst_buffer_unref (buf);
1185 if (G_UNLIKELY (mux->first)) {
1186 ret = gst_base_ts_mux_create_streams (mux);
1187 if (G_UNLIKELY (ret != GST_FLOW_OK)) {
1189 gst_buffer_unref (buf);
1200 gst_base_ts_mux_create_pad_stream (mux, GST_PAD (best));
1201 tsmux_resend_pat (mux->tsmux);
1202 tsmux_resend_si (mux->tsmux);
1204 g_assert_nonnull (prog);
1206 /* output PMT for each program */
1207 for (cur = mux->tsmux->programs; cur; cur = cur->next) {
1208 TsMuxProgram *program = (TsMuxProgram *) cur->data;
1210 tsmux_resend_pmt (program);
1214 g_assert (buf != NULL);
1216 if (best->prepare_func) {
1219 tmp = best->prepare_func (buf, best, mux);
1221 gst_buffer_unref (buf);
1225 if (mux->force_key_unit_event != NULL && best->stream->is_video_stream) {
1228 event = check_pending_key_unit_event (mux->force_key_unit_event,
1229 &agg_pad->segment, GST_BUFFER_PTS (buf),
1230 GST_BUFFER_FLAGS (buf), mux->pending_key_unit_ts);
1232 GstClockTime running_time;
1236 mux->pending_key_unit_ts = GST_CLOCK_TIME_NONE;
1237 gst_event_replace (&mux->force_key_unit_event, NULL);
1239 gst_video_event_parse_downstream_force_key_unit (event,
1240 NULL, NULL, &running_time, NULL, &count);
1242 GST_INFO_OBJECT (mux, "pushing downstream force-key-unit event %d "
1243 "%" GST_TIME_FORMAT " count %d", gst_event_get_seqnum (event),
1244 GST_TIME_ARGS (running_time), count);
1245 gst_pad_push_event (GST_AGGREGATOR_SRC_PAD (mux), event);
1247 /* output PAT, SI tables */
1248 tsmux_resend_pat (mux->tsmux);
1249 tsmux_resend_si (mux->tsmux);
1251 /* output PMT for each program */
1252 for (cur = mux->tsmux->programs; cur; cur = cur->next) {
1253 TsMuxProgram *program = (TsMuxProgram *) cur->data;
1255 tsmux_resend_pmt (program);
1260 if (G_UNLIKELY (prog->pcr_stream == NULL)) {
1261 /* Take the first data stream for the PCR */
1262 GST_DEBUG_OBJECT (best,
1263 "Use stream (pid=%d) from pad as PCR for program (prog_id = %d)",
1264 best->pid, best->prog_id);
1266 /* Set the chosen PCR stream */
1267 tsmux_program_set_pcr_stream (prog, best->stream);
1270 GST_DEBUG_OBJECT (best, "Chose stream for output (PID: 0x%04x)", best->pid);
1272 GST_OBJECT_LOCK (mux);
1273 scte_section = mux->pending_scte35_section;
1274 mux->pending_scte35_section = NULL;
1275 GST_OBJECT_UNLOCK (mux);
1276 if (G_UNLIKELY (scte_section)) {
1277 GST_DEBUG_OBJECT (mux, "Sending pending SCTE section");
1278 if (!tsmux_send_section (mux->tsmux, scte_section))
1279 GST_ERROR_OBJECT (mux, "Error sending SCTE section !");
1282 if (GST_CLOCK_TIME_IS_VALID (GST_BUFFER_PTS (buf))) {
1283 pts = GSTTIME_TO_MPEGTIME (GST_BUFFER_PTS (buf));
1284 GST_DEBUG_OBJECT (mux, "Buffer has PTS %" GST_TIME_FORMAT " pts %"
1285 G_GINT64_FORMAT "%s", GST_TIME_ARGS (GST_BUFFER_PTS (buf)), pts,
1286 !GST_BUFFER_FLAG_IS_SET (buf,
1287 GST_BUFFER_FLAG_DELTA_UNIT) ? " (keyframe)" : "");
1290 if (GST_CLOCK_STIME_IS_VALID (best->dts)) {
1291 dts = GSTTIME_TO_MPEGTIME (best->dts);
1292 GST_DEBUG_OBJECT (mux, "Buffer has DTS %" GST_STIME_FORMAT " dts %"
1293 G_GINT64_FORMAT, GST_STIME_ARGS (best->dts), dts);
1296 /* should not have a DTS without PTS */
1297 if (!GST_CLOCK_STIME_IS_VALID (pts) && GST_CLOCK_STIME_IS_VALID (dts)) {
1298 GST_DEBUG_OBJECT (mux, "using DTS for unknown PTS");
1302 if (best->stream->is_video_stream) {
1303 delta = GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
1304 header = GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_HEADER);
1307 if (best->stream->is_meta && gst_buffer_get_size (buf) > (G_MAXUINT16 - 3)) {
1308 GST_WARNING_OBJECT (mux, "KLV meta unit too big, splitting not supported");
1310 gst_buffer_unref (buf);
1314 GST_DEBUG_OBJECT (mux, "delta: %d", delta);
1316 stream_data = stream_data_new (buf);
1317 tsmux_stream_add_data (best->stream, stream_data->map_info.data,
1318 stream_data->map_info.size, stream_data, pts, dts, !delta);
1320 /* outgoing ts follows ts of PCR program stream */
1321 if (prog->pcr_stream == best->stream) {
1322 /* prefer DTS if present for PCR as it should be monotone */
1324 GST_CLOCK_TIME_IS_VALID (GST_BUFFER_DTS (buf)) ?
1325 GST_BUFFER_DTS (buf) : GST_BUFFER_PTS (buf);
1328 mux->is_delta = delta;
1329 mux->is_header = header;
1330 while (tsmux_stream_bytes_in_buffer (best->stream) > 0) {
1331 if (!tsmux_write_stream_packet (mux->tsmux, best->stream)) {
1332 /* Failed writing data for some reason. Set appropriate error */
1333 GST_DEBUG_OBJECT (mux, "Failed to write data packet");
1334 GST_ELEMENT_ERROR (mux, STREAM, MUX,
1335 ("Failed writing output data to stream %04x", best->stream->id),
1340 /* flush packet cache */
1341 return gst_base_ts_mux_push_packets (mux, FALSE);
1346 return mux->last_flow_ret;
1350 /* GstElement implementation */
1352 gst_base_ts_mux_has_pad_with_pid (GstBaseTsMux * mux, guint16 pid)
1355 gboolean res = FALSE;
1357 GST_OBJECT_LOCK (mux);
1359 for (l = GST_ELEMENT_CAST (mux)->sinkpads; l; l = l->next) {
1360 GstBaseTsMuxPad *tpad = GST_BASE_TS_MUX_PAD (l->data);
1362 if (tpad->pid == pid) {
1368 GST_OBJECT_UNLOCK (mux);
1373 gst_base_ts_mux_request_new_pad (GstElement * element, GstPadTemplate * templ,
1374 const gchar * name, const GstCaps * caps)
1376 GstBaseTsMux *mux = GST_BASE_TS_MUX (element);
1379 gchar *free_name = NULL;
1381 if (name != NULL && sscanf (name, "sink_%d", &pid) == 1) {
1382 if (tsmux_find_stream (mux->tsmux, pid))
1384 /* Make sure we don't use reserved PID.
1385 * FIXME : This should be extended to other variants (ex: ATSC) reserved PID */
1386 if (pid < TSMUX_START_ES_PID)
1387 goto invalid_stream_pid;
1390 pid = tsmux_get_new_pid (mux->tsmux);
1391 } while (gst_base_ts_mux_has_pad_with_pid (mux, pid));
1393 /* Name the pad correctly after the selected pid */
1394 name = free_name = g_strdup_printf ("sink_%d", pid);
1398 GST_ELEMENT_CLASS (parent_class)->request_new_pad (element,
1401 gst_base_ts_mux_pad_reset (GST_BASE_TS_MUX_PAD (pad));
1402 GST_BASE_TS_MUX_PAD (pad)->pid = pid;
1411 GST_ELEMENT_ERROR (element, STREAM, MUX, ("Duplicate PID requested"),
1418 GST_ELEMENT_ERROR (element, STREAM, MUX,
1419 ("Invalid Elementary stream PID (0x%02u < 0x40)", pid), (NULL));
1425 gst_base_ts_mux_release_pad (GstElement * element, GstPad * pad)
1427 GstBaseTsMux *mux = GST_BASE_TS_MUX (element);
1431 GstBaseTsMuxPad *ts_pad = GST_BASE_TS_MUX_PAD (pad);
1432 gint pid = ts_pad->pid;
1435 if (ts_pad->prog->pcr_stream == ts_pad->stream) {
1436 tsmux_program_set_pcr_stream (ts_pad->prog, NULL);
1438 if (tsmux_remove_stream (mux->tsmux, pid, ts_pad->prog)) {
1439 g_hash_table_remove (mux->programs, GINT_TO_POINTER (ts_pad->prog_id));
1443 tsmux_resend_pat (mux->tsmux);
1444 tsmux_resend_si (mux->tsmux);
1446 /* output PMT for each program */
1447 for (cur = mux->tsmux->programs; cur; cur = cur->next) {
1448 TsMuxProgram *program = (TsMuxProgram *) cur->data;
1450 tsmux_resend_pmt (program);
1454 GST_ELEMENT_CLASS (parent_class)->release_pad (element, pad);
1457 /* GstAggregator implementation */
1460 request_keyframe (GstBaseTsMux * mux, GstClockTime running_time)
1463 GST_OBJECT_LOCK (mux);
1465 for (l = GST_ELEMENT_CAST (mux)->sinkpads; l; l = l->next) {
1466 gst_pad_push_event (GST_PAD (l->data),
1467 gst_video_event_new_upstream_force_key_unit (running_time, TRUE, 0));
1470 GST_OBJECT_UNLOCK (mux);
1473 static const guint32 crc_tab[256] = {
1474 0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc, 0x17c56b6b,
1475 0x1a864db2, 0x1e475005, 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61,
1476 0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd, 0x4c11db70, 0x48d0c6c7,
1477 0x4593e01e, 0x4152fda9, 0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75,
1478 0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011, 0x791d4014, 0x7ddc5da3,
1479 0x709f7b7a, 0x745e66cd, 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039,
1480 0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, 0xbe2b5b58, 0xbaea46ef,
1481 0xb7a96036, 0xb3687d81, 0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d,
1482 0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49, 0xc7361b4c, 0xc3f706fb,
1483 0xceb42022, 0xca753d95, 0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1,
1484 0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, 0x34867077, 0x30476dc0,
1485 0x3d044b19, 0x39c556ae, 0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072,
1486 0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16, 0x018aeb13, 0x054bf6a4,
1487 0x0808d07d, 0x0cc9cdca, 0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde,
1488 0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02, 0x5e9f46bf, 0x5a5e5b08,
1489 0x571d7dd1, 0x53dc6066, 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba,
1490 0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, 0xbfa1b04b, 0xbb60adfc,
1491 0xb6238b25, 0xb2e29692, 0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6,
1492 0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a, 0xe0b41de7, 0xe4750050,
1493 0xe9362689, 0xedf73b3e, 0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2,
1494 0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683, 0xd1799b34,
1495 0xdc3abded, 0xd8fba05a, 0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637,
1496 0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb, 0x4f040d56, 0x4bc510e1,
1497 0x46863638, 0x42472b8f, 0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53,
1498 0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47, 0x36194d42, 0x32d850f5,
1499 0x3f9b762c, 0x3b5a6b9b, 0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff,
1500 0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, 0xf12f560e, 0xf5ee4bb9,
1501 0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b,
1502 0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f, 0xc423cd6a, 0xc0e2d0dd,
1503 0xcda1f604, 0xc960ebb3, 0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7,
1504 0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, 0x9b3660c6, 0x9ff77d71,
1505 0x92b45ba8, 0x9675461f, 0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3,
1506 0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640, 0x4e8ee645, 0x4a4ffbf2,
1507 0x470cdd2b, 0x43cdc09c, 0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8,
1508 0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24, 0x119b4be9, 0x155a565e,
1509 0x18197087, 0x1cd86d30, 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec,
1510 0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, 0x2497d08d, 0x2056cd3a,
1511 0x2d15ebe3, 0x29d4f654, 0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0,
1512 0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c, 0xe3a1cbc1, 0xe760d676,
1513 0xea23f0af, 0xeee2ed18, 0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4,
1514 0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0, 0x9abc8bd5, 0x9e7d9662,
1515 0x933eb0bb, 0x97ffad0c, 0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668,
1516 0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4
1520 _calc_crc32 (const guint8 * data, guint datalen)
1523 guint32 crc = 0xffffffff;
1525 for (i = 0; i < datalen; i++) {
1526 crc = (crc << 8) ^ crc_tab[((crc >> 24) ^ *data++) & 0xff];
1531 #define MPEGTIME_TO_GSTTIME(t) ((t) * (guint64)100000 / 9)
1533 static GstMpegtsSCTESpliceEvent *
1534 copy_splice (GstMpegtsSCTESpliceEvent * splice)
1536 return g_boxed_copy (GST_TYPE_MPEGTS_SCTE_SPLICE_EVENT, splice);
1540 free_splice (GstMpegtsSCTESpliceEvent * splice)
1542 g_boxed_free (GST_TYPE_MPEGTS_SCTE_SPLICE_EVENT, splice);
1545 /* FIXME: get rid of this when depending on glib >= 2.62 */
1548 _g_ptr_array_copy (GPtrArray * array,
1549 GCopyFunc func, GFreeFunc free_func, gpointer user_data)
1551 GPtrArray *new_array;
1553 g_return_val_if_fail (array != NULL, NULL);
1555 new_array = g_ptr_array_new_with_free_func (free_func);
1557 g_ptr_array_set_size (new_array, array->len);
1562 for (i = 0; i < array->len; i++)
1563 new_array->pdata[i] = func (array->pdata[i], user_data);
1564 } else if (array->len > 0) {
1565 memcpy (new_array->pdata, array->pdata,
1566 array->len * sizeof (*array->pdata));
1569 new_array->len = array->len;
1574 static GstMpegtsSCTESIT *
1575 deep_copy_sit (const GstMpegtsSCTESIT * sit)
1577 GstMpegtsSCTESIT *sit_copy = g_boxed_copy (GST_TYPE_MPEGTS_SCTE_SIT, sit);
1578 GPtrArray *splices_copy =
1579 _g_ptr_array_copy (sit_copy->splices, (GCopyFunc) copy_splice,
1580 (GFreeFunc) free_splice, NULL);
1582 g_ptr_array_unref (sit_copy->splices);
1583 sit_copy->splices = splices_copy;
1588 /* Takes ownership of @section.
1590 * This function is a bit complex because the SCTE sections can
1591 * have various origins:
1593 * * Sections created by the application with the gst_mpegts_scte_*_new()
1594 * API. The splice times / durations contained by these are expressed
1595 * in the GStreamer running time domain, and must be translated to
1596 * our local PES time domain. In this case, we will packetize the section
1599 * * Sections passed through from tsdemux: this case is complicated as
1600 * splice times in the incoming stream may be encrypted, with pts_adjustment
1601 * being the only timing field guaranteed *not* to be encrypted. In this
1602 * case, the original binary data (section->data) will be reinjected as is
1603 * in the output stream, with pts_adjustment adjusted. tsdemux provides us
1604 * with the pts_offset it introduces, the difference between the original
1605 * PES PTSs and the running times it outputs.
1607 * Additionally, in either of these cases when the splice times aren't encrypted
1608 * we want to make use of those to request keyframes. For the passthrough case,
1609 * as the splice times are left untouched tsdemux provides us with the running
1610 * times the section originally referred to. We cannot calculate it locally
1611 * because we would need to have access to the information that the timestamps
1612 * in the original PES domain have wrapped around, and how many times they have
1613 * done so. While we could probably make educated guesses, tsdemux (more specifically
1614 * mpegtspacketizer) already keeps track of that, and it seemed more logical to
1615 * perform the calculation there and forward it alongside the downstream events.
1617 * Finally, while we can't request keyframes at splice points in the encrypted
1618 * case, if the input stream was compliant in that regard and no reencoding took
1619 * place the splice times will still match with valid splice points, it is up
1620 * to the application to ensure that that is the case.
1623 handle_scte35_section (GstBaseTsMux * mux, GstEvent * event,
1624 GstMpegtsSection * section, guint64 mpeg_pts_offset,
1625 GstStructure * rtime_map)
1627 GstMpegtsSCTESIT *sit;
1629 gboolean forward = TRUE;
1631 guint8 *section_data;
1633 gboolean translate = FALSE;
1635 sit = (GstMpegtsSCTESIT *) gst_mpegts_section_get_scte_sit (section);
1637 /* When the application injects manually constructed splice events,
1638 * their time domain is the GStreamer running time, we receive them
1639 * unpacketized and translate the fields in the SIT to local PTS.
1641 * We make a copy of the SIT in order to make sure we can rewrite it.
1643 if (sit->is_running_time) {
1644 sit = deep_copy_sit (sit);
1648 switch (sit->splice_command_type) {
1649 case GST_MTS_SCTE_SPLICE_COMMAND_NULL:
1650 /* We implement heartbeating ourselves */
1653 case GST_MTS_SCTE_SPLICE_COMMAND_SCHEDULE:
1654 /* No need to request keyframes at this point, splice_insert
1655 * messages will precede the future splice points and we
1656 * can request keyframes then. Only translate if needed.
1659 for (i = 0; i < sit->splices->len; i++) {
1660 GstMpegtsSCTESpliceEvent *sevent =
1661 g_ptr_array_index (sit->splices, i);
1663 if (sevent->program_splice_time_specified)
1664 sevent->program_splice_time =
1665 GSTTIME_TO_MPEGTIME (sevent->program_splice_time) +
1668 if (sevent->duration_flag)
1669 sevent->break_duration =
1670 GSTTIME_TO_MPEGTIME (sevent->break_duration);
1674 case GST_MTS_SCTE_SPLICE_COMMAND_INSERT:
1675 /* We want keyframes at splice points */
1676 if (sit->fully_parsed && (rtime_map || translate)) {
1678 for (i = 0; i < sit->splices->len; i++) {
1679 guint64 running_time = GST_CLOCK_TIME_NONE;
1681 GstMpegtsSCTESpliceEvent *sevent =
1682 g_ptr_array_index (sit->splices, i);
1683 if (sevent->program_splice_time_specified) {
1685 gchar *field_name = g_strdup_printf ("event-%u-splice-time",
1686 sevent->splice_event_id);
1687 if (gst_structure_get_uint64 (rtime_map, field_name,
1689 GST_DEBUG_OBJECT (mux,
1690 "Requesting keyframe for splice point at %" GST_TIME_FORMAT,
1691 GST_TIME_ARGS (running_time));
1692 request_keyframe (mux, running_time);
1694 g_free (field_name);
1696 g_assert (translate == TRUE);
1697 running_time = sevent->program_splice_time;
1698 GST_DEBUG_OBJECT (mux,
1699 "Requesting keyframe for splice point at %" GST_TIME_FORMAT,
1700 GST_TIME_ARGS (running_time));
1701 request_keyframe (mux, running_time);
1702 sevent->program_splice_time =
1703 GSTTIME_TO_MPEGTIME (running_time) + TS_MUX_CLOCK_BASE;
1706 GST_DEBUG_OBJECT (mux,
1707 "Requesting keyframe for immediate splice point");
1708 request_keyframe (mux, GST_CLOCK_TIME_NONE);
1711 if (sevent->duration_flag) {
1713 sevent->break_duration =
1714 GSTTIME_TO_MPEGTIME (sevent->break_duration);
1717 /* Even if auto_return is FALSE, when a break_duration is specified it
1718 * is intended as a redundancy mechanism in case the follow-up
1719 * splice insert goes missing.
1721 * Schedule a keyframe at that point (if we can calculate its position
1724 if (GST_CLOCK_TIME_IS_VALID (running_time)) {
1725 running_time += MPEGTIME_TO_GSTTIME (sevent->break_duration);
1726 GST_DEBUG_OBJECT (mux,
1727 "Requesting keyframe for end of break at %" GST_TIME_FORMAT,
1728 GST_TIME_ARGS (running_time));
1729 request_keyframe (mux, running_time);
1735 case GST_MTS_SCTE_SPLICE_COMMAND_TIME:{
1736 /* Adjust timestamps and potentially request keyframes */
1737 gboolean do_request_keyframes = FALSE;
1739 /* TODO: we can probably be a little more fine-tuned about determining
1740 * whether a keyframe is actually needed, but this at least takes care
1741 * of the requirement in 10.3.4 that a keyframe should not be created
1742 * when the signal contains only a time_descriptor.
1744 if (sit->fully_parsed && (rtime_map || translate)) {
1745 for (i = 0; i < sit->descriptors->len; i++) {
1746 GstMpegtsDescriptor *descriptor =
1747 g_ptr_array_index (sit->descriptors, i);
1749 switch (descriptor->tag) {
1750 case GST_MTS_SCTE_DESC_AVAIL:
1751 case GST_MTS_SCTE_DESC_DTMF:
1752 case GST_MTS_SCTE_DESC_SEGMENTATION:
1753 do_request_keyframes = TRUE;
1755 case GST_MTS_SCTE_DESC_TIME:
1756 case GST_MTS_SCTE_DESC_AUDIO:
1760 if (do_request_keyframes)
1764 if (sit->splice_time_specified) {
1765 GstClockTime running_time = GST_CLOCK_TIME_NONE;
1768 if (do_request_keyframes
1769 && gst_structure_get_uint64 (rtime_map, "splice-time",
1771 GST_DEBUG_OBJECT (mux,
1772 "Requesting keyframe for time signal at %" GST_TIME_FORMAT,
1773 GST_TIME_ARGS (running_time));
1774 request_keyframe (mux, running_time);
1777 g_assert (translate);
1778 running_time = sit->splice_time;
1780 GSTTIME_TO_MPEGTIME (running_time) + TS_MUX_CLOCK_BASE;
1781 if (do_request_keyframes) {
1782 GST_DEBUG_OBJECT (mux,
1783 "Requesting keyframe for time signal at %" GST_TIME_FORMAT,
1784 GST_TIME_ARGS (running_time));
1785 request_keyframe (mux, running_time);
1788 } else if (do_request_keyframes) {
1789 GST_DEBUG_OBJECT (mux,
1790 "Requesting keyframe for immediate time signal");
1791 request_keyframe (mux, GST_CLOCK_TIME_NONE);
1796 case GST_MTS_SCTE_SPLICE_COMMAND_BANDWIDTH:
1797 case GST_MTS_SCTE_SPLICE_COMMAND_PRIVATE:
1798 /* Just let those go through untouched, none of our business */
1805 gst_mpegts_section_unref (section);
1810 g_assert (section->data);
1811 /* Calculate the final adjustment, as a sum of:
1812 * - The adjustment in the original packet
1813 * - The offset introduced between the original local PTS
1814 * and the GStreamer PTS output by tsdemux
1815 * - Our own 1-hour offset
1817 pts_adjust = sit->pts_adjustment + mpeg_pts_offset + TS_MUX_CLOCK_BASE;
1819 /* Account for offsets potentially introduced between the demuxer and us */
1821 GSTTIME_TO_MPEGTIME (gst_event_get_running_time_offset (event));
1823 pts_adjust &= 0x1ffffffff;
1824 section_data = g_memdup2 (section->data, section->section_length);
1825 section_data[4] |= pts_adjust >> 32;
1826 section_data[5] = pts_adjust >> 24;
1827 section_data[6] = pts_adjust >> 16;
1828 section_data[7] = pts_adjust >> 8;
1829 section_data[8] = pts_adjust;
1831 /* Now rewrite our checksum */
1832 crc = section_data + section->section_length - 4;
1833 GST_WRITE_UINT32_BE (crc, _calc_crc32 (section_data, crc - section_data));
1835 GST_OBJECT_LOCK (mux);
1836 GST_DEBUG_OBJECT (mux, "Storing SCTE section");
1837 if (mux->pending_scte35_section)
1838 gst_mpegts_section_unref (mux->pending_scte35_section);
1839 mux->pending_scte35_section =
1840 gst_mpegts_section_new (mux->scte35_pid, section_data,
1841 section->section_length);
1842 GST_OBJECT_UNLOCK (mux);
1844 gst_mpegts_section_unref (section);
1846 GST_OBJECT_LOCK (mux);
1847 GST_DEBUG_OBJECT (mux, "Storing SCTE section");
1848 gst_mpegts_section_unref (section);
1849 if (mux->pending_scte35_section)
1850 gst_mpegts_section_unref (mux->pending_scte35_section);
1851 mux->pending_scte35_section =
1852 gst_mpegts_section_from_scte_sit (sit, mux->scte35_pid);;
1853 GST_OBJECT_UNLOCK (mux);
1858 gst_base_ts_mux_send_event (GstElement * element, GstEvent * event)
1860 GstMpegtsSection *section;
1861 GstBaseTsMux *mux = GST_BASE_TS_MUX (element);
1863 section = gst_event_parse_mpegts_section (event);
1866 GST_DEBUG ("Received event with mpegts section");
1868 if (section->section_type == GST_MPEGTS_SECTION_SCTE_SIT) {
1869 handle_scte35_section (mux, event, section, 0, NULL);
1871 /* TODO: Check that the section type is supported */
1872 tsmux_add_mpegts_si_section (mux->tsmux, section);
1875 gst_event_unref (event);
1880 return GST_ELEMENT_CLASS (parent_class)->send_event (element, event);
1883 /* GstAggregator implementation */
1886 gst_base_ts_mux_sink_event (GstAggregator * agg, GstAggregatorPad * agg_pad,
1889 GstAggregatorClass *agg_class = GST_AGGREGATOR_CLASS (parent_class);
1890 GstBaseTsMux *mux = GST_BASE_TS_MUX (agg);
1891 GstBaseTsMuxPad *ts_pad = GST_BASE_TS_MUX_PAD (agg_pad);
1892 gboolean res = FALSE;
1893 gboolean forward = TRUE;
1895 switch (GST_EVENT_TYPE (event)) {
1896 case GST_EVENT_CAPS:
1902 if (ts_pad->stream == NULL)
1907 gst_event_parse_caps (event, &caps);
1908 if (!caps || !gst_caps_is_fixed (caps))
1911 ret = gst_base_ts_mux_create_or_update_stream (mux, ts_pad, caps);
1912 if (ret != GST_FLOW_OK)
1915 mux->tsmux->pat_changed = TRUE;
1916 mux->tsmux->si_changed = TRUE;
1917 tsmux_resend_pat (mux->tsmux);
1918 tsmux_resend_si (mux->tsmux);
1920 /* output PMT for each program */
1921 for (cur = mux->tsmux->programs; cur; cur = cur->next) {
1922 TsMuxProgram *program = (TsMuxProgram *) cur->data;
1924 program->pmt_changed = TRUE;
1925 tsmux_resend_pmt (program);
1931 case GST_EVENT_CUSTOM_DOWNSTREAM:
1933 GstClockTime timestamp, stream_time, running_time;
1934 gboolean all_headers;
1936 const GstStructure *s;
1938 s = gst_event_get_structure (event);
1940 if (gst_structure_has_name (s, "scte-sit") && mux->scte35_pid != 0) {
1942 /* When operating downstream of tsdemux, tsdemux will send out events
1943 * on all its source pads for each splice table it encounters. If we
1944 * are remuxing multiple streams it has demuxed, this means we could
1945 * unnecessarily repeat the same table multiple times, we avoid that
1946 * by deduplicating thanks to the event sequm
1948 if (gst_event_get_seqnum (event) != mux->last_scte35_event_seqnum) {
1949 GstMpegtsSection *section;
1951 gst_structure_get (s, "section", GST_TYPE_MPEGTS_SECTION, §ion,
1954 guint64 mpeg_pts_offset = 0;
1955 GstStructure *rtime_map = NULL;
1957 gst_structure_get (s, "running-time-map", GST_TYPE_STRUCTURE,
1959 gst_structure_get_uint64 (s, "mpeg-pts-offset", &mpeg_pts_offset);
1961 handle_scte35_section (mux, event, section, mpeg_pts_offset,
1964 gst_structure_free (rtime_map);
1965 mux->last_scte35_event_seqnum = gst_event_get_seqnum (event);
1967 GST_WARNING_OBJECT (ts_pad,
1968 "Ignoring scte-sit event without a section");
1971 GST_DEBUG_OBJECT (ts_pad, "Ignoring duplicate scte-sit event");
1978 if (!gst_video_event_is_force_key_unit (event))
1984 gst_video_event_parse_downstream_force_key_unit (event,
1985 ×tamp, &stream_time, &running_time, &all_headers, &count);
1986 GST_INFO_OBJECT (ts_pad, "have downstream force-key-unit event, "
1987 "seqnum %d, running-time %" GST_TIME_FORMAT " count %d",
1988 gst_event_get_seqnum (event), GST_TIME_ARGS (running_time), count);
1990 if (mux->force_key_unit_event != NULL) {
1991 GST_INFO_OBJECT (mux, "skipping downstream force key unit event "
1992 "as an upstream force key unit is already queued");
1999 mux->pending_key_unit_ts = running_time;
2000 gst_event_replace (&mux->force_key_unit_event, event);
2003 case GST_EVENT_TAG:{
2007 GST_DEBUG_OBJECT (mux, "received tag event");
2008 gst_event_parse_tag (event, &list);
2010 /* Matroska wants ISO 639-2B code, taglist most likely contains 639-1 */
2011 if (gst_tag_list_get_string (list, GST_TAG_LANGUAGE_CODE, &lang)) {
2012 const gchar *lang_code;
2014 lang_code = gst_tag_get_language_code_iso_639_2B (lang);
2016 GST_DEBUG_OBJECT (ts_pad, "Setting language to '%s'", lang_code);
2018 g_free (ts_pad->language);
2019 ts_pad->language = g_strdup (lang_code);
2021 GST_WARNING_OBJECT (ts_pad, "Did not get language code for '%s'",
2027 /* handled this, don't want collectpads to forward it downstream */
2029 forward = gst_tag_list_get_scope (list) == GST_TAG_SCOPE_GLOBAL;
2032 case GST_EVENT_STREAM_START:{
2033 GstStreamFlags flags;
2035 gst_event_parse_stream_flags (event, &flags);
2037 /* Don't wait for data on sparse inputs like metadata streams */
2039 if ((flags & GST_STREAM_FLAG_SPARSE)) {
2040 GST_COLLECT_PADS_STATE_UNSET (data, GST_COLLECT_PADS_STATE_LOCKED);
2041 gst_collect_pads_set_waiting (pads, data, FALSE);
2042 GST_COLLECT_PADS_STATE_SET (data, GST_COLLECT_PADS_STATE_LOCKED);
2053 gst_event_unref (event);
2055 res = agg_class->sink_event (agg, agg_pad, event);
2061 gst_base_ts_mux_src_event (GstAggregator * agg, GstEvent * event)
2063 GstAggregatorClass *agg_class = GST_AGGREGATOR_CLASS (parent_class);
2064 GstBaseTsMux *mux = GST_BASE_TS_MUX (agg);
2065 gboolean res = TRUE, forward = TRUE;
2067 switch (GST_EVENT_TYPE (event)) {
2068 case GST_EVENT_CUSTOM_UPSTREAM:
2071 GValue sinkpad_value = G_VALUE_INIT;
2072 GstClockTime running_time;
2073 gboolean all_headers, done = FALSE, res = FALSE;
2076 if (!gst_video_event_is_force_key_unit (event))
2081 gst_video_event_parse_upstream_force_key_unit (event,
2082 &running_time, &all_headers, &count);
2084 GST_INFO_OBJECT (mux, "received upstream force-key-unit event, "
2085 "seqnum %d running_time %" GST_TIME_FORMAT " all_headers %d count %d",
2086 gst_event_get_seqnum (event), GST_TIME_ARGS (running_time),
2087 all_headers, count);
2092 mux->pending_key_unit_ts = running_time;
2093 gst_event_replace (&mux->force_key_unit_event, event);
2095 iter = gst_element_iterate_sink_pads (GST_ELEMENT_CAST (mux));
2098 switch (gst_iterator_next (iter, &sinkpad_value)) {
2099 case GST_ITERATOR_OK:{
2100 GstPad *sinkpad = g_value_get_object (&sinkpad_value);
2103 GST_INFO_OBJECT (GST_AGGREGATOR_SRC_PAD (agg), "forwarding");
2104 tmp = gst_pad_push_event (sinkpad, gst_event_ref (event));
2105 GST_INFO_OBJECT (mux, "result %d", tmp);
2106 /* succeed if at least one pad succeeds */
2110 case GST_ITERATOR_DONE:
2113 case GST_ITERATOR_RESYNC:
2114 gst_iterator_resync (iter);
2116 case GST_ITERATOR_ERROR:
2117 g_assert_not_reached ();
2120 g_value_reset (&sinkpad_value);
2122 g_value_unset (&sinkpad_value);
2123 gst_iterator_free (iter);
2131 res = agg_class->src_event (agg, event);
2133 gst_event_unref (event);
2139 gst_base_ts_mux_clip (GstAggregator * agg,
2140 GstAggregatorPad * agg_pad, GstBuffer * buf)
2142 GstBaseTsMuxPad *pad = GST_BASE_TS_MUX_PAD (agg_pad);
2149 time = GST_BUFFER_PTS (buf);
2151 /* invalid left alone and passed */
2152 if (G_LIKELY (GST_CLOCK_TIME_IS_VALID (time))) {
2154 gst_segment_to_running_time (&agg_pad->segment, GST_FORMAT_TIME, time);
2155 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (time))) {
2156 GST_DEBUG_OBJECT (pad, "clipping buffer on pad outside segment");
2157 gst_buffer_unref (buf);
2161 GST_LOG_OBJECT (pad, "buffer pts %" GST_TIME_FORMAT " -> %"
2162 GST_TIME_FORMAT " running time",
2163 GST_TIME_ARGS (GST_BUFFER_PTS (buf)), GST_TIME_ARGS (time));
2164 buf = ret = gst_buffer_make_writable (buf);
2165 GST_BUFFER_PTS (ret) = time;
2170 time = GST_BUFFER_DTS (buf);
2172 /* invalid left alone and passed */
2173 if (G_LIKELY (GST_CLOCK_TIME_IS_VALID (time))) {
2177 sign = gst_segment_to_running_time_full (&agg_pad->segment, GST_FORMAT_TIME,
2181 dts = (gint64) time;
2183 dts = -((gint64) time);
2185 GST_LOG_OBJECT (pad, "buffer dts %" GST_TIME_FORMAT " -> %"
2186 GST_STIME_FORMAT " running time", GST_TIME_ARGS (GST_BUFFER_DTS (buf)),
2187 GST_STIME_ARGS (dts));
2189 if (GST_CLOCK_STIME_IS_VALID (pad->dts) && dts < pad->dts) {
2190 /* Ignore DTS going backward */
2191 GST_WARNING_OBJECT (pad, "ignoring DTS going backward");
2195 ret = gst_buffer_make_writable (buf);
2197 GST_BUFFER_DTS (ret) = time;
2199 GST_BUFFER_DTS (ret) = GST_CLOCK_TIME_NONE;
2203 pad->dts = GST_CLOCK_STIME_NONE;
2210 static GstFlowReturn
2211 gst_base_ts_mux_update_src_caps (GstAggregator * agg, GstCaps * caps,
2214 GstBaseTsMux *mux = GST_BASE_TS_MUX (agg);
2217 *ret = gst_caps_copy (caps);
2218 s = gst_caps_get_structure (*ret, 0);
2219 gst_structure_set (s, "packetsize", G_TYPE_INT, mux->packet_size, NULL);
2224 static GstBaseTsMuxPad *
2225 gst_base_ts_mux_find_best_pad (GstAggregator * aggregator)
2227 GstBaseTsMuxPad *best = NULL;
2228 GstClockTime best_ts = GST_CLOCK_TIME_NONE;
2231 GST_OBJECT_LOCK (aggregator);
2233 for (l = GST_ELEMENT_CAST (aggregator)->sinkpads; l; l = l->next) {
2234 GstBaseTsMuxPad *tpad = GST_BASE_TS_MUX_PAD (l->data);
2235 GstAggregatorPad *apad = GST_AGGREGATOR_PAD_CAST (tpad);
2238 buffer = gst_aggregator_pad_peek_buffer (apad);
2241 if (best_ts == GST_CLOCK_TIME_NONE) {
2243 best_ts = GST_BUFFER_DTS_OR_PTS (buffer);
2244 } else if (GST_BUFFER_DTS_OR_PTS (buffer) != GST_CLOCK_TIME_NONE) {
2245 GstClockTime t = GST_BUFFER_DTS_OR_PTS (buffer);
2251 gst_buffer_unref (buffer);
2255 gst_object_ref (best);
2257 GST_OBJECT_UNLOCK (aggregator);
2259 GST_DEBUG_OBJECT (aggregator,
2260 "Best pad found with %" GST_TIME_FORMAT ": %" GST_PTR_FORMAT,
2261 GST_TIME_ARGS (best_ts), best);
2267 gst_base_ts_mux_are_all_pads_eos (GstBaseTsMux * mux)
2270 gboolean ret = TRUE;
2272 GST_OBJECT_LOCK (mux);
2274 for (l = GST_ELEMENT_CAST (mux)->sinkpads; l; l = l->next) {
2275 GstBaseTsMuxPad *pad = GST_BASE_TS_MUX_PAD (l->data);
2277 if (!gst_aggregator_pad_is_eos (GST_AGGREGATOR_PAD (pad))) {
2283 GST_OBJECT_UNLOCK (mux);
2289 static GstFlowReturn
2290 gst_base_ts_mux_aggregate (GstAggregator * agg, gboolean timeout)
2292 GstBaseTsMux *mux = GST_BASE_TS_MUX (agg);
2293 GstFlowReturn ret = GST_FLOW_OK;
2294 GstBaseTsMuxPad *best = gst_base_ts_mux_find_best_pad (agg);
2299 buffer = gst_aggregator_pad_pop_buffer (GST_AGGREGATOR_PAD (best));
2301 /* We might have gotten a flush event after we picked the pad */
2306 gst_base_ts_mux_aggregate_buffer (GST_BASE_TS_MUX (agg),
2307 GST_AGGREGATOR_PAD (best), buffer);
2309 gst_object_unref (best);
2311 if (ret != GST_FLOW_OK)
2315 if (gst_base_ts_mux_are_all_pads_eos (mux)) {
2316 GstBaseTsMuxClass *klass = GST_BASE_TS_MUX_GET_CLASS (mux);
2317 /* drain some possibly cached data */
2320 gst_base_ts_mux_push_packets (mux, TRUE);
2330 gst_base_ts_mux_start (GstAggregator * agg)
2332 gst_base_ts_mux_reset (GST_BASE_TS_MUX (agg), TRUE);
2338 gst_base_ts_mux_stop (GstAggregator * agg)
2340 gst_base_ts_mux_reset (GST_BASE_TS_MUX (agg), TRUE);
2345 /* GObject implementation */
2348 gst_base_ts_mux_dispose (GObject * object)
2350 GstBaseTsMux *mux = GST_BASE_TS_MUX (object);
2352 gst_base_ts_mux_reset (mux, FALSE);
2354 if (mux->out_adapter) {
2355 g_object_unref (mux->out_adapter);
2356 mux->out_adapter = NULL;
2358 if (mux->prog_map) {
2359 gst_structure_free (mux->prog_map);
2360 mux->prog_map = NULL;
2362 if (mux->programs) {
2363 g_hash_table_destroy (mux->programs);
2364 mux->programs = NULL;
2366 GST_CALL_PARENT (G_OBJECT_CLASS, dispose, (object));
2370 gst_base_ts_mux_constructed (GObject * object)
2372 GstBaseTsMux *mux = GST_BASE_TS_MUX (object);
2375 gst_base_ts_mux_reset (mux, TRUE);
2379 gst_base_ts_mux_set_property (GObject * object, guint prop_id,
2380 const GValue * value, GParamSpec * pspec)
2382 GstBaseTsMux *mux = GST_BASE_TS_MUX (object);
2388 const GstStructure *s = gst_value_get_structure (value);
2389 if (mux->prog_map) {
2390 gst_structure_free (mux->prog_map);
2393 mux->prog_map = gst_structure_copy (s);
2395 mux->prog_map = NULL;
2398 case PROP_PAT_INTERVAL:
2399 mux->pat_interval = g_value_get_uint (value);
2401 tsmux_set_pat_interval (mux->tsmux, mux->pat_interval);
2403 case PROP_PMT_INTERVAL:
2404 mux->pmt_interval = g_value_get_uint (value);
2405 GST_OBJECT_LOCK (mux);
2406 for (l = GST_ELEMENT_CAST (mux)->sinkpads; l; l = l->next) {
2407 GstBaseTsMuxPad *ts_pad = GST_BASE_TS_MUX_PAD (l->data);
2409 tsmux_set_pmt_interval (ts_pad->prog, mux->pmt_interval);
2411 GST_OBJECT_UNLOCK (mux);
2413 case PROP_ALIGNMENT:
2414 mux->alignment = g_value_get_int (value);
2416 case PROP_SI_INTERVAL:
2417 mux->si_interval = g_value_get_uint (value);
2418 tsmux_set_si_interval (mux->tsmux, mux->si_interval);
2421 mux->bitrate = g_value_get_uint64 (value);
2423 tsmux_set_bitrate (mux->tsmux, mux->bitrate);
2425 case PROP_PCR_INTERVAL:
2426 mux->pcr_interval = g_value_get_uint (value);
2428 tsmux_set_pcr_interval (mux->tsmux, mux->pcr_interval);
2430 case PROP_SCTE_35_PID:
2431 mux->scte35_pid = g_value_get_uint (value);
2433 case PROP_SCTE_35_NULL_INTERVAL:
2434 mux->scte35_null_interval = g_value_get_uint (value);
2437 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
2443 gst_base_ts_mux_get_property (GObject * object, guint prop_id,
2444 GValue * value, GParamSpec * pspec)
2446 GstBaseTsMux *mux = GST_BASE_TS_MUX (object);
2450 gst_value_set_structure (value, mux->prog_map);
2452 case PROP_PAT_INTERVAL:
2453 g_value_set_uint (value, mux->pat_interval);
2455 case PROP_PMT_INTERVAL:
2456 g_value_set_uint (value, mux->pmt_interval);
2458 case PROP_ALIGNMENT:
2459 g_value_set_int (value, mux->alignment);
2461 case PROP_SI_INTERVAL:
2462 g_value_set_uint (value, mux->si_interval);
2465 g_value_set_uint64 (value, mux->bitrate);
2467 case PROP_PCR_INTERVAL:
2468 g_value_set_uint (value, mux->pcr_interval);
2470 case PROP_SCTE_35_PID:
2471 g_value_set_uint (value, mux->scte35_pid);
2473 case PROP_SCTE_35_NULL_INTERVAL:
2474 g_value_set_uint (value, mux->scte35_null_interval);
2477 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
2482 /* Default vmethods implementation */
2485 gst_base_ts_mux_default_create_ts_mux (GstBaseTsMux * mux)
2487 TsMux *tsmux = tsmux_new ();
2488 tsmux_set_write_func (tsmux, new_packet_cb, mux);
2489 tsmux_set_alloc_func (tsmux, alloc_packet_cb, mux);
2490 tsmux_set_pat_interval (tsmux, mux->pat_interval);
2491 tsmux_set_si_interval (tsmux, mux->si_interval);
2492 tsmux_set_bitrate (tsmux, mux->bitrate);
2493 tsmux_set_pcr_interval (tsmux, mux->pcr_interval);
2499 gst_base_ts_mux_default_allocate_packet (GstBaseTsMux * mux,
2500 GstBuffer ** buffer)
2504 buf = gst_buffer_new_and_alloc (mux->packet_size);
2510 gst_base_ts_mux_default_output_packet (GstBaseTsMux * mux, GstBuffer * buffer,
2513 gst_base_ts_mux_collect_packet (mux, buffer);
2521 gst_base_ts_mux_set_packet_size (GstBaseTsMux * mux, gsize size)
2523 mux->packet_size = size;
2527 gst_base_ts_mux_set_automatic_alignment (GstBaseTsMux * mux, gsize alignment)
2529 mux->automatic_alignment = alignment;
2533 gst_base_ts_mux_class_init (GstBaseTsMuxClass * klass)
2535 GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
2536 GstAggregatorClass *gstagg_class = GST_AGGREGATOR_CLASS (klass);
2537 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
2539 GST_DEBUG_CATEGORY_INIT (gst_base_ts_mux_debug, "basetsmux", 0,
2540 "MPEG Transport Stream muxer");
2542 gst_element_class_set_static_metadata (gstelement_class,
2543 "MPEG Transport Stream Muxer", "Codec/Muxer",
2544 "Multiplexes media streams into an MPEG Transport Stream",
2545 "Fluendo <contact@fluendo.com>");
2547 gobject_class->set_property =
2548 GST_DEBUG_FUNCPTR (gst_base_ts_mux_set_property);
2549 gobject_class->get_property =
2550 GST_DEBUG_FUNCPTR (gst_base_ts_mux_get_property);
2551 gobject_class->dispose = gst_base_ts_mux_dispose;
2552 gobject_class->constructed = gst_base_ts_mux_constructed;
2554 gstelement_class->request_new_pad = gst_base_ts_mux_request_new_pad;
2555 gstelement_class->release_pad = gst_base_ts_mux_release_pad;
2556 gstelement_class->send_event = gst_base_ts_mux_send_event;
2558 gstagg_class->update_src_caps = gst_base_ts_mux_update_src_caps;
2559 gstagg_class->aggregate = gst_base_ts_mux_aggregate;
2560 gstagg_class->clip = gst_base_ts_mux_clip;
2561 gstagg_class->sink_event = gst_base_ts_mux_sink_event;
2562 gstagg_class->src_event = gst_base_ts_mux_src_event;
2563 gstagg_class->start = gst_base_ts_mux_start;
2564 gstagg_class->stop = gst_base_ts_mux_stop;
2566 klass->create_ts_mux = gst_base_ts_mux_default_create_ts_mux;
2567 klass->allocate_packet = gst_base_ts_mux_default_allocate_packet;
2568 klass->output_packet = gst_base_ts_mux_default_output_packet;
2570 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_PROG_MAP,
2571 g_param_spec_boxed ("prog-map", "Program map",
2572 "A GstStructure specifies the mapping from elementary streams to programs",
2574 (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
2576 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_PAT_INTERVAL,
2577 g_param_spec_uint ("pat-interval", "PAT interval",
2578 "Set the interval (in ticks of the 90kHz clock) for writing out the PAT table",
2579 1, G_MAXUINT, TSMUX_DEFAULT_PAT_INTERVAL,
2580 (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
2582 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_PMT_INTERVAL,
2583 g_param_spec_uint ("pmt-interval", "PMT interval",
2584 "Set the interval (in ticks of the 90kHz clock) for writing out the PMT table",
2585 1, G_MAXUINT, TSMUX_DEFAULT_PMT_INTERVAL,
2586 (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
2588 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_ALIGNMENT,
2589 g_param_spec_int ("alignment", "packet alignment",
2590 "Number of packets per buffer (padded with dummy packets on EOS) "
2591 "(-1 = auto, 0 = all available packets, 7 for UDP streaming)",
2592 -1, G_MAXINT, BASETSMUX_DEFAULT_ALIGNMENT,
2593 (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
2595 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_SI_INTERVAL,
2596 g_param_spec_uint ("si-interval", "SI interval",
2597 "Set the interval (in ticks of the 90kHz clock) for writing out the Service"
2598 "Information tables", 1, G_MAXUINT, TSMUX_DEFAULT_SI_INTERVAL,
2599 (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
2601 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_BITRATE,
2602 g_param_spec_uint64 ("bitrate", "Bitrate (in bits per second)",
2603 "Set the target bitrate, will insert null packets as padding "
2604 " to achieve multiplex-wide constant bitrate (0 means no padding)",
2605 0, G_MAXUINT64, TSMUX_DEFAULT_BITRATE,
2606 (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
2608 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_PCR_INTERVAL,
2609 g_param_spec_uint ("pcr-interval", "PCR interval",
2610 "Set the interval (in ticks of the 90kHz clock) for writing PCR",
2611 1, G_MAXUINT, TSMUX_DEFAULT_PCR_INTERVAL,
2612 (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
2614 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_SCTE_35_PID,
2615 g_param_spec_uint ("scte-35-pid", "SCTE-35 PID",
2616 "PID to use for inserting SCTE-35 packets (0: unused)",
2617 0, G_MAXUINT, DEFAULT_SCTE_35_PID,
2618 (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
2620 g_object_class_install_property (G_OBJECT_CLASS (klass),
2621 PROP_SCTE_35_NULL_INTERVAL, g_param_spec_uint ("scte-35-null-interval",
2622 "SCTE-35 NULL packet interval",
2623 "Set the interval (in ticks of the 90kHz clock) for writing SCTE-35 NULL (heartbeat) packets."
2624 " (only valid if scte-35-pid is different from 0)", 1, G_MAXUINT,
2625 TSMUX_DEFAULT_SCTE_35_NULL_INTERVAL,
2626 (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
2628 gst_element_class_add_static_pad_template_with_gtype (gstelement_class,
2629 &gst_base_ts_mux_src_factory, GST_TYPE_AGGREGATOR_PAD);
2631 gst_type_mark_as_plugin_api (GST_TYPE_BASE_TS_MUX_PAD, 0);
2635 gst_base_ts_mux_init (GstBaseTsMux * mux)
2637 mux->out_adapter = gst_adapter_new ();
2640 mux->pat_interval = TSMUX_DEFAULT_PAT_INTERVAL;
2641 mux->pmt_interval = TSMUX_DEFAULT_PMT_INTERVAL;
2642 mux->si_interval = TSMUX_DEFAULT_SI_INTERVAL;
2643 mux->pcr_interval = TSMUX_DEFAULT_PCR_INTERVAL;
2644 mux->prog_map = NULL;
2645 mux->alignment = BASETSMUX_DEFAULT_ALIGNMENT;
2646 mux->bitrate = TSMUX_DEFAULT_BITRATE;
2647 mux->scte35_pid = DEFAULT_SCTE_35_PID;
2648 mux->scte35_null_interval = TSMUX_DEFAULT_SCTE_35_NULL_INTERVAL;
2650 mux->packet_size = GST_BASE_TS_MUX_NORMAL_PACKET_LENGTH;
2651 mux->automatic_alignment = 0;