• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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