Add -Wold-style-definition
[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., 59 Temple Place - Suite 330,
36  * Boston, MA 02111-1307, 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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 "tsmux.h"
87 #include "tsmuxstream.h"
88 #include "crc.h"
89
90 /* Maximum total data length for a PAT section is 1024 bytes, minus an 
91  * 8 byte header, then the length of each program entry is 32 bits, 
92  * then finally a 32 bit CRC. Thus the maximum number of programs in this mux
93  * is (1024 - 8 - 4) / 4 = 253 because it only supports single section PATs */
94 #define TSMUX_MAX_PROGRAMS 253
95
96 #define TSMUX_SECTION_HDR_SIZE 8
97
98 #define TSMUX_DEFAULT_NETWORK_ID 0x0001
99 #define TSMUX_DEFAULT_TS_ID 0x0001
100
101 #define TSMUX_START_PROGRAM_ID 0x0001
102 #define TSMUX_START_PMT_PID 0x0010
103 #define TSMUX_START_ES_PID 0x0040
104
105 /* HACK: We use a fixed buffering offset for the PCR at the moment - 
106  * this is the amount 'in advance' of the stream that the PCR sits.
107  * 1/8 second atm */
108 #define TSMUX_PCR_OFFSET (TSMUX_CLOCK_FREQ / 8)
109
110 /* Times per second to write PCR */
111 #define TSMUX_DEFAULT_PCR_FREQ (25)
112
113 static gboolean tsmux_write_pat (TsMux * mux);
114 static gboolean tsmux_write_pmt (TsMux * mux, TsMuxProgram * program);
115
116 /**
117  * tsmux_new:
118  *
119  * Create a new muxer session.
120  *
121  * Returns: A new #TsMux object.
122  */
123 TsMux *
124 tsmux_new (void)
125 {
126   TsMux *mux;
127
128   mux = g_slice_new0 (TsMux);
129
130   mux->transport_id = TSMUX_DEFAULT_TS_ID;
131
132   mux->next_pgm_no = TSMUX_START_PROGRAM_ID;
133   mux->next_pmt_pid = TSMUX_START_PMT_PID;
134   mux->next_stream_pid = TSMUX_START_ES_PID;
135
136   mux->pat_changed = TRUE;
137   mux->last_pat_ts = -1;
138   mux->pat_interval = TSMUX_DEFAULT_PAT_INTERVAL;
139
140   return mux;
141 }
142
143 /**
144  * tsmux_set_write_func:
145  * @mux: a #TsMux
146  * @func: a user callback function
147  * @user_data: user data passed to @func
148  *
149  * Set the callback function and user data to be called when @mux has output to
150  * produce. @user_data will be passed as user data in @func.
151  */
152 void
153 tsmux_set_write_func (TsMux * mux, TsMuxWriteFunc func, void *user_data)
154 {
155   g_return_if_fail (mux != NULL);
156
157   mux->write_func = func;
158   mux->write_func_data = user_data;
159 }
160
161 /**
162  * tsmux_set_pat_interval:
163  * @mux: a #TsMux
164  * @freq: a new PAT interval
165  *
166  * Set the interval (in cycles of the 90kHz clock) for writing out the PAT table.
167  *
168  * Many transport stream clients might have problems if the PAT table is not
169  * inserted in the stream at regular intervals, especially when initially trying
170  * to figure out the contents of the stream.
171  */
172 void
173 tsmux_set_pat_interval (TsMux * mux, guint freq)
174 {
175   g_return_if_fail (mux != NULL);
176
177   mux->pat_interval = freq;
178 }
179
180 /**
181  * tsmux_get_pat_interval:
182  * @mux: a #TsMux
183  *
184  * Get the configured PAT interval. See also tsmux_set_pat_interval().
185  *
186  * Returns: the configured PAT interval
187  */
188 guint
189 tsmux_get_pat_interval (TsMux * mux)
190 {
191   g_return_val_if_fail (mux != NULL, 0);
192
193   return mux->pat_interval;
194 }
195
196 /**
197  * tsmux_free:
198  * @mux: a #TsMux
199  *
200  * Free all resources associated with @mux. After calling this function @mux can
201  * not be used anymore.
202  */
203 void
204 tsmux_free (TsMux * mux)
205 {
206   GList *cur;
207
208   g_return_if_fail (mux != NULL);
209
210   /* Free all programs */
211   for (cur = g_list_first (mux->programs); cur != NULL; cur = g_list_next (cur)) {
212     TsMuxProgram *program = (TsMuxProgram *) cur->data;
213
214     tsmux_program_free (program);
215   }
216   g_list_free (mux->programs);
217
218   /* Free all streams */
219   for (cur = g_list_first (mux->streams); cur != NULL; cur = g_list_next (cur)) {
220     TsMuxStream *stream = (TsMuxStream *) cur->data;
221
222     tsmux_stream_free (stream);
223   }
224   g_list_free (mux->streams);
225
226   g_slice_free (TsMux, mux);
227 }
228
229 /**
230  * tsmux_program_new:
231  * @mux: a #TsMux
232  *
233  * Create a new program in the mising session @mux.
234  * 
235  * Returns: a new #TsMuxProgram or %NULL when the maximum number of programs has
236  * been reached.
237  */
238 TsMuxProgram *
239 tsmux_program_new (TsMux * mux)
240 {
241   TsMuxProgram *program;
242
243   g_return_val_if_fail (mux != NULL, NULL);
244
245   /* Ensure we have room for another program */
246   if (mux->nb_programs == TSMUX_MAX_PROGRAMS)
247     return NULL;
248
249   program = g_slice_new0 (TsMuxProgram);
250
251   program->pmt_changed = TRUE;
252   program->last_pmt_ts = -1;
253   program->pmt_interval = TSMUX_DEFAULT_PMT_INTERVAL;
254
255   program->pgm_number = mux->next_pgm_no++;
256   program->pmt_pid = mux->next_pmt_pid++;
257   program->pcr_stream = NULL;
258   program->last_pcr = -1;
259
260   program->streams = g_array_sized_new (FALSE, TRUE, sizeof (TsMuxStream *), 1);
261
262   mux->programs = g_list_prepend (mux->programs, program);
263   mux->nb_programs++;
264   mux->pat_changed = TRUE;
265
266   return program;
267 }
268
269 /**
270  * tsmux_set_pmt_interval:
271  * @program: a #TsMuxProgram
272  * @freq: a new PMT interval
273  *
274  * Set the interval (in cycles of the 90kHz clock) for writing out the PMT table.
275  *
276  * Many transport stream clients might have problems if the PMT table is not
277  * inserted in the stream at regular intervals, especially when initially trying
278  * to figure out the contents of the stream.
279  */
280 void
281 tsmux_set_pmt_interval (TsMuxProgram * program, guint freq)
282 {
283   g_return_if_fail (program != NULL);
284
285   program->pmt_interval = freq;
286 }
287
288 /**
289  * tsmux_get_pmt_interval:
290  * @program: a #TsMuxProgram
291  *
292  * Get the configured PMT interval. See also tsmux_set_pmt_interval().
293  *
294  * Returns: the configured PMT interval
295  */
296 guint
297 tsmux_get_pmt_interval (TsMuxProgram * program)
298 {
299   g_return_val_if_fail (program != NULL, 0);
300
301   return program->pmt_interval;
302 }
303
304 /**
305  * tsmux_program_add_stream:
306  * @program: a #TsMuxProgram
307  * @stream: a #TsMuxStream
308  *
309  * Add @stream to @program.
310  */
311 void
312 tsmux_program_add_stream (TsMuxProgram * program, TsMuxStream * stream)
313 {
314   g_return_if_fail (program != NULL);
315   g_return_if_fail (stream != NULL);
316
317   program->nb_streams++;
318   g_array_append_val (program->streams, stream);
319   program->pmt_changed = TRUE;
320 }
321
322 /**
323  * tsmux_program_set_pcr_stream:
324  * @program: a #TsMuxProgram
325  * @stream: a #TsMuxStream
326  *
327  * Set @stream as the PCR stream for @program, overwriting the previously
328  * configured PCR stream. When @stream is NULL, program will have no PCR stream
329  * configured.
330  */
331 void
332 tsmux_program_set_pcr_stream (TsMuxProgram * program, TsMuxStream * stream)
333 {
334   g_return_if_fail (program != NULL);
335
336   if (program->pcr_stream == stream)
337     return;
338
339   if (program->pcr_stream != NULL)
340     tsmux_stream_pcr_unref (program->pcr_stream);
341   if (stream)
342     tsmux_stream_pcr_ref (stream);
343   program->pcr_stream = stream;
344
345   program->pmt_changed = TRUE;
346 }
347
348 /**
349  * tsmux_get_new_pid:
350  * @mux: a #TsMux
351  *
352  * Get a new free PID.
353  *
354  * Returns: a new free PID.
355  */
356 guint16
357 tsmux_get_new_pid (TsMux * mux)
358 {
359   g_return_val_if_fail (mux != NULL, -1);
360
361   /* FIXME: It's possible that this next PID is already taken if a 
362    * specific PID was requested earlier. We should find a free PID */
363   return mux->next_stream_pid++;
364 }
365
366 /**
367  * tsmux_create_stream:
368  * @mux: a #TsMux
369  * @stream_type: a #TsMuxStreamType
370  * @pid: the PID of the new stream.
371  *
372  * Create a new stream of @stream_type in the muxer session @mux.
373  *
374  * When @pid is set to #TSMUX_PID_AUTO, a new free PID will automatically
375  * be allocated for the new stream.
376  *
377  * Returns: a new #TsMuxStream.
378  */
379 TsMuxStream *
380 tsmux_create_stream (TsMux * mux, TsMuxStreamType stream_type, guint16 pid)
381 {
382   TsMuxStream *stream;
383   guint16 new_pid;
384
385   g_return_val_if_fail (mux != NULL, NULL);
386
387   if (pid == TSMUX_PID_AUTO) {
388     new_pid = tsmux_get_new_pid (mux);
389   } else {
390     new_pid = pid & 0x1FFF;
391   }
392
393   /* Ensure we're not creating a PID collision */
394   if (tsmux_find_stream (mux, new_pid))
395     return NULL;
396
397   stream = tsmux_stream_new (new_pid, stream_type);
398
399   mux->streams = g_list_prepend (mux->streams, stream);
400   mux->nb_streams++;
401
402   return stream;
403 }
404
405 /**
406  * tsmux_find_stream:
407  * @mux: a #TsMux
408  * @pid: the PID to find.
409  *
410  * Find the stream associated wih PID.
411  *
412  * Returns: a #TsMuxStream with @pid or NULL when the stream was not found.
413  */
414 TsMuxStream *
415 tsmux_find_stream (TsMux * mux, guint16 pid)
416 {
417   TsMuxStream *found = NULL;
418   GList *cur;
419
420   g_return_val_if_fail (mux != NULL, NULL);
421
422   for (cur = g_list_first (mux->streams); cur != NULL; cur = g_list_next (cur)) {
423     TsMuxStream *stream = (TsMuxStream *) cur->data;
424
425     if (tsmux_stream_get_pid (stream) == pid) {
426       found = stream;
427       break;
428     }
429   }
430   return found;
431 }
432
433 static gboolean
434 tsmux_packet_out (TsMux * mux)
435 {
436   if (G_UNLIKELY (mux->write_func == NULL))
437     return TRUE;
438
439   return mux->write_func (mux->packet_buf, TSMUX_PACKET_LENGTH,
440       mux->write_func_data, mux->new_pcr);
441 }
442
443 /*
444  * adaptation_field() {
445  *   adaptation_field_length                              8 uimsbf
446  *   if(adaptation_field_length >0) {
447  *     discontinuity_indicator                            1 bslbf
448  *     random_access_indicator                            1 bslbf
449  *     elementary_stream_priority_indicator               1 bslbf
450  *     PCR_flag                                           1 bslbf
451  *     OPCR_flag                                          1 bslbf
452  *     splicing_point_flag                                1 bslbf
453  *     transport_private_data_flag                        1 bslbf
454  *     adaptation_field_extension_flag                    1 bslbf
455  *     if(PCR_flag == '1') {
456  *       program_clock_reference_base                    33 uimsbf
457  *       reserved                                         6 bslbf
458  *       program_clock_reference_extension                9 uimsbf
459  *     }
460  *     if(OPCR_flag == '1') {
461  *       original_program_clock_reference_base           33 uimsbf
462  *       reserved                                         6 bslbf
463  *       original_program_clock_reference_extension       9 uimsbf
464  *     }
465  *     if (splicing_point_flag == '1') {
466  *       splice_countdown                                 8 tcimsbf
467  *     }
468  *     if(transport_private_data_flag == '1') {
469  *       transport_private_data_length                    8 uimsbf
470  *       for (i=0; i<transport_private_data_length;i++){
471  *         private_data_byte                              8 bslbf
472  *       }
473  *     }
474  *     if (adaptation_field_extension_flag == '1' ) {
475  *       adaptation_field_extension_length                8 uimsbf
476  *       ltw_flag                                         1 bslbf
477  *       piecewise_rate_flag                              1 bslbf
478  *       seamless_splice_flag                             1 bslbf
479  *       reserved                                         5 bslbf
480  *       if (ltw_flag == '1') {
481  *         ltw_valid_flag                                 1 bslbf
482  *         ltw_offset                                    15 uimsbf
483  *       }
484  *       if (piecewise_rate_flag == '1') {
485  *         reserved                                       2 bslbf
486  *         piecewise_rate                                22 uimsbf
487  *       }
488  *       if (seamless_splice_flag == '1'){
489  *         splice_type                                    4 bslbf
490  *         DTS_next_AU[32..30]                            3 bslbf
491  *         marker_bit                                     1 bslbf
492  *         DTS_next_AU[29..15]                           15 bslbf
493  *         marker_bit                                     1 bslbf
494  *         DTS_next_AU[14..0]                            15 bslbf
495  *         marker_bit                                     1 bslbf
496  *       }
497  *       for ( i=0;i<N;i++) {
498  *         reserved                                       8 bslbf
499  *       }
500  *     }
501  *     for (i=0;i<N;i++){
502  *       stuffing_byte                                    8 bslbf
503  *     }
504  *   }
505  * }
506  */
507 static gboolean
508 tsmux_write_adaptation_field (guint8 * buf,
509     TsMuxPacketInfo * pi, guint8 min_length, guint8 * written)
510 {
511   guint8 pos = 2;
512   guint8 flags = 0;
513
514   g_assert (min_length <= TSMUX_PAYLOAD_LENGTH);
515
516   /* Write out all the fields from the packet info only if the 
517    * user set the flag to request the adaptation field - if the flag
518    * isn't set, we're just supposed to write stuffing bytes */
519   if (pi->flags & TSMUX_PACKET_FLAG_ADAPTATION) {
520     TS_DEBUG ("writing adaptation fields");
521     if (pi->flags & TSMUX_PACKET_FLAG_DISCONT)
522       flags |= 0x80;
523     if (pi->flags & TSMUX_PACKET_FLAG_RANDOM_ACCESS)
524       flags |= 0x40;
525     if (pi->flags & TSMUX_PACKET_FLAG_PRIORITY)
526       flags |= 0x20;
527     if (pi->flags & TSMUX_PACKET_FLAG_WRITE_PCR) {
528       guint64 pcr_base;
529       guint32 pcr_ext;
530
531       pcr_base = (pi->pcr / 300);
532       pcr_ext = (pi->pcr % 300);
533
534       flags |= 0x10;
535       TS_DEBUG ("Writing PCR %" G_GUINT64_FORMAT " + ext %u", pcr_base,
536           pcr_ext);
537       buf[pos++] = (pcr_base >> 25) & 0xff;
538       buf[pos++] = (pcr_base >> 17) & 0xff;
539       buf[pos++] = (pcr_base >> 9) & 0xff;
540       buf[pos++] = (pcr_base >> 1) & 0xff;
541       buf[pos++] = ((pcr_base << 7) & 0x80) | ((pcr_ext >> 8) & 0x01);
542       buf[pos++] = (pcr_ext) & 0xff;
543     }
544     if (pi->flags & TSMUX_PACKET_FLAG_WRITE_OPCR) {
545       guint64 opcr_base;
546       guint32 opcr_ext;
547
548       opcr_base = (pi->opcr / 300);
549       opcr_ext = (pi->opcr % 300);
550
551       flags |= 0x08;
552       TS_DEBUG ("Writing OPCR");
553       buf[pos++] = (opcr_base >> 25) & 0xff;
554       buf[pos++] = (opcr_base >> 17) & 0xff;
555       buf[pos++] = (opcr_base >> 9) & 0xff;
556       buf[pos++] = (opcr_base >> 1) & 0xff;
557       buf[pos++] = ((opcr_base << 7) & 0x80) | ((opcr_ext >> 8) & 0x01);
558       buf[pos++] = (opcr_ext) & 0xff;
559     }
560     if (pi->flags & TSMUX_PACKET_FLAG_WRITE_SPLICE) {
561       flags |= 0x04;
562       buf[pos++] = pi->splice_countdown;
563     }
564     if (pi->private_data_len > 0) {
565       flags |= 0x02;
566       /* Private data to write, ensure we have enough room */
567       if ((1 + pi->private_data_len) > (TSMUX_PAYLOAD_LENGTH - pos))
568         return FALSE;
569       buf[pos++] = pi->private_data_len;
570       memcpy (&(buf[pos]), pi->private_data, pi->private_data_len);
571       pos += pi->private_data_len;
572       TS_DEBUG ("%u bytes of private data", pi->private_data_len);
573     }
574     if (pi->flags & TSMUX_PACKET_FLAG_WRITE_ADAPT_EXT) {
575       flags |= 0x01;
576       TS_DEBUG ("FIXME: write Adaptation extension");
577       /* Write an empty extension for now */
578       buf[pos++] = 1;
579       buf[pos++] = 0;
580     }
581   }
582   /* Write the flags at the start */
583   buf[1] = flags;
584
585   /* Stuffing bytes if needed */
586   while (pos < min_length)
587     buf[pos++] = 0xff;
588
589   /* Write the adaptation field length, which doesn't include its own byte */
590   buf[0] = pos - 1;
591
592   if (written)
593     *written = pos;
594
595   return TRUE;
596 }
597
598 static gboolean
599 tsmux_write_ts_header (guint8 * buf, TsMuxPacketInfo * pi,
600     guint * payload_len_out, guint * payload_offset_out)
601 {
602   guint8 *tmp;
603   guint8 adaptation_flag;
604   guint8 adapt_min_length = 0;
605   guint8 adapt_len = 0;
606   guint payload_len;
607   gboolean write_adapt = FALSE;
608
609   /* Sync byte */
610   buf[0] = TSMUX_SYNC_BYTE;
611
612   TS_DEBUG ("PID 0x%04x, counter = 0x%01x, %u bytes avail", pi->pid,
613       pi->packet_count & 0x0f, pi->stream_avail);
614
615   /* 3 bits: 
616    *   transport_error_indicator
617    *   payload_unit_start_indicator
618    *   transport_priority: (00)
619    * 13 bits: PID
620    */
621   tmp = buf + 1;
622   if (pi->packet_start_unit_indicator) {
623     tsmux_put16 (&tmp, 0x4000 | pi->pid);
624   } else
625     tsmux_put16 (&tmp, pi->pid);
626
627   /* 2 bits: scrambling_control (NOT SUPPORTED) (00)
628    * 2 bits: adaptation field control (1x has_adaptation_field | x1 has_payload)
629    * 4 bits: continuity counter (xxxx)
630    */
631   adaptation_flag = pi->packet_count & 0x0f;
632
633   if (pi->flags & TSMUX_PACKET_FLAG_ADAPTATION) {
634     write_adapt = TRUE;
635   }
636
637   if (pi->stream_avail < TSMUX_PAYLOAD_LENGTH) {
638     /* Need an adaptation field regardless for stuffing */
639     adapt_min_length = TSMUX_PAYLOAD_LENGTH - pi->stream_avail;
640     write_adapt = TRUE;
641   }
642
643   if (write_adapt) {
644     gboolean res;
645
646     /* Flag the adaptation field presence */
647     adaptation_flag |= 0x20;
648     res = tsmux_write_adaptation_field (buf + TSMUX_HEADER_LENGTH,
649         pi, adapt_min_length, &adapt_len);
650     if (G_UNLIKELY (res == FALSE))
651       return FALSE;
652
653     /* Should have written at least the number of bytes we requested */
654     g_assert (adapt_len >= adapt_min_length);
655   }
656
657   /* The amount of packet data we wrote is the remaining space after
658    * the adaptation field */
659   *payload_len_out = payload_len = TSMUX_PAYLOAD_LENGTH - adapt_len;
660   *payload_offset_out = TSMUX_HEADER_LENGTH + adapt_len;
661
662   /* Now if we are going to write out some payload, flag that fact */
663   if (payload_len > 0 && pi->stream_avail > 0) {
664     /* Flag the presence of a payload */
665     adaptation_flag |= 0x10;
666
667     /* We must have enough data to fill the payload, or some calculation
668      * went wrong */
669     g_assert (payload_len <= pi->stream_avail);
670
671     /* Packet with payload, increment the continuity counter */
672     pi->packet_count++;
673   }
674
675   /* Write the byte of transport_scrambling_control, adaptation_field_control 
676    * + continuity counter out */
677   buf[3] = adaptation_flag;
678
679
680   if (write_adapt) {
681     TS_DEBUG ("Adaptation field of size >= %d + %d bytes payload",
682         adapt_len, payload_len);
683   } else {
684     TS_DEBUG ("Payload of %d bytes only", payload_len);
685   }
686
687   return TRUE;
688 }
689
690 /**
691  * tsmux_write_stream_packet:
692  * @mux: a #TsMux
693  * @stream: a #TsMuxStream
694  *
695  * Write a packet of @stream.
696  *
697  * Returns: TRUE if the packet could be written.
698  */
699 gboolean
700 tsmux_write_stream_packet (TsMux * mux, TsMuxStream * stream)
701 {
702   guint payload_len, payload_offs;
703   TsMuxPacketInfo *pi = &stream->pi;
704   gboolean res;
705
706
707   mux->new_pcr = -1;
708   g_return_val_if_fail (mux != NULL, FALSE);
709   g_return_val_if_fail (stream != NULL, FALSE);
710
711   if (tsmux_stream_is_pcr (stream)) {
712     gint64 cur_pcr = 0;
713     gint64 cur_pts = tsmux_stream_get_pts (stream);
714     gboolean write_pat;
715     GList *cur;
716
717     if (cur_pts != -1) {
718       TS_DEBUG ("TS for PCR stream is %" G_GINT64_FORMAT, cur_pts);
719     }
720
721     /* FIXME: The current PCR needs more careful calculation than just
722      * writing a fixed offset */
723     if (cur_pts != -1 && (cur_pts >= TSMUX_PCR_OFFSET))
724       cur_pcr = (cur_pts - TSMUX_PCR_OFFSET) *
725           (TSMUX_SYS_CLOCK_FREQ / TSMUX_CLOCK_FREQ);
726
727     /* Need to decide whether to write a new PCR in this packet */
728     if (stream->last_pcr == -1 ||
729         (cur_pcr - stream->last_pcr >
730             (TSMUX_CLOCK_FREQ / TSMUX_DEFAULT_PCR_FREQ))) {
731
732       stream->pi.flags |=
733           TSMUX_PACKET_FLAG_ADAPTATION | TSMUX_PACKET_FLAG_WRITE_PCR;
734       stream->pi.pcr = cur_pcr;
735       stream->last_pcr = cur_pcr;
736       mux->new_pcr = cur_pcr;
737     }
738
739     /* check if we need to rewrite pat */
740     if (mux->last_pat_ts == -1 || mux->pat_changed)
741       write_pat = TRUE;
742     else if (cur_pts >= mux->last_pat_ts + mux->pat_interval)
743       write_pat = TRUE;
744     else
745       write_pat = FALSE;
746
747     if (write_pat) {
748       mux->last_pat_ts = cur_pts;
749       if (!tsmux_write_pat (mux))
750         return FALSE;
751     }
752
753     /* check if we need to rewrite any of the current pmts */
754     for (cur = g_list_first (mux->programs); cur != NULL;
755         cur = g_list_next (cur)) {
756       TsMuxProgram *program = (TsMuxProgram *) cur->data;
757       gboolean write_pmt;
758
759       if (program->last_pmt_ts == -1 || program->pmt_changed)
760         write_pmt = TRUE;
761       else if (cur_pts >= program->last_pmt_ts + program->pmt_interval)
762         write_pmt = TRUE;
763       else
764         write_pmt = FALSE;
765
766       if (write_pmt) {
767         program->last_pmt_ts = cur_pts;
768         if (!tsmux_write_pmt (mux, program))
769           return FALSE;
770       }
771     }
772   }
773
774   pi->stream_avail = tsmux_stream_bytes_avail (stream);
775   pi->packet_start_unit_indicator = tsmux_stream_at_pes_start (stream);
776
777   if (!tsmux_write_ts_header (mux->packet_buf, pi, &payload_len, &payload_offs))
778     return FALSE;
779
780   if (!tsmux_stream_get_data (stream, mux->packet_buf + payload_offs,
781           payload_len))
782     return FALSE;
783
784   res = tsmux_packet_out (mux);
785
786   /* Reset all dynamic flags */
787   stream->pi.flags &= TSMUX_PACKET_FLAG_PES_FULL_HEADER;
788
789   return res;
790 }
791
792 /**
793  * tsmux_program_free:
794  * @program: a #TsMuxProgram
795  *
796  * Free the resources of @program. After this call @program can not be used
797  * anymore.
798  */
799 void
800 tsmux_program_free (TsMuxProgram * program)
801 {
802   g_return_if_fail (program != NULL);
803
804   g_array_free (program->streams, TRUE);
805   g_slice_free (TsMuxProgram, program);
806 }
807
808 static gboolean
809 tsmux_write_section (TsMux * mux, TsMuxSection * section)
810 {
811   guint8 *cur_in;
812   guint payload_remain;
813   guint payload_len, payload_offs;
814   TsMuxPacketInfo *pi;
815
816   pi = &section->pi;
817
818   pi->packet_start_unit_indicator = TRUE;
819
820   cur_in = section->data;
821   payload_remain = pi->stream_avail;
822
823   while (payload_remain > 0) {
824     if (pi->packet_start_unit_indicator) {
825       /* Need to write an extra single byte start pointer */
826       pi->stream_avail++;
827
828       if (!tsmux_write_ts_header (mux->packet_buf, pi,
829               &payload_len, &payload_offs)) {
830         pi->stream_avail--;
831         return FALSE;
832       }
833       pi->stream_avail--;
834
835       /* Write the pointer byte */
836       mux->packet_buf[payload_offs] = 0x00;
837
838       payload_offs++;
839       payload_len--;
840       pi->packet_start_unit_indicator = FALSE;
841     } else {
842       if (!tsmux_write_ts_header (mux->packet_buf, pi,
843               &payload_len, &payload_offs))
844         return FALSE;
845     }
846
847     TS_DEBUG ("Outputting %d bytes to section. %d remaining after",
848         payload_len, payload_remain - payload_len);
849
850     memcpy (mux->packet_buf + payload_offs, cur_in, payload_len);
851
852     cur_in += payload_len;
853     payload_remain -= payload_len;
854
855     if (G_UNLIKELY (!tsmux_packet_out (mux))) {
856       mux->new_pcr = -1;
857       return FALSE;
858     }
859     mux->new_pcr = -1;
860   }
861
862   return TRUE;
863 }
864
865 static void
866 tsmux_write_section_hdr (guint8 * pos, guint8 table_id, guint16 len,
867     guint16 id, guint8 version, guint8 section_nr, guint8 last_section_nr)
868 {
869   /* The length passed is the total length of the section, but we're not 
870    * supposed to include the first 3 bytes of the header in the count */
871   len -= 3;
872
873   /* 1 byte table identifier */
874   *pos++ = table_id;
875   /* section_syntax_indicator = '0' | '0' | '11' reserved bits | (len >> 8) */
876   tsmux_put16 (&pos, 0xB000 | len);
877   /* 2 bytes transport/program id */
878   tsmux_put16 (&pos, id);
879
880   /* '11' reserved | version 'xxxxxx' | 'x' current_next */
881   *pos++ = 0xC0 | ((version & 0x1F) << 1) | 0x01;
882   *pos++ = section_nr;
883   *pos++ = last_section_nr;
884 }
885
886 static gboolean
887 tsmux_write_pat (TsMux * mux)
888 {
889   GList *cur;
890   TsMuxSection *pat = &mux->pat;
891
892   if (mux->pat_changed) {
893     /* program_association_section ()
894      * table_id                                   8   uimsbf
895      * section_syntax_indicator                   1   bslbf
896      * '0'                                        1   bslbf
897      * reserved                                   2   bslbf
898      * section_length                            12   uimsbf
899      * transport_stream_id                       16   uimsbf
900      * reserved                                   2   bslbf
901      * version_number                             5   uimsbf
902      * current_next_indicator                     1   bslbf
903      * section_number                             8   uimsbf 
904      * last_section_number                        8   uimsbf
905      * for (i = 0; i < N; i++) {
906      *    program_number                         16   uimsbf
907      *    reserved                                3   bslbf
908      *    network_PID_or_program_map_PID         13   uimbsf
909      * }
910      * CRC_32                                    32   rbchof
911      */
912     guint8 *pos;
913     guint32 crc;
914
915     /* Prepare the section data after the section header */
916     pos = pat->data + TSMUX_SECTION_HDR_SIZE;
917
918     for (cur = g_list_first (mux->programs); cur != NULL;
919         cur = g_list_next (cur)) {
920       TsMuxProgram *program = (TsMuxProgram *) cur->data;
921
922       tsmux_put16 (&pos, program->pgm_number);
923       tsmux_put16 (&pos, 0xE000 | program->pmt_pid);
924     }
925
926     /* Measure the section length, include extra 4 bytes for CRC below */
927     pat->pi.stream_avail = pos - pat->data + 4;
928
929     /* Go back and write the header now that we know the final length.
930      * table_id = 0 for PAT */
931     tsmux_write_section_hdr (pat->data, 0x00, pat->pi.stream_avail,
932         mux->transport_id, mux->pat_version, 0, 0);
933
934     /* Calc and output CRC for data bytes, not including itself */
935     crc = calc_crc32 (pat->data, pat->pi.stream_avail - 4);
936     tsmux_put32 (&pos, crc);
937
938     TS_DEBUG ("PAT has %d programs, is %u bytes",
939         mux->nb_programs, pat->pi.stream_avail);
940     mux->pat_changed = FALSE;
941     mux->pat_version++;
942   }
943
944   return tsmux_write_section (mux, pat);
945 }
946
947 static gboolean
948 tsmux_write_pmt (TsMux * mux, TsMuxProgram * program)
949 {
950   TsMuxSection *pmt = &program->pmt;
951
952   if (program->pmt_changed) {
953     /* program_association_section ()
954      * table_id                                   8   uimsbf
955      * section_syntax_indicator                   1   bslbf
956      * '0'                                        1   bslbf
957      * reserved                                   2   bslbf
958      * section_length                            12   uimsbf
959      * program_id                                16   uimsbf
960      * reserved                                   2   bslbf
961      * version_number                             5   uimsbf
962      * current_next_indicator                     1   bslbf
963      * section_number                             8   uimsbf 
964      * last_section_number                        8   uimsbf
965      * reserved                                   3   bslbf
966      * PCR_PID                                   13   uimsbf
967      * reserved                                   4   bslbf
968      * program_info_length                       12   uimsbf
969      * for (i = 0; i < N; i++)
970      *   descriptor ()
971      *
972      * for (i = 0; i < N1; i++) {
973      *    stream_type                             8   uimsbf
974      *    reserved                                3   bslbf
975      *    elementary_PID                         13   uimbsf
976      *    reserved                                4   bslbf
977      *    ES_info_length                         12   uimbsf
978      *    for (i = 0; i < N1; i++) {
979      *      descriptor ();
980      *    }
981      * }
982      * CRC_32                                    32   rbchof
983      */
984     guint8 *pos;
985     guint32 crc;
986     guint i;
987
988     /* Prepare the section data after the basic section header */
989     pos = pmt->data + TSMUX_SECTION_HDR_SIZE;
990
991     if (program->pcr_stream == NULL)
992       tsmux_put16 (&pos, 0xFFFF);
993     else
994       tsmux_put16 (&pos, 0xE000 | tsmux_stream_get_pid (program->pcr_stream));
995
996     /* 4 bits reserved, 12 bits program_info_length, descriptor : HDMV */
997     tsmux_put16 (&pos, 0xF00C);
998     tsmux_put16 (&pos, 0x0504);
999     tsmux_put16 (&pos, 0x4844);
1000     tsmux_put16 (&pos, 0x4D56);
1001     tsmux_put16 (&pos, 0x8804);
1002     tsmux_put16 (&pos, 0x0FFF);
1003     tsmux_put16 (&pos, 0xFCFC);
1004
1005     /* Write out the entries */
1006     for (i = 0; i < program->nb_streams; i++) {
1007       TsMuxStream *stream = g_array_index (program->streams, TsMuxStream *, i);
1008       guint16 es_info_len;
1009
1010       /* FIXME: Use API to retrieve this from the stream */
1011       *pos++ = stream->stream_type;
1012       tsmux_put16 (&pos, 0xE000 | tsmux_stream_get_pid (stream));
1013
1014       /* Write any ES descriptors needed */
1015       tsmux_stream_get_es_descrs (stream, mux->es_info_buf, &es_info_len);
1016       tsmux_put16 (&pos, 0xF000 | es_info_len);
1017
1018       if (es_info_len > 0) {
1019         TS_DEBUG ("Writing descriptor of len %d for PID 0x%04x",
1020             es_info_len, tsmux_stream_get_pid (stream));
1021         if (G_UNLIKELY (pos + es_info_len >=
1022                 pmt->data + TSMUX_MAX_SECTION_LENGTH))
1023           return FALSE;
1024
1025         memcpy (pos, mux->es_info_buf, es_info_len);
1026         pos += es_info_len;
1027       }
1028     }
1029
1030     /* Include the CRC in the byte count */
1031     pmt->pi.stream_avail = pos - pmt->data + 4;
1032
1033     /* Go back and patch the pmt_header now that we know the length.
1034      * table_id = 2 for PMT */
1035     tsmux_write_section_hdr (pmt->data, 0x02, pmt->pi.stream_avail,
1036         program->pgm_number, program->pmt_version, 0, 0);
1037
1038     /* Calc and output CRC for data bytes, 
1039      * but not counting the CRC bytes this time */
1040     crc = calc_crc32 (pmt->data, pmt->pi.stream_avail - 4);
1041     tsmux_put32 (&pos, crc);
1042
1043     TS_DEBUG ("PMT for program %d has %d streams, is %u bytes",
1044         program->pgm_number, program->nb_streams, pmt->pi.stream_avail);
1045
1046     pmt->pi.pid = program->pmt_pid;
1047     program->pmt_changed = FALSE;
1048     program->pmt_version++;
1049   }
1050
1051   return tsmux_write_section (mux, pmt);
1052 }