Commit 7ca6e16f authored by Timothy B. Terriberry's avatar Timothy B. Terriberry Committed by Jean-Baptiste Kempf

Opus decoder.

Manually backported from af4805700c96f17972ab6d3292404f9248be2b90
Signed-off-by: default avatarJean-Baptiste Kempf <jb@videolan.org>
parent 94d204fb
...@@ -5,6 +5,9 @@ Audio Output: ...@@ -5,6 +5,9 @@ Audio Output:
* Improve playback synchronization with PulseAudio. * Improve playback synchronization with PulseAudio.
* Fix ALSA digital pass-through ("S/PDIF"). * Fix ALSA digital pass-through ("S/PDIF").
Codecs:
* Support for OPUS via libopus.
Windows: Windows:
* Fix Wallpaper mode on Windows 7 * Fix Wallpaper mode on Windows 7
......
...@@ -639,7 +639,7 @@ AC_CHECK_FUNC(getopt_long,, [ ...@@ -639,7 +639,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 mod mpc dmo quicktime realvideo qt4 compressor headphone_channel_mixer normvol audiobargraph_a speex mono colorthres extract ball access_imem hotkeys mosaic gaussianblur dbus x264 hqdn3d],[-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 mod mpc dmo quicktime realvideo qt4 compressor headphone_channel_mixer normvol audiobargraph_a speex opus mono colorthres extract ball access_imem hotkeys mosaic gaussianblur dbus x264 hqdn3d],[-lm])
LIBM="-lm" LIBM="-lm"
], [ ], [
LIBM="" LIBM=""
...@@ -2810,6 +2810,11 @@ AS_IF([test "${enable_speex}" != "no"], [ ...@@ -2810,6 +2810,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>]]]
......
...@@ -288,6 +288,7 @@ FunctionEnd ...@@ -288,6 +288,7 @@ FunctionEnd
!insertmacro ${_action} ".mp3" !insertmacro ${_action} ".mp3"
!insertmacro ${_action} ".mpc" !insertmacro ${_action} ".mpc"
!insertmacro ${_action} ".oma" !insertmacro ${_action} ".oma"
!insertmacro ${_action} ".opus"
!insertmacro ${_action} ".oga" !insertmacro ${_action} ".oga"
!insertmacro ${_action} ".qcp" !insertmacro ${_action} ".qcp"
!insertmacro ${_action} ".rmi" !insertmacro ${_action} ".rmi"
......
...@@ -212,6 +212,7 @@ typedef enum vlc_dialog { ...@@ -212,6 +212,7 @@ typedef enum vlc_dialog {
"*.oga;" \ "*.oga;" \
"*.ogg;" \ "*.ogg;" \
"*.oma;" \ "*.oma;" \
"*.opus;" \
"*.qcp;" \ "*.qcp;" \
"*.ra;" \ "*.ra;" \
"*.rmi;" \ "*.rmi;" \
......
...@@ -236,6 +236,7 @@ $Id$ ...@@ -236,6 +236,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
* 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
* oss: audio output module using the OSS /dev/dsp interface * oss: audio output module using the OSS /dev/dsp interface
......
...@@ -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_mpeg_audio = mpeg_audio.c SOURCES_mpeg_audio = mpeg_audio.c
SOURCES_libmpeg2 = libmpeg2.c SOURCES_libmpeg2 = libmpeg2.c
SOURCES_rawvideo = rawvideo.c SOURCES_rawvideo = rawvideo.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
...@@ -974,8 +974,8 @@ void SPrefsPanel::assoDialog() ...@@ -974,8 +974,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" },
......
...@@ -217,6 +217,7 @@ static const struct ...@@ -217,6 +217,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