Commit af480570 authored by Timothy B. Terriberry's avatar Timothy B. Terriberry Committed by Rafaël Carré

Opus decoder.

This patch uses the information passed by the demuxer in block_t's
i_nb_samples and i_length to properly handle pre-skip, seeking
pre-roll, and end-trim. Multi-channel decoding should work. It also
adds .opus to the list of supported formats.
Signed-off-by: default avatarRafaël Carré <funman@videolan.org>
parent 675072a8
...@@ -9,6 +9,7 @@ Important changes for packagers: ...@@ -9,6 +9,7 @@ Important changes for packagers:
* /extras/contrib has been replaced by a better system in /contrib * /extras/contrib has been replaced by a better system in /contrib
Codecs: Codecs:
* Support for OPUS via libopus.
* Support for CDXL, Ut Video, VBLE, Dxtory codecs via libavcodec. * Support for CDXL, Ut Video, VBLE, Dxtory codecs via libavcodec.
* Numerous improvements in OpenMAX IL codec * Numerous improvements in OpenMAX IL codec
* Support for Ulead DV audio * Support for Ulead DV audio
......
...@@ -617,7 +617,7 @@ AC_CHECK_FUNC(getopt_long,, [ ...@@ -617,7 +617,7 @@ AC_CHECK_FUNC(getopt_long,, [
AC_SUBST(GNUGETOPT_LIBS) AC_SUBST(GNUGETOPT_LIBS)
AC_CHECK_LIB(m,cos,[ AC_CHECK_LIB(m,cos,[
VLC_ADD_LIBS([adjust wave ripple psychedelic gradient a52tofloat32 dtstofloat32 x264 goom visual panoramix rotate noise grain scene kate flac lua chorus_flanger freetype avcodec avformat access_avio swscale postproc i420_rgb faad twolame equalizer spatializer param_eq samplerate freetype mpc dmo mp4 quicktime qt4 compressor headphone_channel_mixer normvol audiobargraph_a speex mono colorthres extract ball access_imem hotkeys mosaic gaussianblur dbus x26410b hqdn3d anaglyph oldrc ncurses],[-lm]) VLC_ADD_LIBS([adjust wave ripple psychedelic gradient a52tofloat32 dtstofloat32 x264 goom visual panoramix rotate noise grain scene kate flac lua chorus_flanger freetype avcodec avformat access_avio swscale postproc i420_rgb faad twolame equalizer spatializer param_eq samplerate freetype mpc dmo mp4 quicktime qt4 compressor headphone_channel_mixer normvol audiobargraph_a speex opus mono colorthres extract ball access_imem hotkeys mosaic gaussianblur dbus x26410b hqdn3d anaglyph oldrc ncurses],[-lm])
LIBM="-lm" LIBM="-lm"
], [ ], [
LIBM="" LIBM=""
...@@ -2711,6 +2711,11 @@ AS_IF([test "${enable_speex}" != "no"], [ ...@@ -2711,6 +2711,11 @@ AS_IF([test "${enable_speex}" != "no"], [
]) ])
AM_CONDITIONAL([HAVE_SPEEXDSP], [test "$have_speexdsp" = "yes"]) AM_CONDITIONAL([HAVE_SPEEXDSP], [test "$have_speexdsp" = "yes"])
dnl
dnl Opus plugin
dnl
PKG_ENABLE_MODULES_VLC([OPUS], [], [ogg opus], [Opus support], [auto])
dnl dnl
dnl theora decoder plugin dnl theora decoder plugin
dnl dnl
......
...@@ -42,7 +42,7 @@ complete list of available options. ...@@ -42,7 +42,7 @@ complete list of available options.
.B VLC .B VLC
recognizes several URL-style items: recognizes several URL-style items:
.TP .TP
.B *.mpg, *.vob, *.avi, *.mp3, *.ogg .B *.mpg, *.vob, *.avi, *.mp3, *.ogg, *.opus
Various multimedia file formats Various multimedia file formats
.TP .TP
.B dvd://[<device>][@<raw device>][#[<title>][:[<chapter>][:<angle>]]] .B dvd://[<device>][@<raw device>][#[<title>][:[<chapter>][:<angle>]]]
......
...@@ -142,8 +142,9 @@ FunctionEnd ...@@ -142,8 +142,9 @@ FunctionEnd
!insertmacro ${_action} ".mp3" !insertmacro ${_action} ".mp3"
!insertmacro ${_action} ".mpc" !insertmacro ${_action} ".mpc"
!insertmacro ${_action} ".mpga" !insertmacro ${_action} ".mpga"
!insertmacro ${_action} ".oma"
!insertmacro ${_action} ".oga" !insertmacro ${_action} ".oga"
!insertmacro ${_action} ".oma"
!insertmacro ${_action} ".opus"
!insertmacro ${_action} ".qcp" !insertmacro ${_action} ".qcp"
!insertmacro ${_action} ".ra" !insertmacro ${_action} ".ra"
!insertmacro ${_action} ".rmi" !insertmacro ${_action} ".rmi"
......
...@@ -228,6 +228,7 @@ typedef enum vlc_dialog { ...@@ -228,6 +228,7 @@ typedef enum vlc_dialog {
"*.oga;" \ "*.oga;" \
"*.ogg;" \ "*.ogg;" \
"*.oma;" \ "*.oma;" \
"*.opus;" \
"*.qcp;" \ "*.qcp;" \
"*.ra;" \ "*.ra;" \
"*.rmi;" \ "*.rmi;" \
......
...@@ -226,6 +226,7 @@ $Id$ ...@@ -226,6 +226,7 @@ $Id$
* opencv_example: OpenCV example (face identification) * opencv_example: OpenCV example (face identification)
* opencv_wrapper: OpenCV wrapper video filter * opencv_wrapper: OpenCV wrapper video filter
* opensles_android: OpenSL ES audio output for Android * opensles_android: OpenSL ES audio output for Android
* opus: a opus audio decoder/packetizer using the libopus library
* os2drive: service discovery for OS/2 drives * os2drive: service discovery for OS/2 drives
* osd_parser: OSD import module * osd_parser: OSD import module
* osdmenu: video_filter for displaying and streaming a On Screen Display menu * osdmenu: video_filter for displaying and streaming a On Screen Display menu
......
...@@ -9,6 +9,7 @@ SOURCES_theora = theora.c ...@@ -9,6 +9,7 @@ SOURCES_theora = theora.c
SOURCES_tremor = vorbis.c SOURCES_tremor = vorbis.c
SOURCES_speex = speex.c SOURCES_speex = speex.c
SOURCES_adpcm = adpcm.c SOURCES_adpcm = adpcm.c
SOURCES_opus = opus.c opus_header.c opus_header.h
SOURCES_uleaddvaudio = uleaddvaudio.c SOURCES_uleaddvaudio = uleaddvaudio.c
SOURCES_mpeg_audio = mpeg_audio.c SOURCES_mpeg_audio = mpeg_audio.c
SOURCES_libmpeg2 = libmpeg2.c SOURCES_libmpeg2 = libmpeg2.c
......
This diff is collapsed.
/* Copyright (C)2012 Xiph.Org Foundation
File: opus_header.c
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
- Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include "opus_header.h"
#include <string.h>
#include <stdio.h>
/* Header contents:
- "OpusHead" (64 bits)
- version number (8 bits)
- Channels C (8 bits)
- Pre-skip (16 bits)
- Sampling rate (32 bits)
- Gain in dB (16 bits, S7.8)
- Mapping (8 bits, 0=single stream (mono/stereo) 1=Vorbis mapping,
2..254: reserved, 255: multistream with no mapping)
- if (mapping != 0)
- N = totel number of streams (8 bits)
- M = number of paired streams (8 bits)
- C times channel origin
- if (C<2*M)
- stream = byte/2
- if (byte&0x1 == 0)
- left
else
- right
- else
- stream = byte-M
*/
typedef struct {
unsigned char *data;
int maxlen;
int pos;
} Packet;
typedef struct {
const unsigned char *data;
int maxlen;
int pos;
} ROPacket;
static int write_uint32(Packet *p, ogg_uint32_t val)
{
if (p->pos>p->maxlen-4)
return 0;
p->data[p->pos ] = (val ) & 0xFF;
p->data[p->pos+1] = (val>> 8) & 0xFF;
p->data[p->pos+2] = (val>>16) & 0xFF;
p->data[p->pos+3] = (val>>24) & 0xFF;
p->pos += 4;
return 1;
}
static int write_uint16(Packet *p, ogg_uint16_t val)
{
if (p->pos>p->maxlen-2)
return 0;
p->data[p->pos ] = (val ) & 0xFF;
p->data[p->pos+1] = (val>> 8) & 0xFF;
p->pos += 2;
return 1;
}
static int write_chars(Packet *p, const unsigned char *str, int nb_chars)
{
if (p->pos>p->maxlen-nb_chars)
return 0;
for (int i=0;i<nb_chars;i++)
p->data[p->pos++] = str[i];
return 1;
}
static int read_uint32(ROPacket *p, ogg_uint32_t *val)
{
if (p->pos>p->maxlen-4)
return 0;
*val = (ogg_uint32_t)p->data[p->pos ];
*val |= (ogg_uint32_t)p->data[p->pos+1]<< 8;
*val |= (ogg_uint32_t)p->data[p->pos+2]<<16;
*val |= (ogg_uint32_t)p->data[p->pos+3]<<24;
p->pos += 4;
return 1;
}
static int read_uint16(ROPacket *p, ogg_uint16_t *val)
{
if (p->pos>p->maxlen-2)
return 0;
*val = (ogg_uint16_t)p->data[p->pos ];
*val |= (ogg_uint16_t)p->data[p->pos+1]<<8;
p->pos += 2;
return 1;
}
static int read_chars(ROPacket *p, unsigned char *str, int nb_chars)
{
if (p->pos>p->maxlen-nb_chars)
return 0;
for (int i=0;i<nb_chars;i++)
str[i] = p->data[p->pos++];
return 1;
}
int opus_header_parse(const unsigned char *packet, int len, OpusHeader *h)
{
char str[9];
ROPacket p;
unsigned char ch;
ogg_uint16_t shortval;
p.data = packet;
p.maxlen = len;
p.pos = 0;
str[8] = 0;
if (len<19)return 0;
read_chars(&p, (unsigned char*)str, 8);
if (memcmp(str, "OpusHead", 8)!=0)
return 0;
if (!read_chars(&p, &ch, 1))
return 0;
h->version = ch;
if((h->version&240) != 0) /* Only major version 0 supported. */
return 0;
if (!read_chars(&p, &ch, 1))
return 0;
h->channels = ch;
if (h->channels == 0)
return 0;
if (!read_uint16(&p, &shortval))
return 0;
h->preskip = shortval;
if (!read_uint32(&p, &h->input_sample_rate))
return 0;
if (!read_uint16(&p, &shortval))
return 0;
h->gain = (short)shortval;
if (!read_chars(&p, &ch, 1))
return 0;
h->channel_mapping = ch;
if (h->channel_mapping != 0)
{
if (!read_chars(&p, &ch, 1))
return 0;
if (ch<1)
return 0;
h->nb_streams = ch;
if (!read_chars(&p, &ch, 1))
return 0;
if (ch>h->nb_streams || (ch+h->nb_streams)>255)
return 0;
h->nb_coupled = ch;
/* Multi-stream support */
for (int i=0;i<h->channels;i++)
{
if (!read_chars(&p, &h->stream_map[i], 1))
return 0;
if (h->stream_map[i]>(h->nb_streams+h->nb_coupled) && h->stream_map[i]!=255)
return 0;
}
} else {
if(h->channels>2)
return 0;
h->nb_streams = 1;
h->nb_coupled = h->channels>1;
h->stream_map[0]=0;
h->stream_map[1]=1;
}
/*For version 0/1 we know there won't be any more data
so reject any that have data past the end.*/
if ((h->version==0 || h->version==1) && p.pos != len)
return 0;
return 1;
}
int opus_header_to_packet(const OpusHeader *h, unsigned char *packet, int len)
{
Packet p;
unsigned char ch;
p.data = packet;
p.maxlen = len;
p.pos = 0;
if (len<19)return 0;
if (!write_chars(&p, (const unsigned char*)"OpusHead", 8))
return 0;
/* Version is 1 */
ch = 1;
if (!write_chars(&p, &ch, 1))
return 0;
ch = h->channels;
if (!write_chars(&p, &ch, 1))
return 0;
if (!write_uint16(&p, h->preskip))
return 0;
if (!write_uint32(&p, h->input_sample_rate))
return 0;
if (!write_uint16(&p, h->gain))
return 0;
ch = h->channel_mapping;
if (!write_chars(&p, &ch, 1))
return 0;
if (h->channel_mapping != 0)
{
ch = h->nb_streams;
if (!write_chars(&p, &ch, 1))
return 0;
ch = h->nb_coupled;
if (!write_chars(&p, &ch, 1))
return 0;
/* Multi-stream support */
for (int i=0;i<h->channels;i++)
{
if (!write_chars(&p, &h->stream_map[i], 1))
return 0;
}
}
return p.pos;
}
/* Copyright (C)2012 Xiph.Org Foundation
File: opus_header.h
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
- Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef OPUS_HEADER_H
#define OPUS_HEADER_H
#include <ogg/ogg.h>
typedef struct {
int version;
int channels; /* Number of channels: 1..255 */
int preskip;
ogg_uint32_t input_sample_rate;
int gain; /* in dB S7.8 should be zero whenever possible */
int channel_mapping;
/* The rest is only used if channel_mapping != 0 */
int nb_streams;
int nb_coupled;
unsigned char stream_map[255];
} OpusHeader;
int opus_header_parse(const unsigned char *header, int len, OpusHeader *h);
int opus_header_to_packet(const OpusHeader *h, unsigned char *packet, int len);
#endif
...@@ -978,8 +978,8 @@ void SPrefsPanel::assoDialog() ...@@ -978,8 +978,8 @@ void SPrefsPanel::assoDialog()
aTa( ".a52" ); aTa( ".aac" ); aTa( ".ac3" ); aTa( ".dts" ); aTa( ".flac" ); aTa( ".a52" ); aTa( ".aac" ); aTa( ".ac3" ); aTa( ".dts" ); aTa( ".flac" );
aTa( ".m4a" ); aTa( ".m4p" ); aTa( ".mka" ); aTa( ".mod" ); aTa( ".mp1" ); aTa( ".m4a" ); aTa( ".m4p" ); aTa( ".mka" ); aTa( ".mod" ); aTa( ".mp1" );
aTa( ".mp2" ); aTa( ".mp3" ); aTa( ".oma" ); aTa( ".oga" ); aTa( ".spx" ); aTa( ".mp2" ); aTa( ".mp3" ); aTa( ".oma" ); aTa( ".oga" ); aTa( ".opus" );
aTa( ".tta" ); aTa( ".wav" ); aTa( ".wma" ); aTa( ".xm" ); aTa( ".spx" ); aTa( ".tta" ); aTa( ".wav" ); aTa( ".wma" ); aTa( ".xm" );
audioType->setCheckState( 0, ( i_temp > 0 ) ? audioType->setCheckState( 0, ( i_temp > 0 ) ?
( ( i_temp == audioType->childCount() ) ? ( ( i_temp == audioType->childCount() ) ?
Qt::Checked : Qt::PartiallyChecked ) Qt::Checked : Qt::PartiallyChecked )
......
...@@ -132,6 +132,7 @@ demux_t *demux_New( vlc_object_t *p_obj, input_thread_t *p_parent_input, ...@@ -132,6 +132,7 @@ demux_t *demux_New( vlc_object_t *p_obj, input_thread_t *p_parent_input,
{ "ogg", "ogg" }, { "ogm", "ogg" }, /* legacy Ogg */ { "ogg", "ogg" }, { "ogm", "ogg" }, /* legacy Ogg */
{ "oga", "ogg" }, { "spx", "ogg" }, { "ogv", "ogg" }, { "oga", "ogg" }, { "spx", "ogg" }, { "ogv", "ogg" },
{ "ogx", "ogg" }, /*RFC5334*/ { "ogx", "ogg" }, /*RFC5334*/
{ "opus", "ogg" }, /*draft-terriberry-oggopus-01*/
{ "pva", "pva" }, { "pva", "pva" },
{ "rm", "avformat" }, { "rm", "avformat" },
{ "m4v", "m4v" }, { "m4v", "m4v" },
......
...@@ -74,6 +74,7 @@ static const struct ...@@ -74,6 +74,7 @@ static const struct
{ ".ogm", "application/ogg" }, { ".ogm", "application/ogg" },
{ ".ogv", "video/ogg" }, { ".ogv", "video/ogg" },
{ ".ogx", "application/ogg" }, { ".ogx", "application/ogg" },
{ ".opus", "audio/ogg; codecs=opus" },
{ ".spx", "audio/ogg" }, { ".spx", "audio/ogg" },
{ ".wav", "audio/wav" }, { ".wav", "audio/wav" },
{ ".wma", "audio/x-ms-wma" }, { ".wma", "audio/x-ms-wma" },
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment