1 /*
2 * Copyright 2006 BBC and Fluendo S.A.
3 *
4 * This library is licensed under 3 different licenses and you
5 * can choose to use it under the terms of any one of them. The
6 * three licenses are the MPL 1.1, the LGPL, and the MIT license.
7 *
8 * MPL:
9 *
10 * The contents of this file are subject to the Mozilla Public License
11 * Version 1.1 (the "License"); you may not use this file except in
12 * compliance with the License. You may obtain a copy of the License at
13 * http://www.mozilla.org/MPL/.
14 *
15 * Software distributed under the License is distributed on an "AS IS"
16 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
17 * License for the specific language governing rights and limitations
18 * under the License.
19 *
20 * LGPL:
21 *
22 * This library is free software; you can redistribute it and/or
23 * modify it under the terms of the GNU Library General Public
24 * License as published by the Free Software Foundation; either
25 * version 2 of the License, or (at your option) any later version.
26 *
27 * This library is distributed in the hope that it will be useful,
28 * but WITHOUT ANY WARRANTY; without even the implied warranty of
29 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
30 * Library General Public License for more details.
31 *
32 * You should have received a copy of the GNU Library General Public
33 * License along with this library; if not, write to the
34 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
35 * Boston, MA 02110-1301, USA.
36 *
37 * MIT:
38 *
39 * Unless otherwise indicated, Source Code is licensed under MIT license.
40 * See further explanation attached in License Statement (distributed in the file
41 * LICENSE).
42 *
43 * Permission is hereby granted, free of charge, to any person obtaining a copy of
44 * this software and associated documentation files (the "Software"), to deal in
45 * the Software without restriction, including without limitation the rights to
46 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
47 * of the Software, and to permit persons to whom the Software is furnished to do
48 * so, subject to the following conditions:
49 *
50 * The above copyright notice and this permission notice shall be included in all
51 * copies or substantial portions of the Software.
52 *
53 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
54 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
55 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
56 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
57 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
58 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
59 * SOFTWARE.
60 *
61 * SPDX-License-Identifier: MPL-1.1 OR MIT OR LGPL-2.0-or-later
62 */
63
64 #ifdef HAVE_CONFIG_H
65 #include "config.h"
66 #endif
67
68 #include <string.h>
69
70 #include <gst/mpegts/mpegts.h>
71 #include <gst/base/gstbytewriter.h>
72
73 #include "tsmuxcommon.h"
74 #include "tsmuxstream.h"
75
76 #define GST_CAT_DEFAULT gst_base_ts_mux_debug
77
78 static guint8 tsmux_stream_pes_header_length (TsMuxStream * stream);
79 static void tsmux_stream_write_pes_header (TsMuxStream * stream, guint8 * data);
80 static void tsmux_stream_find_pts_dts_within (TsMuxStream * stream, guint bound,
81 gint64 * pts, gint64 * dts);
82
83 struct TsMuxStreamBuffer
84 {
85 guint8 *data;
86 guint32 size;
87
88 /* PTS & DTS associated with the contents of this buffer */
89 gint64 pts;
90 gint64 dts;
91
92 /* data represents random access point */
93 gboolean random_access;
94
95 /* user_data for release function */
96 void *user_data;
97 };
98
99 /**
100 * tsmux_stream_new:
101 * @pid: a PID
102 * @stream_type: the stream type
103 *
104 * Create a new stream with PID of @pid and @stream_type.
105 *
106 * Returns: a new #TsMuxStream.
107 */
108 TsMuxStream *
tsmux_stream_new(guint16 pid,guint stream_type)109 tsmux_stream_new (guint16 pid, guint stream_type)
110 {
111 TsMuxStream *stream = g_slice_new0 (TsMuxStream);
112
113 stream->state = TSMUX_STREAM_STATE_HEADER;
114 stream->pi.pid = pid;
115 stream->stream_type = stream_type;
116
117 stream->pes_payload_size = 0;
118 stream->cur_pes_payload_size = 0;
119 stream->pes_bytes_written = 0;
120 stream->pmt_index = -1;
121
122 switch (stream_type) {
123 case TSMUX_ST_VIDEO_MPEG1:
124 case TSMUX_ST_VIDEO_MPEG2:
125 case TSMUX_ST_VIDEO_MPEG4:
126 case TSMUX_ST_VIDEO_H264:
127 case TSMUX_ST_VIDEO_HEVC:
128 /* FIXME: Assign sequential IDs? */
129 stream->id = 0xE0;
130 stream->pi.flags |= TSMUX_PACKET_FLAG_PES_FULL_HEADER;
131 stream->is_video_stream = TRUE;
132 break;
133 case TSMUX_ST_VIDEO_JP2K:
134 stream->id = 0xBD;
135 stream->pi.flags |= TSMUX_PACKET_FLAG_PES_FULL_HEADER;
136 stream->is_video_stream = TRUE;
137 break;
138 case TSMUX_ST_AUDIO_AAC:
139 case TSMUX_ST_AUDIO_MPEG1:
140 case TSMUX_ST_AUDIO_MPEG2:
141 /* FIXME: Assign sequential IDs? */
142 stream->is_audio = TRUE;
143 stream->id = 0xC0;
144 stream->pi.flags |= TSMUX_PACKET_FLAG_PES_FULL_HEADER;
145 break;
146 case TSMUX_ST_VIDEO_DIRAC:
147 case TSMUX_ST_PS_AUDIO_LPCM:
148 case TSMUX_ST_PS_AUDIO_AC3:
149 case TSMUX_ST_PS_AUDIO_DTS:
150 stream->id = 0xFD;
151 /* FIXME: assign sequential extended IDs? */
152 switch (stream_type) {
153 case TSMUX_ST_VIDEO_DIRAC:
154 stream->id_extended = 0x60;
155 stream->is_video_stream = TRUE;
156 break;
157 case TSMUX_ST_PS_AUDIO_LPCM:
158 stream->is_audio = TRUE;
159 stream->id_extended = 0x80;
160 break;
161 case TSMUX_ST_PS_AUDIO_AC3:
162 stream->is_audio = TRUE;
163 stream->id_extended = 0x71;
164 break;
165 case TSMUX_ST_PS_AUDIO_DTS:
166 stream->is_audio = TRUE;
167 stream->id_extended = 0x82;
168 break;
169 default:
170 break;
171 }
172 stream->pi.flags |=
173 TSMUX_PACKET_FLAG_PES_FULL_HEADER |
174 TSMUX_PACKET_FLAG_PES_EXT_STREAMID;
175 break;
176 case TSMUX_ST_PS_TELETEXT:
177 /* needs fixes PES header length */
178 stream->pi.pes_header_length = 36;
179 /* fall through */
180 case TSMUX_ST_PS_DVB_SUBPICTURE:
181 /* private stream 1 */
182 stream->id = 0xBD;
183 stream->is_dvb_sub = TRUE;
184 stream->stream_type = TSMUX_ST_PRIVATE_DATA;
185 stream->pi.flags |=
186 TSMUX_PACKET_FLAG_PES_FULL_HEADER |
187 TSMUX_PACKET_FLAG_PES_DATA_ALIGNMENT;
188
189 break;
190 case TSMUX_ST_PS_KLV:
191 /* FIXME: assign sequential extended IDs? */
192 stream->id = 0xBD;
193 stream->stream_type = TSMUX_ST_PRIVATE_DATA;
194 stream->is_meta = TRUE;
195 stream->pi.flags |=
196 TSMUX_PACKET_FLAG_PES_FULL_HEADER |
197 TSMUX_PACKET_FLAG_PES_DATA_ALIGNMENT;
198 break;
199 case TSMUX_ST_PS_OPUS:
200 /* FIXME: assign sequential extended IDs? */
201 stream->id = 0xBD;
202 stream->is_audio = TRUE;
203 stream->stream_type = TSMUX_ST_PRIVATE_DATA;
204 stream->is_opus = TRUE;
205 stream->pi.flags |= TSMUX_PACKET_FLAG_PES_FULL_HEADER;
206 break;
207 default:
208 /* Might be a custom stream type implemented by a subclass */
209 break;
210 }
211
212 stream->first_ts = GST_CLOCK_STIME_NONE;
213
214 stream->last_pts = GST_CLOCK_STIME_NONE;
215 stream->last_dts = GST_CLOCK_STIME_NONE;
216
217 stream->pcr_ref = 0;
218 stream->next_pcr = -1;
219
220 stream->get_es_descrs =
221 (TsMuxStreamGetESDescriptorsFunc) tsmux_stream_default_get_es_descrs;
222 stream->get_es_descrs_data = NULL;
223
224 return stream;
225 }
226
227 /**
228 * tsmux_stream_get_pid:
229 * @stream: a #TsMuxStream
230 *
231 * Get the PID of @stream.
232 *
233 * Returns: The PID of @stream. 0xffff on error.
234 */
235 guint16
tsmux_stream_get_pid(TsMuxStream * stream)236 tsmux_stream_get_pid (TsMuxStream * stream)
237 {
238 g_return_val_if_fail (stream != NULL, G_MAXUINT16);
239
240 return stream->pi.pid;
241 }
242
243 /**
244 * tsmux_stream_free:
245 * @stream: a #TsMuxStream
246 *
247 * Free the resources of @stream.
248 */
249 void
tsmux_stream_free(TsMuxStream * stream)250 tsmux_stream_free (TsMuxStream * stream)
251 {
252 GList *cur;
253
254 g_return_if_fail (stream != NULL);
255
256 /* free buffers */
257 for (cur = stream->buffers; cur; cur = cur->next) {
258 TsMuxStreamBuffer *tmbuf = (TsMuxStreamBuffer *) cur->data;
259
260 if (stream->buffer_release)
261 stream->buffer_release (tmbuf->data, tmbuf->user_data);
262 g_slice_free (TsMuxStreamBuffer, tmbuf);
263 }
264 g_list_free (stream->buffers);
265
266 g_slice_free (TsMuxStream, stream);
267 }
268
269 /**
270 * tsmux_stream_set_buffer_release_func:
271 * @stream: a #TsMuxStream
272 * @func: the new #TsMuxStreamBufferReleaseFunc
273 *
274 * Set the function that will be called when a a piece of data fed to @stream
275 * with tsmux_stream_add_data() can be freed. @func will be called with user
276 * data as provided with the call to tsmux_stream_add_data().
277 */
278 void
tsmux_stream_set_buffer_release_func(TsMuxStream * stream,TsMuxStreamBufferReleaseFunc func)279 tsmux_stream_set_buffer_release_func (TsMuxStream * stream,
280 TsMuxStreamBufferReleaseFunc func)
281 {
282 g_return_if_fail (stream != NULL);
283
284 stream->buffer_release = func;
285 }
286
287 /**
288 * tsmux_stream_set_get_es_descriptors_func:
289 * @stream: a #TsMuxStream
290 * @func: a user callback function
291 * @user_data: user data passed to @func
292 *
293 * Set the callback function and user data to be called when @stream has
294 * to create Elementary Stream Descriptors.
295 */
296 void
tsmux_stream_set_get_es_descriptors_func(TsMuxStream * stream,TsMuxStreamGetESDescriptorsFunc func,void * user_data)297 tsmux_stream_set_get_es_descriptors_func (TsMuxStream * stream,
298 TsMuxStreamGetESDescriptorsFunc func, void *user_data)
299 {
300 g_return_if_fail (stream != NULL);
301
302 stream->get_es_descrs = func;
303 stream->get_es_descrs_data = user_data;
304 }
305
306 /* Advance the current packet stream position by len bytes.
307 * Mustn't consume more than available in the current packet */
308 static void
tsmux_stream_consume(TsMuxStream * stream,guint len)309 tsmux_stream_consume (TsMuxStream * stream, guint len)
310 {
311 g_assert (stream->cur_buffer != NULL);
312 g_assert (len <= stream->cur_buffer->size - stream->cur_buffer_consumed);
313
314 stream->cur_buffer_consumed += len;
315 stream->bytes_avail -= len;
316
317 if (stream->cur_buffer_consumed == 0 && stream->cur_buffer->size != 0)
318 return;
319
320 if (GST_CLOCK_STIME_IS_VALID (stream->cur_buffer->pts))
321 stream->last_pts = stream->cur_buffer->pts;
322 if (GST_CLOCK_STIME_IS_VALID (stream->cur_buffer->dts))
323 stream->last_dts = stream->cur_buffer->dts;
324
325 if (stream->cur_buffer_consumed == stream->cur_buffer->size) {
326 /* Current packet is completed, move along */
327 stream->buffers = g_list_delete_link (stream->buffers, stream->buffers);
328
329 if (stream->buffer_release) {
330 stream->buffer_release (stream->cur_buffer->data,
331 stream->cur_buffer->user_data);
332 }
333
334 g_slice_free (TsMuxStreamBuffer, stream->cur_buffer);
335 stream->cur_buffer = NULL;
336 /* FIXME: As a hack, for unbounded streams, start a new PES packet for each
337 * incoming packet we receive. This assumes that incoming data is
338 * packetised sensibly - ie, every video frame */
339 if (stream->cur_pes_payload_size == 0) {
340 stream->state = TSMUX_STREAM_STATE_HEADER;
341 stream->pes_bytes_written = 0;
342 }
343 }
344 }
345
346 /**
347 * tsmux_stream_at_pes_start:
348 * @stream: a #TsMuxStream
349 *
350 * Check if @stream is at the start of a PES packet.
351 *
352 * Returns: TRUE if @stream is at a PES header packet.
353 */
354 gboolean
tsmux_stream_at_pes_start(TsMuxStream * stream)355 tsmux_stream_at_pes_start (TsMuxStream * stream)
356 {
357 g_return_val_if_fail (stream != NULL, FALSE);
358
359 return stream->state == TSMUX_STREAM_STATE_HEADER;
360 }
361
362 /**
363 * tsmux_stream_bytes_avail:
364 * @stream: a #TsMuxStream
365 *
366 * Calculate how much bytes are available.
367 *
368 * Returns: The number of bytes available.
369 */
370 static inline gint
_tsmux_stream_bytes_avail(TsMuxStream * stream)371 _tsmux_stream_bytes_avail (TsMuxStream * stream)
372 {
373 gint bytes_avail;
374
375 g_return_val_if_fail (stream != NULL, 0);
376
377 if (stream->cur_pes_payload_size != 0)
378 bytes_avail = stream->cur_pes_payload_size - stream->pes_bytes_written;
379 else
380 bytes_avail = stream->bytes_avail;
381
382 bytes_avail = MIN (bytes_avail, stream->bytes_avail);
383
384 /* Calculate the number of bytes available in the current PES */
385 if (stream->state == TSMUX_STREAM_STATE_HEADER)
386 bytes_avail += tsmux_stream_pes_header_length (stream);
387
388 return bytes_avail;
389 }
390
391 gint
tsmux_stream_bytes_avail(TsMuxStream * stream)392 tsmux_stream_bytes_avail (TsMuxStream * stream)
393 {
394 g_return_val_if_fail (stream != NULL, 0);
395
396 return _tsmux_stream_bytes_avail (stream);
397 }
398
399 /**
400 * tsmux_stream_bytes_in_buffer:
401 * @stream: a #TsMuxStream
402 *
403 * Calculate how much bytes are in the buffer.
404 *
405 * Returns: The number of bytes in the buffer.
406 */
407 gint
tsmux_stream_bytes_in_buffer(TsMuxStream * stream)408 tsmux_stream_bytes_in_buffer (TsMuxStream * stream)
409 {
410 g_return_val_if_fail (stream != NULL, 0);
411
412 return stream->bytes_avail;
413 }
414
415 /**
416 * tsmux_stream_initialize_pes_packet:
417 * @stream: a #TsMuxStream
418 *
419 * Initializes the PES packet.
420 *
421 * Returns: TRUE if we the packet was initialized.
422 */
423 gboolean
tsmux_stream_initialize_pes_packet(TsMuxStream * stream)424 tsmux_stream_initialize_pes_packet (TsMuxStream * stream)
425 {
426 if (stream->state != TSMUX_STREAM_STATE_HEADER)
427 return TRUE;
428
429 if (stream->pes_payload_size != 0) {
430 /* Use prescribed fixed PES payload size */
431 stream->cur_pes_payload_size = stream->pes_payload_size;
432 tsmux_stream_find_pts_dts_within (stream, stream->cur_pes_payload_size,
433 &stream->pts, &stream->dts);
434 } else {
435 /* Output a PES packet of all currently available bytes otherwise */
436 stream->cur_pes_payload_size = stream->bytes_avail;
437 tsmux_stream_find_pts_dts_within (stream, stream->cur_pes_payload_size,
438 &stream->pts, &stream->dts);
439 }
440
441 stream->pi.flags &= ~(TSMUX_PACKET_FLAG_PES_WRITE_PTS_DTS |
442 TSMUX_PACKET_FLAG_PES_WRITE_PTS);
443
444 if (GST_CLOCK_STIME_IS_VALID (stream->pts)
445 && GST_CLOCK_STIME_IS_VALID (stream->dts)
446 && stream->pts != stream->dts)
447 stream->pi.flags |= TSMUX_PACKET_FLAG_PES_WRITE_PTS_DTS;
448 else {
449 if (GST_CLOCK_STIME_IS_VALID (stream->pts))
450 stream->pi.flags |= TSMUX_PACKET_FLAG_PES_WRITE_PTS;
451 }
452
453 if (stream->buffers) {
454 TsMuxStreamBuffer *buf = (TsMuxStreamBuffer *) (stream->buffers->data);
455 if (buf->random_access) {
456 stream->pi.flags |= TSMUX_PACKET_FLAG_RANDOM_ACCESS;
457 stream->pi.flags |= TSMUX_PACKET_FLAG_ADAPTATION;
458 }
459 }
460
461 if (stream->is_video_stream) {
462 guint8 hdr_len;
463
464 hdr_len = tsmux_stream_pes_header_length (stream);
465
466 /* Unbounded for video streams if pes packet length is over 16 bit */
467 if ((stream->cur_pes_payload_size + hdr_len - 6) > G_MAXUINT16)
468 stream->cur_pes_payload_size = 0;
469 }
470
471 return TRUE;
472 }
473
474 /**
475 * tsmux_stream_get_data:
476 * @stream: a #TsMuxStream
477 * @buf: a buffer to hold the result
478 * @len: the length of @buf
479 *
480 * Copy up to @len available data in @stream into the buffer @buf.
481 *
482 * Returns: TRUE if @len bytes could be retrieved.
483 */
484 gboolean
tsmux_stream_get_data(TsMuxStream * stream,guint8 * buf,guint len)485 tsmux_stream_get_data (TsMuxStream * stream, guint8 * buf, guint len)
486 {
487 g_return_val_if_fail (stream != NULL, FALSE);
488 g_return_val_if_fail (buf != NULL, FALSE);
489
490 if (stream->state == TSMUX_STREAM_STATE_HEADER) {
491 guint8 pes_hdr_length;
492
493 pes_hdr_length = tsmux_stream_pes_header_length (stream);
494
495 /* Submitted buffer must be at least as large as the PES header */
496 if (len < pes_hdr_length)
497 return FALSE;
498
499 TS_DEBUG ("Writing PES header of length %u and payload %d",
500 pes_hdr_length, stream->cur_pes_payload_size);
501 tsmux_stream_write_pes_header (stream, buf);
502
503 len -= pes_hdr_length;
504 buf += pes_hdr_length;
505
506 stream->state = TSMUX_STREAM_STATE_PACKET;
507 }
508
509 if (len > (guint) _tsmux_stream_bytes_avail (stream))
510 return FALSE;
511
512 stream->pes_bytes_written += len;
513
514 if (stream->cur_pes_payload_size != 0 &&
515 stream->pes_bytes_written == stream->cur_pes_payload_size) {
516 TS_DEBUG ("Finished PES packet");
517 stream->state = TSMUX_STREAM_STATE_HEADER;
518 stream->pes_bytes_written = 0;
519 }
520
521 while (len > 0) {
522 guint32 avail;
523 guint8 *cur;
524
525 if (stream->cur_buffer == NULL) {
526 /* Start next packet */
527 if (stream->buffers == NULL)
528 return FALSE;
529 stream->cur_buffer = (TsMuxStreamBuffer *) (stream->buffers->data);
530 stream->cur_buffer_consumed = 0;
531 }
532
533 /* Take as much as we can from the current buffer */
534 avail = stream->cur_buffer->size - stream->cur_buffer_consumed;
535 cur = stream->cur_buffer->data + stream->cur_buffer_consumed;
536 if (avail < len) {
537 memcpy (buf, cur, avail);
538 tsmux_stream_consume (stream, avail);
539
540 buf += avail;
541 len -= avail;
542 } else {
543 memcpy (buf, cur, len);
544 tsmux_stream_consume (stream, len);
545
546 len = 0;
547 }
548 }
549
550 return TRUE;
551 }
552
553 static guint8
tsmux_stream_pes_header_length(TsMuxStream * stream)554 tsmux_stream_pes_header_length (TsMuxStream * stream)
555 {
556 guint8 packet_len;
557
558 /* Calculate the length of the header for this stream */
559
560 /* start_code prefix + stream_id + pes_packet_length = 6 bytes */
561 packet_len = 6;
562
563 if (stream->pi.flags & TSMUX_PACKET_FLAG_PES_FULL_HEADER) {
564 /* For a PES 'full header' we have at least 3 more bytes,
565 * and then more based on flags */
566 packet_len += 3;
567 if (stream->pi.flags & TSMUX_PACKET_FLAG_PES_WRITE_PTS_DTS) {
568 packet_len += 10;
569 } else if (stream->pi.flags & TSMUX_PACKET_FLAG_PES_WRITE_PTS) {
570 packet_len += 5;
571 }
572 if (stream->pi.flags & TSMUX_PACKET_FLAG_PES_EXT_STREAMID) {
573 /* Need basic extension flags (1 byte), plus 2 more bytes for the
574 * length + extended stream id */
575 packet_len += 3;
576 }
577 if (stream->pi.pes_header_length) {
578 /* check for consistency, then we can add stuffing */
579 g_assert (packet_len <= stream->pi.pes_header_length + 6 + 3);
580 packet_len = stream->pi.pes_header_length + 6 + 3;
581 }
582 }
583
584 return packet_len;
585 }
586
587 /* Find a PTS/DTS to write into the pes header within the next bound bytes
588 * of the data */
589 static void
tsmux_stream_find_pts_dts_within(TsMuxStream * stream,guint bound,gint64 * pts,gint64 * dts)590 tsmux_stream_find_pts_dts_within (TsMuxStream * stream, guint bound,
591 gint64 * pts, gint64 * dts)
592 {
593 GList *cur;
594
595 *pts = GST_CLOCK_STIME_NONE;
596 *dts = GST_CLOCK_STIME_NONE;
597
598 for (cur = stream->buffers; cur; cur = cur->next) {
599 TsMuxStreamBuffer *curbuf = cur->data;
600
601 /* FIXME: This isn't quite correct - if the 'bound' is within this
602 * buffer, we don't know if the timestamp is before or after the split
603 * so we shouldn't return it */
604 if (bound <= curbuf->size) {
605 *pts = curbuf->pts;
606 *dts = curbuf->dts;
607 return;
608 }
609
610 /* Have we found a buffer with pts/dts set? */
611 if (GST_CLOCK_STIME_IS_VALID (curbuf->pts)
612 || GST_CLOCK_STIME_IS_VALID (curbuf->dts)) {
613 *pts = curbuf->pts;
614 *dts = curbuf->dts;
615 return;
616 }
617
618 bound -= curbuf->size;
619 }
620 }
621
622 static void
tsmux_stream_write_pes_header(TsMuxStream * stream,guint8 * data)623 tsmux_stream_write_pes_header (TsMuxStream * stream, guint8 * data)
624 {
625 guint16 length_to_write;
626 guint8 hdr_len = tsmux_stream_pes_header_length (stream);
627 guint8 *orig_data = data;
628
629 /* start_code prefix + stream_id + pes_packet_length = 6 bytes */
630 data[0] = 0x00;
631 data[1] = 0x00;
632 data[2] = 0x01;
633 data[3] = stream->id;
634 data += 4;
635
636 /* Write 2 byte PES packet length here. 0 (unbounded) is only
637 * valid for video packets */
638 if (stream->cur_pes_payload_size != 0) {
639 length_to_write = hdr_len + stream->cur_pes_payload_size - 6;
640 } else {
641 length_to_write = 0;
642 }
643
644 tsmux_put16 (&data, length_to_write);
645
646 if (stream->pi.flags & TSMUX_PACKET_FLAG_PES_FULL_HEADER) {
647 guint8 flags = 0;
648
649 /* Not scrambled, original, not-copyrighted, data_alignment not specified */
650 flags = 0x81;
651 if (stream->pi.flags & TSMUX_PACKET_FLAG_PES_DATA_ALIGNMENT)
652 flags |= 0x4;
653 *data++ = flags;
654 flags = 0;
655
656 /* Flags */
657 if (stream->pi.flags & TSMUX_PACKET_FLAG_PES_WRITE_PTS_DTS)
658 flags |= 0xC0;
659 else if (stream->pi.flags & TSMUX_PACKET_FLAG_PES_WRITE_PTS)
660 flags |= 0x80;
661 if (stream->pi.flags & TSMUX_PACKET_FLAG_PES_EXT_STREAMID)
662 flags |= 0x01; /* Enable PES_extension_flag */
663 *data++ = flags;
664
665 /* Header length is the total pes length,
666 * minus the 9 bytes of start codes, flags + hdr_len */
667 g_return_if_fail (hdr_len >= 9);
668 *data++ = (hdr_len - 9);
669
670 if (stream->pi.flags & TSMUX_PACKET_FLAG_PES_WRITE_PTS_DTS) {
671 tsmux_put_ts (&data, 0x3, stream->pts);
672 tsmux_put_ts (&data, 0x1, stream->dts);
673 } else if (stream->pi.flags & TSMUX_PACKET_FLAG_PES_WRITE_PTS) {
674 tsmux_put_ts (&data, 0x2, stream->pts);
675 }
676 if (stream->pi.flags & TSMUX_PACKET_FLAG_PES_EXT_STREAMID) {
677 guint8 ext_len;
678
679 flags = 0x0f; /* (reserved bits) | PES_extension_flag_2 */
680 *data++ = flags;
681
682 ext_len = 1; /* Only writing 1 byte into the extended fields */
683 *data++ = 0x80 | ext_len;
684 /* Write the extended streamID */
685 *data++ = stream->id_extended;
686 }
687 /* write stuffing bytes if fixed PES header length requested */
688 if (stream->pi.pes_header_length)
689 while (data < orig_data + stream->pi.pes_header_length + 9)
690 *data++ = 0xff;
691 }
692 }
693
694 /**
695 * tsmux_stream_add_data:
696 * @stream: a #TsMuxStream
697 * @data: data to add
698 * @len: length of @data
699 * @user_data: user data to pass to release func
700 * @pts: PTS of access unit in @data
701 * @dts: DTS of access unit in @data
702 * @random_access: TRUE if random access point (keyframe)
703 *
704 * Submit @len bytes of @data into @stream. @pts and @dts can be set to the
705 * timestamp (against a 90Hz clock) of the first access unit in @data. A
706 * timestamp of GST_CLOCK_STIME_NONE for @pts or @dts means unknown.
707 *
708 * @user_data will be passed to the release function as set with
709 * tsmux_stream_set_buffer_release_func() when @data can be freed.
710 */
711 void
tsmux_stream_add_data(TsMuxStream * stream,guint8 * data,guint len,void * user_data,gint64 pts,gint64 dts,gboolean random_access)712 tsmux_stream_add_data (TsMuxStream * stream, guint8 * data, guint len,
713 void *user_data, gint64 pts, gint64 dts, gboolean random_access)
714 {
715 TsMuxStreamBuffer *packet;
716
717 g_return_if_fail (stream != NULL);
718
719 packet = g_slice_new (TsMuxStreamBuffer);
720 packet->data = data;
721 packet->size = len;
722 packet->user_data = user_data;
723 packet->random_access = random_access;
724
725 packet->pts = pts;
726 packet->dts = dts;
727
728 if (stream->bytes_avail == 0) {
729 stream->last_pts = pts;
730 stream->last_dts = dts;
731 }
732
733 stream->bytes_avail += len;
734 stream->buffers = g_list_append (stream->buffers, packet);
735 }
736
737 /**
738 * tsmux_stream_default_get_es_descrs:
739 * @stream: a #TsMuxStream
740 * @buf: a buffer to hold the ES descriptor
741 * @len: the length used in @buf
742 *
743 * Write an Elementary Stream Descriptor for @stream into @buf. the number of
744 * bytes consumed in @buf will be updated in @len.
745 *
746 * @buf and @len must be at least #TSMUX_MIN_ES_DESC_LEN.
747 */
748 void
tsmux_stream_default_get_es_descrs(TsMuxStream * stream,GstMpegtsPMTStream * pmt_stream)749 tsmux_stream_default_get_es_descrs (TsMuxStream * stream,
750 GstMpegtsPMTStream * pmt_stream)
751 {
752 GstMpegtsDescriptor *descriptor;
753
754 g_return_if_fail (stream != NULL);
755 g_return_if_fail (pmt_stream != NULL);
756
757 if (stream->is_audio && stream->language[0] != '\0') {
758 descriptor = gst_mpegts_descriptor_from_iso_639_language (stream->language);
759 g_ptr_array_add (pmt_stream->descriptors, descriptor);
760 descriptor = NULL;
761 }
762
763 /* Based on the stream type, write out any descriptors to go in the
764 * PMT ES_info field */
765 /* tag (registration_descriptor), length, format_identifier */
766 switch (stream->stream_type) {
767 case TSMUX_ST_AUDIO_AAC:
768 /* FIXME */
769 break;
770 case TSMUX_ST_VIDEO_MPEG4:
771 /* FIXME */
772 break;
773 case TSMUX_ST_VIDEO_H264:
774 {
775 /* FIXME : Not sure about this additional_identification_info */
776 guint8 add_info[] = { 0xFF, 0x1B, 0x44, 0x3F };
777
778 descriptor = gst_mpegts_descriptor_from_registration ("HDMV",
779 add_info, 4);
780
781 g_ptr_array_add (pmt_stream->descriptors, descriptor);
782 break;
783 }
784 case TSMUX_ST_VIDEO_DIRAC:
785 descriptor = gst_mpegts_descriptor_from_registration ("drac", NULL, 0);
786 g_ptr_array_add (pmt_stream->descriptors, descriptor);
787 break;
788 case TSMUX_ST_VIDEO_JP2K:
789 {
790 /* J2K video descriptor
791 * descriptor_tag 8 uimsbf
792 * descriptor_length 8 uimsbf
793 * profile_and_level 16 uimsbf
794 * horizontal_size 32 uimsbf
795 * vertical_size 32 uimsbf
796 * max_bit_rate 32 uimsbf
797 * max_buffer_size 32 uimsbf
798 * DEN_frame_rate 16 uimsbf
799 * NUM_frame_rate 16 uimsbf
800 * color_specification 8 bslbf
801 * still_mode 1 bslbf
802 * interlace_video 1 bslbf
803 * reserved 6 bslbf
804 * private_data_byte 8 bslbf
805 */
806 gint8 still_interlace_reserved = 0x00;
807 int wr_size = 0;
808 guint8 *add_info = NULL;
809 guint8 level = stream->profile_and_level & 0xF;
810 guint32 max_buffer_size = 0;
811 GstByteWriter writer;
812 gst_byte_writer_init_with_size (&writer, 32, FALSE);
813
814 switch (level) {
815 case 1:
816 case 2:
817 case 3:
818 max_buffer_size = 1250000;
819 break;
820 case 4:
821 max_buffer_size = 2500000;
822 break;
823 case 5:
824 max_buffer_size = 5000000;
825 break;
826 case 6:
827 max_buffer_size = 10000000;
828 break;
829 default:
830 break;
831 }
832
833 gst_byte_writer_put_uint16_be (&writer, stream->profile_and_level);
834 gst_byte_writer_put_uint32_be (&writer, stream->horizontal_size);
835 gst_byte_writer_put_uint32_be (&writer, stream->vertical_size);
836 gst_byte_writer_put_uint32_be (&writer, max_buffer_size);
837 gst_byte_writer_put_uint32_be (&writer, stream->max_bitrate);
838 gst_byte_writer_put_uint16_be (&writer, stream->den);
839 gst_byte_writer_put_uint16_be (&writer, stream->num);
840 gst_byte_writer_put_uint8 (&writer, stream->color_spec);
841
842 if (stream->interlace_mode)
843 still_interlace_reserved |= 0x40;
844
845 gst_byte_writer_put_uint8 (&writer, still_interlace_reserved);
846 gst_byte_writer_put_uint8 (&writer, 0x00); /* private data byte */
847
848 wr_size = gst_byte_writer_get_size (&writer);
849 add_info = gst_byte_writer_reset_and_get_data (&writer);
850
851 descriptor =
852 gst_mpegts_descriptor_from_custom (GST_MTS_DESC_J2K_VIDEO, add_info,
853 wr_size);
854 g_ptr_array_add (pmt_stream->descriptors, descriptor);
855 }
856 break;
857 case TSMUX_ST_PS_AUDIO_AC3:
858 {
859 guint8 add_info[6];
860 guint8 *pos;
861
862 pos = add_info;
863
864 /* audio_stream_descriptor () | ATSC A/52-2001 Annex A
865 *
866 * descriptor_tag 8 uimsbf
867 * descriptor_length 8 uimsbf
868 * sample_rate_code 3 bslbf
869 * bsid 5 bslbf
870 * bit_rate_code 6 bslbf
871 * surround_mode 2 bslbf
872 * bsmod 3 bslbf
873 * num_channels 4 bslbf
874 * full_svc 1 bslbf
875 * langcod 8 bslbf
876 * [...]
877 */
878 *pos++ = 0x81;
879 *pos++ = 0x04;
880
881 /* 3 bits sample_rate_code, 5 bits hardcoded bsid (default ver 8) */
882 switch (stream->audio_sampling) {
883 case 48000:
884 *pos++ = 0x08;
885 break;
886 case 44100:
887 *pos++ = 0x28;
888 break;
889 case 32000:
890 *pos++ = 0x48;
891 break;
892 default:
893 *pos++ = 0xE8;
894 break; /* 48, 44.1 or 32 Khz */
895 }
896
897 /* 1 bit bit_rate_limit, 5 bits bit_rate_code, 2 bits suround_mode */
898 switch (stream->audio_bitrate) {
899 case 32:
900 *pos++ = 0x00 << 2;
901 break;
902 case 40:
903 *pos++ = 0x01 << 2;
904 break;
905 case 48:
906 *pos++ = 0x02 << 2;
907 break;
908 case 56:
909 *pos++ = 0x03 << 2;
910 break;
911 case 64:
912 *pos++ = 0x04 << 2;
913 break;
914 case 80:
915 *pos++ = 0x05 << 2;
916 break;
917 case 96:
918 *pos++ = 0x06 << 2;
919 break;
920 case 112:
921 *pos++ = 0x07 << 2;
922 break;
923 case 128:
924 *pos++ = 0x08 << 2;
925 break;
926 case 160:
927 *pos++ = 0x09 << 2;
928 break;
929 case 192:
930 *pos++ = 0x0A << 2;
931 break;
932 case 224:
933 *pos++ = 0x0B << 2;
934 break;
935 case 256:
936 *pos++ = 0x0C << 2;
937 break;
938 case 320:
939 *pos++ = 0x0D << 2;
940 break;
941 case 384:
942 *pos++ = 0x0E << 2;
943 break;
944 case 448:
945 *pos++ = 0x0F << 2;
946 break;
947 case 512:
948 *pos++ = 0x10 << 2;
949 break;
950 case 576:
951 *pos++ = 0x11 << 2;
952 break;
953 case 640:
954 *pos++ = 0x12 << 2;
955 break;
956 default:
957 *pos++ = 0x32 << 2;
958 break; /* 640 Kb/s upper limit */
959 }
960
961 /* 3 bits bsmod, 4 bits num_channels, 1 bit full_svc */
962 switch (stream->audio_channels) {
963 case 1:
964 *pos++ = 0x01 << 1;
965 break; /* 1/0 */
966 case 2:
967 *pos++ = 0x02 << 1;
968 break; /* 2/0 */
969 case 3:
970 *pos++ = 0x0A << 1;
971 break; /* <= 3 */
972 case 4:
973 *pos++ = 0x0B << 1;
974 break; /* <= 4 */
975 case 5:
976 *pos++ = 0x0C << 1;
977 break; /* <= 5 */
978 case 6:
979 default:
980 *pos++ = 0x0D << 1;
981 break; /* <= 6 */
982 }
983
984 *pos++ = 0x00;
985
986 descriptor = gst_mpegts_descriptor_from_registration ("AC-3",
987 add_info, 6);
988 g_ptr_array_add (pmt_stream->descriptors, descriptor);
989
990 descriptor =
991 gst_mpegts_descriptor_from_custom (GST_MTS_DESC_AC3_AUDIO_STREAM,
992 add_info, 6);
993 g_ptr_array_add (pmt_stream->descriptors, descriptor);
994
995 break;
996 }
997 case TSMUX_ST_PS_AUDIO_DTS:
998 /* FIXME */
999 break;
1000 case TSMUX_ST_PS_AUDIO_LPCM:
1001 /* FIXME */
1002 break;
1003 case TSMUX_ST_PS_TELETEXT:
1004 /* FIXME empty descriptor for now;
1005 * should be provided by upstream in event or so ? */
1006 descriptor =
1007 gst_mpegts_descriptor_from_custom (GST_MTS_DESC_DVB_TELETEXT, 0, 1);
1008
1009 g_ptr_array_add (pmt_stream->descriptors, descriptor);
1010 break;
1011 case TSMUX_ST_PS_DVB_SUBPICTURE:
1012 /* fallthrough ...
1013 * that should never happen anyway as
1014 * dvb subtitles are private data */
1015 case TSMUX_ST_PRIVATE_DATA:
1016 if (stream->is_dvb_sub) {
1017 GST_DEBUG ("Stream language %s", stream->language);
1018 /* Simple DVB subtitles with no monitor aspect ratio critical
1019 FIXME, how do we make it settable? */
1020 /* Default composition page ID */
1021 /* Default ancillary_page_id */
1022 descriptor =
1023 gst_mpegts_descriptor_from_dvb_subtitling (stream->language, 0x10,
1024 0x0001, 0x0152);
1025
1026 g_ptr_array_add (pmt_stream->descriptors, descriptor);
1027 break;
1028 }
1029 if (stream->is_opus) {
1030 descriptor = gst_mpegts_descriptor_from_registration ("Opus", NULL, 0);
1031 g_ptr_array_add (pmt_stream->descriptors, descriptor);
1032
1033 descriptor =
1034 gst_mpegts_descriptor_from_custom_with_extension
1035 (GST_MTS_DESC_DVB_EXTENSION, 0x80,
1036 &stream->opus_channel_config_code, 1);
1037
1038 g_ptr_array_add (pmt_stream->descriptors, descriptor);
1039 }
1040 if (stream->is_meta) {
1041 descriptor = gst_mpegts_descriptor_from_registration ("KLVA", NULL, 0);
1042 GST_DEBUG ("adding KLVA registration descriptor");
1043 g_ptr_array_add (pmt_stream->descriptors, descriptor);
1044 }
1045 default:
1046 break;
1047 }
1048 }
1049
1050 /**
1051 * tsmux_stream_get_es_descrs:
1052 * @stream: a #TsMuxStream
1053 * @buf: a buffer to hold the ES descriptor
1054 * @len: the length used in @buf
1055 *
1056 * Write an Elementary Stream Descriptor for @stream into @buf. the number of
1057 * bytes consumed in @buf will be updated in @len.
1058 *
1059 * @buf and @len must be at least #TSMUX_MIN_ES_DESC_LEN.
1060 */
1061 void
tsmux_stream_get_es_descrs(TsMuxStream * stream,GstMpegtsPMTStream * pmt_stream)1062 tsmux_stream_get_es_descrs (TsMuxStream * stream,
1063 GstMpegtsPMTStream * pmt_stream)
1064 {
1065 g_return_if_fail (stream->get_es_descrs != NULL);
1066
1067 stream->get_es_descrs (stream, pmt_stream, stream->get_es_descrs_data);
1068 }
1069
1070 /**
1071 * tsmux_stream_pcr_ref:
1072 * @stream: a #TsMuxStream
1073 *
1074 * Mark the stream as being used as the PCR for some program.
1075 */
1076 void
tsmux_stream_pcr_ref(TsMuxStream * stream)1077 tsmux_stream_pcr_ref (TsMuxStream * stream)
1078 {
1079 g_return_if_fail (stream != NULL);
1080
1081 stream->pcr_ref++;
1082 }
1083
1084 /**
1085 * tsmux_stream_pcr_unref:
1086 * @stream: a #TsMuxStream
1087 *
1088 * Mark the stream as no longer being used as the PCR for some program.
1089 */
1090 void
tsmux_stream_pcr_unref(TsMuxStream * stream)1091 tsmux_stream_pcr_unref (TsMuxStream * stream)
1092 {
1093 g_return_if_fail (stream != NULL);
1094
1095 stream->pcr_ref--;
1096 }
1097
1098 /**
1099 * tsmux_stream_is_pcr:
1100 * @stream: a #TsMuxStream
1101 *
1102 * Check if @stream is used as the PCR for some program.
1103 *
1104 * Returns: TRUE if the stream is in use as the PCR for some program.
1105 */
1106 gboolean
tsmux_stream_is_pcr(TsMuxStream * stream)1107 tsmux_stream_is_pcr (TsMuxStream * stream)
1108 {
1109 return stream->pcr_ref != 0;
1110 }
1111
1112 /**
1113 * tsmux_stream_get_pts:
1114 * @stream: a #TsMuxStream
1115 *
1116 * Return the PTS of the last buffer that has had bytes written and
1117 * which _had_ a PTS in @stream.
1118 *
1119 * Returns: the PTS of the last buffer in @stream.
1120 */
1121 gint64
tsmux_stream_get_pts(TsMuxStream * stream)1122 tsmux_stream_get_pts (TsMuxStream * stream)
1123 {
1124 g_return_val_if_fail (stream != NULL, GST_CLOCK_STIME_NONE);
1125
1126 return stream->last_pts;
1127 }
1128
1129 /**
1130 * tsmux_stream_get_dts:
1131 * @stream: a #TsMuxStream
1132 *
1133 * Return the DTS of the last buffer that has had bytes written and
1134 * which _had_ a DTS in @stream.
1135 *
1136 * Returns: the DTS of the last buffer in @stream.
1137 */
1138 gint64
tsmux_stream_get_dts(TsMuxStream * stream)1139 tsmux_stream_get_dts (TsMuxStream * stream)
1140 {
1141 g_return_val_if_fail (stream != NULL, GST_CLOCK_STIME_NONE);
1142
1143 return stream->last_dts;
1144 }
1145