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 */
198 #define GSTTIME_TO_MPEGTIME(time) \
199 (((time) > 0 ? (gint64) 1 : (gint64) -1) * \
200 (gint64) gst_util_uint64_scale (ABS(time), CLOCK_BASE, GST_MSECOND/10))
201 /* 27 MHz SCR conversions: */
202 #define MPEG_SYS_TIME_TO_GSTTIME(time) (gst_util_uint64_scale ((time), \
203 GST_USECOND, CLOCK_FREQ_SCR / 1000000))
204 #define GSTTIME_TO_MPEG_SYS_TIME(time) (gst_util_uint64_scale ((time), \
205 CLOCK_FREQ_SCR / 1000000, GST_USECOND))
207 #define DEFAULT_PROG_ID 0
209 static GstStaticPadTemplate gst_base_ts_mux_src_factory =
210 GST_STATIC_PAD_TEMPLATE ("src",
213 GST_STATIC_CAPS ("video/mpegts, "
214 "systemstream = (boolean) true, " "packetsize = (int) { 188, 192} ")
223 G_DEFINE_TYPE_WITH_CODE (GstBaseTsMux, gst_base_ts_mux, GST_TYPE_AGGREGATOR,
224 gst_mpegts_initialize ());
228 /* Takes over the ref on the buffer */
230 stream_data_new (GstBuffer * buffer)
232 StreamData *res = g_new (StreamData, 1);
233 res->buffer = buffer;
234 gst_buffer_map (buffer, &(res->map_info), GST_MAP_READ);
240 stream_data_free (StreamData * data)
243 gst_buffer_unmap (data->buffer, &data->map_info);
244 gst_buffer_unref (data->buffer);
249 #define parent_class gst_base_ts_mux_parent_class
252 gst_base_ts_mux_set_header_on_caps (GstBaseTsMux * mux)
255 GstStructure *structure;
256 GValue array = { 0 };
257 GValue value = { 0 };
260 caps = gst_pad_get_current_caps (GST_AGGREGATOR_SRC_PAD (mux));
262 /* If we have no caps, we are possibly shutting down */
266 caps = gst_caps_make_writable (caps);
267 structure = gst_caps_get_structure (caps, 0);
269 g_value_init (&array, GST_TYPE_ARRAY);
271 GST_LOG_OBJECT (mux, "setting %u packets into streamheader",
272 g_queue_get_length (&mux->streamheader));
274 while ((buf = GST_BUFFER (g_queue_pop_head (&mux->streamheader)))) {
275 g_value_init (&value, GST_TYPE_BUFFER);
276 gst_value_take_buffer (&value, buf);
277 gst_value_array_append_value (&array, &value);
278 g_value_unset (&value);
281 gst_structure_set_value (structure, "streamheader", &array);
282 gst_aggregator_set_src_caps (GST_AGGREGATOR (mux), caps);
283 g_value_unset (&array);
284 gst_caps_unref (caps);
288 steal_si_section (GstMpegtsSectionType * type, TsMuxSection * section,
291 g_hash_table_insert (mux->si_sections, type, section);
297 gst_base_ts_mux_reset (GstBaseTsMux * mux, gboolean alloc)
300 GstBaseTsMuxClass *klass = GST_BASE_TS_MUX_GET_CLASS (mux);
301 GHashTable *si_sections = NULL;
305 mux->last_flow_ret = GST_FLOW_OK;
307 mux->is_delta = TRUE;
308 mux->is_header = FALSE;
310 mux->streamheader_sent = FALSE;
311 mux->pending_key_unit_ts = GST_CLOCK_TIME_NONE;
312 gst_event_replace (&mux->force_key_unit_event, NULL);
314 if (mux->out_adapter)
315 gst_adapter_clear (mux->out_adapter);
316 mux->output_ts_offset = GST_CLOCK_TIME_NONE;
319 if (mux->tsmux->si_sections)
320 si_sections = g_hash_table_ref (mux->tsmux->si_sections);
322 tsmux_free (mux->tsmux);
327 g_hash_table_destroy (mux->programs);
329 mux->programs = g_hash_table_new (g_direct_hash, g_direct_equal);
331 while ((buf = GST_BUFFER (g_queue_pop_head (&mux->streamheader))))
332 gst_buffer_unref (buf);
334 gst_event_replace (&mux->force_key_unit_event, NULL);
335 gst_buffer_replace (&mux->out_buffer, NULL);
337 GST_OBJECT_LOCK (mux);
339 for (l = GST_ELEMENT (mux)->sinkpads; l; l = l->next) {
340 gst_base_ts_mux_pad_reset (GST_BASE_TS_MUX_PAD (l->data));
343 GST_OBJECT_UNLOCK (mux);
346 g_assert (klass->create_ts_mux);
348 mux->tsmux = klass->create_ts_mux (mux);
350 /* Preserve user-specified sections across resets */
352 g_hash_table_foreach_steal (si_sections, (GHRFunc) steal_si_section,
357 g_hash_table_unref (si_sections);
364 release_buffer_cb (guint8 * data, void *user_data)
366 stream_data_free ((StreamData *) user_data);
370 gst_base_ts_mux_create_stream (GstBaseTsMux * mux, GstBaseTsMuxPad * ts_pad)
372 GstFlowReturn ret = GST_FLOW_ERROR;
376 guint st = TSMUX_ST_RESERVED;
378 const GValue *value = NULL;
379 GstBuffer *codec_data = NULL;
380 guint8 opus_channel_config_code = 0;
381 guint16 profile = GST_JPEG2000_PARSE_PROFILE_NONE;
382 guint8 main_level = 0;
383 guint32 max_rate = 0;
384 guint8 color_spec = 0;
385 j2k_private_data *private_data = NULL;
386 const gchar *stream_format = NULL;
388 pad = GST_PAD (ts_pad);
389 caps = gst_pad_get_current_caps (pad);
393 GST_DEBUG_OBJECT (pad, "Creating stream with PID 0x%04x for caps %"
394 GST_PTR_FORMAT, 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 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 (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 (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");
474 GST_WARNING_OBJECT (pad, "unsupported mpegversion %d", mpegversion);
477 } else if (strcmp (mt, "video/mpeg") == 0) {
480 if (!gst_structure_get_int (s, "mpegversion", &mpegversion)) {
481 GST_ERROR_OBJECT (pad, "caps missing mpegversion");
485 switch (mpegversion) {
487 st = TSMUX_ST_VIDEO_MPEG1;
490 st = TSMUX_ST_VIDEO_MPEG2;
493 st = TSMUX_ST_VIDEO_MPEG4;
496 GST_WARNING_OBJECT (pad, "unsupported mpegversion %d", mpegversion);
499 } else if (strcmp (mt, "subpicture/x-dvb") == 0) {
500 st = TSMUX_ST_PS_DVB_SUBPICTURE;
501 } else if (strcmp (mt, "application/x-teletext") == 0) {
502 st = TSMUX_ST_PS_TELETEXT;
503 /* needs a particularly sized layout */
504 ts_pad->prepare_func = gst_base_ts_mux_prepare_teletext;
505 } else if (strcmp (mt, "audio/x-opus") == 0) {
506 guint8 channels, mapping_family, stream_count, coupled_count;
507 guint8 channel_mapping[256];
509 if (!gst_codec_utils_opus_parse_caps (caps, NULL, &channels,
510 &mapping_family, &stream_count, &coupled_count, channel_mapping)) {
511 GST_ERROR_OBJECT (pad, "Incomplete Opus caps");
515 if (channels <= 2 && mapping_family == 0) {
516 opus_channel_config_code = channels;
517 } else if (channels == 2 && mapping_family == 255 && stream_count == 1
518 && coupled_count == 1) {
520 opus_channel_config_code = 0;
521 } else if (channels >= 2 && channels <= 8 && mapping_family == 1) {
522 static const guint8 coupled_stream_counts[9] = {
523 1, 0, 1, 1, 2, 2, 2, 3, 3
525 static const guint8 channel_map_a[8][8] = {
532 {0, 4, 1, 2, 3, 5, 6},
533 {0, 6, 1, 2, 3, 4, 5, 7},
535 static const guint8 channel_map_b[8][8] = {
542 {0, 1, 2, 3, 4, 5, 6},
543 {0, 1, 2, 3, 4, 5, 6, 7},
547 if (stream_count == channels - coupled_stream_counts[channels] &&
548 coupled_count == coupled_stream_counts[channels] &&
549 memcmp (channel_mapping, channel_map_a[channels - 1],
551 opus_channel_config_code = channels;
552 } else if (stream_count == channels - coupled_stream_counts[channels] &&
553 coupled_count == coupled_stream_counts[channels] &&
554 memcmp (channel_mapping, channel_map_b[channels - 1],
556 opus_channel_config_code = channels | 0x80;
558 GST_FIXME_OBJECT (pad, "Opus channel mapping not handled");
563 st = TSMUX_ST_PS_OPUS;
564 ts_pad->prepare_func = gst_base_ts_mux_prepare_opus;
565 } else if (strcmp (mt, "meta/x-klv") == 0) {
566 st = TSMUX_ST_PS_KLV;
567 } else if (strcmp (mt, "image/x-jpc") == 0) {
569 * See this document for more details on standard:
571 * https://www.itu.int/rec/T-REC-H.222.0-201206-S/en
572 * Annex S describes J2K details
573 * Page 104 of this document describes J2k video descriptor
576 const GValue *vProfile = gst_structure_get_value (s, "profile");
577 const GValue *vMainlevel = gst_structure_get_value (s, "main-level");
578 const GValue *vFramerate = gst_structure_get_value (s, "framerate");
579 const GValue *vColorimetry = gst_structure_get_value (s, "colorimetry");
580 private_data = g_new0 (j2k_private_data, 1);
581 /* for now, we relax the condition that profile must exist and equal
582 * GST_JPEG2000_PARSE_PROFILE_BC_SINGLE */
584 profile = g_value_get_int (vProfile);
585 if (profile != GST_JPEG2000_PARSE_PROFILE_BC_SINGLE) {
586 GST_LOG_OBJECT (pad, "Invalid JPEG 2000 profile %d", profile);
587 /*goto not_negotiated; */
590 /* for now, we will relax the condition that the main level must be present */
592 main_level = g_value_get_uint (vMainlevel);
593 if (main_level > 11) {
594 GST_ERROR_OBJECT (pad, "Invalid main level %d", main_level);
597 if (main_level >= 6) {
598 max_rate = 2 ^ (main_level - 6) * 1600 * 1000000;
600 switch (main_level) {
605 max_rate = 200 * 1000000;
608 max_rate = 400 * 1000000;
611 max_rate = 800 * 1000000;
618 /*GST_ERROR_OBJECT (pad, "Missing main level");
619 goto not_negotiated; */
621 /* We always mux video in J2K-over-MPEG-TS non-interlaced mode */
622 private_data->interlace = FALSE;
623 private_data->den = 0;
624 private_data->num = 0;
625 private_data->max_bitrate = max_rate;
626 private_data->color_spec = 1;
627 /* these two fields are not used, since we always mux as non-interlaced */
628 private_data->Fic = 1;
629 private_data->Fio = 0;
632 if (vFramerate != NULL) {
633 /* Data for ELSM header */
634 private_data->num = gst_value_get_fraction_numerator (vFramerate);
635 private_data->den = gst_value_get_fraction_denominator (vFramerate);
637 /* Get Colorimetry */
639 const char *colorimetry = g_value_get_string (vColorimetry);
640 color_spec = GST_MPEGTS_JPEG2000_COLORSPEC_SRGB; /* RGB as default */
641 if (g_str_equal (colorimetry, GST_VIDEO_COLORIMETRY_BT601)) {
642 color_spec = GST_MPEGTS_JPEG2000_COLORSPEC_REC601;
644 if (g_str_equal (colorimetry, GST_VIDEO_COLORIMETRY_BT709)
645 || g_str_equal (colorimetry, GST_VIDEO_COLORIMETRY_SMPTE240M)) {
646 color_spec = GST_MPEGTS_JPEG2000_COLORSPEC_REC709;
649 private_data->color_spec = color_spec;
651 GST_ERROR_OBJECT (pad, "Colorimetry not present in caps");
654 st = TSMUX_ST_VIDEO_JP2K;
655 ts_pad->prepare_func = gst_base_ts_mux_prepare_jpeg2000;
656 ts_pad->prepare_data = private_data;
657 ts_pad->free_func = gst_base_ts_mux_free_jpeg2000;
659 GstBaseTsMuxClass *klass = GST_BASE_TS_MUX_GET_CLASS (mux);
661 if (klass->handle_media_type) {
662 st = klass->handle_media_type (mux, mt, ts_pad);
667 if (st != TSMUX_ST_RESERVED) {
668 ts_pad->stream = tsmux_create_stream (mux->tsmux, st, ts_pad->pid,
671 GST_DEBUG_OBJECT (pad, "Failed to determine stream type");
674 if (ts_pad->stream != NULL) {
675 const char *interlace_mode = gst_structure_get_string (s, "interlace-mode");
676 gst_structure_get_int (s, "rate", &ts_pad->stream->audio_sampling);
677 gst_structure_get_int (s, "channels", &ts_pad->stream->audio_channels);
678 gst_structure_get_int (s, "bitrate", &ts_pad->stream->audio_bitrate);
681 gst_structure_get_fraction (s, "framerate", &ts_pad->stream->num,
682 &ts_pad->stream->den);
685 ts_pad->stream->interlace_mode = FALSE;
686 if (interlace_mode) {
687 ts_pad->stream->interlace_mode =
688 g_str_equal (interlace_mode, "interleaved");
690 /* Width and Height */
691 gst_structure_get_int (s, "width", &ts_pad->stream->horizontal_size);
692 gst_structure_get_int (s, "height", &ts_pad->stream->vertical_size);
694 ts_pad->stream->color_spec = color_spec;
695 ts_pad->stream->max_bitrate = max_rate;
696 ts_pad->stream->profile_and_level = profile | main_level;
698 ts_pad->stream->opus_channel_config_code = opus_channel_config_code;
700 tsmux_stream_set_buffer_release_func (ts_pad->stream, release_buffer_cb);
701 tsmux_program_add_stream (ts_pad->prog, ts_pad->stream);
705 gst_caps_unref (caps);
710 g_free (private_data);
711 GST_DEBUG_OBJECT (pad, "Sink pad caps were not set before pushing");
713 gst_caps_unref (caps);
714 return GST_FLOW_NOT_NEGOTIATED;
719 is_valid_pmt_pid (guint16 pmt_pid)
721 if (pmt_pid < 0x0010 || pmt_pid > 0x1ffe)
727 gst_base_ts_mux_create_pad_stream (GstBaseTsMux * mux, GstPad * pad)
729 GstBaseTsMuxPad *ts_pad = GST_BASE_TS_MUX_PAD (pad);
732 GstFlowReturn ret = GST_FLOW_OK;
734 if (ts_pad->prog_id == -1) {
735 name = GST_PAD_NAME (pad);
736 if (mux->prog_map != NULL && gst_structure_has_field (mux->prog_map, name)) {
738 gboolean ret = gst_structure_get_int (mux->prog_map, name, &idx);
740 GST_ELEMENT_ERROR (mux, STREAM, MUX,
741 ("Reading program map failed. Assuming default"), (NULL));
742 idx = DEFAULT_PROG_ID;
745 GST_DEBUG_OBJECT (mux, "Program number %d associate with pad %s less "
746 "than zero; DEFAULT_PROGRAM = %d is used instead",
747 idx, name, DEFAULT_PROG_ID);
748 idx = DEFAULT_PROG_ID;
750 ts_pad->prog_id = idx;
752 ts_pad->prog_id = DEFAULT_PROG_ID;
757 (TsMuxProgram *) g_hash_table_lookup (mux->programs,
758 GINT_TO_POINTER (ts_pad->prog_id));
759 if (ts_pad->prog == NULL) {
760 ts_pad->prog = tsmux_program_new (mux->tsmux, ts_pad->prog_id);
761 if (ts_pad->prog == NULL)
763 tsmux_set_pmt_interval (ts_pad->prog, mux->pmt_interval);
764 tsmux_program_set_scte35_pid (ts_pad->prog, mux->scte35_pid);
765 tsmux_program_set_scte35_interval (ts_pad->prog, mux->scte35_null_interval);
766 g_hash_table_insert (mux->programs, GINT_TO_POINTER (ts_pad->prog_id),
769 /* Check for user-specified PMT PID */
770 prop_name = g_strdup_printf ("PMT_%d", ts_pad->prog->pgm_number);
771 if (mux->prog_map && gst_structure_has_field (mux->prog_map, prop_name)) {
774 if (gst_structure_get_uint (mux->prog_map, prop_name, &pmt_pid)) {
775 if (is_valid_pmt_pid (pmt_pid)) {
776 GST_DEBUG_OBJECT (mux, "User specified pid=%u as PMT for "
777 "program (prog_id = %d)", pmt_pid, ts_pad->prog->pgm_number);
778 tsmux_program_set_pmt_pid (ts_pad->prog, pmt_pid);
780 GST_ELEMENT_WARNING (mux, LIBRARY, SETTINGS,
781 ("User specified PMT pid %u for program %d is not valid.",
782 pmt_pid, ts_pad->prog->pgm_number), (NULL));
789 if (ts_pad->stream == NULL) {
790 ret = gst_base_ts_mux_create_stream (mux, ts_pad);
791 if (ret != GST_FLOW_OK)
795 if (ts_pad->prog->pcr_stream == NULL) {
796 /* Take the first stream of the program for the PCR */
797 GST_DEBUG_OBJECT (ts_pad,
798 "Use stream (pid=%d) from pad as PCR for program (prog_id = %d)",
799 ts_pad->pid, ts_pad->prog_id);
801 tsmux_program_set_pcr_stream (ts_pad->prog, ts_pad->stream);
804 /* Check for user-specified PCR PID */
805 prop_name = g_strdup_printf ("PCR_%d", ts_pad->prog->pgm_number);
806 if (mux->prog_map && gst_structure_has_field (mux->prog_map, prop_name)) {
807 const gchar *sink_name =
808 gst_structure_get_string (mux->prog_map, prop_name);
810 if (!g_strcmp0 (name, sink_name)) {
811 GST_DEBUG_OBJECT (mux, "User specified stream (pid=%d) as PCR for "
812 "program (prog_id = %d)", ts_pad->pid, ts_pad->prog->pgm_number);
813 tsmux_program_set_pcr_stream (ts_pad->prog, ts_pad->stream);
823 GST_ELEMENT_ERROR (mux, STREAM, MUX,
824 ("Could not create new program"), (NULL));
825 return GST_FLOW_ERROR;
829 GST_ELEMENT_ERROR (mux, STREAM, MUX,
830 ("Could not create handler for stream"), (NULL));
836 gst_base_ts_mux_create_pad_stream_func (GstElement * element, GstPad * pad,
839 GstFlowReturn *ret = user_data;
841 *ret = gst_base_ts_mux_create_pad_stream (GST_BASE_TS_MUX (element), pad);
843 return *ret == GST_FLOW_OK;
847 gst_base_ts_mux_create_streams (GstBaseTsMux * mux)
849 GstFlowReturn ret = GST_FLOW_OK;
851 gst_element_foreach_sink_pad (GST_ELEMENT_CAST (mux),
852 gst_base_ts_mux_create_pad_stream_func, &ret);
858 new_packet_common_init (GstBaseTsMux * mux, GstBuffer * buf, guint8 * data,
861 /* Packets should be at least 188 bytes, but check anyway */
862 g_assert (len >= 2 || !data);
864 if (!mux->streamheader_sent && data) {
865 guint pid = ((data[1] & 0x1f) << 8) | data[2];
866 /* if it's a PAT or a PMT */
867 if (pid == 0x00 || (pid >= TSMUX_START_PMT_PID && pid < TSMUX_START_ES_PID)) {
871 hbuf = gst_buffer_new_and_alloc (len);
872 gst_buffer_fill (hbuf, 0, data, len);
874 hbuf = gst_buffer_copy (buf);
877 "Collecting packet with pid 0x%04x into streamheaders", pid);
879 g_queue_push_tail (&mux->streamheader, hbuf);
880 } else if (!g_queue_is_empty (&mux->streamheader)) {
881 gst_base_ts_mux_set_header_on_caps (mux);
882 mux->streamheader_sent = TRUE;
887 if (mux->is_header) {
888 GST_LOG_OBJECT (mux, "marking as header buffer");
889 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_HEADER);
892 GST_LOG_OBJECT (mux, "marking as delta unit");
893 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
895 GST_DEBUG_OBJECT (mux, "marking as non-delta unit");
896 mux->is_delta = TRUE;
902 gst_base_ts_mux_push_packets (GstBaseTsMux * mux, gboolean force)
904 GstBufferList *buffer_list;
905 gint align = mux->alignment;
906 gint av, packet_size;
908 packet_size = mux->packet_size;
911 align = mux->automatic_alignment;
913 av = gst_adapter_available (mux->out_adapter);
914 GST_LOG_OBJECT (mux, "align %d, av %d", align, av);
919 /* no alignment, just push all available data */
921 buffer_list = gst_adapter_take_buffer_list (mux->out_adapter, av);
922 return gst_aggregator_finish_buffer_list (GST_AGGREGATOR (mux),
926 align *= packet_size;
928 if (!force && align > av)
931 buffer_list = gst_buffer_list_new_sized ((av / align) + 1);
933 GST_LOG_OBJECT (mux, "aligning to %d bytes", align);
934 while (align <= av) {
938 pts = gst_adapter_prev_pts (mux->out_adapter, NULL);
939 buf = gst_adapter_take_buffer (mux->out_adapter, align);
941 GST_BUFFER_PTS (buf) = pts;
943 gst_buffer_list_add (buffer_list, buf);
947 if (av > 0 && force) {
955 GST_LOG_OBJECT (mux, "handling %d leftover bytes", av);
957 pts = gst_adapter_prev_pts (mux->out_adapter, NULL);
958 buf = gst_buffer_new_and_alloc (align);
960 GST_BUFFER_PTS (buf) = pts;
962 gst_buffer_map (buf, &map, GST_MAP_READ);
965 gst_adapter_copy (mux->out_adapter, data, 0, av);
966 gst_adapter_clear (mux->out_adapter);
969 header = GST_READ_UINT32_BE (data - packet_size);
971 dummy = (map.size - av) / packet_size;
972 GST_LOG_OBJECT (mux, "adding %d null packets", dummy);
974 for (; dummy > 0; dummy--) {
977 if (packet_size > GST_BASE_TS_MUX_NORMAL_PACKET_LENGTH) {
978 GST_WRITE_UINT32_BE (data, header);
979 /* simply increase header a bit and never mind too much */
985 GST_WRITE_UINT8 (data + offset, TSMUX_SYNC_BYTE);
986 /* null packet PID */
987 GST_WRITE_UINT16_BE (data + offset + 1, 0x1FFF);
988 /* no adaptation field exists | continuity counter undefined */
989 GST_WRITE_UINT8 (data + offset + 3, 0x10);
991 memset (data + offset + 4, 0, GST_BASE_TS_MUX_NORMAL_PACKET_LENGTH - 4);
995 gst_buffer_unmap (buf, &map);
996 gst_buffer_list_add (buffer_list, buf);
999 return gst_aggregator_finish_buffer_list (GST_AGGREGATOR (mux), buffer_list);
1002 static GstFlowReturn
1003 gst_base_ts_mux_collect_packet (GstBaseTsMux * mux, GstBuffer * buf)
1005 GST_LOG_OBJECT (mux, "collecting packet size %" G_GSIZE_FORMAT,
1006 gst_buffer_get_size (buf));
1007 gst_adapter_push (mux->out_adapter, buf);
1013 check_pending_key_unit_event (GstEvent * pending_event, GstSegment * segment,
1014 GstClockTime timestamp, guint flags, GstClockTime pending_key_unit_ts)
1016 GstClockTime running_time, stream_time;
1017 gboolean all_headers;
1019 GstEvent *event = NULL;
1021 g_assert (segment != NULL);
1023 if (pending_event == NULL)
1026 if (GST_CLOCK_TIME_IS_VALID (pending_key_unit_ts) &&
1027 timestamp == GST_CLOCK_TIME_NONE)
1030 running_time = timestamp;
1032 GST_INFO ("now %" GST_TIME_FORMAT " wanted %" GST_TIME_FORMAT,
1033 GST_TIME_ARGS (running_time), GST_TIME_ARGS (pending_key_unit_ts));
1034 if (GST_CLOCK_TIME_IS_VALID (pending_key_unit_ts) &&
1035 running_time < pending_key_unit_ts)
1038 if (flags & GST_BUFFER_FLAG_DELTA_UNIT) {
1039 GST_INFO ("pending force key unit, waiting for keyframe");
1043 stream_time = gst_segment_to_stream_time (segment,
1044 GST_FORMAT_TIME, timestamp);
1046 if (GST_EVENT_TYPE (pending_event) == GST_EVENT_CUSTOM_DOWNSTREAM) {
1047 gst_video_event_parse_downstream_force_key_unit (pending_event,
1048 NULL, NULL, NULL, &all_headers, &count);
1050 gst_video_event_parse_upstream_force_key_unit (pending_event, NULL,
1051 &all_headers, &count);
1055 gst_video_event_new_downstream_force_key_unit (timestamp, stream_time,
1056 running_time, all_headers, count);
1057 gst_event_set_seqnum (event, gst_event_get_seqnum (pending_event));
1063 /* Called when the TsMux has prepared a packet for output. Return FALSE
1066 new_packet_cb (GstBuffer * buf, void *user_data, gint64 new_pcr)
1068 GstBaseTsMux *mux = (GstBaseTsMux *) user_data;
1069 GstAggregator *agg = GST_AGGREGATOR (mux);
1070 GstBaseTsMuxClass *klass = GST_BASE_TS_MUX_GET_CLASS (mux);
1072 GstSegment *agg_segment = &GST_AGGREGATOR_PAD (agg->srcpad)->segment;
1074 g_assert (klass->output_packet);
1076 gst_buffer_map (buf, &map, GST_MAP_READWRITE);
1078 if (!GST_CLOCK_TIME_IS_VALID (GST_BUFFER_PTS (buf))) {
1079 /* tsmux isn't generating timestamps. Use the input times */
1080 GST_BUFFER_PTS (buf) = mux->last_ts;
1083 if (GST_CLOCK_TIME_IS_VALID (GST_BUFFER_PTS (buf))) {
1084 if (!GST_CLOCK_TIME_IS_VALID (mux->output_ts_offset)) {
1085 GstClockTime output_start_time = agg_segment->position;
1086 if (agg_segment->position == -1
1087 || agg_segment->position < agg_segment->start) {
1088 output_start_time = agg_segment->start;
1091 mux->output_ts_offset =
1092 GST_CLOCK_DIFF (GST_BUFFER_PTS (buf), output_start_time);
1094 GST_DEBUG_OBJECT (mux, "New output ts offset %" GST_STIME_FORMAT,
1095 GST_STIME_ARGS (mux->output_ts_offset));
1098 if (GST_CLOCK_TIME_IS_VALID (mux->output_ts_offset)) {
1099 GST_BUFFER_PTS (buf) += mux->output_ts_offset;
1103 if (GST_CLOCK_TIME_IS_VALID (GST_BUFFER_PTS (buf))) {
1104 agg_segment->position = GST_BUFFER_PTS (buf);
1107 /* do common init (flags and streamheaders) */
1108 new_packet_common_init (mux, buf, map.data, map.size);
1110 gst_buffer_unmap (buf, &map);
1112 return klass->output_packet (mux, buf, new_pcr);
1115 /* called when TsMux needs new packet to write into */
1117 alloc_packet_cb (GstBuffer ** buf, void *user_data)
1119 GstBaseTsMux *mux = (GstBaseTsMux *) user_data;
1120 GstBaseTsMuxClass *klass = GST_BASE_TS_MUX_GET_CLASS (mux);
1122 g_assert (klass->allocate_packet);
1124 klass->allocate_packet (mux, buf);
1127 static GstFlowReturn
1128 gst_base_ts_mux_aggregate_buffer (GstBaseTsMux * mux,
1129 GstAggregatorPad * agg_pad, GstBuffer * buf)
1131 GstFlowReturn ret = GST_FLOW_OK;
1132 GstBaseTsMuxPad *best = GST_BASE_TS_MUX_PAD (agg_pad);
1134 gint64 pts = GST_CLOCK_STIME_NONE;
1135 gint64 dts = GST_CLOCK_STIME_NONE;
1136 gboolean delta = TRUE, header = FALSE;
1137 StreamData *stream_data;
1138 GstMpegtsSection *scte_section = NULL;
1140 GST_DEBUG_OBJECT (mux, "Pads collected");
1142 if (buf && gst_buffer_get_size (buf) == 0
1143 && GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_GAP)) {
1144 gst_buffer_unref (buf);
1148 if (G_UNLIKELY (mux->first)) {
1149 ret = gst_base_ts_mux_create_streams (mux);
1150 if (G_UNLIKELY (ret != GST_FLOW_OK)) {
1152 gst_buffer_unref (buf);
1163 gst_base_ts_mux_create_pad_stream (mux, GST_PAD (best));
1164 tsmux_resend_pat (mux->tsmux);
1165 tsmux_resend_si (mux->tsmux);
1167 g_assert_nonnull (prog);
1169 /* output PMT for each program */
1170 for (cur = mux->tsmux->programs; cur; cur = cur->next) {
1171 TsMuxProgram *program = (TsMuxProgram *) cur->data;
1173 tsmux_resend_pmt (program);
1177 g_assert (buf != NULL);
1179 if (best->prepare_func) {
1182 tmp = best->prepare_func (buf, best, mux);
1184 gst_buffer_unref (buf);
1188 if (mux->force_key_unit_event != NULL && best->stream->is_video_stream) {
1191 event = check_pending_key_unit_event (mux->force_key_unit_event,
1192 &agg_pad->segment, GST_BUFFER_PTS (buf),
1193 GST_BUFFER_FLAGS (buf), mux->pending_key_unit_ts);
1195 GstClockTime running_time;
1199 mux->pending_key_unit_ts = GST_CLOCK_TIME_NONE;
1200 gst_event_replace (&mux->force_key_unit_event, NULL);
1202 gst_video_event_parse_downstream_force_key_unit (event,
1203 NULL, NULL, &running_time, NULL, &count);
1205 GST_INFO_OBJECT (mux, "pushing downstream force-key-unit event %d "
1206 "%" GST_TIME_FORMAT " count %d", gst_event_get_seqnum (event),
1207 GST_TIME_ARGS (running_time), count);
1208 gst_pad_push_event (GST_AGGREGATOR_SRC_PAD (mux), event);
1210 /* output PAT, SI tables */
1211 tsmux_resend_pat (mux->tsmux);
1212 tsmux_resend_si (mux->tsmux);
1214 /* output PMT for each program */
1215 for (cur = mux->tsmux->programs; cur; cur = cur->next) {
1216 TsMuxProgram *program = (TsMuxProgram *) cur->data;
1218 tsmux_resend_pmt (program);
1223 if (G_UNLIKELY (prog->pcr_stream == NULL)) {
1224 /* Take the first data stream for the PCR */
1225 GST_DEBUG_OBJECT (best,
1226 "Use stream (pid=%d) from pad as PCR for program (prog_id = %d)",
1227 best->pid, best->prog_id);
1229 /* Set the chosen PCR stream */
1230 tsmux_program_set_pcr_stream (prog, best->stream);
1233 GST_DEBUG_OBJECT (best, "Chose stream for output (PID: 0x%04x)", best->pid);
1235 GST_OBJECT_LOCK (mux);
1236 scte_section = mux->pending_scte35_section;
1237 mux->pending_scte35_section = NULL;
1238 GST_OBJECT_UNLOCK (mux);
1239 if (G_UNLIKELY (scte_section)) {
1240 GST_DEBUG_OBJECT (mux, "Sending pending SCTE section");
1241 if (!tsmux_send_section (mux->tsmux, scte_section))
1242 GST_ERROR_OBJECT (mux, "Error sending SCTE section !");
1245 if (GST_CLOCK_TIME_IS_VALID (GST_BUFFER_PTS (buf))) {
1246 pts = GSTTIME_TO_MPEGTIME (GST_BUFFER_PTS (buf));
1247 GST_DEBUG_OBJECT (mux, "Buffer has PTS %" GST_TIME_FORMAT " pts %"
1248 G_GINT64_FORMAT, GST_TIME_ARGS (GST_BUFFER_PTS (buf)), pts);
1251 if (GST_CLOCK_STIME_IS_VALID (best->dts)) {
1252 dts = GSTTIME_TO_MPEGTIME (best->dts);
1253 GST_DEBUG_OBJECT (mux, "Buffer has DTS %" GST_STIME_FORMAT " dts %"
1254 G_GINT64_FORMAT, GST_STIME_ARGS (best->dts), dts);
1257 /* should not have a DTS without PTS */
1258 if (!GST_CLOCK_STIME_IS_VALID (pts) && GST_CLOCK_STIME_IS_VALID (dts)) {
1259 GST_DEBUG_OBJECT (mux, "using DTS for unknown PTS");
1263 if (best->stream->is_video_stream) {
1264 delta = GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
1265 header = GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_HEADER);
1268 if (best->stream->is_meta && gst_buffer_get_size (buf) > (G_MAXUINT16 - 3)) {
1269 GST_WARNING_OBJECT (mux, "KLV meta unit too big, splitting not supported");
1271 gst_buffer_unref (buf);
1275 GST_DEBUG_OBJECT (mux, "delta: %d", delta);
1277 stream_data = stream_data_new (buf);
1278 tsmux_stream_add_data (best->stream, stream_data->map_info.data,
1279 stream_data->map_info.size, stream_data, pts, dts, !delta);
1281 /* outgoing ts follows ts of PCR program stream */
1282 if (prog->pcr_stream == best->stream) {
1283 /* prefer DTS if present for PCR as it should be monotone */
1285 GST_CLOCK_TIME_IS_VALID (GST_BUFFER_DTS (buf)) ?
1286 GST_BUFFER_DTS (buf) : GST_BUFFER_PTS (buf);
1289 mux->is_delta = delta;
1290 mux->is_header = header;
1291 while (tsmux_stream_bytes_in_buffer (best->stream) > 0) {
1292 if (!tsmux_write_stream_packet (mux->tsmux, best->stream)) {
1293 /* Failed writing data for some reason. Set appropriate error */
1294 GST_DEBUG_OBJECT (mux, "Failed to write data packet");
1295 GST_ELEMENT_ERROR (mux, STREAM, MUX,
1296 ("Failed writing output data to stream %04x", best->stream->id),
1301 /* flush packet cache */
1302 return gst_base_ts_mux_push_packets (mux, FALSE);
1307 return mux->last_flow_ret;
1311 /* GstElement implementation */
1313 gst_base_ts_mux_has_pad_with_pid (GstBaseTsMux * mux, guint16 pid)
1316 gboolean res = FALSE;
1318 GST_OBJECT_LOCK (mux);
1320 for (l = GST_ELEMENT_CAST (mux)->sinkpads; l; l = l->next) {
1321 GstBaseTsMuxPad *tpad = GST_BASE_TS_MUX_PAD (l->data);
1323 if (tpad->pid == pid) {
1329 GST_OBJECT_UNLOCK (mux);
1334 gst_base_ts_mux_request_new_pad (GstElement * element, GstPadTemplate * templ,
1335 const gchar * name, const GstCaps * caps)
1337 GstBaseTsMux *mux = GST_BASE_TS_MUX (element);
1340 gchar *free_name = NULL;
1342 if (name != NULL && sscanf (name, "sink_%d", &pid) == 1) {
1343 if (tsmux_find_stream (mux->tsmux, pid))
1345 /* Make sure we don't use reserved PID.
1346 * FIXME : This should be extended to other variants (ex: ATSC) reserved PID */
1347 if (pid < TSMUX_START_ES_PID)
1348 goto invalid_stream_pid;
1351 pid = tsmux_get_new_pid (mux->tsmux);
1352 } while (gst_base_ts_mux_has_pad_with_pid (mux, pid));
1354 /* Name the pad correctly after the selected pid */
1355 name = free_name = g_strdup_printf ("sink_%d", pid);
1359 GST_ELEMENT_CLASS (parent_class)->request_new_pad (element,
1362 gst_base_ts_mux_pad_reset (GST_BASE_TS_MUX_PAD (pad));
1363 GST_BASE_TS_MUX_PAD (pad)->pid = pid;
1372 GST_ELEMENT_ERROR (element, STREAM, MUX, ("Duplicate PID requested"),
1379 GST_ELEMENT_ERROR (element, STREAM, MUX,
1380 ("Invalid Elementary stream PID (0x%02u < 0x40)", pid), (NULL));
1386 gst_base_ts_mux_release_pad (GstElement * element, GstPad * pad)
1388 GstBaseTsMux *mux = GST_BASE_TS_MUX (element);
1392 GstBaseTsMuxPad *ts_pad = GST_BASE_TS_MUX_PAD (pad);
1393 gint pid = ts_pad->pid;
1396 if (ts_pad->prog->pcr_stream == ts_pad->stream) {
1397 tsmux_program_set_pcr_stream (ts_pad->prog, NULL);
1399 if (tsmux_remove_stream (mux->tsmux, pid, ts_pad->prog)) {
1400 g_hash_table_remove (mux->programs, GINT_TO_POINTER (ts_pad->prog_id));
1404 tsmux_resend_pat (mux->tsmux);
1405 tsmux_resend_si (mux->tsmux);
1407 /* output PMT for each program */
1408 for (cur = mux->tsmux->programs; cur; cur = cur->next) {
1409 TsMuxProgram *program = (TsMuxProgram *) cur->data;
1411 tsmux_resend_pmt (program);
1415 GST_ELEMENT_CLASS (parent_class)->release_pad (element, pad);
1419 gst_base_ts_mux_send_event (GstElement * element, GstEvent * event)
1421 GstMpegtsSection *section;
1422 GstBaseTsMux *mux = GST_BASE_TS_MUX (element);
1424 section = gst_event_parse_mpegts_section (event);
1427 GST_DEBUG ("Received event with mpegts section");
1429 if (section->section_type == GST_MPEGTS_SECTION_SCTE_SIT) {
1430 /* Will be sent from the streaming threads */
1431 GST_DEBUG_OBJECT (mux, "Storing SCTE event");
1432 GST_OBJECT_LOCK (element);
1433 if (mux->pending_scte35_section)
1434 gst_mpegts_section_unref (mux->pending_scte35_section);
1435 mux->pending_scte35_section = section;
1436 GST_OBJECT_UNLOCK (element);
1438 /* TODO: Check that the section type is supported */
1439 tsmux_add_mpegts_si_section (mux->tsmux, section);
1442 gst_event_unref (event);
1447 return GST_ELEMENT_CLASS (parent_class)->send_event (element, event);
1450 /* GstAggregator implementation */
1453 gst_base_ts_mux_sink_event (GstAggregator * agg, GstAggregatorPad * agg_pad,
1456 GstAggregatorClass *agg_class = GST_AGGREGATOR_CLASS (parent_class);
1457 GstBaseTsMux *mux = GST_BASE_TS_MUX (agg);
1458 GstBaseTsMuxPad *ts_pad = GST_BASE_TS_MUX_PAD (agg_pad);
1459 gboolean res = FALSE;
1460 gboolean forward = TRUE;
1462 switch (GST_EVENT_TYPE (event)) {
1463 case GST_EVENT_CUSTOM_DOWNSTREAM:
1465 GstClockTime timestamp, stream_time, running_time;
1466 gboolean all_headers;
1469 if (!gst_video_event_is_force_key_unit (event))
1475 gst_video_event_parse_downstream_force_key_unit (event,
1476 ×tamp, &stream_time, &running_time, &all_headers, &count);
1477 GST_INFO_OBJECT (ts_pad, "have downstream force-key-unit event, "
1478 "seqnum %d, running-time %" GST_TIME_FORMAT " count %d",
1479 gst_event_get_seqnum (event), GST_TIME_ARGS (running_time), count);
1481 if (mux->force_key_unit_event != NULL) {
1482 GST_INFO_OBJECT (mux, "skipping downstream force key unit event "
1483 "as an upstream force key unit is already queued");
1490 mux->pending_key_unit_ts = running_time;
1491 gst_event_replace (&mux->force_key_unit_event, event);
1494 case GST_EVENT_TAG:{
1498 GST_DEBUG_OBJECT (mux, "received tag event");
1499 gst_event_parse_tag (event, &list);
1501 /* Matroska wants ISO 639-2B code, taglist most likely contains 639-1 */
1502 if (gst_tag_list_get_string (list, GST_TAG_LANGUAGE_CODE, &lang)) {
1503 const gchar *lang_code;
1505 lang_code = gst_tag_get_language_code_iso_639_2B (lang);
1507 GST_DEBUG_OBJECT (ts_pad, "Setting language to '%s'", lang_code);
1509 g_free (ts_pad->language);
1510 ts_pad->language = g_strdup (lang_code);
1512 GST_WARNING_OBJECT (ts_pad, "Did not get language code for '%s'",
1518 /* handled this, don't want collectpads to forward it downstream */
1520 forward = gst_tag_list_get_scope (list) == GST_TAG_SCOPE_GLOBAL;
1523 case GST_EVENT_STREAM_START:{
1524 GstStreamFlags flags;
1526 gst_event_parse_stream_flags (event, &flags);
1528 /* Don't wait for data on sparse inputs like metadata streams */
1530 if ((flags & GST_STREAM_FLAG_SPARSE)) {
1531 GST_COLLECT_PADS_STATE_UNSET (data, GST_COLLECT_PADS_STATE_LOCKED);
1532 gst_collect_pads_set_waiting (pads, data, FALSE);
1533 GST_COLLECT_PADS_STATE_SET (data, GST_COLLECT_PADS_STATE_LOCKED);
1544 gst_event_unref (event);
1546 res = agg_class->sink_event (agg, agg_pad, event);
1552 gst_base_ts_mux_src_event (GstAggregator * agg, GstEvent * event)
1554 GstAggregatorClass *agg_class = GST_AGGREGATOR_CLASS (parent_class);
1555 GstBaseTsMux *mux = GST_BASE_TS_MUX (agg);
1556 gboolean res = TRUE, forward = TRUE;
1558 switch (GST_EVENT_TYPE (event)) {
1559 case GST_EVENT_CUSTOM_UPSTREAM:
1562 GValue sinkpad_value = G_VALUE_INIT;
1563 GstClockTime running_time;
1564 gboolean all_headers, done = FALSE, res = FALSE;
1567 if (!gst_video_event_is_force_key_unit (event))
1572 gst_video_event_parse_upstream_force_key_unit (event,
1573 &running_time, &all_headers, &count);
1575 GST_INFO_OBJECT (mux, "received upstream force-key-unit event, "
1576 "seqnum %d running_time %" GST_TIME_FORMAT " all_headers %d count %d",
1577 gst_event_get_seqnum (event), GST_TIME_ARGS (running_time),
1578 all_headers, count);
1583 mux->pending_key_unit_ts = running_time;
1584 gst_event_replace (&mux->force_key_unit_event, event);
1586 iter = gst_element_iterate_sink_pads (GST_ELEMENT_CAST (mux));
1589 switch (gst_iterator_next (iter, &sinkpad_value)) {
1590 case GST_ITERATOR_OK:{
1591 GstPad *sinkpad = g_value_get_object (&sinkpad_value);
1594 GST_INFO_OBJECT (GST_AGGREGATOR_SRC_PAD (agg), "forwarding");
1595 tmp = gst_pad_push_event (sinkpad, gst_event_ref (event));
1596 GST_INFO_OBJECT (mux, "result %d", tmp);
1597 /* succeed if at least one pad succeeds */
1601 case GST_ITERATOR_DONE:
1604 case GST_ITERATOR_RESYNC:
1605 gst_iterator_resync (iter);
1607 case GST_ITERATOR_ERROR:
1608 g_assert_not_reached ();
1611 g_value_reset (&sinkpad_value);
1613 g_value_unset (&sinkpad_value);
1614 gst_iterator_free (iter);
1622 res = agg_class->src_event (agg, event);
1624 gst_event_unref (event);
1630 gst_base_ts_mux_clip (GstAggregator * agg,
1631 GstAggregatorPad * agg_pad, GstBuffer * buf)
1633 GstBaseTsMuxPad *pad = GST_BASE_TS_MUX_PAD (agg_pad);
1640 time = GST_BUFFER_PTS (buf);
1642 /* invalid left alone and passed */
1643 if (G_LIKELY (GST_CLOCK_TIME_IS_VALID (time))) {
1645 gst_segment_to_running_time (&agg_pad->segment, GST_FORMAT_TIME, time);
1646 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (time))) {
1647 GST_DEBUG_OBJECT (pad, "clipping buffer on pad outside segment");
1648 gst_buffer_unref (buf);
1652 GST_LOG_OBJECT (pad, "buffer pts %" GST_TIME_FORMAT " -> %"
1653 GST_TIME_FORMAT " running time",
1654 GST_TIME_ARGS (GST_BUFFER_PTS (buf)), GST_TIME_ARGS (time));
1655 buf = ret = gst_buffer_make_writable (buf);
1656 GST_BUFFER_PTS (ret) = time;
1661 time = GST_BUFFER_DTS (buf);
1663 /* invalid left alone and passed */
1664 if (G_LIKELY (GST_CLOCK_TIME_IS_VALID (time))) {
1668 sign = gst_segment_to_running_time_full (&agg_pad->segment, GST_FORMAT_TIME,
1672 dts = (gint64) time;
1674 dts = -((gint64) time);
1676 GST_LOG_OBJECT (pad, "buffer dts %" GST_TIME_FORMAT " -> %"
1677 GST_STIME_FORMAT " running time", GST_TIME_ARGS (GST_BUFFER_DTS (buf)),
1678 GST_STIME_ARGS (dts));
1680 if (GST_CLOCK_STIME_IS_VALID (pad->dts) && dts < pad->dts) {
1681 /* Ignore DTS going backward */
1682 GST_WARNING_OBJECT (pad, "ignoring DTS going backward");
1686 ret = gst_buffer_make_writable (buf);
1688 GST_BUFFER_DTS (ret) = time;
1690 GST_BUFFER_DTS (ret) = GST_CLOCK_TIME_NONE;
1694 pad->dts = GST_CLOCK_STIME_NONE;
1701 static GstFlowReturn
1702 gst_base_ts_mux_update_src_caps (GstAggregator * agg, GstCaps * caps,
1705 GstBaseTsMux *mux = GST_BASE_TS_MUX (agg);
1708 *ret = gst_caps_copy (caps);
1709 s = gst_caps_get_structure (*ret, 0);
1710 gst_structure_set (s, "packetsize", G_TYPE_INT, mux->packet_size, NULL);
1715 static GstBaseTsMuxPad *
1716 gst_base_ts_mux_find_best_pad (GstAggregator * aggregator)
1718 GstBaseTsMuxPad *best = NULL;
1719 GstClockTime best_ts = GST_CLOCK_TIME_NONE;
1722 GST_OBJECT_LOCK (aggregator);
1724 for (l = GST_ELEMENT_CAST (aggregator)->sinkpads; l; l = l->next) {
1725 GstBaseTsMuxPad *tpad = GST_BASE_TS_MUX_PAD (l->data);
1726 GstAggregatorPad *apad = GST_AGGREGATOR_PAD_CAST (tpad);
1729 buffer = gst_aggregator_pad_peek_buffer (apad);
1732 if (best_ts == GST_CLOCK_TIME_NONE) {
1734 best_ts = GST_BUFFER_DTS_OR_PTS (buffer);
1735 } else if (GST_BUFFER_DTS_OR_PTS (buffer) != GST_CLOCK_TIME_NONE) {
1736 GstClockTime t = GST_BUFFER_DTS_OR_PTS (buffer);
1742 gst_buffer_unref (buffer);
1746 gst_object_ref (best);
1748 GST_OBJECT_UNLOCK (aggregator);
1750 GST_DEBUG_OBJECT (aggregator,
1751 "Best pad found with %" GST_TIME_FORMAT ": %" GST_PTR_FORMAT,
1752 GST_TIME_ARGS (best_ts), best);
1758 gst_base_ts_mux_are_all_pads_eos (GstBaseTsMux * mux)
1761 gboolean ret = TRUE;
1763 GST_OBJECT_LOCK (mux);
1765 for (l = GST_ELEMENT_CAST (mux)->sinkpads; l; l = l->next) {
1766 GstBaseTsMuxPad *pad = GST_BASE_TS_MUX_PAD (l->data);
1768 if (!gst_aggregator_pad_is_eos (GST_AGGREGATOR_PAD (pad))) {
1774 GST_OBJECT_UNLOCK (mux);
1780 static GstFlowReturn
1781 gst_base_ts_mux_aggregate (GstAggregator * agg, gboolean timeout)
1783 GstBaseTsMux *mux = GST_BASE_TS_MUX (agg);
1784 GstFlowReturn ret = GST_FLOW_OK;
1785 GstBaseTsMuxPad *best = gst_base_ts_mux_find_best_pad (agg);
1790 buffer = gst_aggregator_pad_pop_buffer (GST_AGGREGATOR_PAD (best));
1793 gst_base_ts_mux_aggregate_buffer (GST_BASE_TS_MUX (agg),
1794 GST_AGGREGATOR_PAD (best), buffer);
1796 gst_object_unref (best);
1798 if (ret != GST_FLOW_OK)
1802 if (gst_base_ts_mux_are_all_pads_eos (mux)) {
1803 GstBaseTsMuxClass *klass = GST_BASE_TS_MUX_GET_CLASS (mux);
1804 /* drain some possibly cached data */
1807 gst_base_ts_mux_push_packets (mux, TRUE);
1817 gst_base_ts_mux_start (GstAggregator * agg)
1819 gst_base_ts_mux_reset (GST_BASE_TS_MUX (agg), TRUE);
1825 gst_base_ts_mux_stop (GstAggregator * agg)
1827 gst_base_ts_mux_reset (GST_BASE_TS_MUX (agg), TRUE);
1832 /* GObject implementation */
1835 gst_base_ts_mux_dispose (GObject * object)
1837 GstBaseTsMux *mux = GST_BASE_TS_MUX (object);
1839 gst_base_ts_mux_reset (mux, FALSE);
1841 if (mux->out_adapter) {
1842 g_object_unref (mux->out_adapter);
1843 mux->out_adapter = NULL;
1845 if (mux->prog_map) {
1846 gst_structure_free (mux->prog_map);
1847 mux->prog_map = NULL;
1849 if (mux->programs) {
1850 g_hash_table_destroy (mux->programs);
1851 mux->programs = NULL;
1853 GST_CALL_PARENT (G_OBJECT_CLASS, dispose, (object));
1857 gst_base_ts_mux_constructed (GObject * object)
1859 GstBaseTsMux *mux = GST_BASE_TS_MUX (object);
1862 gst_base_ts_mux_reset (mux, TRUE);
1866 gst_base_ts_mux_set_property (GObject * object, guint prop_id,
1867 const GValue * value, GParamSpec * pspec)
1869 GstBaseTsMux *mux = GST_BASE_TS_MUX (object);
1875 const GstStructure *s = gst_value_get_structure (value);
1876 if (mux->prog_map) {
1877 gst_structure_free (mux->prog_map);
1880 mux->prog_map = gst_structure_copy (s);
1882 mux->prog_map = NULL;
1885 case PROP_PAT_INTERVAL:
1886 mux->pat_interval = g_value_get_uint (value);
1888 tsmux_set_pat_interval (mux->tsmux, mux->pat_interval);
1890 case PROP_PMT_INTERVAL:
1891 mux->pmt_interval = g_value_get_uint (value);
1892 GST_OBJECT_LOCK (mux);
1893 for (l = GST_ELEMENT_CAST (mux)->sinkpads; l; l = l->next) {
1894 GstBaseTsMuxPad *ts_pad = GST_BASE_TS_MUX_PAD (l->data);
1896 tsmux_set_pmt_interval (ts_pad->prog, mux->pmt_interval);
1898 GST_OBJECT_UNLOCK (mux);
1900 case PROP_ALIGNMENT:
1901 mux->alignment = g_value_get_int (value);
1903 case PROP_SI_INTERVAL:
1904 mux->si_interval = g_value_get_uint (value);
1905 tsmux_set_si_interval (mux->tsmux, mux->si_interval);
1908 mux->bitrate = g_value_get_uint64 (value);
1910 tsmux_set_bitrate (mux->tsmux, mux->bitrate);
1912 case PROP_PCR_INTERVAL:
1913 mux->pcr_interval = g_value_get_uint (value);
1915 tsmux_set_pcr_interval (mux->tsmux, mux->pcr_interval);
1917 case PROP_SCTE_35_PID:
1918 mux->scte35_pid = g_value_get_uint (value);
1920 case PROP_SCTE_35_NULL_INTERVAL:
1921 mux->scte35_null_interval = g_value_get_uint (value);
1924 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1930 gst_base_ts_mux_get_property (GObject * object, guint prop_id,
1931 GValue * value, GParamSpec * pspec)
1933 GstBaseTsMux *mux = GST_BASE_TS_MUX (object);
1937 gst_value_set_structure (value, mux->prog_map);
1939 case PROP_PAT_INTERVAL:
1940 g_value_set_uint (value, mux->pat_interval);
1942 case PROP_PMT_INTERVAL:
1943 g_value_set_uint (value, mux->pmt_interval);
1945 case PROP_ALIGNMENT:
1946 g_value_set_int (value, mux->alignment);
1948 case PROP_SI_INTERVAL:
1949 g_value_set_uint (value, mux->si_interval);
1952 g_value_set_uint64 (value, mux->bitrate);
1954 case PROP_PCR_INTERVAL:
1955 g_value_set_uint (value, mux->pcr_interval);
1957 case PROP_SCTE_35_PID:
1958 g_value_set_uint (value, mux->scte35_pid);
1960 case PROP_SCTE_35_NULL_INTERVAL:
1961 g_value_set_uint (value, mux->scte35_null_interval);
1964 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1969 /* Default vmethods implementation */
1972 gst_base_ts_mux_default_create_ts_mux (GstBaseTsMux * mux)
1974 TsMux *tsmux = tsmux_new ();
1975 tsmux_set_write_func (tsmux, new_packet_cb, mux);
1976 tsmux_set_alloc_func (tsmux, alloc_packet_cb, mux);
1977 tsmux_set_pat_interval (tsmux, mux->pat_interval);
1978 tsmux_set_si_interval (tsmux, mux->si_interval);
1979 tsmux_set_bitrate (tsmux, mux->bitrate);
1980 tsmux_set_pcr_interval (tsmux, mux->pcr_interval);
1986 gst_base_ts_mux_default_allocate_packet (GstBaseTsMux * mux,
1987 GstBuffer ** buffer)
1991 buf = gst_buffer_new_and_alloc (mux->packet_size);
1997 gst_base_ts_mux_default_output_packet (GstBaseTsMux * mux, GstBuffer * buffer,
2000 gst_base_ts_mux_collect_packet (mux, buffer);
2008 gst_base_ts_mux_set_packet_size (GstBaseTsMux * mux, gsize size)
2010 mux->packet_size = size;
2014 gst_base_ts_mux_set_automatic_alignment (GstBaseTsMux * mux, gsize alignment)
2016 mux->automatic_alignment = alignment;
2020 gst_base_ts_mux_class_init (GstBaseTsMuxClass * klass)
2022 GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
2023 GstAggregatorClass *gstagg_class = GST_AGGREGATOR_CLASS (klass);
2024 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
2026 GST_DEBUG_CATEGORY_INIT (gst_base_ts_mux_debug, "basetsmux", 0,
2027 "MPEG Transport Stream muxer");
2029 gst_element_class_set_static_metadata (gstelement_class,
2030 "MPEG Transport Stream Muxer", "Codec/Muxer",
2031 "Multiplexes media streams into an MPEG Transport Stream",
2032 "Fluendo <contact@fluendo.com>");
2034 gobject_class->set_property =
2035 GST_DEBUG_FUNCPTR (gst_base_ts_mux_set_property);
2036 gobject_class->get_property =
2037 GST_DEBUG_FUNCPTR (gst_base_ts_mux_get_property);
2038 gobject_class->dispose = gst_base_ts_mux_dispose;
2039 gobject_class->constructed = gst_base_ts_mux_constructed;
2041 gstelement_class->request_new_pad = gst_base_ts_mux_request_new_pad;
2042 gstelement_class->release_pad = gst_base_ts_mux_release_pad;
2043 gstelement_class->send_event = gst_base_ts_mux_send_event;
2045 gstagg_class->update_src_caps = gst_base_ts_mux_update_src_caps;
2046 gstagg_class->aggregate = gst_base_ts_mux_aggregate;
2047 gstagg_class->clip = gst_base_ts_mux_clip;
2048 gstagg_class->sink_event = gst_base_ts_mux_sink_event;
2049 gstagg_class->src_event = gst_base_ts_mux_src_event;
2050 gstagg_class->start = gst_base_ts_mux_start;
2051 gstagg_class->stop = gst_base_ts_mux_stop;
2053 klass->create_ts_mux = gst_base_ts_mux_default_create_ts_mux;
2054 klass->allocate_packet = gst_base_ts_mux_default_allocate_packet;
2055 klass->output_packet = gst_base_ts_mux_default_output_packet;
2057 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_PROG_MAP,
2058 g_param_spec_boxed ("prog-map", "Program map",
2059 "A GstStructure specifies the mapping from elementary streams to programs",
2061 (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
2063 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_PAT_INTERVAL,
2064 g_param_spec_uint ("pat-interval", "PAT interval",
2065 "Set the interval (in ticks of the 90kHz clock) for writing out the PAT table",
2066 1, G_MAXUINT, TSMUX_DEFAULT_PAT_INTERVAL,
2067 (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
2069 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_PMT_INTERVAL,
2070 g_param_spec_uint ("pmt-interval", "PMT interval",
2071 "Set the interval (in ticks of the 90kHz clock) for writing out the PMT table",
2072 1, G_MAXUINT, TSMUX_DEFAULT_PMT_INTERVAL,
2073 (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
2075 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_ALIGNMENT,
2076 g_param_spec_int ("alignment", "packet alignment",
2077 "Number of packets per buffer (padded with dummy packets on EOS) "
2078 "(-1 = auto, 0 = all available packets, 7 for UDP streaming)",
2079 -1, G_MAXINT, BASETSMUX_DEFAULT_ALIGNMENT,
2080 (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
2082 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_SI_INTERVAL,
2083 g_param_spec_uint ("si-interval", "SI interval",
2084 "Set the interval (in ticks of the 90kHz clock) for writing out the Service"
2085 "Information tables", 1, G_MAXUINT, TSMUX_DEFAULT_SI_INTERVAL,
2086 (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
2088 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_BITRATE,
2089 g_param_spec_uint64 ("bitrate", "Bitrate (in bits per second)",
2090 "Set the target bitrate, will insert null packets as padding "
2091 " to achieve multiplex-wide constant bitrate (0 means no padding)",
2092 0, G_MAXUINT64, TSMUX_DEFAULT_BITRATE,
2093 (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
2095 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_PCR_INTERVAL,
2096 g_param_spec_uint ("pcr-interval", "PCR interval",
2097 "Set the interval (in ticks of the 90kHz clock) for writing PCR",
2098 1, G_MAXUINT, TSMUX_DEFAULT_PCR_INTERVAL,
2099 (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
2101 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_SCTE_35_PID,
2102 g_param_spec_uint ("scte-35-pid", "SCTE-35 PID",
2103 "PID to use for inserting SCTE-35 packets (0: unused)",
2104 0, G_MAXUINT, DEFAULT_SCTE_35_PID,
2105 (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
2107 g_object_class_install_property (G_OBJECT_CLASS (klass),
2108 PROP_SCTE_35_NULL_INTERVAL, g_param_spec_uint ("scte-35-null-interval",
2109 "SCTE-35 NULL packet interval",
2110 "Set the interval (in ticks of the 90kHz clock) for writing SCTE-35 NULL (heartbeat) packets."
2111 " (only valid if scte-35-pid is different from 0)", 1, G_MAXUINT,
2112 TSMUX_DEFAULT_SCTE_35_NULL_INTERVAL,
2113 (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
2115 gst_element_class_add_static_pad_template_with_gtype (gstelement_class,
2116 &gst_base_ts_mux_src_factory, GST_TYPE_AGGREGATOR_PAD);
2118 gst_type_mark_as_plugin_api (GST_TYPE_BASE_TS_MUX_PAD, 0);
2122 gst_base_ts_mux_init (GstBaseTsMux * mux)
2124 mux->out_adapter = gst_adapter_new ();
2127 mux->pat_interval = TSMUX_DEFAULT_PAT_INTERVAL;
2128 mux->pmt_interval = TSMUX_DEFAULT_PMT_INTERVAL;
2129 mux->si_interval = TSMUX_DEFAULT_SI_INTERVAL;
2130 mux->pcr_interval = TSMUX_DEFAULT_PCR_INTERVAL;
2131 mux->prog_map = NULL;
2132 mux->alignment = BASETSMUX_DEFAULT_ALIGNMENT;
2133 mux->bitrate = TSMUX_DEFAULT_BITRATE;
2134 mux->scte35_pid = DEFAULT_SCTE_35_PID;
2135 mux->scte35_null_interval = TSMUX_DEFAULT_SCTE_35_NULL_INTERVAL;
2137 mux->packet_size = GST_BASE_TS_MUX_NORMAL_PACKET_LENGTH;
2138 mux->automatic_alignment = 0;