📄 mpeg4audio.c
字号:
} /* Wait for the configuration */ if( !p_sys->b_latm_cfg ) return 0; /* FIXME do we need to split the subframe into independent packet ? */ if( p_sys->latm.i_sub_frames > 1 ) msg_Err( p_dec, "latm sub frames not yet supported, please send a sample" ); for( i_sub = 0; i_sub < p_sys->latm.i_sub_frames; i_sub++ ) { int pi_payload[LATM_MAX_PROGRAM][LATM_MAX_LAYER]; if( p_sys->latm.b_same_time_framing ) { int i_program; /* Payload length */ for( i_program = 0; i_program < p_sys->latm.i_programs; i_program++ ) { int i_layer; for( i_layer = 0; i_layer < p_sys->latm.pi_layers[i_program]; i_layer++ ) { latm_stream_t *st = &p_sys->latm.stream[p_sys->latm.pi_stream[i_program][i_layer]]; if( st->i_frame_length_type == 0 ) { int i_payload = 0; for( ;; ) { int i_tmp = bs_read( &s, 8 ); i_payload += i_tmp; if( i_tmp != 255 ) break; } pi_payload[i_program][i_layer] = i_payload; } else if( st->i_frame_length_type == 1 ) { pi_payload[i_program][i_layer] = st->i_frame_length / 8; /* XXX not correct */ } else if( ( st->i_frame_length_type == 3 ) || ( st->i_frame_length_type == 5 ) || ( st->i_frame_length_type == 7 ) ) { bs_skip( &s, 2 ); // muxSlotLengthCoded pi_payload[i_program][i_layer] = 0; /* TODO */ } else { pi_payload[i_program][i_layer] = 0; /* TODO */ } } } /* Payload Data */ for( i_program = 0; i_program < p_sys->latm.i_programs; i_program++ ) { int i_layer; int i; for( i_layer = 0; i_layer < p_sys->latm.pi_layers[i_program]; i_layer++ ) { /* XXX we only extract 1 stream */ if( i_program != 0 || i_layer != 0 ) break; if( pi_payload[i_program][i_layer] <= 0 ) continue; /* FIXME that's slow (and a bit ugly to write in place) */ for( i = 0; i < pi_payload[i_program][i_layer]; i++ ) p_buffer[i_accumulated++] = bs_read( &s, 8 ); } } } else { const int i_chunks = bs_read( &s, 4 ); int pi_program[16]; int pi_layer[16]; int i_chunk; msg_Err( p_dec, "latm without same time frameing not yet supported, please send a sample" ); for( i_chunk = 0; i_chunk < i_chunks; i_chunk++ ) { const int streamIndex = bs_read( &s, 4 ); latm_stream_t *st = &p_sys->latm.stream[streamIndex]; const int i_program = st->i_program; const int i_layer = st->i_layer; pi_program[i_chunk] = i_program; pi_layer[i_chunk] = i_layer; if( st->i_frame_length_type == 0 ) { int i_payload = 0; for( ;; ) { int i_tmp = bs_read( &s, 8 ); i_payload += i_tmp; if( i_tmp != 255 ) break; } pi_payload[i_program][i_layer] = i_payload; bs_skip( &s, 1 ); // auEndFlag } else if( st->i_frame_length_type == 1 ) { pi_payload[i_program][i_layer] = st->i_frame_length / 8; /* XXX not correct */ } else if( ( st->i_frame_length_type == 3 ) || ( st->i_frame_length_type == 5 ) || ( st->i_frame_length_type == 7 ) ) { bs_read( &s, 2 ); // muxSlotLengthCoded } else { } } for( i_chunk = 0; i_chunk < i_chunks; i_chunk++ ) { //const int i_program = pi_program[i_chunk]; //const int i_layer = pi_layer[i_chunk]; /* TODO ? Payload */ } } } if( p_sys->latm.i_other_data > 0 ) { /* Other data XXX we just ignore them */ } bs_align( &s ); return i_accumulated;}/**************************************************************************** * PacketizeStreamBlock: ADTS/LOAS packetizer ****************************************************************************/static void SetupOutput( decoder_t *p_dec, block_t *p_block );static block_t *PacketizeStreamBlock( decoder_t *p_dec, block_t **pp_block ){ decoder_sys_t *p_sys = p_dec->p_sys; uint8_t p_header[ADTS_HEADER_SIZE + LOAS_HEADER_SIZE]; block_t *p_out_buffer; uint8_t *p_buf; if( !pp_block || !*pp_block ) return NULL; if( (*pp_block)->i_flags&(BLOCK_FLAG_DISCONTINUITY|BLOCK_FLAG_CORRUPTED) ) { if( (*pp_block)->i_flags&BLOCK_FLAG_CORRUPTED ) { p_sys->i_state = STATE_NOSYNC; block_BytestreamFlush( &p_sys->bytestream ); } //aout_DateSet( &p_sys->end_date, 0 ); block_Release( *pp_block ); return NULL; } if( !aout_DateGet( &p_sys->end_date ) && !(*pp_block)->i_pts ) { /* We've just started the stream, wait for the first PTS. */ block_Release( *pp_block ); return NULL; } if( (*pp_block)->i_rate > 0 ) p_sys->i_input_rate = (*pp_block)->i_rate; block_BytestreamPush( &p_sys->bytestream, *pp_block ); for( ;; ) { switch( p_sys->i_state ) { case STATE_NOSYNC: while( block_PeekBytes( &p_sys->bytestream, p_header, 2 ) == VLC_SUCCESS ) { /* Look for sync word - should be 0xfff(adts) or 0x2b7(loas) */ if( p_header[0] == 0xff && (p_header[1] & 0xf6) == 0xf0 ) { if( p_sys->i_type != TYPE_ADTS ) msg_Dbg( p_dec, "detected ADTS format" ); p_sys->i_state = STATE_SYNC; p_sys->i_type = TYPE_ADTS; break; } else if( p_header[0] == 0x56 && (p_header[1] & 0xe0) == 0xe0 ) { if( p_sys->i_type != TYPE_LOAS ) msg_Dbg( p_dec, "detected LOAS format" ); p_sys->i_state = STATE_SYNC; p_sys->i_type = TYPE_LOAS; break; } block_SkipByte( &p_sys->bytestream ); } if( p_sys->i_state != STATE_SYNC ) { block_BytestreamFlush( &p_sys->bytestream ); /* Need more data */ return NULL; } case STATE_SYNC: /* New frame, set the Presentation Time Stamp */ p_sys->i_pts = p_sys->bytestream.p_block->i_pts; if( p_sys->i_pts != 0 && p_sys->i_pts != aout_DateGet( &p_sys->end_date ) ) { aout_DateSet( &p_sys->end_date, p_sys->i_pts ); } p_sys->i_state = STATE_HEADER; break; case STATE_HEADER: if( p_sys->i_type == TYPE_ADTS ) { /* Get ADTS frame header (ADTS_HEADER_SIZE bytes) */ if( block_PeekBytes( &p_sys->bytestream, p_header, ADTS_HEADER_SIZE ) != VLC_SUCCESS ) { /* Need more data */ return NULL; } /* Check if frame is valid and get frame info */ p_sys->i_frame_size = ADTSSyncInfo( p_dec, p_header, &p_sys->i_channels, &p_sys->i_rate, &p_sys->i_frame_length, &p_sys->i_header_size ); } else { assert( p_sys->i_type == TYPE_LOAS ); /* Get LOAS frame header (LOAS_HEADER_SIZE bytes) */ if( block_PeekBytes( &p_sys->bytestream, p_header, LOAS_HEADER_SIZE ) != VLC_SUCCESS ) { /* Need more data */ return NULL; } /* Check if frame is valid and get frame info */ p_sys->i_frame_size = LOASSyncInfo( p_header, &p_sys->i_header_size ); } if( p_sys->i_frame_size <= 0 ) { msg_Dbg( p_dec, "emulated sync word" ); block_SkipByte( &p_sys->bytestream ); p_sys->i_state = STATE_NOSYNC; break; } p_sys->i_state = STATE_NEXT_SYNC; case STATE_NEXT_SYNC: /* TODO: If p_block == NULL, flush the buffer without checking the * next sync word */ if( p_sys->bytestream.p_block == NULL ) { p_sys->i_state = STATE_NOSYNC; block_BytestreamFlush( &p_sys->bytestream ); return NULL; } /* Check if next expected frame contains the sync word */ if( block_PeekOffsetBytes( &p_sys->bytestream, p_sys->i_frame_size + p_sys->i_header_size, p_header, 2 ) != VLC_SUCCESS ) { /* Need more data */ return NULL; } assert( (p_sys->i_type == TYPE_ADTS) || (p_sys->i_type == TYPE_LOAS) ); if( ( ( p_sys->i_type == TYPE_ADTS ) && ( p_header[0] != 0xff || (p_header[1] & 0xf6) != 0xf0 ) ) || ( ( p_sys->i_type == TYPE_LOAS ) && ( p_header[0] != 0x56 || (p_header[1] & 0xe0) != 0xe0 ) ) ) { msg_Dbg( p_dec, "emulated sync word " "(no sync on following frame)" ); p_sys->i_state = STATE_NOSYNC; block_SkipByte( &p_sys->bytestream ); break; } p_sys->i_state = STATE_SEND_DATA; break; case STATE_GET_DATA: /* Make sure we have enough data. * (Not useful if we went through NEXT_SYNC) */ if( block_WaitBytes( &p_sys->bytestream, p_sys->i_frame_size + p_sys->i_header_size) != VLC_SUCCESS ) { /* Need more data */ return NULL; } p_sys->i_state = STATE_SEND_DATA; case STATE_SEND_DATA: /* When we reach this point we already know we have enough * data available. */ p_out_buffer = block_New( p_dec, p_sys->i_frame_size ); if( !p_out_buffer ) { //p_dec->b_error = true; return NULL; } p_buf = p_out_buffer->p_buffer; /* Skip the ADTS/LOAS header */ block_SkipBytes( &p_sys->bytestream, p_sys->i_header_size ); if( p_sys->i_type == TYPE_ADTS ) { /* Copy the whole frame into the buffer */ block_GetBytes( &p_sys->bytestream, p_buf, p_sys->i_frame_size ); } else { assert( p_sys->i_type == TYPE_LOAS ); /* Copy the whole frame into the buffer and parse/extract it */ block_GetBytes( &p_sys->bytestream, p_buf, p_sys->i_frame_size ); p_out_buffer->i_buffer = LOASParse( p_dec, p_buf, p_sys->i_frame_size ); if( p_out_buffer->i_buffer <= 0 ) { if( !p_sys->b_latm_cfg ) msg_Warn( p_dec, "waiting for header" ); block_Release( p_out_buffer ); p_out_buffer = NULL; p_sys->i_state = STATE_NOSYNC; break; } } SetupOutput( p_dec, p_out_buffer ); /* Make sure we don't reuse the same pts twice */ if( p_sys->i_pts == p_sys->bytestream.p_block->i_pts ) p_sys->i_pts = p_sys->bytestream.p_block->i_pts = 0; /* So p_block doesn't get re-added several times */ *pp_block = block_BytestreamPop( &p_sys->bytestream ); p_sys->i_state = STATE_NOSYNC; return p_out_buffer; } } return NULL;}/***************************************************************************** * SetupBuffer: *****************************************************************************/static void SetupOutput( decoder_t *p_dec, block_t *p_block ){ decoder_sys_t *p_sys = p_dec->p_sys; if( p_dec->fmt_out.audio.i_rate != p_sys->i_rate ) { msg_Info( p_dec, "AAC channels: %d samplerate: %d", p_sys->i_channels, p_sys->i_rate ); aout_DateInit( &p_sys->end_date, p_sys->i_rate ); aout_DateSet( &p_sys->end_date, p_sys->i_pts ); } p_dec->fmt_out.audio.i_rate = p_sys->i_rate; p_dec->fmt_out.audio.i_channels = p_sys->i_channels; p_dec->fmt_out.audio.i_bytes_per_frame = p_sys->i_frame_size; p_dec->fmt_out.audio.i_frame_length = p_sys->i_frame_length;#if 0 p_dec->fmt_out.audio.i_original_channels = p_sys->i_channels_conf; p_dec->fmt_out.audio.i_physical_channels = p_sys->i_channels_conf & AOUT_CHAN_PHYSMASK;#endif p_block->i_pts = p_block->i_dts = aout_DateGet( &p_sys->end_date ); p_block->i_length = aout_DateIncrement( &p_sys->end_date, p_sys->i_frame_length * p_sys->i_input_rate / INPUT_RATE_DEFAULT ) - p_block->i_pts;}/***************************************************************************** * ClosePacketizer: clean up the packetizer *****************************************************************************/static void ClosePacketizer( vlc_object_t *p_this ){ decoder_t *p_dec = (decoder_t *)p_this; decoder_sys_t *p_sys = p_dec->p_sys; block_BytestreamRelease( &p_sys->bytestream ); free( p_dec->p_sys );}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -