documentation: fixed a heap o' typos
[platform/upstream/gstreamer.git] / gst / mpegtsmux / tsmux / tsmux.c
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
88 #include "tsmux.h"
89 #include "tsmuxstream.h"
90
91 #define GST_CAT_DEFAULT gst_base_ts_mux_debug
92
93 /* Maximum total data length for a PAT section is 1024 bytes, minus an
94  * 8 byte header, then the length of each program entry is 32 bits,
95  * then finally a 32 bit CRC. Thus the maximum number of programs in this mux
96  * is (1024 - 8 - 4) / 4 = 253 because it only supports single section PATs */
97 #define TSMUX_MAX_PROGRAMS 253
98
99 #define TSMUX_SECTION_HDR_SIZE 8
100
101 #define TSMUX_DEFAULT_NETWORK_ID 0x0001
102 #define TSMUX_DEFAULT_TS_ID 0x0001
103
104 /* HACK: We use a fixed buffering offset for the PCR at the moment -
105  * this is the amount 'in advance' of the stream that the PCR sits.
106  * 1/8 second atm */
107 #define TSMUX_PCR_OFFSET (TSMUX_CLOCK_FREQ / 8)
108
109 /* Base for all written PCR and DTS/PTS,
110  * so we have some slack to go backwards */
111 #define CLOCK_BASE (TSMUX_CLOCK_FREQ * 10 * 360)
112
113 static gboolean tsmux_write_pat (TsMux * mux);
114 static gboolean tsmux_write_pmt (TsMux * mux, TsMuxProgram * program);
115 static gboolean tsmux_write_scte_null (TsMux * mux, TsMuxProgram * program);
116 static void
117 tsmux_section_free (TsMuxSection * section)
118 {
119   gst_mpegts_section_unref (section->section);
120   g_slice_free (TsMuxSection, section);
121 }
122
123 /**
124  * tsmux_new:
125  *
126  * Create a new muxer session.
127  *
128  * Returns: A new #TsMux object.
129  */
130 TsMux *
131 tsmux_new (void)
132 {
133   TsMux *mux;
134
135   mux = g_slice_new0 (TsMux);
136
137   mux->transport_id = TSMUX_DEFAULT_TS_ID;
138
139   mux->next_pgm_no = TSMUX_START_PROGRAM_ID;
140   mux->next_pmt_pid = TSMUX_START_PMT_PID;
141   mux->next_stream_pid = TSMUX_START_ES_PID;
142
143   mux->pat_changed = TRUE;
144   mux->next_pat_pcr = -1;
145   mux->pat_interval = TSMUX_DEFAULT_PAT_INTERVAL;
146
147   mux->si_changed = TRUE;
148   mux->si_interval = TSMUX_DEFAULT_SI_INTERVAL;
149
150   mux->pcr_interval = TSMUX_DEFAULT_PCR_INTERVAL;
151
152   mux->next_si_pcr = -1;
153
154   mux->si_sections = g_hash_table_new_full (g_direct_hash, g_direct_equal,
155       NULL, (GDestroyNotify) tsmux_section_free);
156
157   mux->new_stream_func = (TsMuxNewStreamFunc) tsmux_stream_new;
158   mux->new_stream_data = NULL;
159
160   return mux;
161 }
162
163 /**
164  * tsmux_set_write_func:
165  * @mux: a #TsMux
166  * @func: a user callback function
167  * @user_data: user data passed to @func
168  *
169  * Set the callback function and user data to be called when @mux has output to
170  * produce. @user_data will be passed as user data in @func.
171  */
172 void
173 tsmux_set_write_func (TsMux * mux, TsMuxWriteFunc func, void *user_data)
174 {
175   g_return_if_fail (mux != NULL);
176
177   mux->write_func = func;
178   mux->write_func_data = user_data;
179 }
180
181 /**
182  * tsmux_set_alloc_func:
183  * @mux: a #TsMux
184  * @func: a user callback function
185  * @user_data: user data passed to @func
186  *
187  * Set the callback function and user data to be called when @mux needs
188  * a new buffer to write a packet into.
189  * @user_data will be passed as user data in @func.
190  */
191 void
192 tsmux_set_alloc_func (TsMux * mux, TsMuxAllocFunc func, void *user_data)
193 {
194   g_return_if_fail (mux != NULL);
195
196   mux->alloc_func = func;
197   mux->alloc_func_data = user_data;
198 }
199
200 /**
201  * tsmux_set_new_stream_func:
202  * @mux: a #TsMux
203  * @func: a user callback function
204  * @user_data: user data passed to @func
205  *
206  * Set the callback function and user data to be called when @mux needs
207  * to create a new stream.
208  * @user_data will be passed as user data in @func.
209  */
210 void
211 tsmux_set_new_stream_func (TsMux * mux, TsMuxNewStreamFunc func,
212     void *user_data)
213 {
214   g_return_if_fail (mux != NULL);
215
216   mux->new_stream_func = func;
217   mux->new_stream_data = user_data;
218 }
219
220 /**
221  * tsmux_set_pat_interval:
222  * @mux: a #TsMux
223  * @freq: a new PAT interval
224  *
225  * Set the interval (in cycles of the 90kHz clock) for writing out the PAT table.
226  *
227  * Many transport stream clients might have problems if the PAT table is not
228  * inserted in the stream at regular intervals, especially when initially trying
229  * to figure out the contents of the stream.
230  */
231 void
232 tsmux_set_pat_interval (TsMux * mux, guint freq)
233 {
234   g_return_if_fail (mux != NULL);
235
236   mux->pat_interval = freq;
237 }
238
239 /**
240  * tsmux_set_pcr_interval:
241  * @mux: a #TsMux
242  * @freq: a new PCR interval
243  *
244  * Set the interval (in cycles of the 90kHz clock) for writing the PCR.
245  */
246 void
247 tsmux_set_pcr_interval (TsMux * mux, guint freq)
248 {
249   g_return_if_fail (mux != NULL);
250
251   mux->pcr_interval = freq;
252 }
253
254 /**
255  * tsmux_get_pat_interval:
256  * @mux: a #TsMux
257  *
258  * Get the configured PAT interval. See also tsmux_set_pat_interval().
259  *
260  * Returns: the configured PAT interval
261  */
262 guint
263 tsmux_get_pat_interval (TsMux * mux)
264 {
265   g_return_val_if_fail (mux != NULL, 0);
266
267   return mux->pat_interval;
268 }
269
270 /**
271  * tsmux_resend_pat:
272  * @mux: a #TsMux
273  *
274  * Resends the PAT before the next stream packet.
275  */
276 void
277 tsmux_resend_pat (TsMux * mux)
278 {
279   g_return_if_fail (mux != NULL);
280
281   mux->next_pat_pcr = -1;
282 }
283
284 /**
285  * tsmux_set_si_interval:
286  * @mux: a #TsMux
287  * @freq: a new SI table interval
288  *
289  * Set the interval (in cycles of the 90kHz clock) for writing out the SI tables.
290  *
291  */
292 void
293 tsmux_set_si_interval (TsMux * mux, guint freq)
294 {
295   g_return_if_fail (mux != NULL);
296
297   mux->si_interval = freq;
298 }
299
300 /**
301  * tsmux_get_si_interval:
302  * @mux: a #TsMux
303  *
304  * Get the configured SI table interval. See also tsmux_set_si_interval().
305  *
306  * Returns: the configured SI interval
307  */
308 guint
309 tsmux_get_si_interval (TsMux * mux)
310 {
311   g_return_val_if_fail (mux != NULL, 0);
312
313   return mux->si_interval;
314 }
315
316 /**
317  * tsmux_resend_si:
318  * @mux: a #TsMux
319  *
320  * Resends the SI tables before the next stream packet.
321  *
322  */
323 void
324 tsmux_resend_si (TsMux * mux)
325 {
326   g_return_if_fail (mux != NULL);
327
328   mux->next_si_pcr = -1;
329 }
330
331 /**
332  * tsmux_add_mpegts_si_section:
333  * @mux: a #TsMux
334  * @section: (transfer full): a #GstMpegtsSection to add
335  *
336  * Add a Service Information #GstMpegtsSection to the stream
337  *
338  * Returns: %TRUE on success, %FALSE otherwise
339  */
340 gboolean
341 tsmux_add_mpegts_si_section (TsMux * mux, GstMpegtsSection * section)
342 {
343   TsMuxSection *tsmux_section;
344
345   g_return_val_if_fail (mux != NULL, FALSE);
346   g_return_val_if_fail (section != NULL, FALSE);
347   g_return_val_if_fail (mux->si_sections != NULL, FALSE);
348
349   tsmux_section = g_slice_new0 (TsMuxSection);
350
351   GST_DEBUG ("Adding mpegts section with type %d to mux",
352       section->section_type);
353
354   tsmux_section->section = section;
355   tsmux_section->pi.pid = section->pid;
356
357   g_hash_table_insert (mux->si_sections,
358       GINT_TO_POINTER (section->section_type), tsmux_section);
359
360   mux->si_changed = TRUE;
361
362   return TRUE;
363 }
364
365
366 /**
367  * tsmux_free:
368  * @mux: a #TsMux
369  *
370  * Free all resources associated with @mux. After calling this function @mux can
371  * not be used anymore.
372  */
373 void
374 tsmux_free (TsMux * mux)
375 {
376   GList *cur;
377
378   g_return_if_fail (mux != NULL);
379
380   /* Free PAT section */
381   if (mux->pat.section)
382     gst_mpegts_section_unref (mux->pat.section);
383
384   /* Free all programs */
385   for (cur = mux->programs; cur; cur = cur->next) {
386     TsMuxProgram *program = (TsMuxProgram *) cur->data;
387
388     tsmux_program_free (program);
389   }
390   g_list_free (mux->programs);
391
392   /* Free all streams */
393   for (cur = mux->streams; cur; cur = cur->next) {
394     TsMuxStream *stream = (TsMuxStream *) cur->data;
395
396     tsmux_stream_free (stream);
397   }
398   g_list_free (mux->streams);
399
400   /* Free SI table sections */
401   g_hash_table_unref (mux->si_sections);
402
403   g_slice_free (TsMux, mux);
404 }
405
406 static gint
407 tsmux_program_compare (TsMuxProgram * program, gint * needle)
408 {
409   return (program->pgm_number - *needle);
410 }
411
412 /**
413  * tsmux_program_new:
414  * @mux: a #TsMux
415  *
416  * Create a new program in the missing session @mux.
417  *
418  * Returns: a new #TsMuxProgram or %NULL when the maximum number of programs has
419  * been reached.
420  */
421 TsMuxProgram *
422 tsmux_program_new (TsMux * mux, gint prog_id)
423 {
424   TsMuxProgram *program;
425
426   g_return_val_if_fail (mux != NULL, NULL);
427
428   /* Ensure we have room for another program */
429   if (mux->nb_programs == TSMUX_MAX_PROGRAMS)
430     return NULL;
431
432   program = g_slice_new0 (TsMuxProgram);
433
434   program->pmt_changed = TRUE;
435   program->pmt_interval = TSMUX_DEFAULT_PMT_INTERVAL;
436
437   program->next_pmt_pcr = -1;
438
439   if (prog_id == 0) {
440     program->pgm_number = mux->next_pgm_no++;
441     while (g_list_find_custom (mux->programs, &program->pgm_number,
442             (GCompareFunc) tsmux_program_compare) != NULL) {
443       program->pgm_number = mux->next_pgm_no++;
444     }
445   } else {
446     program->pgm_number = prog_id;
447     while (g_list_find_custom (mux->programs, &program->pgm_number,
448             (GCompareFunc) tsmux_program_compare) != NULL) {
449       program->pgm_number++;
450     }
451   }
452
453   program->pmt_pid = mux->next_pmt_pid++;
454   program->pcr_stream = NULL;
455
456   /* SCTE35 is disabled by default */
457   program->scte35_pid = 0;
458   program->scte35_null_interval = TSMUX_DEFAULT_SCTE_35_NULL_INTERVAL;
459   program->next_scte35_pcr = -1;
460
461   program->streams = g_array_sized_new (FALSE, TRUE, sizeof (TsMuxStream *), 1);
462
463   mux->programs = g_list_prepend (mux->programs, program);
464   mux->nb_programs++;
465   mux->pat_changed = TRUE;
466
467   return program;
468 }
469
470 /**
471  * tsmux_set_pmt_interval:
472  * @program: a #TsMuxProgram
473  * @freq: a new PMT interval
474  *
475  * Set the interval (in cycles of the 90kHz clock) for writing out the PMT table.
476  *
477  * Many transport stream clients might have problems if the PMT table is not
478  * inserted in the stream at regular intervals, especially when initially trying
479  * to figure out the contents of the stream.
480  */
481 void
482 tsmux_set_pmt_interval (TsMuxProgram * program, guint freq)
483 {
484   g_return_if_fail (program != NULL);
485
486   program->pmt_interval = freq;
487 }
488
489 /**
490  * tsmux_get_pmt_interval:
491  * @program: a #TsMuxProgram
492  *
493  * Get the configured PMT interval. See also tsmux_set_pmt_interval().
494  *
495  * Returns: the configured PMT interval
496  */
497 guint
498 tsmux_get_pmt_interval (TsMuxProgram * program)
499 {
500   g_return_val_if_fail (program != NULL, 0);
501
502   return program->pmt_interval;
503 }
504
505 /**
506  * tsmux_program_set_scte35_interval:
507  * @program: a #TsMuxProgram
508  * @freq: a new SCTE-35 NULL interval
509  *
510  * Set the interval (in cycles of the 90kHz clock) for sending out the SCTE-35
511  * NULL command. This is only effective is the SCTE-35 PID is not 0.
512  */
513 void
514 tsmux_program_set_scte35_interval (TsMuxProgram * program, guint interval)
515 {
516   g_return_if_fail (program != NULL);
517
518   program->scte35_null_interval = interval;
519 }
520
521 /**
522  * tsmux_resend_pmt:
523  * @program: a #TsMuxProgram
524  *
525  * Resends the PMT before the next stream packet.
526  */
527 void
528 tsmux_resend_pmt (TsMuxProgram * program)
529 {
530   g_return_if_fail (program != NULL);
531
532   program->next_pmt_pcr = -1;
533 }
534
535 /**
536  * tsmux_program_set_scte35_pid:
537  * @program: a #TsMuxProgram
538  * @pid: The pid to use, or 0 to deactivate usage.
539  *
540  * Set the @pid to use for sending SCTE-35 packets on the given
541  * @program.
542  *
543  * This needs to be called as early as possible if SCTE-35 sections
544  * are even going to be used with the given @program so that the PMT
545  * can be properly configured.
546  */
547 void
548 tsmux_program_set_scte35_pid (TsMuxProgram * program, guint16 pid)
549 {
550   TsMuxSection *section;
551   GstMpegtsSCTESIT *sit;
552   g_return_if_fail (program != NULL);
553
554   program->scte35_pid = pid;
555   /* Create/Update the section */
556   if (program->scte35_null_section) {
557     tsmux_section_free (program->scte35_null_section);
558     program->scte35_null_section = NULL;
559   }
560   if (pid != 0) {
561     program->scte35_null_section = section = g_slice_new0 (TsMuxSection);
562     section->pi.pid = pid;
563     sit = gst_mpegts_scte_null_new ();
564     section->section = gst_mpegts_section_from_scte_sit (sit, pid);
565   }
566 }
567
568 /**
569  * tsmux_program_get_scte35_pid:
570  * @program: a #TsMuxProgram
571  *
572  * Get the PID configured for sending SCTE-35 packets.
573  *
574  * Returns: the configured SCTE-35 PID, or 0 if not active.
575  */
576 guint16
577 tsmux_program_get_scte35_pid (TsMuxProgram * program)
578 {
579   g_return_val_if_fail (program != NULL, 0);
580
581   return program->scte35_pid;
582 }
583
584 /**
585  * tsmux_program_add_stream:
586  * @program: a #TsMuxProgram
587  * @stream: a #TsMuxStream
588  *
589  * Add @stream to @program.
590  */
591 void
592 tsmux_program_add_stream (TsMuxProgram * program, TsMuxStream * stream)
593 {
594   g_return_if_fail (program != NULL);
595   g_return_if_fail (stream != NULL);
596
597   g_array_append_val (program->streams, stream);
598   program->pmt_changed = TRUE;
599 }
600
601 /**
602  * tsmux_program_set_pcr_stream:
603  * @program: a #TsMuxProgram
604  * @stream: a #TsMuxStream
605  *
606  * Set @stream as the PCR stream for @program, overwriting the previously
607  * configured PCR stream. When @stream is NULL, program will have no PCR stream
608  * configured.
609  */
610 void
611 tsmux_program_set_pcr_stream (TsMuxProgram * program, TsMuxStream * stream)
612 {
613   g_return_if_fail (program != NULL);
614
615   if (program->pcr_stream == stream)
616     return;
617
618   if (program->pcr_stream != NULL)
619     tsmux_stream_pcr_unref (program->pcr_stream);
620   if (stream)
621     tsmux_stream_pcr_ref (stream);
622   program->pcr_stream = stream;
623
624   program->pmt_changed = TRUE;
625 }
626
627 /**
628  * tsmux_get_new_pid:
629  * @mux: a #TsMux
630  *
631  * Get a new free PID.
632  *
633  * Returns: a new free PID.
634  */
635 guint16
636 tsmux_get_new_pid (TsMux * mux)
637 {
638   g_return_val_if_fail (mux != NULL, -1);
639
640   /* make sure this PID is free
641    * (and not taken by a specific earlier request) */
642   do {
643     mux->next_stream_pid++;
644   } while (tsmux_find_stream (mux, mux->next_stream_pid));
645
646   return mux->next_stream_pid;
647 }
648
649 /**
650  * tsmux_create_stream:
651  * @mux: a #TsMux
652  * @stream_type: the stream type
653  * @pid: the PID of the new stream.
654  *
655  * Create a new stream of @stream_type in the muxer session @mux.
656  *
657  * When @pid is set to #TSMUX_PID_AUTO, a new free PID will automatically
658  * be allocated for the new stream.
659  *
660  * Returns: a new #TsMuxStream.
661  */
662 TsMuxStream *
663 tsmux_create_stream (TsMux * mux, guint stream_type, guint16 pid,
664     gchar * language)
665 {
666   TsMuxStream *stream;
667   guint16 new_pid;
668
669   g_return_val_if_fail (mux != NULL, NULL);
670   g_return_val_if_fail (mux->new_stream_func != NULL, NULL);
671
672   if (pid == TSMUX_PID_AUTO) {
673     new_pid = tsmux_get_new_pid (mux);
674   } else {
675     new_pid = pid & 0x1FFF;
676   }
677
678   /* Ensure we're not creating a PID collision */
679   if (tsmux_find_stream (mux, new_pid))
680     return NULL;
681
682   stream = mux->new_stream_func (new_pid, stream_type, mux->new_stream_data);
683
684   mux->streams = g_list_prepend (mux->streams, stream);
685   mux->nb_streams++;
686
687   if (language)
688     g_strlcat (stream->language, language, 3 * sizeof (gchar));
689   else
690     g_strlcat (stream->language, "eng", 3 * sizeof (gchar));
691
692   return stream;
693 }
694
695 /**
696  * tsmux_find_stream:
697  * @mux: a #TsMux
698  * @pid: the PID to find.
699  *
700  * Find the stream associated with PID.
701  *
702  * Returns: a #TsMuxStream with @pid or NULL when the stream was not found.
703  */
704 TsMuxStream *
705 tsmux_find_stream (TsMux * mux, guint16 pid)
706 {
707   TsMuxStream *found = NULL;
708   GList *cur;
709
710   g_return_val_if_fail (mux != NULL, NULL);
711
712   for (cur = mux->streams; cur; cur = cur->next) {
713     TsMuxStream *stream = (TsMuxStream *) cur->data;
714
715     if (tsmux_stream_get_pid (stream) == pid) {
716       found = stream;
717       break;
718     }
719   }
720   return found;
721 }
722
723 static gboolean
724 tsmux_get_buffer (TsMux * mux, GstBuffer ** buf)
725 {
726   g_return_val_if_fail (buf, FALSE);
727
728   if (G_UNLIKELY (!mux->alloc_func))
729     return FALSE;
730
731   mux->alloc_func (buf, mux->alloc_func_data);
732
733   if (!*buf)
734     return FALSE;
735
736   g_assert (gst_buffer_get_size (*buf) == TSMUX_PACKET_LENGTH);
737   return TRUE;
738 }
739
740 static gboolean
741 tsmux_packet_out (TsMux * mux, GstBuffer * buf, gint64 pcr)
742 {
743   if (G_UNLIKELY (mux->write_func == NULL)) {
744     if (buf)
745       gst_buffer_unref (buf);
746     return TRUE;
747   }
748
749   if (mux->bitrate)
750     GST_BUFFER_PTS (buf) =
751         gst_util_uint64_scale (mux->n_bytes * 8, GST_SECOND, mux->bitrate);
752
753   mux->n_bytes += gst_buffer_get_size (buf);
754
755   return mux->write_func (buf, mux->write_func_data, pcr);
756 }
757
758 /*
759  * adaptation_field() {
760  *   adaptation_field_length                              8 uimsbf
761  *   if(adaptation_field_length >0) {
762  *     discontinuity_indicator                            1 bslbf
763  *     random_access_indicator                            1 bslbf
764  *     elementary_stream_priority_indicator               1 bslbf
765  *     PCR_flag                                           1 bslbf
766  *     OPCR_flag                                          1 bslbf
767  *     splicing_point_flag                                1 bslbf
768  *     transport_private_data_flag                        1 bslbf
769  *     adaptation_field_extension_flag                    1 bslbf
770  *     if(PCR_flag == '1') {
771  *       program_clock_reference_base                    33 uimsbf
772  *       reserved                                         6 bslbf
773  *       program_clock_reference_extension                9 uimsbf
774  *     }
775  *     if(OPCR_flag == '1') {
776  *       original_program_clock_reference_base           33 uimsbf
777  *       reserved                                         6 bslbf
778  *       original_program_clock_reference_extension       9 uimsbf
779  *     }
780  *     if (splicing_point_flag == '1') {
781  *       splice_countdown                                 8 tcimsbf
782  *     }
783  *     if(transport_private_data_flag == '1') {
784  *       transport_private_data_length                    8 uimsbf
785  *       for (i=0; i<transport_private_data_length;i++){
786  *         private_data_byte                              8 bslbf
787  *       }
788  *     }
789  *     if (adaptation_field_extension_flag == '1' ) {
790  *       adaptation_field_extension_length                8 uimsbf
791  *       ltw_flag                                         1 bslbf
792  *       piecewise_rate_flag                              1 bslbf
793  *       seamless_splice_flag                             1 bslbf
794  *       reserved                                         5 bslbf
795  *       if (ltw_flag == '1') {
796  *         ltw_valid_flag                                 1 bslbf
797  *         ltw_offset                                    15 uimsbf
798  *       }
799  *       if (piecewise_rate_flag == '1') {
800  *         reserved                                       2 bslbf
801  *         piecewise_rate                                22 uimsbf
802  *       }
803  *       if (seamless_splice_flag == '1'){
804  *         splice_type                                    4 bslbf
805  *         DTS_next_AU[32..30]                            3 bslbf
806  *         marker_bit                                     1 bslbf
807  *         DTS_next_AU[29..15]                           15 bslbf
808  *         marker_bit                                     1 bslbf
809  *         DTS_next_AU[14..0]                            15 bslbf
810  *         marker_bit                                     1 bslbf
811  *       }
812  *       for ( i=0;i<N;i++) {
813  *         reserved                                       8 bslbf
814  *       }
815  *     }
816  *     for (i=0;i<N;i++){
817  *       stuffing_byte                                    8 bslbf
818  *     }
819  *   }
820  * }
821  */
822 static gboolean
823 tsmux_write_adaptation_field (guint8 * buf,
824     TsMuxPacketInfo * pi, guint8 min_length, guint8 * written)
825 {
826   guint8 pos = 2;
827   guint8 flags = 0;
828
829   g_assert (min_length <= TSMUX_PAYLOAD_LENGTH);
830
831   /* Write out all the fields from the packet info only if the
832    * user set the flag to request the adaptation field - if the flag
833    * isn't set, we're just supposed to write stuffing bytes */
834   if (pi->flags & TSMUX_PACKET_FLAG_ADAPTATION) {
835     TS_DEBUG ("writing adaptation fields");
836     if (pi->flags & TSMUX_PACKET_FLAG_DISCONT)
837       flags |= 0x80;
838     if (pi->flags & TSMUX_PACKET_FLAG_RANDOM_ACCESS)
839       flags |= 0x40;
840     if (pi->flags & TSMUX_PACKET_FLAG_PRIORITY)
841       flags |= 0x20;
842     if (pi->flags & TSMUX_PACKET_FLAG_WRITE_PCR) {
843       guint64 pcr_base;
844       guint32 pcr_ext;
845
846       pcr_base = (pi->pcr / 300);
847       pcr_ext = (pi->pcr % 300);
848
849       flags |= 0x10;
850       TS_DEBUG ("Writing PCR %" G_GUINT64_FORMAT " + ext %u", pcr_base,
851           pcr_ext);
852       buf[pos++] = (pcr_base >> 25) & 0xff;
853       buf[pos++] = (pcr_base >> 17) & 0xff;
854       buf[pos++] = (pcr_base >> 9) & 0xff;
855       buf[pos++] = (pcr_base >> 1) & 0xff;
856       buf[pos++] = ((pcr_base << 7) & 0x80) | 0x7e | ((pcr_ext >> 8) & 0x01);   /* set 6 reserve bits to 1 */
857       buf[pos++] = (pcr_ext) & 0xff;
858     }
859     if (pi->flags & TSMUX_PACKET_FLAG_WRITE_OPCR) {
860       guint64 opcr_base;
861       guint32 opcr_ext;
862
863       opcr_base = (pi->opcr / 300);
864       opcr_ext = (pi->opcr % 300);
865
866       flags |= 0x08;
867       TS_DEBUG ("Writing OPCR");
868       buf[pos++] = (opcr_base >> 25) & 0xff;
869       buf[pos++] = (opcr_base >> 17) & 0xff;
870       buf[pos++] = (opcr_base >> 9) & 0xff;
871       buf[pos++] = (opcr_base >> 1) & 0xff;
872       buf[pos++] = ((opcr_base << 7) & 0x80) | 0x7e | ((opcr_ext >> 8) & 0x01); /* set 6 reserve bits to 1 */
873       buf[pos++] = (opcr_ext) & 0xff;
874     }
875     if (pi->flags & TSMUX_PACKET_FLAG_WRITE_SPLICE) {
876       flags |= 0x04;
877       buf[pos++] = pi->splice_countdown;
878     }
879     if (pi->private_data_len > 0) {
880       flags |= 0x02;
881       /* Private data to write, ensure we have enough room */
882       if ((1 + pi->private_data_len) > (TSMUX_PAYLOAD_LENGTH - pos))
883         return FALSE;
884       buf[pos++] = pi->private_data_len;
885       memcpy (&(buf[pos]), pi->private_data, pi->private_data_len);
886       pos += pi->private_data_len;
887       TS_DEBUG ("%u bytes of private data", pi->private_data_len);
888     }
889     if (pi->flags & TSMUX_PACKET_FLAG_WRITE_ADAPT_EXT) {
890       flags |= 0x01;
891       TS_DEBUG ("FIXME: write Adaptation extension");
892       /* Write an empty extension for now */
893       buf[pos++] = 1;
894       buf[pos++] = 0x1f;        /* lower 5 bits are reserved, and should be all 1 */
895     }
896   }
897   /* Write the flags at the start */
898   buf[1] = flags;
899
900   /* Stuffing bytes if needed */
901   while (pos < min_length)
902     buf[pos++] = 0xff;
903
904   /* Write the adaptation field length, which doesn't include its own byte */
905   buf[0] = pos - 1;
906
907   if (written)
908     *written = pos;
909
910   return TRUE;
911 }
912
913 static gboolean
914 tsmux_write_ts_header (TsMux * mux, guint8 * buf, TsMuxPacketInfo * pi,
915     guint * payload_len_out, guint * payload_offset_out, guint stream_avail)
916 {
917   guint8 *tmp;
918   guint8 adaptation_flag = 0;
919   guint8 adapt_min_length = 0;
920   guint8 adapt_len = 0;
921   guint payload_len;
922   gboolean write_adapt = FALSE;
923
924   /* Sync byte */
925   buf[0] = TSMUX_SYNC_BYTE;
926
927   TS_DEBUG ("PID 0x%04x, counter = 0x%01x, %u bytes avail", pi->pid,
928       mux->pid_packet_counts[pi->pid] & 0x0f, stream_avail);
929
930   /* 3 bits:
931    *   transport_error_indicator
932    *   payload_unit_start_indicator
933    *   transport_priority: (00)
934    * 13 bits: PID
935    */
936   tmp = buf + 1;
937   if (pi->packet_start_unit_indicator) {
938     tsmux_put16 (&tmp, 0x4000 | pi->pid);
939   } else
940     tsmux_put16 (&tmp, pi->pid);
941
942   /* 2 bits: scrambling_control (NOT SUPPORTED) (00)
943    * 2 bits: adaptation field control (1x has_adaptation_field | x1 has_payload)
944    * 4 bits: continuity counter (xxxx)
945    */
946
947   if (pi->flags & TSMUX_PACKET_FLAG_ADAPTATION) {
948     write_adapt = TRUE;
949   }
950
951   if (stream_avail < TSMUX_PAYLOAD_LENGTH) {
952     /* Need an adaptation field regardless for stuffing */
953     adapt_min_length = TSMUX_PAYLOAD_LENGTH - stream_avail;
954     write_adapt = TRUE;
955   }
956
957   if (write_adapt) {
958     gboolean res;
959
960     /* Flag the adaptation field presence */
961     adaptation_flag |= 0x20;
962     res = tsmux_write_adaptation_field (buf + TSMUX_HEADER_LENGTH,
963         pi, adapt_min_length, &adapt_len);
964     if (G_UNLIKELY (res == FALSE))
965       return FALSE;
966
967     /* Should have written at least the number of bytes we requested */
968     g_assert (adapt_len >= adapt_min_length);
969   }
970
971   /* The amount of packet data we wrote is the remaining space after
972    * the adaptation field */
973   *payload_len_out = payload_len = TSMUX_PAYLOAD_LENGTH - adapt_len;
974   *payload_offset_out = TSMUX_HEADER_LENGTH + adapt_len;
975
976   /* Now if we are going to write out some payload, flag that fact */
977   if (payload_len > 0 && stream_avail > 0) {
978     /* Flag the presence of a payload */
979     adaptation_flag |= 0x10;
980
981     /* We must have enough data to fill the payload, or some calculation
982      * went wrong */
983     g_assert (payload_len <= stream_avail);
984
985     /* Packet with payload, increment the continuity counter */
986     mux->pid_packet_counts[pi->pid]++;
987   }
988
989   adaptation_flag |= mux->pid_packet_counts[pi->pid] & 0x0f;
990
991   /* Write the byte of transport_scrambling_control, adaptation_field_control
992    * + continuity counter out */
993   buf[3] = adaptation_flag;
994
995
996   if (write_adapt) {
997     TS_DEBUG ("Adaptation field of size >= %d + %d bytes payload",
998         adapt_len, payload_len);
999   } else {
1000     TS_DEBUG ("Payload of %d bytes only", payload_len);
1001   }
1002
1003   return TRUE;
1004 }
1005
1006 /* The unused_arg is needed for g_hash_table_foreach() */
1007 static gboolean
1008 tsmux_section_write_packet (gpointer unused_arg,
1009     TsMuxSection * section, TsMux * mux)
1010 {
1011   GstBuffer *section_buffer;
1012   GstBuffer *packet_buffer = NULL;
1013   GstMemory *mem;
1014   guint8 *packet;
1015   guint8 *data;
1016   gsize data_size = 0;
1017   gsize payload_written;
1018   guint len = 0, offset = 0, payload_len = 0;
1019   guint extra_alloc_bytes = 0;
1020
1021   g_return_val_if_fail (section != NULL, FALSE);
1022   g_return_val_if_fail (mux != NULL, FALSE);
1023
1024   /* Mark the start of new PES unit */
1025   section->pi.packet_start_unit_indicator = TRUE;
1026
1027   data = gst_mpegts_section_packetize (section->section, &data_size);
1028
1029   if (!data) {
1030     TS_DEBUG ("Could not packetize section");
1031     return FALSE;
1032   }
1033
1034   /* Mark payload data size */
1035   section->pi.stream_avail = data_size;
1036   payload_written = 0;
1037
1038   /* Wrap section data in a buffer without free function.
1039      The data will be freed when the GstMpegtsSection is destroyed. */
1040   section_buffer = gst_buffer_new_wrapped_full (GST_MEMORY_FLAG_READONLY,
1041       data, data_size, 0, data_size, NULL, NULL);
1042
1043   TS_DEBUG ("Section buffer with size %" G_GSIZE_FORMAT " created",
1044       gst_buffer_get_size (section_buffer));
1045
1046   while (section->pi.stream_avail > 0) {
1047
1048     packet = g_malloc (TSMUX_PACKET_LENGTH);
1049
1050     if (section->pi.packet_start_unit_indicator) {
1051       /* Wee need room for a pointer byte */
1052       section->pi.stream_avail++;
1053
1054       if (!tsmux_write_ts_header (mux, packet, &section->pi, &len, &offset,
1055               section->pi.stream_avail))
1056         goto fail;
1057
1058       /* Write the pointer byte */
1059       packet[offset++] = 0x00;
1060       payload_len = len - 1;
1061
1062     } else {
1063       if (!tsmux_write_ts_header (mux, packet, &section->pi, &len, &offset,
1064               section->pi.stream_avail))
1065         goto fail;
1066       payload_len = len;
1067     }
1068
1069     /* Wrap the TS header and adaption field in a GstMemory */
1070     mem = gst_memory_new_wrapped (GST_MEMORY_FLAG_READONLY,
1071         packet, TSMUX_PACKET_LENGTH, 0, offset, packet, g_free);
1072
1073     TS_DEBUG ("Creating packet buffer at offset "
1074         "%" G_GSIZE_FORMAT " with length %u", payload_written, payload_len);
1075
1076     /* If in M2TS mode, we will need to resize to 4 bytes after the end
1077        of the buffer. For performance reasons, we will now try to include
1078        4 extra bytes from the source buffer, then resize down, to avoid
1079        having an extra 4 byte GstMemory appended. If the source buffer
1080        does not have enough data for this, a new GstMemory will be used */
1081     if (gst_buffer_get_size (section_buffer) - (payload_written +
1082             payload_len) >= 4) {
1083       /* enough space */
1084       extra_alloc_bytes = 4;
1085     }
1086     packet_buffer = gst_buffer_copy_region (section_buffer, GST_BUFFER_COPY_ALL,
1087         payload_written, payload_len + extra_alloc_bytes);
1088
1089     /* Prepend the header to the section data */
1090     gst_buffer_prepend_memory (packet_buffer, mem);
1091
1092     /* add an extra 4 bytes if it could not be reserved already */
1093     if (extra_alloc_bytes == 4) {
1094       /* we allocated those already, resize */
1095       gst_buffer_set_size (packet_buffer,
1096           gst_buffer_get_size (packet_buffer) - extra_alloc_bytes);
1097     } else {
1098       void *ptr = g_malloc (4);
1099       GstMemory *extra =
1100           gst_memory_new_wrapped (GST_MEMORY_FLAG_READONLY, ptr, 4, 0, 0, ptr,
1101           g_free);
1102       gst_buffer_append_memory (packet_buffer, extra);
1103     }
1104
1105     TS_DEBUG ("Writing %d bytes to section. %d bytes remaining",
1106         len, section->pi.stream_avail - len);
1107
1108     /* Push the packet without PCR */
1109     if (G_UNLIKELY (!tsmux_packet_out (mux, packet_buffer, -1))) {
1110       /* Buffer given away */
1111       packet_buffer = NULL;
1112       goto fail;
1113     }
1114
1115     packet_buffer = NULL;
1116     section->pi.stream_avail -= len;
1117     payload_written += payload_len;
1118     section->pi.packet_start_unit_indicator = FALSE;
1119   }
1120
1121   gst_buffer_unref (section_buffer);
1122
1123   return TRUE;
1124
1125 fail:
1126   g_free (packet);
1127   if (section_buffer)
1128     gst_buffer_unref (section_buffer);
1129   return FALSE;
1130 }
1131
1132 /**
1133  * tsmux_send_section:
1134  * @mux: a #TsMux
1135  * @section: (transfer full): a #GstMpegtsSection to add
1136  *
1137  * Send a @section immediately on the stream.
1138  *
1139  * Returns: %TRUE on success, %FALSE otherwise
1140  */
1141 gboolean
1142 tsmux_send_section (TsMux * mux, GstMpegtsSection * section)
1143 {
1144   gboolean ret;
1145   TsMuxSection tsmux_section;
1146
1147   g_return_val_if_fail (mux != NULL, FALSE);
1148   g_return_val_if_fail (section != NULL, FALSE);
1149
1150   memset (&tsmux_section, 0, sizeof (tsmux_section));
1151
1152   GST_DEBUG ("Sending mpegts section with type %d to mux",
1153       section->section_type);
1154
1155   tsmux_section.section = section;
1156   tsmux_section.pi.pid = section->pid;
1157
1158   ret = tsmux_section_write_packet (NULL, &tsmux_section, mux);
1159   gst_mpegts_section_unref (section);
1160
1161   return ret;
1162 }
1163
1164 static gboolean
1165 tsmux_write_si (TsMux * mux)
1166 {
1167   g_hash_table_foreach (mux->si_sections,
1168       (GHFunc) tsmux_section_write_packet, mux);
1169
1170   mux->si_changed = FALSE;
1171
1172   return TRUE;
1173
1174 }
1175
1176 static void
1177 tsmux_write_null_ts_header (guint8 * buf)
1178 {
1179   *buf++ = TSMUX_SYNC_BYTE;
1180   *buf++ = 0x1f;
1181   *buf++ = 0xff;
1182   *buf++ = 0x10;
1183 }
1184
1185 static gint64
1186 get_current_pcr (TsMux * mux, gint64 cur_ts)
1187 {
1188   if (mux->bitrate)
1189     return (CLOCK_BASE - TSMUX_PCR_OFFSET) * 300 +
1190         gst_util_uint64_scale (mux->n_bytes * 8, TSMUX_SYS_CLOCK_FREQ,
1191         mux->bitrate);
1192   else if (cur_ts != G_MININT64)
1193     return (cur_ts -
1194         TSMUX_PCR_OFFSET) * (TSMUX_SYS_CLOCK_FREQ / TSMUX_CLOCK_FREQ);
1195   else
1196     return 0;
1197 }
1198
1199 static gint64
1200 write_new_pcr (TsMux * mux, TsMuxStream * stream, gint64 cur_pcr)
1201 {
1202   if (stream->next_pcr == -1 || cur_pcr > stream->next_pcr) {
1203     stream->pi.flags |=
1204         TSMUX_PACKET_FLAG_ADAPTATION | TSMUX_PACKET_FLAG_WRITE_PCR;
1205     stream->pi.pcr = cur_pcr;
1206
1207     if (stream->next_pcr == -1)
1208       stream->next_pcr = cur_pcr + mux->pcr_interval * 300;
1209     else
1210       stream->next_pcr += mux->pcr_interval * 300;
1211   } else {
1212     cur_pcr = -1;
1213   }
1214
1215   return cur_pcr;
1216 }
1217
1218 static gboolean
1219 rewrite_si (TsMux * mux, gint64 cur_ts)
1220 {
1221   gboolean write_pat;
1222   gboolean write_si;
1223   GList *cur;
1224   gint64 cur_pcr;
1225
1226   cur_pcr = get_current_pcr (mux, cur_ts);
1227
1228   /* check if we need to rewrite pat */
1229   if (mux->next_pat_pcr == -1 || mux->pat_changed)
1230     write_pat = TRUE;
1231   else if (cur_pcr > mux->next_pat_pcr)
1232     write_pat = TRUE;
1233   else
1234     write_pat = FALSE;
1235
1236   if (write_pat) {
1237     if (mux->next_pat_pcr == -1)
1238       mux->next_pat_pcr = cur_pcr + mux->pat_interval * 300;
1239     else
1240       mux->next_pat_pcr += mux->pat_interval * 300;
1241
1242     if (!tsmux_write_pat (mux))
1243       return FALSE;
1244
1245     cur_pcr = get_current_pcr (mux, cur_ts);
1246   }
1247
1248   /* check if we need to rewrite sit */
1249   if (mux->next_si_pcr == -1 || mux->si_changed)
1250     write_si = TRUE;
1251   else if (cur_pcr > mux->next_si_pcr)
1252     write_si = TRUE;
1253   else
1254     write_si = FALSE;
1255
1256   if (write_si) {
1257     if (mux->next_si_pcr == -1)
1258       mux->next_si_pcr = cur_pcr + mux->si_interval * 300;
1259     else
1260       mux->next_si_pcr += mux->si_interval * 300;
1261
1262     if (!tsmux_write_si (mux))
1263       return FALSE;
1264
1265     cur_pcr = get_current_pcr (mux, cur_ts);
1266   }
1267
1268   /* check if we need to rewrite any of the current pmts */
1269   for (cur = mux->programs; cur; cur = cur->next) {
1270     TsMuxProgram *program = (TsMuxProgram *) cur->data;
1271     gboolean write_pmt;
1272
1273     if (program->next_pmt_pcr == -1 || program->pmt_changed)
1274       write_pmt = TRUE;
1275     else if (cur_pcr > program->next_pmt_pcr)
1276       write_pmt = TRUE;
1277     else
1278       write_pmt = FALSE;
1279
1280     if (write_pmt) {
1281       if (program->next_pmt_pcr == -1)
1282         program->next_pmt_pcr = cur_pcr + program->pmt_interval * 300;
1283       else
1284         program->next_pmt_pcr += program->pmt_interval * 300;
1285
1286       if (!tsmux_write_pmt (mux, program))
1287         return FALSE;
1288
1289       cur_pcr = get_current_pcr (mux, cur_ts);
1290     }
1291
1292     if (program->scte35_pid != 0) {
1293       gboolean write_scte_null = FALSE;
1294       if (program->next_scte35_pcr == -1)
1295         write_scte_null = TRUE;
1296       else if (cur_pcr > program->next_scte35_pcr)
1297         write_scte_null = TRUE;
1298
1299       if (write_scte_null) {
1300         GST_DEBUG ("next scte35 pcr %" G_GINT64_FORMAT,
1301             program->next_scte35_pcr);
1302         if (program->next_scte35_pcr == -1)
1303           program->next_scte35_pcr =
1304               cur_pcr + program->scte35_null_interval * 300;
1305         else
1306           program->next_scte35_pcr += program->scte35_null_interval * 300;
1307         GST_DEBUG ("next scte35 NOW pcr %" G_GINT64_FORMAT,
1308             program->next_scte35_pcr);
1309
1310         if (!tsmux_write_scte_null (mux, program))
1311           return FALSE;
1312
1313         cur_pcr = get_current_pcr (mux, cur_ts);
1314       }
1315     }
1316   }
1317
1318   return TRUE;
1319 }
1320
1321 static gboolean
1322 pad_stream (TsMux * mux, TsMuxStream * stream, gint64 cur_ts)
1323 {
1324   guint64 bitrate;
1325   GstBuffer *buf = NULL;
1326   GstMapInfo map;
1327   gboolean ret = TRUE;
1328
1329   if (!mux->bitrate)
1330     goto done;
1331
1332   do {
1333     if (GST_CLOCK_STIME_IS_VALID (cur_ts)) {
1334       GstClockTimeDiff diff;
1335
1336       if (!GST_CLOCK_STIME_IS_VALID (stream->first_ts))
1337         stream->first_ts = cur_ts;
1338
1339       diff = GST_CLOCK_DIFF (stream->first_ts, cur_ts);
1340
1341       if (diff) {
1342         bitrate =
1343             gst_util_uint64_scale (mux->n_bytes * 8, TSMUX_CLOCK_FREQ, diff);
1344
1345         GST_LOG ("Transport stream bitrate: %" G_GUINT64_FORMAT, bitrate);
1346
1347         if (bitrate < mux->bitrate) {
1348           gint64 new_pcr;
1349           guint payload_len, payload_offs;
1350
1351           GST_LOG ("Padding transport stream");
1352
1353           if (!rewrite_si (mux, cur_ts)) {
1354             ret = FALSE;
1355             goto done;
1356           }
1357
1358           if (!tsmux_get_buffer (mux, &buf)) {
1359             ret = FALSE;
1360             goto done;
1361           }
1362
1363           gst_buffer_map (buf, &map, GST_MAP_READ);
1364
1365           if ((new_pcr =
1366                   write_new_pcr (mux, stream, get_current_pcr (mux,
1367                           cur_ts)) != -1))
1368             tsmux_write_ts_header (mux, map.data, &stream->pi, &payload_len,
1369                 &payload_offs, 0);
1370           else
1371             tsmux_write_null_ts_header (map.data);
1372
1373           gst_buffer_unmap (buf, &map);
1374
1375           stream->pi.flags &= TSMUX_PACKET_FLAG_PES_FULL_HEADER;
1376
1377           if (!(ret = tsmux_packet_out (mux, buf, new_pcr)))
1378             goto done;
1379         }
1380       } else {
1381         break;
1382       }
1383     } else {
1384       break;
1385     }
1386   } while (bitrate < mux->bitrate);
1387
1388 done:
1389   return ret;
1390 }
1391
1392 /**
1393  * tsmux_write_stream_packet:
1394  * @mux: a #TsMux
1395  * @stream: a #TsMuxStream
1396  *
1397  * Write a packet of @stream.
1398  *
1399  * Returns: TRUE if the packet could be written.
1400  */
1401 gboolean
1402 tsmux_write_stream_packet (TsMux * mux, TsMuxStream * stream)
1403 {
1404   guint payload_len, payload_offs;
1405   TsMuxPacketInfo *pi = &stream->pi;
1406   gboolean res;
1407   gint64 new_pcr = -1;
1408   GstBuffer *buf = NULL;
1409   GstMapInfo map;
1410
1411   g_return_val_if_fail (mux != NULL, FALSE);
1412   g_return_val_if_fail (stream != NULL, FALSE);
1413
1414   if (tsmux_stream_is_pcr (stream)) {
1415     gint64 cur_ts = CLOCK_BASE;
1416
1417     if (tsmux_stream_get_dts (stream) != G_MININT64)
1418       cur_ts += tsmux_stream_get_dts (stream);
1419     else
1420       cur_ts += tsmux_stream_get_pts (stream);
1421
1422     if (!rewrite_si (mux, cur_ts))
1423       goto fail;
1424
1425     if (!pad_stream (mux, stream, cur_ts))
1426       goto fail;
1427
1428     new_pcr = write_new_pcr (mux, stream, get_current_pcr (mux, cur_ts));
1429   }
1430
1431   pi->packet_start_unit_indicator = tsmux_stream_at_pes_start (stream);
1432   if (pi->packet_start_unit_indicator) {
1433     tsmux_stream_initialize_pes_packet (stream);
1434     if (stream->dts != G_MININT64)
1435       stream->dts += CLOCK_BASE;
1436     if (stream->pts != G_MININT64)
1437       stream->pts += CLOCK_BASE;
1438   }
1439   pi->stream_avail = tsmux_stream_bytes_avail (stream);
1440
1441   /* obtain buffer */
1442   if (!tsmux_get_buffer (mux, &buf))
1443     return FALSE;
1444
1445   gst_buffer_map (buf, &map, GST_MAP_READ);
1446
1447   if (!tsmux_write_ts_header (mux, map.data, pi, &payload_len, &payload_offs,
1448           pi->stream_avail))
1449     goto fail;
1450
1451
1452   if (!tsmux_stream_get_data (stream, map.data + payload_offs, payload_len))
1453     goto fail;
1454
1455   gst_buffer_unmap (buf, &map);
1456
1457   GST_DEBUG ("Writing PES of size %d", (int) gst_buffer_get_size (buf));
1458   res = tsmux_packet_out (mux, buf, new_pcr);
1459
1460   /* Reset all dynamic flags */
1461   stream->pi.flags &= TSMUX_PACKET_FLAG_PES_FULL_HEADER;
1462
1463   return res;
1464
1465   /* ERRORS */
1466 fail:
1467   {
1468     if (buf) {
1469       gst_buffer_unmap (buf, &map);
1470       gst_buffer_unref (buf);
1471     }
1472     return FALSE;
1473   }
1474 }
1475
1476 /**
1477  * tsmux_program_free:
1478  * @program: a #TsMuxProgram
1479  *
1480  * Free the resources of @program. After this call @program can not be used
1481  * anymore.
1482  */
1483 void
1484 tsmux_program_free (TsMuxProgram * program)
1485 {
1486   g_return_if_fail (program != NULL);
1487
1488   /* Free PMT section */
1489   if (program->pmt.section)
1490     gst_mpegts_section_unref (program->pmt.section);
1491   if (program->scte35_null_section)
1492     tsmux_section_free (program->scte35_null_section);
1493
1494   g_array_free (program->streams, TRUE);
1495   g_slice_free (TsMuxProgram, program);
1496 }
1497
1498 static gboolean
1499 tsmux_write_pat (TsMux * mux)
1500 {
1501
1502   if (mux->pat_changed) {
1503     /* program_association_section ()
1504      * for (i = 0; i < N; i++) {
1505      *    program_number                         16   uimsbf
1506      *    reserved                                3   bslbf
1507      *    network_PID_or_program_map_PID         13   uimbsf
1508      * }
1509      * CRC_32                                    32   rbchof
1510      */
1511     GList *cur;
1512     GPtrArray *pat;
1513
1514     pat = gst_mpegts_pat_new ();
1515
1516     for (cur = mux->programs; cur; cur = cur->next) {
1517       GstMpegtsPatProgram *pat_pgm;
1518       TsMuxProgram *program = (TsMuxProgram *) cur->data;
1519
1520       pat_pgm = gst_mpegts_pat_program_new ();
1521       pat_pgm->program_number = program->pgm_number;
1522       pat_pgm->network_or_program_map_PID = program->pmt_pid;
1523
1524       g_ptr_array_add (pat, pat_pgm);
1525     }
1526
1527     if (mux->pat.section)
1528       gst_mpegts_section_unref (mux->pat.section);
1529
1530     mux->pat.section = gst_mpegts_section_from_pat (pat, mux->transport_id);
1531
1532     mux->pat.section->version_number = mux->pat_version++;
1533
1534     TS_DEBUG ("PAT has %d programs", mux->nb_programs);
1535     mux->pat_changed = FALSE;
1536   }
1537
1538   return tsmux_section_write_packet (NULL, &mux->pat, mux);
1539 }
1540
1541 static gboolean
1542 tsmux_write_pmt (TsMux * mux, TsMuxProgram * program)
1543 {
1544
1545   if (program->pmt_changed) {
1546     /* program_association_section ()
1547      * reserved                                   3   bslbf
1548      * PCR_PID                                   13   uimsbf
1549      * reserved                                   4   bslbf
1550      * program_info_length                       12   uimsbf
1551      * for (i = 0; i < N; i++)
1552      *   descriptor ()
1553      *
1554      * for (i = 0; i < N1; i++) {
1555      *    stream_type                             8   uimsbf
1556      *    reserved                                3   bslbf
1557      *    elementary_PID                         13   uimbsf
1558      *    reserved                                4   bslbf
1559      *    ES_info_length                         12   uimbsf
1560      *    for (i = 0; i < N1; i++) {
1561      *      descriptor ();
1562      *    }
1563      * }
1564      */
1565     GstMpegtsDescriptor *descriptor;
1566     GstMpegtsPMT *pmt;
1567 #if 0
1568     /* See note about bluray descriptors below */
1569     guint8 desc[] = { 0x0F, 0xFF, 0xFC, 0xFC };
1570 #endif
1571     guint i;
1572
1573     pmt = gst_mpegts_pmt_new ();
1574
1575     if (program->pcr_stream == NULL)
1576       pmt->pcr_pid = 0x1FFF;
1577     else
1578       pmt->pcr_pid = tsmux_stream_get_pid (program->pcr_stream);
1579
1580 #if 0
1581     /* FIXME : These two descriptors should not be added in all PMT
1582      * but only in "bluray-compatible" mpeg-ts output. I even have my
1583      * doubt whether the DTCP descriptor is even needed */
1584     descriptor = gst_mpegts_descriptor_from_registration ("HDMV", NULL, 0);
1585     g_ptr_array_add (pmt->descriptors, descriptor);
1586
1587     /* DTCP descriptor, see
1588      * http://www.dtcp.com/documents/dtcp/info-20150204-dtcp-v1-rev%201-71.pdf */
1589     descriptor = gst_mpegts_descriptor_from_custom (0x88, desc, 4);
1590     g_ptr_array_add (pmt->descriptors, descriptor);
1591 #endif
1592
1593     /* Will SCTE-35 be potentially used ? */
1594     if (program->scte35_pid != 0) {
1595       descriptor = gst_mpegts_descriptor_from_registration ("CUEI", NULL, 0);
1596       g_ptr_array_add (pmt->descriptors, descriptor);
1597     }
1598
1599     /* Write out the entries */
1600     for (i = 0; i < program->streams->len; i++) {
1601       GstMpegtsPMTStream *pmt_stream;
1602       TsMuxStream *stream = g_array_index (program->streams, TsMuxStream *, i);
1603
1604       pmt_stream = gst_mpegts_pmt_stream_new ();
1605
1606       /* FIXME: Use API to retrieve this from the stream */
1607       pmt_stream->stream_type = stream->stream_type;
1608       pmt_stream->pid = tsmux_stream_get_pid (stream);
1609
1610       /* Write any ES descriptors needed */
1611       tsmux_stream_get_es_descrs (stream, pmt_stream);
1612       g_ptr_array_add (pmt->streams, pmt_stream);
1613     }
1614
1615     /* Will SCTE-35 be potentially used ? */
1616     if (program->scte35_pid != 0) {
1617       GstMpegtsPMTStream *pmt_stream = gst_mpegts_pmt_stream_new ();
1618       pmt_stream->stream_type = GST_MPEGTS_STREAM_TYPE_SCTE_SIT;
1619       pmt_stream->pid = program->scte35_pid;
1620       g_ptr_array_add (pmt->streams, pmt_stream);
1621     }
1622
1623     TS_DEBUG ("PMT for program %d has %d streams",
1624         program->pgm_number, program->streams->len);
1625
1626     pmt->program_number = program->pgm_number;
1627
1628     program->pmt.pi.pid = program->pmt_pid;
1629     program->pmt_changed = FALSE;
1630
1631     if (program->pmt.section)
1632       gst_mpegts_section_unref (program->pmt.section);
1633
1634     program->pmt.section = gst_mpegts_section_from_pmt (pmt, program->pmt_pid);
1635     program->pmt.section->version_number = program->pmt_version++;
1636   }
1637
1638   return tsmux_section_write_packet (NULL, &program->pmt, mux);
1639 }
1640
1641 static gboolean
1642 tsmux_write_scte_null (TsMux * mux, TsMuxProgram * program)
1643 {
1644   /* SCTE-35 NULL section is created when PID is set */
1645   GST_LOG ("Writing SCTE NULL packet");
1646   return tsmux_section_write_packet (NULL, program->scte35_null_section, mux);
1647 }
1648
1649 void
1650 tsmux_set_bitrate (TsMux * mux, guint64 bitrate)
1651 {
1652   mux->bitrate = bitrate;
1653 }