1 /*****************************************************************************
2 * ts_hotfixes.c : MPEG PMT/PAT less streams fixups
3 *****************************************************************************
4 * Copyright (C) 2014-2016 - VideoLAN Authors
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU Lesser General Public License as published by
8 * the Free Software Foundation; either version 2.1 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Lesser General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 *****************************************************************************/
23 #include <vlc_common.h>
24 #include <vlc_demux.h>
27 #ifndef _DVBPSI_DVBPSI_H_
28 #include <dvbpsi/dvbpsi.h>
30 #include <dvbpsi/descriptor.h>
31 #include <dvbpsi/pat.h>
32 #include <dvbpsi/pmt.h>
34 #include "../../mux/mpeg/streams.h"
35 #include "../../mux/mpeg/tsutil.h"
36 #include "../../mux/mpeg/tables.h"
38 #include "timestamps.h"
41 #include "ts_streams.h"
44 #include "ts_streams_private.h"
46 #include "ts_hotfixes.h"
50 void ProbePES( demux_t
*p_demux
, ts_pid_t
*pid
, const uint8_t *p_pesstart
, size_t i_data
, bool b_adaptfield
)
52 demux_sys_t
*p_sys
= p_demux
->p_sys
;
53 const uint8_t *p_pes
= p_pesstart
;
65 p_pes
++; i_data
--;/* stuffing */
71 if( len
>= 7 && (p_pes
[0] & 0x10) )
72 pid
->probed
.i_pcr_count
++;
81 if( p_pes
[0] != 0 || p_pes
[1] != 0 || p_pes
[2] != 1 )
84 size_t i_pesextoffset
= 8;
86 if( p_pes
[7] & 0x80 ) // PTS
89 if ( i_data
< i_pesextoffset
||
90 !ExtractPESTimestamp( &p_pes
[9], p_pes
[7] >> 6, &i_dts
) )
92 pid
->probed
.i_dts_count
++;
94 if( p_pes
[7] & 0x40 ) // DTS
97 if ( i_data
< i_pesextoffset
||
98 !ExtractPESTimestamp( &p_pes
[14], 0x01, &i_dts
) )
101 if( p_pes
[7] & 0x20 ) // ESCR
103 if( p_pes
[7] & 0x10 ) // ESrate
105 if( p_pes
[7] & 0x08 ) // DSM
107 if( p_pes
[7] & 0x04 ) // CopyInfo
109 if( p_pes
[7] & 0x02 ) // PESCRC
112 if( pid
->probed
.i_fourcc
!= 0 )
113 goto codecprobingend
;
115 if ( i_data
< i_pesextoffset
)
118 /* HeaderdataLength */
119 const size_t i_payloadoffset
= 8 + 1 + p_pes
[8];
122 if ( i_data
< i_pesextoffset
|| i_data
< i_payloadoffset
)
125 i_data
-= 8 + 1 + p_pes
[8];
127 if( p_pes
[7] & 0x01 ) // PESExt
129 size_t i_extension2_offset
= 1;
130 if ( p_pes
[i_pesextoffset
] & 0x80 ) // private data
131 i_extension2_offset
+= 16;
132 if ( p_pes
[i_pesextoffset
] & 0x40 ) // pack
133 i_extension2_offset
+= 1;
134 if ( p_pes
[i_pesextoffset
] & 0x20 ) // seq
135 i_extension2_offset
+= 2;
136 if ( p_pes
[i_pesextoffset
] & 0x10 ) // P-STD
137 i_extension2_offset
+= 2;
138 if ( p_pes
[i_pesextoffset
] & 0x01 ) // Extension 2
140 uint8_t i_len
= p_pes
[i_pesextoffset
+ i_extension2_offset
] & 0x7F;
141 i_extension2_offset
+= i_len
;
143 if( i_data
< i_extension2_offset
)
146 i_data
-= i_extension2_offset
;
148 /* (i_payloadoffset - i_pesextoffset) 0xFF stuffing */
153 const uint8_t *p_data
= &p_pes
[i_payloadoffset
];
154 const uint8_t i_stream_id
= pid
->probed
.i_stream_id
= p_pes
[3];
155 /* NON MPEG audio & subpictures STREAM */
156 if(i_stream_id
== 0xBD)
158 if( !memcmp( p_data
, "\x7F\xFE\x80\x01", 4 ) )
160 pid
->probed
.i_fourcc
= VLC_CODEC_DTS
;
161 pid
->probed
.i_cat
= AUDIO_ES
;
163 else if( !memcmp( p_data
, "\x0B\x77", 2 ) )
165 pid
->probed
.i_fourcc
= VLC_CODEC_EAC3
;
166 pid
->probed
.i_cat
= AUDIO_ES
;
169 /* MPEG AUDIO STREAM */
170 else if(i_stream_id
>= 0xC0 && i_stream_id
<= 0xDF)
172 pid
->probed
.i_cat
= AUDIO_ES
;
173 if( p_data
[0] == 0xFF && (p_data
[1] & 0xE0) == 0xE0 &&
174 (p_data
[1] & 0x18) != 0x08 && (p_data
[1] & 0x06) != 0x00 )
176 pid
->probed
.i_fourcc
= VLC_CODEC_MPGA
;
178 else if( p_data
[0] == 0xFF && (p_data
[1] & 0xF6) == 0xF0 )
180 pid
->probed
.i_fourcc
= VLC_CODEC_MP4A
; /* ADTS */
181 pid
->probed
.i_original_fourcc
= VLC_FOURCC('A','D','T','S');
185 else if( i_stream_id
>= 0xE0 && i_stream_id
<= 0xEF )
187 pid
->probed
.i_cat
= VIDEO_ES
;
188 if( !memcmp( p_data
, "\x00\x00\x00\x01", 4 ) )
190 pid
->probed
.i_fourcc
= VLC_CODEC_H264
;
192 else if( !memcmp( p_data
, "\x00\x00\x01", 4 ) )
194 pid
->probed
.i_fourcc
= VLC_CODEC_MPGV
;
199 /* Track timestamps and flag missing PAT */
200 if( !p_sys
->patfix
.i_timesourcepid
&& i_dts
> -1 )
202 p_sys
->patfix
.i_first_dts
= i_dts
;
203 p_sys
->patfix
.i_timesourcepid
= pid
->i_pid
;
205 else if( p_sys
->patfix
.i_timesourcepid
== pid
->i_pid
&& i_dts
> -1 &&
206 p_sys
->patfix
.status
== PAT_WAITING
)
208 if( i_dts
- p_sys
->patfix
.i_first_dts
> TO_SCALE(MIN_PAT_INTERVAL
) )
209 p_sys
->patfix
.status
= PAT_MISSING
;
214 static void BuildPATCallback( void *p_opaque
, block_t
*p_block
)
216 ts_pid_t
*pat_pid
= (ts_pid_t
*) p_opaque
;
217 dvbpsi_packet_push( pat_pid
->u
.p_pat
->handle
, p_block
->p_buffer
);
218 block_Release( p_block
);
221 static void BuildPMTCallback( void *p_opaque
, block_t
*p_block
)
223 ts_pid_t
*program_pid
= (ts_pid_t
*) p_opaque
;
224 assert(program_pid
->type
== TYPE_PMT
);
227 dvbpsi_packet_push( program_pid
->u
.p_pmt
->handle
,
229 block_t
*p_next
= p_block
->p_next
;
230 block_Release( p_block
);
235 void MissingPATPMTFixup( demux_t
*p_demux
)
237 demux_sys_t
*p_sys
= p_demux
->p_sys
;
238 int i_program_number
= 1234;
239 int i_program_pid
= 1337;
240 int i_pcr_pid
= 0x1FFF;
243 ts_pid_t
*p_program_pid
= GetPID( p_sys
, i_program_pid
);
244 if( SEEN(p_program_pid
) )
246 /* Find a free one */
247 for( i_program_pid
= MIN_ES_PID
;
248 i_program_pid
<= MAX_ES_PID
&& SEEN(p_program_pid
);
251 p_program_pid
= GetPID( p_sys
, i_program_pid
);
255 const ts_pid_t
* candidates
[4] = { NULL
};
256 const ts_pid_t
*p_pid
= NULL
;
257 ts_pid_next_context_t pidnextctx
= ts_pid_NextContextInitValue
;
258 while( (p_pid
= ts_pid_Next( &p_sys
->pids
, &pidnextctx
)) )
260 if( !SEEN(p_pid
) || p_pid
->probed
.i_fourcc
== 0 )
263 if( p_pid
->probed
.i_pcr_count
&& candidates
[0] == NULL
&& false )
264 candidates
[0] = p_pid
;
266 if( p_pid
->probed
.i_cat
== AUDIO_ES
&&
267 (candidates
[1] == NULL
||
268 candidates
[1]->probed
.i_dts_count
> p_pid
->probed
.i_dts_count
) )
269 candidates
[1] = p_pid
;
271 if( candidates
[2] == NULL
&& p_pid
!= candidates
[1] &&
272 p_pid
->probed
.i_dts_count
> 0 )
273 candidates
[2] = p_pid
;
275 if( candidates
[3] == NULL
)
276 candidates
[3] = p_pid
;
281 for(int i
=0; i
<4; i
++)
285 i_pcr_pid
= candidates
[i
]->i_pid
;
286 p_sys
->patfix
.b_pcrhasnopcrfield
= (candidates
[i
]->probed
.i_pcr_count
< 1);
293 tsmux_stream_t patstream
=
296 .i_continuity_counter
= 0x10,
297 .b_discontinuity
= false
300 tsmux_stream_t pmtprogramstream
=
302 .i_pid
= i_program_pid
,
303 .i_continuity_counter
= 0x0,
304 .b_discontinuity
= false
307 BuildPAT( GetPID(p_sys
, 0)->u
.p_pat
->handle
,
308 &p_sys
->pids
.pat
, BuildPATCallback
,
311 1, &pmtprogramstream
, &i_program_number
);
313 /* PAT callback should have been triggered */
314 if( p_program_pid
->type
!= TYPE_PMT
)
316 msg_Err( p_demux
, "PAT creation failed" );
320 ts_mux_standard mux_standard
= (p_sys
->standard
== TS_STANDARD_ATSC
) ? TS_MUX_STANDARD_ATSC
321 : TS_MUX_STANDARD_DVB
;
329 struct esstreams_t
*esstreams
= calloc( i_num_pes
, sizeof(struct esstreams_t
) );
330 pes_mapped_stream_t
*mapped
= calloc( i_num_pes
, sizeof(pes_mapped_stream_t
) );
331 if( esstreams
&& mapped
)
334 for( int i
=0; i
<p_sys
->pids
.i_all
; i
++ )
336 p_pid
= p_sys
->pids
.pp_all
[i
];
339 p_pid
->probed
.i_fourcc
== 0 )
342 es_format_Init(&esstreams
[j
].fmt
, p_pid
->probed
.i_cat
, p_pid
->probed
.i_fourcc
);
343 esstreams
[j
].fmt
.i_original_fourcc
= p_pid
->probed
.i_original_fourcc
;
346 FillPMTESParams(mux_standard
, &esstreams
[j
].fmt
, &esstreams
[j
].ts
, &esstreams
[j
].pes
) )
348 es_format_Clean( &esstreams
[j
].fmt
);
352 /* Important for correct remapping: Enforce probed PES stream id */
353 esstreams
[j
].pes
.i_stream_id
= p_pid
->probed
.i_stream_id
;
355 esstreams
[j
].ts
.i_pid
= p_pid
->i_pid
;
356 mapped
[j
].pes
= &esstreams
[j
].pes
;
357 mapped
[j
].ts
= &esstreams
[j
].ts
;
358 mapped
[j
].fmt
= &esstreams
[j
].fmt
;
362 BuildPMT( GetPID(p_sys
, 0)->u
.p_pat
->handle
, VLC_OBJECT(p_demux
),
364 p_program_pid
, BuildPMTCallback
,
368 1, &pmtprogramstream
, &i_program_number
,
372 for( int i
=0; i
<j
; i
++ )
373 es_format_Clean( &esstreams
[i
].fmt
);