]> git.sesse.net Git - vlc/blob - modules/demux/asf/asf.c
9c41e77772e9feaca21c662c23475a4328261d15
[vlc] / modules / demux / asf / asf.c
1 /*****************************************************************************
2  * asf.c : ASFv01 file input module for vlc
3  *****************************************************************************
4  * Copyright (C) 2002-2003 VideoLAN
5  * $Id: asf.c,v 1.48 2004/01/05 13:00:20 zorglub Exp $
6  *
7  * Authors: Laurent Aimar <fenrir@via.ecp.fr>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
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 General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
22  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27 #include <stdlib.h>                                      /* malloc(), free() */
28
29 #include <vlc/vlc.h>
30 #include <vlc/input.h>
31
32 #include "vlc_playlist.h"
33
34 #include "codecs.h"                        /* BITMAPINFOHEADER, WAVEFORMATEX */
35 #include "libasf.h"
36
37 /*****************************************************************************
38  * Module descriptor
39  *****************************************************************************/
40 static int  Open  ( vlc_object_t * );
41 static void Close ( vlc_object_t * );
42
43 vlc_module_begin();
44     set_description( _("ASF v1.0 demuxer") );
45     set_capability( "demux", 200 );
46     set_callbacks( Open, Close );
47     add_shortcut( "asf" );
48 vlc_module_end();
49
50
51 /*****************************************************************************
52  * Local prototypes
53  *****************************************************************************/
54 static int  Demux   ( input_thread_t * );
55
56 typedef struct asf_stream_s
57 {
58     int i_cat;
59
60     es_out_id_t     *p_es;
61
62     asf_object_stream_properties_t *p_sp;
63
64     mtime_t i_time;
65
66     block_t         *p_frame; /* use to gather complete frame */
67
68 } asf_stream_t;
69
70 struct demux_sys_t
71 {
72     mtime_t             i_time;     /* µs */
73     mtime_t             i_length;   /* length of file file */
74
75     asf_object_root_t            *p_root;
76     asf_object_file_properties_t *p_fp;
77
78     unsigned int        i_streams;
79     asf_stream_t        *stream[128];
80
81     int64_t             i_data_begin;
82     int64_t             i_data_end;
83 };
84
85 static mtime_t  GetMoviePTS( demux_sys_t * );
86 static int      DemuxPacket( input_thread_t *, vlc_bool_t b_play_audio );
87
88 /*****************************************************************************
89  * Open: check file and initializes ASF structures
90  *****************************************************************************/
91 static int Open( vlc_object_t * p_this )
92 {
93     input_thread_t  *p_input = (input_thread_t *)p_this;
94     uint8_t         *p_peek;
95
96     guid_t          guid;
97
98     demux_sys_t     *p_sys;
99     unsigned int    i_stream, i;
100     asf_object_content_description_t *p_cd;
101
102     vlc_bool_t      b_seekable;
103
104     input_info_category_t *p_cat;
105
106     /* a little test to see if it could be a asf stream */
107     if( input_Peek( p_input, &p_peek, 16 ) < 16 )
108     {
109         msg_Warn( p_input, "ASF plugin discarded (cannot peek)" );
110         return VLC_EGENERIC;
111     }
112     ASF_GetGUID( &guid, p_peek );
113     if( !ASF_CmpGUID( &guid, &asf_object_header_guid ) )
114     {
115         msg_Warn( p_input, "ASF plugin discarded (not a valid file)" );
116         return VLC_EGENERIC;
117     }
118
119     /* Set p_input field */
120     p_input->pf_demux         = Demux;
121     p_input->pf_demux_control = demux_vaControlDefault;
122     p_input->p_demux_data = p_sys = malloc( sizeof( demux_sys_t ) );
123     memset( p_sys, 0, sizeof( demux_sys_t ) );
124     p_sys->i_time = -1;
125     p_sys->i_length = 0;
126
127     /* Now load all object ( except raw data ) */
128     stream_Control( p_input->s, STREAM_CAN_FASTSEEK, &b_seekable );
129     if( (p_sys->p_root = ASF_ReadObjectRoot( p_input->s, b_seekable )) == NULL )
130     {
131         msg_Warn( p_input, "ASF plugin discarded (not a valid file)" );
132         free( p_sys );
133         return VLC_EGENERIC;
134     }
135     p_sys->p_fp = p_sys->p_root->p_fp;
136
137     if( p_sys->p_fp->i_min_data_packet_size != p_sys->p_fp->i_max_data_packet_size )
138     {
139         msg_Warn( p_input,
140                   "ASF plugin discarded (invalid file_properties object)" );
141         goto error;
142     }
143
144     p_sys->i_streams = ASF_CountObject( p_sys->p_root->p_hdr,
145                                           &asf_object_stream_properties_guid );
146     if( !p_sys->i_streams )
147     {
148         msg_Warn( p_input, "ASF plugin discarded (cannot find any stream!)" );
149         goto error;
150     }
151
152     msg_Dbg( p_input, "found %d streams", p_sys->i_streams );
153
154     vlc_mutex_lock( &p_input->stream.stream_lock );
155     if( input_InitStream( p_input, 0 ) == -1)
156     {
157         vlc_mutex_unlock( &p_input->stream.stream_lock );
158         msg_Err( p_input, "cannot init stream" );
159         goto error;
160     }
161     p_input->stream.i_mux_rate = 0 ; /* updated later */
162     vlc_mutex_unlock( &p_input->stream.stream_lock );
163
164     for( i_stream = 0; i_stream < p_sys->i_streams; i_stream ++ )
165     {
166         asf_stream_t    *p_stream;
167         asf_object_stream_properties_t *p_sp;
168
169         p_sp = ASF_FindObject( p_sys->p_root->p_hdr,
170                                &asf_object_stream_properties_guid,
171                                i_stream );
172
173         p_stream =
174             p_sys->stream[p_sp->i_stream_number] =
175                 malloc( sizeof( asf_stream_t ) );
176         memset( p_stream, 0, sizeof( asf_stream_t ) );
177
178         p_stream->i_time = -1;
179         p_stream->p_sp = p_sp;
180         p_stream->p_es = NULL;
181         p_stream->p_frame = NULL;
182
183         if( ASF_CmpGUID( &p_sp->i_stream_type, &asf_object_stream_type_audio ) &&
184             p_sp->i_type_specific_data_length >= sizeof( WAVEFORMATEX ) - 2 )
185         {
186             es_format_t  fmt;
187             uint8_t      *p_data = p_sp->p_type_specific_data;
188
189             es_format_Init( &fmt, AUDIO_ES, 0 );
190             wf_tag_to_fourcc( GetWLE( &p_data[0] ), &fmt.i_codec, NULL );
191             fmt.audio.i_channels        = GetWLE(  &p_data[2] );
192             fmt.audio.i_rate      = GetDWLE( &p_data[4] );
193             fmt.i_bitrate         = GetDWLE( &p_data[8] ) * 8;
194             fmt.audio.i_blockalign      = GetWLE(  &p_data[12] );
195             fmt.audio.i_bitspersample   = GetWLE(  &p_data[14] );
196
197             if( p_sp->i_type_specific_data_length > sizeof( WAVEFORMATEX ) )
198             {
199                 fmt.i_extra = __MIN( GetWLE( &p_data[16] ),
200                                      p_sp->i_type_specific_data_length - sizeof( WAVEFORMATEX ) );
201                 fmt.p_extra = malloc( fmt.i_extra );
202                 memcpy( fmt.p_extra, &p_data[sizeof( WAVEFORMATEX )], fmt.i_extra );
203             }
204
205             p_stream->i_cat = AUDIO_ES;
206             p_stream->p_es = es_out_Add( p_input->p_es_out, &fmt );
207
208             msg_Dbg( p_input,
209                     "added new audio stream(codec:0x%x,ID:%d)",
210                     GetWLE( p_data ), p_sp->i_stream_number );
211         }
212         else if( ASF_CmpGUID( &p_sp->i_stream_type, &asf_object_stream_type_video ) &&
213                  p_sp->i_type_specific_data_length >= 11 + sizeof( BITMAPINFOHEADER ) )
214         {
215             es_format_t  fmt;
216             uint8_t      *p_data = &p_sp->p_type_specific_data[11];
217
218             es_format_Init( &fmt, VIDEO_ES,
219                             VLC_FOURCC( p_data[16], p_data[17], p_data[18], p_data[19] ) );
220             fmt.video.i_width = GetDWLE( p_data + 4 );
221             fmt.video.i_height= GetDWLE( p_data + 8 );
222
223             if( p_sp->i_type_specific_data_length > 11 + sizeof( BITMAPINFOHEADER ) )
224             {
225                 fmt.i_extra = __MIN( GetDWLE( p_data ),
226                                      p_sp->i_type_specific_data_length - 11 - sizeof( BITMAPINFOHEADER ) );
227                 fmt.p_extra = malloc( fmt.i_extra );
228                 memcpy( fmt.p_extra, &p_data[sizeof( BITMAPINFOHEADER )], fmt.i_extra );
229             }
230
231             p_stream->i_cat = VIDEO_ES;
232             p_stream->p_es = es_out_Add( p_input->p_es_out, &fmt );
233
234             msg_Dbg( p_input, "added new video stream(ID:%d)",
235                      p_sp->i_stream_number );
236         }
237         else
238         {
239             p_stream->i_cat = UNKNOWN_ES;
240             msg_Dbg( p_input, "ignoring unknown stream(ID:%d)",
241                      p_sp->i_stream_number );
242         }
243     }
244
245     p_sys->i_data_begin = p_sys->p_root->p_data->i_object_pos + 50;
246     if( p_sys->p_root->p_data->i_object_size != 0 )
247     { /* local file */
248         p_sys->i_data_end = p_sys->p_root->p_data->i_object_pos +
249                                     p_sys->p_root->p_data->i_object_size;
250     }
251     else
252     { /* live/broacast */
253         p_sys->i_data_end = -1;
254     }
255
256
257     /* go to first packet */
258     stream_Seek( p_input->s, p_sys->i_data_begin );
259
260     /* try to calculate movie time */
261     if( p_sys->p_fp->i_data_packets_count > 0 )
262     {
263         int64_t i_count;
264         int64_t i_size = stream_Size( p_input->s );
265
266         if( p_sys->i_data_end > 0 && i_size > p_sys->i_data_end )
267         {
268             i_size = p_sys->i_data_end;
269         }
270
271         /* real number of packets */
272         i_count = ( i_size - p_sys->i_data_begin ) /
273                   p_sys->p_fp->i_min_data_packet_size;
274
275         /* calculate the time duration in micro-s */
276         p_sys->i_length = (mtime_t)p_sys->p_fp->i_play_duration / 10 *
277                    (mtime_t)i_count /
278                    (mtime_t)p_sys->p_fp->i_data_packets_count;
279
280         if( p_sys->i_length > 0 )
281         {
282             p_input->stream.i_mux_rate =
283                 i_size / 50 * (int64_t)1000000 / p_sys->i_length;
284         }
285     }
286
287     /* We add all info about this stream */
288     p_cat = input_InfoCategory( p_input, "Asf" );
289     playlist_t *p_playlist = (playlist_t *)vlc_object_find( p_input,
290                                      VLC_OBJECT_PLAYLIST,  FIND_PARENT);
291     if( p_sys->i_length > 0 )
292     {
293         int64_t i_second = p_sys->i_length / (int64_t)1000000;
294
295         input_AddInfo( p_cat, _("Length"), "%d:%d:%d",
296                        (int)(i_second / 36000),
297                        (int)(( i_second / 60 ) % 60),
298                        (int)(i_second % 60) );
299         if( p_playlist )
300         {
301             playlist_AddInfo( p_playlist, -1, _("Asf"), _("Length"),
302                                "%d:%d:%d",
303                                (int)(i_second / 36000),
304                                (int)(( i_second / 60 ) % 60),
305                                (int)(i_second % 60) );
306         }
307     }
308     input_AddInfo( p_cat, _("Number of streams"), "%d" , p_sys->i_streams );
309     if( p_playlist )
310     {
311         playlist_AddInfo( p_playlist, -1, _("Asf"),_("Number of streams"),"%d",
312                          p_sys->i_streams );
313     }
314
315     if( ( p_cd = ASF_FindObject( p_sys->p_root->p_hdr,
316                                  &asf_object_content_description_guid, 0 ) ) )
317     {
318         if( *p_cd->psz_title )
319         {
320             input_AddInfo( p_cat, _("Title"), p_cd->psz_title );
321             playlist_AddInfo( p_playlist, -1, _("Asf"),_("Title"),
322                               p_cd->psz_title );
323             playlist_SetName( p_playlist, -1, p_cd->psz_title );
324         }
325         if( p_cd->psz_author )
326         {
327             input_AddInfo( p_cat, _("Author"), p_cd->psz_author );
328             playlist_AddInfo( p_playlist, -1, _("Asf"),_("Author"),
329                               p_cd->psz_author );
330             playlist_AddInfo( p_playlist, -1, _("General"),_("Author"),
331                               p_cd->psz_author );
332         }
333         if( p_cd->psz_copyright )
334         {
335             input_AddInfo( p_cat, _("Copyright"), p_cd->psz_copyright );
336             playlist_AddInfo( p_playlist, -1, _("Asf"),  _("Copyright"),
337                                p_cd->psz_copyright );
338         }
339         if( *p_cd->psz_description )
340         {
341             input_AddInfo( p_cat, _("Description"), p_cd->psz_description );
342             playlist_AddInfo( p_playlist, -1, _("Asf"),  _("Description"),
343                                p_cd->psz_description );
344         }
345         if( *p_cd->psz_rating )
346         {
347             input_AddInfo( p_cat, _("Rating"), p_cd->psz_rating );
348             playlist_AddInfo( p_playlist, -1, _("Asf"),  _("Rating"),
349                               p_cd->psz_rating );
350         }
351     }
352
353     /* FIXME to port to new way */
354     for( i_stream = 0, i = 0; i < 128; i++ )
355     {
356         asf_object_codec_list_t *p_cl =
357             ASF_FindObject( p_sys->p_root->p_hdr,
358                             &asf_object_codec_list_guid, 0 );
359
360         if( p_sys->stream[i] )
361         {
362             char *psz_cat = malloc( strlen(_("Stream")) + 10 );
363             sprintf( psz_cat, "%s %d", _("Stream"), i_stream );
364             p_cat = input_InfoCategory( p_input, psz_cat);
365
366             if( p_cl && i_stream < p_cl->i_codec_entries_count )
367             {
368                 input_AddInfo( p_cat, _("Codec name"),
369                                p_cl->codec[i_stream].psz_name );
370                 playlist_AddInfo( p_playlist, -1, psz_cat, _("Codec name"),
371                                   p_cl->codec[i_stream].psz_name );
372                 input_AddInfo( p_cat, _("Codec description"),
373                                p_cl->codec[i_stream].psz_description );
374                 playlist_AddInfo( p_playlist, -1, psz_cat,
375                                 _("Codec description"),
376                                  p_cl->codec[i_stream].psz_description );
377             }
378             free( psz_cat );
379             i_stream++;
380         }
381     }
382
383     if( p_playlist ) vlc_object_release( p_playlist );
384     return VLC_SUCCESS;
385
386 error:
387     ASF_FreeObjectRoot( p_input->s, p_sys->p_root );
388     free( p_sys );
389     return VLC_EGENERIC;
390 }
391
392
393 /*****************************************************************************
394  * Demux: read packet and send them to decoders
395  *****************************************************************************/
396 static int Demux( input_thread_t *p_input )
397 {
398     demux_sys_t *p_sys = p_input->p_demux_data;
399     vlc_bool_t b_play_audio;
400     int i;
401
402     /* catch seek from user */
403     if( p_input->stream.p_selected_program->i_synchro_state == SYNCHRO_REINIT )
404     {
405         int64_t i_offset;
406
407         msleep( p_input->i_pts_delay );
408
409         i_offset = stream_Tell( p_input->s ) - p_sys->i_data_begin;
410         if( i_offset  < 0 )
411         {
412             i_offset = 0;
413         }
414         if( i_offset % p_sys->p_fp->i_min_data_packet_size > 0 )
415         {
416             i_offset -= i_offset % p_sys->p_fp->i_min_data_packet_size;
417         }
418
419         if( stream_Seek( p_input->s, i_offset + p_sys->i_data_begin ) )
420         {
421             msg_Warn( p_input, "cannot resynch after seek (EOF?)" );
422             return -1;
423         }
424
425         p_sys->i_time = -1;
426         for( i = 0; i < 128 ; i++ )
427         {
428 #define p_stream p_sys->stream[i]
429             if( p_stream )
430             {
431                 p_stream->i_time = -1;
432             }
433 #undef p_stream
434         }
435     }
436
437     /* Check if we need to send the audio data to decoder */
438     b_play_audio = !p_input->stream.control.b_mute;
439
440     for( ;; )
441     {
442         mtime_t i_length;
443         mtime_t i_time_begin = GetMoviePTS( p_sys );
444         int i_result;
445
446         if( p_input->b_die )
447         {
448             break;
449         }
450
451         if( ( i_result = DemuxPacket( p_input, b_play_audio ) ) <= 0 )
452         {
453             return i_result;
454         }
455         if( i_time_begin == -1 )
456         {
457             i_time_begin = GetMoviePTS( p_sys );
458         }
459         else
460         {
461             i_length = GetMoviePTS( p_sys ) - i_time_begin;
462             if( i_length < 0 || i_length >= 40 * 1000 )
463             {
464                 break;
465             }
466         }
467     }
468
469     p_sys->i_time = GetMoviePTS( p_sys );
470     if( p_sys->i_time >= 0 )
471     {
472         input_ClockManageRef( p_input,
473                               p_input->stream.p_selected_program,
474                               p_sys->i_time * 9 / 100 );
475     }
476
477     return( 1 );
478 }
479
480 /*****************************************************************************
481  * Close: frees unused data
482  *****************************************************************************/
483 static void Close( vlc_object_t * p_this )
484 {
485     input_thread_t *p_input = (input_thread_t *)p_this;
486     demux_sys_t    *p_sys = p_input->p_demux_data;
487     int i_stream;
488
489     msg_Dbg( p_input, "Freeing all memory" );
490
491     ASF_FreeObjectRoot( p_input->s, p_sys->p_root );
492     for( i_stream = 0; i_stream < 128; i_stream++ )
493     {
494         asf_stream_t *p_stream = p_sys->stream[i_stream];
495
496         if( p_stream )
497         {
498             if( p_stream->p_frame )
499             {
500                 block_ChainRelease( p_stream->p_frame );
501             }
502             free( p_stream );
503         }
504     }
505     free( p_sys );
506 }
507
508
509 /*****************************************************************************
510  *
511  *****************************************************************************/
512 static mtime_t GetMoviePTS( demux_sys_t *p_sys )
513 {
514     mtime_t i_time;
515     int     i_stream;
516
517     i_time = -1;
518     for( i_stream = 0; i_stream < 128 ; i_stream++ )
519     {
520         asf_stream_t *p_stream = p_sys->stream[i_stream];
521
522         if( p_stream && p_stream->p_es && p_stream->i_time > 0)
523         {
524             if( i_time < 0 )
525             {
526                 i_time = p_stream->i_time;
527             }
528             else
529             {
530                 i_time = __MIN( i_time, p_stream->i_time );
531             }
532         }
533     }
534
535     return( i_time );
536 }
537
538 #define GETVALUE2b( bits, var, def ) \
539     switch( (bits)&0x03 ) \
540     { \
541         case 1: var = p_peek[i_skip]; i_skip++; break; \
542         case 2: var = GetWLE( p_peek + i_skip );  i_skip+= 2; break; \
543         case 3: var = GetDWLE( p_peek + i_skip ); i_skip+= 4; break; \
544         case 0: \
545         default: var = def; break;\
546     }
547
548 static int DemuxPacket( input_thread_t *p_input, vlc_bool_t b_play_audio )
549 {
550     demux_sys_t *p_sys = p_input->p_demux_data;
551     int     i_data_packet_min = p_sys->p_fp->i_min_data_packet_size;
552     uint8_t *p_peek;
553     int     i_skip;
554
555     int     i_packet_size_left;
556     int     i_packet_flags;
557     int     i_packet_property;
558
559     int     b_packet_multiple_payload;
560     int     i_packet_length;
561     int     i_packet_sequence;
562     int     i_packet_padding_length;
563
564     uint32_t    i_packet_send_time;
565     uint16_t    i_packet_duration;
566     int         i_payload;
567     int         i_payload_count;
568     int         i_payload_length_type;
569
570
571     if( stream_Peek( p_input->s, &p_peek,i_data_packet_min)<i_data_packet_min )
572     {
573         // EOF ?
574         msg_Warn( p_input, "cannot peek while getting new packet, EOF ?" );
575         return( 0 );
576     }
577     i_skip = 0;
578
579     /* *** parse error correction if present *** */
580     if( p_peek[0]&0x80 )
581     {
582         unsigned int i_error_correction_length_type;
583         unsigned int i_error_correction_data_length;
584         unsigned int i_opaque_data_present;
585
586         i_error_correction_data_length = p_peek[0] & 0x0f;  // 4bits
587         i_opaque_data_present = ( p_peek[0] >> 4 )& 0x01;    // 1bit
588         i_error_correction_length_type = ( p_peek[0] >> 5 ) & 0x03; // 2bits
589         i_skip += 1; // skip error correction flags
590
591         if( i_error_correction_length_type != 0x00 ||
592             i_opaque_data_present != 0 ||
593             i_error_correction_data_length != 0x02 )
594         {
595             goto loop_error_recovery;
596         }
597
598         i_skip += i_error_correction_data_length;
599     }
600     else
601     {
602         msg_Warn( p_input, "p_peek[0]&0x80 != 0x80" );
603     }
604
605     /* sanity check */
606     if( i_skip + 2 >= i_data_packet_min )
607     {
608         goto loop_error_recovery;
609     }
610
611     i_packet_flags = p_peek[i_skip]; i_skip++;
612     i_packet_property = p_peek[i_skip]; i_skip++;
613
614     b_packet_multiple_payload = i_packet_flags&0x01;
615
616     /* read some value */
617     GETVALUE2b( i_packet_flags >> 5, i_packet_length, i_data_packet_min );
618     GETVALUE2b( i_packet_flags >> 1, i_packet_sequence, 0 );
619     GETVALUE2b( i_packet_flags >> 3, i_packet_padding_length, 0 );
620
621     i_packet_send_time = GetDWLE( p_peek + i_skip ); i_skip += 4;
622     i_packet_duration  = GetWLE( p_peek + i_skip ); i_skip += 2;
623
624 //        i_packet_size_left = i_packet_length;   // XXX données reellement lu
625     /* FIXME I have to do that for some file, I don't known why */
626     i_packet_size_left = i_data_packet_min;
627
628     if( b_packet_multiple_payload )
629     {
630         i_payload_count = p_peek[i_skip] & 0x3f;
631         i_payload_length_type = ( p_peek[i_skip] >> 6 )&0x03;
632         i_skip++;
633     }
634     else
635     {
636         i_payload_count = 1;
637         i_payload_length_type = 0x02; // unused
638     }
639
640     for( i_payload = 0; i_payload < i_payload_count ; i_payload++ )
641     {
642         asf_stream_t   *p_stream;
643
644         int i_stream_number;
645         int i_media_object_number;
646         int i_media_object_offset;
647         int i_replicated_data_length;
648         int i_payload_data_length;
649         int i_payload_data_pos;
650         int i_sub_payload_data_length;
651         int i_tmp;
652
653         mtime_t i_pts;
654         mtime_t i_pts_delta;
655
656         if( i_skip >= i_packet_size_left )
657         {
658             /* prevent some segfault with invalid file */
659             break;
660         }
661
662         i_stream_number = p_peek[i_skip] & 0x7f;
663         i_skip++;
664
665         GETVALUE2b( i_packet_property >> 4, i_media_object_number, 0 );
666         GETVALUE2b( i_packet_property >> 2, i_tmp, 0 );
667         GETVALUE2b( i_packet_property, i_replicated_data_length, 0 );
668
669         if( i_replicated_data_length > 1 ) // should be at least 8 bytes
670         {
671             i_pts = (mtime_t)GetDWLE( p_peek + i_skip + 4 ) * 1000;
672             i_skip += i_replicated_data_length;
673             i_pts_delta = 0;
674
675             i_media_object_offset = i_tmp;
676
677             if( i_skip >= i_packet_size_left )
678             {
679                 break;
680             }
681         }
682         else if( i_replicated_data_length == 1 )
683         {
684
685             msg_Dbg( p_input, "found compressed payload" );
686
687             i_pts = (mtime_t)i_tmp * 1000;
688             i_pts_delta = (mtime_t)p_peek[i_skip] * 1000; i_skip++;
689
690             i_media_object_offset = 0;
691         }
692         else
693         {
694             i_pts = (mtime_t)i_packet_send_time * 1000;
695             i_pts_delta = 0;
696
697             i_media_object_offset = i_tmp;
698         }
699
700         i_pts = __MAX( i_pts - p_sys->p_fp->i_preroll * 1000, 0 );
701         if( b_packet_multiple_payload )
702         {
703             GETVALUE2b( i_payload_length_type, i_payload_data_length, 0 );
704         }
705         else
706         {
707             i_payload_data_length = i_packet_length -
708                                         i_packet_padding_length - i_skip;
709         }
710
711         if( i_payload_data_length < 0 || i_skip + i_payload_data_length > i_packet_size_left )
712         {
713             break;
714         }
715
716 #if 0
717          msg_Dbg( p_input,
718                   "payload(%d/%d) stream_number:%d media_object_number:%d media_object_offset:%d replicated_data_length:%d payload_data_length %d",
719                   i_payload + 1,
720                   i_payload_count,
721                   i_stream_number,
722                   i_media_object_number,
723                   i_media_object_offset,
724                   i_replicated_data_length,
725                   i_payload_data_length );
726 #endif
727
728         if( !( p_stream = p_sys->stream[i_stream_number] ) )
729         {
730             msg_Warn( p_input,
731                       "undeclared stream[Id 0x%x]", i_stream_number );
732             i_skip += i_payload_data_length;
733             continue;   // over payload
734         }
735
736         if( !p_stream->p_es )
737         {
738             i_skip += i_payload_data_length;
739             continue;
740         }
741
742
743         for( i_payload_data_pos = 0;
744              i_payload_data_pos < i_payload_data_length &&
745                     i_packet_size_left > 0;
746              i_payload_data_pos += i_sub_payload_data_length )
747         {
748             block_t *p_frag;
749             int i_read;
750
751             // read sub payload length
752             if( i_replicated_data_length == 1 )
753             {
754                 i_sub_payload_data_length = p_peek[i_skip]; i_skip++;
755                 i_payload_data_pos++;
756             }
757             else
758             {
759                 i_sub_payload_data_length = i_payload_data_length;
760             }
761
762             /* FIXME I don't use i_media_object_number, sould I ? */
763             if( p_stream->p_frame && i_media_object_offset == 0 )
764             {
765                 /* send complete packet to decoder */
766                 block_t *p_gather = block_ChainGather( p_stream->p_frame );
767
768                 es_out_Send( p_input->p_es_out, p_stream->p_es, p_gather );
769
770                 p_stream->p_frame = NULL;
771             }
772
773             i_read = i_sub_payload_data_length + i_skip;
774             if( ( p_frag = stream_Block( p_input->s, i_read ) ) == NULL )
775             {
776                 msg_Warn( p_input, "cannot read data" );
777                 return( 0 );
778             }
779             i_packet_size_left -= i_read;
780
781             p_frag->p_buffer += i_skip;
782             p_frag->i_buffer -= i_skip;
783
784             if( p_stream->p_frame == NULL )
785             {
786                 p_stream->i_time =
787                     ( (mtime_t)i_pts + i_payload * (mtime_t)i_pts_delta );
788
789                 p_frag->i_pts =
790                     input_ClockGetTS( p_input,
791                                       p_input->stream.p_selected_program,
792                                       p_stream->i_time * 9 /100 );
793
794                 if( p_stream->i_cat != VIDEO_ES )
795                     p_frag->i_dts = p_frag->i_pts;
796                 else
797                 {
798                     p_frag->i_dts = p_frag->i_pts;
799                     p_frag->i_pts = 0;
800                 }
801             }
802
803             block_ChainAppend( &p_stream->p_frame, p_frag );
804
805             i_skip = 0;
806             if( i_packet_size_left > 0 )
807             {
808                 if( stream_Peek( p_input->s, &p_peek, i_packet_size_left )
809                                                          < i_packet_size_left )
810                 {
811                     // EOF ?
812                     msg_Warn( p_input, "cannot peek, EOF ?" );
813                     return( 0 );
814                 }
815             }
816         }
817     }
818
819     if( i_packet_size_left > 0 )
820     {
821         if( stream_Read( p_input->s, NULL, i_packet_size_left )
822                                                          < i_packet_size_left )
823         {
824             msg_Warn( p_input, "cannot skip data, EOF ?" );
825             return( 0 );
826         }
827     }
828
829     return( 1 );
830
831 loop_error_recovery:
832     msg_Warn( p_input, "unsupported packet header" );
833     if( p_sys->p_fp->i_min_data_packet_size != p_sys->p_fp->i_max_data_packet_size )
834     {
835         msg_Err( p_input, "unsupported packet header, fatal error" );
836         return( -1 );
837     }
838     stream_Read( p_input->s, NULL, i_data_packet_min );
839
840     return( 1 );
841 }
842
843