1 /*****************************************************************************
3 *****************************************************************************
4 * Copyright (C) 2004 VLC authors and VideoLAN
7 * Authors: Laurent Aimar <fenrir@via.ecp.fr>
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU Lesser General Public License as published by
11 * the Free Software Foundation; either version 2.1 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public License
20 * along with this program; if not, write to the Free Software Foundation,
21 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22 *****************************************************************************/
24 /*****************************************************************************
26 *****************************************************************************/
32 #include <vlc_common.h>
33 #include <vlc_plugin.h>
34 #include <vlc_demux.h>
38 /*****************************************************************************
40 *****************************************************************************/
41 static int Open ( vlc_object_t
* );
42 static void Close ( vlc_object_t
* );
45 set_description( N_("PVA demuxer" ) )
46 set_capability( "demux", 10 )
47 set_category( CAT_INPUT
)
48 set_subcategory( SUBCAT_INPUT_DEMUX
)
49 set_callbacks( Open
, Close
)
53 /*****************************************************************************
55 *****************************************************************************/
66 /* audio/video block */
67 block_t
*p_pes
; /* audio */
68 block_t
*p_es
; /* video */
73 static int Demux ( demux_t
*p_demux
);
74 static int Control ( demux_t
*p_demux
, int i_query
, va_list args
);
76 static int ReSynch ( demux_t
* );
77 static void ParsePES( demux_t
* );
79 /*****************************************************************************
81 *****************************************************************************/
82 static int Open( vlc_object_t
*p_this
)
84 demux_t
*p_demux
= (demux_t
*)p_this
;
87 const uint8_t *p_peek
;
89 if( vlc_stream_Peek( p_demux
->s
, &p_peek
, 8 ) < 8 ) return VLC_EGENERIC
;
90 if( p_peek
[0] != 'A' || p_peek
[1] != 'V' || p_peek
[4] != 0x55 )
92 /* In case we had forced this demuxer we try to resynch */
93 if( !p_demux
->obj
.force
|| ReSynch( p_demux
) )
97 p_sys
= malloc( sizeof( demux_sys_t
) );
98 if( unlikely(p_sys
== NULL
) )
101 /* Fill p_demux field */
102 p_demux
->pf_demux
= Demux
;
103 p_demux
->pf_control
= Control
;
104 p_demux
->p_sys
= p_sys
;
106 /* Register one audio and one video stream */
107 es_format_Init( &fmt
, AUDIO_ES
, VLC_CODEC_MPGA
);
108 fmt
.b_packetized
= false;
109 p_sys
->p_audio
= es_out_Add( p_demux
->out
, &fmt
);
111 es_format_Init( &fmt
, VIDEO_ES
, VLC_CODEC_MPGV
);
112 fmt
.b_packetized
= false;
113 p_sys
->p_video
= es_out_Add( p_demux
->out
, &fmt
);
120 p_sys
->b_pcr_audio
= false;
125 /*****************************************************************************
127 *****************************************************************************/
128 static void Close( vlc_object_t
*p_this
)
130 demux_t
*p_demux
= (demux_t
*)p_this
;
131 demux_sys_t
*p_sys
= p_demux
->p_sys
;
133 block_ChainRelease( p_sys
->p_es
);
134 block_ChainRelease( p_sys
->p_pes
);
140 /*****************************************************************************
142 *****************************************************************************
143 * See http://multimedia.cx/mirror/av_format_v1.pdf
144 *****************************************************************************/
145 static int Demux( demux_t
*p_demux
)
147 demux_sys_t
*p_sys
= p_demux
->p_sys
;
149 const uint8_t *p_peek
;
155 if( vlc_stream_Peek( p_demux
->s
, &p_peek
, 8 ) < 8 )
157 msg_Warn( p_demux
, "eof ?" );
158 return VLC_DEMUXER_EOF
;
160 if( p_peek
[0] != 'A' || p_peek
[1] != 'V' || p_peek
[4] != 0x55 )
162 msg_Warn( p_demux
, "lost synchro" );
163 if( ReSynch( p_demux
) )
165 return VLC_DEMUXER_EGENERIC
;
167 if( vlc_stream_Peek( p_demux
->s
, &p_peek
, 8 ) < 8 )
169 msg_Warn( p_demux
, "eof ?" );
170 return VLC_DEMUXER_EOF
;
174 i_size
= GetWBE( &p_peek
[6] );
177 case 0x01: /* VideoStream */
178 if( p_sys
->i_vc
< 0 )
180 msg_Dbg( p_demux
, "first packet for video" );
182 else if( ((p_sys
->i_vc
+ 1)&0xff) != p_peek
[3] )
184 msg_Dbg( p_demux
, "packet lost (video)" );
187 block_ChainRelease( p_sys
->p_es
);
191 p_sys
->i_vc
= p_peek
[3];
193 /* read the PTS and potential extra bytes TODO: make it a bit more optimised */
198 int i_pre
= p_peek
[5]&0x3;
200 if( ( p_frame
= vlc_stream_Block( p_demux
->s
, 8 + 4 + i_pre
) ) )
202 i_pts
= GetDWBE( &p_frame
->p_buffer
[8] );
203 if( p_frame
->i_buffer
> 12 )
205 p_frame
->p_buffer
+= 12;
206 p_frame
->i_buffer
-= 12;
207 block_ChainAppend( &p_sys
->p_es
, p_frame
);
211 block_Release( p_frame
);
217 if( ( p_frame
= p_sys
->p_es
) )
220 if( p_frame
->i_pts
!= VLC_TICK_INVALID
&& !p_sys
->b_pcr_audio
)
222 es_out_SetPCR( p_demux
->out
, p_frame
->i_pts
);
225 p_frame
= block_ChainGather( p_frame
);
226 if( likely(p_frame
) )
227 es_out_Send( p_demux
->out
, p_sys
->p_video
, p_frame
);
233 if( ( p_frame
= vlc_stream_Block( p_demux
->s
, i_size
+ i_skip
) ) )
235 p_frame
->p_buffer
+= i_skip
;
236 p_frame
->i_buffer
-= i_skip
;
238 p_frame
->i_pts
= FROM_SCALE(i_pts
);
239 block_ChainAppend( &p_sys
->p_es
, p_frame
);
243 case 0x02: /* MainAudioStream */
244 if( p_sys
->i_ac
< 0 )
246 msg_Dbg( p_demux
, "first packet for audio" );
248 else if( ((p_sys
->i_ac
+ 1)&0xff) != p_peek
[3] )
250 msg_Dbg( p_demux
, "packet lost (audio)" );
253 block_ChainRelease( p_sys
->p_pes
);
257 p_sys
->i_ac
= p_peek
[3];
259 if( p_peek
[5]&0x10 && p_sys
->p_pes
)
263 if( ( p_frame
= vlc_stream_Block( p_demux
->s
, i_size
+ 8 ) ) )
265 p_frame
->p_buffer
+= 8;
266 p_frame
->i_buffer
-= 8;
267 /* XXX this a hack, some streams aren't compliant and
268 * don't set pes_start flag */
269 if( p_sys
->p_pes
&& p_frame
->i_buffer
> 4 &&
270 p_frame
->p_buffer
[0] == 0x00 &&
271 p_frame
->p_buffer
[1] == 0x00 &&
272 p_frame
->p_buffer
[2] == 0x01 )
276 block_ChainAppend( &p_sys
->p_pes
, p_frame
);
281 msg_Warn( p_demux
, "unknown id=0x%x", p_peek
[2] );
282 if( vlc_stream_Read( p_demux
->s
, NULL
, i_size
+ 8 ) < i_size
+ 8 )
283 return VLC_DEMUXER_EOF
;
286 return VLC_DEMUXER_SUCCESS
;
289 /*****************************************************************************
291 *****************************************************************************/
292 static int Control( demux_t
*p_demux
, int i_query
, va_list args
)
294 /* demux_sys_t *p_sys = p_demux->p_sys; */
300 return vlc_stream_vaControl( p_demux
->s
, i_query
, args
);
302 case DEMUX_GET_POSITION
:
303 if( ( i64
= stream_Size( p_demux
->s
) ) > 0 )
305 pf
= va_arg( args
, double * );
306 double current
= vlc_stream_Tell( p_demux
->s
);
307 *pf
= current
/ (double)i64
;
312 case DEMUX_SET_POSITION
:
313 f
= va_arg( args
, double );
314 i64
= stream_Size( p_demux
->s
);
316 if( vlc_stream_Seek( p_demux
->s
, (int64_t)(i64
* f
) ) || ReSynch( p_demux
) )
324 pi64
= va_arg( args
, vlc_tick_t
* );
325 if( p_sys
->i_time
< 0 )
330 *pi64
= p_sys
->i_time
;
334 case DEMUX_GET_LENGTH
:
335 pi64
= va_arg( args
, vlc_tick_t
* );
336 if( p_sys
->i_mux_rate
> 0 )
338 *pi64
= vlc_tick_from_samples( stream_Size( p_demux
->s
) / 50, p_sys
->i_mux_rate
);
346 pf
= va_arg( args
, double * );
347 *pf
= (double)1000000.0 / (double)p_sys
->i_pcr_inc
;
350 case DEMUX_CAN_PAUSE
:
351 case DEMUX_SET_PAUSE_STATE
:
352 case DEMUX_CAN_CONTROL_PACE
:
353 case DEMUX_GET_PTS_DELAY
:
354 return demux_vaControlHelper( p_demux
->s
, 0, -1, 0, 1, i_query
, args
);
362 /*****************************************************************************
364 *****************************************************************************/
365 static int ReSynch( demux_t
*p_demux
)
369 const uint8_t *p_peek
;
370 int i_peek
= vlc_stream_Peek( p_demux
->s
, &p_peek
, 1024 );
376 while( i_skip
< i_peek
- 5 )
378 if( p_peek
[0] == 'A' && p_peek
[1] == 'V' && p_peek
[4] == 0x55 )
381 && vlc_stream_Read( p_demux
->s
, NULL
, i_skip
) < i_skip
)
389 if( vlc_stream_Read( p_demux
->s
, NULL
, i_skip
) < i_skip
)
396 static void ParsePES( demux_t
*p_demux
)
398 demux_sys_t
*p_sys
= p_demux
->p_sys
;
399 block_t
*p_pes
= p_sys
->p_pes
;
408 /* FIXME find real max size */
409 block_ChainExtract( p_pes
, hdr
, 30 );
411 /* See ยง2.4.3.6 of ISO 13818-1 */
412 if( hdr
[0] != 0 || hdr
[1] != 0 || hdr
[2] != 1 )
414 msg_Warn( p_demux
, "invalid hdr [0x%2.2x:%2.2x:%2.2x:%2.2x]",
415 hdr
[0], hdr
[1],hdr
[2],hdr
[3] );
416 block_ChainRelease( p_pes
);
419 // hdr[4] i_pes_size, 2 bytes
420 // hdr[6] Marker -> original_or_copy
422 /* we assume mpeg2 PES */
424 if( hdr
[7]&0x80 ) /* has pts */
426 i_pts
= GetPESTimestamp( &hdr
[9] );
428 if( hdr
[7]&0x40 ) /* has dts */
430 i_dts
= GetPESTimestamp( &hdr
[14] );
434 p_pes
= block_ChainGather( p_pes
);
435 if( unlikely(p_pes
== NULL
) )
437 if( p_pes
->i_buffer
<= i_skip
)
439 block_ChainRelease( p_pes
);
443 p_pes
->i_buffer
-= i_skip
;
444 p_pes
->p_buffer
+= i_skip
;
447 p_pes
->i_dts
= FROM_SCALE(i_dts
);
449 p_pes
->i_pts
= FROM_SCALE(i_pts
);
452 if( p_pes
->i_pts
!= VLC_TICK_INVALID
)
454 es_out_SetPCR( p_demux
->out
, p_pes
->i_pts
);
455 p_sys
->b_pcr_audio
= true;
457 es_out_Send( p_demux
->out
, p_sys
->p_audio
, p_pes
);