| 254 | | static block_t *ADTSPacketizeBlock( decoder_t *p_dec, block_t **pp_block ) |
|---|
| 255 | | { |
|---|
| 256 | | decoder_sys_t *p_sys = p_dec->p_sys; |
|---|
| 257 | | uint8_t p_header[ADTS_HEADER_SIZE]; |
|---|
| 258 | | void *p_out_buffer; |
|---|
| 259 | | uint8_t *p_buf; |
|---|
| 260 | | |
|---|
| 261 | | if( !pp_block || !*pp_block ) return NULL; |
|---|
| 262 | | |
|---|
| 263 | | if( (*pp_block)->i_flags&(BLOCK_FLAG_DISCONTINUITY|BLOCK_FLAG_CORRUPTED) ) |
|---|
| 264 | | { |
|---|
| 265 | | if( (*pp_block)->i_flags&BLOCK_FLAG_CORRUPTED ) |
|---|
| 266 | | { |
|---|
| 267 | | p_sys->i_state = STATE_NOSYNC; |
|---|
| 268 | | block_BytestreamFlush( &p_sys->bytestream ); |
|---|
| 269 | | } |
|---|
| 270 | | //aout_DateSet( &p_sys->end_date, 0 ); |
|---|
| 271 | | block_Release( *pp_block ); |
|---|
| 272 | | return NULL; |
|---|
| 273 | | } |
|---|
| 274 | | |
|---|
| 275 | | if( !aout_DateGet( &p_sys->end_date ) && !(*pp_block)->i_pts ) |
|---|
| 276 | | { |
|---|
| 277 | | /* We've just started the stream, wait for the first PTS. */ |
|---|
| 278 | | block_Release( *pp_block ); |
|---|
| 279 | | return NULL; |
|---|
| 280 | | } |
|---|
| 281 | | |
|---|
| 282 | | if( (*pp_block)->i_rate > 0 ) |
|---|
| 283 | | p_sys->i_input_rate = (*pp_block)->i_rate; |
|---|
| 284 | | |
|---|
| 285 | | block_BytestreamPush( &p_sys->bytestream, *pp_block ); |
|---|
| 286 | | |
|---|
| 287 | | while( 1 ) |
|---|
| 288 | | { |
|---|
| 289 | | switch( p_sys->i_state ) |
|---|
| 290 | | { |
|---|
| 291 | | |
|---|
| 292 | | case STATE_NOSYNC: |
|---|
| 293 | | while( block_PeekBytes( &p_sys->bytestream, p_header, 2 ) |
|---|
| 294 | | == VLC_SUCCESS ) |
|---|
| 295 | | { |
|---|
| 296 | | /* Look for sync word - should be 0xfff + 2 layer bits */ |
|---|
| 297 | | if( p_header[0] == 0xff && (p_header[1] & 0xf6) == 0xf0 ) |
|---|
| 298 | | { |
|---|
| 299 | | p_sys->i_state = STATE_SYNC; |
|---|
| 300 | | break; |
|---|
| 301 | | } |
|---|
| 302 | | block_SkipByte( &p_sys->bytestream ); |
|---|
| 303 | | } |
|---|
| 304 | | if( p_sys->i_state != STATE_SYNC ) |
|---|
| 305 | | { |
|---|
| 306 | | block_BytestreamFlush( &p_sys->bytestream ); |
|---|
| 307 | | |
|---|
| 308 | | /* Need more data */ |
|---|
| 309 | | return NULL; |
|---|
| 310 | | } |
|---|
| 311 | | |
|---|
| 312 | | case STATE_SYNC: |
|---|
| 313 | | /* New frame, set the Presentation Time Stamp */ |
|---|
| 314 | | p_sys->i_pts = p_sys->bytestream.p_block->i_pts; |
|---|
| 315 | | if( p_sys->i_pts != 0 && |
|---|
| 316 | | p_sys->i_pts != aout_DateGet( &p_sys->end_date ) ) |
|---|
| 317 | | { |
|---|
| 318 | | aout_DateSet( &p_sys->end_date, p_sys->i_pts ); |
|---|
| 319 | | } |
|---|
| 320 | | p_sys->i_state = STATE_HEADER; |
|---|
| 321 | | break; |
|---|
| 322 | | |
|---|
| 323 | | case STATE_HEADER: |
|---|
| 324 | | /* Get ADTS frame header (ADTS_HEADER_SIZE bytes) */ |
|---|
| 325 | | if( block_PeekBytes( &p_sys->bytestream, p_header, |
|---|
| 326 | | ADTS_HEADER_SIZE ) != VLC_SUCCESS ) |
|---|
| 327 | | { |
|---|
| 328 | | /* Need more data */ |
|---|
| 329 | | return NULL; |
|---|
| 330 | | } |
|---|
| 331 | | |
|---|
| 332 | | /* Check if frame is valid and get frame info */ |
|---|
| 333 | | p_sys->i_frame_size = ADTSSyncInfo( p_dec, p_header, |
|---|
| 334 | | &p_sys->i_channels, |
|---|
| 335 | | &p_sys->i_rate, |
|---|
| 336 | | &p_sys->i_frame_length, |
|---|
| 337 | | &p_sys->i_header_size, |
|---|
| 338 | | &p_sys->i_raw_blocks ); |
|---|
| 339 | | if( p_sys->i_frame_size <= 0 ) |
|---|
| 340 | | { |
|---|
| 341 | | msg_Dbg( p_dec, "emulated sync word" ); |
|---|
| 342 | | block_SkipByte( &p_sys->bytestream ); |
|---|
| 343 | | p_sys->i_state = STATE_NOSYNC; |
|---|
| 344 | | break; |
|---|
| 345 | | } |
|---|
| 346 | | |
|---|
| 347 | | p_sys->i_state = STATE_NEXT_SYNC; |
|---|
| 348 | | |
|---|
| 349 | | case STATE_NEXT_SYNC: |
|---|
| 350 | | /* TODO: If p_block == NULL, flush the buffer without checking the |
|---|
| 351 | | * next sync word */ |
|---|
| 352 | | |
|---|
| 353 | | /* Check if next expected frame contains the sync word */ |
|---|
| 354 | | if( block_PeekOffsetBytes( &p_sys->bytestream, p_sys->i_frame_size |
|---|
| 355 | | + p_sys->i_header_size, p_header, 2 ) |
|---|
| 356 | | != VLC_SUCCESS ) |
|---|
| 357 | | { |
|---|
| 358 | | /* Need more data */ |
|---|
| 359 | | return NULL; |
|---|
| 360 | | } |
|---|
| 361 | | |
|---|
| 362 | | if( p_header[0] != 0xff || (p_header[1] & 0xf6) != 0xf0 ) |
|---|
| 363 | | { |
|---|
| 364 | | msg_Dbg( p_dec, "emulated sync word " |
|---|
| 365 | | "(no sync on following frame)" ); |
|---|
| 366 | | p_sys->i_state = STATE_NOSYNC; |
|---|
| 367 | | block_SkipByte( &p_sys->bytestream ); |
|---|
| 368 | | break; |
|---|
| 369 | | } |
|---|
| 370 | | |
|---|
| 371 | | p_sys->i_state = STATE_SEND_DATA; |
|---|
| 372 | | break; |
|---|
| 373 | | |
|---|
| 374 | | case STATE_GET_DATA: |
|---|
| 375 | | /* Make sure we have enough data. |
|---|
| 376 | | * (Not useful if we went through NEXT_SYNC) */ |
|---|
| 377 | | if( block_WaitBytes( &p_sys->bytestream, p_sys->i_frame_size + |
|---|
| 378 | | p_sys->i_header_size) != VLC_SUCCESS ) |
|---|
| 379 | | { |
|---|
| 380 | | /* Need more data */ |
|---|
| 381 | | return NULL; |
|---|
| 382 | | } |
|---|
| 383 | | p_sys->i_state = STATE_SEND_DATA; |
|---|
| 384 | | |
|---|
| 385 | | case STATE_SEND_DATA: |
|---|
| 386 | | if( !(p_buf = GetOutBuffer( p_dec, &p_out_buffer )) ) |
|---|
| 387 | | { |
|---|
| 388 | | //p_dec->b_error = VLC_TRUE; |
|---|
| 389 | | return NULL; |
|---|
| 390 | | } |
|---|
| 391 | | |
|---|
| 392 | | /* When we reach this point we already know we have enough |
|---|
| 393 | | * data available. */ |
|---|
| 394 | | |
|---|
| 395 | | /* Skip the ADTS header */ |
|---|
| 396 | | block_SkipBytes( &p_sys->bytestream, p_sys->i_header_size ); |
|---|
| 397 | | |
|---|
| 398 | | /* Copy the whole frame into the buffer */ |
|---|
| 399 | | block_GetBytes( &p_sys->bytestream, p_buf, p_sys->i_frame_size ); |
|---|
| 400 | | |
|---|
| 401 | | /* Make sure we don't reuse the same pts twice */ |
|---|
| 402 | | if( p_sys->i_pts == p_sys->bytestream.p_block->i_pts ) |
|---|
| 403 | | p_sys->i_pts = p_sys->bytestream.p_block->i_pts = 0; |
|---|
| 404 | | |
|---|
| 405 | | /* So p_block doesn't get re-added several times */ |
|---|
| 406 | | *pp_block = block_BytestreamPop( &p_sys->bytestream ); |
|---|
| 407 | | |
|---|
| 408 | | p_sys->i_state = STATE_NOSYNC; |
|---|
| 409 | | |
|---|
| 410 | | return p_out_buffer; |
|---|
| 411 | | } |
|---|
| 412 | | } |
|---|
| 413 | | |
|---|
| 414 | | return NULL; |
|---|
| 415 | | } |
|---|
| 416 | | |
|---|
| 417 | | /***************************************************************************** |
|---|
| 418 | | * GetOutBuffer: |
|---|
| 419 | | *****************************************************************************/ |
|---|
| 420 | | static uint8_t *GetOutBuffer( decoder_t *p_dec, void **pp_out_buffer ) |
|---|
| 421 | | { |
|---|
| 422 | | decoder_sys_t *p_sys = p_dec->p_sys; |
|---|
| 423 | | block_t *p_block; |
|---|
| 424 | | |
|---|
| 425 | | if( p_dec->fmt_out.audio.i_rate != p_sys->i_rate ) |
|---|
| 426 | | { |
|---|
| 427 | | msg_Info( p_dec, "AAC channels: %d samplerate: %d", |
|---|
| 428 | | p_sys->i_channels, p_sys->i_rate ); |
|---|
| 429 | | |
|---|
| 430 | | aout_DateInit( &p_sys->end_date, p_sys->i_rate ); |
|---|
| 431 | | aout_DateSet( &p_sys->end_date, p_sys->i_pts ); |
|---|
| 432 | | } |
|---|
| 433 | | |
|---|
| 434 | | p_dec->fmt_out.audio.i_rate = p_sys->i_rate; |
|---|
| 435 | | p_dec->fmt_out.audio.i_channels = p_sys->i_channels; |
|---|
| 436 | | p_dec->fmt_out.audio.i_bytes_per_frame = p_sys->i_frame_size; |
|---|
| 437 | | p_dec->fmt_out.audio.i_frame_length = p_sys->i_frame_length; |
|---|
| 438 | | |
|---|
| 439 | | #if 0 |
|---|
| 440 | | p_dec->fmt_out.audio.i_original_channels = p_sys->i_channels_conf; |
|---|
| 441 | | p_dec->fmt_out.audio.i_physical_channels = |
|---|
| 442 | | p_sys->i_channels_conf & AOUT_CHAN_PHYSMASK; |
|---|
| 443 | | #endif |
|---|
| 444 | | |
|---|
| 445 | | p_block = block_New( p_dec, p_sys->i_frame_size ); |
|---|
| 446 | | if( p_block == NULL ) return NULL; |
|---|
| 447 | | |
|---|
| 448 | | p_block->i_pts = p_block->i_dts = aout_DateGet( &p_sys->end_date ); |
|---|
| 449 | | |
|---|
| 450 | | p_block->i_length = aout_DateIncrement( &p_sys->end_date, |
|---|
| 451 | | p_sys->i_frame_length * p_sys->i_input_rate / INPUT_RATE_DEFAULT ) - |
|---|
| 452 | | p_block->i_pts; |
|---|
| 453 | | |
|---|
| 454 | | *pp_out_buffer = p_block; |
|---|
| 455 | | return p_block->p_buffer; |
|---|
| 456 | | } |
|---|
| 457 | | |
|---|
| 458 | | /***************************************************************************** |
|---|
| 459 | | * ClosePacketizer: clean up the packetizer |
|---|
| 460 | | *****************************************************************************/ |
|---|
| 461 | | static void ClosePacketizer( vlc_object_t *p_this ) |
|---|
| 462 | | { |
|---|
| 463 | | decoder_t *p_dec = (decoder_t *)p_this; |
|---|
| 464 | | decoder_sys_t *p_sys = p_dec->p_sys; |
|---|
| 465 | | |
|---|
| 466 | | block_BytestreamRelease( &p_sys->bytestream ); |
|---|
| 467 | | |
|---|
| 468 | | free( p_dec->p_sys ); |
|---|
| 469 | | } |
|---|
| 470 | | |
|---|
| 471 | | /***************************************************************************** |
|---|
| 472 | | * ADTSSyncInfo: parse MPEG 4 audio ADTS sync info |
|---|
| 473 | | *****************************************************************************/ |
|---|
| | 364 | /**************************************************************************** |
|---|
| | 365 | * LOAS helpers |
|---|
| | 366 | ****************************************************************************/ |
|---|
| | 367 | static int LOASSyncInfo( decoder_t *p_dec, uint8_t p_header[LOAS_HEADER_SIZE], unsigned int *pi_header_size ) |
|---|
| | 368 | { |
|---|
| | 369 | *pi_header_size = 3; |
|---|
| | 370 | return ( ( p_header[1] & 0x1f ) << 8 ) + p_header[2]; |
|---|
| | 371 | } |
|---|
| | 372 | static int Mpeg4GAProgramConfigElement( bs_t *s ) |
|---|
| | 373 | { |
|---|
| | 374 | /* TODO compute channels count ? */ |
|---|
| | 375 | int i_tag = bs_read( s, 4 ); |
|---|
| | 376 | if( i_tag != 0x05 ) |
|---|
| | 377 | return -1; |
|---|
| | 378 | bs_skip( s, 2 + 4 ); // object type + sampling index |
|---|
| | 379 | int i_num_front = bs_read( s, 4 ); |
|---|
| | 380 | int i_num_side = bs_read( s, 4 ); |
|---|
| | 381 | int i_num_back = bs_read( s, 4 ); |
|---|
| | 382 | int i_num_lfe = bs_read( s, 2 ); |
|---|
| | 383 | int i_num_assoc_data = bs_read( s, 3 ); |
|---|
| | 384 | int i_num_valid_cc = bs_read( s, 4 ); |
|---|
| | 385 | |
|---|
| | 386 | if( bs_read1(s) ) |
|---|
| | 387 | bs_skip( s, 4 ); // mono downmix |
|---|
| | 388 | if( bs_read1(s) ) |
|---|
| | 389 | bs_skip( s, 4 ); // stereo downmix |
|---|
| | 390 | if( bs_read1(s) ) |
|---|
| | 391 | bs_skip( s, 2+1 ); // matrix downmix + pseudo_surround |
|---|
| | 392 | |
|---|
| | 393 | bs_skip( s, i_num_front * (1+4) ); |
|---|
| | 394 | bs_skip( s, i_num_side * (1+4) ); |
|---|
| | 395 | bs_skip( s, i_num_back * (1+4) ); |
|---|
| | 396 | bs_skip( s, i_num_lfe * (4) ); |
|---|
| | 397 | bs_skip( s, i_num_assoc_data * (4) ); |
|---|
| | 398 | bs_skip( s, i_num_valid_cc * (5) ); |
|---|
| | 399 | bs_align( s ); |
|---|
| | 400 | int i_comment = bs_read( s, 8 ); |
|---|
| | 401 | bs_skip( s, i_comment * 8 ); |
|---|
| | 402 | return 0; |
|---|
| | 403 | } |
|---|
| | 404 | static int Mpeg4GASpecificConfig( mpeg4_cfg_t *p_cfg, bs_t *s ) |
|---|
| | 405 | { |
|---|
| | 406 | p_cfg->i_frame_length = bs_read1(s) ? 960 : 1024; |
|---|
| | 407 | |
|---|
| | 408 | if( bs_read1( s ) ) // depend on core coder |
|---|
| | 409 | bs_skip( s, 14 ); // core coder delay |
|---|
| | 410 | |
|---|
| | 411 | int i_extension_flag = bs_read1( s ); |
|---|
| | 412 | if( p_cfg->i_channel == 0 ) |
|---|
| | 413 | { |
|---|
| | 414 | Mpeg4GAProgramConfigElement( s ); |
|---|
| | 415 | } |
|---|
| | 416 | if( p_cfg->i_object_type == 6 || p_cfg->i_object_type == 20 ) |
|---|
| | 417 | bs_skip( s, 3 ); // layer |
|---|
| | 418 | |
|---|
| | 419 | if( i_extension_flag ) |
|---|
| | 420 | { |
|---|
| | 421 | if( p_cfg->i_object_type == 22 ) |
|---|
| | 422 | { |
|---|
| | 423 | bs_skip( s, 5 + 11 ); // numOfSubFrame + layer length |
|---|
| | 424 | } |
|---|
| | 425 | if( p_cfg->i_object_type == 17 || p_cfg->i_object_type == 19 || |
|---|
| | 426 | p_cfg->i_object_type == 20 || p_cfg->i_object_type == 23 ) |
|---|
| | 427 | { |
|---|
| | 428 | bs_skip( s, 1+1+1 ); // ER data : section scale spectral */ |
|---|
| | 429 | } |
|---|
| | 430 | if( bs_read1( s ) ) // extension 3 |
|---|
| | 431 | fprintf( stderr, "Mpeg4GASpecificConfig: error 1\n" ); |
|---|
| | 432 | } |
|---|
| | 433 | return 0; |
|---|
| | 434 | } |
|---|
| | 435 | static int Mpeg4ReadAudioObjectType( bs_t *s ) |
|---|
| | 436 | { |
|---|
| | 437 | int i_type = bs_read( s, 5 ); |
|---|
| | 438 | if( i_type == 0x1f ) |
|---|
| | 439 | i_type += bs_read( s, 6 ); |
|---|
| | 440 | return i_type; |
|---|
| | 441 | } |
|---|
| | 442 | static int Mpeg4ReadAudioSamplerate( bs_t *s ) |
|---|
| | 443 | { |
|---|
| | 444 | int i_index = bs_read( s, 4 ); |
|---|
| | 445 | if( i_index != 0x0f ) |
|---|
| | 446 | return pi_sample_rates[i_index]; |
|---|
| | 447 | return bs_read( s, 24 ); |
|---|
| | 448 | } |
|---|
| | 449 | static int Mpeg4ReadAudioSpecificInfo( mpeg4_cfg_t *p_cfg, int *pi_extra, uint8_t *p_extra, bs_t *s, int i_max_size ) |
|---|
| | 450 | { |
|---|
| | 451 | #if 0 |
|---|
| | 452 | static const char *ppsz_otype[] = { |
|---|
| | 453 | "NULL", |
|---|
| | 454 | "AAC Main", "AAC LC", "AAC SSR", "AAC LTP", "SBR", "AAC Scalable", |
|---|
| | 455 | "TwinVQ", |
|---|
| | 456 | "CELP", "HVXC", |
|---|
| | 457 | "Reserved", "Reserved", |
|---|
| | 458 | "TTSI", |
|---|
| | 459 | "Main Synthetic", "Wavetables Synthesis", "General MIDI", |
|---|
| | 460 | "Algorithmic Synthesis and Audio FX", |
|---|
| | 461 | "ER AAC LC", |
|---|
| | 462 | "Reserved", |
|---|
| | 463 | "ER AAC LTP", "ER AAC Scalable", "ER TwinVQ", "ER BSAC", "ER AAC LD", |
|---|
| | 464 | "ER CELP", "ER HVXC", "ER HILN", "ER Parametric", |
|---|
| | 465 | "SSC", |
|---|
| | 466 | "Reserved", "Reserved", "Escape", |
|---|
| | 467 | "Layer 1", "Layer 2", "Layer 3", |
|---|
| | 468 | "DST", |
|---|
| | 469 | }; |
|---|
| | 470 | #endif |
|---|
| | 471 | const int i_pos_start = bs_pos( s ); |
|---|
| | 472 | bs_t s_sav = *s; |
|---|
| | 473 | int i_bits; |
|---|
| | 474 | int i; |
|---|
| | 475 | |
|---|
| | 476 | memset( p_cfg, 0, sizeof(*p_cfg) ); |
|---|
| | 477 | *pi_extra = 0; |
|---|
| | 478 | |
|---|
| | 479 | p_cfg->i_object_type = Mpeg4ReadAudioObjectType( s ); |
|---|
| | 480 | p_cfg->i_samplerate = Mpeg4ReadAudioSamplerate( s ); |
|---|
| | 481 | |
|---|
| | 482 | p_cfg->i_channel = bs_read( s, 4 ); |
|---|
| | 483 | if( p_cfg->i_channel == 7 ) |
|---|
| | 484 | p_cfg->i_channel = 8; // 7.1 |
|---|
| | 485 | else if( p_cfg->i_channel >= 8 ) |
|---|
| | 486 | p_cfg->i_channel = -1; |
|---|
| | 487 | |
|---|
| | 488 | p_cfg->i_sbr = -1; |
|---|
| | 489 | p_cfg->extension.i_object_type = 0; |
|---|
| | 490 | p_cfg->extension.i_samplerate = 0; |
|---|
| | 491 | if( p_cfg->i_object_type == 5 ) |
|---|
| | 492 | { |
|---|
| | 493 | p_cfg->i_sbr = 1; |
|---|
| | 494 | p_cfg->extension.i_object_type = p_cfg->i_object_type; |
|---|
| | 495 | p_cfg->extension.i_samplerate = Mpeg4ReadAudioSamplerate( s ); |
|---|
| | 496 | |
|---|
| | 497 | p_cfg->i_object_type = Mpeg4ReadAudioObjectType( s ); |
|---|
| | 498 | } |
|---|
| | 499 | |
|---|
| | 500 | switch( p_cfg->i_object_type ) |
|---|
| | 501 | { |
|---|
| | 502 | case 1: case 2: case 3: case 4: |
|---|
| | 503 | case 6: case 7: |
|---|
| | 504 | case 17: case 19: case 20: case 21: case 22: case 23: |
|---|
| | 505 | Mpeg4GASpecificConfig( p_cfg, s ); |
|---|
| | 506 | break; |
|---|
| | 507 | case 8: |
|---|
| | 508 | // CelpSpecificConfig(); |
|---|
| | 509 | break; |
|---|
| | 510 | case 9: |
|---|
| | 511 | // HvxcSpecificConfig(); |
|---|
| | 512 | break; |
|---|
| | 513 | case 12: |
|---|
| | 514 | // TTSSSpecificConfig(); |
|---|
| | 515 | break; |
|---|
| | 516 | case 13: case 14: case 15: case 16: |
|---|
| | 517 | // StructuredAudioSpecificConfig(); |
|---|
| | 518 | break; |
|---|
| | 519 | case 24: |
|---|
| | 520 | // ERCelpSpecificConfig(); |
|---|
| | 521 | break; |
|---|
| | 522 | case 25: |
|---|
| | 523 | // ERHvxcSpecificConfig(); |
|---|
| | 524 | break; |
|---|
| | 525 | case 26: case 27: |
|---|
| | 526 | // ParametricSpecificConfig(); |
|---|
| | 527 | break; |
|---|
| | 528 | case 28: |
|---|
| | 529 | // SSCSpecificConfig(); |
|---|
| | 530 | break; |
|---|
| | 531 | case 32: case 33: case 34: |
|---|
| | 532 | // MPEG_1_2_SpecificConfig(); |
|---|
| | 533 | break; |
|---|
| | 534 | case 35: |
|---|
| | 535 | // DSTSpecificConfig(); |
|---|
| | 536 | break; |
|---|
| | 537 | default: |
|---|
| | 538 | // error |
|---|
| | 539 | break; |
|---|
| | 540 | } |
|---|
| | 541 | switch( p_cfg->i_object_type ) |
|---|
| | 542 | { |
|---|
| | 543 | case 17: case 19: case 20: case 21: case 22: case 23: |
|---|
| | 544 | case 24: case 25: case 26: case 27: |
|---|
| | 545 | { |
|---|
| | 546 | int epConfig = bs_read( s, 2 ); |
|---|
| | 547 | if( epConfig == 2 || epConfig == 3 ) |
|---|
| | 548 | { |
|---|
| | 549 | //ErrorProtectionSpecificConfig(); |
|---|
| | 550 | } |
|---|
| | 551 | if( epConfig == 3 ) |
|---|
| | 552 | { |
|---|
| | 553 | int directMapping = bs_read1( s ); |
|---|
| | 554 | if( directMapping ) |
|---|
| | 555 | { |
|---|
| | 556 | // tbd ... |
|---|
| | 557 | } |
|---|
| | 558 | } |
|---|
| | 559 | break; |
|---|
| | 560 | } |
|---|
| | 561 | default: |
|---|
| | 562 | break; |
|---|
| | 563 | } |
|---|
| | 564 | if( p_cfg->extension.i_object_type != 5 && i_max_size > 0 && i_max_size - (bs_pos(s) - i_pos_start) >= 16 && |
|---|
| | 565 | bs_read( s, 11 ) == 0x2b7 ) |
|---|
| | 566 | { |
|---|
| | 567 | p_cfg->extension.i_object_type = Mpeg4ReadAudioObjectType( s ); |
|---|
| | 568 | if( p_cfg->extension.i_object_type == 5 ) |
|---|
| | 569 | { |
|---|
| | 570 | p_cfg->i_sbr = bs_read1( s ); |
|---|
| | 571 | if( p_cfg->i_sbr == 1 ) |
|---|
| | 572 | p_cfg->extension.i_samplerate = Mpeg4ReadAudioSamplerate( s ); |
|---|
| | 573 | } |
|---|
| | 574 | } |
|---|
| | 575 | |
|---|
| | 576 | //fprintf( stderr, "Mpeg4ReadAudioSpecificInfo: t=%s(%d)f=%d c=%d sbr=%d\n", |
|---|
| | 577 | // ppsz_otype[p_cfg->i_object_type], p_cfg->i_object_type, p_cfg->i_samplerate, p_cfg->i_channel, p_cfg->i_sbr ); |
|---|
| | 578 | |
|---|
| | 579 | i_bits = bs_pos(s) - i_pos_start; |
|---|
| | 580 | |
|---|
| | 581 | *pi_extra = ( i_bits + 7 ) / 8; |
|---|
| | 582 | for( i = 0; i < __MIN( LATM_MAX_EXTRA_SIZE, *pi_extra ); i++ ) |
|---|
| | 583 | { |
|---|
| | 584 | const int i_read = __MIN( 8, i_bits - 8*i ); |
|---|
| | 585 | p_extra[i] = bs_read( &s_sav, i_read ) << (8-i_read); |
|---|
| | 586 | } |
|---|
| | 587 | return i_bits; |
|---|
| | 588 | } |
|---|
| | 589 | |
|---|
| | 590 | static int LatmGetValue( bs_t *s ) |
|---|
| | 591 | { |
|---|
| | 592 | int i_bytes = bs_read( s, 2 ); |
|---|
| | 593 | int v = 0; |
|---|
| | 594 | int i; |
|---|
| | 595 | for( i = 0; i < i_bytes; i++ ) |
|---|
| | 596 | v = (v << 8) + bs_read( s, 8 ); |
|---|
| | 597 | |
|---|
| | 598 | return v; |
|---|
| | 599 | } |
|---|
| | 600 | |
|---|
| | 601 | static int LatmReadStreamMuxConfiguration( latm_mux_t *m, bs_t *s ) |
|---|
| | 602 | { |
|---|
| | 603 | int i_mux_version; |
|---|
| | 604 | int i_mux_versionA; |
|---|
| | 605 | int i_program; |
|---|
| | 606 | |
|---|
| | 607 | i_mux_version = bs_read( s, 1 ); |
|---|
| | 608 | i_mux_versionA = 0; |
|---|
| | 609 | if( i_mux_version ) |
|---|
| | 610 | i_mux_versionA = bs_read( s, 1 ); |
|---|
| | 611 | |
|---|
| | 612 | if( i_mux_versionA != 0 ) /* support only A=0 */ |
|---|
| | 613 | return -1; |
|---|
| | 614 | |
|---|
| | 615 | memset( m, 0, sizeof(*m) ); |
|---|
| | 616 | |
|---|
| | 617 | if( i_mux_versionA == 0 ) |
|---|
| | 618 | { |
|---|
| | 619 | if( i_mux_version == 1 ) |
|---|
| | 620 | { |
|---|
| | 621 | LatmGetValue(s); /* taraBufferFullness */ |
|---|
| | 622 | } |
|---|
| | 623 | } |
|---|
| | 624 | |
|---|
| | 625 | m->b_same_time_framing = bs_read1( s ); |
|---|
| | 626 | m->i_sub_frames = 1 + bs_read( s, 6 ); |
|---|
| | 627 | m->i_programs = 1 + bs_read( s, 4 ); |
|---|
| | 628 | |
|---|
| | 629 | for( i_program = 0; i_program < m->i_programs; i_program++ ) |
|---|
| | 630 | { |
|---|
| | 631 | int i_layer; |
|---|
| | 632 | |
|---|
| | 633 | m->pi_layers[i_program] = 1+bs_read( s, 3 ); |
|---|
| | 634 | |
|---|
| | 635 | for( i_layer = 0; i_layer < m->pi_layers[i_program]; i_layer++ ) |
|---|
| | 636 | { |
|---|
| | 637 | latm_stream_t *st = &m->stream[m->i_streams]; |
|---|
| | 638 | vlc_bool_t b_previous_cfg; |
|---|
| | 639 | |
|---|
| | 640 | m->pi_stream[i_program][i_layer] = m->i_streams; |
|---|
| | 641 | st->i_program = i_program; |
|---|
| | 642 | st->i_layer = i_layer; |
|---|
| | 643 | |
|---|
| | 644 | b_previous_cfg = VLC_FALSE; |
|---|
| | 645 | if( i_program != 0 || i_layer != 0 ) |
|---|
| | 646 | b_previous_cfg = bs_read1( s ); |
|---|
| | 647 | |
|---|
| | 648 | if( b_previous_cfg ) |
|---|
| | 649 | { |
|---|
| | 650 | assert( m->i_streams > 0 ); |
|---|
| | 651 | st->cfg = m->stream[m->i_streams-1].cfg; |
|---|
| | 652 | } |
|---|
| | 653 | else |
|---|
| | 654 | { |
|---|
| | 655 | int i_cfg_size = 0; |
|---|
| | 656 | if( i_mux_version == 1 ) |
|---|
| | 657 | i_cfg_size = LatmGetValue(s); |
|---|
| | 658 | i_cfg_size -= Mpeg4ReadAudioSpecificInfo( &st->cfg, &st->i_extra, st->extra, s, i_cfg_size ); |
|---|
| | 659 | if( i_cfg_size > 0 ) |
|---|
| | 660 | bs_skip( s, i_cfg_size ); |
|---|
| | 661 | } |
|---|
| | 662 | |
|---|
| | 663 | st->i_frame_length_type = bs_read( s, 3 ); |
|---|
| | 664 | switch( st->i_frame_length_type ) |
|---|
| | 665 | { |
|---|
| | 666 | case 0: |
|---|
| | 667 | { |
|---|
| | 668 | bs_skip( s, 8 ); /* latmBufferFullnes */ |
|---|
| | 669 | if( !m->b_same_time_framing ) |
|---|
| | 670 | { |
|---|
| | 671 | if( st->cfg.i_object_type == 6 || st->cfg.i_object_type == 20 || |
|---|
| | 672 | st->cfg.i_object_type == 8 || st->cfg.i_object_type == 24 ) |
|---|
| | 673 | { |
|---|
| | 674 | bs_skip( s, 6 ); /* eFrameOffset */ |
|---|
| | 675 | } |
|---|
| | 676 | } |
|---|
| | 677 | break; |
|---|
| | 678 | } |
|---|
| | 679 | case 1: |
|---|
| | 680 | st->i_frame_length = bs_read( s, 9 ); |
|---|
| | 681 | break; |
|---|
| | 682 | case 3: case 4: case 5: |
|---|
| | 683 | st->i_frame_length_index = bs_read( s, 6 ); // celp |
|---|
| | 684 | break; |
|---|
| | 685 | case 6: case 7: |
|---|
| | 686 | st->i_frame_length_index = bs_read( s, 1 ); // hvxc |
|---|
| | 687 | default: |
|---|
| | 688 | break; |
|---|
| | 689 | } |
|---|
| | 690 | /* Next stream */ |
|---|
| | 691 | m->i_streams++; |
|---|
| | 692 | } |
|---|
| | 693 | } |
|---|
| | 694 | |
|---|
| | 695 | /* other data */ |
|---|
| | 696 | if( bs_read1( s ) ) |
|---|
| | 697 | { |
|---|
| | 698 | if( i_mux_version == 1 ) |
|---|
| | 699 | { |
|---|
| | 700 | m->i_other_data = LatmGetValue( s ); |
|---|
| | 701 | } |
|---|
| | 702 | else |
|---|
| | 703 | { |
|---|
| | 704 | int b_continue; |
|---|
| | 705 | do { |
|---|
| | 706 | b_continue = bs_read1(s); |
|---|
| | 707 | m->i_other_data = (m->i_other_data << 8) + bs_read( s, 8 ); |
|---|
| | 708 | } while( b_continue ); |
|---|
| | 709 | } |
|---|
| | 710 | } |
|---|
| | 711 | |
|---|
| | 712 | /* crc */ |
|---|
| | 713 | m->i_crc = -1; |
|---|
| | 714 | if( bs_read1( s ) ) |
|---|
| | 715 | m->i_crc = bs_read( s, 8 ); |
|---|
| | 716 | |
|---|
| | 717 | return 0; |
|---|
| | 718 | } |
|---|
| | 719 | |
|---|
| | 720 | static int LOASParse( decoder_t *p_dec, uint8_t *p_buffer, int i_buffer ) |
|---|
| | 721 | { |
|---|
| | 722 | decoder_sys_t *p_sys = p_dec->p_sys; |
|---|
| | 723 | bs_t s; |
|---|
| | 724 | int i_sub; |
|---|
| | 725 | int i_accumulated = 0; |
|---|
| | 726 | |
|---|
| | 727 | bs_init( &s, p_buffer, i_buffer ); |
|---|
| | 728 | |
|---|
| | 729 | /* Read the stream mux configuration if present */ |
|---|
| | 730 | if( !bs_read1( &s ) ) |
|---|
| | 731 | { |
|---|
| | 732 | if( !LatmReadStreamMuxConfiguration( &p_sys->latm, &s ) && p_sys->latm.i_streams > 0 ) |
|---|
| | 733 | { |
|---|
| | 734 | const latm_stream_t *st = &p_sys->latm.stream[0]; |
|---|
| | 735 | |
|---|
| | 736 | p_sys->i_channels = st->cfg.i_channel; |
|---|
| | 737 | p_sys->i_rate = st->cfg.i_samplerate; |
|---|
| | 738 | p_sys->i_frame_length = st->cfg.i_frame_length; |
|---|
| | 739 | |
|---|
| | 740 | /* FIXME And if it changes ? */ |
|---|
| | 741 | if( !p_dec->fmt_out.i_extra && st->i_extra > 0 ) |
|---|
| | 742 | { |
|---|
| | 743 | p_dec->fmt_out.i_extra = st->i_extra; |
|---|
| | 744 | p_dec->fmt_out.p_extra = malloc( st->i_extra ); |
|---|
| | 745 | memcpy( p_dec->fmt_out.p_extra, st->extra, st->i_extra ); |
|---|
| | 746 | } |
|---|
| | 747 | |
|---|
| | 748 | p_sys->b_latm_cfg = VLC_TRUE; |
|---|
| | 749 | } |
|---|
| | 750 | } |
|---|
| | 751 | /* Wait for the configuration */ |
|---|
| | 752 | if( !p_sys->b_latm_cfg ) |
|---|
| | 753 | return -1; |
|---|
| | 754 | |
|---|
| | 755 | /* FIXME do we need to split the subframe into independant packet ? */ |
|---|
| | 756 | if( p_sys->latm.i_sub_frames > 1 ) |
|---|
| | 757 | msg_Err( p_dec, "latm sub frames not yet supported, please send a sample" ); |
|---|
| | 758 | |
|---|
| | 759 | for( i_sub = 0; i_sub < p_sys->latm.i_sub_frames; i_sub++ ) |
|---|
| | 760 | { |
|---|
| | 761 | int pi_payload[LATM_MAX_PROGRAM][LATM_MAX_LAYER]; |
|---|
| | 762 | if( p_sys->latm.b_same_time_framing ) |
|---|
| | 763 | { |
|---|
| | 764 | int i_program; |
|---|
| | 765 | /* Payload length */ |
|---|
| | 766 | for( i_program = 0; i_program < p_sys->latm.i_programs; i_program++ ) |
|---|
| | 767 | { |
|---|
| | 768 | int i_layer; |
|---|
| | 769 | for( i_layer = 0; i_layer < p_sys->latm.pi_layers[i_program]; i_layer++ ) |
|---|
| | 770 | { |
|---|
| | 771 | latm_stream_t *st = &p_sys->latm.stream[p_sys->latm.pi_stream[i_program][i_layer]]; |
|---|
| | 772 | if( st->i_frame_length_type == 0 ) |
|---|
| | 773 | { |
|---|
| | 774 | int i_payload = 0; |
|---|
| | 775 | for( ;; ) |
|---|
| | 776 | { |
|---|
| | 777 | int i_tmp = bs_read( &s, 8 ); |
|---|
| | 778 | i_payload += i_tmp; |
|---|
| | 779 | if( i_tmp != 255 ) |
|---|
| | 780 | break; |
|---|
| | 781 | } |
|---|
| | 782 | pi_payload[i_program][i_layer] = i_payload; |
|---|
| | 783 | } |
|---|
| | 784 | else if( st->i_frame_length_type == 1 ) |
|---|
| | 785 | { |
|---|
| | 786 | pi_payload[i_program][i_layer] = st->i_frame_length / 8; /* XXX not correct */ |
|---|
| | 787 | } |
|---|
| | 788 | else if( st->i_frame_length_type == 3 || st->i_frame_length_type == 5 || st->i_frame_length_type == 7 ) |
|---|
| | 789 | { |
|---|
| | 790 | bs_skip( &s, 2 ); // muxSlotLengthCoded |
|---|
| | 791 | pi_payload[i_program][i_layer] = 0; /* TODO */ |
|---|
| | 792 | } |
|---|
| | 793 | else |
|---|
| | 794 | { |
|---|
| | 795 | pi_payload[i_program][i_layer] = 0; /* TODO */ |
|---|
| | 796 | } |
|---|
| | 797 | } |
|---|
| | 798 | } |
|---|
| | 799 | /* Payload Data */ |
|---|
| | 800 | for( i_program = 0; i_program < p_sys->latm.i_programs; i_program++ ) |
|---|
| | 801 | { |
|---|
| | 802 | int i_layer; |
|---|
| | 803 | int i; |
|---|
| | 804 | for( i_layer = 0; i_layer < p_sys->latm.pi_layers[i_program]; i_layer++ ) |
|---|
| | 805 | { |
|---|
| | 806 | /* XXX we only extract 1 stream */ |
|---|
| | 807 | if( i_program != 0 || i_layer != 0 ) |
|---|
| | 808 | break; |
|---|
| | 809 | |
|---|
| | 810 | if( pi_payload[i_program][i_layer] <= 0 ) |
|---|
| | 811 | continue; |
|---|
| | 812 | |
|---|
| | 813 | /* FIXME that's slow (and a bit ugly to write in place) */ |
|---|
| | 814 | for( i = 0; i < pi_payload[i_program][i_layer]; i++ ) |
|---|
| | 815 | p_buffer[i_accumulated++] = bs_read( &s, 8 ); |
|---|
| | 816 | } |
|---|
| | 817 | } |
|---|
| | 818 | } |
|---|
| | 819 | else |
|---|
| | 820 | { |
|---|
| | 821 | const int i_chunks = bs_read( &s, 4 ); |
|---|
| | 822 | int pi_program[16]; |
|---|
| | 823 | int pi_layer[16]; |
|---|
| | 824 | int i_chunk; |
|---|
| | 825 | |
|---|
| | 826 | msg_Err( p_dec, "latm without same time frameing not yet supported, please send a sample" ); |
|---|
| | 827 | |
|---|
| | 828 | for( i_chunk = 0; i_chunk < i_chunks; i_chunk++ ) |
|---|
| | 829 | { |
|---|
| | 830 | const int streamIndex = bs_read( &s, 4 ); |
|---|
| | 831 | latm_stream_t *st = &p_sys->latm.stream[streamIndex]; |
|---|
| | 832 | const int i_program = st->i_program; |
|---|
| | 833 | const int i_layer = st->i_layer; |
|---|
| | 834 | |
|---|
| | 835 | pi_program[i_chunk] = i_program; |
|---|
| | 836 | pi_layer[i_chunk] = i_layer; |
|---|
| | 837 | |
|---|
| | 838 | if( st->i_frame_length_type == 0 ) |
|---|
| | 839 | { |
|---|
| | 840 | int i_payload = 0; |
|---|
| | 841 | for( ;; ) |
|---|
| | 842 | { |
|---|
| | 843 | int i_tmp = bs_read( &s, 8 ); |
|---|
| | 844 | i_payload += i_tmp; |
|---|
| | 845 | if( i_tmp != 255 ) |
|---|
| | 846 | break; |
|---|
| | 847 | } |
|---|
| | 848 | pi_payload[i_program][i_layer] = i_payload; |
|---|
| | 849 | bs_skip( &s, 1 ); // auEndFlag |
|---|
| | 850 | } |
|---|
| | 851 | else if( st->i_frame_length_type == 1 ) |
|---|
| | 852 | { |
|---|
| | 853 | pi_payload[i_program][i_layer] = st->i_frame_length / 8; /* XXX not correct */ |
|---|
| | 854 | } |
|---|
| | 855 | else if( st->i_frame_length_type == 3 || st->i_frame_length_type == 5 || st->i_frame_length_type == 7 ) |
|---|
| | 856 | { |
|---|
| | 857 | bs_read( &s, 2 ); // muxSlotLengthCoded |
|---|
| | 858 | } |
|---|
| | 859 | else |
|---|
| | 860 | { |
|---|
| | 861 | } |
|---|
| | 862 | } |
|---|
| | 863 | for( i_chunk = 0; i_chunk < i_chunks; i_chunk++ ) |
|---|
| | 864 | { |
|---|
| | 865 | //const int i_program = pi_program[i_chunk]; |
|---|
| | 866 | //const int i_layer = pi_layer[i_chunk]; |
|---|
| | 867 | |
|---|
| | 868 | /* TODO ? Payload */ |
|---|
| | 869 | } |
|---|
| | 870 | } |
|---|
| | 871 | } |
|---|
| | 872 | |
|---|
| | 873 | if( p_sys->latm.i_other_data > 0 ) |
|---|
| | 874 | { |
|---|
| | 875 | /* Other data XXX we just ignore them */ |
|---|
| | 876 | } |
|---|
| | 877 | bs_align( &s ); |
|---|
| | 878 | |
|---|
| | 879 | return i_accumulated; |
|---|
| | 880 | } |
|---|
| | 881 | |
|---|
| | 882 | /**************************************************************************** |
|---|
| | 883 | * PacketizeStreamBlock: ADTS/LOAS packetizer |
|---|
| | 884 | ****************************************************************************/ |
|---|
| | 885 | static void SetupOutput( decoder_t *p_dec, block_t *p_block ); |
|---|
| | 886 | static block_t *PacketizeStreamBlock( decoder_t *p_dec, block_t **pp_block ) |
|---|
| | 887 | { |
|---|
| | 888 | decoder_sys_t *p_sys = p_dec->p_sys; |
|---|
| | 889 | uint8_t p_header[ADTS_HEADER_SIZE + LOAS_HEADER_SIZE]; |
|---|
| | 890 | block_t *p_out_buffer; |
|---|
| | 891 | uint8_t *p_buf; |
|---|
| | 892 | |
|---|
| | 893 | if( !pp_block || !*pp_block ) return NULL; |
|---|
| | 894 | |
|---|
| | 895 | if( (*pp_block)->i_flags&(BLOCK_FLAG_DISCONTINUITY|BLOCK_FLAG_CORRUPTED) ) |
|---|
| | 896 | { |
|---|
| | 897 | if( (*pp_block)->i_flags&BLOCK_FLAG_CORRUPTED ) |
|---|
| | 898 | { |
|---|
| | 899 | p_sys->i_state = STATE_NOSYNC; |
|---|
| | 900 | block_BytestreamFlush( &p_sys->bytestream ); < |
|---|