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