1 /*****************************************************************************
2  * asfpacket.c :
3  *****************************************************************************
4  * Copyright © 2001-2004, 2011, 2014 VLC authors and VideoLAN
5  *
6  * Authors: Laurent Aimar <fenrir@via.ecp.fr>
7  *
8  * This program is free software; you can redistribute it and/or modify it
9  * under the terms of the GNU Lesser General Public License as published by
10  * the Free Software Foundation; either version 2.1 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public License
19  * along with this program; if not, write to the Free Software Foundation,
20  * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
21  *****************************************************************************/
22 #ifdef HAVE_CONFIG_H
23 # include "config.h"
24 #endif
25 
26 #include "asfpacket.h"
27 #include <limits.h>
28 
29 #ifndef NDEBUG
30 # define ASF_DEBUG 1
31 #endif
32 
33 typedef struct asf_packet_t
34 {
35     uint32_t property;
36     uint32_t length;
37     uint32_t padding_length;
38     uint32_t send_time;
39     bool multiple;
40     int length_type;
41 
42     /* buffer handling for this ASF packet */
43     uint32_t i_skip;
44     const uint8_t *p_peek;
45     uint32_t left;
46 } asf_packet_t;
47 
GetValue2b(uint32_t * var,const uint8_t * p,unsigned int * skip,int left,int bits)48 static inline int GetValue2b(uint32_t *var, const uint8_t *p, unsigned int *skip, int left, int bits)
49 {
50     switch(bits&0x03)
51     {
52     case 1:
53         if (left < 1)
54             return -1;
55         *var = p[*skip]; *skip += 1;
56         return 0;
57     case 2:
58         if (left < 2)
59             return -1;
60         *var = GetWLE(&p[*skip]); *skip += 2;
61         return 0;
62     case 3:
63         if (left < 4)
64             return -1;
65         *var = GetDWLE(&p[*skip]); *skip += 4;
66         return 0;
67     case 0:
68     default:
69         return 0;
70     }
71 }
72 
SkipBytes(stream_t * s,uint32_t i_bytes)73 static uint32_t SkipBytes( stream_t *s, uint32_t i_bytes )
74 {
75     ssize_t i_read = vlc_stream_Read( s, NULL, i_bytes );
76     return i_read > 0 ? (uint32_t) i_read : 0;
77 }
78 
DemuxSubPayload(asf_packet_sys_t * p_packetsys,uint8_t i_stream_number,block_t ** pp_frame,uint32_t i_sub_payload_data_length,mtime_t i_pts,mtime_t i_dts,uint32_t i_media_object_offset,bool b_keyframe,bool b_ignore_pts)79 static int DemuxSubPayload( asf_packet_sys_t *p_packetsys,
80                             uint8_t i_stream_number, block_t **pp_frame,
81                             uint32_t i_sub_payload_data_length, mtime_t i_pts, mtime_t i_dts,
82                             uint32_t i_media_object_offset, bool b_keyframe, bool b_ignore_pts )
83 {
84     /* FIXME I don't use i_media_object_number, sould I ? */
85     if( *pp_frame && i_media_object_offset == 0 )
86     {
87         p_packetsys->pf_send( p_packetsys, i_stream_number, pp_frame );
88     }
89 
90     block_t *p_frag = vlc_stream_Block( p_packetsys->p_demux->s, i_sub_payload_data_length );
91     if( p_frag == NULL ) {
92         msg_Warn( p_packetsys->p_demux, "cannot read data" );
93         return -1;
94     }
95 
96     p_frag->i_pts = (b_ignore_pts) ? VLC_TS_INVALID : VLC_TS_0 + i_pts;
97     p_frag->i_dts = VLC_TS_0 + i_dts;
98     if ( b_keyframe )
99         p_frag->i_flags |= BLOCK_FLAG_TYPE_I;
100 
101     block_ChainAppend( pp_frame, p_frag );
102 
103     return 0;
104 }
105 
ParsePayloadExtensions(asf_packet_sys_t * p_packetsys,const asf_track_info_t * p_tkinfo,const uint8_t * p_data,size_t i_data,bool * b_keyframe,int64_t * pi_extension_pts)106 static void ParsePayloadExtensions( asf_packet_sys_t *p_packetsys,
107                                     const asf_track_info_t *p_tkinfo,
108                                     const uint8_t *p_data, size_t i_data,
109                                     bool *b_keyframe,
110                                     int64_t *pi_extension_pts )
111 {
112     demux_t *p_demux = p_packetsys->p_demux;
113 
114     if ( !p_tkinfo || !p_tkinfo->p_esp || !p_tkinfo->p_esp->p_ext )
115         return;
116 
117     uint16_t i_payload_extensions_size;
118     asf_payload_extension_system_t *p_ext = NULL;
119 
120     /* Extensions always come in the declared order */
121     for ( int i=0; i< p_tkinfo->p_esp->i_payload_extension_system_count; i++ )
122     {
123         p_ext = &p_tkinfo->p_esp->p_ext[i];
124         if ( p_ext->i_data_size == 0xFFFF ) /* Variable length extension data */
125         {
126             if ( i_data < 2 ) return;
127             i_payload_extensions_size = GetWLE( p_data );
128             p_data += 2;
129             i_data -= 2;
130             i_payload_extensions_size = 0;
131         }
132         else
133         {
134             i_payload_extensions_size = p_ext->i_data_size;
135         }
136 
137         if ( i_data < i_payload_extensions_size ) return;
138 
139         if ( guidcmp( &p_ext->i_extension_id, &mfasf_sampleextension_outputcleanpoint_guid ) )
140         {
141             if ( i_payload_extensions_size != sizeof(uint8_t) ) goto sizeerror;
142             *b_keyframe |= *p_data;
143         }
144         else if ( guidcmp( &p_ext->i_extension_id, &asf_dvr_sampleextension_videoframe_guid ) )
145         {
146             if ( i_payload_extensions_size != sizeof(uint32_t) ) goto sizeerror;
147 
148             uint32_t i_val = GetDWLE( p_data );
149             /* Valid keyframe must be a split frame start fragment */
150             *b_keyframe = i_val & ASF_EXTENSION_VIDEOFRAME_NEWFRAME;
151             if ( *b_keyframe )
152             {
153                 /* And flagged as IFRAME */
154                 *b_keyframe |= ( ( i_val & ASF_EXTENSION_VIDEOFRAME_TYPE_MASK )
155                                  == ASF_EXTENSION_VIDEOFRAME_IFRAME );
156             }
157         }
158         else if ( guidcmp( &p_ext->i_extension_id, &mfasf_sampleextension_pixelaspectratio_guid ) &&
159                   p_packetsys->pf_setaspectratio )
160         {
161             if ( i_payload_extensions_size != sizeof(uint16_t) ) goto sizeerror;
162 
163             p_packetsys->pf_setaspectratio( p_packetsys, p_tkinfo->p_sp->i_stream_number,
164                                             p_data[0], p_data[1] );
165         }
166         else if ( guidcmp( &p_ext->i_extension_id, &asf_dvr_sampleextension_timing_rep_data_guid ) )
167         {
168             if ( i_payload_extensions_size != 48 ) goto sizeerror;
169             const int64_t i_pts = GetQWLE(&p_data[8]);
170             if(i_pts != -1)
171                 *pi_extension_pts = i_pts / 10000;
172         }
173 #if 0
174         else
175         {
176             msg_Dbg( p_demux, "Unknown extension " GUID_FMT, GUID_PRINT( p_ext->i_extension_id ) );
177         }
178 #endif
179         i_data -= i_payload_extensions_size;
180         p_data += i_payload_extensions_size;
181     }
182 
183     return;
184 
185 sizeerror:
186     msg_Warn( p_demux, "Unknown extension " GUID_FMT " data size of %u",
187               GUID_PRINT( p_ext->i_extension_id ), i_payload_extensions_size );
188 }
189 
DemuxPayload(asf_packet_sys_t * p_packetsys,asf_packet_t * pkt,int i_payload)190 static int DemuxPayload(asf_packet_sys_t *p_packetsys, asf_packet_t *pkt, int i_payload)
191 {
192 #ifndef ASF_DEBUG
193     VLC_UNUSED( i_payload );
194 #endif
195     demux_t *p_demux = p_packetsys->p_demux;
196 
197     if( ! pkt->left || pkt->i_skip >= pkt->left )
198         return -1;
199 
200     bool b_packet_keyframe = pkt->p_peek[pkt->i_skip] >> 7;
201     uint8_t i_stream_number = pkt->p_peek[pkt->i_skip++] & 0x7f;
202 
203     uint32_t i_media_object_number = 0;
204     if (GetValue2b(&i_media_object_number, pkt->p_peek, &pkt->i_skip, pkt->left - pkt->i_skip, pkt->property >> 4) < 0)
205         return -1;
206     uint32_t i_media_object_offset = 0;
207     if (GetValue2b(&i_media_object_offset, pkt->p_peek, &pkt->i_skip, pkt->left - pkt->i_skip, pkt->property >> 2) < 0)
208         return -1;
209     uint32_t i_replicated_data_length = 0;
210     if (GetValue2b(&i_replicated_data_length, pkt->p_peek, &pkt->i_skip, pkt->left - pkt->i_skip, pkt->property) < 0)
211         return -1;
212 
213     int64_t i_pkt_time;
214     uint8_t i_pkt_time_delta = 0;
215     int64_t i_extension_pts = -1;
216     uint32_t i_payload_data_length = 0;
217     uint32_t i_temp_payload_length = 0;
218     *p_packetsys->pi_preroll = __MIN( *p_packetsys->pi_preroll, INT64_MAX );
219 
220     /* First packet, in case we do not have index to guess preroll start time */
221     if ( *p_packetsys->pi_preroll_start == ASFPACKET_PREROLL_FROM_CURRENT )
222         *p_packetsys->pi_preroll_start = pkt->send_time * 1000;
223 
224     asf_track_info_t *p_tkinfo = p_packetsys->pf_gettrackinfo( p_packetsys, i_stream_number );
225     if ( !p_tkinfo )
226         goto skip;
227 
228     bool b_ignore_pts = (p_tkinfo->i_cat == VIDEO_ES); /* ignore PTS delta with video when not set by mux */
229 
230     if( pkt->left - pkt->i_skip < i_replicated_data_length )
231         return -1;
232 
233     /* Non compressed */
234     if( i_replicated_data_length > 7 ) // should be at least 8 bytes
235     {
236         /* Followed by 2 optional DWORDS, offset in media and *media* presentation time */
237         i_pkt_time = (mtime_t)GetDWLE( pkt->p_peek + pkt->i_skip + 4 );
238 
239         /* Parsing extensions, See 7.3.1 */
240         ParsePayloadExtensions( p_packetsys, p_tkinfo,
241                                 &pkt->p_peek[pkt->i_skip + 8],
242                                 i_replicated_data_length - 8,
243                                 &b_packet_keyframe,
244                                 &i_extension_pts );
245         i_pkt_time -= *p_packetsys->pi_preroll;
246         if(i_extension_pts != -1)
247             i_extension_pts -= *p_packetsys->pi_preroll;
248         pkt->i_skip += i_replicated_data_length;
249     }
250     else if ( i_replicated_data_length == 0 )
251     {
252         /* optional DWORDS missing */
253         i_pkt_time = (mtime_t)pkt->send_time;
254     }
255     /* Compressed payload */
256     else if( i_replicated_data_length == 1 )
257     {
258         /* i_media_object_offset is *media* presentation time */
259         /* Next byte is *media* Presentation Time Delta */
260         i_pkt_time_delta = pkt->p_peek[pkt->i_skip];
261         b_ignore_pts = false;
262         i_pkt_time = (mtime_t)i_media_object_offset;
263         i_pkt_time -= *p_packetsys->pi_preroll;
264         pkt->i_skip++;
265         i_media_object_offset = 0;
266     }
267     else
268     {
269         /* >1 && <8 Invalid replicated length ! */
270         msg_Warn( p_demux, "Invalid replicated data length detected." );
271         if( pkt->length - pkt->i_skip < pkt->padding_length )
272             return -1;
273 
274         i_payload_data_length = pkt->length - pkt->padding_length - pkt->i_skip;
275         goto skip;
276     }
277 
278     if( ! pkt->left || pkt->i_skip >= pkt->left )
279         return -1;
280 
281     bool b_preroll_done = ( pkt->send_time > (*p_packetsys->pi_preroll_start/1000 + *p_packetsys->pi_preroll) );
282 
283     if (i_pkt_time < 0) i_pkt_time = 0; // FIXME?
284     i_pkt_time *= 1000;
285 
286     if( pkt->multiple ) {
287         if (GetValue2b(&i_temp_payload_length, pkt->p_peek, &pkt->i_skip, pkt->left - pkt->i_skip, pkt->length_type) < 0)
288             return -1;
289     }
290     else
291     {
292         if( pkt->length - pkt->i_skip < pkt->padding_length )
293             return -1;
294         i_temp_payload_length = pkt->length - pkt->padding_length - pkt->i_skip;
295     }
296 
297     i_payload_data_length = i_temp_payload_length;
298 
299 #ifdef ASF_DEBUG
300      msg_Dbg( p_demux,
301               "payload(%d) stream_number:%"PRIu8" media_object_number:%d media_object_offset:%"PRIu32" replicated_data_length:%"PRIu32" payload_data_length %"PRIu32,
302               i_payload + 1, i_stream_number, i_media_object_number,
303               i_media_object_offset, i_replicated_data_length, i_payload_data_length );
304      msg_Dbg( p_demux,
305               "  extpts=%"PRId64" pkttime=%"PRId64" st=%"PRIu32,
306               (i_extension_pts >= 0) ? i_extension_pts * 1000 : -1, i_pkt_time, pkt->send_time );
307 #endif
308 
309      if( ! i_payload_data_length || i_payload_data_length > pkt->left )
310      {
311          msg_Dbg( p_demux, "  payload length problem %d %"PRIu32" %"PRIu32, pkt->multiple, i_payload_data_length, pkt->left );
312          return -1;
313      }
314 
315     if ( p_packetsys->pf_doskip &&
316          p_packetsys->pf_doskip( p_packetsys, i_stream_number, b_packet_keyframe ) )
317         goto skip;
318 
319     if ( b_preroll_done )
320     {
321         mtime_t i_track_time = i_pkt_time;
322 
323         if ( p_packetsys->pf_updatetime )
324             p_packetsys->pf_updatetime( p_packetsys, i_stream_number, i_track_time );
325     }
326 
327     if( p_packetsys->pf_updatesendtime )
328         p_packetsys->pf_updatesendtime( p_packetsys, INT64_C(1000) * pkt->send_time );
329 
330     uint32_t i_subpayload_count = 0;
331     while (i_payload_data_length && pkt->i_skip < pkt->left )
332     {
333         uint32_t i_sub_payload_data_length = i_payload_data_length;
334         if( i_replicated_data_length == 1 )
335         {
336             i_sub_payload_data_length = pkt->p_peek[pkt->i_skip++];
337             i_payload_data_length--;
338             if( i_sub_payload_data_length > i_payload_data_length )
339                 goto skip;
340         }
341 
342         SkipBytes( p_demux->s, pkt->i_skip );
343 
344         mtime_t i_payload_pts;
345 #if 0
346         if( i_extension_pts != -1 )
347         {
348             i_payload_pts = i_extension_pts * 1000;
349             b_ignore_pts = false;
350         }
351         else
352 #endif
353         {
354             i_payload_pts = i_pkt_time + (mtime_t)i_pkt_time_delta * i_subpayload_count * 1000;
355             if ( p_tkinfo->p_sp )
356                 i_payload_pts -= p_tkinfo->p_sp->i_time_offset * 10;
357         }
358 
359         mtime_t i_payload_dts = i_pkt_time;
360 
361         if ( p_tkinfo->p_sp )
362             i_payload_dts -= p_tkinfo->p_sp->i_time_offset * 10;
363 
364         if ( i_sub_payload_data_length &&
365              DemuxSubPayload( p_packetsys, i_stream_number, &p_tkinfo->p_frame,
366                               i_sub_payload_data_length, i_payload_pts, i_payload_dts,
367                               i_media_object_offset, b_packet_keyframe, b_ignore_pts ) < 0)
368             return -1;
369 
370         if ( pkt->left > pkt->i_skip + i_sub_payload_data_length )
371             pkt->left -= pkt->i_skip + i_sub_payload_data_length;
372         else
373             pkt->left = 0;
374         pkt->i_skip = 0;
375         if( pkt->left > 0 )
376         {
377             ssize_t i_return = vlc_stream_Peek( p_demux->s, &pkt->p_peek, pkt->left );
378             if ( i_return <= 0 || (size_t) i_return < pkt->left )
379             {
380             msg_Warn( p_demux, "cannot peek, EOF ?" );
381             return -1;
382             }
383         }
384 
385         if ( i_sub_payload_data_length <= i_payload_data_length )
386             i_payload_data_length -= i_sub_payload_data_length;
387         else
388             i_payload_data_length = 0;
389 
390         i_subpayload_count++;
391     }
392 
393     return 0;
394 
395 skip:
396     pkt->i_skip += i_payload_data_length;
397     return 0;
398 }
399 
DemuxASFPacket(asf_packet_sys_t * p_packetsys,uint32_t i_data_packet_min,uint32_t i_data_packet_max,uint64_t i_data_begin,uint64_t i_data_end)400 int DemuxASFPacket( asf_packet_sys_t *p_packetsys,
401                     uint32_t i_data_packet_min, uint32_t i_data_packet_max,
402                     uint64_t i_data_begin, uint64_t i_data_end )
403 {
404     demux_t *p_demux = p_packetsys->p_demux;
405 
406     const uint64_t i_read_pos = vlc_stream_Tell( p_demux->s );
407     if( i_read_pos < i_data_begin ||
408         (i_data_end && ( i_data_packet_min > i_data_end ||
409                          i_read_pos > i_data_end - i_data_packet_min ) ) )
410         return 0;
411 
412     const uint8_t *p_peek;
413     ssize_t i_return = vlc_stream_Peek( p_demux->s, &p_peek,i_data_packet_min );
414     if( i_return <= 0 || (size_t) i_return < i_data_packet_min )
415     {
416         msg_Warn( p_demux, "cannot peek while getting new packet, EOF ?" );
417         return 0;
418     }
419     unsigned int i_skip = 0;
420 
421     /* *** parse error correction if present *** */
422     if( p_peek[0]&0x80 )
423     {
424         unsigned int i_error_correction_data_length = p_peek[0] & 0x0f;
425         unsigned int i_opaque_data_present = ( p_peek[0] >> 4 )& 0x01;
426         unsigned int i_error_correction_length_type = ( p_peek[0] >> 5 ) & 0x03;
427         i_skip += 1; // skip error correction flags
428 
429         if( i_error_correction_length_type != 0x00 ||
430             i_opaque_data_present != 0 ||
431             i_error_correction_data_length != 0x02 )
432         {
433             goto loop_error_recovery;
434         }
435 
436         i_skip += i_error_correction_data_length;
437     }
438     else
439         msg_Warn( p_demux, "no error correction" );
440 
441     /* sanity check */
442     if( i_skip + 2 >= i_data_packet_min )
443         goto loop_error_recovery;
444 
445     asf_packet_t pkt;
446     int i_packet_flags = p_peek[i_skip]; i_skip++;
447     pkt.property = p_peek[i_skip]; i_skip++;
448     pkt.multiple = !!(i_packet_flags&0x01);
449 
450     pkt.length = i_data_packet_min;
451     pkt.padding_length = 0;
452 
453     if (GetValue2b(&pkt.length, p_peek, &i_skip, i_data_packet_min - i_skip, i_packet_flags >> 5) < 0)
454         goto loop_error_recovery;
455     uint32_t i_packet_sequence;
456     if (GetValue2b(&i_packet_sequence, p_peek, &i_skip, i_data_packet_min - i_skip, i_packet_flags >> 1) < 0)
457         goto loop_error_recovery;
458     if (GetValue2b(&pkt.padding_length, p_peek, &i_skip, i_data_packet_min - i_skip, i_packet_flags >> 3) < 0)
459         goto loop_error_recovery;
460 
461     if( pkt.padding_length > pkt.length )
462     {
463         msg_Warn( p_demux, "Too large padding: %"PRIu32, pkt.padding_length );
464         goto loop_error_recovery;
465     }
466 
467     if( pkt.length < i_data_packet_min )
468     {
469         /* if packet length too short, there is extra padding */
470         pkt.padding_length += i_data_packet_min - pkt.length;
471         pkt.length = i_data_packet_min;
472     }
473 
474     if( i_skip + 4 > i_data_packet_min )
475         goto loop_error_recovery;
476 
477     pkt.send_time = GetDWLE( p_peek + i_skip ); i_skip += 4;
478     /* uint16_t i_packet_duration = GetWLE( p_peek + i_skip ); */ i_skip += 2;
479 
480     if( i_data_end &&
481         (pkt.length > i_data_end ||
482          i_read_pos > i_data_end - pkt.length) )
483     {
484         msg_Warn( p_demux, "pkt size %"PRIu32" at %"PRIu64" does not fit data chunk",
485                   pkt.length, i_read_pos );
486         return 0;
487     }
488 
489     i_return = vlc_stream_Peek( p_demux->s, &p_peek, pkt.length );
490     if( i_return <= 0 || pkt.length == 0 || (size_t)i_return < pkt.length )
491     {
492         msg_Warn( p_demux, "cannot peek, EOF ?" );
493         return 0;
494     }
495 
496     int i_payload_count = 1;
497     pkt.length_type = 0x02; //unused
498     if( pkt.multiple )
499     {
500         if( i_skip + 1 >= i_data_packet_min )
501             goto loop_error_recovery;
502         i_payload_count = p_peek[i_skip] & 0x3f;
503         pkt.length_type = ( p_peek[i_skip] >> 6 )&0x03;
504         i_skip++;
505     }
506 
507 #ifdef ASF_DEBUG
508     msg_Dbg(p_demux, "%d payloads", i_payload_count);
509 #endif
510 
511     pkt.i_skip = i_skip;
512     pkt.p_peek = p_peek;
513     pkt.left = pkt.length;
514 
515     for( int i_payload = 0; i_payload < i_payload_count ; i_payload++ )
516         if (DemuxPayload(p_packetsys, &pkt, i_payload) < 0)
517         {
518             msg_Warn( p_demux, "payload err %d / %d", i_payload + 1, i_payload_count );
519             return 0;
520         }
521 
522     if( pkt.left > 0 )
523     {
524 #ifdef ASF_DEBUG
525         if( pkt.left > pkt.padding_length )
526             msg_Warn( p_demux, "Didn't read %"PRIu32" bytes in the packet",
527                             pkt.left - pkt.padding_length );
528         else if( pkt.left < pkt.padding_length )
529             msg_Warn( p_demux, "Read %"PRIu32" too much bytes in the packet",
530                             pkt.padding_length - pkt.left );
531 #endif
532         i_return = vlc_stream_Read( p_demux->s, NULL, pkt.left );
533         if( i_return < 0 || (size_t) i_return < pkt.left )
534         {
535             msg_Err( p_demux, "cannot skip data, EOF ?" );
536             return 0;
537         }
538     }
539 
540     return 1;
541 
542 loop_error_recovery:
543     msg_Warn( p_demux, "unsupported packet header" );
544     if( i_data_packet_min != i_data_packet_max )
545     {
546         msg_Err( p_demux, "unsupported packet header, fatal error" );
547         return -1;
548     }
549     i_return = vlc_stream_Read( p_demux->s, NULL, i_data_packet_min );
550     if( i_return <= 0 || (size_t) i_return != i_data_packet_min )
551     {
552         msg_Warn( p_demux, "cannot skip data, EOF ?" );
553         return 0;
554     }
555 
556     return 1;
557 }
558