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
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 = \
...
@@ -24,7 +24,7 @@ SOURCES_ts_dvbpsi = \
ts.c \
ts.c \
$(NULL)
$(NULL)
SOURCES_
audio
= \
SOURCES_
mpga
= \
audio
.c \
mpga
.c \
$(NULL)
$(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