| 1 |
|
|---|
| 2 |
|
|---|
| 3 |
|
|---|
| 4 |
|
|---|
| 5 |
|
|---|
| 6 |
|
|---|
| 7 |
|
|---|
| 8 |
|
|---|
| 9 |
|
|---|
| 10 |
|
|---|
| 11 |
|
|---|
| 12 |
|
|---|
| 13 |
|
|---|
| 14 |
|
|---|
| 15 |
|
|---|
| 16 |
|
|---|
| 17 |
|
|---|
| 18 |
|
|---|
| 19 |
|
|---|
| 20 |
|
|---|
| 21 |
|
|---|
| 22 |
|
|---|
| 23 |
|
|---|
| 24 |
|
|---|
| 25 |
|
|---|
| 26 |
|
|---|
| 27 |
|
|---|
| 28 |
#ifdef HAVE_CONFIG_H |
|---|
| 29 |
# include "config.h" |
|---|
| 30 |
#endif |
|---|
| 31 |
|
|---|
| 32 |
#include <vlc_common.h> |
|---|
| 33 |
#include <vlc_plugin.h> |
|---|
| 34 |
#include <vlc_demux.h> |
|---|
| 35 |
#include <vlc_interface.h> |
|---|
| 36 |
|
|---|
| 37 |
#include <vlc_meta.h> |
|---|
| 38 |
#include <vlc_access.h> |
|---|
| 39 |
#include <vlc_codecs.h> |
|---|
| 40 |
#include "libasf.h" |
|---|
| 41 |
|
|---|
| 42 |
|
|---|
| 43 |
|
|---|
| 44 |
|
|---|
| 45 |
|
|---|
| 46 |
|
|---|
| 47 |
|
|---|
| 48 |
|
|---|
| 49 |
|
|---|
| 50 |
static int Open ( vlc_object_t * ); |
|---|
| 51 |
static void Close ( vlc_object_t * ); |
|---|
| 52 |
|
|---|
| 53 |
vlc_module_begin(); |
|---|
| 54 |
set_category( CAT_INPUT ); |
|---|
| 55 |
set_subcategory( SUBCAT_INPUT_DEMUX ); |
|---|
| 56 |
set_description( N_("ASF v1.0 demuxer") ); |
|---|
| 57 |
set_capability( "demux", 200 ); |
|---|
| 58 |
set_callbacks( Open, Close ); |
|---|
| 59 |
add_shortcut( "asf" ); |
|---|
| 60 |
vlc_module_end(); |
|---|
| 61 |
|
|---|
| 62 |
|
|---|
| 63 |
|
|---|
| 64 |
|
|---|
| 65 |
|
|---|
| 66 |
static int Demux ( demux_t * ); |
|---|
| 67 |
static int Control( demux_t *, int i_query, va_list args ); |
|---|
| 68 |
|
|---|
| 69 |
typedef struct |
|---|
| 70 |
{ |
|---|
| 71 |
int i_cat; |
|---|
| 72 |
|
|---|
| 73 |
es_out_id_t *p_es; |
|---|
| 74 |
|
|---|
| 75 |
asf_object_stream_properties_t *p_sp; |
|---|
| 76 |
|
|---|
| 77 |
mtime_t i_time; |
|---|
| 78 |
|
|---|
| 79 |
block_t *p_frame; |
|---|
| 80 |
|
|---|
| 81 |
} asf_track_t; |
|---|
| 82 |
|
|---|
| 83 |
struct demux_sys_t |
|---|
| 84 |
{ |
|---|
| 85 |
mtime_t i_time; |
|---|
| 86 |
mtime_t i_length; |
|---|
| 87 |
int64_t i_bitrate; |
|---|
| 88 |
|
|---|
| 89 |
asf_object_root_t *p_root; |
|---|
| 90 |
asf_object_file_properties_t *p_fp; |
|---|
| 91 |
|
|---|
| 92 |
unsigned int i_track; |
|---|
| 93 |
asf_track_t *track[128]; |
|---|
| 94 |
|
|---|
| 95 |
int64_t i_data_begin; |
|---|
| 96 |
int64_t i_data_end; |
|---|
| 97 |
|
|---|
| 98 |
bool b_index; |
|---|
| 99 |
vlc_meta_t *meta; |
|---|
| 100 |
}; |
|---|
| 101 |
|
|---|
| 102 |
static mtime_t GetMoviePTS( demux_sys_t * ); |
|---|
| 103 |
static int DemuxInit( demux_t * ); |
|---|
| 104 |
static void DemuxEnd( demux_t * ); |
|---|
| 105 |
static int DemuxPacket( demux_t * ); |
|---|
| 106 |
|
|---|
| 107 |
|
|---|
| 108 |
|
|---|
| 109 |
|
|---|
| 110 |
static int Open( vlc_object_t * p_this ) |
|---|
| 111 |
{ |
|---|
| 112 |
demux_t *p_demux = (demux_t *)p_this; |
|---|
| 113 |
demux_sys_t *p_sys; |
|---|
| 114 |
guid_t guid; |
|---|
| 115 |
const uint8_t *p_peek; |
|---|
| 116 |
|
|---|
| 117 |
|
|---|
| 118 |
if( stream_Peek( p_demux->s, &p_peek, 16 ) < 16 ) return VLC_EGENERIC; |
|---|
| 119 |
|
|---|
| 120 |
ASF_GetGUID( &guid, p_peek ); |
|---|
| 121 |
if( !ASF_CmpGUID( &guid, &asf_object_header_guid ) ) return VLC_EGENERIC; |
|---|
| 122 |
|
|---|
| 123 |
|
|---|
| 124 |
p_demux->pf_demux = Demux; |
|---|
| 125 |
p_demux->pf_control = Control; |
|---|
| 126 |
p_demux->p_sys = p_sys = malloc( sizeof( demux_sys_t ) ); |
|---|
| 127 |
memset( p_sys, 0, sizeof( demux_sys_t ) ); |
|---|
| 128 |
|
|---|
| 129 |
|
|---|
| 130 |
if( DemuxInit( p_demux ) ) |
|---|
| 131 |
{ |
|---|
| 132 |
free( p_sys ); |
|---|
| 133 |
return VLC_EGENERIC; |
|---|
| 134 |
} |
|---|
| 135 |
return VLC_SUCCESS; |
|---|
| 136 |
} |
|---|
| 137 |
|
|---|
| 138 |
|
|---|
| 139 |
|
|---|
| 140 |
|
|---|
| 141 |
|
|---|
| 142 |
static int Demux( demux_t *p_demux ) |
|---|
| 143 |
{ |
|---|
| 144 |
demux_sys_t *p_sys = p_demux->p_sys; |
|---|
| 145 |
|
|---|
| 146 |
for( ;; ) |
|---|
| 147 |
{ |
|---|
| 148 |
const uint8_t *p_peek; |
|---|
| 149 |
mtime_t i_length; |
|---|
| 150 |
mtime_t i_time_begin = GetMoviePTS( p_sys ); |
|---|
| 151 |
int i_result; |
|---|
| 152 |
|
|---|
| 153 |
if( !vlc_object_alive (p_demux) ) |
|---|
| 154 |
break; |
|---|
| 155 |
#if 0 |
|---|
| 156 |
|
|---|
| 157 |
if( p_sys->i_data_end >= 0 && |
|---|
| 158 |
stream_Tell( p_demux->s ) >= p_sys->i_data_end ) |
|---|
| 159 |
return 0; |
|---|
| 160 |
#endif |
|---|
| 161 |
|
|---|
| 162 |
|
|---|
| 163 |
if( stream_Peek( p_demux->s, &p_peek, 16 ) == 16 ) |
|---|
| 164 |
{ |
|---|
| 165 |
guid_t guid; |
|---|
| 166 |
|
|---|
| 167 |
ASF_GetGUID( &guid, p_peek ); |
|---|
| 168 |
if( ASF_CmpGUID( &guid, &asf_object_header_guid ) ) |
|---|
| 169 |
{ |
|---|
| 170 |
msg_Warn( p_demux, "found a new ASF header" ); |
|---|
| 171 |
|
|---|
| 172 |
DemuxEnd( p_demux ); |
|---|
| 173 |
|
|---|
| 174 |
|
|---|
| 175 |
if( DemuxInit( p_demux ) ) |
|---|
| 176 |
{ |
|---|
| 177 |
msg_Err( p_demux, "failed to load the new header" ); |
|---|
| 178 |
intf_UserFatal( p_demux, false, _("Could not demux ASF stream"), |
|---|
| 179 |
_("VLC failed to load the ASF header.") ); |
|---|
| 180 |
return 0; |
|---|
| 181 |
} |
|---|
| 182 |
continue; |
|---|
| 183 |
} |
|---|
| 184 |
} |
|---|
| 185 |
|
|---|
| 186 |
|
|---|
| 187 |
if( ( i_result = DemuxPacket( p_demux ) ) <= 0 ) |
|---|
| 188 |
{ |
|---|
| 189 |
return i_result; |
|---|
| 190 |
} |
|---|
| 191 |
if( i_time_begin == -1 ) |
|---|
| 192 |
{ |
|---|
| 193 |
i_time_begin = GetMoviePTS( p_sys ); |
|---|
| 194 |
} |
|---|
| 195 |
else |
|---|
| 196 |
{ |
|---|
| 197 |
i_length = GetMoviePTS( p_sys ) - i_time_begin; |
|---|
| 198 |
if( i_length < 0 || i_length >= 40 * 1000 ) break; |
|---|
| 199 |
} |
|---|
| 200 |
} |
|---|
| 201 |
|
|---|
| 202 |
|
|---|
| 203 |
p_sys->i_time = GetMoviePTS( p_sys ); |
|---|
| 204 |
if( p_sys->i_time >= 0 ) |
|---|
| 205 |
{ |
|---|
| 206 |
es_out_Control( p_demux->out, ES_OUT_SET_PCR, p_sys->i_time ); |
|---|
| 207 |
} |
|---|
| 208 |
|
|---|
| 209 |
return 1; |
|---|
| 210 |
} |
|---|
| 211 |
|
|---|
| 212 |
|
|---|
| 213 |
|
|---|
| 214 |
|
|---|
| 215 |
static void Close( vlc_object_t * p_this ) |
|---|
| 216 |
{ |
|---|
| 217 |
demux_t *p_demux = (demux_t *)p_this; |
|---|
| 218 |
|
|---|
| 219 |
DemuxEnd( p_demux ); |
|---|
| 220 |
|
|---|
| 221 |
free( p_demux->p_sys ); |
|---|
| 222 |
} |
|---|
| 223 |
|
|---|
| 224 |
|
|---|
| 225 |
|
|---|
| 226 |
|
|---|
| 227 |
static int SeekIndex( demux_t *p_demux, mtime_t i_date, float f_pos ) |
|---|
| 228 |
{ |
|---|
| 229 |
demux_sys_t *p_sys = p_demux->p_sys; |
|---|
| 230 |
asf_object_index_t *p_index; |
|---|
| 231 |
int64_t i_pos; |
|---|
| 232 |
|
|---|
| 233 |
msg_Dbg( p_demux, "seek with index: %i seconds, position %f", |
|---|
| 234 |
(int)(i_date/1000000), f_pos ); |
|---|
| 235 |
|
|---|
| 236 |
p_index = ASF_FindObject( p_sys->p_root, &asf_object_index_guid, 0 ); |
|---|
| 237 |
|
|---|
| 238 |
if( i_date < 0 ) i_date = p_sys->i_length * f_pos; |
|---|
| 239 |
|
|---|
| 240 |
i_pos = i_date * 10 / p_index->i_index_entry_time_interval; |
|---|
| 241 |
i_pos = p_index->index_entry[i_pos].i_packet_number * |
|---|
| 242 |
p_sys->p_fp->i_min_data_packet_size; |
|---|
| 243 |
|
|---|
| 244 |
return stream_Seek( p_demux->s, p_sys->i_data_begin + i_pos ); |
|---|
| 245 |
} |
|---|
| 246 |
|
|---|
| 247 |
|
|---|
| 248 |
|
|---|
| 249 |
|
|---|
| 250 |
static int Control( demux_t *p_demux, int i_query, va_list args ) |
|---|
| 251 |
{ |
|---|
| 252 |
demux_sys_t *p_sys = p_demux->p_sys; |
|---|
| 253 |
vlc_meta_t *p_meta; |
|---|
| 254 |
int64_t i64, *pi64; |
|---|
| 255 |
double f, *pf; |
|---|
| 256 |
int i; |
|---|
| 257 |
|
|---|
| 258 |
switch( i_query ) |
|---|
| 259 |
{ |
|---|
| 260 |
case DEMUX_GET_LENGTH: |
|---|
| 261 |
pi64 = (int64_t*)va_arg( args, int64_t * ); |
|---|
| 262 |
*pi64 = p_sys->i_length; |
|---|
| 263 |
return VLC_SUCCESS; |
|---|
| 264 |
|
|---|
| 265 |
case DEMUX_GET_TIME: |
|---|
| 266 |
pi64 = (int64_t*)va_arg( args, int64_t * ); |
|---|
| 267 |
if( p_sys->i_time < 0 ) return VLC_EGENERIC; |
|---|
| 268 |
*pi64 = p_sys->i_time; |
|---|
| 269 |
return VLC_SUCCESS; |
|---|
| 270 |
|
|---|
| 271 |
case DEMUX_SET_TIME: |
|---|
| 272 |
p_sys->i_time = -1; |
|---|
| 273 |
for( i = 0; i < 128 ; i++ ) |
|---|
| 274 |
if( p_sys->track[i] ) p_sys->track[i]->i_time = -1; |
|---|
| 275 |
|
|---|
| 276 |
if( p_sys->b_index && p_sys->i_length > 0 ) |
|---|
| 277 |
{ |
|---|
| 278 |
i64 = (int64_t)va_arg( args, int64_t ); |
|---|
| 279 |
return SeekIndex( p_demux, i64, -1 ); |
|---|
| 280 |
} |
|---|
| 281 |
else |
|---|
| 282 |
{ |
|---|
| 283 |
return demux_vaControlHelper( p_demux->s, p_sys->i_data_begin, |
|---|
| 284 |
p_sys->i_data_end, p_sys->i_bitrate, |
|---|
| 285 |
p_sys->p_fp->i_min_data_packet_size, |
|---|
| 286 |
i_query, args ); |
|---|
| 287 |
} |
|---|
| 288 |
|
|---|
| 289 |
case DEMUX_GET_POSITION: |
|---|
| 290 |
if( p_sys->i_time < 0 ) return VLC_EGENERIC; |
|---|
| 291 |
if( p_sys->i_length > 0 ) |
|---|
| 292 |
{ |
|---|
| 293 |
pf = (double*)va_arg( args, double * ); |
|---|
| 294 |
*pf = p_sys->i_time / (double)p_sys->i_length; |
|---|
| 295 |
return VLC_SUCCESS; |
|---|
| 296 |
} |
|---|
| 297 |
return demux_vaControlHelper( p_demux->s, p_sys->i_data_begin, |
|---|
| 298 |
p_sys->i_data_end, p_sys->i_bitrate, |
|---|
| 299 |
p_sys->p_fp->i_min_data_packet_size, |
|---|
| 300 |
i_query, args ); |
|---|
| 301 |
|
|---|
| 302 |
case DEMUX_SET_POSITION: |
|---|
| 303 |
p_sys->i_time = -1; |
|---|
| 304 |
for( i = 0; i < 128 ; i++ ) |
|---|
| 305 |
if( p_sys->track[i] ) p_sys->track[i]->i_time = -1; |
|---|
| 306 |
|
|---|
| 307 |
if( p_sys->b_index && p_sys->i_length > 0 ) |
|---|
| 308 |
{ |
|---|
| 309 |
f = (double)va_arg( args, double ); |
|---|
| 310 |
return SeekIndex( p_demux, -1, f ); |
|---|
| 311 |
} |
|---|
| 312 |
else |
|---|
| 313 |
{ |
|---|
| 314 |
return demux_vaControlHelper( p_demux->s, p_sys->i_data_begin, |
|---|
| 315 |
p_sys->i_data_end, p_sys->i_bitrate, |
|---|
| 316 |
p_sys->p_fp->i_min_data_packet_size, |
|---|
| 317 |
i_query, args ); |
|---|
| 318 |
} |
|---|
| 319 |
|
|---|
| 320 |
case DEMUX_GET_META: |
|---|
| 321 |
p_meta = (vlc_meta_t*)va_arg( args, vlc_meta_t* ); |
|---|
| 322 |
vlc_meta_Merge( p_meta, p_sys->meta ); |
|---|
| 323 |
return VLC_SUCCESS; |
|---|
| 324 |
|
|---|
| 325 |
default: |
|---|
| 326 |
return demux_vaControlHelper( p_demux->s, p_sys->i_data_begin, |
|---|
| 327 |
p_sys->i_data_end, p_sys->i_bitrate, |
|---|
| 328 |
p_sys->p_fp->i_min_data_packet_size, |
|---|
| 329 |
i_query, args ); |
|---|
| 330 |
} |
|---|
| 331 |
} |
|---|
| 332 |
|
|---|
| 333 |
|
|---|
| 334 |
|
|---|
| 335 |
|
|---|
| 336 |
static mtime_t GetMoviePTS( demux_sys_t *p_sys ) |
|---|
| 337 |
{ |
|---|
| 338 |
mtime_t i_time = -1; |
|---|
| 339 |
int i; |
|---|
| 340 |
|
|---|
| 341 |
for( i = 0; i < 128 ; i++ ) |
|---|
| 342 |
{ |
|---|
| 343 |
asf_track_t *tk = p_sys->track[i]; |
|---|
| 344 |
|
|---|
| 345 |
if( tk && tk->p_es && tk->i_time > 0) |
|---|
| 346 |
{ |
|---|
| 347 |
if( i_time < 0 ) i_time = tk->i_time; |
|---|
| 348 |
else i_time = __MIN( i_time, tk->i_time ); |
|---|
| 349 |
} |
|---|
| 350 |
} |
|---|
| 351 |
|
|---|
| 352 |
return i_time; |
|---|
| 353 |
} |
|---|
| 354 |
|
|---|
| 355 |
#define GETVALUE2b( bits, var, def ) \ |
|---|
| 356 |
switch( (bits)&0x03 ) \ |
|---|
| 357 |
{ \ |
|---|
| 358 |
case 1: var = p_peek[i_skip]; i_skip++; break; \ |
|---|
| 359 |
case 2: var = GetWLE( p_peek + i_skip ); i_skip+= 2; break; \ |
|---|
| 360 |
case 3: var = GetDWLE( p_peek + i_skip ); i_skip+= 4; break; \ |
|---|
| 361 |
case 0: \ |
|---|
| 362 |
default: var = def; break;\ |
|---|
| 363 |
} |
|---|
| 364 |
|
|---|
| 365 |
static int DemuxPacket( demux_t *p_demux ) |
|---|
| 366 |
{ |
|---|
| 367 |
demux_sys_t *p_sys = p_demux->p_sys; |
|---|
| 368 |
int i_data_packet_min = p_sys->p_fp->i_min_data_packet_size; |
|---|
| 369 |
const uint8_t *p_peek; |
|---|
| 370 |
int i_skip; |
|---|
| 371 |
|
|---|
| 372 |
int i_packet_size_left; |
|---|
| 373 |
int i_packet_flags; |
|---|
| 374 |
int i_packet_property; |
|---|
| 375 |
|
|---|
| 376 |
int b_packet_multiple_payload; |
|---|
| 377 |
int i_packet_length; |
|---|
| 378 |
int i_packet_sequence; |
|---|
| 379 |
int i_packet_padding_length; |
|---|
| 380 |
|
|---|
| 381 |
uint32_t i_packet_send_time; |
|---|
| 382 |
uint16_t i_packet_duration; |
|---|
| 383 |
int i_payload; |
|---|
| 384 |
int i_payload_count; |
|---|
| 385 |
int i_payload_length_type; |
|---|
| 386 |
|
|---|
| 387 |
|
|---|
| 388 |
if( stream_Peek( p_demux->s, &p_peek,i_data_packet_min)<i_data_packet_min ) |
|---|
| 389 |
{ |
|---|
| 390 |
msg_Warn( p_demux, "cannot peek while getting new packet, EOF ?" ); |
|---|
| 391 |
return 0; |
|---|
| 392 |
} |
|---|
| 393 |
i_skip = 0; |
|---|
| 394 |
|
|---|
| 395 |
|
|---|
| 396 |
if( p_peek[0]&0x80 ) |
|---|
| 397 |
{ |
|---|
| 398 |
unsigned int i_error_correction_length_type; |
|---|
| 399 |
unsigned int i_error_correction_data_length; |
|---|
| 400 |
unsigned int i_opaque_data_present; |
|---|
| 401 |
|
|---|
| 402 |
i_error_correction_data_length = p_peek[0] & 0x0f; |
|---|
| 403 |
i_opaque_data_present = ( p_peek[0] >> 4 )& 0x01; |
|---|
| 404 |
i_error_correction_length_type = ( p_peek[0] >> 5 ) & 0x03; |
|---|
| 405 |
i_skip += 1; |
|---|
| 406 |
|
|---|
| 407 |
if( i_error_correction_length_type != 0x00 || |
|---|
| 408 |
i_opaque_data_present != 0 || |
|---|
| 409 |
i_error_correction_data_length != 0x02 ) |
|---|
| 410 |
{ |
|---|
| 411 |
goto loop_error_recovery; |
|---|
| 412 |
} |
|---|
| 413 |
|
|---|
| 414 |
i_skip += i_error_correction_data_length; |
|---|
| 415 |
} |
|---|
| 416 |
else |
|---|
| 417 |
{ |
|---|
| 418 |
msg_Warn( p_demux, "p_peek[0]&0x80 != 0x80" ); |
|---|
| 419 |
} |
|---|
| 420 |
|
|---|
| 421 |
|
|---|
| 422 |
if( i_skip + 2 >= i_data_packet_min ) |
|---|
| 423 |
{ |
|---|
| 424 |
goto loop_error_recovery; |
|---|
| 425 |
} |
|---|
| 426 |
|
|---|
| 427 |
i_packet_flags = p_peek[i_skip]; i_skip++; |
|---|
| 428 |
i_packet_property = p_peek[i_skip]; i_skip++; |
|---|
| 429 |
|
|---|
| 430 |
b_packet_multiple_payload = i_packet_flags&0x01; |
|---|
| 431 |
|
|---|
| 432 |
|
|---|
| 433 |
GETVALUE2b( i_packet_flags >> 5, i_packet_length, i_data_packet_min ); |
|---|
| 434 |
GETVALUE2b( i_packet_flags >> 1, i_packet_sequence, 0 ); |
|---|
| 435 |
GETVALUE2b( i_packet_flags >> 3, i_packet_padding_length, 0 ); |
|---|
| 436 |
|
|---|
| 437 |
if( i_packet_padding_length > i_packet_length ) |
|---|
| 438 |
{ |
|---|
| 439 |
msg_Warn( p_demux, "Too large padding: %d", i_packet_padding_length ); |
|---|
| 440 |
goto loop_error_recovery; |
|---|
| 441 |
} |
|---|
| 442 |
|
|---|
| 443 |
i_packet_send_time = GetDWLE( p_peek + i_skip ); i_skip += 4; |
|---|
| 444 |
i_packet_duration = GetWLE( p_peek + i_skip ); i_skip += 2; |
|---|
| 445 |
|
|---|
| 446 |
|
|---|
| 447 |
i_packet_size_left = i_data_packet_min ; |
|---|
| 448 |
|
|---|
| 449 |
if( b_packet_multiple_payload ) |
|---|
| 450 |
{ |
|---|
| 451 |
i_payload_count = p_peek[i_skip] & 0x3f; |
|---|
| 452 |
i_payload_length_type = ( p_peek[i_skip] >> 6 )&0x03; |
|---|
| 453 |
i_skip++; |
|---|
| 454 |
} |
|---|
| 455 |
else |
|---|
| 456 |
{ |
|---|
| 457 |
i_payload_count = 1; |
|---|
| 458 |
i_payload_length_type = 0x02; |
|---|
| 459 |
} |
|---|
| 460 |
|
|---|
| 461 |
for( i_payload = 0; i_payload < i_payload_count ; i_payload++ ) |
|---|
| 462 |
{ |
|---|
| 463 |
asf_track_t *tk; |
|---|
| 464 |
|
|---|
| 465 |
int i_packet_keyframe; |
|---|
| 466 |
int i_stream_number; |
|---|
| 467 |
int i_media_object_number; |
|---|
| 468 |
int i_media_object_offset; |
|---|
| 469 |
int i_replicated_data_length; |
|---|
| 470 |
int i_payload_data_length; |
|---|
| 471 |
int i_payload_data_pos; |
|---|
| 472 |
int i_sub_payload_data_length; |
|---|
| 473 |
int i_tmp; |
|---|
| 474 |
|
|---|
| 475 |
mtime_t i_pts; |
|---|
| 476 |
mtime_t i_pts_delta; |
|---|
| 477 |
|
|---|
| 478 |
if( i_skip >= i_packet_size_left ) |
|---|
| 479 |
{ |
|---|
| 480 |
|
|---|
| 481 |
break; |
|---|
| 482 |
} |
|---|
| 483 |
|
|---|
| 484 |
i_packet_keyframe = p_peek[i_skip] >> 7; |
|---|
| 485 |
i_stream_number = p_peek[i_skip++] & 0x7f; |
|---|
| 486 |
|
|---|
| 487 |
GETVALUE2b( i_packet_property >> 4, i_media_object_number, 0 ); |
|---|
| 488 |
GETVALUE2b( i_packet_property >> 2, i_tmp, 0 ); |
|---|
| 489 |
GETVALUE2b( i_packet_property, i_replicated_data_length, 0 ); |
|---|
| 490 |
|
|---|
| 491 |
if( i_replicated_data_length > 1 ) |
|---|
| 492 |
{ |
|---|
| 493 |
i_pts = (mtime_t)GetDWLE( p_peek + i_skip + 4 ) * 1000; |
|---|
| 494 |
i_skip += i_replicated_data_length; |
|---|
| 495 |
i_pts_delta = 0; |
|---|
| 496 |
|
|---|
| 497 |
i_media_object_offset = i_tmp; |
|---|
| 498 |
|
|---|
| 499 |
if( i_skip >= i_packet_size_left ) |
|---|
| 500 |
{ |
|---|
| 501 |
break; |
|---|
| 502 |
} |
|---|
| 503 |
} |
|---|
| 504 |
else if( i_replicated_data_length == 1 ) |
|---|
| 505 |
{ |
|---|
| 506 |
|
|---|
| 507 |
|
|---|
| 508 |
i_pts = (mtime_t)i_tmp * 1000; |
|---|
| 509 |
i_pts_delta = (mtime_t)p_peek[i_skip] * 1000; i_skip++; |
|---|
| 510 |
|
|---|
| 511 |
i_media_object_offset = 0; |
|---|
| 512 |
} |
|---|
| 513 |
else |
|---|
| 514 |
{ |
|---|
| 515 |
i_pts = (mtime_t)i_packet_send_time * 1000; |
|---|
| 516 |
i_pts_delta = 0; |
|---|
| 517 |
|
|---|
| 518 |
i_media_object_offset = i_tmp; |
|---|
| 519 |
} |
|---|
| 520 |
|
|---|
| 521 |
i_pts = __MAX( i_pts - p_sys->p_fp->i_preroll * 1000, 0 ); |
|---|
| 522 |
if( b_packet_multiple_payload ) |
|---|
| 523 |
{ |
|---|
| 524 |
GETVALUE2b( i_payload_length_type, i_payload_data_length, 0 ); |
|---|
| 525 |
} |
|---|
| 526 |
else |
|---|
| 527 |
{ |
|---|
| 528 |
i_payload_data_length = i_packet_length - |
|---|
| 529 |
i_packet_padding_length - i_skip; |
|---|
| 530 |
} |
|---|
| 531 |
|
|---|
| 532 |
if( i_payload_data_length < 0 || i_payload_data_length > i_packet_size_left ) |
|---|
| 533 |
{ |
|---|
| 534 |
break; |
|---|
| 535 |
} |
|---|
| 536 |
#if 0 |
|---|
| 537 |
msg_Dbg( p_demux, |
|---|
| 538 |
"payload(%d/%d) stream_number:%d media_object_number:%d media_object_offset:%d replicated_data_length:%d payload_data_length %d", |
|---|
| 539 |
i_payload + 1, i_payload_count, i_stream_number, i_media_object_number, |
|---|
| 540 |
i_media_object_offset, i_replicated_data_length, i_payload_data_length ); |
|---|
| 541 |
#endif |
|---|
| 542 |
|
|---|
| 543 |
if( ( tk = p_sys->track[i_stream_number] ) == NULL ) |
|---|
| 544 |
{ |
|---|
| 545 |
msg_Warn( p_demux, |
|---|
| 546 |
"undeclared stream[Id 0x%x]", i_stream_number ); |
|---|
| 547 |
i_skip += i_payload_data_length; |
|---|
| 548 |
continue; |
|---|
| 549 |
} |
|---|
| 550 |
|
|---|
| 551 |
if( !tk->p_es ) |
|---|
| 552 |
{ |
|---|
| 553 |
i_skip += i_payload_data_length; |
|---|
| 554 |
continue; |
|---|
| 555 |
} |
|---|
| 556 |
|
|---|
| 557 |
|
|---|
| 558 |
for( i_payload_data_pos = 0; |
|---|
| 559 |
i_payload_data_pos < i_payload_data_length && |
|---|
| 560 |
i_packet_size_left > 0; |
|---|
| 561 |
i_payload_data_pos += i_sub_payload_data_length ) |
|---|
| 562 |
{ |
|---|
| 563 |
block_t *p_frag; |
|---|
| 564 |
int i_read; |
|---|
| 565 |
|
|---|
| 566 |
|
|---|
| 567 |
if( i_replicated_data_length == 1 ) |
|---|
| 568 |
{ |
|---|
| 569 |
i_sub_payload_data_length = p_peek[i_skip]; i_skip++; |
|---|
| 570 |
i_payload_data_pos++; |
|---|
| 571 |
} |
|---|
| 572 |
else |
|---|
| 573 |
{ |
|---|
| 574 |
i_sub_payload_data_length = i_payload_data_length; |
|---|
| 575 |
} |
|---|
| 576 |
|
|---|
| 577 |
|
|---|
| 578 |
if( tk->p_frame && i_media_object_offset == 0 ) |
|---|
| 579 |
{ |
|---|
| 580 |
|
|---|
| 581 |
block_t *p_gather = block_ChainGather( tk->p_frame ); |
|---|
| 582 |
|
|---|
| 583 |
es_out_Send( p_demux->out, tk->p_es, p_gather ); |
|---|
| 584 |
|
|---|
| 585 |
tk->p_frame = NULL; |
|---|
| 586 |
} |
|---|
| 587 |
|
|---|
| 588 |
i_read = i_sub_payload_data_length + i_skip; |
|---|
| 589 |
if( ( p_frag = stream_Block( p_demux->s, i_read ) ) == NULL ) |
|---|
| 590 |
{ |
|---|
| 591 |
msg_Warn( p_demux, "cannot read data" ); |
|---|
| 592 |
return 0; |
|---|
| 593 |
} |
|---|
| 594 |
i_packet_size_left -= i_read; |
|---|
| 595 |
|
|---|
| 596 |
p_frag->p_buffer += i_skip; |
|---|
| 597 |
p_frag->i_buffer -= i_skip; |
|---|
| 598 |
|
|---|
| 599 |
if( tk->p_frame == NULL ) |
|---|
| 600 |
{ |
|---|
| 601 |
tk->i_time = |
|---|
| 602 |
( (mtime_t)i_pts + i_payload * (mtime_t)i_pts_delta ); |
|---|
| 603 |
|
|---|
| 604 |
p_frag->i_pts = tk->i_time; |
|---|
| 605 |
|
|---|
| 606 |
if( tk->i_cat != VIDEO_ES ) |
|---|
| 607 |
p_frag->i_dts = p_frag->i_pts; |
|---|
| 608 |
else |
|---|
| 609 |
{ |
|---|
| 610 |
p_frag->i_dts = p_frag->i_pts; |
|---|
| 611 |
p_frag->i_pts = 0; |
|---|
| 612 |
} |
|---|
| 613 |
} |
|---|
| 614 |
|
|---|
| 615 |
block_ChainAppend( &tk->p_frame, p_frag ); |
|---|
| 616 |
|
|---|
| 617 |
i_skip = 0; |
|---|
| 618 |
if( i_packet_size_left > 0 ) |
|---|
| 619 |
{ |
|---|
| 620 |
if( stream_Peek( p_demux->s, &p_peek, i_packet_size_left ) |
|---|
| 621 |
< i_packet_size_left ) |
|---|
| 622 |
{ |
|---|
| 623 |
msg_Warn( p_demux, "cannot peek, EOF ?" ); |
|---|
| 624 |
return 0; |
|---|
| 625 |
} |
|---|
| 626 |
} |
|---|
| 627 |
} |
|---|
| 628 |
} |
|---|
| 629 |
|
|---|
| 630 |
if( i_packet_size_left > 0 ) |
|---|
| 631 |
{ |
|---|
| 632 |
#ifdef ASF_DEBUG |
|---|
| 633 |
if( i_packet_size_left > i_packet_padding_length ) |
|---|
| 634 |
msg_Warn( p_demux, "Didn't read %d bytes in the packet", |
|---|
| 635 |
i_packet_size_left - i_packet_padding_length ); |
|---|
| 636 |
else if( i_packet_size_left < i_packet_padding_length ) |
|---|
| 637 |
msg_Warn( p_demux, "Read %d too much bytes in the packet", |
|---|
| 638 |
i_packet_padding_length - i_packet_size_left ); |
|---|
| 639 |
#endif |
|---|
| 640 |
if( stream_Read( p_demux->s, NULL, i_packet_size_left ) |
|---|
| 641 |
< i_packet_size_left ) |
|---|
| 642 |
{ |
|---|
| 643 |
msg_Err( p_demux, "cannot skip data, EOF ?" ); |
|---|
| 644 |
return 0; |
|---|
| 645 |
} |
|---|
| 646 |
} |
|---|
| 647 |
|
|---|
| 648 |
return 1; |
|---|
| 649 |
|
|---|
| 650 |
loop_error_recovery: |
|---|
| 651 |
msg_Warn( p_demux, "unsupported packet header" ); |
|---|
| 652 |
if( p_sys->p_fp->i_min_data_packet_size != p_sys->p_fp->i_max_data_packet_size ) |
|---|
| 653 |
{ |
|---|
| 654 |
msg_Err( p_demux, "unsupported packet header, fatal error" ); |
|---|
| 655 |
return -1; |
|---|
| 656 |
} |
|---|
| 657 |
if( stream_Read( p_demux->s, NULL, i_data_packet_min ) != i_data_packet_min ) |
|---|
| 658 |
{ |
|---|
| 659 |
msg_Warn( p_demux, "cannot skip data, EOF ?" ); |
|---|
| 660 |
return 0; |
|---|
| 661 |
} |
|---|
| 662 |
|
|---|
| 663 |
return 1; |
|---|
| 664 |
} |
|---|
| 665 |
|
|---|
| 666 |
|
|---|
| 667 |
|
|---|
| 668 |
|
|---|
| 669 |
static int DemuxInit( demux_t *p_demux ) |
|---|
| 670 |
{ |
|---|
| 671 |
demux_sys_t *p_sys = p_demux->p_sys; |
|---|
| 672 |
bool b_seekable; |
|---|
| 673 |
unsigned int i_stream, i; |
|---|
| 674 |
asf_object_content_description_t *p_cd; |
|---|
| 675 |
asf_object_index_t *p_index; |
|---|
| 676 |
bool b_index; |
|---|
| 677 |
|
|---|
| 678 |
|
|---|
| 679 |
p_sys->i_time = -1; |
|---|
| 680 |
p_sys->i_length = 0; |
|---|
| 681 |
p_sys->i_bitrate = 0; |
|---|
| 682 |
p_sys->p_root = NULL; |
|---|
| 683 |
p_sys->p_fp = NULL; |
|---|
| 684 |
p_sys->b_index = 0; |
|---|
| 685 |
p_sys->i_track = 0; |
|---|
| 686 |
for( i = 0; i < 128; i++ ) |
|---|
| 687 |
{ |
|---|
| 688 |
p_sys->track[i] = NULL; |
|---|
| 689 |
} |
|---|
| 690 |
p_sys->i_data_begin = -1; |
|---|
| 691 |
p_sys->i_data_end = -1; |
|---|
| 692 |
p_sys->meta = NULL; |
|---|
| 693 |
|
|---|
| 694 |
|
|---|
| 695 |
stream_Control( p_demux->s, STREAM_CAN_FASTSEEK, &b_seekable ); |
|---|
| 696 |
if( !(p_sys->p_root = ASF_ReadObjectRoot(p_demux->s, b_seekable)) ) |
|---|
| 697 |
{ |
|---|
| 698 |
msg_Warn( p_demux, "ASF plugin discarded (not a valid file)" ); |
|---|
| 699 |
return VLC_EGENERIC; |
|---|
| 700 |
} |
|---|
| 701 |
p_sys->p_fp = p_sys->p_root->p_fp; |
|---|
| 702 |
|
|---|
| 703 |
if( p_sys->p_fp->i_min_data_packet_size != p_sys->p_fp->i_max_data_packet_size ) |
|---|
| 704 |
{ |
|---|
| 705 |
msg_Warn( p_demux, "ASF plugin discarded (invalid file_properties object)" ); |
|---|
| 706 |
goto error; |
|---|
| 707 |
} |
|---|
| 708 |
|
|---|
| 709 |
p_sys->i_track = ASF_CountObject( p_sys->p_root->p_hdr, |
|---|
| 710 |
&asf_object_stream_properties_guid ); |
|---|
| 711 |
if( p_sys->i_track <= 0 ) |
|---|
| 712 |
{ |
|---|
| 713 |
msg_Warn( p_demux, "ASF plugin discarded (cannot find any stream!)" ); |
|---|
| 714 |
goto error; |
|---|
| 715 |
} |
|---|
| 716 |
|
|---|
| 717 |
|
|---|
| 718 |
p_index = ASF_FindObject( p_sys->p_root, &asf_object_index_guid, 0 ); |
|---|
| 719 |
b_index = p_index && p_index->i_index_entry_count; |
|---|
| 720 |
|
|---|
| 721 |
msg_Dbg( p_demux, "found %d streams", p_sys->i_track ); |
|---|
| 722 |
|
|---|
| 723 |
for( i_stream = 0; i_stream < p_sys->i_track; i_stream ++ ) |
|---|
| 724 |
{ |
|---|
| 725 |
asf_track_t *tk; |
|---|
| 726 |
asf_object_stream_properties_t *p_sp; |
|---|
| 727 |
bool b_access_selected; |
|---|
| 728 |
|
|---|
| 729 |
p_sp = ASF_FindObject( p_sys->p_root->p_hdr, |
|---|
| 730 |
&asf_object_stream_properties_guid, |
|---|
| 731 |
i_stream ); |
|---|
| 732 |
|
|---|
| 733 |
tk = p_sys->track[p_sp->i_stream_number] = malloc( sizeof( asf_track_t ) ); |
|---|
| 734 |
memset( tk, 0, sizeof( asf_track_t ) ); |
|---|
| 735 |
|
|---|
| 736 |
tk->i_time = -1; |
|---|
| 737 |
tk->p_sp = p_sp; |
|---|
| 738 |
tk->p_es = NULL; |
|---|
| 739 |
tk->p_frame = NULL; |
|---|
| 740 |
|
|---|
| 741 |
|
|---|
| 742 |
if( !stream_Control( p_demux->s, STREAM_CONTROL_ACCESS, ACCESS_GET_PRIVATE_ID_STATE, |
|---|
| 743 |
p_sp->i_stream_number, &b_access_selected ) && |
|---|
| 744 |
!b_access_selected ) |
|---|
| 745 |
{ |
|---|
| 746 |
tk->i_cat = UNKNOWN_ES; |
|---|
| 747 |
msg_Dbg( p_demux, "ignoring not selected stream(ID:%d) (by access)", |
|---|
| 748 |
p_sp->i_stream_number ); |
|---|
| 749 |
continue; |
|---|
| 750 |
} |
|---|
| 751 |
|
|---|
| 752 |
if( ASF_CmpGUID( &p_sp->i_stream_type, &asf_object_stream_type_audio ) && |
|---|
| 753 |
p_sp->i_type_specific_data_length >= sizeof( WAVEFORMATEX ) - 2 ) |
|---|
| 754 |
{ |
|---|
| 755 |
es_format_t fmt; |
|---|
| 756 |
uint8_t *p_data = p_sp->p_type_specific_data; |
|---|
| 757 |
int i_format; |
|---|
| 758 |
|
|---|
| 759 |
es_format_Init( &fmt, AUDIO_ES, 0 ); |
|---|
| 760 |
i_format = GetWLE( &p_data[0] ); |
|---|
| 761 |
wf_tag_to_fourcc( i_format, &fmt.i_codec, NULL ); |
|---|
| 762 |
fmt.audio.i_channels = GetWLE( &p_data[2] ); |
|---|
| 763 |
fmt.audio.i_rate = GetDWLE( &p_data[4] ); |
|---|
| 764 |
fmt.i_bitrate = GetDWLE( &p_data[8] ) * 8; |
|---|
| 765 |
fmt.audio.i_blockalign = GetWLE( &p_data[12] ); |
|---|
| 766 |
fmt.audio.i_bitspersample = GetWLE( &p_data[14] ); |
|---|
| 767 |
|
|---|
| 768 |
if( p_sp->i_type_specific_data_length > sizeof( WAVEFORMATEX ) && |
|---|
| 769 |
i_format != WAVE_FORMAT_MPEGLAYER3 && |
|---|
| 770 |
i_format != WAVE_FORMAT_MPEG ) |
|---|
| 771 |
{ |
|---|
| 772 |
fmt.i_extra = __MIN( GetWLE( &p_data[16] ), |
|---|
| 773 |
p_sp->i_type_specific_data_length - |
|---|
| 774 |
sizeof( WAVEFORMATEX ) ); |
|---|
| 775 |
fmt.p_extra = malloc( fmt.i_extra ); |
|---|
| 776 |
memcpy( fmt.p_extra, &p_data[sizeof( WAVEFORMATEX )], |
|---|
| 777 |
fmt.i_extra ); |
|---|
| 778 |
} |
|---|
| 779 |
|
|---|
| 780 |
tk->i_cat = AUDIO_ES; |
|---|
| 781 |
tk->p_es = es_out_Add( p_demux->out, &fmt ); |
|---|
| 782 |
es_format_Clean( &fmt ); |
|---|
| 783 |
|
|---|
| 784 |
msg_Dbg( p_demux, "added new audio stream(codec:0x%x,ID:%d)", |
|---|
| 785 |
GetWLE( p_data ), p_sp->i_stream_number ); |
|---|
| 786 |
} |
|---|
| 787 |
else if( ASF_CmpGUID( &p_sp->i_stream_type, |
|---|
| 788 |
&asf_object_stream_type_video ) && |
|---|
| 789 |
p_sp->i_type_specific_data_length >= 11 + |
|---|
| 790 |
sizeof( BITMAPINFOHEADER ) ) |
|---|
| 791 |
{ |
|---|
| 792 |
es_format_t fmt; |
|---|
| 793 |
uint8_t *p_data = &p_sp->p_type_specific_data[11]; |
|---|
| 794 |
|
|---|
| 795 |
es_format_Init( &fmt, VIDEO_ES, |
|---|
| 796 |
VLC_FOURCC( p_data[16], p_data[17], |
|---|
| 797 |
p_data[18], p_data[19] ) ); |
|---|
| 798 |
fmt.video.i_width = GetDWLE( p_data + 4 ); |
|---|
| 799 |
fmt.video.i_height= GetDWLE( p_data + 8 ); |
|---|
| 800 |
|
|---|
| 801 |
|
|---|
| 802 |
if( fmt.i_codec == VLC_FOURCC( 'D','V','R',' ') ) |
|---|
| 803 |
{ |
|---|
| 804 |
|
|---|
| 805 |
fmt.i_codec = VLC_FOURCC( 'm','p','g','2' ) ; |
|---|
| 806 |
fmt.b_packetized = false; |
|---|
| 807 |
} |
|---|
| 808 |
|
|---|
| 809 |
if( p_sp->i_type_specific_data_length > 11 + |
|---|
| 810 |
sizeof( BITMAPINFOHEADER ) ) |
|---|
| 811 |
{ |
|---|
| 812 |
fmt.i_extra = __MIN( GetDWLE( p_data ), |
|---|
| 813 |
p_sp->i_type_specific_data_length - 11 - |
|---|
| 814 |
sizeof( BITMAPINFOHEADER ) ); |
|---|
| 815 |
fmt.p_extra = malloc( fmt.i_extra ); |
|---|
| 816 |
memcpy( fmt.p_extra, &p_data[sizeof( BITMAPINFOHEADER )], |
|---|
| 817 |
fmt.i_extra ); |
|---|
| 818 |
} |
|---|
| 819 |
|
|---|
| 820 |
|
|---|
| 821 |
if( p_sys->p_root->p_metadata ) |
|---|
| 822 |
{ |
|---|
| 823 |
asf_object_metadata_t *p_meta = p_sys->p_root->p_metadata; |
|---|
| 824 |
int i_aspect_x = 0, i_aspect_y = 0; |
|---|
| 825 |
unsigned int i; |
|---|
| 826 |
|
|---|
| 827 |
for( i = 0; i < p_meta->i_record_entries_count; i++ ) |
|---|
| 828 |
{ |
|---|
| 829 |
if( !strcmp( p_meta->record[i].psz_name, "AspectRatioX" ) ) |
|---|
| 830 |
{ |
|---|
| 831 |
if( (!i_aspect_x && !p_meta->record[i].i_stream) || |
|---|
| 832 |
p_meta->record[i].i_stream == |
|---|
| 833 |
p_sp->i_stream_number ) |
|---|
| 834 |
i_aspect_x = p_meta->record[i].i_val; |
|---|
| 835 |
} |
|---|
| 836 |
if( !strcmp( p_meta->record[i].psz_name, "AspectRatioY" ) ) |
|---|
| 837 |
{ |
|---|
| 838 |
if( (!i_aspect_y && !p_meta->record[i].i_stream) || |
|---|
| 839 |
p_meta->record[i].i_stream == |
|---|
| 840 |
p_sp->i_stream_number ) |
|---|
| 841 |
i_aspect_y = p_meta->record[i].i_val; |
|---|
| 842 |
} |
|---|
| 843 |
} |
|---|
| 844 |
|
|---|
| 845 |
if( i_aspect_x && i_aspect_y ) |
|---|
| 846 |
{ |
|---|
| 847 |
fmt.video.i_aspect = i_aspect_x * |
|---|
| 848 |
(int64_t)fmt.video.i_width * VOUT_ASPECT_FACTOR / |
|---|
| 849 |
fmt.video.i_height / i_aspect_y; |
|---|
| 850 |
} |
|---|
| 851 |
} |
|---|
| 852 |
|
|---|
| 853 |
tk->i_cat = VIDEO_ES; |
|---|
| 854 |
tk->p_es = es_out_Add( p_demux->out, &fmt ); |
|---|
| 855 |
es_format_Clean( &fmt ); |
|---|
| 856 |
|
|---|
| 857 |
|
|---|
| 858 |
p_sys->b_index = b_index; |
|---|
| 859 |
|
|---|
| 860 |
msg_Dbg( p_demux, "added new video stream(ID:%d)", |
|---|
| 861 |
p_sp->i_stream_number ); |
|---|
| 862 |
} |
|---|
| 863 |
else if( ASF_CmpGUID( &p_sp->i_stream_type, &asf_object_extended_stream_header ) && |
|---|
| 864 |
p_sp->i_type_specific_data_length >= 64 ) |
|---|
| 865 |
{ |
|---|
| 866 |
|
|---|
| 867 |
es_format_t fmt; |
|---|
| 868 |
guid_t *p_ref = (guid_t *)p_sp->p_type_specific_data; |
|---|
| 869 |
uint8_t *p_data = p_sp->p_type_specific_data + 64; |
|---|
| 870 |
unsigned int i_data = p_sp->i_type_specific_data_length - 64; |
|---|
| 871 |
|
|---|
| 872 |
msg_Dbg( p_demux, "Ext stream header detected. datasize = %d", p_sp->i_type_specific_data_length ); |
|---|
| 873 |
if( ASF_CmpGUID( p_ref, &asf_object_extended_stream_type_audio ) && |
|---|
| 874 |
i_data >= sizeof( WAVEFORMATEX ) - 2) |
|---|
| 875 |
{ |
|---|
| 876 |
int i_format; |
|---|
| 877 |
es_format_Init( &fmt, AUDIO_ES, 0 ); |
|---|
| 878 |
i_format = GetWLE( &p_data[0] ); |
|---|
| 879 |
if( i_format == 0 ) |
|---|
| 880 |
fmt.i_codec = VLC_FOURCC( 'a','5','2',' '); |
|---|
| 881 |
else |
|---|
| 882 |
wf_tag_to_fourcc( i_format, &fmt.i_codec, NULL ); |
|---|
| 883 |
fmt.audio.i_channels = GetWLE( &p_data[2] ); |
|---|
| 884 |
fmt.audio.i_rate = GetDWLE( &p_data[4] ); |
|---|
| 885 |
fmt.i_bitrate = GetDWLE( &p_data[8] ) * 8; |
|---|
| 886 |
fmt.audio.i_blockalign = GetWLE( &p_data[12] ); |
|---|
| 887 |
fmt.audio.i_bitspersample = GetWLE( &p_data[14] ); |
|---|
| 888 |
fmt.b_packetized = true; |
|---|
| 889 |
|
|---|
| 890 |
if( p_sp->i_type_specific_data_length > sizeof( WAVEFORMATEX ) && |
|---|
| 891 |
i_format != WAVE_FORMAT_MPEGLAYER3 && |
|---|
| 892 |
i_format != WAVE_FORMAT_MPEG ) |
|---|
| 893 |
{ |
|---|
| 894 |
fmt.i_extra = __MIN( GetWLE( &p_data[16] ), |
|---|
| 895 |
p_sp->i_type_specific_data_length - |
|---|
| 896 |
sizeof( WAVEFORMATEX ) ); |
|---|
| 897 |
|
|---|