Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
V
vlc-1.1
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-1.1
Commits
3051781d
Commit
3051781d
authored
Aug 01, 2003
by
Laurent Aimar
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
* mpga: mp3 demuxer written from scratch using ninput.h
parent
3b20789e
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
481 additions
and
728 deletions
+481
-728
modules/demux/mpeg/Modules.am
modules/demux/mpeg/Modules.am
+2
-2
modules/demux/mpeg/audio.c
modules/demux/mpeg/audio.c
+0
-726
modules/demux/mpeg/mpga.c
modules/demux/mpeg/mpga.c
+479
-0
No files found.
modules/demux/mpeg/Modules.am
View file @
3051781d
...
...
@@ -24,7 +24,7 @@ SOURCES_ts_dvbpsi = \
ts.c \
$(NULL)
SOURCES_
audio
= \
audio
.c \
SOURCES_
mpga
= \
mpga
.c \
$(NULL)
modules/demux/mpeg/audio.c
deleted
100644 → 0
View file @
3b20789e
/*****************************************************************************
* audio.c : mpeg audio Stream input module for vlc
*****************************************************************************
* Copyright (C) 2001 VideoLAN
* $Id: audio.c,v 1.18 2003/05/05 22:23:36 gbazin Exp $
*
* Authors: Laurent Aimar <fenrir@via.ecp.fr>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
*****************************************************************************/
/*****************************************************************************
* Preamble
*****************************************************************************/
#include <stdlib.h>
/* malloc(), free() */
#include <string.h>
#include <vlc/vlc.h>
#include <vlc/input.h>
#include <sys/types.h>
/*****************************************************************************
* Local prototypes
*****************************************************************************/
static
int
Activate
(
vlc_object_t
*
);
static
int
Demux
(
input_thread_t
*
);
/* TODO: support MPEG-2.5, not difficult, but I need somes samples... */
/*****************************************************************************
* Module descriptor
*****************************************************************************/
vlc_module_begin
();
set_description
(
_
(
"MPEG I/II audio stream demuxer"
)
);
set_capability
(
"demux"
,
50
);
set_callbacks
(
Activate
,
NULL
);
add_shortcut
(
"mpegaudio"
);
add_shortcut
(
"mp3"
);
vlc_module_end
();
/*****************************************************************************
* Definitions of structures and functions used by this plugins
*****************************************************************************/
/* XXX set this to 0 to avoid problem with PS XXX */
/* but with some file or web radio will failed to detect */
/* it's you to choose */
#define MPEGAUDIO_MAXTESTPOS 0
typedef
struct
mpeg_header_s
{
uint32_t
i_header
;
int
i_version
;
int
i_layer
;
int
i_crc
;
int
i_bitrate
;
int
i_samplerate
;
int
i_padding
;
int
i_extension
;
int
i_mode
;
int
i_modeext
;
int
i_copyright
;
int
i_original
;
int
i_emphasis
;
}
mpeg_header_t
;
/* Xing Header if present */
#define FRAMES_FLAG 0x0001
/* these flags is for i_flags */
#define BYTES_FLAG 0x0002
/* because all is optionnal */
#define TOC_FLAG 0x0004
#define VBR_SCALE_FLAG 0x0008
typedef
struct
xing_header_s
{
int
i_flags
;
/* from Xing header data */
int
i_frames
;
/* total bit stream frames from Xing header data */
int
i_bytes
;
/* total bit stream bytes from Xing header data */
int
i_vbr_scale
;
/* encoded vbr scale from Xing header data */
uint8_t
i_toc
[
100
];
/* for seek */
int
i_avgbitrate
;
/* calculated, XXX: bits/sec not Kb */
}
xing_header_t
;
struct
demux_sys_t
{
mtime_t
i_pts
;
es_descriptor_t
*
p_es
;
mpeg_header_t
mpeg
;
xing_header_t
xingheader
;
/* extracted information */
int
i_samplerate
;
int
i_samplelength
;
int
i_framelength
;
};
static
int
mpegaudio_bitrate
[
2
][
3
][
16
]
=
{
{
/* v1 l1 */
{
0
,
32
,
64
,
96
,
128
,
160
,
192
,
224
,
256
,
288
,
320
,
352
,
384
,
416
,
448
,
0
},
/* v1 l2 */
{
0
,
32
,
48
,
56
,
64
,
80
,
96
,
112
,
128
,
160
,
192
,
224
,
256
,
320
,
384
,
0
},
/* v1 l3 */
{
0
,
32
,
40
,
48
,
56
,
64
,
80
,
96
,
112
,
128
,
160
,
192
,
224
,
256
,
320
,
0
}
},
{
/* v2 l1 */
{
0
,
32
,
48
,
56
,
64
,
80
,
96
,
112
,
128
,
144
,
160
,
176
,
192
,
224
,
256
,
0
},
/* v2 l2 */
{
0
,
8
,
16
,
24
,
32
,
40
,
48
,
56
,
64
,
80
,
96
,
112
,
128
,
144
,
160
,
0
},
/* v2 l3 */
{
0
,
8
,
16
,
24
,
32
,
40
,
48
,
56
,
64
,
80
,
96
,
112
,
128
,
144
,
160
,
0
}
}
};
static
int
mpegaudio_samplerate
[
2
][
4
]
=
/* version 1 then 2 */
{
{
44100
,
48000
,
32000
,
0
},
{
22050
,
24000
,
16000
,
0
}
};
static
char
*
mpegaudio_mode
[
4
]
=
{
"stereo"
,
"joint stereo"
,
"dual channel"
,
"mono"
};
static
inline
uint32_t
GetDWBE
(
uint8_t
*
p_buff
)
{
return
(
(
p_buff
[
0
]
<<
24
)
|
(
p_buff
[
1
]
<<
16
)
|
(
p_buff
[
2
]
<<
8
)
|
(
p_buff
[
3
]
)
);
}
/*****************************************************************************
* Function to manipulate stream easily
*****************************************************************************
*
* SkipBytes : skip bytes, not yet optimised, read bytes to be skipped :P
*
* ReadPes : read data and make a PES
*
*****************************************************************************/
static
int
SkipBytes
(
input_thread_t
*
p_input
,
int
i_size
)
{
data_packet_t
*
p_data
;
int
i_read
;
while
(
i_size
>
0
)
{
i_read
=
input_SplitBuffer
(
p_input
,
&
p_data
,
__MIN
(
i_size
,
1024
)
);
if
(
i_read
<=
0
)
{
return
(
0
);
}
input_DeletePacket
(
p_input
->
p_method_data
,
p_data
);
i_size
-=
i_read
;
}
return
(
1
);
}
static
int
ReadPES
(
input_thread_t
*
p_input
,
pes_packet_t
**
pp_pes
,
int
i_size
)
{
pes_packet_t
*
p_pes
;
*
pp_pes
=
NULL
;
if
(
!
(
p_pes
=
input_NewPES
(
p_input
->
p_method_data
))
)
{
msg_Err
(
p_input
,
"cannot allocate new PES"
);
return
(
0
);
}
while
(
i_size
>
0
)
{
data_packet_t
*
p_data
;
int
i_read
;
if
(
(
i_read
=
input_SplitBuffer
(
p_input
,
&
p_data
,
__MIN
(
i_size
,
1024
)
)
)
<=
0
)
{
input_DeletePES
(
p_input
->
p_method_data
,
p_pes
);
return
(
0
);
}
if
(
!
p_pes
->
p_first
)
{
p_pes
->
p_first
=
p_data
;
p_pes
->
i_nb_data
=
1
;
p_pes
->
i_pes_size
=
i_read
;
}
else
{
p_pes
->
p_last
->
p_next
=
p_data
;
p_pes
->
i_nb_data
++
;
p_pes
->
i_pes_size
+=
i_read
;
}
p_pes
->
p_last
=
p_data
;
i_size
-=
i_read
;
}
*
pp_pes
=
p_pes
;
return
(
1
);
}
/*****************************************************************************
* CheckHeader : Test the validity of the header
*****************************************************************************/
static
int
CheckHeader
(
uint32_t
i_header
)
{
if
(
(((
i_header
>>
20
)
&
0x0FFF
)
!=
0x0FFF
)
/* header sync */
||
(((
i_header
>>
17
)
&
0x03
)
==
0
)
/* valid layer ?*/
||
(((
i_header
>>
12
)
&
0x0F
)
==
0x0F
)
||
(((
i_header
>>
12
)
&
0x0F
)
==
0x00
)
/* valid bitrate ? */
||
(((
i_header
>>
10
)
&
0x03
)
==
0x03
)
/* valide sampling freq ? */
||
((
i_header
&
0x03
)
==
0x02
))
/* valid emphasis ? */
{
return
(
0
);
/*invalid */
}
return
(
1
);
/* valid */
}
/*****************************************************************************
* DecodedFrameSize : give the length of the decoded pcm data
*****************************************************************************/
static
int
DecodedFrameSize
(
mpeg_header_t
*
p_mpeg
)
{
switch
(
p_mpeg
->
i_layer
)
{
case
(
0
):
/* layer 1 */
return
(
384
);
case
(
1
):
/* layer 2 */
return
(
1152
);
case
(
2
):
/* layer 3 */
return
(
!
p_mpeg
->
i_version
?
1152
:
576
);
/* XXX: perhaps we have to /2 for all layer but i'm not sure */
}
return
(
0
);
}
/****************************************************************************
* GetHeader : find an mpeg header and load it
****************************************************************************/
static
int
GetHeader
(
input_thread_t
*
p_input
,
mpeg_header_t
*
p_mpeg
,
int
i_max_pos
,
int
*
pi_skip
)
{
uint32_t
i_header
;
uint8_t
*
p_peek
;
int
i_size
;
*
pi_skip
=
0
;
i_size
=
input_Peek
(
p_input
,
&
p_peek
,
i_max_pos
+
4
);
for
(
;
;
)
{
if
(
i_size
<
4
)
{
return
(
0
);
}
if
(
!
CheckHeader
(
GetDWBE
(
p_peek
)
)
)
{
p_peek
++
;
i_size
--
;
*
pi_skip
+=
1
;
continue
;
}
/* we found an header, load it */
break
;
}
i_header
=
GetDWBE
(
p_peek
);
p_mpeg
->
i_header
=
i_header
;
p_mpeg
->
i_version
=
1
-
(
(
i_header
>>
19
)
&
0x01
);
p_mpeg
->
i_layer
=
3
-
(
(
i_header
>>
17
)
&
0x03
);
p_mpeg
->
i_crc
=
1
-
((
i_header
>>
16
)
&
0x01
);
p_mpeg
->
i_bitrate
=
mpegaudio_bitrate
[
p_mpeg
->
i_version
][
p_mpeg
->
i_layer
][(
i_header
>>
12
)
&
0x0F
];
p_mpeg
->
i_samplerate
=
mpegaudio_samplerate
[
p_mpeg
->
i_version
][(
i_header
>>
10
)
&
0x03
];
p_mpeg
->
i_padding
=
((
i_header
>>
9
)
&
0x01
);
p_mpeg
->
i_extension
=
(
i_header
>>
7
)
&
0x01
;
p_mpeg
->
i_mode
=
(
i_header
>>
6
)
&
0x03
;
p_mpeg
->
i_modeext
=
(
i_header
>>
4
)
&
0x03
;
p_mpeg
->
i_copyright
=
(
i_header
>>
3
)
&
0x01
;
p_mpeg
->
i_original
=
(
i_header
>>
2
)
&
0x01
;
p_mpeg
->
i_emphasis
=
(
i_header
)
&
0x03
;
return
(
1
);
}
/*****************************************************************************
* ExtractXingHeader : extract a Xing header if exist
*****************************************************************************
* It also calcul avgbitrate, using Xing header if present or assume that
* the bitrate of the first frame is the same for the all file
*****************************************************************************/
static
void
ExtractXingHeader
(
input_thread_t
*
p_input
,
xing_header_t
*
p_xh
)
{
int
i_skip
;
int
i_size
;
uint8_t
*
p_peek
;
mpeg_header_t
mpeg
;
p_xh
->
i_flags
=
0
;
/* nothing present */
if
(
!
(
GetHeader
(
p_input
,
&
mpeg
,
8192
,
&
i_skip
)
)
)
{
msg_Err
(
p_input
,
"ExtractXingHeader failed, shouldn't ..."
);
return
;
}
p_xh
->
i_avgbitrate
=
mpeg
.
i_bitrate
*
1000
;
/* default */
/* 1024 is enougth */
if
(
(
i_size
=
input_Peek
(
p_input
,
&
p_peek
,
1024
+
i_skip
)
)
<
8
)
{
return
;
}
p_peek
+=
i_skip
;
i_size
-=
i_skip
;
/* calculate pos of xing header */
if
(
!
mpeg
.
i_version
)
{
p_peek
+=
mpeg
.
i_mode
!=
3
?
36
:
21
;
i_size
-=
mpeg
.
i_mode
!=
3
?
36
:
21
;
}
else
{
p_peek
+=
mpeg
.
i_mode
!=
3
?
21
:
13
;
i_size
-=
mpeg
.
i_mode
!=
3
?
21
:
13
;
}
if
(
i_size
<
8
)
{
return
;
}
if
(
(
p_peek
[
0
]
!=
'X'
)
||
(
p_peek
[
1
]
!=
'i'
)
||
(
p_peek
[
2
]
!=
'n'
)
||
(
p_peek
[
3
]
!=
'g'
)
)
{
return
;
}
else
{
msg_Dbg
(
p_input
,
"Xing header is present"
);
p_peek
+=
4
;
i_size
-=
4
;
}
if
(
i_size
<
4
)
{
return
;
}
else
{
p_xh
->
i_flags
=
GetDWBE
(
p_peek
);
p_peek
+=
4
;
i_size
-=
4
;
}
if
(
(
p_xh
->
i_flags
&
FRAMES_FLAG
)
&&
(
i_size
>=
4
)
)
{
p_xh
->
i_frames
=
GetDWBE
(
p_peek
);
if
(
p_xh
->
i_frames
==
0
)
p_xh
->
i_flags
&=
~
FRAMES_FLAG
;
p_peek
+=
4
;
i_size
-=
4
;
}
if
(
(
p_xh
->
i_flags
&
BYTES_FLAG
)
&&
(
i_size
>=
4
)
)
{
p_xh
->
i_bytes
=
GetDWBE
(
p_peek
);
if
(
p_xh
->
i_bytes
==
0
)
p_xh
->
i_flags
&=
~
BYTES_FLAG
;
p_peek
+=
4
;
i_size
-=
4
;
}
if
(
(
p_xh
->
i_flags
&
TOC_FLAG
)
&&
(
i_size
>=
100
)
)
{
memcpy
(
p_xh
->
i_toc
,
p_peek
,
100
);
p_peek
+=
100
;
i_size
-=
100
;
}
if
(
(
p_xh
->
i_flags
&
VBR_SCALE_FLAG
)
&&
(
i_size
>=
4
)
)
{
p_xh
->
i_vbr_scale
=
GetDWBE
(
p_peek
);
p_peek
+=
4
;
i_size
-=
4
;
}
if
(
(
p_xh
->
i_flags
&
FRAMES_FLAG
)
&&
(
p_xh
->
i_flags
&
BYTES_FLAG
)
)
{
p_xh
->
i_avgbitrate
=
(
(
uint64_t
)
p_xh
->
i_bytes
*
(
uint64_t
)
8
*
(
uint64_t
)
mpeg
.
i_samplerate
)
/
((
uint64_t
)
p_xh
->
i_frames
*
(
uint64_t
)
DecodedFrameSize
(
&
mpeg
)
);
}
}
/****************************************************************************
* ExtractConfiguration : extract usefull informations from mpeg_header_t
****************************************************************************/
static
void
ExtractConfiguration
(
demux_sys_t
*
p_demux
)
{
p_demux
->
i_samplerate
=
p_demux
->
mpeg
.
i_samplerate
;
p_demux
->
i_samplelength
=
DecodedFrameSize
(
&
p_demux
->
mpeg
);
/* XXX if crc do i need to add 2 bytes or not? */
switch
(
p_demux
->
mpeg
.
i_layer
)
{
case
(
0
):
p_demux
->
i_framelength
=
(
(
12000
*
p_demux
->
mpeg
.
i_bitrate
)
/
p_demux
->
mpeg
.
i_samplerate
+
p_demux
->
mpeg
.
i_padding
)
*
4
;
break
;
case
(
1
):
p_demux
->
i_framelength
=
(
144000
*
p_demux
->
mpeg
.
i_bitrate
)
/
p_demux
->
mpeg
.
i_samplerate
+
p_demux
->
mpeg
.
i_padding
;
break
;
case
(
2
):
p_demux
->
i_framelength
=
(
p_demux
->
mpeg
.
i_version
?
72000
:
144000
)
*
p_demux
->
mpeg
.
i_bitrate
/
p_demux
->
mpeg
.
i_samplerate
+
p_demux
->
mpeg
.
i_padding
;
break
;
}
}
/****************************************************************************
* CheckPS : check if this stream could be some ps,
* yes it's ugly ... but another idea ?
*
****************************************************************************/
static
int
CheckPS
(
input_thread_t
*
p_input
)
{
uint8_t
*
p_peek
;
int
i_startcode
=
0
;
int
i_size
=
input_Peek
(
p_input
,
&
p_peek
,
8196
);
while
(
i_size
>
4
)
{
if
(
(
p_peek
[
0
]
==
0
)
&&
(
p_peek
[
1
]
==
0
)
&&
(
p_peek
[
2
]
==
1
)
&&
(
p_peek
[
3
]
>=
0xb9
)
&&
++
i_startcode
>=
3
)
{
return
1
;
}
p_peek
++
;
i_size
--
;
}
return
0
;
}
/*****************************************************************************
* Activate: initializes MPEGaudio structures
*****************************************************************************/
static
int
Activate
(
vlc_object_t
*
p_this
)
{
input_thread_t
*
p_input
=
(
input_thread_t
*
)
p_this
;
demux_sys_t
*
p_demux
;
input_info_category_t
*
p_category
;
module_t
*
p_id3
;
int
i_found
;
int
b_forced
;
int
i_skip
;
int
i_max_pos
;
/* Set the demux function */
p_input
->
pf_demux
=
Demux
;
/* Initialize access plug-in structures. */
if
(
p_input
->
i_mtu
==
0
)
{
/* Improve speed. */
p_input
->
i_bufsize
=
INPUT_DEFAULT_BUFSIZE
;
}
b_forced
=
VLC_FALSE
;
i_max_pos
=
MPEGAUDIO_MAXTESTPOS
;
if
(
(
*
p_input
->
psz_demux
)
&&
(
(
!
strncmp
(
p_input
->
psz_demux
,
"mpegaudio"
,
10
)
)
||
(
!
strncmp
(
p_input
->
psz_demux
,
"mp3"
,
3
)
)
)
)
{
b_forced
=
VLC_TRUE
;
i_max_pos
=
4000
;
}
else
if
(
p_input
->
psz_name
)
{
char
*
name
=
p_input
->
psz_name
;
int
i_len
=
strlen
(
name
);
if
(
i_len
>
4
&&
!
strcasecmp
(
&
name
[
i_len
-
4
],
".mp3"
)
)
{
i_max_pos
=
2000
;
}
}
p_id3
=
module_Need
(
p_input
,
"id3"
,
NULL
);
if
(
p_id3
)
{
module_Unneed
(
p_input
,
p_id3
);
}
/* create p_demux and init it */
if
(
!
(
p_demux
=
p_input
->
p_demux_data
=
malloc
(
sizeof
(
demux_sys_t
)
)
)
)
{
msg_Err
(
p_input
,
"out of memory"
);
return
(
-
1
);
}
memset
(
p_demux
,
0
,
sizeof
(
demux_sys_t
)
);
/* check if it could be a ps stream */
if
(
!
b_forced
&&
CheckPS
(
p_input
))
{
free
(
p_input
->
p_demux_data
);
return
(
-
1
);
}
/* must be sure that is mpeg audio stream unless forced */
if
(
!
(
i_found
=
GetHeader
(
p_input
,
&
p_demux
->
mpeg
,
i_max_pos
,
&
i_skip
)
)
)
{
if
(
b_forced
)
{
msg_Warn
(
p_input
,
"this does not look like an MPEG audio stream, "
"but continuing anyway"
);
}
else
{
msg_Warn
(
p_input
,
"MPEGAudio module discarded (no frame found)"
);
free
(
p_input
->
p_demux_data
);
return
(
-
1
);
}
}
else
{
ExtractConfiguration
(
p_demux
);
}
vlc_mutex_lock
(
&
p_input
->
stream
.
stream_lock
);
if
(
input_InitStream
(
p_input
,
0
)
==
-
1
)
{
msg_Err
(
p_input
,
"cannot init stream"
);
free
(
p_input
->
p_demux_data
);
return
(
-
1
);
}
if
(
input_AddProgram
(
p_input
,
0
,
0
)
==
NULL
)
{
msg_Err
(
p_input
,
"cannot add program"
);
free
(
p_input
->
p_demux_data
);
return
(
-
1
);
}
p_input
->
stream
.
pp_programs
[
0
]
->
b_is_ok
=
0
;
p_input
->
stream
.
p_selected_program
=
p_input
->
stream
.
pp_programs
[
0
];
/* create our ES */
p_demux
->
p_es
=
input_AddES
(
p_input
,
p_input
->
stream
.
p_selected_program
,
1
/* id */
,
AUDIO_ES
,
NULL
,
0
);
if
(
!
p_demux
->
p_es
)
{
vlc_mutex_unlock
(
&
p_input
->
stream
.
stream_lock
);
msg_Err
(
p_input
,
"out of memory"
);
free
(
p_input
->
p_demux_data
);
return
(
-
1
);
}
p_demux
->
p_es
->
i_stream_id
=
1
;
p_demux
->
p_es
->
i_fourcc
=
VLC_FOURCC
(
'm'
,
'p'
,
'g'
,
'a'
);
input_SelectES
(
p_input
,
p_demux
->
p_es
);
p_input
->
stream
.
p_selected_program
->
b_is_ok
=
1
;
vlc_mutex_unlock
(
&
p_input
->
stream
.
stream_lock
);
if
(
i_found
)
{
/* parse Xing Header if present */
ExtractXingHeader
(
p_input
,
&
p_demux
->
xingheader
);
vlc_mutex_lock
(
&
p_input
->
stream
.
stream_lock
);
p_input
->
stream
.
i_mux_rate
=
p_demux
->
xingheader
.
i_avgbitrate
/
50
/
8
;
vlc_mutex_unlock
(
&
p_input
->
stream
.
stream_lock
);
/* all is ok :)) */
msg_Dbg
(
p_input
,
"audio MPEG-%d layer %d %s %dHz %dKb/s %s"
,
p_demux
->
mpeg
.
i_version
+
1
,
p_demux
->
mpeg
.
i_layer
+
1
,
mpegaudio_mode
[
p_demux
->
mpeg
.
i_mode
],
p_demux
->
mpeg
.
i_samplerate
,
p_demux
->
xingheader
.
i_avgbitrate
/
1000
,
p_demux
->
xingheader
.
i_flags
?
"VBR (Xing)"
:
""
);
vlc_mutex_lock
(
&
p_input
->
stream
.
stream_lock
);
p_category
=
input_InfoCategory
(
p_input
,
_
(
"mpeg"
)
);
input_AddInfo
(
p_category
,
_
(
"Input Type"
),
"Audio MPEG-%d"
,
p_demux
->
mpeg
.
i_version
+
1
);
input_AddInfo
(
p_category
,
_
(
"Layer"
),
"%d"
,
p_demux
->
mpeg
.
i_layer
+
1
);
input_AddInfo
(
p_category
,
_
(
"Mode"
),
mpegaudio_mode
[
p_demux
->
mpeg
.
i_mode
]
);
input_AddInfo
(
p_category
,
_
(
"Sample Rate"
),
"%dHz"
,
p_demux
->
mpeg
.
i_samplerate
);
input_AddInfo
(
p_category
,
_
(
"Average Bitrate"
),
"%dKb/s"
,
p_demux
->
xingheader
.
i_avgbitrate
/
1000
);
vlc_mutex_unlock
(
&
p_input
->
stream
.
stream_lock
);
}
else
{
msg_Dbg
(
p_input
,
"assuming audio MPEG, but not frame header yet found"
);
vlc_mutex_lock
(
&
p_input
->
stream
.
stream_lock
);
p_category
=
input_InfoCategory
(
p_input
,
_
(
"mpeg"
)
);
input_AddInfo
(
p_category
,
_
(
"Input Type"
),
"Audio MPEG-?"
);
vlc_mutex_unlock
(
&
p_input
->
stream
.
stream_lock
);
}
return
(
0
);
}
/*****************************************************************************
* Demux: reads and demuxes data packets
*****************************************************************************
* Returns -1 in case of error, 0 in case of EOF, 1 otherwise
*****************************************************************************/
static
int
Demux
(
input_thread_t
*
p_input
)
{
demux_sys_t
*
p_demux
=
p_input
->
p_demux_data
;
pes_packet_t
*
p_pes
;
int
i_skip
;
if
(
!
GetHeader
(
p_input
,
&
p_demux
->
mpeg
,
8192
,
&
i_skip
)
)
{
if
(
i_skip
>
0
)
{
msg_Dbg
(
p_input
,
"skipping %d bytes (garbage ?)"
,
i_skip
);
SkipBytes
(
p_input
,
i_skip
);
return
(
1
);
}
else
{
msg_Dbg
(
p_input
,
"cannot find next frame (EOF ?)"
);
return
(
0
);
}
}
ExtractConfiguration
(
p_demux
);
input_ClockManageRef
(
p_input
,
p_input
->
stream
.
p_selected_program
,
p_demux
->
i_pts
);
/*
* For layer 1 and 2 i_skip is garbage but for layer 3 it is not.
* Since mad accept without to much trouble garbage I don't skip
* it ( in case I misdetect garbage ... )
*
*/
if
(
!
ReadPES
(
p_input
,
&
p_pes
,
p_demux
->
i_framelength
+
i_skip
)
)
{
msg_Warn
(
p_input
,
"cannot read data"
);
return
(
-
1
);
}
p_pes
->
i_rate
=
p_input
->
stream
.
control
.
i_rate
;
p_pes
->
i_dts
=
p_pes
->
i_pts
=
input_ClockGetTS
(
p_input
,
p_input
->
stream
.
p_selected_program
,
p_demux
->
i_pts
);
if
(
!
p_demux
->
p_es
->
p_decoder_fifo
)
{
msg_Err
(
p_input
,
"no audio decoder"
);
input_DeletePES
(
p_input
->
p_method_data
,
p_pes
);
return
(
-
1
);
/* perhaps not, it's my choice */
}
else
{
input_DecodePES
(
p_demux
->
p_es
->
p_decoder_fifo
,
p_pes
);
}
p_demux
->
i_pts
+=
(
mtime_t
)
90000
*
(
mtime_t
)
p_demux
->
i_samplelength
/
(
mtime_t
)
p_demux
->
i_samplerate
;
return
(
1
);
}
modules/demux/mpeg/mpga.c
0 → 100644
View file @
3051781d
/*****************************************************************************
* mpga.c : MPEG-I/II Audio input module for vlc
*****************************************************************************
* Copyright (C) 2001 VideoLAN
* $Id: mpga.c,v 1.1 2003/08/01 00:37:06 fenrir Exp $
*
* Authors: Laurent Aimar <fenrir@via.ecp.fr>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
*****************************************************************************/
/*****************************************************************************
* Preamble
*****************************************************************************/
#include <stdlib.h>
/* malloc(), free() */
#include <vlc/vlc.h>
#include <vlc/input.h>
#include <ninput.h>
/*****************************************************************************
* Module descriptor
*****************************************************************************/
static
int
Open
(
vlc_object_t
*
);
static
void
Close
(
vlc_object_t
*
);
vlc_module_begin
();
set_description
(
_
(
"MPEG-I/II Audio demuxer"
)
);
set_capability
(
"demux"
,
100
);
set_callbacks
(
Open
,
Close
);
add_shortcut
(
"mpga"
);
add_shortcut
(
"mp3"
);
vlc_module_end
();
/* TODO:
* - mpeg 2.5
* - free bitrate
*/
/*****************************************************************************
* Local prototypes
*****************************************************************************/
static
int
Demux
(
input_thread_t
*
);
struct
demux_sys_t
{
stream_t
*
s
;
mtime_t
i_time
;
int
i_bitrate_avg
;
/* extracted from Xing header */
es_descriptor_t
*
p_es
;
};
static
inline
uint32_t
GetDWBE
(
uint8_t
*
p
)
{
return
(
(
p
[
0
]
<<
24
)
|
(
p
[
1
]
<<
16
)
|
(
p
[
2
]
<<
8
)
|
(
p
[
3
]
)
);
}
static
int
HeaderCheck
(
uint32_t
h
)
{
if
(
(((
h
>>
20
)
&
0x0FFF
)
!=
0x0FFF
)
/* header sync */
||
(((
h
>>
17
)
&
0x03
)
==
0
)
/* valid layer ?*/
||
(((
h
>>
12
)
&
0x0F
)
==
0x0F
)
||
(((
h
>>
12
)
&
0x0F
)
==
0x00
)
/* valid bitrate ? */
||
(((
h
>>
10
)
&
0x03
)
==
0x03
)
/* valide sampling freq ? */
||
((
h
&
0x03
)
==
0x02
))
/* valid emphasis ? */
{
return
(
VLC_FALSE
);
}
return
(
VLC_TRUE
);
}
static
int
mpga_sample_rate
[
2
][
4
]
=
{
{
44100
,
48000
,
32000
,
0
},
{
22050
,
24000
,
16000
,
0
}
};
static
int
mpga_bitrate
[
2
][
3
][
16
]
=
{
{
{
0
,
32
,
64
,
96
,
128
,
160
,
192
,
224
,
256
,
288
,
320
,
352
,
384
,
416
,
448
,
0
},
{
0
,
32
,
48
,
56
,
64
,
80
,
96
,
112
,
128
,
160
,
192
,
224
,
256
,
320
,
384
,
0
},
{
0
,
32
,
40
,
48
,
56
,
64
,
80
,
96
,
112
,
128
,
160
,
192
,
224
,
256
,
320
,
0
}
},
{
{
0
,
32
,
48
,
56
,
64
,
80
,
96
,
112
,
128
,
144
,
160
,
176
,
192
,
224
,
256
,
0
},
{
0
,
8
,
16
,
24
,
32
,
40
,
48
,
56
,
64
,
80
,
96
,
112
,
128
,
144
,
160
,
0
},
{
0
,
8
,
16
,
24
,
32
,
40
,
48
,
56
,
64
,
80
,
96
,
112
,
128
,
144
,
160
,
0
}
}
};
#define MPGA_VERSION( h ) ( 1 - (((h)>>19)&0x01) )
#define MPGA_LAYER( h ) ( 3 - (((h)>>17)&0x03) )
#define MPGA_SAMPLE_RATE(h) mpga_sample_rate[MPGA_VERSION(h)][((h)>>10)&0x03]
#define MPGA_CHANNELS(h) ( (((h)>>6)&0x03) == 3 ? 1 : 2)
#define MPGA_BITRATE(h) mpga_bitrate[MPGA_VERSION(h)][MPGA_LAYER(h)][((h)>>12)&0x0f]
#define MPGA_PADDING(h) ( ((h)>>9)&0x01 )
#define MPGA_MODE(h) (((h)>> 6)&0x03)
static
int
mpga_frame_size
(
uint32_t
h
)
{
switch
(
MPGA_LAYER
(
h
)
)
{
case
0
:
return
(
(
12000
*
MPGA_BITRATE
(
h
)
)
/
MPGA_SAMPLE_RATE
(
h
)
+
MPGA_PADDING
(
h
)
)
*
4
;
case
1
:
return
(
144000
*
MPGA_BITRATE
(
h
)
)
/
MPGA_SAMPLE_RATE
(
h
)
+
MPGA_PADDING
(
h
);
case
2
:
return
(
(
MPGA_VERSION
(
h
)
?
72000
:
144000
)
*
MPGA_BITRATE
(
h
)
)
/
MPGA_SAMPLE_RATE
(
h
)
+
MPGA_PADDING
(
h
);
default:
return
0
;
}
}
static
int
mpga_frame_samples
(
uint32_t
h
)
{
switch
(
MPGA_LAYER
(
h
)
)
{
case
0
:
return
384
;
case
1
:
return
1152
;
case
2
:
return
MPGA_VERSION
(
h
)
?
576
:
1152
;
default:
return
0
;
}
}
#if 0
static int CheckPS( input_thread_t *p_input )
{
uint8_t *p_peek;
int i_startcode = 0;
int i_size = input_Peek( p_input, &p_peek, 8196 );
while( i_size > 4 )
{
if( ( p_peek[0] == 0 ) && ( p_peek[1] == 0 ) &&
( p_peek[2] == 1 ) && ( p_peek[3] >= 0xb9 ) &&
++i_startcode >= 3 )
{
return 1;
}
p_peek++;
i_size--;
}
return 0;
}
#endif
/*****************************************************************************
* Open: initializes demux structures
*****************************************************************************/
static
int
Open
(
vlc_object_t
*
p_this
)
{
input_thread_t
*
p_input
=
(
input_thread_t
*
)
p_this
;
demux_sys_t
*
p_sys
;
vlc_bool_t
b_forced
=
VLC_FALSE
;
vlc_bool_t
b_extention
=
VLC_FALSE
;
uint32_t
header
;
uint8_t
*
p_peek
;
module_t
*
p_id3
;
if
(
p_input
->
psz_demux
&&
(
!
strncmp
(
p_input
->
psz_demux
,
"mpga"
,
4
)
||
!
strncmp
(
p_input
->
psz_demux
,
"mp3"
,
3
)
)
)
{
b_forced
=
VLC_TRUE
;
}
if
(
p_input
->
psz_name
)
{
int
i_len
=
strlen
(
p_input
->
psz_name
);
if
(
i_len
>
4
&&
!
strcasecmp
(
&
p_input
->
psz_name
[
i_len
-
4
],
".mp3"
)
)
{
b_extention
=
VLC_TRUE
;
}
}
/* skip possible id3 header */
p_id3
=
module_Need
(
p_input
,
"id3"
,
NULL
);
if
(
p_id3
)
{
module_Unneed
(
p_input
,
p_id3
);
}
if
(
input_Peek
(
p_input
,
&
p_peek
,
4
)
<
4
)
{
msg_Err
(
p_input
,
"cannot peek"
);
return
VLC_EGENERIC
;
}
if
(
!
HeaderCheck
(
header
=
GetDWBE
(
p_peek
)
)
)
{
vlc_bool_t
b_ok
=
VLC_FALSE
;
int
i_peek
;
if
(
!
b_forced
&&
!
b_extention
)
{
msg_Warn
(
p_input
,
"mpga module discarded"
);
return
VLC_EGENERIC
;
}
i_peek
=
input_Peek
(
p_input
,
&
p_peek
,
8096
);
while
(
i_peek
>
4
)
{
if
(
HeaderCheck
(
header
=
GetDWBE
(
p_peek
)
)
)
{
b_ok
=
VLC_TRUE
;
break
;
}
p_peek
+=
4
;
i_peek
-=
4
;
}
if
(
!
b_ok
&&
!
b_forced
)
{
msg_Warn
(
p_input
,
"mpga module discarded"
);
return
VLC_EGENERIC
;
}
}
p_input
->
pf_demux
=
Demux
;
p_input
->
p_demux_data
=
p_sys
=
malloc
(
sizeof
(
demux_sys_t
)
);
p_sys
->
i_time
=
0
;
p_sys
->
i_bitrate_avg
=
0
;
if
(
(
p_sys
->
s
=
stream_OpenInput
(
p_input
)
)
==
NULL
)
{
msg_Err
(
p_input
,
"cannot create stream"
);
goto
error
;
}
if
(
HeaderCheck
(
header
)
)
{
int
i_xing
;
uint8_t
*
p_xing
;
input_info_category_t
*
p_cat
;
static
char
*
mpga_mode
[
4
]
=
{
"stereo"
,
"joint stereo"
,
"dual channel"
,
"mono"
};
p_sys
->
i_bitrate_avg
=
MPGA_BITRATE
(
header
)
*
1000
;
if
(
(
i_xing
=
stream_Peek
(
p_sys
->
s
,
&
p_xing
,
1024
)
)
>=
21
)
{
int
i_skip
;
if
(
MPGA_VERSION
(
header
)
==
0
)
{
i_skip
=
MPGA_MODE
(
header
)
!=
3
?
36
:
21
;
}
else
{
i_skip
=
MPGA_MODE
(
header
)
!=
3
?
21
:
13
;
}
if
(
i_skip
+
8
<
i_xing
&&
!
strncmp
(
&
p_xing
[
i_skip
],
"Xing"
,
4
)
)
{
unsigned
int
i_flags
=
GetDWBE
(
&
p_xing
[
i_skip
+
4
]
);
unsigned
int
i_bytes
=
0
,
i_frames
=
0
;
p_xing
+=
i_skip
+
8
;
i_xing
-=
i_skip
+
8
;
i_skip
=
0
;
if
(
i_flags
&
0x01
&&
i_skip
+
4
<=
i_xing
)
/* XING_FRAMES */
{
i_frames
=
GetDWBE
(
&
p_xing
[
i_skip
]
);
i_skip
+=
4
;
}
if
(
i_flags
&
0x02
&&
i_skip
+
4
<=
i_xing
)
/* XING_BYTES */
{
i_bytes
=
GetDWBE
(
&
p_xing
[
i_skip
]
);
i_skip
+=
4
;
}
if
(
i_flags
&
0x04
)
/* XING_TOC */
{
i_skip
+=
100
;
}
if
(
i_flags
&
0x08
&&
i_skip
+
4
<=
i_xing
)
/* XING_VBR */
{
p_sys
->
i_bitrate_avg
=
GetDWBE
(
&
p_xing
[
i_skip
]
);
msg_Dbg
(
p_input
,
"xing vbr value present (%d)"
,
p_sys
->
i_bitrate_avg
);
}
else
if
(
i_frames
>
0
&&
i_bytes
>
0
)
{
p_sys
->
i_bitrate_avg
=
(
int64_t
)
i_bytes
*
(
int64_t
)
8
*
(
int64_t
)
MPGA_SAMPLE_RATE
(
header
)
/
(
int64_t
)
i_frames
/
(
int64_t
)
mpga_frame_samples
(
header
);
msg_Dbg
(
p_input
,
"xing frames&bytes value present (%db/s)"
,
p_sys
->
i_bitrate_avg
);
}
}
}
msg_Dbg
(
p_input
,
"version=%d layer=%d channels=%d samplerate=%d"
,
MPGA_VERSION
(
header
)
+
1
,
MPGA_LAYER
(
header
)
+
1
,
MPGA_CHANNELS
(
header
),
MPGA_SAMPLE_RATE
(
header
)
);
vlc_mutex_lock
(
&
p_input
->
stream
.
stream_lock
);
p_cat
=
input_InfoCategory
(
p_input
,
_
(
"MPEG"
)
);
input_AddInfo
(
p_cat
,
_
(
"Input Type"
),
"Audio MPEG-%d"
,
MPGA_VERSION
(
header
)
+
1
);
input_AddInfo
(
p_cat
,
_
(
"Layer"
),
"%d"
,
MPGA_LAYER
(
header
)
+
1
);
input_AddInfo
(
p_cat
,
_
(
"Mode"
),
mpga_mode
[
MPGA_MODE
(
header
)]
);
input_AddInfo
(
p_cat
,
_
(
"Sample Rate"
),
"%dHz"
,
MPGA_SAMPLE_RATE
(
header
)
);
input_AddInfo
(
p_cat
,
_
(
"Average Bitrate"
),
"%dKb/s"
,
p_sys
->
i_bitrate_avg
/
1000
);
vlc_mutex_unlock
(
&
p_input
->
stream
.
stream_lock
);
}
vlc_mutex_lock
(
&
p_input
->
stream
.
stream_lock
);
if
(
input_InitStream
(
p_input
,
0
)
==
-
1
)
{
vlc_mutex_unlock
(
&
p_input
->
stream
.
stream_lock
);
msg_Err
(
p_input
,
"cannot init stream"
);
goto
error
;
}
if
(
input_AddProgram
(
p_input
,
0
,
0
)
==
NULL
)
{
vlc_mutex_unlock
(
&
p_input
->
stream
.
stream_lock
);
msg_Err
(
p_input
,
"cannot add program"
);
goto
error
;
}
p_input
->
stream
.
pp_programs
[
0
]
->
b_is_ok
=
0
;
p_input
->
stream
.
p_selected_program
=
p_input
->
stream
.
pp_programs
[
0
];
p_input
->
stream
.
i_mux_rate
=
p_sys
->
i_bitrate_avg
/
8
/
50
;
p_sys
->
p_es
=
input_AddES
(
p_input
,
p_input
->
stream
.
p_selected_program
,
1
,
AUDIO_ES
,
NULL
,
0
);
p_sys
->
p_es
->
i_stream_id
=
1
;
p_sys
->
p_es
->
i_fourcc
=
VLC_FOURCC
(
'm'
,
'p'
,
'g'
,
'a'
);
input_SelectES
(
p_input
,
p_sys
->
p_es
);
p_input
->
stream
.
p_selected_program
->
b_is_ok
=
1
;
vlc_mutex_unlock
(
&
p_input
->
stream
.
stream_lock
);
return
VLC_SUCCESS
;
error:
if
(
p_sys
->
s
)
{
stream_Release
(
p_sys
->
s
);
}
free
(
p_sys
);
return
VLC_EGENERIC
;
}
/*****************************************************************************
* Demux: reads and demuxes data packets
*****************************************************************************
* Returns -1 in case of error, 0 in case of EOF, 1 otherwise
*****************************************************************************/
static
int
Demux
(
input_thread_t
*
p_input
)
{
demux_sys_t
*
p_sys
=
p_input
->
p_demux_data
;
pes_packet_t
*
p_pes
;
uint32_t
header
;
uint8_t
*
p_peek
;
if
(
stream_Peek
(
p_sys
->
s
,
&
p_peek
,
4
)
<
4
)
{
msg_Warn
(
p_input
,
"cannot peek"
);
return
0
;
}
if
(
!
HeaderCheck
(
header
=
GetDWBE
(
p_peek
)
)
)
{
/* we need to resynch */
vlc_bool_t
b_ok
=
VLC_FALSE
;
int
i_skip
=
0
;
int
i_peek
;
i_peek
=
stream_Peek
(
p_sys
->
s
,
&
p_peek
,
8096
);
if
(
i_peek
<
4
)
{
msg_Warn
(
p_input
,
"cannot peek"
);
return
0
;
}
while
(
i_peek
>=
4
)
{
if
(
HeaderCheck
(
header
=
GetDWBE
(
p_peek
)
)
)
{
b_ok
=
VLC_TRUE
;
break
;
}
p_peek
++
;
i_peek
--
;
i_skip
++
;
}
msg_Warn
(
p_input
,
"garbage=%d bytes"
,
i_skip
);
stream_Read
(
p_sys
->
s
,
NULL
,
i_skip
);
return
1
;
}
input_ClockManageRef
(
p_input
,
p_input
->
stream
.
p_selected_program
,
p_sys
->
i_time
*
9
/
100
);
if
(
(
p_pes
=
stream_PesPacket
(
p_sys
->
s
,
mpga_frame_size
(
header
)
)
)
==
NULL
)
{
msg_Warn
(
p_input
,
"cannot read data"
);
return
0
;
}
p_pes
->
i_dts
=
p_pes
->
i_pts
=
input_ClockGetTS
(
p_input
,
p_input
->
stream
.
p_selected_program
,
p_sys
->
i_time
*
9
/
100
);
if
(
!
p_sys
->
p_es
->
p_decoder_fifo
)
{
msg_Err
(
p_input
,
"no audio decoder"
);
input_DeletePES
(
p_input
->
p_method_data
,
p_pes
);
return
(
-
1
);
}
input_DecodePES
(
p_sys
->
p_es
->
p_decoder_fifo
,
p_pes
);
p_sys
->
i_time
+=
(
mtime_t
)
1000000
*
(
mtime_t
)
mpga_frame_samples
(
header
)
/
(
mtime_t
)
MPGA_SAMPLE_RATE
(
header
);
return
(
1
);
}
/*****************************************************************************
* Close: frees unused data
*****************************************************************************/
static
void
Close
(
vlc_object_t
*
p_this
)
{
input_thread_t
*
p_input
=
(
input_thread_t
*
)
p_this
;
demux_sys_t
*
p_sys
=
p_input
->
p_demux_data
;
if
(
p_sys
->
s
)
{
stream_Release
(
p_sys
->
s
);
}
free
(
p_sys
);
}
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