Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
V
vlc
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Redmine
Redmine
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Operations
Operations
Metrics
Environments
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
videolan
vlc
Commits
734d1871
Commit
734d1871
authored
Mar 31, 2008
by
Jean-Paul Saman
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Backport recent AAC (ADTS) fixes from 0.9.0
parent
000d98c2
Changes
1
Show whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
852 additions
and
117 deletions
+852
-117
modules/packetizer/mpeg4audio.c
modules/packetizer/mpeg4audio.c
+852
-117
No files found.
modules/packetizer/mpeg4audio.c
View file @
734d1871
...
...
@@ -2,7 +2,7 @@
* mpeg4audio.c: parse and packetize an MPEG 4 audio stream
*****************************************************************************
* Copyright (C) 2001, 2002, 2006 the VideoLAN team
* $Id$
* $Id
: ab5d5956d4738080904edb28e2d08eaf394da1be
$
*
* Authors: Laurent Aimar <fenrir@via.ecp.fr>
* Gildas Bazin <gbazin@netcourrier.com>
...
...
@@ -27,12 +27,15 @@
*****************************************************************************/
#include <stdlib.h>
/* malloc(), free() */
#include <string.h>
/* strdup() */
#include <assert.h>
#include <vlc/vlc.h>
#include <vlc/aout.h>
#include <vlc/decoder.h>
#include <vlc/input.h>
#include <vlc/sout.h>
#include <vlc_block.h>
#include <vlc_bits.h>
#include "codecs.h"
#include "vlc_block_helper.h"
...
...
@@ -53,12 +56,68 @@
/*****************************************************************************
* decoder_sys_t : decoder descriptor
*****************************************************************************/
typedef
struct
{
int
i_object_type
;
int
i_samplerate
;
int
i_channel
;
int
i_sbr
;
// 0: no sbr, 1: sbr, -1: unknown
struct
{
int
i_object_type
;
int
i_samplerate
;
}
extension
;
/* GASpecific */
int
i_frame_length
;
// 1024 or 960
}
mpeg4_cfg_t
;
#define LATM_MAX_EXTRA_SIZE 64
typedef
struct
{
int
i_program
;
int
i_layer
;
int
i_frame_length_type
;
int
i_frame_length
;
// type 1
int
i_frame_length_index
;
// type 3 4 5 6 7
mpeg4_cfg_t
cfg
;
/* Raw configuration */
int
i_extra
;
uint8_t
extra
[
LATM_MAX_EXTRA_SIZE
];
}
latm_stream_t
;
#define LATM_MAX_LAYER (8)
#define LATM_MAX_PROGRAM (16)
typedef
struct
{
int
b_same_time_framing
;
int
i_sub_frames
;
int
i_programs
;
int
pi_layers
[
LATM_MAX_PROGRAM
];
int
pi_stream
[
LATM_MAX_PROGRAM
][
LATM_MAX_LAYER
];
int
i_streams
;
latm_stream_t
stream
[
LATM_MAX_PROGRAM
*
LATM_MAX_LAYER
];
int
i_other_data
;
int
i_crc
;
/* -1 if not set */
}
latm_mux_t
;
struct
decoder_sys_t
{
/*
* Input properties
*/
int
i_state
;
int
i_type
;
block_bytestream_t
bytestream
;
...
...
@@ -68,13 +127,18 @@ struct decoder_sys_t
audio_date_t
end_date
;
mtime_t
i_pts
;
int
i_frame_size
,
i_raw_blocks
;
int
i_frame_size
;
unsigned
int
i_channels
;
unsigned
int
i_rate
,
i_frame_length
,
i_header_size
;
int
i_input_rate
;
/* LOAS */
vlc_bool_t
b_latm_cfg
;
latm_mux_t
latm
;
};
enum
{
STATE_NOSYNC
,
STATE_SYNC
,
STATE_HEADER
,
...
...
@@ -83,13 +147,21 @@ enum {
STATE_SEND_DATA
};
static
int
i_sample_rates
[]
=
enum
{
TYPE_NONE
,
TYPE_RAW
,
TYPE_ADTS
,
TYPE_LOAS
};
static
const
int
pi_sample_rates
[
16
]
=
{
96000
,
88200
,
64000
,
48000
,
44100
,
32000
,
24000
,
22050
,
16000
,
12000
,
11025
,
8000
,
7350
,
0
,
0
,
0
};
#define ADTS_HEADER_SIZE 9
#define LOAS_HEADER_SIZE 3
/****************************************************************************
* Local prototypes
...
...
@@ -97,17 +169,8 @@ static int i_sample_rates[] =
static
int
OpenPacketizer
(
vlc_object_t
*
);
static
void
ClosePacketizer
(
vlc_object_t
*
);
static
block_t
*
PacketizeBlock
(
decoder_t
*
,
block_t
**
);
static
block_t
*
ADTSPacketizeBlock
(
decoder_t
*
,
block_t
**
);
static
uint8_t
*
GetOutBuffer
(
decoder_t
*
,
void
**
);
static
int
ADTSSyncInfo
(
decoder_t
*
,
const
byte_t
*
p_buf
,
unsigned
int
*
pi_channels
,
unsigned
int
*
pi_sample_rate
,
unsigned
int
*
pi_frame_length
,
unsigned
int
*
pi_header_size
,
unsigned
int
*
pi_raw_blocks
);
static
block_t
*
PacketizeRawBlock
(
decoder_t
*
,
block_t
**
);
static
block_t
*
PacketizeStreamBlock
(
decoder_t
*
,
block_t
**
);
/*****************************************************************************
* Module descriptor
...
...
@@ -145,14 +208,13 @@ static int OpenPacketizer( vlc_object_t *p_this )
p_sys
->
i_state
=
STATE_NOSYNC
;
aout_DateSet
(
&
p_sys
->
end_date
,
0
);
p_sys
->
bytestream
=
block_BytestreamInit
(
p_dec
);
p_sys
->
i_input_rate
=
INPUT_RATE_DEFAULT
;
p_sys
->
b_latm_cfg
=
VLC_FALSE
;
/* Set output properties */
p_dec
->
fmt_out
.
i_cat
=
AUDIO_ES
;
p_dec
->
fmt_out
.
i_codec
=
VLC_FOURCC
(
'm'
,
'p'
,
'4'
,
'a'
);
/* Set callback */
p_dec
->
pf_packetize
=
PacketizeBlock
;
msg_Dbg
(
p_dec
,
"running MPEG4 audio packetizer"
);
if
(
p_dec
->
fmt_in
.
i_extra
>
0
)
...
...
@@ -163,7 +225,7 @@ static int OpenPacketizer( vlc_object_t *p_this )
i_index
=
(
(
p_config
[
0
]
<<
1
)
|
(
p_config
[
1
]
>>
7
)
)
&
0x0f
;
if
(
i_index
!=
0x0f
)
{
p_dec
->
fmt_out
.
audio
.
i_rate
=
i_sample_rates
[
i_index
];
p_dec
->
fmt_out
.
audio
.
i_rate
=
p
i_sample_rates
[
i_index
];
p_dec
->
fmt_out
.
audio
.
i_frame_length
=
((
p_config
[
1
]
>>
2
)
&
0x01
)
?
960
:
1024
;
}
...
...
@@ -176,45 +238,66 @@ static int OpenPacketizer( vlc_object_t *p_this )
((
p_config
[
4
]
>>
2
)
&
0x01
)
?
960
:
1024
;
}
p_dec
->
fmt_out
.
audio
.
i_channels
=
(
p_config
[
i_index
==
0x0f
?
4
:
1
]
>>
3
)
&
0x0f
;
msg_Dbg
(
p_dec
,
"AAC %dHz %d samples/frame"
,
p_dec
->
fmt_out
.
audio
.
i_rate
,
p_dec
->
fmt_out
.
audio
.
i_frame_length
);
aout_DateInit
(
&
p_sys
->
end_date
,
p_dec
->
fmt_out
.
audio
.
i_rate
);
p_dec
->
fmt_out
.
audio
.
i_channels
=
p_dec
->
fmt_in
.
audio
.
i_channels
;
p_dec
->
fmt_out
.
i_extra
=
p_dec
->
fmt_in
.
i_extra
;
p_dec
->
fmt_out
.
p_extra
=
malloc
(
p_dec
->
fmt_in
.
i_extra
);
if
(
!
p_dec
->
fmt_out
.
p_extra
)
{
p_dec
->
fmt_out
.
i_extra
=
0
;
return
VLC_ENOMEM
;
}
memcpy
(
p_dec
->
fmt_out
.
p_extra
,
p_dec
->
fmt_in
.
p_extra
,
p_dec
->
fmt_in
.
i_extra
);
/* Set callback */
p_dec
->
pf_packetize
=
PacketizeRawBlock
;
p_sys
->
i_type
=
TYPE_RAW
;
}
else
{
msg_Dbg
(
p_dec
,
"no decoder specific info, must be an ADTS stream"
);
msg_Dbg
(
p_dec
,
"no decoder specific info, must be an ADTS
or LOAS
stream"
);
aout_DateInit
(
&
p_sys
->
end_date
,
p_dec
->
fmt_in
.
audio
.
i_rate
);
/* We will try to create a AAC Config from adts */
/* We will try to create a AAC Config from adts
/loas
*/
p_dec
->
fmt_out
.
i_extra
=
0
;
p_dec
->
fmt_out
.
p_extra
=
NULL
;
p_dec
->
pf_packetize
=
ADTSPacketizeBlock
;
/* Set callback */
p_dec
->
pf_packetize
=
PacketizeStreamBlock
;
p_sys
->
i_type
=
TYPE_NONE
;
}
return
VLC_SUCCESS
;
}
/****************************************************************************
* PacketizeBlock: the whole thing
* Packetize
Raw
Block: the whole thing
****************************************************************************
* This function must be fed with complete frames.
****************************************************************************/
static
block_t
*
PacketizeBlock
(
decoder_t
*
p_dec
,
block_t
**
pp_block
)
static
block_t
*
Packetize
Raw
Block
(
decoder_t
*
p_dec
,
block_t
**
pp_block
)
{
decoder_sys_t
*
p_sys
=
p_dec
->
p_sys
;
block_t
*
p_block
;
if
(
!
pp_block
||
!*
pp_block
)
return
NULL
;
if
(
(
*
pp_block
)
->
i_flags
&
(
BLOCK_FLAG_DISCONTINUITY
|
BLOCK_FLAG_CORRUPTED
)
)
{
//aout_DateSet( &p_sys->end_date, 0 );
block_Release
(
*
pp_block
);
return
NULL
;
}
p_block
=
*
pp_block
;
*
pp_block
=
NULL
;
/* Don't reuse this block */
...
...
@@ -233,38 +316,685 @@ static block_t *PacketizeBlock( decoder_t *p_dec, block_t **pp_block )
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_dec
->
fmt_out
.
audio
.
i_frame_length
)
-
p_block
->
i_pts
;
p_dec
->
fmt_out
.
audio
.
i_frame_length
*
p_sys
->
i_input_rate
/
INPUT_RATE_DEFAULT
)
-
p_block
->
i_pts
;
return
p_block
;
}
/****************************************************************************
* DTSPacketizeBlock: the whole thing
* ADTS helpers
****************************************************************************/
static
int
ADTSSyncInfo
(
decoder_t
*
p_dec
,
const
byte_t
*
p_buf
,
unsigned
int
*
pi_channels
,
unsigned
int
*
pi_sample_rate
,
unsigned
int
*
pi_frame_length
,
unsigned
int
*
pi_header_size
)
{
int
i_profile
,
i_sample_rate_idx
,
i_frame_size
;
vlc_bool_t
b_crc
;
/* Fixed header between frames */
//int i_id = ( (p_buf[1] >> 3) & 0x01) ? 2 : 4; /* MPEG-2 or 4 */
b_crc
=
!
(
p_buf
[
1
]
&
0x01
);
i_profile
=
p_buf
[
2
]
>>
6
;
i_sample_rate_idx
=
(
p_buf
[
2
]
>>
2
)
&
0x0f
;
*
pi_sample_rate
=
pi_sample_rates
[
i_sample_rate_idx
];
//private_bit = (p_buf[2] >> 1) & 0x01;
*
pi_channels
=
((
p_buf
[
2
]
&
0x01
)
<<
2
)
|
((
p_buf
[
3
]
>>
6
)
&
0x03
);
//original_copy = (p_buf[3] >> 5) & 0x01;
//home = (p_buf[3] >> 4) & 0x01;
/* Variable header */
//copyright_id_bit = (p_buf[3] >> 3) & 0x01;
//copyright_id_start = (p_buf[3] >> 2) & 0x01;
i_frame_size
=
((
p_buf
[
3
]
&
0x03
)
<<
11
)
|
(
p_buf
[
4
]
<<
3
)
|
((
p_buf
[
5
]
>>
5
)
/*& 0x7*/
);
//uint16_t buffer_fullness = ((p_buf[5] & 0x1f) << 6) | (p_buf[6] >> 2);
unsigned
short
i_raw_blocks_in_frame
=
p_buf
[
6
]
&
0x03
;
if
(
!*
pi_sample_rate
||
!*
pi_channels
||
!
i_frame_size
)
{
msg_Warn
(
p_dec
,
"Invalid ADTS header"
);
return
0
;
}
*
pi_frame_length
=
1024
;
if
(
i_raw_blocks_in_frame
==
0
)
{
if
(
b_crc
)
{
msg_Warn
(
p_dec
,
"ADTS CRC not supported"
);
//uint16_t crc = (p_buf[7] << 8) | p_buf[8];
}
}
else
{
msg_Err
(
p_dec
,
"Multiple blocks per frame in ADTS not supported"
);
return
0
;
#if 0
int i;
const uint8_t *p_pos = p_buf + 7;
uint16_t crc_block;
uint16_t i_block_pos[3];
if( b_crc )
{
for( i = 0 ; i < i_raw_blocks_in_frame ; i++ )
{ /* the 1st block's position is known ... */
i_block_pos[i] = (*p_pos << 8) | *(p_pos+1);
p_pos += 2;
}
crc_block = (*p_pos << 8) | *(p_pos+1);
p_pos += 2;
}
for( i = 0 ; i <= i_raw_blocks_in_frame ; i++ )
{
//read 1 block
if( b_crc )
{
msg_Err( p_dec, "ADTS CRC not supported" );
//uint16_t crc = (*p_pos << 8) | *(p_pos+1);
//p_pos += 2;
}
}
#endif
}
/* Build the decoder specific info header */
if
(
!
p_dec
->
fmt_out
.
i_extra
)
{
p_dec
->
fmt_out
.
p_extra
=
malloc
(
2
);
if
(
!
p_dec
->
fmt_out
.
p_extra
)
{
p_dec
->
fmt_out
.
i_extra
=
0
;
return
0
;
}
p_dec
->
fmt_out
.
i_extra
=
2
;
((
uint8_t
*
)
p_dec
->
fmt_out
.
p_extra
)[
0
]
=
(
i_profile
+
1
)
<<
3
|
(
i_sample_rate_idx
>>
1
);
((
uint8_t
*
)
p_dec
->
fmt_out
.
p_extra
)[
1
]
=
((
i_sample_rate_idx
&
0x01
)
<<
7
)
|
(
*
pi_channels
<<
3
);
}
/* ADTS header length */
*
pi_header_size
=
b_crc
?
9
:
7
;
return
i_frame_size
-
*
pi_header_size
;
}
/****************************************************************************
* LOAS helpers
****************************************************************************/
static
int
LOASSyncInfo
(
uint8_t
p_header
[
LOAS_HEADER_SIZE
],
unsigned
int
*
pi_header_size
)
{
*
pi_header_size
=
3
;
return
(
(
p_header
[
1
]
&
0x1f
)
<<
8
)
+
p_header
[
2
];
}
static
int
Mpeg4GAProgramConfigElement
(
bs_t
*
s
)
{
/* TODO compute channels count ? */
int
i_tag
=
bs_read
(
s
,
4
);
if
(
i_tag
!=
0x05
)
return
-
1
;
bs_skip
(
s
,
2
+
4
);
// object type + sampling index
int
i_num_front
=
bs_read
(
s
,
4
);
int
i_num_side
=
bs_read
(
s
,
4
);
int
i_num_back
=
bs_read
(
s
,
4
);
int
i_num_lfe
=
bs_read
(
s
,
2
);
int
i_num_assoc_data
=
bs_read
(
s
,
3
);
int
i_num_valid_cc
=
bs_read
(
s
,
4
);
if
(
bs_read1
(
s
)
)
bs_skip
(
s
,
4
);
// mono downmix
if
(
bs_read1
(
s
)
)
bs_skip
(
s
,
4
);
// stereo downmix
if
(
bs_read1
(
s
)
)
bs_skip
(
s
,
2
+
1
);
// matrix downmix + pseudo_surround
bs_skip
(
s
,
i_num_front
*
(
1
+
4
)
);
bs_skip
(
s
,
i_num_side
*
(
1
+
4
)
);
bs_skip
(
s
,
i_num_back
*
(
1
+
4
)
);
bs_skip
(
s
,
i_num_lfe
*
(
4
)
);
bs_skip
(
s
,
i_num_assoc_data
*
(
4
)
);
bs_skip
(
s
,
i_num_valid_cc
*
(
5
)
);
bs_align
(
s
);
int
i_comment
=
bs_read
(
s
,
8
);
bs_skip
(
s
,
i_comment
*
8
);
return
0
;
}
static
int
Mpeg4GASpecificConfig
(
mpeg4_cfg_t
*
p_cfg
,
bs_t
*
s
)
{
p_cfg
->
i_frame_length
=
bs_read1
(
s
)
?
960
:
1024
;
if
(
bs_read1
(
s
)
)
// depend on core coder
bs_skip
(
s
,
14
);
// core coder delay
int
i_extension_flag
=
bs_read1
(
s
);
if
(
p_cfg
->
i_channel
==
0
)
{
Mpeg4GAProgramConfigElement
(
s
);
}
if
(
p_cfg
->
i_object_type
==
6
||
p_cfg
->
i_object_type
==
20
)
bs_skip
(
s
,
3
);
// layer
if
(
i_extension_flag
)
{
if
(
p_cfg
->
i_object_type
==
22
)
{
bs_skip
(
s
,
5
+
11
);
// numOfSubFrame + layer length
}
if
(
p_cfg
->
i_object_type
==
17
||
p_cfg
->
i_object_type
==
19
||
p_cfg
->
i_object_type
==
20
||
p_cfg
->
i_object_type
==
23
)
{
bs_skip
(
s
,
1
+
1
+
1
);
// ER data : section scale spectral */
}
if
(
bs_read1
(
s
)
)
// extension 3
fprintf
(
stderr
,
"Mpeg4GASpecificConfig: error 1
\n
"
);
}
return
0
;
}
static
int
Mpeg4ReadAudioObjectType
(
bs_t
*
s
)
{
int
i_type
=
bs_read
(
s
,
5
);
if
(
i_type
==
0x1f
)
i_type
+=
bs_read
(
s
,
6
);
return
i_type
;
}
static
int
Mpeg4ReadAudioSamplerate
(
bs_t
*
s
)
{
int
i_index
=
bs_read
(
s
,
4
);
if
(
i_index
!=
0x0f
)
return
pi_sample_rates
[
i_index
];
return
bs_read
(
s
,
24
);
}
static
int
Mpeg4ReadAudioSpecificInfo
(
mpeg4_cfg_t
*
p_cfg
,
int
*
pi_extra
,
uint8_t
*
p_extra
,
bs_t
*
s
,
int
i_max_size
)
{
#if 0
static const char *ppsz_otype[] = {
"NULL",
"AAC Main", "AAC LC", "AAC SSR", "AAC LTP", "SBR", "AAC Scalable",
"TwinVQ",
"CELP", "HVXC",
"Reserved", "Reserved",
"TTSI",
"Main Synthetic", "Wavetables Synthesis", "General MIDI",
"Algorithmic Synthesis and Audio FX",
"ER AAC LC",
"Reserved",
"ER AAC LTP", "ER AAC Scalable", "ER TwinVQ", "ER BSAC", "ER AAC LD",
"ER CELP", "ER HVXC", "ER HILN", "ER Parametric",
"SSC",
"Reserved", "Reserved", "Escape",
"Layer 1", "Layer 2", "Layer 3",
"DST",
};
#endif
const
int
i_pos_start
=
bs_pos
(
s
);
bs_t
s_sav
=
*
s
;
int
i_bits
;
int
i
;
memset
(
p_cfg
,
0
,
sizeof
(
*
p_cfg
)
);
*
pi_extra
=
0
;
p_cfg
->
i_object_type
=
Mpeg4ReadAudioObjectType
(
s
);
p_cfg
->
i_samplerate
=
Mpeg4ReadAudioSamplerate
(
s
);
p_cfg
->
i_channel
=
bs_read
(
s
,
4
);
if
(
p_cfg
->
i_channel
==
7
)
p_cfg
->
i_channel
=
8
;
// 7.1
else
if
(
p_cfg
->
i_channel
>=
8
)
p_cfg
->
i_channel
=
-
1
;
p_cfg
->
i_sbr
=
-
1
;
p_cfg
->
extension
.
i_object_type
=
0
;
p_cfg
->
extension
.
i_samplerate
=
0
;
if
(
p_cfg
->
i_object_type
==
5
)
{
p_cfg
->
i_sbr
=
1
;
p_cfg
->
extension
.
i_object_type
=
p_cfg
->
i_object_type
;
p_cfg
->
extension
.
i_samplerate
=
Mpeg4ReadAudioSamplerate
(
s
);
p_cfg
->
i_object_type
=
Mpeg4ReadAudioObjectType
(
s
);
}
switch
(
p_cfg
->
i_object_type
)
{
case
1
:
case
2
:
case
3
:
case
4
:
case
6
:
case
7
:
case
17
:
case
19
:
case
20
:
case
21
:
case
22
:
case
23
:
Mpeg4GASpecificConfig
(
p_cfg
,
s
);
break
;
case
8
:
// CelpSpecificConfig();
break
;
case
9
:
// HvxcSpecificConfig();
break
;
case
12
:
// TTSSSpecificConfig();
break
;
case
13
:
case
14
:
case
15
:
case
16
:
// StructuredAudioSpecificConfig();
break
;
case
24
:
// ERCelpSpecificConfig();
break
;
case
25
:
// ERHvxcSpecificConfig();
break
;
case
26
:
case
27
:
// ParametricSpecificConfig();
break
;
case
28
:
// SSCSpecificConfig();
break
;
case
32
:
case
33
:
case
34
:
// MPEG_1_2_SpecificConfig();
break
;
case
35
:
// DSTSpecificConfig();
break
;
default:
// error
break
;
}
switch
(
p_cfg
->
i_object_type
)
{
case
17
:
case
19
:
case
20
:
case
21
:
case
22
:
case
23
:
case
24
:
case
25
:
case
26
:
case
27
:
{
int
epConfig
=
bs_read
(
s
,
2
);
if
(
epConfig
==
2
||
epConfig
==
3
)
{
//ErrorProtectionSpecificConfig();
}
if
(
epConfig
==
3
)
{
int
directMapping
=
bs_read1
(
s
);
if
(
directMapping
)
{
// tbd ...
}
}
break
;
}
default:
break
;
}
if
(
p_cfg
->
extension
.
i_object_type
!=
5
&&
i_max_size
>
0
&&
i_max_size
-
(
bs_pos
(
s
)
-
i_pos_start
)
>=
16
&&
bs_read
(
s
,
11
)
==
0x2b7
)
{
p_cfg
->
extension
.
i_object_type
=
Mpeg4ReadAudioObjectType
(
s
);
if
(
p_cfg
->
extension
.
i_object_type
==
5
)
{
p_cfg
->
i_sbr
=
bs_read1
(
s
);
if
(
p_cfg
->
i_sbr
==
1
)
p_cfg
->
extension
.
i_samplerate
=
Mpeg4ReadAudioSamplerate
(
s
);
}
}
//fprintf( stderr, "Mpeg4ReadAudioSpecificInfo: t=%s(%d)f=%d c=%d sbr=%d\n",
// ppsz_otype[p_cfg->i_object_type], p_cfg->i_object_type, p_cfg->i_samplerate, p_cfg->i_channel, p_cfg->i_sbr );
i_bits
=
bs_pos
(
s
)
-
i_pos_start
;
*
pi_extra
=
(
i_bits
+
7
)
/
8
;
for
(
i
=
0
;
i
<
__MIN
(
LATM_MAX_EXTRA_SIZE
,
*
pi_extra
);
i
++
)
{
const
int
i_read
=
__MIN
(
8
,
i_bits
-
8
*
i
);
p_extra
[
i
]
=
bs_read
(
&
s_sav
,
i_read
)
<<
(
8
-
i_read
);
}
return
i_bits
;
}
static
int
LatmGetValue
(
bs_t
*
s
)
{
int
i_bytes
=
bs_read
(
s
,
2
);
int
v
=
0
;
int
i
;
for
(
i
=
0
;
i
<
i_bytes
;
i
++
)
v
=
(
v
<<
8
)
+
bs_read
(
s
,
8
);
return
v
;
}
static
int
LatmReadStreamMuxConfiguration
(
latm_mux_t
*
m
,
bs_t
*
s
)
{
int
i_mux_version
;
int
i_mux_versionA
;
int
i_program
;
i_mux_version
=
bs_read
(
s
,
1
);
i_mux_versionA
=
0
;
if
(
i_mux_version
)
i_mux_versionA
=
bs_read
(
s
,
1
);
if
(
i_mux_versionA
!=
0
)
/* support only A=0 */
return
-
1
;
memset
(
m
,
0
,
sizeof
(
*
m
)
);
if
(
i_mux_versionA
==
0
)
{
if
(
i_mux_version
==
1
)
{
LatmGetValue
(
s
);
/* taraBufferFullness */
}
}
m
->
b_same_time_framing
=
bs_read1
(
s
);
m
->
i_sub_frames
=
1
+
bs_read
(
s
,
6
);
m
->
i_programs
=
1
+
bs_read
(
s
,
4
);
for
(
i_program
=
0
;
i_program
<
m
->
i_programs
;
i_program
++
)
{
int
i_layer
;
m
->
pi_layers
[
i_program
]
=
1
+
bs_read
(
s
,
3
);
for
(
i_layer
=
0
;
i_layer
<
m
->
pi_layers
[
i_program
];
i_layer
++
)
{
latm_stream_t
*
st
=
&
m
->
stream
[
m
->
i_streams
];
vlc_bool_t
b_previous_cfg
;
m
->
pi_stream
[
i_program
][
i_layer
]
=
m
->
i_streams
;
st
->
i_program
=
i_program
;
st
->
i_layer
=
i_layer
;
b_previous_cfg
=
VLC_FALSE
;
if
(
i_program
!=
0
||
i_layer
!=
0
)
b_previous_cfg
=
bs_read1
(
s
);
if
(
b_previous_cfg
)
{
assert
(
m
->
i_streams
>
0
);
st
->
cfg
=
m
->
stream
[
m
->
i_streams
-
1
].
cfg
;
}
else
{
int
i_cfg_size
=
0
;
if
(
i_mux_version
==
1
)
i_cfg_size
=
LatmGetValue
(
s
);
i_cfg_size
-=
Mpeg4ReadAudioSpecificInfo
(
&
st
->
cfg
,
&
st
->
i_extra
,
st
->
extra
,
s
,
i_cfg_size
);
if
(
i_cfg_size
>
0
)
bs_skip
(
s
,
i_cfg_size
);
}
st
->
i_frame_length_type
=
bs_read
(
s
,
3
);
switch
(
st
->
i_frame_length_type
)
{
case
0
:
{
bs_skip
(
s
,
8
);
/* latmBufferFullnes */
if
(
!
m
->
b_same_time_framing
)
{
if
(
st
->
cfg
.
i_object_type
==
6
||
st
->
cfg
.
i_object_type
==
20
||
st
->
cfg
.
i_object_type
==
8
||
st
->
cfg
.
i_object_type
==
24
)
{
bs_skip
(
s
,
6
);
/* eFrameOffset */
}
}
break
;
}
case
1
:
st
->
i_frame_length
=
bs_read
(
s
,
9
);
break
;
case
3
:
case
4
:
case
5
:
st
->
i_frame_length_index
=
bs_read
(
s
,
6
);
// celp
break
;
case
6
:
case
7
:
st
->
i_frame_length_index
=
bs_read
(
s
,
1
);
// hvxc
default:
break
;
}
/* Next stream */
m
->
i_streams
++
;
}
}
/* other data */
if
(
bs_read1
(
s
)
)
{
if
(
i_mux_version
==
1
)
{
m
->
i_other_data
=
LatmGetValue
(
s
);
}
else
{
int
b_continue
;
do
{
b_continue
=
bs_read1
(
s
);
m
->
i_other_data
=
(
m
->
i_other_data
<<
8
)
+
bs_read
(
s
,
8
);
}
while
(
b_continue
);
}
}
/* crc */
m
->
i_crc
=
-
1
;
if
(
bs_read1
(
s
)
)
m
->
i_crc
=
bs_read
(
s
,
8
);
return
0
;
}
static
int
LOASParse
(
decoder_t
*
p_dec
,
uint8_t
*
p_buffer
,
int
i_buffer
)
{
decoder_sys_t
*
p_sys
=
p_dec
->
p_sys
;
bs_t
s
;
int
i_sub
;
int
i_accumulated
=
0
;
bs_init
(
&
s
,
p_buffer
,
i_buffer
);
/* Read the stream mux configuration if present */
if
(
!
bs_read1
(
&
s
)
)
{
if
(
!
LatmReadStreamMuxConfiguration
(
&
p_sys
->
latm
,
&
s
)
&&
p_sys
->
latm
.
i_streams
>
0
)
{
const
latm_stream_t
*
st
=
&
p_sys
->
latm
.
stream
[
0
];
p_sys
->
i_channels
=
st
->
cfg
.
i_channel
;
p_sys
->
i_rate
=
st
->
cfg
.
i_samplerate
;
p_sys
->
i_frame_length
=
st
->
cfg
.
i_frame_length
;
/* FIXME And if it changes ? */
if
(
!
p_dec
->
fmt_out
.
i_extra
&&
st
->
i_extra
>
0
)
{
p_dec
->
fmt_out
.
i_extra
=
st
->
i_extra
;
p_dec
->
fmt_out
.
p_extra
=
malloc
(
st
->
i_extra
);
if
(
!
p_dec
->
fmt_out
.
p_extra
)
{
p_dec
->
fmt_out
.
i_extra
=
0
;
return
0
;
}
memcpy
(
p_dec
->
fmt_out
.
p_extra
,
st
->
extra
,
st
->
i_extra
);
}
p_sys
->
b_latm_cfg
=
VLC_TRUE
;
}
}
/* Wait for the configuration */
if
(
!
p_sys
->
b_latm_cfg
)
return
0
;
/* FIXME do we need to split the subframe into independant 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
block_t
*
ADTSPacketizeBlock
(
decoder_t
*
p_dec
,
block_t
**
pp_block
)
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
];
void
*
p_out_buffer
;
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
(
!
aout_DateGet
(
&
p_sys
->
end_date
)
&&
!
(
*
pp_block
)
->
i_pts
)
if
(
(
*
pp_block
)
->
i_flags
&
(
BLOCK_FLAG_DISCONTINUITY
|
BLOCK_FLAG_CORRUPTED
)
)
{
/* We've just started the stream, wait for the first PTS. */
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
(
(
*
pp_block
)
->
i_flags
&
BLOCK_FLAG_DISCONTINUITY
)
if
(
!
aout_DateGet
(
&
p_sys
->
end_date
)
&&
!
(
*
pp_block
)
->
i_pts
)
{
p_sys
->
i_state
=
STATE_NOSYNC
;
/* 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
);
while
(
1
)
for
(
;;
)
{
switch
(
p_sys
->
i_state
)
{
...
...
@@ -273,10 +1003,23 @@ static block_t *ADTSPacketizeBlock( decoder_t *p_dec, block_t **pp_block )
while
(
block_PeekBytes
(
&
p_sys
->
bytestream
,
p_header
,
2
)
==
VLC_SUCCESS
)
{
/* Look for sync word - should be 0xfff
+ 2 layer bits
*/
/* 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
);
...
...
@@ -301,6 +1044,8 @@ static block_t *ADTSPacketizeBlock( decoder_t *p_dec, block_t **pp_block )
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
)
...
...
@@ -314,8 +1059,23 @@ static block_t *ADTSPacketizeBlock( decoder_t *p_dec, block_t **pp_block )
&
p_sys
->
i_channels
,
&
p_sys
->
i_rate
,
&
p_sys
->
i_frame_length
,
&
p_sys
->
i_header_size
,
&
p_sys
->
i_raw_blocks
);
&
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"
);
...
...
@@ -329,6 +1089,12 @@ static block_t *ADTSPacketizeBlock( decoder_t *p_dec, block_t **pp_block )
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
...
...
@@ -339,7 +1105,11 @@ static block_t *ADTSPacketizeBlock( decoder_t *p_dec, block_t **pp_block )
return
NULL
;
}
if
(
p_header
[
0
]
!=
0xff
||
(
p_header
[
1
]
&
0xf6
)
!=
0xf0
)
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)"
);
...
...
@@ -363,21 +1133,43 @@ static block_t *ADTSPacketizeBlock( decoder_t *p_dec, block_t **pp_block )
p_sys
->
i_state
=
STATE_SEND_DATA
;
case
STATE_SEND_DATA
:
if
(
!
(
p_buf
=
GetOutBuffer
(
p_dec
,
&
p_out_buffer
))
)
/* 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 = VLC_TRUE;
return
NULL
;
}
p_buf
=
p_out_buffer
->
p_buffer
;
/* When we reach this point we already know we have enough
* data available. */
/* Skip the ADTS header */
/* 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
;
...
...
@@ -395,12 +1187,11 @@ static block_t *ADTSPacketizeBlock( decoder_t *p_dec, block_t **pp_block )
}
/*****************************************************************************
*
GetOut
Buffer:
*
Setup
Buffer:
*****************************************************************************/
static
uint8_t
*
GetOutBuffer
(
decoder_t
*
p_dec
,
void
**
pp_out_buffer
)
static
void
SetupOutput
(
decoder_t
*
p_dec
,
block_t
*
p_block
)
{
decoder_sys_t
*
p_sys
=
p_dec
->
p_sys
;
block_t
*
p_block
;
if
(
p_dec
->
fmt_out
.
audio
.
i_rate
!=
p_sys
->
i_rate
)
{
...
...
@@ -422,16 +1213,11 @@ static uint8_t *GetOutBuffer( decoder_t *p_dec, void **pp_out_buffer )
p_sys->i_channels_conf & AOUT_CHAN_PHYSMASK;
#endif
p_block
=
block_New
(
p_dec
,
p_sys
->
i_frame_size
);
if
(
p_block
==
NULL
)
return
NULL
;
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_block
->
i_pts
;
*
pp_out_buffer
=
p_block
;
return
p_block
->
p_buffer
;
p_sys
->
i_frame_length
*
p_sys
->
i_input_rate
/
INPUT_RATE_DEFAULT
)
-
p_block
->
i_pts
;
}
/*****************************************************************************
...
...
@@ -446,54 +1232,3 @@ static void ClosePacketizer( vlc_object_t *p_this )
free
(
p_dec
->
p_sys
);
}
/*****************************************************************************
* ADTSSyncInfo: parse MPEG 4 audio ADTS sync info
*****************************************************************************/
static
int
ADTSSyncInfo
(
decoder_t
*
p_dec
,
const
byte_t
*
p_buf
,
unsigned
int
*
pi_channels
,
unsigned
int
*
pi_sample_rate
,
unsigned
int
*
pi_frame_length
,
unsigned
int
*
pi_header_size
,
unsigned
int
*
pi_raw_blocks_in_frame
)
{
int
i_id
,
i_profile
,
i_sample_rate_idx
,
i_frame_size
;
vlc_bool_t
b_crc
;
/* Fixed header between frames */
i_id
=
(
(
p_buf
[
1
]
>>
3
)
&
0x01
)
?
2
:
4
;
b_crc
=
!
(
p_buf
[
1
]
&
0x01
);
i_profile
=
p_buf
[
2
]
>>
6
;
i_sample_rate_idx
=
(
p_buf
[
2
]
>>
2
)
&
0x0f
;
*
pi_sample_rate
=
i_sample_rates
[
i_sample_rate_idx
];
*
pi_channels
=
((
p_buf
[
2
]
&
0x01
)
<<
2
)
|
((
p_buf
[
3
]
>>
6
)
&
0x03
);
/* Variable header */
i_frame_size
=
((
p_buf
[
3
]
&
0x03
)
<<
11
)
|
(
p_buf
[
4
]
<<
3
)
|
((
p_buf
[
5
]
>>
5
)
&
0x7
);
*
pi_raw_blocks_in_frame
=
(
p_buf
[
6
]
&
0x02
)
+
1
;
if
(
!*
pi_sample_rate
||
!*
pi_channels
||
!
i_frame_size
)
{
return
0
;
}
/* Fixme */
*
pi_frame_length
=
1024
;
/* Build the decoder specific info header */
if
(
!
p_dec
->
fmt_out
.
i_extra
)
{
p_dec
->
fmt_out
.
i_extra
=
2
;
p_dec
->
fmt_out
.
p_extra
=
malloc
(
2
);
((
uint8_t
*
)
p_dec
->
fmt_out
.
p_extra
)[
0
]
=
(
i_profile
+
1
)
<<
3
|
(
i_sample_rate_idx
>>
1
);
((
uint8_t
*
)
p_dec
->
fmt_out
.
p_extra
)[
1
]
=
((
i_sample_rate_idx
&
0x01
)
<<
7
)
|
(
*
pi_channels
<<
3
);
}
/* ADTS header length */
*
pi_header_size
=
b_crc
?
9
:
7
;
return
i_frame_size
-
*
pi_header_size
;
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment