2 * Copyright 2006, 2007, 2008, 2009, 2010 Fluendo S.A.
3 * Authors: Jan Schmidt <jan@fluendo.com>
4 * Kapil Agrawal <kapil@fluendo.com>
5 * Julien Moutte <julien@fluendo.com>
7 * Copyright (C) 2011 Jan Schmidt <thaytan@noraisin.net>
9 * This library is licensed under 3 different licenses and you
10 * can choose to use it under the terms of any one of them. The
11 * three licenses are the MPL 1.1, the LGPL and the MIT license.
15 * The contents of this file are subject to the Mozilla Public License
16 * Version 1.1 (the "License"); you may not use this file except in
17 * compliance with the License. You may obtain a copy of the License at
18 * http://www.mozilla.org/MPL/.
20 * Software distributed under the License is distributed on an "AS IS"
21 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
22 * License for the specific language governing rights and limitations
27 * This library is free software; you can redistribute it and/or
28 * modify it under the terms of the GNU Library General Public
29 * License as published by the Free Software Foundation; either
30 * version 2 of the License, or (at your option) any later version.
32 * This library is distributed in the hope that it will be useful,
33 * but WITHOUT ANY WARRANTY; without even the implied warranty of
34 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
35 * Library General Public License for more details.
37 * You should have received a copy of the GNU Library General Public
38 * License along with this library; if not, write to the
39 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
40 * Boston, MA 02110-1301, USA.
44 * Unless otherwise indicated, Source Code is licensed under MIT license.
45 * See further explanation attached in License Statement (distributed in the file
48 * Permission is hereby granted, free of charge, to any person obtaining a copy of
49 * this software and associated documentation files (the "Software"), to deal in
50 * the Software without restriction, including without limitation the rights to
51 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
52 * of the Software, and to permit persons to whom the Software is furnished to do
53 * so, subject to the following conditions:
55 * The above copyright notice and this permission notice shall be included in all
56 * copies or substantial portions of the Software.
58 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
59 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
60 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
61 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
62 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
63 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
66 * SPDX-License-Identifier: MPL-1.1 OR MIT OR LGPL-2.0-or-later
72 #include <gst/tag/tag.h>
73 #include <gst/video/video.h>
74 #include <gst/mpegts/mpegts.h>
75 #include <gst/pbutils/pbutils.h>
76 #include <gst/videoparsers/gstjpeg2000parse.h>
77 #include <gst/video/video-color.h>
79 #include "gstbasetsmux.h"
80 #include "gstbasetsmuxaac.h"
81 #include "gstbasetsmuxttxt.h"
82 #include "gstbasetsmuxopus.h"
83 #include "gstbasetsmuxjpeg2000.h"
85 GST_DEBUG_CATEGORY (gst_base_ts_mux_debug);
86 #define GST_CAT_DEFAULT gst_base_ts_mux_debug
90 G_DEFINE_TYPE (GstBaseTsMuxPad, gst_base_ts_mux_pad, GST_TYPE_AGGREGATOR_PAD);
95 gst_base_ts_mux_pad_reset (GstBaseTsMuxPad * pad)
97 pad->dts = GST_CLOCK_STIME_NONE;
101 pad->free_func (pad->prepare_data);
102 pad->prepare_data = NULL;
103 pad->prepare_func = NULL;
104 pad->free_func = NULL;
107 gst_buffer_replace (&pad->codec_data, NULL);
109 /* reference owned elsewhere */
114 g_free (pad->language);
115 pad->language = NULL;
119 /* GstAggregatorPad implementation */
122 gst_base_ts_mux_pad_flush (GstAggregatorPad * agg_pad, GstAggregator * agg)
125 GstBaseTsMux *mux = GST_BASE_TS_MUX (agg);
127 /* Send initial segments again after a flush-stop, and also resend the
131 /* output PAT, SI tables */
132 tsmux_resend_pat (mux->tsmux);
133 tsmux_resend_si (mux->tsmux);
135 /* output PMT for each program */
136 for (cur = mux->tsmux->programs; cur; cur = cur->next) {
137 TsMuxProgram *program = (TsMuxProgram *) cur->data;
139 tsmux_resend_pmt (program);
145 /* GObject implementation */
148 gst_base_ts_mux_pad_dispose (GObject * obj)
150 GstBaseTsMuxPad *ts_pad = GST_BASE_TS_MUX_PAD (obj);
152 gst_base_ts_mux_pad_reset (ts_pad);
154 G_OBJECT_CLASS (gst_base_ts_mux_pad_parent_class)->dispose (obj);
158 gst_base_ts_mux_pad_class_init (GstBaseTsMuxPadClass * klass)
160 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
161 GstAggregatorPadClass *gstaggpad_class = GST_AGGREGATOR_PAD_CLASS (klass);
163 gobject_class->dispose = gst_base_ts_mux_pad_dispose;
164 gstaggpad_class->flush = gst_base_ts_mux_pad_flush;
166 gst_type_mark_as_plugin_api (GST_TYPE_BASE_TS_MUX, 0);
170 gst_base_ts_mux_pad_init (GstBaseTsMuxPad * vaggpad)
187 PROP_SCTE_35_NULL_INTERVAL
190 #define DEFAULT_SCTE_35_PID 0
192 #define BASETSMUX_DEFAULT_ALIGNMENT -1
194 #define CLOCK_BASE 9LL
195 #define CLOCK_FREQ (CLOCK_BASE * 10000) /* 90 kHz PTS clock */
196 #define CLOCK_FREQ_SCR (CLOCK_FREQ * 300) /* 27 MHz SCR clock */
197 #define TS_MUX_CLOCK_BASE (TSMUX_CLOCK_FREQ * 10 * 360)
199 #define GSTTIME_TO_MPEGTIME(time) \
200 (((time) > 0 ? (gint64) 1 : (gint64) -1) * \
201 (gint64) gst_util_uint64_scale (ABS(time), CLOCK_BASE, GST_MSECOND/10))
202 /* 27 MHz SCR conversions: */
203 #define MPEG_SYS_TIME_TO_GSTTIME(time) (gst_util_uint64_scale ((time), \
204 GST_USECOND, CLOCK_FREQ_SCR / 1000000))
205 #define GSTTIME_TO_MPEG_SYS_TIME(time) (gst_util_uint64_scale ((time), \
206 CLOCK_FREQ_SCR / 1000000, GST_USECOND))
208 #define DEFAULT_PROG_ID 0
210 static GstStaticPadTemplate gst_base_ts_mux_src_factory =
211 GST_STATIC_PAD_TEMPLATE ("src",
214 GST_STATIC_CAPS ("video/mpegts, "
215 "systemstream = (boolean) true, " "packetsize = (int) { 188, 192} ")
224 G_DEFINE_TYPE_WITH_CODE (GstBaseTsMux, gst_base_ts_mux, GST_TYPE_AGGREGATOR,
225 gst_mpegts_initialize ());
229 /* Takes over the ref on the buffer */
231 stream_data_new (GstBuffer * buffer)
233 StreamData *res = g_new (StreamData, 1);
234 res->buffer = buffer;
235 gst_buffer_map (buffer, &(res->map_info), GST_MAP_READ);
241 stream_data_free (StreamData * data)
244 gst_buffer_unmap (data->buffer, &data->map_info);
245 gst_buffer_unref (data->buffer);
250 #define parent_class gst_base_ts_mux_parent_class
253 gst_base_ts_mux_set_header_on_caps (GstBaseTsMux * mux)
256 GstStructure *structure;
257 GValue array = { 0 };
258 GValue value = { 0 };
261 caps = gst_pad_get_current_caps (GST_AGGREGATOR_SRC_PAD (mux));
263 /* If we have no caps, we are possibly shutting down */
267 caps = gst_caps_make_writable (caps);
268 structure = gst_caps_get_structure (caps, 0);
270 g_value_init (&array, GST_TYPE_ARRAY);
272 GST_LOG_OBJECT (mux, "setting %u packets into streamheader",
273 g_queue_get_length (&mux->streamheader));
275 while ((buf = GST_BUFFER (g_queue_pop_head (&mux->streamheader)))) {
276 g_value_init (&value, GST_TYPE_BUFFER);
277 gst_value_take_buffer (&value, buf);
278 gst_value_array_append_value (&array, &value);
279 g_value_unset (&value);
282 gst_structure_set_value (structure, "streamheader", &array);
283 gst_aggregator_set_src_caps (GST_AGGREGATOR (mux), caps);
284 g_value_unset (&array);
285 gst_caps_unref (caps);
289 steal_si_section (GstMpegtsSectionType * type, TsMuxSection * section,
292 g_hash_table_insert (mux->si_sections, type, section);
298 gst_base_ts_mux_reset (GstBaseTsMux * mux, gboolean alloc)
301 GstBaseTsMuxClass *klass = GST_BASE_TS_MUX_GET_CLASS (mux);
302 GHashTable *si_sections = NULL;
306 mux->last_flow_ret = GST_FLOW_OK;
308 mux->is_delta = TRUE;
309 mux->is_header = FALSE;
311 mux->streamheader_sent = FALSE;
312 mux->pending_key_unit_ts = GST_CLOCK_TIME_NONE;
313 gst_event_replace (&mux->force_key_unit_event, NULL);
315 if (mux->out_adapter)
316 gst_adapter_clear (mux->out_adapter);
317 mux->output_ts_offset = GST_CLOCK_TIME_NONE;
320 if (mux->tsmux->si_sections)
321 si_sections = g_hash_table_ref (mux->tsmux->si_sections);
323 tsmux_free (mux->tsmux);
328 g_hash_table_destroy (mux->programs);
330 mux->programs = g_hash_table_new (g_direct_hash, g_direct_equal);
332 while ((buf = GST_BUFFER (g_queue_pop_head (&mux->streamheader))))
333 gst_buffer_unref (buf);
335 gst_event_replace (&mux->force_key_unit_event, NULL);
336 gst_buffer_replace (&mux->out_buffer, NULL);
338 GST_OBJECT_LOCK (mux);
340 for (l = GST_ELEMENT (mux)->sinkpads; l; l = l->next) {
341 gst_base_ts_mux_pad_reset (GST_BASE_TS_MUX_PAD (l->data));
344 GST_OBJECT_UNLOCK (mux);
347 g_assert (klass->create_ts_mux);
349 mux->tsmux = klass->create_ts_mux (mux);
351 /* Preserve user-specified sections across resets */
353 g_hash_table_foreach_steal (si_sections, (GHRFunc) steal_si_section,
358 g_hash_table_unref (si_sections);
360 mux->last_scte35_event_seqnum = GST_SEQNUM_INVALID;
367 release_buffer_cb (guint8 * data, void *user_data)
369 stream_data_free ((StreamData *) user_data);
373 gst_base_ts_mux_create_stream (GstBaseTsMux * mux, GstBaseTsMuxPad * ts_pad)
375 GstFlowReturn ret = GST_FLOW_ERROR;
379 guint st = TSMUX_ST_RESERVED;
381 const GValue *value = NULL;
382 GstBuffer *codec_data = NULL;
383 guint8 opus_channel_config_code = 0;
384 guint16 profile = GST_JPEG2000_PARSE_PROFILE_NONE;
385 guint8 main_level = 0;
386 guint32 max_rate = 0;
387 guint8 color_spec = 0;
388 j2k_private_data *private_data = NULL;
389 const gchar *stream_format = NULL;
391 pad = GST_PAD (ts_pad);
392 caps = gst_pad_get_current_caps (pad);
396 GST_DEBUG_OBJECT (pad, "Creating stream with PID 0x%04x for caps %"
397 GST_PTR_FORMAT, ts_pad->pid, caps);
399 s = gst_caps_get_structure (caps, 0);
401 mt = gst_structure_get_name (s);
402 value = gst_structure_get_value (s, "codec_data");
404 codec_data = gst_value_get_buffer (value);
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 (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 (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");
477 GST_WARNING_OBJECT (pad, "unsupported mpegversion %d", mpegversion);
480 } else if (strcmp (mt, "video/mpeg") == 0) {
483 if (!gst_structure_get_int (s, "mpegversion", &mpegversion)) {
484 GST_ERROR_OBJECT (pad, "caps missing mpegversion");
488 switch (mpegversion) {
490 st = TSMUX_ST_VIDEO_MPEG1;
493 st = TSMUX_ST_VIDEO_MPEG2;
496 st = TSMUX_ST_VIDEO_MPEG4;
499 GST_WARNING_OBJECT (pad, "unsupported mpegversion %d", mpegversion);
502 } else if (strcmp (mt, "subpicture/x-dvb") == 0) {
503 st = TSMUX_ST_PS_DVB_SUBPICTURE;
504 } else if (strcmp (mt, "application/x-teletext") == 0) {
505 st = TSMUX_ST_PS_TELETEXT;
506 /* needs a particularly sized layout */
507 ts_pad->prepare_func = gst_base_ts_mux_prepare_teletext;
508 } else if (strcmp (mt, "audio/x-opus") == 0) {
509 guint8 channels, mapping_family, stream_count, coupled_count;
510 guint8 channel_mapping[256];
512 if (!gst_codec_utils_opus_parse_caps (caps, NULL, &channels,
513 &mapping_family, &stream_count, &coupled_count, channel_mapping)) {
514 GST_ERROR_OBJECT (pad, "Incomplete Opus caps");
518 if (channels <= 2 && mapping_family == 0) {
519 opus_channel_config_code = channels;
520 } else if (channels == 2 && mapping_family == 255 && stream_count == 1
521 && coupled_count == 1) {
523 opus_channel_config_code = 0;
524 } else if (channels >= 2 && channels <= 8 && mapping_family == 1) {
525 static const guint8 coupled_stream_counts[9] = {
526 1, 0, 1, 1, 2, 2, 2, 3, 3
528 static const guint8 channel_map_a[8][8] = {
535 {0, 4, 1, 2, 3, 5, 6},
536 {0, 6, 1, 2, 3, 4, 5, 7},
538 static const guint8 channel_map_b[8][8] = {
545 {0, 1, 2, 3, 4, 5, 6},
546 {0, 1, 2, 3, 4, 5, 6, 7},
550 if (stream_count == channels - coupled_stream_counts[channels] &&
551 coupled_count == coupled_stream_counts[channels] &&
552 memcmp (channel_mapping, channel_map_a[channels - 1],
554 opus_channel_config_code = channels;
555 } else if (stream_count == channels - coupled_stream_counts[channels] &&
556 coupled_count == coupled_stream_counts[channels] &&
557 memcmp (channel_mapping, channel_map_b[channels - 1],
559 opus_channel_config_code = channels | 0x80;
561 GST_FIXME_OBJECT (pad, "Opus channel mapping not handled");
566 st = TSMUX_ST_PS_OPUS;
567 ts_pad->prepare_func = gst_base_ts_mux_prepare_opus;
568 } else if (strcmp (mt, "meta/x-klv") == 0) {
569 st = TSMUX_ST_PS_KLV;
570 } else if (strcmp (mt, "image/x-jpc") == 0) {
572 * See this document for more details on standard:
574 * https://www.itu.int/rec/T-REC-H.222.0-201206-S/en
575 * Annex S describes J2K details
576 * Page 104 of this document describes J2k video descriptor
579 const GValue *vProfile = gst_structure_get_value (s, "profile");
580 const GValue *vMainlevel = gst_structure_get_value (s, "main-level");
581 const GValue *vFramerate = gst_structure_get_value (s, "framerate");
582 const GValue *vColorimetry = gst_structure_get_value (s, "colorimetry");
583 private_data = g_new0 (j2k_private_data, 1);
584 /* for now, we relax the condition that profile must exist and equal
585 * GST_JPEG2000_PARSE_PROFILE_BC_SINGLE */
587 profile = g_value_get_int (vProfile);
588 if (profile != GST_JPEG2000_PARSE_PROFILE_BC_SINGLE) {
589 GST_LOG_OBJECT (pad, "Invalid JPEG 2000 profile %d", profile);
590 /*goto not_negotiated; */
593 /* for now, we will relax the condition that the main level must be present */
595 main_level = g_value_get_uint (vMainlevel);
596 if (main_level > 11) {
597 GST_ERROR_OBJECT (pad, "Invalid main level %d", main_level);
600 if (main_level >= 6) {
601 max_rate = 2 ^ (main_level - 6) * 1600 * 1000000;
603 switch (main_level) {
608 max_rate = 200 * 1000000;
611 max_rate = 400 * 1000000;
614 max_rate = 800 * 1000000;
621 /*GST_ERROR_OBJECT (pad, "Missing main level");
622 goto not_negotiated; */
624 /* We always mux video in J2K-over-MPEG-TS non-interlaced mode */
625 private_data->interlace = FALSE;
626 private_data->den = 0;
627 private_data->num = 0;
628 private_data->max_bitrate = max_rate;
629 private_data->color_spec = 1;
630 /* these two fields are not used, since we always mux as non-interlaced */
631 private_data->Fic = 1;
632 private_data->Fio = 0;
635 if (vFramerate != NULL) {
636 /* Data for ELSM header */
637 private_data->num = gst_value_get_fraction_numerator (vFramerate);
638 private_data->den = gst_value_get_fraction_denominator (vFramerate);
640 /* Get Colorimetry */
642 const char *colorimetry = g_value_get_string (vColorimetry);
643 color_spec = GST_MPEGTS_JPEG2000_COLORSPEC_SRGB; /* RGB as default */
644 if (g_str_equal (colorimetry, GST_VIDEO_COLORIMETRY_BT601)) {
645 color_spec = GST_MPEGTS_JPEG2000_COLORSPEC_REC601;
647 if (g_str_equal (colorimetry, GST_VIDEO_COLORIMETRY_BT709)
648 || g_str_equal (colorimetry, GST_VIDEO_COLORIMETRY_SMPTE240M)) {
649 color_spec = GST_MPEGTS_JPEG2000_COLORSPEC_REC709;
652 private_data->color_spec = color_spec;
654 GST_ERROR_OBJECT (pad, "Colorimetry not present in caps");
657 st = TSMUX_ST_VIDEO_JP2K;
658 ts_pad->prepare_func = gst_base_ts_mux_prepare_jpeg2000;
659 ts_pad->prepare_data = private_data;
660 ts_pad->free_func = gst_base_ts_mux_free_jpeg2000;
662 GstBaseTsMuxClass *klass = GST_BASE_TS_MUX_GET_CLASS (mux);
664 if (klass->handle_media_type) {
665 st = klass->handle_media_type (mux, mt, ts_pad);
670 if (st != TSMUX_ST_RESERVED) {
671 ts_pad->stream = tsmux_create_stream (mux->tsmux, st, ts_pad->pid,
674 GST_DEBUG_OBJECT (pad, "Failed to determine stream type");
677 if (ts_pad->stream != NULL) {
678 const char *interlace_mode = gst_structure_get_string (s, "interlace-mode");
679 gst_structure_get_int (s, "rate", &ts_pad->stream->audio_sampling);
680 gst_structure_get_int (s, "channels", &ts_pad->stream->audio_channels);
681 gst_structure_get_int (s, "bitrate", &ts_pad->stream->audio_bitrate);
684 gst_structure_get_fraction (s, "framerate", &ts_pad->stream->num,
685 &ts_pad->stream->den);
688 ts_pad->stream->interlace_mode = FALSE;
689 if (interlace_mode) {
690 ts_pad->stream->interlace_mode =
691 g_str_equal (interlace_mode, "interleaved");
693 /* Width and Height */
694 gst_structure_get_int (s, "width", &ts_pad->stream->horizontal_size);
695 gst_structure_get_int (s, "height", &ts_pad->stream->vertical_size);
697 ts_pad->stream->color_spec = color_spec;
698 ts_pad->stream->max_bitrate = max_rate;
699 ts_pad->stream->profile_and_level = profile | main_level;
701 ts_pad->stream->opus_channel_config_code = opus_channel_config_code;
703 tsmux_stream_set_buffer_release_func (ts_pad->stream, release_buffer_cb);
704 tsmux_program_add_stream (ts_pad->prog, ts_pad->stream);
708 gst_caps_unref (caps);
713 g_free (private_data);
714 GST_DEBUG_OBJECT (pad, "Sink pad caps were not set before pushing");
716 gst_caps_unref (caps);
717 return GST_FLOW_NOT_NEGOTIATED;
722 is_valid_pmt_pid (guint16 pmt_pid)
724 if (pmt_pid < 0x0010 || pmt_pid > 0x1ffe)
730 gst_base_ts_mux_create_pad_stream (GstBaseTsMux * mux, GstPad * pad)
732 GstBaseTsMuxPad *ts_pad = GST_BASE_TS_MUX_PAD (pad);
735 GstFlowReturn ret = GST_FLOW_OK;
737 if (ts_pad->prog_id == -1) {
738 name = GST_PAD_NAME (pad);
739 if (mux->prog_map != NULL && gst_structure_has_field (mux->prog_map, name)) {
741 gboolean ret = gst_structure_get_int (mux->prog_map, name, &idx);
743 GST_ELEMENT_ERROR (mux, STREAM, MUX,
744 ("Reading program map failed. Assuming default"), (NULL));
745 idx = DEFAULT_PROG_ID;
748 GST_DEBUG_OBJECT (mux, "Program number %d associate with pad %s less "
749 "than zero; DEFAULT_PROGRAM = %d is used instead",
750 idx, name, DEFAULT_PROG_ID);
751 idx = DEFAULT_PROG_ID;
753 ts_pad->prog_id = idx;
755 ts_pad->prog_id = DEFAULT_PROG_ID;
760 (TsMuxProgram *) g_hash_table_lookup (mux->programs,
761 GINT_TO_POINTER (ts_pad->prog_id));
762 if (ts_pad->prog == NULL) {
763 ts_pad->prog = tsmux_program_new (mux->tsmux, ts_pad->prog_id);
764 if (ts_pad->prog == NULL)
766 tsmux_set_pmt_interval (ts_pad->prog, mux->pmt_interval);
767 tsmux_program_set_scte35_pid (ts_pad->prog, mux->scte35_pid);
768 tsmux_program_set_scte35_interval (ts_pad->prog, mux->scte35_null_interval);
769 g_hash_table_insert (mux->programs, GINT_TO_POINTER (ts_pad->prog_id),
772 /* Check for user-specified PMT PID */
773 prop_name = g_strdup_printf ("PMT_%d", ts_pad->prog->pgm_number);
774 if (mux->prog_map && gst_structure_has_field (mux->prog_map, prop_name)) {
777 if (gst_structure_get_uint (mux->prog_map, prop_name, &pmt_pid)) {
778 if (is_valid_pmt_pid (pmt_pid)) {
779 GST_DEBUG_OBJECT (mux, "User specified pid=%u as PMT for "
780 "program (prog_id = %d)", pmt_pid, ts_pad->prog->pgm_number);
781 tsmux_program_set_pmt_pid (ts_pad->prog, pmt_pid);
783 GST_ELEMENT_WARNING (mux, LIBRARY, SETTINGS,
784 ("User specified PMT pid %u for program %d is not valid.",
785 pmt_pid, ts_pad->prog->pgm_number), (NULL));
792 if (ts_pad->stream == NULL) {
793 ret = gst_base_ts_mux_create_stream (mux, ts_pad);
794 if (ret != GST_FLOW_OK)
798 if (ts_pad->prog->pcr_stream == NULL) {
799 /* Take the first stream of the program for the PCR */
800 GST_DEBUG_OBJECT (ts_pad,
801 "Use stream (pid=%d) from pad as PCR for program (prog_id = %d)",
802 ts_pad->pid, ts_pad->prog_id);
804 tsmux_program_set_pcr_stream (ts_pad->prog, ts_pad->stream);
807 /* Check for user-specified PCR PID */
808 prop_name = g_strdup_printf ("PCR_%d", ts_pad->prog->pgm_number);
809 if (mux->prog_map && gst_structure_has_field (mux->prog_map, prop_name)) {
810 const gchar *sink_name =
811 gst_structure_get_string (mux->prog_map, prop_name);
813 if (!g_strcmp0 (name, sink_name)) {
814 GST_DEBUG_OBJECT (mux, "User specified stream (pid=%d) as PCR for "
815 "program (prog_id = %d)", ts_pad->pid, ts_pad->prog->pgm_number);
816 tsmux_program_set_pcr_stream (ts_pad->prog, ts_pad->stream);
826 GST_ELEMENT_ERROR (mux, STREAM, MUX,
827 ("Could not create new program"), (NULL));
828 return GST_FLOW_ERROR;
832 GST_ELEMENT_ERROR (mux, STREAM, MUX,
833 ("Could not create handler for stream"), (NULL));
839 gst_base_ts_mux_create_pad_stream_func (GstElement * element, GstPad * pad,
842 GstFlowReturn *ret = user_data;
844 *ret = gst_base_ts_mux_create_pad_stream (GST_BASE_TS_MUX (element), pad);
846 return *ret == GST_FLOW_OK;
850 gst_base_ts_mux_create_streams (GstBaseTsMux * mux)
852 GstFlowReturn ret = GST_FLOW_OK;
854 gst_element_foreach_sink_pad (GST_ELEMENT_CAST (mux),
855 gst_base_ts_mux_create_pad_stream_func, &ret);
861 new_packet_common_init (GstBaseTsMux * mux, GstBuffer * buf, guint8 * data,
864 /* Packets should be at least 188 bytes, but check anyway */
865 g_assert (len >= 2 || !data);
867 if (!mux->streamheader_sent && data) {
868 guint pid = ((data[1] & 0x1f) << 8) | data[2];
869 /* if it's a PAT or a PMT */
870 if (pid == 0x00 || (pid >= TSMUX_START_PMT_PID && pid < TSMUX_START_ES_PID)) {
874 hbuf = gst_buffer_new_and_alloc (len);
875 gst_buffer_fill (hbuf, 0, data, len);
877 hbuf = gst_buffer_copy (buf);
880 "Collecting packet with pid 0x%04x into streamheaders", pid);
882 g_queue_push_tail (&mux->streamheader, hbuf);
883 } else if (!g_queue_is_empty (&mux->streamheader)) {
884 gst_base_ts_mux_set_header_on_caps (mux);
885 mux->streamheader_sent = TRUE;
890 if (mux->is_header) {
891 GST_LOG_OBJECT (mux, "marking as header buffer");
892 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_HEADER);
895 GST_LOG_OBJECT (mux, "marking as delta unit");
896 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
898 GST_DEBUG_OBJECT (mux, "marking as non-delta unit");
899 mux->is_delta = TRUE;
905 gst_base_ts_mux_push_packets (GstBaseTsMux * mux, gboolean force)
907 GstBufferList *buffer_list;
908 gint align = mux->alignment;
909 gint av, packet_size;
911 packet_size = mux->packet_size;
914 align = mux->automatic_alignment;
916 av = gst_adapter_available (mux->out_adapter);
917 GST_LOG_OBJECT (mux, "align %d, av %d", align, av);
922 /* no alignment, just push all available data */
924 buffer_list = gst_adapter_take_buffer_list (mux->out_adapter, av);
925 return gst_aggregator_finish_buffer_list (GST_AGGREGATOR (mux),
929 align *= packet_size;
931 if (!force && align > av)
934 buffer_list = gst_buffer_list_new_sized ((av / align) + 1);
936 GST_LOG_OBJECT (mux, "aligning to %d bytes", align);
937 while (align <= av) {
941 pts = gst_adapter_prev_pts (mux->out_adapter, NULL);
942 buf = gst_adapter_take_buffer (mux->out_adapter, align);
944 GST_BUFFER_PTS (buf) = pts;
946 gst_buffer_list_add (buffer_list, buf);
950 if (av > 0 && force) {
958 GST_LOG_OBJECT (mux, "handling %d leftover bytes", av);
960 pts = gst_adapter_prev_pts (mux->out_adapter, NULL);
961 buf = gst_buffer_new_and_alloc (align);
963 GST_BUFFER_PTS (buf) = pts;
965 gst_buffer_map (buf, &map, GST_MAP_READ);
968 gst_adapter_copy (mux->out_adapter, data, 0, av);
969 gst_adapter_clear (mux->out_adapter);
972 header = GST_READ_UINT32_BE (data - packet_size);
974 dummy = (map.size - av) / packet_size;
975 GST_LOG_OBJECT (mux, "adding %d null packets", dummy);
977 for (; dummy > 0; dummy--) {
980 if (packet_size > GST_BASE_TS_MUX_NORMAL_PACKET_LENGTH) {
981 GST_WRITE_UINT32_BE (data, header);
982 /* simply increase header a bit and never mind too much */
988 GST_WRITE_UINT8 (data + offset, TSMUX_SYNC_BYTE);
989 /* null packet PID */
990 GST_WRITE_UINT16_BE (data + offset + 1, 0x1FFF);
991 /* no adaptation field exists | continuity counter undefined */
992 GST_WRITE_UINT8 (data + offset + 3, 0x10);
994 memset (data + offset + 4, 0, GST_BASE_TS_MUX_NORMAL_PACKET_LENGTH - 4);
998 gst_buffer_unmap (buf, &map);
999 gst_buffer_list_add (buffer_list, buf);
1002 return gst_aggregator_finish_buffer_list (GST_AGGREGATOR (mux), buffer_list);
1005 static GstFlowReturn
1006 gst_base_ts_mux_collect_packet (GstBaseTsMux * mux, GstBuffer * buf)
1008 GST_LOG_OBJECT (mux, "collecting packet size %" G_GSIZE_FORMAT,
1009 gst_buffer_get_size (buf));
1010 gst_adapter_push (mux->out_adapter, buf);
1016 check_pending_key_unit_event (GstEvent * pending_event, GstSegment * segment,
1017 GstClockTime timestamp, guint flags, GstClockTime pending_key_unit_ts)
1019 GstClockTime running_time, stream_time;
1020 gboolean all_headers;
1022 GstEvent *event = NULL;
1024 g_assert (segment != NULL);
1026 if (pending_event == NULL)
1029 if (GST_CLOCK_TIME_IS_VALID (pending_key_unit_ts) &&
1030 timestamp == GST_CLOCK_TIME_NONE)
1033 running_time = timestamp;
1035 GST_INFO ("now %" GST_TIME_FORMAT " wanted %" GST_TIME_FORMAT,
1036 GST_TIME_ARGS (running_time), GST_TIME_ARGS (pending_key_unit_ts));
1037 if (GST_CLOCK_TIME_IS_VALID (pending_key_unit_ts) &&
1038 running_time < pending_key_unit_ts)
1041 if (flags & GST_BUFFER_FLAG_DELTA_UNIT) {
1042 GST_INFO ("pending force key unit, waiting for keyframe");
1046 stream_time = gst_segment_to_stream_time (segment,
1047 GST_FORMAT_TIME, timestamp);
1049 if (GST_EVENT_TYPE (pending_event) == GST_EVENT_CUSTOM_DOWNSTREAM) {
1050 gst_video_event_parse_downstream_force_key_unit (pending_event,
1051 NULL, NULL, NULL, &all_headers, &count);
1053 gst_video_event_parse_upstream_force_key_unit (pending_event, NULL,
1054 &all_headers, &count);
1058 gst_video_event_new_downstream_force_key_unit (timestamp, stream_time,
1059 running_time, all_headers, count);
1060 gst_event_set_seqnum (event, gst_event_get_seqnum (pending_event));
1066 /* Called when the TsMux has prepared a packet for output. Return FALSE
1069 new_packet_cb (GstBuffer * buf, void *user_data, gint64 new_pcr)
1071 GstBaseTsMux *mux = (GstBaseTsMux *) user_data;
1072 GstAggregator *agg = GST_AGGREGATOR (mux);
1073 GstBaseTsMuxClass *klass = GST_BASE_TS_MUX_GET_CLASS (mux);
1075 GstSegment *agg_segment = &GST_AGGREGATOR_PAD (agg->srcpad)->segment;
1077 g_assert (klass->output_packet);
1079 gst_buffer_map (buf, &map, GST_MAP_READWRITE);
1081 if (!GST_CLOCK_TIME_IS_VALID (GST_BUFFER_PTS (buf))) {
1082 /* tsmux isn't generating timestamps. Use the input times */
1083 GST_BUFFER_PTS (buf) = mux->last_ts;
1086 if (GST_CLOCK_TIME_IS_VALID (GST_BUFFER_PTS (buf))) {
1087 if (!GST_CLOCK_TIME_IS_VALID (mux->output_ts_offset)) {
1088 GstClockTime output_start_time = agg_segment->position;
1089 if (agg_segment->position == -1
1090 || agg_segment->position < agg_segment->start) {
1091 output_start_time = agg_segment->start;
1094 mux->output_ts_offset =
1095 GST_CLOCK_DIFF (GST_BUFFER_PTS (buf), output_start_time);
1097 GST_DEBUG_OBJECT (mux, "New output ts offset %" GST_STIME_FORMAT,
1098 GST_STIME_ARGS (mux->output_ts_offset));
1101 if (GST_CLOCK_TIME_IS_VALID (mux->output_ts_offset)) {
1102 GST_BUFFER_PTS (buf) += mux->output_ts_offset;
1106 if (GST_CLOCK_TIME_IS_VALID (GST_BUFFER_PTS (buf))) {
1107 agg_segment->position = GST_BUFFER_PTS (buf);
1110 /* do common init (flags and streamheaders) */
1111 new_packet_common_init (mux, buf, map.data, map.size);
1113 gst_buffer_unmap (buf, &map);
1115 return klass->output_packet (mux, buf, new_pcr);
1118 /* called when TsMux needs new packet to write into */
1120 alloc_packet_cb (GstBuffer ** buf, void *user_data)
1122 GstBaseTsMux *mux = (GstBaseTsMux *) user_data;
1123 GstBaseTsMuxClass *klass = GST_BASE_TS_MUX_GET_CLASS (mux);
1125 g_assert (klass->allocate_packet);
1127 klass->allocate_packet (mux, buf);
1130 static GstFlowReturn
1131 gst_base_ts_mux_aggregate_buffer (GstBaseTsMux * mux,
1132 GstAggregatorPad * agg_pad, GstBuffer * buf)
1134 GstFlowReturn ret = GST_FLOW_OK;
1135 GstBaseTsMuxPad *best = GST_BASE_TS_MUX_PAD (agg_pad);
1137 gint64 pts = GST_CLOCK_STIME_NONE;
1138 gint64 dts = GST_CLOCK_STIME_NONE;
1139 gboolean delta = TRUE, header = FALSE;
1140 StreamData *stream_data;
1141 GstMpegtsSection *scte_section = NULL;
1143 GST_DEBUG_OBJECT (mux, "Pads collected");
1145 if (buf && gst_buffer_get_size (buf) == 0
1146 && GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_GAP)) {
1147 gst_buffer_unref (buf);
1151 if (G_UNLIKELY (mux->first)) {
1152 ret = gst_base_ts_mux_create_streams (mux);
1153 if (G_UNLIKELY (ret != GST_FLOW_OK)) {
1155 gst_buffer_unref (buf);
1166 gst_base_ts_mux_create_pad_stream (mux, GST_PAD (best));
1167 tsmux_resend_pat (mux->tsmux);
1168 tsmux_resend_si (mux->tsmux);
1170 g_assert_nonnull (prog);
1172 /* output PMT for each program */
1173 for (cur = mux->tsmux->programs; cur; cur = cur->next) {
1174 TsMuxProgram *program = (TsMuxProgram *) cur->data;
1176 tsmux_resend_pmt (program);
1180 g_assert (buf != NULL);
1182 if (best->prepare_func) {
1185 tmp = best->prepare_func (buf, best, mux);
1187 gst_buffer_unref (buf);
1191 if (mux->force_key_unit_event != NULL && best->stream->is_video_stream) {
1194 event = check_pending_key_unit_event (mux->force_key_unit_event,
1195 &agg_pad->segment, GST_BUFFER_PTS (buf),
1196 GST_BUFFER_FLAGS (buf), mux->pending_key_unit_ts);
1198 GstClockTime running_time;
1202 mux->pending_key_unit_ts = GST_CLOCK_TIME_NONE;
1203 gst_event_replace (&mux->force_key_unit_event, NULL);
1205 gst_video_event_parse_downstream_force_key_unit (event,
1206 NULL, NULL, &running_time, NULL, &count);
1208 GST_INFO_OBJECT (mux, "pushing downstream force-key-unit event %d "
1209 "%" GST_TIME_FORMAT " count %d", gst_event_get_seqnum (event),
1210 GST_TIME_ARGS (running_time), count);
1211 gst_pad_push_event (GST_AGGREGATOR_SRC_PAD (mux), event);
1213 /* output PAT, SI tables */
1214 tsmux_resend_pat (mux->tsmux);
1215 tsmux_resend_si (mux->tsmux);
1217 /* output PMT for each program */
1218 for (cur = mux->tsmux->programs; cur; cur = cur->next) {
1219 TsMuxProgram *program = (TsMuxProgram *) cur->data;
1221 tsmux_resend_pmt (program);
1226 if (G_UNLIKELY (prog->pcr_stream == NULL)) {
1227 /* Take the first data stream for the PCR */
1228 GST_DEBUG_OBJECT (best,
1229 "Use stream (pid=%d) from pad as PCR for program (prog_id = %d)",
1230 best->pid, best->prog_id);
1232 /* Set the chosen PCR stream */
1233 tsmux_program_set_pcr_stream (prog, best->stream);
1236 GST_DEBUG_OBJECT (best, "Chose stream for output (PID: 0x%04x)", best->pid);
1238 GST_OBJECT_LOCK (mux);
1239 scte_section = mux->pending_scte35_section;
1240 mux->pending_scte35_section = NULL;
1241 GST_OBJECT_UNLOCK (mux);
1242 if (G_UNLIKELY (scte_section)) {
1243 GST_DEBUG_OBJECT (mux, "Sending pending SCTE section");
1244 if (!tsmux_send_section (mux->tsmux, scte_section))
1245 GST_ERROR_OBJECT (mux, "Error sending SCTE section !");
1248 if (GST_CLOCK_TIME_IS_VALID (GST_BUFFER_PTS (buf))) {
1249 pts = GSTTIME_TO_MPEGTIME (GST_BUFFER_PTS (buf));
1250 GST_DEBUG_OBJECT (mux, "Buffer has PTS %" GST_TIME_FORMAT " pts %"
1251 G_GINT64_FORMAT "%s", GST_TIME_ARGS (GST_BUFFER_PTS (buf)), pts,
1252 !GST_BUFFER_FLAG_IS_SET (buf,
1253 GST_BUFFER_FLAG_DELTA_UNIT) ? " (keyframe)" : "");
1256 if (GST_CLOCK_STIME_IS_VALID (best->dts)) {
1257 dts = GSTTIME_TO_MPEGTIME (best->dts);
1258 GST_DEBUG_OBJECT (mux, "Buffer has DTS %" GST_STIME_FORMAT " dts %"
1259 G_GINT64_FORMAT, GST_STIME_ARGS (best->dts), dts);
1262 /* should not have a DTS without PTS */
1263 if (!GST_CLOCK_STIME_IS_VALID (pts) && GST_CLOCK_STIME_IS_VALID (dts)) {
1264 GST_DEBUG_OBJECT (mux, "using DTS for unknown PTS");
1268 if (best->stream->is_video_stream) {
1269 delta = GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
1270 header = GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_HEADER);
1273 if (best->stream->is_meta && gst_buffer_get_size (buf) > (G_MAXUINT16 - 3)) {
1274 GST_WARNING_OBJECT (mux, "KLV meta unit too big, splitting not supported");
1276 gst_buffer_unref (buf);
1280 GST_DEBUG_OBJECT (mux, "delta: %d", delta);
1282 stream_data = stream_data_new (buf);
1283 tsmux_stream_add_data (best->stream, stream_data->map_info.data,
1284 stream_data->map_info.size, stream_data, pts, dts, !delta);
1286 /* outgoing ts follows ts of PCR program stream */
1287 if (prog->pcr_stream == best->stream) {
1288 /* prefer DTS if present for PCR as it should be monotone */
1290 GST_CLOCK_TIME_IS_VALID (GST_BUFFER_DTS (buf)) ?
1291 GST_BUFFER_DTS (buf) : GST_BUFFER_PTS (buf);
1294 mux->is_delta = delta;
1295 mux->is_header = header;
1296 while (tsmux_stream_bytes_in_buffer (best->stream) > 0) {
1297 if (!tsmux_write_stream_packet (mux->tsmux, best->stream)) {
1298 /* Failed writing data for some reason. Set appropriate error */
1299 GST_DEBUG_OBJECT (mux, "Failed to write data packet");
1300 GST_ELEMENT_ERROR (mux, STREAM, MUX,
1301 ("Failed writing output data to stream %04x", best->stream->id),
1306 /* flush packet cache */
1307 return gst_base_ts_mux_push_packets (mux, FALSE);
1312 return mux->last_flow_ret;
1316 /* GstElement implementation */
1318 gst_base_ts_mux_has_pad_with_pid (GstBaseTsMux * mux, guint16 pid)
1321 gboolean res = FALSE;
1323 GST_OBJECT_LOCK (mux);
1325 for (l = GST_ELEMENT_CAST (mux)->sinkpads; l; l = l->next) {
1326 GstBaseTsMuxPad *tpad = GST_BASE_TS_MUX_PAD (l->data);
1328 if (tpad->pid == pid) {
1334 GST_OBJECT_UNLOCK (mux);
1339 gst_base_ts_mux_request_new_pad (GstElement * element, GstPadTemplate * templ,
1340 const gchar * name, const GstCaps * caps)
1342 GstBaseTsMux *mux = GST_BASE_TS_MUX (element);
1345 gchar *free_name = NULL;
1347 if (name != NULL && sscanf (name, "sink_%d", &pid) == 1) {
1348 if (tsmux_find_stream (mux->tsmux, pid))
1350 /* Make sure we don't use reserved PID.
1351 * FIXME : This should be extended to other variants (ex: ATSC) reserved PID */
1352 if (pid < TSMUX_START_ES_PID)
1353 goto invalid_stream_pid;
1356 pid = tsmux_get_new_pid (mux->tsmux);
1357 } while (gst_base_ts_mux_has_pad_with_pid (mux, pid));
1359 /* Name the pad correctly after the selected pid */
1360 name = free_name = g_strdup_printf ("sink_%d", pid);
1364 GST_ELEMENT_CLASS (parent_class)->request_new_pad (element,
1367 gst_base_ts_mux_pad_reset (GST_BASE_TS_MUX_PAD (pad));
1368 GST_BASE_TS_MUX_PAD (pad)->pid = pid;
1377 GST_ELEMENT_ERROR (element, STREAM, MUX, ("Duplicate PID requested"),
1384 GST_ELEMENT_ERROR (element, STREAM, MUX,
1385 ("Invalid Elementary stream PID (0x%02u < 0x40)", pid), (NULL));
1391 gst_base_ts_mux_release_pad (GstElement * element, GstPad * pad)
1393 GstBaseTsMux *mux = GST_BASE_TS_MUX (element);
1397 GstBaseTsMuxPad *ts_pad = GST_BASE_TS_MUX_PAD (pad);
1398 gint pid = ts_pad->pid;
1401 if (ts_pad->prog->pcr_stream == ts_pad->stream) {
1402 tsmux_program_set_pcr_stream (ts_pad->prog, NULL);
1404 if (tsmux_remove_stream (mux->tsmux, pid, ts_pad->prog)) {
1405 g_hash_table_remove (mux->programs, GINT_TO_POINTER (ts_pad->prog_id));
1409 tsmux_resend_pat (mux->tsmux);
1410 tsmux_resend_si (mux->tsmux);
1412 /* output PMT for each program */
1413 for (cur = mux->tsmux->programs; cur; cur = cur->next) {
1414 TsMuxProgram *program = (TsMuxProgram *) cur->data;
1416 tsmux_resend_pmt (program);
1420 GST_ELEMENT_CLASS (parent_class)->release_pad (element, pad);
1423 /* GstAggregator implementation */
1426 request_keyframe (GstBaseTsMux * mux, GstClockTime running_time)
1429 GST_OBJECT_LOCK (mux);
1431 for (l = GST_ELEMENT_CAST (mux)->sinkpads; l; l = l->next) {
1432 gst_pad_push_event (GST_PAD (l->data),
1433 gst_video_event_new_upstream_force_key_unit (running_time, TRUE, 0));
1436 GST_OBJECT_UNLOCK (mux);
1439 static const guint32 crc_tab[256] = {
1440 0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc, 0x17c56b6b,
1441 0x1a864db2, 0x1e475005, 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61,
1442 0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd, 0x4c11db70, 0x48d0c6c7,
1443 0x4593e01e, 0x4152fda9, 0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75,
1444 0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011, 0x791d4014, 0x7ddc5da3,
1445 0x709f7b7a, 0x745e66cd, 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039,
1446 0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, 0xbe2b5b58, 0xbaea46ef,
1447 0xb7a96036, 0xb3687d81, 0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d,
1448 0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49, 0xc7361b4c, 0xc3f706fb,
1449 0xceb42022, 0xca753d95, 0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1,
1450 0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, 0x34867077, 0x30476dc0,
1451 0x3d044b19, 0x39c556ae, 0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072,
1452 0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16, 0x018aeb13, 0x054bf6a4,
1453 0x0808d07d, 0x0cc9cdca, 0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde,
1454 0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02, 0x5e9f46bf, 0x5a5e5b08,
1455 0x571d7dd1, 0x53dc6066, 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba,
1456 0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, 0xbfa1b04b, 0xbb60adfc,
1457 0xb6238b25, 0xb2e29692, 0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6,
1458 0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a, 0xe0b41de7, 0xe4750050,
1459 0xe9362689, 0xedf73b3e, 0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2,
1460 0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683, 0xd1799b34,
1461 0xdc3abded, 0xd8fba05a, 0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637,
1462 0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb, 0x4f040d56, 0x4bc510e1,
1463 0x46863638, 0x42472b8f, 0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53,
1464 0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47, 0x36194d42, 0x32d850f5,
1465 0x3f9b762c, 0x3b5a6b9b, 0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff,
1466 0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, 0xf12f560e, 0xf5ee4bb9,
1467 0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b,
1468 0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f, 0xc423cd6a, 0xc0e2d0dd,
1469 0xcda1f604, 0xc960ebb3, 0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7,
1470 0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, 0x9b3660c6, 0x9ff77d71,
1471 0x92b45ba8, 0x9675461f, 0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3,
1472 0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640, 0x4e8ee645, 0x4a4ffbf2,
1473 0x470cdd2b, 0x43cdc09c, 0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8,
1474 0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24, 0x119b4be9, 0x155a565e,
1475 0x18197087, 0x1cd86d30, 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec,
1476 0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, 0x2497d08d, 0x2056cd3a,
1477 0x2d15ebe3, 0x29d4f654, 0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0,
1478 0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c, 0xe3a1cbc1, 0xe760d676,
1479 0xea23f0af, 0xeee2ed18, 0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4,
1480 0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0, 0x9abc8bd5, 0x9e7d9662,
1481 0x933eb0bb, 0x97ffad0c, 0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668,
1482 0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4
1486 _calc_crc32 (const guint8 * data, guint datalen)
1489 guint32 crc = 0xffffffff;
1491 for (i = 0; i < datalen; i++) {
1492 crc = (crc << 8) ^ crc_tab[((crc >> 24) ^ *data++) & 0xff];
1497 #define MPEGTIME_TO_GSTTIME(t) ((t) * (guint64)100000 / 9)
1499 static GstMpegtsSCTESpliceEvent *
1500 copy_splice (GstMpegtsSCTESpliceEvent * splice)
1502 return g_boxed_copy (GST_TYPE_MPEGTS_SCTE_SPLICE_EVENT, splice);
1506 free_splice (GstMpegtsSCTESpliceEvent * splice)
1508 return g_boxed_free (GST_TYPE_MPEGTS_SCTE_SPLICE_EVENT, splice);
1511 /* FIXME: get rid of this when depending on glib >= 2.62 */
1514 _g_ptr_array_copy (GPtrArray * array,
1515 GCopyFunc func, GFreeFunc free_func, gpointer user_data)
1517 GPtrArray *new_array;
1519 g_return_val_if_fail (array != NULL, NULL);
1521 new_array = g_ptr_array_new_with_free_func (free_func);
1523 g_ptr_array_set_size (new_array, array->len);
1528 for (i = 0; i < array->len; i++)
1529 new_array->pdata[i] = func (array->pdata[i], user_data);
1530 } else if (array->len > 0) {
1531 memcpy (new_array->pdata, array->pdata,
1532 array->len * sizeof (*array->pdata));
1535 new_array->len = array->len;
1540 static GstMpegtsSCTESIT *
1541 deep_copy_sit (const GstMpegtsSCTESIT * sit)
1543 GstMpegtsSCTESIT *sit_copy = g_boxed_copy (GST_TYPE_MPEGTS_SCTE_SIT, sit);
1544 GPtrArray *splices_copy =
1545 _g_ptr_array_copy (sit_copy->splices, (GCopyFunc) copy_splice,
1546 (GFreeFunc) free_splice, NULL);
1548 g_ptr_array_unref (sit_copy->splices);
1549 sit_copy->splices = splices_copy;
1554 /* Takes ownership of @section.
1556 * This function is a bit complex because the SCTE sections can
1557 * have various origins:
1559 * * Sections created by the application with the gst_mpegts_scte_*_new()
1560 * API. The splice times / durations contained by these are expressed
1561 * in the GStreamer running time domain, and must be translated to
1562 * our local PES time domain. In this case, we will packetize the section
1565 * * Sections passed through from tsdemux: this case is complicated as
1566 * splice times in the incoming stream may be encrypted, with pts_adjustment
1567 * being the only timing field guaranteed *not* to be encrypted. In this
1568 * case, the original binary data (section->data) will be reinjected as is
1569 * in the output stream, with pts_adjustment adjusted. tsdemux provides us
1570 * with the pts_offset it introduces, the difference between the original
1571 * PES PTSs and the running times it outputs.
1573 * Additionally, in either of these cases when the splice times aren't encrypted
1574 * we want to make use of those to request keyframes. For the passthrough case,
1575 * as the splice times are left untouched tsdemux provides us with the running
1576 * times the section originally referred to. We cannot calculate it locally
1577 * because we would need to have access to the information that the timestamps
1578 * in the original PES domain have wrapped around, and how many times they have
1579 * done so. While we could probably make educated guesses, tsdemux (more specifically
1580 * mpegtspacketizer) already keeps track of that, and it seemed more logical to
1581 * perform the calculation there and forward it alongside the downstream events.
1583 * Finally, while we can't request keyframes at splice points in the encrypted
1584 * case, if the input stream was compliant in that regard and no reencoding took
1585 * place the splice times will still match with valid splice points, it is up
1586 * to the application to ensure that that is the case.
1589 handle_scte35_section (GstBaseTsMux * mux, GstEvent * event,
1590 GstMpegtsSection * section, guint64 mpeg_pts_offset,
1591 GstStructure * rtime_map)
1593 GstMpegtsSCTESIT *sit;
1595 gboolean forward = TRUE;
1597 guint8 *section_data;
1599 gboolean translate = FALSE;
1601 sit = (GstMpegtsSCTESIT *) gst_mpegts_section_get_scte_sit (section);
1603 /* When the application injects manually constructed splice events,
1604 * their time domain is the GStreamer running time, we receive them
1605 * unpacketized and translate the fields in the SIT to local PTS.
1607 * We make a copy of the SIT in order to make sure we can rewrite it.
1609 if (sit->is_running_time) {
1610 sit = deep_copy_sit (sit);
1614 switch (sit->splice_command_type) {
1615 case GST_MTS_SCTE_SPLICE_COMMAND_NULL:
1616 /* We implement heartbeating ourselves */
1619 case GST_MTS_SCTE_SPLICE_COMMAND_SCHEDULE:
1620 /* No need to request keyframes at this point, splice_insert
1621 * messages will precede the future splice points and we
1622 * can request keyframes then. Only translate if needed.
1625 for (i = 0; i < sit->splices->len; i++) {
1626 GstMpegtsSCTESpliceEvent *sevent =
1627 g_ptr_array_index (sit->splices, i);
1629 if (sevent->program_splice_time_specified)
1630 sevent->program_splice_time =
1631 GSTTIME_TO_MPEGTIME (sevent->program_splice_time) +
1634 if (sevent->duration_flag)
1635 sevent->break_duration =
1636 GSTTIME_TO_MPEGTIME (sevent->break_duration);
1640 case GST_MTS_SCTE_SPLICE_COMMAND_INSERT:
1641 /* We want keyframes at splice points */
1642 if (sit->fully_parsed && (rtime_map || translate)) {
1644 for (i = 0; i < sit->splices->len; i++) {
1645 guint64 running_time = GST_CLOCK_TIME_NONE;
1647 GstMpegtsSCTESpliceEvent *sevent =
1648 g_ptr_array_index (sit->splices, i);
1649 if (sevent->program_splice_time_specified) {
1651 gchar *field_name = g_strdup_printf ("event-%u-splice-time",
1652 sevent->splice_event_id);
1653 if (gst_structure_get_uint64 (rtime_map, field_name,
1655 GST_DEBUG_OBJECT (mux,
1656 "Requesting keyframe for splice point at %" GST_TIME_FORMAT,
1657 GST_TIME_ARGS (running_time));
1658 request_keyframe (mux, running_time);
1660 g_free (field_name);
1662 g_assert (translate == TRUE);
1663 running_time = sevent->program_splice_time;
1664 GST_DEBUG_OBJECT (mux,
1665 "Requesting keyframe for splice point at %" GST_TIME_FORMAT,
1666 GST_TIME_ARGS (running_time));
1667 request_keyframe (mux, running_time);
1668 sevent->program_splice_time =
1669 GSTTIME_TO_MPEGTIME (running_time) + TS_MUX_CLOCK_BASE;
1672 GST_DEBUG_OBJECT (mux,
1673 "Requesting keyframe for immediate splice point");
1674 request_keyframe (mux, GST_CLOCK_TIME_NONE);
1677 if (sevent->duration_flag) {
1679 sevent->break_duration =
1680 GSTTIME_TO_MPEGTIME (sevent->break_duration);
1683 /* Even if auto_return is FALSE, when a break_duration is specified it
1684 * is intended as a redundancy mechanism in case the follow-up
1685 * splice insert goes missing.
1687 * Schedule a keyframe at that point (if we can calculate its position
1690 if (GST_CLOCK_TIME_IS_VALID (running_time)) {
1691 running_time += MPEGTIME_TO_GSTTIME (sevent->break_duration);
1692 GST_DEBUG_OBJECT (mux,
1693 "Requesting keyframe for end of break at %" GST_TIME_FORMAT,
1694 GST_TIME_ARGS (running_time));
1695 request_keyframe (mux, running_time);
1701 case GST_MTS_SCTE_SPLICE_COMMAND_TIME:{
1702 /* Adjust timestamps and potentially request keyframes */
1703 gboolean do_request_keyframes = FALSE;
1705 /* TODO: we can probably be a little more fine-tuned about determining
1706 * whether a keyframe is actually needed, but this at least takes care
1707 * of the requirement in 10.3.4 that a keyframe should not be created
1708 * when the signal contains only a time_descriptor.
1710 if (sit->fully_parsed && (rtime_map || translate)) {
1711 for (i = 0; i < sit->descriptors->len; i++) {
1712 GstMpegtsDescriptor *descriptor =
1713 g_ptr_array_index (sit->descriptors, i);
1715 switch (descriptor->tag) {
1716 case GST_MTS_SCTE_DESC_AVAIL:
1717 case GST_MTS_SCTE_DESC_DTMF:
1718 case GST_MTS_SCTE_DESC_SEGMENTATION:
1719 do_request_keyframes = TRUE;
1721 case GST_MTS_SCTE_DESC_TIME:
1722 case GST_MTS_SCTE_DESC_AUDIO:
1726 if (do_request_keyframes)
1730 if (sit->splice_time_specified) {
1731 GstClockTime running_time = GST_CLOCK_TIME_NONE;
1734 if (do_request_keyframes
1735 && gst_structure_get_uint64 (rtime_map, "splice-time",
1737 GST_DEBUG_OBJECT (mux,
1738 "Requesting keyframe for time signal at %" GST_TIME_FORMAT,
1739 GST_TIME_ARGS (running_time));
1740 request_keyframe (mux, running_time);
1743 g_assert (translate);
1744 running_time = sit->splice_time;
1746 GSTTIME_TO_MPEGTIME (running_time) + TS_MUX_CLOCK_BASE;
1747 if (do_request_keyframes) {
1748 GST_DEBUG_OBJECT (mux,
1749 "Requesting keyframe for time signal at %" GST_TIME_FORMAT,
1750 GST_TIME_ARGS (running_time));
1751 request_keyframe (mux, running_time);
1754 } else if (do_request_keyframes) {
1755 GST_DEBUG_OBJECT (mux,
1756 "Requesting keyframe for immediate time signal");
1757 request_keyframe (mux, GST_CLOCK_TIME_NONE);
1762 case GST_MTS_SCTE_SPLICE_COMMAND_BANDWIDTH:
1763 case GST_MTS_SCTE_SPLICE_COMMAND_PRIVATE:
1764 /* Just let those go through untouched, none of our business */
1771 gst_mpegts_section_unref (section);
1776 g_assert (section->data);
1777 /* Calculate the final adjustment, as a sum of:
1778 * - The adjustment in the original packet
1779 * - The offset introduced between the original local PTS
1780 * and the GStreamer PTS output by tsdemux
1781 * - Our own 1-hour offset
1783 pts_adjust = sit->pts_adjustment + mpeg_pts_offset + TS_MUX_CLOCK_BASE;
1785 /* Account for offsets potentially introduced between the demuxer and us */
1787 GSTTIME_TO_MPEGTIME (gst_event_get_running_time_offset (event));
1789 pts_adjust &= 0x1ffffffff;
1790 section_data = g_memdup (section->data, section->section_length);
1791 section_data[4] |= pts_adjust >> 32;
1792 section_data[5] = pts_adjust >> 24;
1793 section_data[6] = pts_adjust >> 16;
1794 section_data[7] = pts_adjust >> 8;
1795 section_data[8] = pts_adjust;
1797 /* Now rewrite our checksum */
1798 crc = section_data + section->section_length - 4;
1799 GST_WRITE_UINT32_BE (crc, _calc_crc32 (section_data, crc - section_data));
1801 GST_OBJECT_LOCK (mux);
1802 GST_DEBUG_OBJECT (mux, "Storing SCTE section");
1803 if (mux->pending_scte35_section)
1804 gst_mpegts_section_unref (mux->pending_scte35_section);
1805 mux->pending_scte35_section =
1806 gst_mpegts_section_new (mux->scte35_pid, section_data,
1807 section->section_length);
1808 GST_OBJECT_UNLOCK (mux);
1810 gst_mpegts_section_unref (section);
1812 GST_OBJECT_LOCK (mux);
1813 GST_DEBUG_OBJECT (mux, "Storing SCTE section");
1814 gst_mpegts_section_unref (section);
1815 if (mux->pending_scte35_section)
1816 gst_mpegts_section_unref (mux->pending_scte35_section);
1817 mux->pending_scte35_section =
1818 gst_mpegts_section_from_scte_sit (sit, mux->scte35_pid);;
1819 GST_OBJECT_UNLOCK (mux);
1824 gst_base_ts_mux_send_event (GstElement * element, GstEvent * event)
1826 GstMpegtsSection *section;
1827 GstBaseTsMux *mux = GST_BASE_TS_MUX (element);
1829 section = gst_event_parse_mpegts_section (event);
1832 GST_DEBUG ("Received event with mpegts section");
1834 if (section->section_type == GST_MPEGTS_SECTION_SCTE_SIT) {
1835 handle_scte35_section (mux, event, section, 0, NULL);
1837 /* TODO: Check that the section type is supported */
1838 tsmux_add_mpegts_si_section (mux->tsmux, section);
1841 gst_event_unref (event);
1846 return GST_ELEMENT_CLASS (parent_class)->send_event (element, event);
1849 /* GstAggregator implementation */
1852 gst_base_ts_mux_sink_event (GstAggregator * agg, GstAggregatorPad * agg_pad,
1855 GstAggregatorClass *agg_class = GST_AGGREGATOR_CLASS (parent_class);
1856 GstBaseTsMux *mux = GST_BASE_TS_MUX (agg);
1857 GstBaseTsMuxPad *ts_pad = GST_BASE_TS_MUX_PAD (agg_pad);
1858 gboolean res = FALSE;
1859 gboolean forward = TRUE;
1861 switch (GST_EVENT_TYPE (event)) {
1862 case GST_EVENT_CUSTOM_DOWNSTREAM:
1864 GstClockTime timestamp, stream_time, running_time;
1865 gboolean all_headers;
1867 const GstStructure *s;
1869 s = gst_event_get_structure (event);
1871 if (gst_structure_has_name (s, "scte-sit") && mux->scte35_pid != 0) {
1873 /* When operating downstream of tsdemux, tsdemux will send out events
1874 * on all its source pads for each splice table it encounters. If we
1875 * are remuxing multiple streams it has demuxed, this means we could
1876 * unnecessarily repeat the same table multiple times, we avoid that
1877 * by deduplicating thanks to the event sequm
1879 if (gst_event_get_seqnum (event) != mux->last_scte35_event_seqnum) {
1880 GstMpegtsSection *section;
1882 gst_structure_get (s, "section", GST_TYPE_MPEGTS_SECTION, §ion,
1885 guint64 mpeg_pts_offset = 0;
1886 GstStructure *rtime_map = NULL;
1888 gst_structure_get (s, "running-time-map", GST_TYPE_STRUCTURE,
1890 gst_structure_get_uint64 (s, "mpeg-pts-offset", &mpeg_pts_offset);
1892 handle_scte35_section (mux, event, section, mpeg_pts_offset,
1895 gst_structure_free (rtime_map);
1896 mux->last_scte35_event_seqnum = gst_event_get_seqnum (event);
1898 GST_WARNING_OBJECT (ts_pad,
1899 "Ignoring scte-sit event without a section");
1902 GST_DEBUG_OBJECT (ts_pad, "Ignoring duplicate scte-sit event");
1909 if (!gst_video_event_is_force_key_unit (event))
1915 gst_video_event_parse_downstream_force_key_unit (event,
1916 ×tamp, &stream_time, &running_time, &all_headers, &count);
1917 GST_INFO_OBJECT (ts_pad, "have downstream force-key-unit event, "
1918 "seqnum %d, running-time %" GST_TIME_FORMAT " count %d",
1919 gst_event_get_seqnum (event), GST_TIME_ARGS (running_time), count);
1921 if (mux->force_key_unit_event != NULL) {
1922 GST_INFO_OBJECT (mux, "skipping downstream force key unit event "
1923 "as an upstream force key unit is already queued");
1930 mux->pending_key_unit_ts = running_time;
1931 gst_event_replace (&mux->force_key_unit_event, event);
1934 case GST_EVENT_TAG:{
1938 GST_DEBUG_OBJECT (mux, "received tag event");
1939 gst_event_parse_tag (event, &list);
1941 /* Matroska wants ISO 639-2B code, taglist most likely contains 639-1 */
1942 if (gst_tag_list_get_string (list, GST_TAG_LANGUAGE_CODE, &lang)) {
1943 const gchar *lang_code;
1945 lang_code = gst_tag_get_language_code_iso_639_2B (lang);
1947 GST_DEBUG_OBJECT (ts_pad, "Setting language to '%s'", lang_code);
1949 g_free (ts_pad->language);
1950 ts_pad->language = g_strdup (lang_code);
1952 GST_WARNING_OBJECT (ts_pad, "Did not get language code for '%s'",
1958 /* handled this, don't want collectpads to forward it downstream */
1960 forward = gst_tag_list_get_scope (list) == GST_TAG_SCOPE_GLOBAL;
1963 case GST_EVENT_STREAM_START:{
1964 GstStreamFlags flags;
1966 gst_event_parse_stream_flags (event, &flags);
1968 /* Don't wait for data on sparse inputs like metadata streams */
1970 if ((flags & GST_STREAM_FLAG_SPARSE)) {
1971 GST_COLLECT_PADS_STATE_UNSET (data, GST_COLLECT_PADS_STATE_LOCKED);
1972 gst_collect_pads_set_waiting (pads, data, FALSE);
1973 GST_COLLECT_PADS_STATE_SET (data, GST_COLLECT_PADS_STATE_LOCKED);
1984 gst_event_unref (event);
1986 res = agg_class->sink_event (agg, agg_pad, event);
1992 gst_base_ts_mux_src_event (GstAggregator * agg, GstEvent * event)
1994 GstAggregatorClass *agg_class = GST_AGGREGATOR_CLASS (parent_class);
1995 GstBaseTsMux *mux = GST_BASE_TS_MUX (agg);
1996 gboolean res = TRUE, forward = TRUE;
1998 switch (GST_EVENT_TYPE (event)) {
1999 case GST_EVENT_CUSTOM_UPSTREAM:
2002 GValue sinkpad_value = G_VALUE_INIT;
2003 GstClockTime running_time;
2004 gboolean all_headers, done = FALSE, res = FALSE;
2007 if (!gst_video_event_is_force_key_unit (event))
2012 gst_video_event_parse_upstream_force_key_unit (event,
2013 &running_time, &all_headers, &count);
2015 GST_INFO_OBJECT (mux, "received upstream force-key-unit event, "
2016 "seqnum %d running_time %" GST_TIME_FORMAT " all_headers %d count %d",
2017 gst_event_get_seqnum (event), GST_TIME_ARGS (running_time),
2018 all_headers, count);
2023 mux->pending_key_unit_ts = running_time;
2024 gst_event_replace (&mux->force_key_unit_event, event);
2026 iter = gst_element_iterate_sink_pads (GST_ELEMENT_CAST (mux));
2029 switch (gst_iterator_next (iter, &sinkpad_value)) {
2030 case GST_ITERATOR_OK:{
2031 GstPad *sinkpad = g_value_get_object (&sinkpad_value);
2034 GST_INFO_OBJECT (GST_AGGREGATOR_SRC_PAD (agg), "forwarding");
2035 tmp = gst_pad_push_event (sinkpad, gst_event_ref (event));
2036 GST_INFO_OBJECT (mux, "result %d", tmp);
2037 /* succeed if at least one pad succeeds */
2041 case GST_ITERATOR_DONE:
2044 case GST_ITERATOR_RESYNC:
2045 gst_iterator_resync (iter);
2047 case GST_ITERATOR_ERROR:
2048 g_assert_not_reached ();
2051 g_value_reset (&sinkpad_value);
2053 g_value_unset (&sinkpad_value);
2054 gst_iterator_free (iter);
2062 res = agg_class->src_event (agg, event);
2064 gst_event_unref (event);
2070 gst_base_ts_mux_clip (GstAggregator * agg,
2071 GstAggregatorPad * agg_pad, GstBuffer * buf)
2073 GstBaseTsMuxPad *pad = GST_BASE_TS_MUX_PAD (agg_pad);
2080 time = GST_BUFFER_PTS (buf);
2082 /* invalid left alone and passed */
2083 if (G_LIKELY (GST_CLOCK_TIME_IS_VALID (time))) {
2085 gst_segment_to_running_time (&agg_pad->segment, GST_FORMAT_TIME, time);
2086 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (time))) {
2087 GST_DEBUG_OBJECT (pad, "clipping buffer on pad outside segment");
2088 gst_buffer_unref (buf);
2092 GST_LOG_OBJECT (pad, "buffer pts %" GST_TIME_FORMAT " -> %"
2093 GST_TIME_FORMAT " running time",
2094 GST_TIME_ARGS (GST_BUFFER_PTS (buf)), GST_TIME_ARGS (time));
2095 buf = ret = gst_buffer_make_writable (buf);
2096 GST_BUFFER_PTS (ret) = time;
2101 time = GST_BUFFER_DTS (buf);
2103 /* invalid left alone and passed */
2104 if (G_LIKELY (GST_CLOCK_TIME_IS_VALID (time))) {
2108 sign = gst_segment_to_running_time_full (&agg_pad->segment, GST_FORMAT_TIME,
2112 dts = (gint64) time;
2114 dts = -((gint64) time);
2116 GST_LOG_OBJECT (pad, "buffer dts %" GST_TIME_FORMAT " -> %"
2117 GST_STIME_FORMAT " running time", GST_TIME_ARGS (GST_BUFFER_DTS (buf)),
2118 GST_STIME_ARGS (dts));
2120 if (GST_CLOCK_STIME_IS_VALID (pad->dts) && dts < pad->dts) {
2121 /* Ignore DTS going backward */
2122 GST_WARNING_OBJECT (pad, "ignoring DTS going backward");
2126 ret = gst_buffer_make_writable (buf);
2128 GST_BUFFER_DTS (ret) = time;
2130 GST_BUFFER_DTS (ret) = GST_CLOCK_TIME_NONE;
2134 pad->dts = GST_CLOCK_STIME_NONE;
2141 static GstFlowReturn
2142 gst_base_ts_mux_update_src_caps (GstAggregator * agg, GstCaps * caps,
2145 GstBaseTsMux *mux = GST_BASE_TS_MUX (agg);
2148 *ret = gst_caps_copy (caps);
2149 s = gst_caps_get_structure (*ret, 0);
2150 gst_structure_set (s, "packetsize", G_TYPE_INT, mux->packet_size, NULL);
2155 static GstBaseTsMuxPad *
2156 gst_base_ts_mux_find_best_pad (GstAggregator * aggregator)
2158 GstBaseTsMuxPad *best = NULL;
2159 GstClockTime best_ts = GST_CLOCK_TIME_NONE;
2162 GST_OBJECT_LOCK (aggregator);
2164 for (l = GST_ELEMENT_CAST (aggregator)->sinkpads; l; l = l->next) {
2165 GstBaseTsMuxPad *tpad = GST_BASE_TS_MUX_PAD (l->data);
2166 GstAggregatorPad *apad = GST_AGGREGATOR_PAD_CAST (tpad);
2169 buffer = gst_aggregator_pad_peek_buffer (apad);
2172 if (best_ts == GST_CLOCK_TIME_NONE) {
2174 best_ts = GST_BUFFER_DTS_OR_PTS (buffer);
2175 } else if (GST_BUFFER_DTS_OR_PTS (buffer) != GST_CLOCK_TIME_NONE) {
2176 GstClockTime t = GST_BUFFER_DTS_OR_PTS (buffer);
2182 gst_buffer_unref (buffer);
2186 gst_object_ref (best);
2188 GST_OBJECT_UNLOCK (aggregator);
2190 GST_DEBUG_OBJECT (aggregator,
2191 "Best pad found with %" GST_TIME_FORMAT ": %" GST_PTR_FORMAT,
2192 GST_TIME_ARGS (best_ts), best);
2198 gst_base_ts_mux_are_all_pads_eos (GstBaseTsMux * mux)
2201 gboolean ret = TRUE;
2203 GST_OBJECT_LOCK (mux);
2205 for (l = GST_ELEMENT_CAST (mux)->sinkpads; l; l = l->next) {
2206 GstBaseTsMuxPad *pad = GST_BASE_TS_MUX_PAD (l->data);
2208 if (!gst_aggregator_pad_is_eos (GST_AGGREGATOR_PAD (pad))) {
2214 GST_OBJECT_UNLOCK (mux);
2220 static GstFlowReturn
2221 gst_base_ts_mux_aggregate (GstAggregator * agg, gboolean timeout)
2223 GstBaseTsMux *mux = GST_BASE_TS_MUX (agg);
2224 GstFlowReturn ret = GST_FLOW_OK;
2225 GstBaseTsMuxPad *best = gst_base_ts_mux_find_best_pad (agg);
2230 buffer = gst_aggregator_pad_pop_buffer (GST_AGGREGATOR_PAD (best));
2233 gst_base_ts_mux_aggregate_buffer (GST_BASE_TS_MUX (agg),
2234 GST_AGGREGATOR_PAD (best), buffer);
2236 gst_object_unref (best);
2238 if (ret != GST_FLOW_OK)
2242 if (gst_base_ts_mux_are_all_pads_eos (mux)) {
2243 GstBaseTsMuxClass *klass = GST_BASE_TS_MUX_GET_CLASS (mux);
2244 /* drain some possibly cached data */
2247 gst_base_ts_mux_push_packets (mux, TRUE);
2257 gst_base_ts_mux_start (GstAggregator * agg)
2259 gst_base_ts_mux_reset (GST_BASE_TS_MUX (agg), TRUE);
2265 gst_base_ts_mux_stop (GstAggregator * agg)
2267 gst_base_ts_mux_reset (GST_BASE_TS_MUX (agg), TRUE);
2272 /* GObject implementation */
2275 gst_base_ts_mux_dispose (GObject * object)
2277 GstBaseTsMux *mux = GST_BASE_TS_MUX (object);
2279 gst_base_ts_mux_reset (mux, FALSE);
2281 if (mux->out_adapter) {
2282 g_object_unref (mux->out_adapter);
2283 mux->out_adapter = NULL;
2285 if (mux->prog_map) {
2286 gst_structure_free (mux->prog_map);
2287 mux->prog_map = NULL;
2289 if (mux->programs) {
2290 g_hash_table_destroy (mux->programs);
2291 mux->programs = NULL;
2293 GST_CALL_PARENT (G_OBJECT_CLASS, dispose, (object));
2297 gst_base_ts_mux_constructed (GObject * object)
2299 GstBaseTsMux *mux = GST_BASE_TS_MUX (object);
2302 gst_base_ts_mux_reset (mux, TRUE);
2306 gst_base_ts_mux_set_property (GObject * object, guint prop_id,
2307 const GValue * value, GParamSpec * pspec)
2309 GstBaseTsMux *mux = GST_BASE_TS_MUX (object);
2315 const GstStructure *s = gst_value_get_structure (value);
2316 if (mux->prog_map) {
2317 gst_structure_free (mux->prog_map);
2320 mux->prog_map = gst_structure_copy (s);
2322 mux->prog_map = NULL;
2325 case PROP_PAT_INTERVAL:
2326 mux->pat_interval = g_value_get_uint (value);
2328 tsmux_set_pat_interval (mux->tsmux, mux->pat_interval);
2330 case PROP_PMT_INTERVAL:
2331 mux->pmt_interval = g_value_get_uint (value);
2332 GST_OBJECT_LOCK (mux);
2333 for (l = GST_ELEMENT_CAST (mux)->sinkpads; l; l = l->next) {
2334 GstBaseTsMuxPad *ts_pad = GST_BASE_TS_MUX_PAD (l->data);
2336 tsmux_set_pmt_interval (ts_pad->prog, mux->pmt_interval);
2338 GST_OBJECT_UNLOCK (mux);
2340 case PROP_ALIGNMENT:
2341 mux->alignment = g_value_get_int (value);
2343 case PROP_SI_INTERVAL:
2344 mux->si_interval = g_value_get_uint (value);
2345 tsmux_set_si_interval (mux->tsmux, mux->si_interval);
2348 mux->bitrate = g_value_get_uint64 (value);
2350 tsmux_set_bitrate (mux->tsmux, mux->bitrate);
2352 case PROP_PCR_INTERVAL:
2353 mux->pcr_interval = g_value_get_uint (value);
2355 tsmux_set_pcr_interval (mux->tsmux, mux->pcr_interval);
2357 case PROP_SCTE_35_PID:
2358 mux->scte35_pid = g_value_get_uint (value);
2360 case PROP_SCTE_35_NULL_INTERVAL:
2361 mux->scte35_null_interval = g_value_get_uint (value);
2364 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
2370 gst_base_ts_mux_get_property (GObject * object, guint prop_id,
2371 GValue * value, GParamSpec * pspec)
2373 GstBaseTsMux *mux = GST_BASE_TS_MUX (object);
2377 gst_value_set_structure (value, mux->prog_map);
2379 case PROP_PAT_INTERVAL:
2380 g_value_set_uint (value, mux->pat_interval);
2382 case PROP_PMT_INTERVAL:
2383 g_value_set_uint (value, mux->pmt_interval);
2385 case PROP_ALIGNMENT:
2386 g_value_set_int (value, mux->alignment);
2388 case PROP_SI_INTERVAL:
2389 g_value_set_uint (value, mux->si_interval);
2392 g_value_set_uint64 (value, mux->bitrate);
2394 case PROP_PCR_INTERVAL:
2395 g_value_set_uint (value, mux->pcr_interval);
2397 case PROP_SCTE_35_PID:
2398 g_value_set_uint (value, mux->scte35_pid);
2400 case PROP_SCTE_35_NULL_INTERVAL:
2401 g_value_set_uint (value, mux->scte35_null_interval);
2404 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
2409 /* Default vmethods implementation */
2412 gst_base_ts_mux_default_create_ts_mux (GstBaseTsMux * mux)
2414 TsMux *tsmux = tsmux_new ();
2415 tsmux_set_write_func (tsmux, new_packet_cb, mux);
2416 tsmux_set_alloc_func (tsmux, alloc_packet_cb, mux);
2417 tsmux_set_pat_interval (tsmux, mux->pat_interval);
2418 tsmux_set_si_interval (tsmux, mux->si_interval);
2419 tsmux_set_bitrate (tsmux, mux->bitrate);
2420 tsmux_set_pcr_interval (tsmux, mux->pcr_interval);
2426 gst_base_ts_mux_default_allocate_packet (GstBaseTsMux * mux,
2427 GstBuffer ** buffer)
2431 buf = gst_buffer_new_and_alloc (mux->packet_size);
2437 gst_base_ts_mux_default_output_packet (GstBaseTsMux * mux, GstBuffer * buffer,
2440 gst_base_ts_mux_collect_packet (mux, buffer);
2448 gst_base_ts_mux_set_packet_size (GstBaseTsMux * mux, gsize size)
2450 mux->packet_size = size;
2454 gst_base_ts_mux_set_automatic_alignment (GstBaseTsMux * mux, gsize alignment)
2456 mux->automatic_alignment = alignment;
2460 gst_base_ts_mux_class_init (GstBaseTsMuxClass * klass)
2462 GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
2463 GstAggregatorClass *gstagg_class = GST_AGGREGATOR_CLASS (klass);
2464 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
2466 GST_DEBUG_CATEGORY_INIT (gst_base_ts_mux_debug, "basetsmux", 0,
2467 "MPEG Transport Stream muxer");
2469 gst_element_class_set_static_metadata (gstelement_class,
2470 "MPEG Transport Stream Muxer", "Codec/Muxer",
2471 "Multiplexes media streams into an MPEG Transport Stream",
2472 "Fluendo <contact@fluendo.com>");
2474 gobject_class->set_property =
2475 GST_DEBUG_FUNCPTR (gst_base_ts_mux_set_property);
2476 gobject_class->get_property =
2477 GST_DEBUG_FUNCPTR (gst_base_ts_mux_get_property);
2478 gobject_class->dispose = gst_base_ts_mux_dispose;
2479 gobject_class->constructed = gst_base_ts_mux_constructed;
2481 gstelement_class->request_new_pad = gst_base_ts_mux_request_new_pad;
2482 gstelement_class->release_pad = gst_base_ts_mux_release_pad;
2483 gstelement_class->send_event = gst_base_ts_mux_send_event;
2485 gstagg_class->update_src_caps = gst_base_ts_mux_update_src_caps;
2486 gstagg_class->aggregate = gst_base_ts_mux_aggregate;
2487 gstagg_class->clip = gst_base_ts_mux_clip;
2488 gstagg_class->sink_event = gst_base_ts_mux_sink_event;
2489 gstagg_class->src_event = gst_base_ts_mux_src_event;
2490 gstagg_class->start = gst_base_ts_mux_start;
2491 gstagg_class->stop = gst_base_ts_mux_stop;
2493 klass->create_ts_mux = gst_base_ts_mux_default_create_ts_mux;
2494 klass->allocate_packet = gst_base_ts_mux_default_allocate_packet;
2495 klass->output_packet = gst_base_ts_mux_default_output_packet;
2497 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_PROG_MAP,
2498 g_param_spec_boxed ("prog-map", "Program map",
2499 "A GstStructure specifies the mapping from elementary streams to programs",
2501 (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
2503 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_PAT_INTERVAL,
2504 g_param_spec_uint ("pat-interval", "PAT interval",
2505 "Set the interval (in ticks of the 90kHz clock) for writing out the PAT table",
2506 1, G_MAXUINT, TSMUX_DEFAULT_PAT_INTERVAL,
2507 (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
2509 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_PMT_INTERVAL,
2510 g_param_spec_uint ("pmt-interval", "PMT interval",
2511 "Set the interval (in ticks of the 90kHz clock) for writing out the PMT table",
2512 1, G_MAXUINT, TSMUX_DEFAULT_PMT_INTERVAL,
2513 (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
2515 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_ALIGNMENT,
2516 g_param_spec_int ("alignment", "packet alignment",
2517 "Number of packets per buffer (padded with dummy packets on EOS) "
2518 "(-1 = auto, 0 = all available packets, 7 for UDP streaming)",
2519 -1, G_MAXINT, BASETSMUX_DEFAULT_ALIGNMENT,
2520 (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
2522 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_SI_INTERVAL,
2523 g_param_spec_uint ("si-interval", "SI interval",
2524 "Set the interval (in ticks of the 90kHz clock) for writing out the Service"
2525 "Information tables", 1, G_MAXUINT, TSMUX_DEFAULT_SI_INTERVAL,
2526 (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
2528 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_BITRATE,
2529 g_param_spec_uint64 ("bitrate", "Bitrate (in bits per second)",
2530 "Set the target bitrate, will insert null packets as padding "
2531 " to achieve multiplex-wide constant bitrate (0 means no padding)",
2532 0, G_MAXUINT64, TSMUX_DEFAULT_BITRATE,
2533 (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
2535 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_PCR_INTERVAL,
2536 g_param_spec_uint ("pcr-interval", "PCR interval",
2537 "Set the interval (in ticks of the 90kHz clock) for writing PCR",
2538 1, G_MAXUINT, TSMUX_DEFAULT_PCR_INTERVAL,
2539 (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
2541 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_SCTE_35_PID,
2542 g_param_spec_uint ("scte-35-pid", "SCTE-35 PID",
2543 "PID to use for inserting SCTE-35 packets (0: unused)",
2544 0, G_MAXUINT, DEFAULT_SCTE_35_PID,
2545 (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
2547 g_object_class_install_property (G_OBJECT_CLASS (klass),
2548 PROP_SCTE_35_NULL_INTERVAL, g_param_spec_uint ("scte-35-null-interval",
2549 "SCTE-35 NULL packet interval",
2550 "Set the interval (in ticks of the 90kHz clock) for writing SCTE-35 NULL (heartbeat) packets."
2551 " (only valid if scte-35-pid is different from 0)", 1, G_MAXUINT,
2552 TSMUX_DEFAULT_SCTE_35_NULL_INTERVAL,
2553 (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
2555 gst_element_class_add_static_pad_template_with_gtype (gstelement_class,
2556 &gst_base_ts_mux_src_factory, GST_TYPE_AGGREGATOR_PAD);
2558 gst_type_mark_as_plugin_api (GST_TYPE_BASE_TS_MUX_PAD, 0);
2562 gst_base_ts_mux_init (GstBaseTsMux * mux)
2564 mux->out_adapter = gst_adapter_new ();
2567 mux->pat_interval = TSMUX_DEFAULT_PAT_INTERVAL;
2568 mux->pmt_interval = TSMUX_DEFAULT_PMT_INTERVAL;
2569 mux->si_interval = TSMUX_DEFAULT_SI_INTERVAL;
2570 mux->pcr_interval = TSMUX_DEFAULT_PCR_INTERVAL;
2571 mux->prog_map = NULL;
2572 mux->alignment = BASETSMUX_DEFAULT_ALIGNMENT;
2573 mux->bitrate = TSMUX_DEFAULT_BITRATE;
2574 mux->scte35_pid = DEFAULT_SCTE_35_PID;
2575 mux->scte35_null_interval = TSMUX_DEFAULT_SCTE_35_NULL_INTERVAL;
2577 mux->packet_size = GST_BASE_TS_MUX_NORMAL_PACKET_LENGTH;
2578 mux->automatic_alignment = 0;