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