mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-04 02:42:49 -04:00
Support loading Opus audio files via libopusfile.
This commit is contained in:
parent
257311cc0c
commit
828f1c10ca
6
dtool/src/parser-inc/opus/opus.h
Normal file
6
dtool/src/parser-inc/opus/opus.h
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
#ifndef OPUS_H
|
||||||
|
#define OPUS_H
|
||||||
|
|
||||||
|
#include "opus_types.h"
|
||||||
|
|
||||||
|
#endif
|
19
dtool/src/parser-inc/opus/opus_types.h
Normal file
19
dtool/src/parser-inc/opus/opus_types.h
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
#ifndef OPUS_TYPES_H
|
||||||
|
#define OPUS_TYPES_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
typedef int16_t opus_int16;
|
||||||
|
typedef uint16_t opus_uint16;
|
||||||
|
typedef int32_t opus_int32;
|
||||||
|
typedef uint32_t opus_uint32;
|
||||||
|
|
||||||
|
#define opus_int int
|
||||||
|
#define opus_int64 long long
|
||||||
|
#define opus_int8 signed char
|
||||||
|
|
||||||
|
#define opus_uint unsigned int
|
||||||
|
#define opus_uint64 unsigned long long
|
||||||
|
#define opus_uint8 unsigned char
|
||||||
|
|
||||||
|
#endif
|
8
dtool/src/parser-inc/opus/opusfile.h
Normal file
8
dtool/src/parser-inc/opus/opusfile.h
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
#include "opus.h"
|
||||||
|
|
||||||
|
typedef struct OpusHead OpusHead;
|
||||||
|
typedef struct OpusTags OpusTags;
|
||||||
|
typedef struct OpusPictureTag OpusPictureTag;
|
||||||
|
typedef struct OpusServerInfo OpusServerInfo;
|
||||||
|
typedef struct OpusFileCallbacks OpusFileCallbacks;
|
||||||
|
typedef struct OggOpusFile OggOpusFile;
|
@ -77,7 +77,7 @@ PkgListSet(["PYTHON", "DIRECT", # Python support
|
|||||||
"EGL", # OpenGL (ES) integration
|
"EGL", # OpenGL (ES) integration
|
||||||
"EIGEN", # Linear algebra acceleration
|
"EIGEN", # Linear algebra acceleration
|
||||||
"OPENAL", "FMODEX", # Audio playback
|
"OPENAL", "FMODEX", # Audio playback
|
||||||
"VORBIS", "FFMPEG", "SWSCALE", "SWRESAMPLE", # Audio decoding
|
"VORBIS", "OPUS", "FFMPEG", "SWSCALE", "SWRESAMPLE", # Audio decoding
|
||||||
"ODE", "PHYSX", "BULLET", "PANDAPHYSICS", # Physics
|
"ODE", "PHYSX", "BULLET", "PANDAPHYSICS", # Physics
|
||||||
"SPEEDTREE", # SpeedTree
|
"SPEEDTREE", # SpeedTree
|
||||||
"ZLIB", "PNG", "JPEG", "TIFF", "OPENEXR", "SQUISH", # 2D Formats support
|
"ZLIB", "PNG", "JPEG", "TIFF", "OPENEXR", "SQUISH", # 2D Formats support
|
||||||
@ -700,6 +700,10 @@ if (COMPILER == "MSVC"):
|
|||||||
LibName("VORBIS", GetThirdpartyDir() + "vorbis/lib/libogg_static.lib")
|
LibName("VORBIS", GetThirdpartyDir() + "vorbis/lib/libogg_static.lib")
|
||||||
LibName("VORBIS", GetThirdpartyDir() + "vorbis/lib/libvorbis_static.lib")
|
LibName("VORBIS", GetThirdpartyDir() + "vorbis/lib/libvorbis_static.lib")
|
||||||
LibName("VORBIS", GetThirdpartyDir() + "vorbis/lib/libvorbisfile_static.lib")
|
LibName("VORBIS", GetThirdpartyDir() + "vorbis/lib/libvorbisfile_static.lib")
|
||||||
|
if (PkgSkip("OPUS")==0):
|
||||||
|
LibName("OPUS", GetThirdpartyDir() + "opus/lib/libogg_static.lib")
|
||||||
|
LibName("OPUS", GetThirdpartyDir() + "opus/lib/libopus_static.lib")
|
||||||
|
LibName("OPUS", GetThirdpartyDir() + "opus/lib/libopusfile_static.lib")
|
||||||
for pkg in MAYAVERSIONS:
|
for pkg in MAYAVERSIONS:
|
||||||
if (PkgSkip(pkg)==0):
|
if (PkgSkip(pkg)==0):
|
||||||
LibName(pkg, '"' + SDK[pkg] + '/lib/Foundation.lib"')
|
LibName(pkg, '"' + SDK[pkg] + '/lib/Foundation.lib"')
|
||||||
@ -819,6 +823,7 @@ if (COMPILER=="GCC"):
|
|||||||
SmartPkgEnable("VRPN", "", ("vrpn", "quat"), ("vrpn", "quat.h", "vrpn/vrpn_Types.h"))
|
SmartPkgEnable("VRPN", "", ("vrpn", "quat"), ("vrpn", "quat.h", "vrpn/vrpn_Types.h"))
|
||||||
SmartPkgEnable("BULLET", "bullet", ("BulletSoftBody", "BulletDynamics", "BulletCollision", "LinearMath"), ("bullet", "bullet/btBulletDynamicsCommon.h"))
|
SmartPkgEnable("BULLET", "bullet", ("BulletSoftBody", "BulletDynamics", "BulletCollision", "LinearMath"), ("bullet", "bullet/btBulletDynamicsCommon.h"))
|
||||||
SmartPkgEnable("VORBIS", "vorbisfile",("vorbisfile", "vorbis", "ogg"), ("ogg/ogg.h", "vorbis/vorbisfile.h"))
|
SmartPkgEnable("VORBIS", "vorbisfile",("vorbisfile", "vorbis", "ogg"), ("ogg/ogg.h", "vorbis/vorbisfile.h"))
|
||||||
|
SmartPkgEnable("OPUS", "opusfile", ("opusfile", "opus", "ogg"), ("ogg/ogg.h", "opus/opusfile.h"))
|
||||||
SmartPkgEnable("JPEG", "", ("jpeg"), "jpeglib.h")
|
SmartPkgEnable("JPEG", "", ("jpeg"), "jpeglib.h")
|
||||||
SmartPkgEnable("PNG", "libpng", ("png"), "png.h", tool = "libpng-config")
|
SmartPkgEnable("PNG", "libpng", ("png"), "png.h", tool = "libpng-config")
|
||||||
|
|
||||||
@ -2236,6 +2241,7 @@ DTOOL_CONFIG=[
|
|||||||
("HAVE_PNM", '1', '1'),
|
("HAVE_PNM", '1', '1'),
|
||||||
("HAVE_STB_IMAGE", '1', '1'),
|
("HAVE_STB_IMAGE", '1', '1'),
|
||||||
("HAVE_VORBIS", 'UNDEF', 'UNDEF'),
|
("HAVE_VORBIS", 'UNDEF', 'UNDEF'),
|
||||||
|
("HAVE_OPUS", 'UNDEF', 'UNDEF'),
|
||||||
("HAVE_FREETYPE", 'UNDEF', 'UNDEF'),
|
("HAVE_FREETYPE", 'UNDEF', 'UNDEF'),
|
||||||
("HAVE_FFTW", 'UNDEF', 'UNDEF'),
|
("HAVE_FFTW", 'UNDEF', 'UNDEF'),
|
||||||
("HAVE_OPENSSL", 'UNDEF', 'UNDEF'),
|
("HAVE_OPENSSL", 'UNDEF', 'UNDEF'),
|
||||||
@ -3880,10 +3886,10 @@ if (not RUNTIME):
|
|||||||
#
|
#
|
||||||
|
|
||||||
if (not RUNTIME):
|
if (not RUNTIME):
|
||||||
OPTS=['DIR:panda/src/movies', 'BUILDING:PANDA', 'VORBIS']
|
OPTS=['DIR:panda/src/movies', 'BUILDING:PANDA', 'VORBIS', 'OPUS']
|
||||||
TargetAdd('p3movies_composite1.obj', opts=OPTS, input='p3movies_composite1.cxx')
|
TargetAdd('p3movies_composite1.obj', opts=OPTS, input='p3movies_composite1.cxx')
|
||||||
|
|
||||||
OPTS=['DIR:panda/src/movies', 'VORBIS', 'PYTHON']
|
OPTS=['DIR:panda/src/movies', 'VORBIS', 'OPUS', 'PYTHON']
|
||||||
IGATEFILES=GetDirectoryContents('panda/src/movies', ["*.h", "*_composite*.cxx"])
|
IGATEFILES=GetDirectoryContents('panda/src/movies', ["*.h", "*_composite*.cxx"])
|
||||||
TargetAdd('libp3movies.in', opts=OPTS, input=IGATEFILES)
|
TargetAdd('libp3movies.in', opts=OPTS, input=IGATEFILES)
|
||||||
TargetAdd('libp3movies.in', opts=['IMOD:panda3d.core', 'ILIB:libp3movies', 'SRCDIR:panda/src/movies'])
|
TargetAdd('libp3movies.in', opts=['IMOD:panda3d.core', 'ILIB:libp3movies', 'SRCDIR:panda/src/movies'])
|
||||||
@ -4017,7 +4023,7 @@ if (not RUNTIME):
|
|||||||
if (not RUNTIME):
|
if (not RUNTIME):
|
||||||
OPTS=['DIR:panda/metalibs/panda', 'BUILDING:PANDA', 'JPEG', 'PNG', 'HARFBUZZ',
|
OPTS=['DIR:panda/metalibs/panda', 'BUILDING:PANDA', 'JPEG', 'PNG', 'HARFBUZZ',
|
||||||
'TIFF', 'OPENEXR', 'ZLIB', 'OPENSSL', 'FREETYPE', 'FFTW', 'ADVAPI', 'WINSOCK2',
|
'TIFF', 'OPENEXR', 'ZLIB', 'OPENSSL', 'FREETYPE', 'FFTW', 'ADVAPI', 'WINSOCK2',
|
||||||
'SQUISH', 'NVIDIACG', 'VORBIS', 'WINUSER', 'WINMM', 'WINGDI', 'IPHLPAPI']
|
'SQUISH', 'NVIDIACG', 'VORBIS', 'OPUS', 'WINUSER', 'WINMM', 'WINGDI', 'IPHLPAPI']
|
||||||
|
|
||||||
TargetAdd('panda_panda.obj', opts=OPTS, input='panda.cxx')
|
TargetAdd('panda_panda.obj', opts=OPTS, input='panda.cxx')
|
||||||
|
|
||||||
@ -7226,10 +7232,14 @@ def MakeInstallerOSX():
|
|||||||
|
|
||||||
if not PkgSkip("FFMPEG"):
|
if not PkgSkip("FFMPEG"):
|
||||||
dist.write(' <choice id="ffmpeg" title="FFMpeg Plug-In" tooltip="FFMpeg video and audio decoding plug-in" description="This package contains the FFMpeg plug-in, which is used for decoding video and audio files with OpenAL.')
|
dist.write(' <choice id="ffmpeg" title="FFMpeg Plug-In" tooltip="FFMpeg video and audio decoding plug-in" description="This package contains the FFMpeg plug-in, which is used for decoding video and audio files with OpenAL.')
|
||||||
if PkgSkip("VORBIS"):
|
if PkgSkip("VORBIS") and PkgSkip("OPUS"):
|
||||||
dist.write(' It is not required for loading .wav files, which Panda3D can read out of the box.">\n')
|
dist.write(' It is not required for loading .wav files, which Panda3D can read out of the box.">\n')
|
||||||
else:
|
elif PkgSkip("VORBIS"):
|
||||||
|
dist.write(' It is not required for loading .wav or .opus files, which Panda3D can read out of the box.">\n')
|
||||||
|
elif PkgSkip("OPUS"):
|
||||||
dist.write(' It is not required for loading .wav or .ogg files, which Panda3D can read out of the box.">\n')
|
dist.write(' It is not required for loading .wav or .ogg files, which Panda3D can read out of the box.">\n')
|
||||||
|
else:
|
||||||
|
dist.write(' It is not required for loading .wav, .ogg or .opus files, which Panda3D can read out of the box.">\n')
|
||||||
dist.write(' <pkg-ref id="org.panda3d.panda3d.ffmpeg.pkg"/>\n')
|
dist.write(' <pkg-ref id="org.panda3d.panda3d.ffmpeg.pkg"/>\n')
|
||||||
dist.write(' </choice>\n')
|
dist.write(' </choice>\n')
|
||||||
|
|
||||||
|
@ -23,6 +23,8 @@
|
|||||||
#include "movieTypeRegistry.h"
|
#include "movieTypeRegistry.h"
|
||||||
#include "movieVideo.h"
|
#include "movieVideo.h"
|
||||||
#include "movieVideoCursor.h"
|
#include "movieVideoCursor.h"
|
||||||
|
#include "opusAudio.h"
|
||||||
|
#include "opusAudioCursor.h"
|
||||||
#include "userDataAudio.h"
|
#include "userDataAudio.h"
|
||||||
#include "userDataAudioCursor.h"
|
#include "userDataAudioCursor.h"
|
||||||
#include "vorbisAudio.h"
|
#include "vorbisAudio.h"
|
||||||
@ -51,6 +53,11 @@ ConfigVariableList load_video_type
|
|||||||
"either the name of a module, or a space-separate list of filename "
|
"either the name of a module, or a space-separate list of filename "
|
||||||
"extensions, followed by the name of the module."));
|
"extensions, followed by the name of the module."));
|
||||||
|
|
||||||
|
ConfigVariableBool opus_enable_seek
|
||||||
|
("opus-enable-seek", true,
|
||||||
|
PRC_DESC("Set this to false if you're having trouble with seeking while "
|
||||||
|
"using the Opus decoder."));
|
||||||
|
|
||||||
ConfigVariableBool vorbis_enable_seek
|
ConfigVariableBool vorbis_enable_seek
|
||||||
("vorbis-enable-seek", true,
|
("vorbis-enable-seek", true,
|
||||||
PRC_DESC("Set this to false if you're having trouble with seeking while "
|
PRC_DESC("Set this to false if you're having trouble with seeking while "
|
||||||
@ -91,6 +98,11 @@ init_libmovies() {
|
|||||||
WavAudio::init_type();
|
WavAudio::init_type();
|
||||||
WavAudioCursor::init_type();
|
WavAudioCursor::init_type();
|
||||||
|
|
||||||
|
#ifdef HAVE_OPUS
|
||||||
|
OpusAudio::init_type();
|
||||||
|
OpusAudioCursor::init_type();
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_VORBIS
|
#ifdef HAVE_VORBIS
|
||||||
VorbisAudio::init_type();
|
VorbisAudio::init_type();
|
||||||
VorbisAudioCursor::init_type();
|
VorbisAudioCursor::init_type();
|
||||||
@ -100,6 +112,10 @@ init_libmovies() {
|
|||||||
reg->register_audio_type(&FlacAudio::make, "flac");
|
reg->register_audio_type(&FlacAudio::make, "flac");
|
||||||
reg->register_audio_type(&WavAudio::make, "wav wave");
|
reg->register_audio_type(&WavAudio::make, "wav wave");
|
||||||
|
|
||||||
|
#ifdef HAVE_OPUS
|
||||||
|
reg->register_audio_type(&OpusAudio::make, "opus");
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_VORBIS
|
#ifdef HAVE_VORBIS
|
||||||
reg->register_audio_type(&VorbisAudio::make, "ogg oga");
|
reg->register_audio_type(&VorbisAudio::make, "ogg oga");
|
||||||
#endif
|
#endif
|
||||||
|
@ -27,6 +27,8 @@ NotifyCategoryDecl(movies, EXPCL_PANDA_MOVIES, EXPTP_PANDA_MOVIES);
|
|||||||
extern ConfigVariableList load_audio_type;
|
extern ConfigVariableList load_audio_type;
|
||||||
extern ConfigVariableList load_video_type;
|
extern ConfigVariableList load_video_type;
|
||||||
|
|
||||||
|
extern ConfigVariableBool opus_enable_seek;
|
||||||
|
|
||||||
extern ConfigVariableBool vorbis_enable_seek;
|
extern ConfigVariableBool vorbis_enable_seek;
|
||||||
extern ConfigVariableBool vorbis_seek_lap;
|
extern ConfigVariableBool vorbis_seek_lap;
|
||||||
|
|
||||||
|
12
panda/src/movies/opusAudio.I
Normal file
12
panda/src/movies/opusAudio.I
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
/**
|
||||||
|
* PANDA 3D SOFTWARE
|
||||||
|
* Copyright (c) Carnegie Mellon University. All rights reserved.
|
||||||
|
*
|
||||||
|
* All use of this software is subject to the terms of the revised BSD
|
||||||
|
* license. You should have received a copy of this license along
|
||||||
|
* with this source code in a file named "LICENSE."
|
||||||
|
*
|
||||||
|
* @file opusAudio.I
|
||||||
|
* @author rdb
|
||||||
|
* @date 2017-05-24
|
||||||
|
*/
|
68
panda/src/movies/opusAudio.cxx
Normal file
68
panda/src/movies/opusAudio.cxx
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
/**
|
||||||
|
* PANDA 3D SOFTWARE
|
||||||
|
* Copyright (c) Carnegie Mellon University. All rights reserved.
|
||||||
|
*
|
||||||
|
* All use of this software is subject to the terms of the revised BSD
|
||||||
|
* license. You should have received a copy of this license along
|
||||||
|
* with this source code in a file named "LICENSE."
|
||||||
|
*
|
||||||
|
* @file opusAudio.cxx
|
||||||
|
* @author rdb
|
||||||
|
* @date 2017-05-24
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "opusAudio.h"
|
||||||
|
#include "opusAudioCursor.h"
|
||||||
|
#include "virtualFileSystem.h"
|
||||||
|
#include "dcast.h"
|
||||||
|
|
||||||
|
#ifdef HAVE_OPUS
|
||||||
|
|
||||||
|
TypeHandle OpusAudio::_type_handle;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* xxx
|
||||||
|
*/
|
||||||
|
OpusAudio::
|
||||||
|
OpusAudio(const Filename &name) :
|
||||||
|
MovieAudio(name)
|
||||||
|
{
|
||||||
|
_filename = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* xxx
|
||||||
|
*/
|
||||||
|
OpusAudio::
|
||||||
|
~OpusAudio() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Open this audio, returning a MovieAudioCursor
|
||||||
|
*/
|
||||||
|
PT(MovieAudioCursor) OpusAudio::
|
||||||
|
open() {
|
||||||
|
VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
|
||||||
|
istream *stream = vfs->open_read_file(_filename, true);
|
||||||
|
|
||||||
|
if (stream == nullptr) {
|
||||||
|
return nullptr;
|
||||||
|
} else {
|
||||||
|
PT(OpusAudioCursor) cursor = new OpusAudioCursor(this, stream);
|
||||||
|
if (cursor == nullptr || !cursor->_is_valid) {
|
||||||
|
return nullptr;
|
||||||
|
} else {
|
||||||
|
return DCAST(MovieAudioCursor, cursor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtains a MovieAudio that references a file.
|
||||||
|
*/
|
||||||
|
PT(MovieAudio) OpusAudio::
|
||||||
|
make(const Filename &name) {
|
||||||
|
return DCAST(MovieAudio, new OpusAudio(name));
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // HAVE_OPUS
|
61
panda/src/movies/opusAudio.h
Normal file
61
panda/src/movies/opusAudio.h
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
/**
|
||||||
|
* PANDA 3D SOFTWARE
|
||||||
|
* Copyright (c) Carnegie Mellon University. All rights reserved.
|
||||||
|
*
|
||||||
|
* All use of this software is subject to the terms of the revised BSD
|
||||||
|
* license. You should have received a copy of this license along
|
||||||
|
* with this source code in a file named "LICENSE."
|
||||||
|
*
|
||||||
|
* @file opusAudio.h
|
||||||
|
* @author rdb
|
||||||
|
* @date 2017-05-24
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef OPUSAUDIO_H
|
||||||
|
#define OPUSAUDIO_H
|
||||||
|
|
||||||
|
#include "pandabase.h"
|
||||||
|
#include "movieAudio.h"
|
||||||
|
|
||||||
|
#ifdef HAVE_OPUS
|
||||||
|
|
||||||
|
class OpusAudioCursor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interfaces with the libopusfile library to implement decoding of Opus
|
||||||
|
* audio files.
|
||||||
|
*/
|
||||||
|
class EXPCL_PANDA_MOVIES OpusAudio : public MovieAudio {
|
||||||
|
PUBLISHED:
|
||||||
|
OpusAudio(const Filename &name);
|
||||||
|
virtual ~OpusAudio();
|
||||||
|
virtual PT(MovieAudioCursor) open();
|
||||||
|
|
||||||
|
static PT(MovieAudio) make(const Filename &name);
|
||||||
|
|
||||||
|
private:
|
||||||
|
friend class OpusAudioCursor;
|
||||||
|
|
||||||
|
public:
|
||||||
|
static TypeHandle get_class_type() {
|
||||||
|
return _type_handle;
|
||||||
|
}
|
||||||
|
static void init_type() {
|
||||||
|
TypedWritableReferenceCount::init_type();
|
||||||
|
register_type(_type_handle, "OpusAudio",
|
||||||
|
MovieAudio::get_class_type());
|
||||||
|
}
|
||||||
|
virtual TypeHandle get_type() const {
|
||||||
|
return get_class_type();
|
||||||
|
}
|
||||||
|
virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
|
||||||
|
|
||||||
|
private:
|
||||||
|
static TypeHandle _type_handle;
|
||||||
|
};
|
||||||
|
|
||||||
|
#include "opusAudio.I"
|
||||||
|
|
||||||
|
#endif // HAVE_OPUS
|
||||||
|
|
||||||
|
#endif // OPUSAUDIO_H
|
12
panda/src/movies/opusAudioCursor.I
Normal file
12
panda/src/movies/opusAudioCursor.I
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
/**
|
||||||
|
* PANDA 3D SOFTWARE
|
||||||
|
* Copyright (c) Carnegie Mellon University. All rights reserved.
|
||||||
|
*
|
||||||
|
* All use of this software is subject to the terms of the revised BSD
|
||||||
|
* license. You should have received a copy of this license along
|
||||||
|
* with this source code in a file named "LICENSE."
|
||||||
|
*
|
||||||
|
* @file opusAudioCursor.I
|
||||||
|
* @author rdb
|
||||||
|
* @date 2017-05-24
|
||||||
|
*/
|
224
panda/src/movies/opusAudioCursor.cxx
Normal file
224
panda/src/movies/opusAudioCursor.cxx
Normal file
@ -0,0 +1,224 @@
|
|||||||
|
/**
|
||||||
|
* PANDA 3D SOFTWARE
|
||||||
|
* Copyright (c) Carnegie Mellon University. All rights reserved.
|
||||||
|
*
|
||||||
|
* All use of this software is subject to the terms of the revised BSD
|
||||||
|
* license. You should have received a copy of this license along
|
||||||
|
* with this source code in a file named "LICENSE."
|
||||||
|
*
|
||||||
|
* @file opusAudioCursor.cxx
|
||||||
|
* @author rdb
|
||||||
|
* @date 2017-05-24
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "opusAudioCursor.h"
|
||||||
|
#include "virtualFileSystem.h"
|
||||||
|
|
||||||
|
#ifdef HAVE_OPUS
|
||||||
|
|
||||||
|
#include <opus/opusfile.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callbacks passed to libopusfile to implement file I/O via the
|
||||||
|
* VirtualFileSystem.
|
||||||
|
*/
|
||||||
|
int cb_read(void *stream, unsigned char *ptr, int nbytes) {
|
||||||
|
istream *in = (istream *)stream;
|
||||||
|
nassertr(in != nullptr, -1);
|
||||||
|
|
||||||
|
in->read((char *)ptr, nbytes);
|
||||||
|
|
||||||
|
if (in->eof()) {
|
||||||
|
// Gracefully handle EOF.
|
||||||
|
in->clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
return in->gcount();
|
||||||
|
}
|
||||||
|
|
||||||
|
int cb_seek(void *stream, opus_int64 offset, int whence) {
|
||||||
|
if (!opus_enable_seek) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
istream *in = (istream *)stream;
|
||||||
|
nassertr(in != nullptr, -1);
|
||||||
|
|
||||||
|
switch (whence) {
|
||||||
|
case SEEK_SET:
|
||||||
|
in->seekg(offset, ios::beg);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SEEK_CUR:
|
||||||
|
in->seekg(offset, ios::cur);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SEEK_END:
|
||||||
|
in->seekg(offset, ios::end);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
movies_cat.error()
|
||||||
|
<< "Illegal parameter to seek in cb_seek\n";
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (in->fail()) {
|
||||||
|
movies_cat.error()
|
||||||
|
<< "Failure to seek to byte " << offset;
|
||||||
|
|
||||||
|
switch (whence) {
|
||||||
|
case SEEK_CUR:
|
||||||
|
movies_cat.error(false)
|
||||||
|
<< " from current location!\n";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SEEK_END:
|
||||||
|
movies_cat.error(false)
|
||||||
|
<< " from end of file!\n";
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
movies_cat.error(false) << "!\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
opus_int64 cb_tell(void *stream) {
|
||||||
|
istream *in = (istream *)stream;
|
||||||
|
nassertr(in != nullptr, -1);
|
||||||
|
|
||||||
|
return in->tellg();
|
||||||
|
}
|
||||||
|
|
||||||
|
int cb_close(void *stream) {
|
||||||
|
istream *in = (istream *)stream;
|
||||||
|
nassertr(in != nullptr, EOF);
|
||||||
|
|
||||||
|
VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
|
||||||
|
vfs->close_read_file(in);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const OpusFileCallbacks callbacks = {cb_read, cb_seek, cb_tell, cb_close};
|
||||||
|
|
||||||
|
TypeHandle OpusAudioCursor::_type_handle;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads the .wav header from the indicated stream. This leaves the read
|
||||||
|
* pointer positioned at the start of the data.
|
||||||
|
*/
|
||||||
|
OpusAudioCursor::
|
||||||
|
OpusAudioCursor(OpusAudio *src, istream *stream) :
|
||||||
|
MovieAudioCursor(src),
|
||||||
|
_is_valid(false),
|
||||||
|
_link(0)
|
||||||
|
{
|
||||||
|
nassertv(stream != nullptr);
|
||||||
|
nassertv(stream->good());
|
||||||
|
|
||||||
|
int error = 0;
|
||||||
|
_op = op_open_callbacks((void *)stream, &callbacks, nullptr, 0, &error);
|
||||||
|
if (_op == nullptr) {
|
||||||
|
movies_cat.error()
|
||||||
|
<< "Failed to read Opus file (error code " << error << ").\n";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ogg_int64_t samples = op_pcm_total(_op, -1);
|
||||||
|
if (samples != OP_EINVAL) {
|
||||||
|
// Opus timestamps are fixed at 48 kHz.
|
||||||
|
_length = (double)samples / 48000.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
_audio_channels = op_channel_count(_op, -1);
|
||||||
|
_audio_rate = 48000;
|
||||||
|
|
||||||
|
_can_seek = opus_enable_seek && op_seekable(_op);
|
||||||
|
_can_seek_fast = _can_seek;
|
||||||
|
|
||||||
|
_is_valid = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* xxx
|
||||||
|
*/
|
||||||
|
OpusAudioCursor::
|
||||||
|
~OpusAudioCursor() {
|
||||||
|
if (_op != nullptr) {
|
||||||
|
op_free(_op);
|
||||||
|
_op = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Seeks to a target location. Afterward, the packet_time is guaranteed to be
|
||||||
|
* less than or equal to the specified time.
|
||||||
|
*/
|
||||||
|
void OpusAudioCursor::
|
||||||
|
seek(double t) {
|
||||||
|
if (!opus_enable_seek) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
t = max(t, 0.0);
|
||||||
|
|
||||||
|
// Use op_time_seek_lap if cross-lapping is enabled.
|
||||||
|
int error = op_pcm_seek(_op, (ogg_int64_t)(t * 48000.0));
|
||||||
|
if (error != 0) {
|
||||||
|
movies_cat.error()
|
||||||
|
<< "Seek failed (error " << error << "). Opus stream may not be seekable.\n";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_last_seek = op_pcm_tell(_op) / 48000.0;
|
||||||
|
_samples_read = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read audio samples from the stream. N is the number of samples you wish to
|
||||||
|
* read. Your buffer must be equal in size to N * channels. Multiple-channel
|
||||||
|
* audio will be interleaved.
|
||||||
|
*/
|
||||||
|
void OpusAudioCursor::
|
||||||
|
read_samples(int n, int16_t *data) {
|
||||||
|
int16_t *end = data + (n * _audio_channels);
|
||||||
|
|
||||||
|
while (data < end) {
|
||||||
|
// op_read gives it to us in the exact format we need. Nifty!
|
||||||
|
int link;
|
||||||
|
int read_samples = op_read(_op, data, end - data, &link);
|
||||||
|
if (read_samples > 0) {
|
||||||
|
data += read_samples * _audio_channels;
|
||||||
|
_samples_read += read_samples;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_link != link) {
|
||||||
|
// It is technically possible for it to change parameters from one link
|
||||||
|
// to the next. However, we don't offer this flexibility.
|
||||||
|
int channels = op_channel_count(_op, link);
|
||||||
|
if (channels != _audio_channels) {
|
||||||
|
movies_cat.error()
|
||||||
|
<< "Opus file has inconsistent channel count!\n";
|
||||||
|
|
||||||
|
// We'll change it anyway. Not sure what happens next.
|
||||||
|
_audio_channels = channels;
|
||||||
|
}
|
||||||
|
|
||||||
|
_link = link;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fill the rest of the buffer with silence.
|
||||||
|
if (data < end) {
|
||||||
|
memset(data, 0, (unsigned char *)end - (unsigned char *)data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // HAVE_OPUS
|
78
panda/src/movies/opusAudioCursor.h
Normal file
78
panda/src/movies/opusAudioCursor.h
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
/**
|
||||||
|
* PANDA 3D SOFTWARE
|
||||||
|
* Copyright (c) Carnegie Mellon University. All rights reserved.
|
||||||
|
*
|
||||||
|
* All use of this software is subject to the terms of the revised BSD
|
||||||
|
* license. You should have received a copy of this license along
|
||||||
|
* with this source code in a file named "LICENSE."
|
||||||
|
*
|
||||||
|
* @file opusAudioCursor.h
|
||||||
|
* @author rdb
|
||||||
|
* @date 2017-05-24
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef OPUSAUDIOCURSOR_H
|
||||||
|
#define OPUSAUDIOCURSOR_H
|
||||||
|
|
||||||
|
#include "pandabase.h"
|
||||||
|
#include "movieAudioCursor.h"
|
||||||
|
|
||||||
|
#ifdef HAVE_OPUS
|
||||||
|
|
||||||
|
#include <ogg/ogg.h>
|
||||||
|
|
||||||
|
typedef struct OggOpusFile OggOpusFile;
|
||||||
|
|
||||||
|
class OpusAudio;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interfaces with the libopusfile library to implement decoding of Opus
|
||||||
|
* audio files.
|
||||||
|
*/
|
||||||
|
class EXPCL_PANDA_MOVIES OpusAudioCursor : public MovieAudioCursor {
|
||||||
|
PUBLISHED:
|
||||||
|
OpusAudioCursor(OpusAudio *src, istream *stream);
|
||||||
|
virtual ~OpusAudioCursor();
|
||||||
|
virtual void seek(double offset);
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual void read_samples(int n, int16_t *data);
|
||||||
|
|
||||||
|
bool _is_valid;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
OggOpusFile *_op;
|
||||||
|
|
||||||
|
int _link;
|
||||||
|
double _byte_rate;
|
||||||
|
int _block_align;
|
||||||
|
int _bytes_per_sample;
|
||||||
|
bool _is_float;
|
||||||
|
|
||||||
|
streampos _data_start;
|
||||||
|
streampos _data_pos;
|
||||||
|
size_t _data_size;
|
||||||
|
|
||||||
|
public:
|
||||||
|
static TypeHandle get_class_type() {
|
||||||
|
return _type_handle;
|
||||||
|
}
|
||||||
|
static void init_type() {
|
||||||
|
MovieAudioCursor::init_type();
|
||||||
|
register_type(_type_handle, "OpusAudioCursor",
|
||||||
|
MovieAudioCursor::get_class_type());
|
||||||
|
}
|
||||||
|
virtual TypeHandle get_type() const {
|
||||||
|
return get_class_type();
|
||||||
|
}
|
||||||
|
virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
|
||||||
|
|
||||||
|
private:
|
||||||
|
static TypeHandle _type_handle;
|
||||||
|
};
|
||||||
|
|
||||||
|
#include "opusAudioCursor.I"
|
||||||
|
|
||||||
|
#endif // HAVE_OPUS
|
||||||
|
|
||||||
|
#endif // OPUSAUDIOCURSOR_H
|
@ -10,6 +10,8 @@
|
|||||||
#include "movieTypeRegistry.cxx"
|
#include "movieTypeRegistry.cxx"
|
||||||
#include "movieVideo.cxx"
|
#include "movieVideo.cxx"
|
||||||
#include "movieVideoCursor.cxx"
|
#include "movieVideoCursor.cxx"
|
||||||
|
#include "opusAudio.cxx"
|
||||||
|
#include "opusAudioCursor.cxx"
|
||||||
#include "userDataAudio.cxx"
|
#include "userDataAudio.cxx"
|
||||||
#include "userDataAudioCursor.cxx"
|
#include "userDataAudioCursor.cxx"
|
||||||
#include "vorbisAudio.cxx"
|
#include "vorbisAudio.cxx"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user