1 /*****************************************************************************
3 *****************************************************************************
4 * Copyright © 2001-2004, 2011, 2014 VLC authors and VideoLAN
6 * Authors: Laurent Aimar <fenrir@via.ecp.fr>
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.
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.
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 *****************************************************************************/
26 #include "asfpacket.h"
33 typedef struct asf_packet_t
37 uint32_t padding_length
;
42 /* buffer handling for this ASF packet */
44 const uint8_t *p_peek
;
48 static inline int GetValue2b(uint32_t *var
, const uint8_t *p
, unsigned int *skip
, int left
, int bits
)
55 *var
= p
[*skip
]; *skip
+= 1;
60 *var
= GetWLE(&p
[*skip
]); *skip
+= 2;
65 *var
= GetDWLE(&p
[*skip
]); *skip
+= 4;
73 static uint32_t SkipBytes( stream_t
*s
, uint32_t i_bytes
)
75 ssize_t i_read
= vlc_stream_Read( s
, NULL
, i_bytes
);
76 return i_read
> 0 ? (uint32_t) i_read
: 0;
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
, vlc_tick_t i_pts
, vlc_tick_t i_dts
,
82 uint32_t i_media_object_offset
, bool b_keyframe
, bool b_ignore_pts
)
84 /* FIXME I don't use i_media_object_number, sould I ? */
85 if( *pp_frame
&& i_media_object_offset
== 0 )
87 p_packetsys
->pf_send( p_packetsys
, i_stream_number
, pp_frame
);
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" );
96 p_frag
->i_pts
= (b_ignore_pts
) ? VLC_TICK_INVALID
: VLC_TICK_0
+ i_pts
;
97 p_frag
->i_dts
= VLC_TICK_0
+ i_dts
;
99 p_frag
->i_flags
|= BLOCK_FLAG_TYPE_I
;
101 block_ChainAppend( pp_frame
, p_frag
);
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
,
111 demux_t
*p_demux
= p_packetsys
->p_demux
;
113 if ( !p_tkinfo
|| !p_tkinfo
->p_esp
|| !p_tkinfo
->p_esp
->p_ext
)
116 uint16_t i_payload_extensions_size
;
117 asf_payload_extension_system_t
*p_ext
= NULL
;
119 /* Extensions always come in the declared order */
120 for ( int i
=0; i
< p_tkinfo
->p_esp
->i_payload_extension_system_count
; i
++ )
122 p_ext
= &p_tkinfo
->p_esp
->p_ext
[i
];
123 if ( p_ext
->i_data_size
== 0xFFFF ) /* Variable length extension data */
125 if ( i_data
< 2 ) return;
126 i_payload_extensions_size
= GetWLE( p_data
);
129 i_payload_extensions_size
= 0;
133 i_payload_extensions_size
= p_ext
->i_data_size
;
136 if ( i_data
< i_payload_extensions_size
) return;
138 if ( guidcmp( &p_ext
->i_extension_id
, &mfasf_sampleextension_outputcleanpoint_guid
) )
140 if ( i_payload_extensions_size
!= sizeof(uint8_t) ) goto sizeerror
;
141 *b_keyframe
|= *p_data
;
143 else if ( guidcmp( &p_ext
->i_extension_id
, &asf_dvr_sampleextension_videoframe_guid
) )
145 if ( i_payload_extensions_size
!= sizeof(uint32_t) ) goto sizeerror
;
147 uint32_t i_val
= GetDWLE( p_data
);
148 /* Valid keyframe must be a split frame start fragment */
149 *b_keyframe
= i_val
& ASF_EXTENSION_VIDEOFRAME_NEWFRAME
;
152 /* And flagged as IFRAME */
153 *b_keyframe
|= ( ( i_val
& ASF_EXTENSION_VIDEOFRAME_TYPE_MASK
)
154 == ASF_EXTENSION_VIDEOFRAME_IFRAME
);
157 else if ( guidcmp( &p_ext
->i_extension_id
, &mfasf_sampleextension_pixelaspectratio_guid
) &&
158 p_packetsys
->pf_setaspectratio
)
160 if ( i_payload_extensions_size
!= sizeof(uint16_t) ) goto sizeerror
;
162 p_packetsys
->pf_setaspectratio( p_packetsys
, p_tkinfo
->p_sp
->i_stream_number
,
163 p_data
[0], p_data
[1] );
165 else if ( guidcmp( &p_ext
->i_extension_id
, &asf_dvr_sampleextension_timing_rep_data_guid
) )
167 if ( i_payload_extensions_size
!= 48 ) goto sizeerror
;
168 /* const int64_t i_pts = GetQWLE(&p_data[8]); */
173 msg_Dbg( p_demux
, "Unknown extension " GUID_FMT
, GUID_PRINT( p_ext
->i_extension_id
) );
176 i_data
-= i_payload_extensions_size
;
177 p_data
+= i_payload_extensions_size
;
183 msg_Warn( p_demux
, "Unknown extension " GUID_FMT
" data size of %u",
184 GUID_PRINT( p_ext
->i_extension_id
), i_payload_extensions_size
);
187 static int DemuxPayload(asf_packet_sys_t
*p_packetsys
, asf_packet_t
*pkt
, int i_payload
)
190 VLC_UNUSED( i_payload
);
192 demux_t
*p_demux
= p_packetsys
->p_demux
;
194 if( ! pkt
->left
|| pkt
->i_skip
>= pkt
->left
)
197 bool b_packet_keyframe
= pkt
->p_peek
[pkt
->i_skip
] >> 7;
198 uint8_t i_stream_number
= pkt
->p_peek
[pkt
->i_skip
++] & 0x7f;
200 uint32_t i_media_object_number
= 0;
201 if (GetValue2b(&i_media_object_number
, pkt
->p_peek
, &pkt
->i_skip
, pkt
->left
- pkt
->i_skip
, pkt
->property
>> 4) < 0)
203 uint32_t i_media_object_offset
= 0;
204 if (GetValue2b(&i_media_object_offset
, pkt
->p_peek
, &pkt
->i_skip
, pkt
->left
- pkt
->i_skip
, pkt
->property
>> 2) < 0)
206 uint32_t i_replicated_data_length
= 0;
207 if (GetValue2b(&i_replicated_data_length
, pkt
->p_peek
, &pkt
->i_skip
, pkt
->left
- pkt
->i_skip
, pkt
->property
) < 0)
210 vlc_tick_t i_pkt_time
;
211 vlc_tick_t i_pkt_time_delta
= 0;
212 uint32_t i_payload_data_length
= 0;
213 uint32_t i_temp_payload_length
= 0;
214 *p_packetsys
->pi_preroll
= __MIN( *p_packetsys
->pi_preroll
, INT64_MAX
);
216 /* First packet, in case we do not have index to guess preroll start time */
217 if ( *p_packetsys
->pi_preroll_start
== ASFPACKET_PREROLL_FROM_CURRENT
)
218 *p_packetsys
->pi_preroll_start
= pkt
->send_time
;
220 asf_track_info_t
*p_tkinfo
= p_packetsys
->pf_gettrackinfo( p_packetsys
, i_stream_number
);
224 bool b_ignore_pts
= (p_tkinfo
->i_cat
== VIDEO_ES
); /* ignore PTS delta with video when not set by mux */
226 if( pkt
->left
- pkt
->i_skip
< i_replicated_data_length
)
230 if( i_replicated_data_length
> 7 ) // should be at least 8 bytes
232 /* Followed by 2 optional DWORDS, offset in media and *media* presentation time */
233 i_pkt_time
= VLC_TICK_FROM_MS(GetDWLE( pkt
->p_peek
+ pkt
->i_skip
+ 4 ));
235 /* Parsing extensions, See 7.3.1 */
236 ParsePayloadExtensions( p_packetsys
, p_tkinfo
,
237 &pkt
->p_peek
[pkt
->i_skip
+ 8],
238 i_replicated_data_length
- 8,
239 &b_packet_keyframe
);
240 i_pkt_time
-= *p_packetsys
->pi_preroll
;
241 pkt
->i_skip
+= i_replicated_data_length
;
243 else if ( i_replicated_data_length
== 0 )
245 /* optional DWORDS missing */
246 i_pkt_time
= pkt
->send_time
;
248 /* Compressed payload */
249 else if( i_replicated_data_length
== 1 )
251 /* i_media_object_offset is *media* presentation time */
252 /* Next byte is *media* Presentation Time Delta */
253 i_pkt_time_delta
= VLC_TICK_FROM_MS(pkt
->p_peek
[pkt
->i_skip
]);
254 b_ignore_pts
= false;
255 i_pkt_time
= VLC_TICK_FROM_MS(i_media_object_offset
);
256 i_pkt_time
-= *p_packetsys
->pi_preroll
;
258 i_media_object_offset
= 0;
262 /* >1 && <8 Invalid replicated length ! */
263 msg_Warn( p_demux
, "Invalid replicated data length detected." );
264 if( pkt
->length
- pkt
->i_skip
< pkt
->padding_length
)
267 i_payload_data_length
= pkt
->length
- pkt
->padding_length
- pkt
->i_skip
;
271 if( ! pkt
->left
|| pkt
->i_skip
>= pkt
->left
)
274 bool b_preroll_done
= ( pkt
->send_time
> (*p_packetsys
->pi_preroll_start
+ *p_packetsys
->pi_preroll
) );
276 if (i_pkt_time
< 0) i_pkt_time
= 0; // FIXME?
278 if( pkt
->multiple
) {
279 if (GetValue2b(&i_temp_payload_length
, pkt
->p_peek
, &pkt
->i_skip
, pkt
->left
- pkt
->i_skip
, pkt
->length_type
) < 0)
284 if( pkt
->length
- pkt
->i_skip
< pkt
->padding_length
)
286 i_temp_payload_length
= pkt
->length
- pkt
->padding_length
- pkt
->i_skip
;
289 i_payload_data_length
= i_temp_payload_length
;
293 "payload(%d) stream_number:%"PRIu8
" media_object_number:%d media_object_offset:%"PRIu32
" replicated_data_length:%"PRIu32
" payload_data_length %"PRIu32
,
294 i_payload
+ 1, i_stream_number
, i_media_object_number
,
295 i_media_object_offset
, i_replicated_data_length
, i_payload_data_length
);
297 " pkttime=%"PRId64
" st=%"PRId64
,
298 i_pkt_time
, MS_FROM_VLC_TICK(pkt
->send_time
) );
301 if( ! i_payload_data_length
|| i_payload_data_length
> pkt
->left
)
303 msg_Dbg( p_demux
, " payload length problem %d %"PRIu32
" %"PRIu32
, pkt
->multiple
, i_payload_data_length
, pkt
->left
);
307 if ( p_packetsys
->pf_doskip
&&
308 p_packetsys
->pf_doskip( p_packetsys
, i_stream_number
, b_packet_keyframe
) )
311 if ( b_preroll_done
)
313 vlc_tick_t i_track_time
= i_pkt_time
;
315 if ( p_packetsys
->pf_updatetime
)
316 p_packetsys
->pf_updatetime( p_packetsys
, i_stream_number
, i_track_time
);
319 if( p_packetsys
->pf_updatesendtime
)
320 p_packetsys
->pf_updatesendtime( p_packetsys
, pkt
->send_time
);
322 uint32_t i_subpayload_count
= 0;
323 while (i_payload_data_length
&& pkt
->i_skip
< pkt
->left
)
325 uint32_t i_sub_payload_data_length
= i_payload_data_length
;
326 if( i_replicated_data_length
== 1 )
328 i_sub_payload_data_length
= pkt
->p_peek
[pkt
->i_skip
++];
329 i_payload_data_length
--;
330 if( i_sub_payload_data_length
> i_payload_data_length
)
334 SkipBytes( p_demux
->s
, pkt
->i_skip
);
336 vlc_tick_t i_payload_pts
;
337 i_payload_pts
= i_pkt_time
+ i_pkt_time_delta
* i_subpayload_count
;
338 if ( p_tkinfo
->p_sp
)
339 i_payload_pts
-= VLC_TICK_FROM_MSFTIME(p_tkinfo
->p_sp
->i_time_offset
);
341 vlc_tick_t i_payload_dts
= i_pkt_time
;
343 if ( p_tkinfo
->p_sp
)
344 i_payload_dts
-= VLC_TICK_FROM_MSFTIME(p_tkinfo
->p_sp
->i_time_offset
);
346 if ( i_sub_payload_data_length
&&
347 DemuxSubPayload( p_packetsys
, i_stream_number
, &p_tkinfo
->p_frame
,
348 i_sub_payload_data_length
, i_payload_pts
, i_payload_dts
,
349 i_media_object_offset
, b_packet_keyframe
, b_ignore_pts
) < 0)
352 if ( pkt
->left
> pkt
->i_skip
+ i_sub_payload_data_length
)
353 pkt
->left
-= pkt
->i_skip
+ i_sub_payload_data_length
;
359 ssize_t i_return
= vlc_stream_Peek( p_demux
->s
, &pkt
->p_peek
, pkt
->left
);
360 if ( i_return
<= 0 || (size_t) i_return
< pkt
->left
)
362 msg_Warn( p_demux
, "unexpected end of file" );
367 if ( i_sub_payload_data_length
<= i_payload_data_length
)
368 i_payload_data_length
-= i_sub_payload_data_length
;
370 i_payload_data_length
= 0;
372 i_subpayload_count
++;
378 pkt
->i_skip
+= i_payload_data_length
;
382 int DemuxASFPacket( asf_packet_sys_t
*p_packetsys
,
383 uint32_t i_data_packet_min
, uint32_t i_data_packet_max
,
384 uint64_t i_data_begin
, uint64_t i_data_end
)
386 demux_t
*p_demux
= p_packetsys
->p_demux
;
388 const uint64_t i_read_pos
= vlc_stream_Tell( p_demux
->s
);
389 if( i_read_pos
< i_data_begin
||
390 i_data_packet_min
> i_data_end
||
391 i_read_pos
> i_data_end
- i_data_packet_min
)
394 const uint8_t *p_peek
;
395 ssize_t i_return
= vlc_stream_Peek( p_demux
->s
, &p_peek
,i_data_packet_min
);
396 if( i_return
<= 0 || (size_t) i_return
< i_data_packet_min
)
398 msg_Warn( p_demux
, "unexpected end of file" );
401 unsigned int i_skip
= 0;
403 /* *** parse error correction if present *** */
406 unsigned int i_error_correction_data_length
= p_peek
[0] & 0x0f;
407 unsigned int i_opaque_data_present
= ( p_peek
[0] >> 4 )& 0x01;
408 unsigned int i_error_correction_length_type
= ( p_peek
[0] >> 5 ) & 0x03;
409 i_skip
+= 1; // skip error correction flags
411 if( i_error_correction_length_type
!= 0x00 ||
412 i_opaque_data_present
!= 0 ||
413 i_error_correction_data_length
!= 0x02 )
415 goto loop_error_recovery
;
418 i_skip
+= i_error_correction_data_length
;
421 msg_Warn( p_demux
, "no error correction" );
424 if( i_skip
+ 2 >= i_data_packet_min
)
425 goto loop_error_recovery
;
428 int i_packet_flags
= p_peek
[i_skip
]; i_skip
++;
429 pkt
.property
= p_peek
[i_skip
]; i_skip
++;
430 pkt
.multiple
= !!(i_packet_flags
&0x01);
432 pkt
.length
= i_data_packet_min
;
433 pkt
.padding_length
= 0;
435 if (GetValue2b(&pkt
.length
, p_peek
, &i_skip
, i_data_packet_min
- i_skip
, i_packet_flags
>> 5) < 0)
436 goto loop_error_recovery
;
437 uint32_t i_packet_sequence
;
438 if (GetValue2b(&i_packet_sequence
, p_peek
, &i_skip
, i_data_packet_min
- i_skip
, i_packet_flags
>> 1) < 0)
439 goto loop_error_recovery
;
440 if (GetValue2b(&pkt
.padding_length
, p_peek
, &i_skip
, i_data_packet_min
- i_skip
, i_packet_flags
>> 3) < 0)
441 goto loop_error_recovery
;
443 if( pkt
.padding_length
> pkt
.length
)
445 msg_Warn( p_demux
, "Too large padding: %"PRIu32
, pkt
.padding_length
);
446 goto loop_error_recovery
;
449 if( pkt
.length
< i_data_packet_min
)
451 /* if packet length too short, there is extra padding */
452 pkt
.padding_length
+= i_data_packet_min
- pkt
.length
;
453 pkt
.length
= i_data_packet_min
;
456 if( i_skip
+ 4 > i_data_packet_min
)
457 goto loop_error_recovery
;
459 pkt
.send_time
= VLC_TICK_FROM_MS(GetDWLE( p_peek
+ i_skip
)); i_skip
+= 4;
460 /* uint16_t i_packet_duration = GetWLE( p_peek + i_skip ); */ i_skip
+= 2;
462 if( pkt
.length
> i_data_end
||
463 i_read_pos
> i_data_end
- pkt
.length
)
465 msg_Warn( p_demux
, "pkt size %"PRIu32
" at %"PRIu64
" does not fit data chunk",
466 pkt
.length
, i_read_pos
);
470 i_return
= vlc_stream_Peek( p_demux
->s
, &p_peek
, pkt
.length
);
471 if( i_return
<= 0 || pkt
.length
== 0 || (size_t)i_return
< pkt
.length
)
473 msg_Warn( p_demux
, "unexpected end of file" );
477 int i_payload_count
= 1;
478 pkt
.length_type
= 0x02; //unused
481 if( i_skip
+ 1 >= i_data_packet_min
)
482 goto loop_error_recovery
;
483 i_payload_count
= p_peek
[i_skip
] & 0x3f;
484 pkt
.length_type
= ( p_peek
[i_skip
] >> 6 )&0x03;
489 msg_Dbg(p_demux
, "%d payloads", i_payload_count
);
494 pkt
.left
= pkt
.length
;
496 for( int i_payload
= 0; i_payload
< i_payload_count
; i_payload
++ )
497 if (DemuxPayload(p_packetsys
, &pkt
, i_payload
) < 0)
499 msg_Warn( p_demux
, "payload err %d / %d", i_payload
+ 1, i_payload_count
);
506 if( pkt
.left
> pkt
.padding_length
)
507 msg_Warn( p_demux
, "Didn't read %"PRIu32
" bytes in the packet",
508 pkt
.left
- pkt
.padding_length
);
509 else if( pkt
.left
< pkt
.padding_length
)
510 msg_Warn( p_demux
, "Read %"PRIu32
" too much bytes in the packet",
511 pkt
.padding_length
- pkt
.left
);
513 i_return
= vlc_stream_Read( p_demux
->s
, NULL
, pkt
.left
);
514 if( i_return
< 0 || (size_t) i_return
< pkt
.left
)
516 msg_Err( p_demux
, "cannot skip data, EOF ?" );
524 msg_Warn( p_demux
, "unsupported packet header" );
525 if( i_data_packet_min
!= i_data_packet_max
)
527 msg_Err( p_demux
, "unsupported packet header, fatal error" );
530 i_return
= vlc_stream_Read( p_demux
->s
, NULL
, i_data_packet_min
);
531 if( i_return
<= 0 || (size_t) i_return
!= i_data_packet_min
)
533 msg_Warn( p_demux
, "cannot skip data, EOF ?" );