1 /*
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>
6 *
7 * Copyright (C) 2011 Jan Schmidt <thaytan@noraisin.net>
8 *
9 * This library is licensed under 4 different licenses and you
10 * can choose to use it under the terms of any one of them. The
11 * four licenses are the MPL 1.1, the LGPL, the GPL and the MIT
12 * license.
13 *
14 * MPL:
15 *
16 * The contents of this file are subject to the Mozilla Public License
17 * Version 1.1 (the "License"); you may not use this file except in
18 * compliance with the License. You may obtain a copy of the License at
19 * http://www.mozilla.org/MPL/.
20 *
21 * Software distributed under the License is distributed on an "AS IS"
22 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
23 * License for the specific language governing rights and limitations
24 * under the License.
25 *
26 * LGPL:
27 *
28 * This library is free software; you can redistribute it and/or
29 * modify it under the terms of the GNU Library General Public
30 * License as published by the Free Software Foundation; either
31 * version 2 of the License, or (at your option) any later version.
32 *
33 * This library is distributed in the hope that it will be useful,
34 * but WITHOUT ANY WARRANTY; without even the implied warranty of
35 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
36 * Library General Public License for more details.
37 *
38 * You should have received a copy of the GNU Library General Public
39 * License along with this library; if not, write to the
40 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
41 * Boston, MA 02110-1301, USA.
42 *
43 * GPL:
44 *
45 * This program is free software; you can redistribute it and/or modify
46 * it under the terms of the GNU General Public License as published by
47 * the Free Software Foundation; either version 2 of the License, or
48 * (at your option) any later version.
49 *
50 * This program is distributed in the hope that it will be useful,
51 * but WITHOUT ANY WARRANTY; without even the implied warranty of
52 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
53 * GNU General Public License for more details.
54 *
55 * You should have received a copy of the GNU General Public License
56 * along with this program; if not, write to the Free Software
57 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
58 *
59 * MIT:
60 *
61 * Unless otherwise indicated, Source Code is licensed under MIT license.
62 * See further explanation attached in License Statement (distributed in the file
63 * LICENSE).
64 *
65 * Permission is hereby granted, free of charge, to any person obtaining a copy of
66 * this software and associated documentation files (the "Software"), to deal in
67 * the Software without restriction, including without limitation the rights to
68 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
69 * of the Software, and to permit persons to whom the Software is furnished to do
70 * so, subject to the following conditions:
71 *
72 * The above copyright notice and this permission notice shall be included in all
73 * copies or substantial portions of the Software.
74 *
75 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
76 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
77 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
78 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
79 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
80 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
81 * SOFTWARE.
82 *
83 */
84
85 #ifdef HAVE_CONFIG_H
86 #include "config.h"
87 #endif
88 #include <stdio.h>
89 #include <string.h>
90
91 #include <gst/tag/tag.h>
92 #include <gst/video/video.h>
93 #include <gst/mpegts/mpegts.h>
94 #include <gst/pbutils/pbutils.h>
95
96 #include "mpegtsmux.h"
97
98 #include "mpegtsmux_aac.h"
99 #include "mpegtsmux_ttxt.h"
100 #include "mpegtsmux_opus.h"
101 #include "mpegtsmux_jpeg2000.h"
102 #include <gst/videoparsers/gstjpeg2000parse.h>
103 #include <gst/video/video-color.h>
104
105 GST_DEBUG_CATEGORY (mpegtsmux_debug);
106 #define GST_CAT_DEFAULT mpegtsmux_debug
107
108 #define COLLECT_DATA_PAD(collect_data) (((GstCollectData *)(collect_data))->pad)
109
110 enum
111 {
112 PROP_0,
113 PROP_PROG_MAP,
114 PROP_M2TS_MODE,
115 PROP_PAT_INTERVAL,
116 PROP_PMT_INTERVAL,
117 PROP_ALIGNMENT,
118 PROP_SI_INTERVAL
119 };
120
121 #define MPEGTSMUX_DEFAULT_ALIGNMENT -1
122 #define MPEGTSMUX_DEFAULT_M2TS FALSE
123
124 static GstStaticPadTemplate mpegtsmux_sink_factory =
125 GST_STATIC_PAD_TEMPLATE ("sink_%d",
126 GST_PAD_SINK,
127 GST_PAD_REQUEST,
128 GST_STATIC_CAPS ("video/mpeg, "
129 "parsed = (boolean) TRUE, "
130 "mpegversion = (int) { 1, 2, 4 }, "
131 "systemstream = (boolean) false; "
132 "video/x-dirac;"
133 "image/x-jpc;"
134 "video/x-h264,stream-format=(string)byte-stream,"
135 "alignment=(string){au, nal}; "
136 "video/x-h265,stream-format=(string)byte-stream,"
137 "alignment=(string){au, nal}; "
138 "audio/mpeg, "
139 "parsed = (boolean) TRUE, "
140 "mpegversion = (int) { 1, 2 };"
141 "audio/mpeg, "
142 "framed = (boolean) TRUE, "
143 "mpegversion = (int) 4, stream-format = (string) adts;"
144 "audio/mpeg, "
145 "mpegversion = (int) 4, stream-format = (string) raw;"
146 "audio/x-lpcm, "
147 "width = (int) { 16, 20, 24 }, "
148 "rate = (int) { 48000, 96000 }, "
149 "channels = (int) [ 1, 8 ], "
150 "dynamic_range = (int) [ 0, 255 ], "
151 "emphasis = (boolean) { FALSE, TRUE }, "
152 "mute = (boolean) { FALSE, TRUE }; "
153 "audio/x-ac3, framed = (boolean) TRUE;"
154 "audio/x-dts, framed = (boolean) TRUE;"
155 "audio/x-opus, "
156 "channels = (int) [1, 8], "
157 "channel-mapping-family = (int) {0, 1};"
158 "subpicture/x-dvb; application/x-teletext; meta/x-klv, parsed=true;"
159 "image/x-jpc, profile = (int)[0, 49151];"));
160
161 static GstStaticPadTemplate mpegtsmux_src_factory =
162 GST_STATIC_PAD_TEMPLATE ("src",
163 GST_PAD_SRC,
164 GST_PAD_ALWAYS,
165 GST_STATIC_CAPS ("video/mpegts, "
166 "systemstream = (boolean) true, " "packetsize = (int) { 188, 192} ")
167 );
168
169 static void gst_mpegtsmux_set_property (GObject * object, guint prop_id,
170 const GValue * value, GParamSpec * pspec);
171 static void gst_mpegtsmux_get_property (GObject * object, guint prop_id,
172 GValue * value, GParamSpec * pspec);
173
174 static void mpegtsmux_reset (MpegTsMux * mux, gboolean alloc);
175 static void mpegtsmux_dispose (GObject * object);
176 static void alloc_packet_cb (GstBuffer ** _buf, void *user_data);
177 static gboolean new_packet_cb (GstBuffer * buf, void *user_data,
178 gint64 new_pcr);
179 static void release_buffer_cb (guint8 * data, void *user_data);
180 static GstFlowReturn mpegtsmux_collect_packet (MpegTsMux * mux,
181 GstBuffer * buf);
182 static GstFlowReturn mpegtsmux_push_packets (MpegTsMux * mux, gboolean force);
183 static gboolean new_packet_m2ts (MpegTsMux * mux, GstBuffer * buf,
184 gint64 new_pcr);
185
186 static void mpegtsmux_prepare_srcpad (MpegTsMux * mux);
187 GstFlowReturn mpegtsmux_clip_inc_running_time (GstCollectPads * pads,
188 GstCollectData * cdata, GstBuffer * buf, GstBuffer ** outbuf,
189 gpointer user_data);
190 static GstFlowReturn mpegtsmux_collected_buffer (GstCollectPads * pads,
191 GstCollectData * data, GstBuffer * buf, MpegTsMux * mux);
192
193 static gboolean mpegtsmux_sink_event (GstCollectPads * pads,
194 GstCollectData * data, GstEvent * event, gpointer user_data);
195 static GstPad *mpegtsmux_request_new_pad (GstElement * element,
196 GstPadTemplate * templ, const gchar * name, const GstCaps * caps);
197 static void mpegtsmux_release_pad (GstElement * element, GstPad * pad);
198 static GstStateChangeReturn mpegtsmux_change_state (GstElement * element,
199 GstStateChange transition);
200 static gboolean mpegtsmux_send_event (GstElement * element, GstEvent * event);
201 static void mpegtsmux_set_header_on_caps (MpegTsMux * mux);
202 static gboolean mpegtsmux_src_event (GstPad * pad, GstObject * parent,
203 GstEvent * event);
204
205 #if 0
206 static void mpegtsmux_set_index (GstElement * element, GstIndex * index);
207 static GstIndex *mpegtsmux_get_index (GstElement * element);
208
209 static GstFormat pts_format;
210 static GstFormat spn_format;
211 #endif
212
213 typedef struct
214 {
215 GstMapInfo map_info;
216 GstBuffer *buffer;
217 } StreamData;
218
G_DEFINE_TYPE(MpegTsMux,mpegtsmux,GST_TYPE_ELEMENT)219 G_DEFINE_TYPE (MpegTsMux, mpegtsmux, GST_TYPE_ELEMENT)
220
221 /* Takes over the ref on the buffer */
222 static StreamData *stream_data_new (GstBuffer * buffer)
223 {
224 StreamData *res = g_new (StreamData, 1);
225 res->buffer = buffer;
226 gst_buffer_map (buffer, &(res->map_info), GST_MAP_READ);
227
228 return res;
229 }
230
231 static void
stream_data_free(StreamData * data)232 stream_data_free (StreamData * data)
233 {
234 if (data) {
235 gst_buffer_unmap (data->buffer, &data->map_info);
236 gst_buffer_unref (data->buffer);
237 g_free (data);
238 }
239 }
240
241 #define parent_class mpegtsmux_parent_class
242
243 static void
mpegtsmux_class_init(MpegTsMuxClass * klass)244 mpegtsmux_class_init (MpegTsMuxClass * klass)
245 {
246 GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
247 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
248
249 gst_element_class_add_static_pad_template (gstelement_class,
250 &mpegtsmux_sink_factory);
251 gst_element_class_add_static_pad_template (gstelement_class,
252 &mpegtsmux_src_factory);
253
254 gst_element_class_set_static_metadata (gstelement_class,
255 "MPEG Transport Stream Muxer", "Codec/Muxer",
256 "Multiplexes media streams into an MPEG Transport Stream",
257 "Fluendo <contact@fluendo.com>");
258
259 gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_mpegtsmux_set_property);
260 gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_mpegtsmux_get_property);
261 gobject_class->dispose = mpegtsmux_dispose;
262
263 gstelement_class->request_new_pad = mpegtsmux_request_new_pad;
264 gstelement_class->release_pad = mpegtsmux_release_pad;
265 gstelement_class->change_state = mpegtsmux_change_state;
266 gstelement_class->send_event = mpegtsmux_send_event;
267
268 #if 0
269 gstelement_class->set_index = GST_DEBUG_FUNCPTR (mpegtsmux_set_index);
270 gstelement_class->get_index = GST_DEBUG_FUNCPTR (mpegtsmux_get_index);
271 #endif
272
273 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_PROG_MAP,
274 g_param_spec_boxed ("prog-map", "Program map",
275 "A GstStructure specifies the mapping from elementary streams to programs",
276 GST_TYPE_STRUCTURE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
277
278 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_M2TS_MODE,
279 g_param_spec_boolean ("m2ts-mode", "M2TS(192 bytes) Mode",
280 "Set to TRUE to output Blu-Ray disc format with 192 byte packets. "
281 "FALSE for standard TS format with 188 byte packets.",
282 MPEGTSMUX_DEFAULT_M2TS, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
283
284 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_PAT_INTERVAL,
285 g_param_spec_uint ("pat-interval", "PAT interval",
286 "Set the interval (in ticks of the 90kHz clock) for writing out the PAT table",
287 1, G_MAXUINT, TSMUX_DEFAULT_PAT_INTERVAL,
288 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
289
290 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_PMT_INTERVAL,
291 g_param_spec_uint ("pmt-interval", "PMT interval",
292 "Set the interval (in ticks of the 90kHz clock) for writing out the PMT table",
293 1, G_MAXUINT, TSMUX_DEFAULT_PMT_INTERVAL,
294 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
295
296 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_ALIGNMENT,
297 g_param_spec_int ("alignment", "packet alignment",
298 "Number of packets per buffer (padded with dummy packets on EOS) "
299 "(-1 = auto, 0 = all available packets, 7 for UDP streaming)",
300 -1, G_MAXINT, MPEGTSMUX_DEFAULT_ALIGNMENT,
301 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
302
303 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_SI_INTERVAL,
304 g_param_spec_uint ("si-interval", "SI interval",
305 "Set the interval (in ticks of the 90kHz clock) for writing out the Service"
306 "Information tables", 1, G_MAXUINT, TSMUX_DEFAULT_SI_INTERVAL,
307 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
308 }
309
310 static void
mpegtsmux_init(MpegTsMux * mux)311 mpegtsmux_init (MpegTsMux * mux)
312 {
313 mux->srcpad =
314 gst_pad_new_from_static_template (&mpegtsmux_src_factory, "src");
315 gst_pad_use_fixed_caps (mux->srcpad);
316 gst_pad_set_event_function (mux->srcpad,
317 GST_DEBUG_FUNCPTR (mpegtsmux_src_event));
318 gst_element_add_pad (GST_ELEMENT (mux), mux->srcpad);
319
320 mux->collect = gst_collect_pads_new ();
321 gst_collect_pads_set_buffer_function (mux->collect,
322 (GstCollectPadsBufferFunction)
323 GST_DEBUG_FUNCPTR (mpegtsmux_collected_buffer), mux);
324
325 gst_collect_pads_set_event_function (mux->collect,
326 (GstCollectPadsEventFunction) GST_DEBUG_FUNCPTR (mpegtsmux_sink_event),
327 mux);
328 gst_collect_pads_set_clip_function (mux->collect, (GstCollectPadsClipFunction)
329 GST_DEBUG_FUNCPTR (mpegtsmux_clip_inc_running_time), mux);
330
331 mux->adapter = gst_adapter_new ();
332 mux->out_adapter = gst_adapter_new ();
333
334 /* properties */
335 mux->m2ts_mode = MPEGTSMUX_DEFAULT_M2TS;
336 mux->pat_interval = TSMUX_DEFAULT_PAT_INTERVAL;
337 mux->pmt_interval = TSMUX_DEFAULT_PMT_INTERVAL;
338 mux->si_interval = TSMUX_DEFAULT_SI_INTERVAL;
339 mux->prog_map = NULL;
340 mux->alignment = MPEGTSMUX_DEFAULT_ALIGNMENT;
341
342 /* initial state */
343 mpegtsmux_reset (mux, TRUE);
344 }
345
346 static void
mpegtsmux_pad_reset(MpegTsPadData * pad_data)347 mpegtsmux_pad_reset (MpegTsPadData * pad_data)
348 {
349 pad_data->dts = GST_CLOCK_STIME_NONE;
350 pad_data->prog_id = -1;
351 #if 0
352 pad_data->prog_id = -1;
353 pad_data->element_index_writer_id = -1;
354 #endif
355
356 if (pad_data->free_func)
357 pad_data->free_func (pad_data->prepare_data);
358 pad_data->prepare_data = NULL;
359 pad_data->prepare_func = NULL;
360 pad_data->free_func = NULL;
361
362 if (pad_data->codec_data)
363 gst_buffer_replace (&pad_data->codec_data, NULL);
364
365 /* reference owned elsewhere */
366 pad_data->stream = NULL;
367 pad_data->prog = NULL;
368
369 if (pad_data->language) {
370 g_free (pad_data->language);
371 pad_data->language = NULL;
372 }
373
374 }
375
376 static void
mpegtsmux_reset(MpegTsMux * mux,gboolean alloc)377 mpegtsmux_reset (MpegTsMux * mux, gboolean alloc)
378 {
379 GstBuffer *buf;
380 GSList *walk;
381
382 mux->first = TRUE;
383 mux->last_flow_ret = GST_FLOW_OK;
384 mux->previous_pcr = -1;
385 mux->previous_offset = 0;
386 mux->pcr_rate_num = mux->pcr_rate_den = 1;
387 mux->last_ts = 0;
388 mux->is_delta = TRUE;
389 mux->is_header = FALSE;
390
391 mux->streamheader_sent = FALSE;
392 mux->pending_key_unit_ts = GST_CLOCK_TIME_NONE;
393 gst_event_replace (&mux->force_key_unit_event, NULL);
394 #if 0
395 mux->spn_count = 0;
396
397 if (mux->element_index) {
398 gst_object_unref (mux->element_index);
399 mux->element_index = NULL;
400 }
401 #endif
402 if (mux->adapter)
403 gst_adapter_clear (mux->adapter);
404 if (mux->out_adapter)
405 gst_adapter_clear (mux->out_adapter);
406
407 if (mux->tsmux) {
408 tsmux_free (mux->tsmux);
409 mux->tsmux = NULL;
410 }
411
412 if (mux->programs) {
413 g_hash_table_destroy (mux->programs);
414 }
415 mux->programs = g_hash_table_new (g_direct_hash, g_direct_equal);
416
417 while ((buf = g_queue_pop_head (&mux->streamheader)))
418 gst_buffer_unref (buf);
419
420 gst_event_replace (&mux->force_key_unit_event, NULL);
421 gst_buffer_replace (&mux->out_buffer, NULL);
422
423 if (mux->collect) {
424 GST_COLLECT_PADS_STREAM_LOCK (mux->collect);
425 for (walk = mux->collect->data; walk != NULL; walk = g_slist_next (walk))
426 mpegtsmux_pad_reset ((MpegTsPadData *) walk->data);
427 GST_COLLECT_PADS_STREAM_UNLOCK (mux->collect);
428 }
429
430 if (alloc) {
431 mux->tsmux = tsmux_new ();
432 tsmux_set_write_func (mux->tsmux, new_packet_cb, mux);
433 tsmux_set_alloc_func (mux->tsmux, alloc_packet_cb, mux);
434 }
435 }
436
437 static void
mpegtsmux_dispose(GObject * object)438 mpegtsmux_dispose (GObject * object)
439 {
440 MpegTsMux *mux = GST_MPEG_TSMUX (object);
441
442 mpegtsmux_reset (mux, FALSE);
443
444 if (mux->adapter) {
445 g_object_unref (mux->adapter);
446 mux->adapter = NULL;
447 }
448 if (mux->out_adapter) {
449 g_object_unref (mux->out_adapter);
450 mux->out_adapter = NULL;
451 }
452 if (mux->collect) {
453 gst_object_unref (mux->collect);
454 mux->collect = NULL;
455 }
456 if (mux->prog_map) {
457 gst_structure_free (mux->prog_map);
458 mux->prog_map = NULL;
459 }
460 if (mux->programs) {
461 g_hash_table_destroy (mux->programs);
462 mux->programs = NULL;
463 }
464 GST_CALL_PARENT (G_OBJECT_CLASS, dispose, (object));
465 }
466
467 static void
gst_mpegtsmux_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)468 gst_mpegtsmux_set_property (GObject * object, guint prop_id,
469 const GValue * value, GParamSpec * pspec)
470 {
471 MpegTsMux *mux = GST_MPEG_TSMUX (object);
472 GSList *walk;
473
474 switch (prop_id) {
475 case PROP_M2TS_MODE:
476 /*set incase if the output stream need to be of 192 bytes */
477 mux->m2ts_mode = g_value_get_boolean (value);
478 break;
479 case PROP_PROG_MAP:
480 {
481 const GstStructure *s = gst_value_get_structure (value);
482 if (mux->prog_map) {
483 gst_structure_free (mux->prog_map);
484 }
485 if (s)
486 mux->prog_map = gst_structure_copy (s);
487 else
488 mux->prog_map = NULL;
489 break;
490 }
491 case PROP_PAT_INTERVAL:
492 mux->pat_interval = g_value_get_uint (value);
493 if (mux->tsmux)
494 tsmux_set_pat_interval (mux->tsmux, mux->pat_interval);
495 break;
496 case PROP_PMT_INTERVAL:
497 walk = mux->collect->data;
498 mux->pmt_interval = g_value_get_uint (value);
499
500 while (walk) {
501 MpegTsPadData *ts_data = (MpegTsPadData *) walk->data;
502
503 tsmux_set_pmt_interval (ts_data->prog, mux->pmt_interval);
504 walk = g_slist_next (walk);
505 }
506 break;
507 case PROP_ALIGNMENT:
508 mux->alignment = g_value_get_int (value);
509 break;
510 case PROP_SI_INTERVAL:
511 mux->si_interval = g_value_get_uint (value);
512 tsmux_set_si_interval (mux->tsmux, mux->si_interval);
513 break;
514 default:
515 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
516 break;
517 }
518 }
519
520 static void
gst_mpegtsmux_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)521 gst_mpegtsmux_get_property (GObject * object, guint prop_id,
522 GValue * value, GParamSpec * pspec)
523 {
524 MpegTsMux *mux = GST_MPEG_TSMUX (object);
525
526 switch (prop_id) {
527 case PROP_M2TS_MODE:
528 g_value_set_boolean (value, mux->m2ts_mode);
529 break;
530 case PROP_PROG_MAP:
531 gst_value_set_structure (value, mux->prog_map);
532 break;
533 case PROP_PAT_INTERVAL:
534 g_value_set_uint (value, mux->pat_interval);
535 break;
536 case PROP_PMT_INTERVAL:
537 g_value_set_uint (value, mux->pmt_interval);
538 break;
539 case PROP_ALIGNMENT:
540 g_value_set_int (value, mux->alignment);
541 break;
542 case PROP_SI_INTERVAL:
543 g_value_set_uint (value, mux->si_interval);
544 break;
545 default:
546 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
547 break;
548 }
549 }
550
551 #if 0
552 static void
553 mpegtsmux_set_index (GstElement * element, GstIndex * index)
554 {
555 MpegTsMux *mux = GST_MPEG_TSMUX (element);
556
557 GST_OBJECT_LOCK (mux);
558 if (mux->element_index)
559 gst_object_unref (mux->element_index);
560 mux->element_index = index ? gst_object_ref (index) : NULL;
561 GST_OBJECT_UNLOCK (mux);
562
563 GST_DEBUG_OBJECT (mux, "Set index %" GST_PTR_FORMAT, mux->element_index);
564 }
565
566 static GstIndex *
567 mpegtsmux_get_index (GstElement * element)
568 {
569 GstIndex *result = NULL;
570 MpegTsMux *mux = GST_MPEG_TSMUX (element);
571
572 GST_OBJECT_LOCK (mux);
573 if (mux->element_index)
574 result = gst_object_ref (mux->element_index);
575 GST_OBJECT_UNLOCK (mux);
576
577 GST_DEBUG_OBJECT (mux, "Returning index %" GST_PTR_FORMAT, result);
578
579 return result;
580 }
581 #endif
582
583 static void
release_buffer_cb(guint8 * data,void * user_data)584 release_buffer_cb (guint8 * data, void *user_data)
585 {
586 stream_data_free (user_data);
587 }
588
589 static GstFlowReturn
mpegtsmux_create_stream(MpegTsMux * mux,MpegTsPadData * ts_data)590 mpegtsmux_create_stream (MpegTsMux * mux, MpegTsPadData * ts_data)
591 {
592 GstFlowReturn ret = GST_FLOW_ERROR;
593 GstCaps *caps;
594 GstStructure *s;
595 GstPad *pad;
596 TsMuxStreamType st = TSMUX_ST_RESERVED;
597 const gchar *mt;
598 const GValue *value = NULL;
599 GstBuffer *codec_data = NULL;
600 guint8 opus_channel_config_code = 0;
601 guint16 profile = 0;
602 guint8 main_level = 0;
603 guint32 max_rate = 0;
604 guint8 color_spec = 0;
605 j2k_private_data *private_data = NULL;
606
607 pad = ts_data->collect.pad;
608 caps = gst_pad_get_current_caps (pad);
609 if (caps == NULL)
610 goto not_negotiated;
611
612 GST_DEBUG_OBJECT (pad, "Creating stream with PID 0x%04x for caps %"
613 GST_PTR_FORMAT, ts_data->pid, caps);
614
615 s = gst_caps_get_structure (caps, 0);
616
617 mt = gst_structure_get_name (s);
618 value = gst_structure_get_value (s, "codec_data");
619 if (value != NULL)
620 codec_data = gst_value_get_buffer (value);
621
622 if (strcmp (mt, "video/x-dirac") == 0) {
623 st = TSMUX_ST_VIDEO_DIRAC;
624 } else if (strcmp (mt, "audio/x-ac3") == 0) {
625 st = TSMUX_ST_PS_AUDIO_AC3;
626 } else if (strcmp (mt, "audio/x-dts") == 0) {
627 st = TSMUX_ST_PS_AUDIO_DTS;
628 } else if (strcmp (mt, "audio/x-lpcm") == 0) {
629 st = TSMUX_ST_PS_AUDIO_LPCM;
630 } else if (strcmp (mt, "video/x-h264") == 0) {
631 st = TSMUX_ST_VIDEO_H264;
632 } else if (strcmp (mt, "video/x-h265") == 0) {
633 st = TSMUX_ST_VIDEO_HEVC;
634 } else if (strcmp (mt, "audio/mpeg") == 0) {
635 gint mpegversion;
636
637 if (!gst_structure_get_int (s, "mpegversion", &mpegversion)) {
638 GST_ERROR_OBJECT (pad, "caps missing mpegversion");
639 goto not_negotiated;
640 }
641
642 switch (mpegversion) {
643 case 1:
644 st = TSMUX_ST_AUDIO_MPEG1;
645 break;
646 case 2:
647 st = TSMUX_ST_AUDIO_MPEG2;
648 break;
649 case 4:
650 {
651 st = TSMUX_ST_AUDIO_AAC;
652 if (codec_data) { /* TODO - Check stream format - codec data should only come with RAW stream */
653 GST_DEBUG_OBJECT (pad,
654 "we have additional codec data (%" G_GSIZE_FORMAT " bytes)",
655 gst_buffer_get_size (codec_data));
656 ts_data->codec_data = gst_buffer_ref (codec_data);
657 ts_data->prepare_func = mpegtsmux_prepare_aac;
658 } else {
659 ts_data->codec_data = NULL;
660 }
661 break;
662 }
663 default:
664 GST_WARNING_OBJECT (pad, "unsupported mpegversion %d", mpegversion);
665 goto not_negotiated;
666 }
667 } else if (strcmp (mt, "video/mpeg") == 0) {
668 gint mpegversion;
669
670 if (!gst_structure_get_int (s, "mpegversion", &mpegversion)) {
671 GST_ERROR_OBJECT (pad, "caps missing mpegversion");
672 goto not_negotiated;
673 }
674
675 switch (mpegversion) {
676 case 1:
677 st = TSMUX_ST_VIDEO_MPEG1;
678 break;
679 case 2:
680 st = TSMUX_ST_VIDEO_MPEG2;
681 break;
682 case 4:
683 st = TSMUX_ST_VIDEO_MPEG4;
684 break;
685 default:
686 GST_WARNING_OBJECT (pad, "unsupported mpegversion %d", mpegversion);
687 goto not_negotiated;
688 }
689 } else if (strcmp (mt, "subpicture/x-dvb") == 0) {
690 st = TSMUX_ST_PS_DVB_SUBPICTURE;
691 } else if (strcmp (mt, "application/x-teletext") == 0) {
692 st = TSMUX_ST_PS_TELETEXT;
693 /* needs a particularly sized layout */
694 ts_data->prepare_func = mpegtsmux_prepare_teletext;
695 } else if (strcmp (mt, "audio/x-opus") == 0) {
696 guint8 channels, mapping_family, stream_count, coupled_count;
697 guint8 channel_mapping[256];
698
699 if (!gst_codec_utils_opus_parse_caps (caps, NULL, &channels,
700 &mapping_family, &stream_count, &coupled_count, channel_mapping)) {
701 GST_ERROR_OBJECT (pad, "Incomplete Opus caps");
702 goto not_negotiated;
703 }
704
705 if (channels <= 2 && mapping_family == 0) {
706 opus_channel_config_code = channels;
707 } else if (channels == 2 && mapping_family == 255 && stream_count == 1
708 && coupled_count == 1) {
709 /* Dual mono */
710 opus_channel_config_code = 0;
711 } else if (channels >= 2 && channels <= 8 && mapping_family == 1) {
712 static const guint8 coupled_stream_counts[9] = {
713 1, 0, 1, 1, 2, 2, 2, 3, 3
714 };
715 static const guint8 channel_map_a[8][8] = {
716 {0},
717 {0, 1},
718 {0, 2, 1},
719 {0, 1, 2, 3},
720 {0, 4, 1, 2, 3},
721 {0, 4, 1, 2, 3, 5},
722 {0, 4, 1, 2, 3, 5, 6},
723 {0, 6, 1, 2, 3, 4, 5, 7},
724 };
725 static const guint8 channel_map_b[8][8] = {
726 {0},
727 {0, 1},
728 {0, 1, 2},
729 {0, 1, 2, 3},
730 {0, 1, 2, 3, 4},
731 {0, 1, 2, 3, 4, 5},
732 {0, 1, 2, 3, 4, 5, 6},
733 {0, 1, 2, 3, 4, 5, 6, 7},
734 };
735
736 /* Vorbis mapping */
737 if (stream_count == channels - coupled_stream_counts[channels] &&
738 coupled_count == coupled_stream_counts[channels] &&
739 memcmp (channel_mapping, channel_map_a[channels - 1],
740 channels) == 0) {
741 opus_channel_config_code = channels;
742 } else if (stream_count == channels - coupled_stream_counts[channels] &&
743 coupled_count == coupled_stream_counts[channels] &&
744 memcmp (channel_mapping, channel_map_b[channels - 1],
745 channels) == 0) {
746 opus_channel_config_code = channels | 0x80;
747 } else {
748 GST_FIXME_OBJECT (pad, "Opus channel mapping not handled");
749 goto not_negotiated;
750 }
751 }
752
753 st = TSMUX_ST_PS_OPUS;
754 ts_data->prepare_func = mpegtsmux_prepare_opus;
755 } else if (strcmp (mt, "meta/x-klv") == 0) {
756 st = TSMUX_ST_PS_KLV;
757 } else if (strcmp (mt, "image/x-jpc") == 0) {
758 /*
759 * See this document for more details on standard:
760 *
761 * https://www.itu.int/rec/T-REC-H.222.0-201206-S/en
762 * Annex S describes J2K details
763 * Page 104 of this document describes J2k video descriptor
764 */
765
766 const GValue *vProfile = gst_structure_get_value (s, "profile");
767 const GValue *vMainlevel = gst_structure_get_value (s, "main-level");
768 const GValue *vFramerate = gst_structure_get_value (s, "framerate");
769 const GValue *vColorimetry = gst_structure_get_value (s, "colorimetry");
770 private_data = g_new0 (j2k_private_data, 1);
771 profile = g_value_get_uint (vProfile);
772 if (profile != GST_JPEG2000_PARSE_PROFILE_BC_SINGLE) {
773 /* for now, we will relax the condition that the profile must equal GST_JPEG2000_PARSE_PROFILE_BC_SINGLE */
774 /*GST_ERROR_OBJECT (pad, "Invalid JPEG 2000 profile %d", profile);
775 goto not_negotiated; */
776 }
777 /* for now, we will relax the condition that the main level must be present */
778 if (vMainlevel) {
779 main_level = g_value_get_uint (vMainlevel);
780 if (main_level > 11) {
781 GST_ERROR_OBJECT (pad, "Invalid main level %d", main_level);
782 goto not_negotiated;
783 }
784 if (main_level >= 6) {
785 max_rate = 2 ^ (main_level - 6) * 1600 * 1000000;
786 } else {
787 switch (main_level) {
788 case 0:
789 case 1:
790 case 2:
791 case 3:
792 max_rate = 200 * 1000000;
793 break;
794 case 4:
795 max_rate = 400 * 1000000;
796 break;
797 case 5:
798 max_rate = 800 * 1000000;
799 break;
800 default:
801 break;
802 }
803 }
804 } else {
805 /*GST_ERROR_OBJECT (pad, "Missing main level");
806 goto not_negotiated; */
807 }
808 /* We always mux video in J2K-over-MPEG-TS non-interlaced mode */
809 private_data->interlace = FALSE;
810 private_data->den = 0;
811 private_data->num = 0;
812 private_data->max_bitrate = max_rate;
813 private_data->color_spec = 1;
814 /* these two fields are not used, since we always mux as non-interlaced */
815 private_data->Fic = 1;
816 private_data->Fio = 0;
817
818 /* Get Framerate */
819 if (vFramerate != NULL) {
820 /* Data for ELSM header */
821 private_data->num = gst_value_get_fraction_numerator (vFramerate);
822 private_data->den = gst_value_get_fraction_denominator (vFramerate);
823 }
824 /* Get Colorimetry */
825 if (vColorimetry) {
826 const char *colorimetry = g_value_get_string (vColorimetry);
827 color_spec = GST_MPEGTS_JPEG2000_COLORSPEC_SRGB; /* RGB as default */
828 if (g_str_equal (colorimetry, GST_VIDEO_COLORIMETRY_BT601)) {
829 color_spec = GST_MPEGTS_JPEG2000_COLORSPEC_REC601;
830 } else {
831 if (g_str_equal (colorimetry, GST_VIDEO_COLORIMETRY_BT709)
832 || g_str_equal (colorimetry, GST_VIDEO_COLORIMETRY_SMPTE240M)) {
833 color_spec = GST_MPEGTS_JPEG2000_COLORSPEC_REC709;
834 }
835 }
836 private_data->color_spec = color_spec;
837 } else {
838 GST_ERROR_OBJECT (pad, "Colorimetry not present in caps");
839 goto not_negotiated;
840 }
841 st = TSMUX_ST_VIDEO_JP2K;
842 ts_data->prepare_func = mpegtsmux_prepare_jpeg2000;
843 ts_data->prepare_data = private_data;
844 ts_data->free_func = mpegtsmux_free_jpeg2000;
845 }
846
847 if (st != TSMUX_ST_RESERVED) {
848 ts_data->stream = tsmux_create_stream (mux->tsmux, st, ts_data->pid,
849 ts_data->language);
850 } else {
851 GST_DEBUG_OBJECT (pad, "Failed to determine stream type");
852 }
853
854 if (ts_data->stream != NULL) {
855 const char *interlace_mode = gst_structure_get_string (s, "interlace-mode");
856 gst_structure_get_int (s, "rate", &ts_data->stream->audio_sampling);
857 gst_structure_get_int (s, "channels", &ts_data->stream->audio_channels);
858 gst_structure_get_int (s, "bitrate", &ts_data->stream->audio_bitrate);
859
860 /* frame rate */
861 gst_structure_get_fraction (s, "framerate", &ts_data->stream->num,
862 &ts_data->stream->den);
863
864 /* Interlace mode */
865 ts_data->stream->interlace_mode = FALSE;
866 if (interlace_mode) {
867 ts_data->stream->interlace_mode =
868 g_str_equal (interlace_mode, "interleaved");
869 }
870 /* Width and Height */
871 gst_structure_get_int (s, "width", &ts_data->stream->horizontal_size);
872 gst_structure_get_int (s, "height", &ts_data->stream->vertical_size);
873
874 ts_data->stream->color_spec = color_spec;
875 ts_data->stream->max_bitrate = max_rate;
876 ts_data->stream->profile_and_level = profile | main_level;
877
878 ts_data->stream->opus_channel_config_code = opus_channel_config_code;
879
880 tsmux_stream_set_buffer_release_func (ts_data->stream, release_buffer_cb);
881 tsmux_program_add_stream (ts_data->prog, ts_data->stream);
882
883 ret = GST_FLOW_OK;
884 }
885 #if 0
886 GST_OBJECT_LOCK (mux);
887 if (mux->element_index) {
888 gboolean parsed = FALSE;
889
890 if (ts_data->stream->is_video_stream) {
891 if (gst_structure_get_boolean (s, "parsed", &parsed) && parsed) {
892 if (ts_data->element_index_writer_id == -1) {
893 gst_index_get_writer_id (mux->element_index, GST_OBJECT (mux),
894 &ts_data->element_index_writer_id);
895 GST_DEBUG_OBJECT (mux, "created GstIndex writer_id = %d for stream",
896 ts_data->element_index_writer_id);
897 gst_index_add_format (mux->element_index,
898 ts_data->element_index_writer_id, pts_format);
899 gst_index_add_format (mux->element_index,
900 ts_data->element_index_writer_id, spn_format);
901 }
902 } else {
903 GST_WARNING_OBJECT (pad, "no indexing for (unparsed) stream !");
904 }
905 }
906 }
907 GST_OBJECT_UNLOCK (mux);
908 #endif
909 gst_caps_unref (caps);
910 return ret;
911 /* ERRORS */
912 not_negotiated:
913 {
914 g_free (private_data);
915 GST_DEBUG_OBJECT (pad, "Sink pad caps were not set before pushing");
916 if (caps)
917 gst_caps_unref (caps);
918 return GST_FLOW_NOT_NEGOTIATED;
919 }
920 }
921
922 static GstFlowReturn
mpegtsmux_create_streams(MpegTsMux * mux)923 mpegtsmux_create_streams (MpegTsMux * mux)
924 {
925 GstFlowReturn ret = GST_FLOW_OK;
926 GSList *walk = mux->collect->data;
927
928 /* Create the streams */
929 while (walk) {
930 GstCollectData *c_data = (GstCollectData *) walk->data;
931 MpegTsPadData *ts_data = (MpegTsPadData *) walk->data;
932 gchar *name = NULL;
933 gchar *pcr_name;
934
935 walk = g_slist_next (walk);
936
937 if (ts_data->prog_id == -1) {
938 name = GST_PAD_NAME (c_data->pad);
939 if (mux->prog_map != NULL && gst_structure_has_field (mux->prog_map,
940 name)) {
941 gint idx;
942 gboolean ret = gst_structure_get_int (mux->prog_map, name, &idx);
943 if (!ret) {
944 GST_ELEMENT_ERROR (mux, STREAM, MUX,
945 ("Reading program map failed. Assuming default"), (NULL));
946 idx = DEFAULT_PROG_ID;
947 }
948 if (idx < 0) {
949 GST_DEBUG_OBJECT (mux, "Program number %d associate with pad %s less "
950 "than zero; DEFAULT_PROGRAM = %d is used instead",
951 idx, name, DEFAULT_PROG_ID);
952 idx = DEFAULT_PROG_ID;
953 }
954 ts_data->prog_id = idx;
955 } else {
956 ts_data->prog_id = DEFAULT_PROG_ID;
957 }
958 }
959
960 ts_data->prog =
961 g_hash_table_lookup (mux->programs, GINT_TO_POINTER (ts_data->prog_id));
962 if (ts_data->prog == NULL) {
963 ts_data->prog = tsmux_program_new (mux->tsmux, ts_data->prog_id);
964 if (ts_data->prog == NULL)
965 goto no_program;
966 tsmux_set_pmt_interval (ts_data->prog, mux->pmt_interval);
967 g_hash_table_insert (mux->programs,
968 GINT_TO_POINTER (ts_data->prog_id), ts_data->prog);
969
970 /* Take the first stream of the program for the PCR */
971 GST_DEBUG_OBJECT (COLLECT_DATA_PAD (ts_data),
972 "Use stream (pid=%d) from pad as PCR for program (prog_id = %d)",
973 ts_data->pid, ts_data->prog_id);
974
975 tsmux_program_set_pcr_stream (ts_data->prog, ts_data->stream);
976 }
977
978 if (ts_data->stream == NULL) {
979 ret = mpegtsmux_create_stream (mux, ts_data);
980 if (ret != GST_FLOW_OK)
981 goto no_stream;
982 }
983
984 /* Check for user-specified PCR PID */
985 pcr_name = g_strdup_printf ("PCR_%d", ts_data->prog->pgm_number);
986 if (mux->prog_map && gst_structure_has_field (mux->prog_map, pcr_name)) {
987 const gchar *sink_name =
988 gst_structure_get_string (mux->prog_map, pcr_name);
989
990 if (!g_strcmp0 (name, sink_name)) {
991 GST_DEBUG_OBJECT (mux, "User specified stream (pid=%d) as PCR for "
992 "program (prog_id = %d)", ts_data->pid, ts_data->prog->pgm_number);
993 tsmux_program_set_pcr_stream (ts_data->prog, ts_data->stream);
994 }
995 }
996 g_free (pcr_name);
997 }
998
999 return GST_FLOW_OK;
1000
1001 /* ERRORS */
1002 no_program:
1003 {
1004 GST_ELEMENT_ERROR (mux, STREAM, MUX,
1005 ("Could not create new program"), (NULL));
1006 return GST_FLOW_ERROR;
1007 }
1008 no_stream:
1009 {
1010 GST_ELEMENT_ERROR (mux, STREAM, MUX,
1011 ("Could not create handler for stream"), (NULL));
1012 return ret;
1013 }
1014 }
1015
1016 static gboolean
mpegtsmux_sink_event(GstCollectPads * pads,GstCollectData * data,GstEvent * event,gpointer user_data)1017 mpegtsmux_sink_event (GstCollectPads * pads, GstCollectData * data,
1018 GstEvent * event, gpointer user_data)
1019 {
1020 MpegTsMux *mux = GST_MPEG_TSMUX (user_data);
1021 gboolean res = FALSE;
1022 gboolean forward = TRUE;
1023 MpegTsPadData *pad_data = (MpegTsPadData *) data;
1024
1025 #ifndef GST_DISABLE_GST_DEBUG
1026 GstPad *pad;
1027
1028 pad = data->pad;
1029 #endif
1030
1031 switch (GST_EVENT_TYPE (event)) {
1032 case GST_EVENT_CUSTOM_DOWNSTREAM:
1033 {
1034 GstClockTime timestamp, stream_time, running_time;
1035 gboolean all_headers;
1036 guint count;
1037
1038 if (!gst_video_event_is_force_key_unit (event))
1039 goto out;
1040
1041 res = TRUE;
1042 forward = FALSE;
1043
1044 gst_video_event_parse_downstream_force_key_unit (event,
1045 ×tamp, &stream_time, &running_time, &all_headers, &count);
1046 GST_INFO_OBJECT (pad, "have downstream force-key-unit event, "
1047 "seqnum %d, running-time %" GST_TIME_FORMAT " count %d",
1048 gst_event_get_seqnum (event), GST_TIME_ARGS (running_time), count);
1049
1050 if (mux->force_key_unit_event != NULL) {
1051 GST_INFO_OBJECT (mux, "skipping downstream force key unit event "
1052 "as an upstream force key unit is already queued");
1053 goto out;
1054 }
1055
1056 if (!all_headers)
1057 goto out;
1058
1059 mux->pending_key_unit_ts = running_time;
1060 gst_event_replace (&mux->force_key_unit_event, event);
1061 break;
1062 }
1063 case GST_EVENT_TAG:{
1064 GstTagList *list;
1065 gchar *lang = NULL;
1066
1067 GST_DEBUG_OBJECT (mux, "received tag event");
1068 gst_event_parse_tag (event, &list);
1069
1070 /* Matroska wants ISO 639-2B code, taglist most likely contains 639-1 */
1071 if (gst_tag_list_get_string (list, GST_TAG_LANGUAGE_CODE, &lang)) {
1072 const gchar *lang_code;
1073
1074 lang_code = gst_tag_get_language_code_iso_639_2B (lang);
1075 if (lang_code) {
1076 GST_DEBUG_OBJECT (pad, "Setting language to '%s'", lang_code);
1077
1078 g_free (pad_data->language);
1079 pad_data->language = g_strdup (lang_code);
1080 } else {
1081 GST_WARNING_OBJECT (pad, "Did not get language code for '%s'", lang);
1082 }
1083 g_free (lang);
1084 }
1085
1086 /* handled this, don't want collectpads to forward it downstream */
1087 res = TRUE;
1088 forward = gst_tag_list_get_scope (list) == GST_TAG_SCOPE_GLOBAL;
1089 break;
1090 }
1091 case GST_EVENT_STREAM_START:{
1092 GstStreamFlags flags;
1093
1094 gst_event_parse_stream_flags (event, &flags);
1095
1096 /* Don't wait for data on sparse inputs like metadata streams */
1097 if ((flags & GST_STREAM_FLAG_SPARSE)) {
1098 GST_COLLECT_PADS_STATE_UNSET (data, GST_COLLECT_PADS_STATE_LOCKED);
1099 gst_collect_pads_set_waiting (pads, data, FALSE);
1100 GST_COLLECT_PADS_STATE_SET (data, GST_COLLECT_PADS_STATE_LOCKED);
1101 }
1102 break;
1103 }
1104 case GST_EVENT_FLUSH_STOP:{
1105 GList *cur;
1106
1107 /* Send initial segments again after a flush-stop, and also resend the
1108 * header sections */
1109 mux->first = TRUE;
1110
1111 /* output PAT, SI tables */
1112 tsmux_resend_pat (mux->tsmux);
1113 tsmux_resend_si (mux->tsmux);
1114
1115 /* output PMT for each program */
1116 for (cur = mux->tsmux->programs; cur; cur = cur->next) {
1117 TsMuxProgram *program = (TsMuxProgram *) cur->data;
1118
1119 tsmux_resend_pmt (program);
1120 }
1121 break;
1122 }
1123 default:
1124 break;
1125 }
1126
1127 out:
1128 if (!forward)
1129 gst_event_unref (event);
1130 else
1131 res = gst_collect_pads_event_default (pads, data, event, FALSE);
1132
1133 return res;
1134 }
1135
1136 static gboolean
mpegtsmux_src_event(GstPad * pad,GstObject * parent,GstEvent * event)1137 mpegtsmux_src_event (GstPad * pad, GstObject * parent, GstEvent * event)
1138 {
1139 MpegTsMux *mux = GST_MPEG_TSMUX (parent);
1140 gboolean res = TRUE, forward = TRUE;
1141
1142 switch (GST_EVENT_TYPE (event)) {
1143 case GST_EVENT_CUSTOM_UPSTREAM:
1144 {
1145 GstIterator *iter;
1146 GstIteratorResult iter_ret;
1147 GstPad *sinkpad;
1148 GValue sinkpad_value = G_VALUE_INIT;
1149 GstClockTime running_time;
1150 gboolean all_headers, done, res = FALSE;
1151 guint count;
1152
1153 if (!gst_video_event_is_force_key_unit (event))
1154 break;
1155
1156 forward = FALSE;
1157
1158 gst_video_event_parse_upstream_force_key_unit (event,
1159 &running_time, &all_headers, &count);
1160
1161 GST_INFO_OBJECT (mux, "received upstream force-key-unit event, "
1162 "seqnum %d running_time %" GST_TIME_FORMAT " all_headers %d count %d",
1163 gst_event_get_seqnum (event), GST_TIME_ARGS (running_time),
1164 all_headers, count);
1165
1166 if (!all_headers)
1167 break;
1168
1169 mux->pending_key_unit_ts = running_time;
1170 gst_event_replace (&mux->force_key_unit_event, event);
1171
1172 iter = gst_element_iterate_sink_pads (GST_ELEMENT_CAST (mux));
1173 done = FALSE;
1174 while (!done) {
1175 gboolean tmp;
1176
1177 iter_ret = gst_iterator_next (iter, &sinkpad_value);
1178 sinkpad = g_value_get_object (&sinkpad_value);
1179
1180 switch (iter_ret) {
1181 case GST_ITERATOR_DONE:
1182 done = TRUE;
1183 break;
1184 case GST_ITERATOR_OK:
1185 GST_INFO_OBJECT (pad, "forwarding");
1186 tmp = gst_pad_push_event (sinkpad, gst_event_ref (event));
1187 GST_INFO_OBJECT (mux, "result %d", tmp);
1188 /* succeed if at least one pad succeeds */
1189 res |= tmp;
1190 break;
1191 case GST_ITERATOR_ERROR:
1192 done = TRUE;
1193 break;
1194 case GST_ITERATOR_RESYNC:
1195 break;
1196 }
1197 g_value_reset (&sinkpad_value);
1198 }
1199 g_value_unset (&sinkpad_value);
1200 gst_iterator_free (iter);
1201 break;
1202 }
1203 default:
1204 break;
1205 }
1206
1207 if (forward)
1208 res = gst_pad_event_default (pad, parent, event);
1209 else
1210 gst_event_unref (event);
1211
1212 return res;
1213 }
1214
1215 static GstEvent *
check_pending_key_unit_event(GstEvent * pending_event,GstSegment * segment,GstClockTime timestamp,guint flags,GstClockTime pending_key_unit_ts)1216 check_pending_key_unit_event (GstEvent * pending_event, GstSegment * segment,
1217 GstClockTime timestamp, guint flags, GstClockTime pending_key_unit_ts)
1218 {
1219 GstClockTime running_time, stream_time;
1220 gboolean all_headers;
1221 guint count;
1222 GstEvent *event = NULL;
1223
1224 g_assert (segment != NULL);
1225
1226 if (pending_event == NULL)
1227 goto out;
1228
1229 if (GST_CLOCK_TIME_IS_VALID (pending_key_unit_ts) &&
1230 timestamp == GST_CLOCK_TIME_NONE)
1231 goto out;
1232
1233 running_time = timestamp;
1234
1235 GST_INFO ("now %" GST_TIME_FORMAT " wanted %" GST_TIME_FORMAT,
1236 GST_TIME_ARGS (running_time), GST_TIME_ARGS (pending_key_unit_ts));
1237 if (GST_CLOCK_TIME_IS_VALID (pending_key_unit_ts) &&
1238 running_time < pending_key_unit_ts)
1239 goto out;
1240
1241 if (flags & GST_BUFFER_FLAG_DELTA_UNIT) {
1242 GST_INFO ("pending force key unit, waiting for keyframe");
1243 goto out;
1244 }
1245
1246 stream_time = gst_segment_to_stream_time (segment,
1247 GST_FORMAT_TIME, timestamp);
1248
1249 if (GST_EVENT_TYPE (pending_event) == GST_EVENT_CUSTOM_DOWNSTREAM) {
1250 gst_video_event_parse_downstream_force_key_unit (pending_event,
1251 NULL, NULL, NULL, &all_headers, &count);
1252 } else {
1253 gst_video_event_parse_upstream_force_key_unit (pending_event, NULL,
1254 &all_headers, &count);
1255 }
1256
1257 event =
1258 gst_video_event_new_downstream_force_key_unit (timestamp, stream_time,
1259 running_time, all_headers, count);
1260 gst_event_set_seqnum (event, gst_event_get_seqnum (pending_event));
1261
1262 out:
1263 return event;
1264 }
1265
1266 GstFlowReturn
mpegtsmux_clip_inc_running_time(GstCollectPads * pads,GstCollectData * cdata,GstBuffer * buf,GstBuffer ** outbuf,gpointer user_data)1267 mpegtsmux_clip_inc_running_time (GstCollectPads * pads,
1268 GstCollectData * cdata, GstBuffer * buf, GstBuffer ** outbuf,
1269 gpointer user_data)
1270 {
1271 MpegTsPadData *pad_data = (MpegTsPadData *) cdata;
1272 GstClockTime time;
1273
1274 *outbuf = buf;
1275
1276 /* PTS */
1277 time = GST_BUFFER_PTS (buf);
1278
1279 /* invalid left alone and passed */
1280 if (G_LIKELY (GST_CLOCK_TIME_IS_VALID (time))) {
1281 time = gst_segment_to_running_time (&cdata->segment, GST_FORMAT_TIME, time);
1282 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (time))) {
1283 GST_DEBUG_OBJECT (cdata->pad, "clipping buffer on pad outside segment");
1284 gst_buffer_unref (buf);
1285 *outbuf = NULL;
1286 goto beach;
1287 } else {
1288 GST_LOG_OBJECT (cdata->pad, "buffer pts %" GST_TIME_FORMAT " -> %"
1289 GST_TIME_FORMAT " running time",
1290 GST_TIME_ARGS (GST_BUFFER_PTS (buf)), GST_TIME_ARGS (time));
1291 buf = *outbuf = gst_buffer_make_writable (buf);
1292 GST_BUFFER_PTS (*outbuf) = time;
1293 }
1294 }
1295
1296 /* DTS */
1297 time = GST_BUFFER_DTS (buf);
1298
1299 /* invalid left alone and passed */
1300 if (G_LIKELY (GST_CLOCK_TIME_IS_VALID (time))) {
1301 gint sign;
1302 gint64 dts;
1303
1304 sign = gst_segment_to_running_time_full (&cdata->segment, GST_FORMAT_TIME,
1305 time, &time);
1306
1307 if (sign > 0)
1308 dts = (gint64) time;
1309 else
1310 dts = -((gint64) time);
1311
1312 GST_LOG_OBJECT (cdata->pad, "buffer dts %" GST_TIME_FORMAT " -> %"
1313 GST_STIME_FORMAT " running time", GST_TIME_ARGS (GST_BUFFER_DTS (buf)),
1314 GST_STIME_ARGS (dts));
1315
1316 if (GST_CLOCK_STIME_IS_VALID (pad_data->dts) && dts < pad_data->dts) {
1317 /* Ignore DTS going backward */
1318 GST_WARNING_OBJECT (cdata->pad, "ignoring DTS going backward");
1319 dts = pad_data->dts;
1320 }
1321
1322 *outbuf = gst_buffer_make_writable (buf);
1323 if (sign > 0)
1324 GST_BUFFER_DTS (*outbuf) = time;
1325 else
1326 GST_BUFFER_DTS (*outbuf) = GST_CLOCK_TIME_NONE;
1327
1328 pad_data->dts = dts;
1329 } else {
1330 pad_data->dts = GST_CLOCK_STIME_NONE;
1331 }
1332
1333 beach:
1334 return GST_FLOW_OK;
1335 }
1336
1337 static GstFlowReturn
mpegtsmux_collected_buffer(GstCollectPads * pads,GstCollectData * data,GstBuffer * buf,MpegTsMux * mux)1338 mpegtsmux_collected_buffer (GstCollectPads * pads, GstCollectData * data,
1339 GstBuffer * buf, MpegTsMux * mux)
1340 {
1341 GstFlowReturn ret = GST_FLOW_OK;
1342 MpegTsPadData *best = (MpegTsPadData *) data;
1343 TsMuxProgram *prog;
1344 gint64 pts = GST_CLOCK_STIME_NONE;
1345 gint64 dts = GST_CLOCK_STIME_NONE;
1346 gboolean delta = TRUE, header = FALSE;
1347 StreamData *stream_data;
1348
1349 GST_DEBUG_OBJECT (mux, "Pads collected");
1350
1351 if (G_UNLIKELY (mux->first)) {
1352 ret = mpegtsmux_create_streams (mux);
1353 if (G_UNLIKELY (ret != GST_FLOW_OK)) {
1354 if (buf)
1355 gst_buffer_unref (buf);
1356 return ret;
1357 }
1358
1359 mpegtsmux_prepare_srcpad (mux);
1360
1361 mux->first = FALSE;
1362 }
1363
1364 if (G_UNLIKELY (best == NULL)) {
1365 /* EOS */
1366 GST_INFO_OBJECT (mux, "EOS");
1367 /* drain some possibly cached data */
1368 new_packet_m2ts (mux, NULL, -1);
1369 mpegtsmux_push_packets (mux, TRUE);
1370 gst_pad_push_event (mux->srcpad, gst_event_new_eos ());
1371
1372 if (buf)
1373 gst_buffer_unref (buf);
1374
1375 return GST_FLOW_OK;
1376 }
1377
1378 prog = best->prog;
1379 if (prog == NULL)
1380 goto no_program;
1381
1382 g_assert (buf != NULL);
1383
1384 if (best->prepare_func) {
1385 GstBuffer *tmp;
1386
1387 tmp = best->prepare_func (buf, best, mux);
1388 g_assert (tmp);
1389 gst_buffer_unref (buf);
1390 buf = tmp;
1391 }
1392
1393 if (mux->force_key_unit_event != NULL && best->stream->is_video_stream) {
1394 GstEvent *event;
1395
1396 event = check_pending_key_unit_event (mux->force_key_unit_event,
1397 &best->collect.segment, GST_BUFFER_PTS (buf),
1398 GST_BUFFER_FLAGS (buf), mux->pending_key_unit_ts);
1399 if (event) {
1400 GstClockTime running_time;
1401 guint count;
1402 GList *cur;
1403
1404 mux->pending_key_unit_ts = GST_CLOCK_TIME_NONE;
1405 gst_event_replace (&mux->force_key_unit_event, NULL);
1406
1407 gst_video_event_parse_downstream_force_key_unit (event,
1408 NULL, NULL, &running_time, NULL, &count);
1409
1410 GST_INFO_OBJECT (mux, "pushing downstream force-key-unit event %d "
1411 "%" GST_TIME_FORMAT " count %d", gst_event_get_seqnum (event),
1412 GST_TIME_ARGS (running_time), count);
1413 gst_pad_push_event (mux->srcpad, event);
1414
1415 /* output PAT, SI tables */
1416 tsmux_resend_pat (mux->tsmux);
1417 tsmux_resend_si (mux->tsmux);
1418
1419 /* output PMT for each program */
1420 for (cur = mux->tsmux->programs; cur; cur = cur->next) {
1421 TsMuxProgram *program = (TsMuxProgram *) cur->data;
1422
1423 tsmux_resend_pmt (program);
1424 }
1425 }
1426 }
1427
1428 if (G_UNLIKELY (prog->pcr_stream == NULL)) {
1429 /* Take the first data stream for the PCR */
1430 GST_DEBUG_OBJECT (COLLECT_DATA_PAD (best),
1431 "Use stream (pid=%d) from pad as PCR for program (prog_id = %d)",
1432 best->pid, best->prog_id);
1433
1434 /* Set the chosen PCR stream */
1435 tsmux_program_set_pcr_stream (prog, best->stream);
1436 }
1437
1438 GST_DEBUG_OBJECT (COLLECT_DATA_PAD (best),
1439 "Chose stream for output (PID: 0x%04x)", best->pid);
1440
1441 if (GST_CLOCK_TIME_IS_VALID (GST_BUFFER_PTS (buf))) {
1442 pts = GSTTIME_TO_MPEGTIME (GST_BUFFER_PTS (buf));
1443 GST_DEBUG_OBJECT (mux, "Buffer has PTS %" GST_TIME_FORMAT " pts %"
1444 G_GINT64_FORMAT, GST_TIME_ARGS (GST_BUFFER_PTS (buf)), pts);
1445 }
1446
1447 if (GST_CLOCK_STIME_IS_VALID (best->dts)) {
1448 dts = GSTTIME_TO_MPEGTIME (best->dts);
1449 GST_DEBUG_OBJECT (mux, "Buffer has DTS %" GST_STIME_FORMAT " dts %"
1450 G_GINT64_FORMAT, GST_STIME_ARGS (best->dts), dts);
1451 }
1452
1453 /* should not have a DTS without PTS */
1454 if (!GST_CLOCK_STIME_IS_VALID (pts) && GST_CLOCK_STIME_IS_VALID (dts)) {
1455 GST_DEBUG_OBJECT (mux, "using DTS for unknown PTS");
1456 pts = dts;
1457 }
1458
1459 if (best->stream->is_video_stream) {
1460 delta = GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
1461 header = GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_HEADER);
1462 #if 0
1463 GST_OBJECT_LOCK (mux);
1464 if (mux->element_index && !delta && best->element_index_writer_id != -1) {
1465 gst_index_add_association (mux->element_index,
1466 best->element_index_writer_id,
1467 GST_ASSOCIATION_FLAG_KEY_UNIT, spn_format, mux->spn_count,
1468 pts_format, pts, NULL);
1469 }
1470 GST_OBJECT_UNLOCK (mux);
1471 #endif
1472 }
1473
1474 if (best->stream->is_meta && gst_buffer_get_size (buf) > (G_MAXUINT16 - 3)) {
1475 GST_WARNING_OBJECT (mux, "KLV meta unit too big, splitting not supported");
1476
1477 gst_buffer_unref (buf);
1478 return GST_FLOW_OK;
1479 }
1480
1481 GST_DEBUG_OBJECT (mux, "delta: %d", delta);
1482
1483 stream_data = stream_data_new (buf);
1484 tsmux_stream_add_data (best->stream, stream_data->map_info.data,
1485 stream_data->map_info.size, stream_data, pts, dts, !delta);
1486
1487 /* outgoing ts follows ts of PCR program stream */
1488 if (prog->pcr_stream == best->stream) {
1489 /* prefer DTS if present for PCR as it should be monotone */
1490 mux->last_ts =
1491 GST_CLOCK_TIME_IS_VALID (GST_BUFFER_DTS (buf)) ?
1492 GST_BUFFER_DTS (buf) : GST_BUFFER_PTS (buf);
1493 }
1494
1495 mux->is_delta = delta;
1496 mux->is_header = header;
1497 while (tsmux_stream_bytes_in_buffer (best->stream) > 0) {
1498 if (!tsmux_write_stream_packet (mux->tsmux, best->stream)) {
1499 /* Failed writing data for some reason. Set appropriate error */
1500 GST_DEBUG_OBJECT (mux, "Failed to write data packet");
1501 GST_ELEMENT_ERROR (mux, STREAM, MUX,
1502 ("Failed writing output data to stream %04x", best->stream->id),
1503 (NULL));
1504 goto write_fail;
1505 }
1506 }
1507 /* flush packet cache */
1508 return mpegtsmux_push_packets (mux, FALSE);
1509
1510 /* ERRORS */
1511 write_fail:
1512 {
1513 return mux->last_flow_ret;
1514 }
1515 no_program:
1516 {
1517 if (buf)
1518 gst_buffer_unref (buf);
1519 GST_ELEMENT_ERROR (mux, STREAM, MUX,
1520 ("Stream on pad %" GST_PTR_FORMAT
1521 " is not associated with any program", COLLECT_DATA_PAD (best)),
1522 (NULL));
1523 return GST_FLOW_ERROR;
1524 }
1525 }
1526
1527 static GstPad *
mpegtsmux_request_new_pad(GstElement * element,GstPadTemplate * templ,const gchar * name,const GstCaps * caps)1528 mpegtsmux_request_new_pad (GstElement * element, GstPadTemplate * templ,
1529 const gchar * name, const GstCaps * caps)
1530 {
1531 MpegTsMux *mux = GST_MPEG_TSMUX (element);
1532 gint pid = -1;
1533 gchar *pad_name = NULL;
1534 GstPad *pad = NULL;
1535 MpegTsPadData *pad_data = NULL;
1536
1537 if (name != NULL && sscanf (name, "sink_%d", &pid) == 1) {
1538 if (tsmux_find_stream (mux->tsmux, pid))
1539 goto stream_exists;
1540 } else {
1541 pid = tsmux_get_new_pid (mux->tsmux);
1542 }
1543
1544 pad_name = g_strdup_printf ("sink_%d", pid);
1545 pad = gst_pad_new_from_template (templ, pad_name);
1546 g_free (pad_name);
1547
1548 pad_data = (MpegTsPadData *)
1549 gst_collect_pads_add_pad (mux->collect, pad, sizeof (MpegTsPadData),
1550 (GstCollectDataDestroyNotify) (mpegtsmux_pad_reset), TRUE);
1551 if (pad_data == NULL)
1552 goto pad_failure;
1553
1554 mpegtsmux_pad_reset (pad_data);
1555 pad_data->pid = pid;
1556
1557 if (G_UNLIKELY (!gst_element_add_pad (element, pad)))
1558 goto could_not_add;
1559
1560 return pad;
1561
1562 /* ERRORS */
1563 stream_exists:
1564 {
1565 GST_ELEMENT_ERROR (element, STREAM, MUX, ("Duplicate PID requested"),
1566 (NULL));
1567 return NULL;
1568 }
1569 could_not_add:
1570 {
1571 GST_ELEMENT_ERROR (element, STREAM, FAILED,
1572 ("Internal data stream error."), ("Could not add pad to element"));
1573 gst_collect_pads_remove_pad (mux->collect, pad);
1574 gst_object_unref (pad);
1575 return NULL;
1576 }
1577 pad_failure:
1578 {
1579 GST_ELEMENT_ERROR (element, STREAM, FAILED,
1580 ("Internal data stream error."), ("Could not add pad to collectpads"));
1581 gst_object_unref (pad);
1582 return NULL;
1583 }
1584 }
1585
1586 static void
mpegtsmux_release_pad(GstElement * element,GstPad * pad)1587 mpegtsmux_release_pad (GstElement * element, GstPad * pad)
1588 {
1589 MpegTsMux *mux = GST_MPEG_TSMUX (element);
1590
1591 GST_DEBUG_OBJECT (mux, "Pad %" GST_PTR_FORMAT " being released", pad);
1592
1593 if (mux->collect) {
1594 gst_collect_pads_remove_pad (mux->collect, pad);
1595 }
1596
1597 /* chain up */
1598 gst_element_remove_pad (element, pad);
1599 }
1600
1601 static void
new_packet_common_init(MpegTsMux * mux,GstBuffer * buf,guint8 * data,guint len)1602 new_packet_common_init (MpegTsMux * mux, GstBuffer * buf, guint8 * data,
1603 guint len)
1604 {
1605 /* Packets should be at least 188 bytes, but check anyway */
1606 g_assert (len >= 2 || !data);
1607
1608 if (!mux->streamheader_sent && data) {
1609 guint pid = ((data[1] & 0x1f) << 8) | data[2];
1610 /* if it's a PAT or a PMT */
1611 if (pid == 0x00 || (pid >= TSMUX_START_PMT_PID && pid < TSMUX_START_ES_PID)) {
1612 GstBuffer *hbuf;
1613
1614 if (!buf) {
1615 hbuf = gst_buffer_new_and_alloc (len);
1616 gst_buffer_fill (hbuf, 0, data, len);
1617 } else {
1618 hbuf = gst_buffer_copy (buf);
1619 }
1620 GST_LOG_OBJECT (mux,
1621 "Collecting packet with pid 0x%04x into streamheaders", pid);
1622
1623 g_queue_push_tail (&mux->streamheader, hbuf);
1624 } else if (!g_queue_is_empty (&mux->streamheader)) {
1625 mpegtsmux_set_header_on_caps (mux);
1626 mux->streamheader_sent = TRUE;
1627 }
1628 }
1629
1630 if (buf) {
1631 if (mux->is_header) {
1632 GST_LOG_OBJECT (mux, "marking as header buffer");
1633 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_HEADER);
1634 }
1635 if (mux->is_delta) {
1636 GST_LOG_OBJECT (mux, "marking as delta unit");
1637 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
1638 } else {
1639 GST_DEBUG_OBJECT (mux, "marking as non-delta unit");
1640 mux->is_delta = TRUE;
1641 }
1642 }
1643 }
1644
1645 static GstFlowReturn
mpegtsmux_push_packets(MpegTsMux * mux,gboolean force)1646 mpegtsmux_push_packets (MpegTsMux * mux, gboolean force)
1647 {
1648 GstBufferList *buffer_list;
1649 gint align = mux->alignment;
1650 gint av, packet_size;
1651
1652 if (mux->m2ts_mode) {
1653 packet_size = M2TS_PACKET_LENGTH;
1654 if (align < 0)
1655 align = 32;
1656 } else {
1657 packet_size = NORMAL_TS_PACKET_LENGTH;
1658 if (align < 0)
1659 align = 0;
1660 }
1661
1662 av = gst_adapter_available (mux->out_adapter);
1663 GST_LOG_OBJECT (mux, "align %d, av %d", align, av);
1664
1665 if (av == 0)
1666 return GST_FLOW_OK;
1667
1668 /* no alignment, just push all available data */
1669 if (align == 0) {
1670 buffer_list = gst_adapter_take_buffer_list (mux->out_adapter, av);
1671 return gst_pad_push_list (mux->srcpad, buffer_list);
1672 }
1673
1674 align *= packet_size;
1675
1676 if (!force && align > av)
1677 return GST_FLOW_OK;
1678
1679 buffer_list = gst_buffer_list_new_sized ((av / align) + 1);
1680
1681 GST_LOG_OBJECT (mux, "aligning to %d bytes", align);
1682 while (align <= av) {
1683 GstBuffer *buf;
1684 GstClockTime pts;
1685
1686 pts = gst_adapter_prev_pts (mux->out_adapter, NULL);
1687 buf = gst_adapter_take_buffer (mux->out_adapter, align);
1688
1689 GST_BUFFER_PTS (buf) = pts;
1690
1691 gst_buffer_list_add (buffer_list, buf);
1692 av -= align;
1693 }
1694
1695 if (av > 0 && force) {
1696 GstBuffer *buf;
1697 GstClockTime pts;
1698 guint8 *data;
1699 guint32 header;
1700 gint dummy;
1701 GstMapInfo map;
1702
1703 GST_LOG_OBJECT (mux, "handling %d leftover bytes", av);
1704
1705 pts = gst_adapter_prev_pts (mux->out_adapter, NULL);
1706 buf = gst_buffer_new_and_alloc (align);
1707
1708 GST_BUFFER_PTS (buf) = pts;
1709
1710 gst_buffer_map (buf, &map, GST_MAP_READ);
1711 data = map.data;
1712
1713 gst_adapter_copy (mux->out_adapter, data, 0, av);
1714 gst_adapter_clear (mux->out_adapter);
1715
1716 data += av;
1717 header = GST_READ_UINT32_BE (data - packet_size);
1718
1719 dummy = (map.size - av) / packet_size;
1720 GST_LOG_OBJECT (mux, "adding %d null packets", dummy);
1721
1722 for (; dummy > 0; dummy--) {
1723 gint offset;
1724
1725 if (packet_size > NORMAL_TS_PACKET_LENGTH) {
1726 GST_WRITE_UINT32_BE (data, header);
1727 /* simply increase header a bit and never mind too much */
1728 header++;
1729 offset = 4;
1730 } else {
1731 offset = 0;
1732 }
1733 GST_WRITE_UINT8 (data + offset, TSMUX_SYNC_BYTE);
1734 /* null packet PID */
1735 GST_WRITE_UINT16_BE (data + offset + 1, 0x1FFF);
1736 /* no adaptation field exists | continuity counter undefined */
1737 GST_WRITE_UINT8 (data + offset + 3, 0x10);
1738 /* payload */
1739 memset (data + offset + 4, 0, NORMAL_TS_PACKET_LENGTH - 4);
1740 data += packet_size;
1741 }
1742
1743 gst_buffer_unmap (buf, &map);
1744 gst_buffer_list_add (buffer_list, buf);
1745 }
1746
1747 return gst_pad_push_list (mux->srcpad, buffer_list);
1748 }
1749
1750 static GstFlowReturn
mpegtsmux_collect_packet(MpegTsMux * mux,GstBuffer * buf)1751 mpegtsmux_collect_packet (MpegTsMux * mux, GstBuffer * buf)
1752 {
1753 GST_LOG_OBJECT (mux, "collecting packet size %" G_GSIZE_FORMAT,
1754 gst_buffer_get_size (buf));
1755 gst_adapter_push (mux->out_adapter, buf);
1756
1757 return GST_FLOW_OK;
1758 }
1759
1760 static gboolean
new_packet_m2ts(MpegTsMux * mux,GstBuffer * buf,gint64 new_pcr)1761 new_packet_m2ts (MpegTsMux * mux, GstBuffer * buf, gint64 new_pcr)
1762 {
1763 GstBuffer *out_buf;
1764 int chunk_bytes;
1765 GstMapInfo map;
1766
1767 GST_LOG_OBJECT (mux, "Have buffer %p with new_pcr=%" G_GINT64_FORMAT,
1768 buf, new_pcr);
1769
1770 chunk_bytes = gst_adapter_available (mux->adapter);
1771
1772 if (G_LIKELY (buf)) {
1773 if (new_pcr < 0) {
1774 /* If there is no pcr in current ts packet then just add the packet
1775 to the adapter for later output when we see a PCR */
1776 GST_LOG_OBJECT (mux, "Accumulating non-PCR packet");
1777 gst_adapter_push (mux->adapter, buf);
1778 goto exit;
1779 }
1780
1781 /* no first interpolation point yet, then this is the one,
1782 * otherwise it is the second interpolation point */
1783 if (mux->previous_pcr < 0 && chunk_bytes) {
1784 mux->previous_pcr = new_pcr;
1785 mux->previous_offset = chunk_bytes;
1786 GST_LOG_OBJECT (mux, "Accumulating non-PCR packet");
1787 gst_adapter_push (mux->adapter, buf);
1788 goto exit;
1789 }
1790 } else {
1791 g_assert (new_pcr == -1);
1792 }
1793
1794 /* interpolate if needed, and 2 points available */
1795 if (chunk_bytes && (new_pcr != mux->previous_pcr)) {
1796 gint64 offset = 0;
1797
1798 GST_LOG_OBJECT (mux, "Processing pending packets; "
1799 "previous pcr %" G_GINT64_FORMAT ", previous offset %d, "
1800 "current pcr %" G_GINT64_FORMAT ", current offset %d",
1801 mux->previous_pcr, (gint) mux->previous_offset,
1802 new_pcr, (gint) chunk_bytes);
1803
1804 g_assert (chunk_bytes > mux->previous_offset);
1805 /* if draining, use previous rate */
1806 if (G_LIKELY (new_pcr > 0)) {
1807 mux->pcr_rate_num = new_pcr - mux->previous_pcr;
1808 mux->pcr_rate_den = chunk_bytes - mux->previous_offset;
1809 }
1810
1811 while (offset < chunk_bytes) {
1812 guint64 cur_pcr, ts;
1813
1814 /* Loop, pulling packets of the adapter, updating their 4 byte
1815 * timestamp header and pushing */
1816
1817 /* interpolate PCR */
1818 if (G_LIKELY (offset >= mux->previous_offset))
1819 cur_pcr = mux->previous_pcr +
1820 gst_util_uint64_scale (offset - mux->previous_offset,
1821 mux->pcr_rate_num, mux->pcr_rate_den);
1822 else
1823 cur_pcr = mux->previous_pcr -
1824 gst_util_uint64_scale (mux->previous_offset - offset,
1825 mux->pcr_rate_num, mux->pcr_rate_den);
1826
1827 /* FIXME: what about DTS here? */
1828 ts = gst_adapter_prev_pts (mux->adapter, NULL);
1829 out_buf = gst_adapter_take_buffer (mux->adapter, M2TS_PACKET_LENGTH);
1830 g_assert (out_buf);
1831 offset += M2TS_PACKET_LENGTH;
1832
1833 GST_BUFFER_PTS (out_buf) = ts;
1834
1835 gst_buffer_map (out_buf, &map, GST_MAP_WRITE);
1836
1837 /* The header is the bottom 30 bits of the PCR, apparently not
1838 * encoded into base + ext as in the packets themselves */
1839 GST_WRITE_UINT32_BE (map.data, cur_pcr & 0x3FFFFFFF);
1840 gst_buffer_unmap (out_buf, &map);
1841
1842 GST_LOG_OBJECT (mux, "Outputting a packet of length %d PCR %"
1843 G_GUINT64_FORMAT, M2TS_PACKET_LENGTH, cur_pcr);
1844 mpegtsmux_collect_packet (mux, out_buf);
1845 }
1846 }
1847
1848 if (G_UNLIKELY (!buf))
1849 goto exit;
1850
1851 gst_buffer_map (buf, &map, GST_MAP_WRITE);
1852
1853 /* Finally, output the passed in packet */
1854 /* Only write the bottom 30 bits of the PCR */
1855 GST_WRITE_UINT32_BE (map.data, new_pcr & 0x3FFFFFFF);
1856
1857 gst_buffer_unmap (buf, &map);
1858
1859 GST_LOG_OBJECT (mux, "Outputting a packet of length %d PCR %"
1860 G_GUINT64_FORMAT, M2TS_PACKET_LENGTH, new_pcr);
1861 mpegtsmux_collect_packet (mux, buf);
1862
1863 if (new_pcr != mux->previous_pcr) {
1864 mux->previous_pcr = new_pcr;
1865 mux->previous_offset = -M2TS_PACKET_LENGTH;
1866 }
1867
1868 exit:
1869 return TRUE;
1870 }
1871
1872 /* Called when the TsMux has prepared a packet for output. Return FALSE
1873 * on error */
1874 static gboolean
new_packet_cb(GstBuffer * buf,void * user_data,gint64 new_pcr)1875 new_packet_cb (GstBuffer * buf, void *user_data, gint64 new_pcr)
1876 {
1877 MpegTsMux *mux = (MpegTsMux *) user_data;
1878 gint offset = 0;
1879 GstMapInfo map;
1880
1881 #if 0
1882 GST_LOG_OBJECT (mux, "handling packet %d", mux->spn_count);
1883 mux->spn_count++;
1884 #endif
1885
1886 if (mux->m2ts_mode) {
1887 offset = 4;
1888 gst_buffer_set_size (buf, NORMAL_TS_PACKET_LENGTH + offset);
1889 }
1890
1891 gst_buffer_map (buf, &map, GST_MAP_READWRITE);
1892
1893 if (offset) {
1894 /* there should be a better way to do this */
1895 memmove (map.data + offset, map.data, map.size - offset);
1896 }
1897
1898 GST_BUFFER_PTS (buf) = mux->last_ts;
1899 /* do common init (flags and streamheaders) */
1900 new_packet_common_init (mux, buf, map.data + offset, map.size);
1901
1902 gst_buffer_unmap (buf, &map);
1903
1904 /* all is meant for downstream, including any prefix */
1905 if (offset)
1906 return new_packet_m2ts (mux, buf, new_pcr);
1907 else
1908 mpegtsmux_collect_packet (mux, buf);
1909
1910 return TRUE;
1911 }
1912
1913 /* called when TsMux needs new packet to write into */
1914 static void
alloc_packet_cb(GstBuffer ** _buf,void * user_data)1915 alloc_packet_cb (GstBuffer ** _buf, void *user_data)
1916 {
1917 MpegTsMux *mux = (MpegTsMux *) user_data;
1918 GstBuffer *buf;
1919 gint offset = 0;
1920
1921 if (mux->m2ts_mode == TRUE)
1922 offset = 4;
1923
1924 buf = gst_buffer_new_and_alloc (NORMAL_TS_PACKET_LENGTH + offset);
1925 gst_buffer_set_size (buf, NORMAL_TS_PACKET_LENGTH);
1926
1927 *_buf = buf;
1928 }
1929
1930 static void
mpegtsmux_set_header_on_caps(MpegTsMux * mux)1931 mpegtsmux_set_header_on_caps (MpegTsMux * mux)
1932 {
1933 GstBuffer *buf;
1934 GstStructure *structure;
1935 GValue array = { 0 };
1936 GValue value = { 0 };
1937 GstCaps *caps;
1938
1939 caps = gst_caps_make_writable (gst_pad_get_current_caps (mux->srcpad));
1940 structure = gst_caps_get_structure (caps, 0);
1941
1942 g_value_init (&array, GST_TYPE_ARRAY);
1943
1944 GST_LOG_OBJECT (mux, "setting %u packets into streamheader",
1945 g_queue_get_length (&mux->streamheader));
1946
1947 while ((buf = g_queue_pop_head (&mux->streamheader))) {
1948 g_value_init (&value, GST_TYPE_BUFFER);
1949 gst_value_take_buffer (&value, buf);
1950 gst_value_array_append_value (&array, &value);
1951 g_value_unset (&value);
1952 }
1953
1954 gst_structure_set_value (structure, "streamheader", &array);
1955 gst_pad_set_caps (mux->srcpad, caps);
1956 g_value_unset (&array);
1957 gst_caps_unref (caps);
1958 }
1959
1960 static void
mpegtsmux_prepare_srcpad(MpegTsMux * mux)1961 mpegtsmux_prepare_srcpad (MpegTsMux * mux)
1962 {
1963 GstSegment seg;
1964 /* we are not going to seek */
1965 GstEvent *new_seg;
1966 gchar s_id[32];
1967 GstCaps *caps = gst_caps_new_simple ("video/mpegts",
1968 "systemstream", G_TYPE_BOOLEAN, TRUE,
1969 "packetsize", G_TYPE_INT,
1970 (mux->m2ts_mode ? M2TS_PACKET_LENGTH : NORMAL_TS_PACKET_LENGTH),
1971 NULL);
1972
1973 /* stream-start (FIXME: create id based on input ids) */
1974 g_snprintf (s_id, sizeof (s_id), "mpegtsmux-%08x", g_random_int ());
1975 gst_pad_push_event (mux->srcpad, gst_event_new_stream_start (s_id));
1976
1977 gst_segment_init (&seg, GST_FORMAT_TIME);
1978 new_seg = gst_event_new_segment (&seg);
1979
1980 /* Set caps on src pad from our template and push new segment */
1981 gst_pad_set_caps (mux->srcpad, caps);
1982 gst_caps_unref (caps);
1983
1984 if (!gst_pad_push_event (mux->srcpad, new_seg)) {
1985 GST_WARNING_OBJECT (mux, "New segment event was not handled downstream");
1986 }
1987 }
1988
1989 static GstStateChangeReturn
mpegtsmux_change_state(GstElement * element,GstStateChange transition)1990 mpegtsmux_change_state (GstElement * element, GstStateChange transition)
1991 {
1992 MpegTsMux *mux = GST_MPEG_TSMUX (element);
1993 GstStateChangeReturn ret;
1994
1995 switch (transition) {
1996 case GST_STATE_CHANGE_NULL_TO_READY:
1997 break;
1998 case GST_STATE_CHANGE_READY_TO_PAUSED:
1999 gst_collect_pads_start (mux->collect);
2000 break;
2001 case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
2002 break;
2003 case GST_STATE_CHANGE_PAUSED_TO_READY:
2004 gst_collect_pads_stop (mux->collect);
2005 break;
2006 case GST_STATE_CHANGE_READY_TO_NULL:
2007 break;
2008 default:
2009 break;
2010 }
2011
2012 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
2013
2014 switch (transition) {
2015 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
2016 break;
2017 case GST_STATE_CHANGE_PAUSED_TO_READY:
2018 mpegtsmux_reset (mux, TRUE);
2019 break;
2020 case GST_STATE_CHANGE_READY_TO_NULL:
2021 break;
2022 default:
2023 break;
2024 }
2025
2026 return ret;
2027 }
2028
2029 static gboolean
mpegtsmux_send_event(GstElement * element,GstEvent * event)2030 mpegtsmux_send_event (GstElement * element, GstEvent * event)
2031 {
2032 GstMpegtsSection *section;
2033 MpegTsMux *mux = GST_MPEG_TSMUX (element);
2034
2035 section = gst_event_parse_mpegts_section (event);
2036 gst_event_unref (event);
2037
2038 if (section) {
2039 GST_DEBUG ("Received event with mpegts section");
2040
2041 /* TODO: Check that the section type is supported */
2042 tsmux_add_mpegts_si_section (mux->tsmux, section);
2043
2044 return TRUE;
2045 }
2046
2047 return FALSE;
2048 }
2049
2050 static gboolean
plugin_init(GstPlugin * plugin)2051 plugin_init (GstPlugin * plugin)
2052 {
2053 gst_mpegts_initialize ();
2054 if (!gst_element_register (plugin, "mpegtsmux", GST_RANK_PRIMARY,
2055 mpegtsmux_get_type ()))
2056 return FALSE;
2057
2058 GST_DEBUG_CATEGORY_INIT (mpegtsmux_debug, "mpegtsmux", 0,
2059 "MPEG Transport Stream muxer");
2060
2061 return TRUE;
2062 }
2063
2064 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, GST_VERSION_MINOR,
2065 mpegtsmux, "MPEG-TS muxer",
2066 plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN);
2067