зеркало из https://github.com/mozilla/pjs.git
Bug 556455 - Remove liboggz, liboggplay, libfishsound from video decoder. r=doublec
This commit is contained in:
Родитель
0f8dbb7df1
Коммит
59037fa6fb
|
@ -47,13 +47,11 @@ LIBXUL_LIBRARY = 1
|
|||
|
||||
|
||||
EXPORTS += \
|
||||
nsChannelReader.h \
|
||||
nsOggDecoder.h \
|
||||
nsOggCodecState.h \
|
||||
$(NULL)
|
||||
|
||||
CPPSRCS = \
|
||||
nsChannelReader.cpp \
|
||||
nsOggDecoder.cpp \
|
||||
nsOggCodecState.cpp \
|
||||
nsOggReader.cpp \
|
||||
|
|
|
@ -1,156 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Mozilla code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is the Mozilla Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2007
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Chris Double <chris.double@double.co.nz>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
#include "nsAString.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "nsNetUtil.h"
|
||||
#include "prlog.h"
|
||||
#include "nsOggDecoder.h"
|
||||
#include "nsChannelReader.h"
|
||||
#include "nsIScriptSecurityManager.h"
|
||||
|
||||
OggPlayErrorCode nsChannelReader::initialise(int aBlock)
|
||||
{
|
||||
return E_OGGPLAY_OK;
|
||||
}
|
||||
|
||||
OggPlayErrorCode nsChannelReader::destroy()
|
||||
{
|
||||
// We don't have to do anything here, the decoder will clean stuff up
|
||||
return E_OGGPLAY_OK;
|
||||
}
|
||||
|
||||
void nsChannelReader::SetLastFrameTime(PRInt64 aTime)
|
||||
{
|
||||
mLastFrameTime = aTime;
|
||||
}
|
||||
|
||||
size_t nsChannelReader::io_read(char* aBuffer, size_t aCount)
|
||||
{
|
||||
PRUint32 bytes = 0;
|
||||
nsresult rv = mStream->Read(aBuffer, aCount, &bytes);
|
||||
if (!NS_SUCCEEDED(rv)) {
|
||||
return static_cast<size_t>(OGGZ_ERR_SYSTEM);
|
||||
}
|
||||
nsOggDecoder* decoder =
|
||||
static_cast<nsOggDecoder*>(mStream->Decoder());
|
||||
decoder->NotifyBytesConsumed(bytes);
|
||||
return bytes;
|
||||
}
|
||||
|
||||
int nsChannelReader::io_seek(long aOffset, int aWhence)
|
||||
{
|
||||
nsresult rv = mStream->Seek(aWhence, aOffset);
|
||||
if (NS_SUCCEEDED(rv))
|
||||
return aOffset;
|
||||
|
||||
return OGGZ_STOP_ERR;
|
||||
}
|
||||
|
||||
long nsChannelReader::io_tell()
|
||||
{
|
||||
return mStream->Tell();
|
||||
}
|
||||
|
||||
ogg_int64_t nsChannelReader::duration()
|
||||
{
|
||||
return mLastFrameTime;
|
||||
}
|
||||
|
||||
static OggPlayErrorCode oggplay_channel_reader_initialise(OggPlayReader* aReader, int aBlock)
|
||||
{
|
||||
nsChannelReader * me = static_cast<nsChannelReader*>(aReader);
|
||||
|
||||
if (me == NULL) {
|
||||
return E_OGGPLAY_BAD_READER;
|
||||
}
|
||||
return me->initialise(aBlock);
|
||||
}
|
||||
|
||||
static OggPlayErrorCode oggplay_channel_reader_destroy(OggPlayReader* aReader)
|
||||
{
|
||||
nsChannelReader* me = static_cast<nsChannelReader*>(aReader);
|
||||
return me->destroy();
|
||||
}
|
||||
|
||||
static size_t oggplay_channel_reader_io_read(void* aReader, void* aBuffer, size_t aCount)
|
||||
{
|
||||
nsChannelReader* me = static_cast<nsChannelReader*>(aReader);
|
||||
return me->io_read(static_cast<char*>(aBuffer), aCount);
|
||||
}
|
||||
|
||||
static int oggplay_channel_reader_io_seek(void* aReader, long aOffset, int aWhence)
|
||||
{
|
||||
nsChannelReader* me = static_cast<nsChannelReader*>(aReader);
|
||||
return me->io_seek(aOffset, aWhence);
|
||||
}
|
||||
|
||||
static long oggplay_channel_reader_io_tell(void* aReader)
|
||||
{
|
||||
nsChannelReader* me = static_cast<nsChannelReader*>(aReader);
|
||||
return me->io_tell();
|
||||
}
|
||||
|
||||
static ogg_int64_t oggplay_channel_reader_duration(struct _OggPlayReader *aReader)
|
||||
{
|
||||
nsChannelReader* me = static_cast<nsChannelReader*>(aReader);
|
||||
return me->duration();
|
||||
}
|
||||
|
||||
void nsChannelReader::Init(nsMediaStream* aStream)
|
||||
{
|
||||
mStream = aStream;
|
||||
}
|
||||
|
||||
nsChannelReader::~nsChannelReader()
|
||||
{
|
||||
MOZ_COUNT_DTOR(nsChannelReader);
|
||||
}
|
||||
|
||||
nsChannelReader::nsChannelReader() :
|
||||
mLastFrameTime(-1)
|
||||
{
|
||||
MOZ_COUNT_CTOR(nsChannelReader);
|
||||
OggPlayReader* reader = this;
|
||||
reader->initialise = &oggplay_channel_reader_initialise;
|
||||
reader->destroy = &oggplay_channel_reader_destroy;
|
||||
reader->seek = 0;
|
||||
reader->io_read = &oggplay_channel_reader_io_read;
|
||||
reader->io_seek = &oggplay_channel_reader_io_seek;
|
||||
reader->io_tell = &oggplay_channel_reader_io_tell;
|
||||
reader->duration = &oggplay_channel_reader_duration;
|
||||
}
|
|
@ -1,87 +0,0 @@
|
|||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Mozilla code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is the Mozilla Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2007
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Chris Double <chris.double@double.co.nz>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
#if !defined(nsChannelReader_h_)
|
||||
#define nsChannelReader_h_
|
||||
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsMediaStream.h"
|
||||
|
||||
#include "oggplay/oggplay.h"
|
||||
|
||||
class nsIURI;
|
||||
class nsIChannel;
|
||||
class nsIStreamListener;
|
||||
class nsMediaDecoder;
|
||||
|
||||
class nsChannelReader : public OggPlayReader
|
||||
{
|
||||
public:
|
||||
nsChannelReader();
|
||||
~nsChannelReader();
|
||||
|
||||
/**
|
||||
* Initialize the reader with the media stream.
|
||||
* This takes ownership of aStream.
|
||||
*/
|
||||
void Init(nsMediaStream* aStream);
|
||||
|
||||
nsMediaStream* Stream() { return mStream; }
|
||||
|
||||
// Set the time of the last frame. This is returned in duration() to
|
||||
// liboggplay. Call with decoder lock obtained so that liboggplay cannot
|
||||
// call duration() on the decoder thread while it is changing.
|
||||
void SetLastFrameTime(PRInt64 aTime);
|
||||
|
||||
nsIPrincipal* GetCurrentPrincipal();
|
||||
|
||||
// Implementation of OggPlay Reader API.
|
||||
OggPlayErrorCode initialise(int aBlock);
|
||||
OggPlayErrorCode destroy();
|
||||
size_t io_read(char* aBuffer, size_t aCount);
|
||||
int io_seek(long aOffset, int aWhence);
|
||||
long io_tell();
|
||||
ogg_int64_t duration();
|
||||
|
||||
public:
|
||||
nsAutoPtr<nsMediaStream> mStream;
|
||||
|
||||
// Timestamp of the end of the last frame in the media resource.
|
||||
// -1 if not known.
|
||||
PRInt64 mLastFrameTime;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -43,7 +43,6 @@
|
|||
#include "nsBuiltinDecoder.h"
|
||||
#include "nsOggReader.h"
|
||||
#include "nsOggPlayStateMachine.h"
|
||||
#include "oggplay/oggplay.h"
|
||||
#include "mozilla/mozalloc.h"
|
||||
#include "VideoUtils.h"
|
||||
|
||||
|
|
|
@ -246,10 +246,8 @@ public:
|
|||
/**
|
||||
* This makes a copy of the data buffers.
|
||||
* XXX Eventually we will change this to not make a copy of the data,
|
||||
* but we can't do that until we have tighter control of nsOggDecoder's
|
||||
* buffer management (i.e. not going through liboggplay). Right now
|
||||
* it doesn't matter because the BasicLayer implementation does YCbCr
|
||||
* conversion here anyway.
|
||||
* Right now it doesn't matter because the BasicLayer implementation
|
||||
* does YCbCr conversion here anyway.
|
||||
*/
|
||||
virtual void SetData(const Data& aData) = 0;
|
||||
|
||||
|
|
|
@ -118,10 +118,7 @@ endif
|
|||
|
||||
ifdef MOZ_OGG
|
||||
SHARED_LIBRARY_LIBS += \
|
||||
$(DEPTH)/media/libfishsound/src/libfishsound/$(LIB_PREFIX)fishsound.$(LIB_SUFFIX) \
|
||||
$(DEPTH)/media/libogg/src/$(LIB_PREFIX)ogg.$(LIB_SUFFIX) \
|
||||
$(DEPTH)/media/liboggplay/src/liboggplay/$(LIB_PREFIX)oggplay.$(LIB_SUFFIX) \
|
||||
$(DEPTH)/media/liboggz/src/liboggz/$(LIB_PREFIX)oggz.$(LIB_SUFFIX) \
|
||||
$(DEPTH)/media/libtheora/lib/$(LIB_PREFIX)theora.$(LIB_SUFFIX) \
|
||||
$(DEPTH)/media/libvorbis/lib/$(LIB_PREFIX)vorbis.$(LIB_SUFFIX) \
|
||||
$(DEPTH)/content/media/ogg/$(LIB_PREFIX)gkconogg_s.$(LIB_SUFFIX) \
|
||||
|
|
|
@ -1,25 +0,0 @@
|
|||
Conrad Parker <conrad@metadecks.org>
|
||||
- Design, implementation.
|
||||
- Vorbis, Speex support
|
||||
|
||||
Tobias Gehrig
|
||||
- FLAC support
|
||||
|
||||
Michel Salim
|
||||
- libFLAC 1.1.3 support
|
||||
|
||||
Silvia Pfeiffer <silvia@annodex.net>
|
||||
- MS Windows porting, general packaging.
|
||||
|
||||
Zentaro Kavanagh <ogg@illiminable.com>
|
||||
- Windows porting and packaging.
|
||||
|
||||
|
||||
based on code from:
|
||||
|
||||
libvorbis, by Monty <monty@xiph.org>, Xiph.org Foundation.
|
||||
|
||||
libspeex, by Jean-Marc Valin <jean-marc.valin@hermes.usherb.ca>,
|
||||
Xiph.Org Foundation
|
||||
|
||||
libFLAC, by Josh Coalson, Xiph.Org Foundation.
|
|
@ -1,29 +0,0 @@
|
|||
Copyright (C) 2003 CSIRO Australia
|
||||
|
||||
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.
|
||||
|
||||
- Neither the name of the CSIRO nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
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 ORGANISATION 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.
|
||||
|
|
@ -1,83 +0,0 @@
|
|||
2007-01-12 Thomas Vander Stichele <thomas at apestaart dot org>
|
||||
|
||||
* Makefile.am:
|
||||
dist m4 macro
|
||||
* include/fishsound/Makefile.am:
|
||||
fix include directory when overriding includedir
|
||||
|
||||
2005-06-13 Thomas Vander Stichele <thomas at apestaart dot org>
|
||||
|
||||
* autogen.sh:
|
||||
* m4/as-ac-expand.m4:
|
||||
add m4 dir and use it
|
||||
add an expand macro
|
||||
* configure.ac:
|
||||
uniformize configure's output across the annodex stack
|
||||
|
||||
Thu Jan 13 17:58:45 EST 2005 Conrad Parker <conrad@metadecks.org>
|
||||
|
||||
* added liboil support from David Schleef <ds@schleef.org>
|
||||
|
||||
Thu Jun 24 18:48:46 EST 2004 Conrad Parker <conrad@metadecks.org>
|
||||
|
||||
* Version 0.6.3
|
||||
|
||||
Bug fixes:
|
||||
* non-interleaved Speex encoding re-written and tested
|
||||
* memory leak in comments API closed
|
||||
|
||||
Tests and examples:
|
||||
* new examples fishsound-encdec and fishsound-decenc to trial
|
||||
encode<->decode pipelines
|
||||
* improved testing of Speex non-interleaved encoding
|
||||
|
||||
Fri May 21 14:32:41 EST 2004 Conrad Parker <conrad@metadecks.org>
|
||||
|
||||
* Version 0.6.2
|
||||
|
||||
Improved handling of first and last blocks of data (bos and eos
|
||||
packets in Ogg):
|
||||
* new fish_sound_prepare_truncation() API call
|
||||
* improved encdec-audio test to keep track of frames in and out,
|
||||
and warn if unequal. (Currently not set to FAIL on this condition
|
||||
as it appears to be common for Speex)
|
||||
|
||||
Updates to Win32 nmake build files
|
||||
|
||||
Wed May 5 21:44:26 EST 2004 Conrad Parker <conrad@metadecks.org>
|
||||
|
||||
* Version 0.6.1
|
||||
|
||||
Added support for comment packets, tests, and various bugfixes.
|
||||
* Added fish_sound_comment_() API, <fishsound/comments.h>
|
||||
* Fixed segv bug in decoding stereo Speex to non-interleaved
|
||||
* Added test for encode/decode pipeline with a variety of
|
||||
combinations of format, interleave, samplerate, channels and
|
||||
buffer size.
|
||||
* Added tests for comments data structure and encode/decode pipeline
|
||||
|
||||
* Added fish_sound_{get,set}_frameno() API calls
|
||||
|
||||
Wed Mar 24 17:53:55 EST 2004 Conrad Parker <conrad@metadecks.org>
|
||||
|
||||
* Version 0.6.0
|
||||
* moved encode and decode to examples, added documentation for each
|
||||
* added fish_sound_{get,set}_interleave() api calls
|
||||
* various bugfixes from zen and silvia
|
||||
* updated win32 dev files from silvia
|
||||
|
||||
Sun Mar 07 17:30:00 EST 2004 Silvia Pfeiffer <Silvia.Pfeiffer@csiro.au>
|
||||
* Version 0.5.41
|
||||
* fixed up windows port and release preparation with
|
||||
REAME files etc.
|
||||
|
||||
|
||||
Some time in the year 2003...
|
||||
|
||||
* A new fish was born...
|
||||
|
||||
* ... by Conrad Parker <Conrad.Parker@csiro.au>
|
||||
|
||||
* ... and it had a long unlogged journey...
|
||||
|
||||
* before arriving at 0.5.40 . :)
|
|
@ -1,51 +0,0 @@
|
|||
# ***** BEGIN LICENSE BLOCK *****
|
||||
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
#
|
||||
# The contents of this file are subject to the Mozilla Public License Version
|
||||
# 1.1 (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
# http://www.mozilla.org/MPL/
|
||||
#
|
||||
# Software distributed under the License is distributed on an "AS IS" basis,
|
||||
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
# for the specific language governing rights and limitations under the
|
||||
# License.
|
||||
#
|
||||
# The Original Code is Mozilla code.
|
||||
#
|
||||
# The Initial Developer of the Original Code is the Mozilla Corporation.
|
||||
# Portions created by the Initial Developer are Copyright (C) 2007
|
||||
# the Initial Developer. All Rights Reserved.
|
||||
#
|
||||
# Contributor(s):
|
||||
# Chris Double <chris.double@double.co.nz>
|
||||
#
|
||||
# Alternatively, the contents of this file may be used under the terms of
|
||||
# either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
# in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
# of those above. If you wish to allow use of your version of this file only
|
||||
# under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
# use your version of this file under the terms of the MPL, indicate your
|
||||
# decision by deleting the provisions above and replace them with the notice
|
||||
# and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
# the provisions above, a recipient may use your version of this file under
|
||||
# the terms of any one of the MPL, the GPL or the LGPL.
|
||||
#
|
||||
# ***** END LICENSE BLOCK *****
|
||||
|
||||
DEPTH = ../..
|
||||
topsrcdir = @top_srcdir@
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
|
||||
include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
MODULE = fishsound
|
||||
|
||||
DIRS = \
|
||||
include \
|
||||
src \
|
||||
$(NULL)
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
|
@ -1,46 +0,0 @@
|
|||
FishSound, the sound of fish!
|
||||
-----------------------------
|
||||
|
||||
Full documentation is available in doc/fishsound/html/index.html,
|
||||
or online at http://www.annodex.net/software/libfishsound/html/
|
||||
|
||||
Updates are available online at the FishSound homepage:
|
||||
http://www.annodex.net/software/libfishsound/
|
||||
|
||||
libfishsound provides a simple programming interface for decoding and
|
||||
encoding audio data using Xiph.Org codecs (FLAC, Speex and Vorbis).
|
||||
|
||||
libfishsound by itself is designed to handle raw codec streams from a
|
||||
lower level layer such as UDP datagrams. When these codecs are used in
|
||||
files, they are commonly encapsulated in Ogg to produce Ogg FLAC, Speex
|
||||
and Ogg Vorbis files.
|
||||
|
||||
libfishsound is a wrapper around the existing codec libraries and provides
|
||||
a consistent, higher-level programming interface. It has been designed for
|
||||
use in a wide variety of applications; it has no direct dependencies on
|
||||
Ogg encapsulation, though it is most commonly used in conjunction with
|
||||
liboggz to decode or encode FLAC, Speex or Vorbis audio tracks in Ogg files,
|
||||
including Ogg Theora and Annodex.
|
||||
|
||||
This source tarball
|
||||
-------------------
|
||||
|
||||
FishSound has been developed and tested on GNU/Linux, Darwin/MacOSX and
|
||||
Win32. It probably also works on other Unix-like systems via GNU autoconf.
|
||||
For Win32: nmake Makefiles, Visual Studio .NET 2003 solution files and
|
||||
Visual C++ 6.0 workspace files are all provided in the source distribution.
|
||||
|
||||
Details for building with GNU autotools are in the file INSTALL. Read the
|
||||
file README.win32 for installing under MS Windows.
|
||||
|
||||
src/libfishsound/ the library source code.
|
||||
src/examples/ example tools for programming with libfishsound.
|
||||
|
||||
include/ the libfishound include files that will be installed
|
||||
into the system include directory.
|
||||
|
||||
doc/ documentation for libfishsound. The subdirectory
|
||||
doc/libfishsound is autocreated by doxygen from
|
||||
comments contained in <fishsound/fishsound.h>
|
||||
|
||||
win32/ files necessary to compile under MS Windows.
|
|
@ -1,18 +0,0 @@
|
|||
The source from this directory was copied from the libfishsound git
|
||||
distribution using the update.sh script. The only changes made
|
||||
were those applied by update.sh and the addition/upate of Makefile.in
|
||||
files for the Mozilla build system.
|
||||
|
||||
Some files are renamed during the copy to prevent clashes with object
|
||||
file names with other Mozilla libraries.
|
||||
|
||||
The git commit id used was 20b5cdf6fe38f61a9847e46e82da60d7ac4b7877
|
||||
from git://git.xiph.org/libfishsound.git
|
||||
|
||||
endian.patch is applied to fix Bug 452698.
|
||||
|
||||
bug487519.patch: Fixes for bug487519
|
||||
trac497.patch: Annodex trac ticket 497 fix and mozilla bug 462141.
|
||||
fishsound_reset.patch: Fixes bug 516323.
|
||||
bug520500.patch: Don't reject files with vorbis comments with name or
|
||||
values of length 0.
|
|
@ -1,20 +0,0 @@
|
|||
diff --git a/media/libfishsound/src/libfishsound/fishsound_vorbis.c b/media/libfishsound/src/libfishsound/fishsound_vorbis.c
|
||||
index 68bdb3a..236dda4 100644
|
||||
--- a/media/libfishsound/src/libfishsound/fishsound_vorbis.c
|
||||
+++ b/media/libfishsound/src/libfishsound/fishsound_vorbis.c
|
||||
@@ -154,9 +154,13 @@ fs_vorbis_decode (FishSound * fsound, unsigned char * buf, long bytes)
|
||||
} else {
|
||||
FishSoundDecoded_FloatIlv df;
|
||||
FishSoundDecoded_Float dfi;
|
||||
-
|
||||
- if (vorbis_synthesis (&fsv->vb, &op) == 0)
|
||||
+ int r;
|
||||
+ if ((r = vorbis_synthesis (&fsv->vb, &op)) == 0)
|
||||
vorbis_synthesis_blockin (&fsv->vd, &fsv->vb);
|
||||
+
|
||||
+ if (r == OV_EBADPACKET) {
|
||||
+ return FISH_SOUND_ERR_GENERIC;
|
||||
+ }
|
||||
|
||||
while ((samples = vorbis_synthesis_pcmout (&fsv->vd, &fsv->pcm)) > 0) {
|
||||
vorbis_synthesis_read (&fsv->vd, samples);
|
|
@ -1,54 +0,0 @@
|
|||
diff --git a/media/libfishsound/src/libfishsound/fishsound_comments.c b/media/libfishsound/src/libfishsound/fishsound_comments.c
|
||||
--- a/media/libfishsound/src/libfishsound/fishsound_comments.c
|
||||
+++ b/media/libfishsound/src/libfishsound/fishsound_comments.c
|
||||
@@ -480,44 +480,47 @@ fish_sound_comments_decode (FishSound *
|
||||
len=readint(c, 0);
|
||||
debug_printf (1, "[%d] len %d\n", i, len);
|
||||
|
||||
c+=4;
|
||||
if (len > (unsigned long) (end-c)) return -1;
|
||||
|
||||
name = c;
|
||||
value = fs_index_len (c, '=', len);
|
||||
+ n = 0;
|
||||
if (value) {
|
||||
*value = '\0';
|
||||
value++;
|
||||
-
|
||||
n = c+len - value;
|
||||
+
|
||||
+ }
|
||||
+ if (n) {
|
||||
if ((nvalue = fs_strdup_len (value, n)) == NULL)
|
||||
return FISH_SOUND_ERR_OUT_OF_MEMORY;
|
||||
|
||||
debug_printf (1, "%s -> %s (length %d)", name, nvalue, n);
|
||||
|
||||
if ((comment = fs_comment_new (name, nvalue)) == NULL) {
|
||||
fs_free (nvalue);
|
||||
return FISH_SOUND_ERR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
if (_fs_comment_add (fsound, comment) == NULL) {
|
||||
fs_free (nvalue);
|
||||
return FISH_SOUND_ERR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
fs_free (nvalue);
|
||||
- } else {
|
||||
+ } else if (len > 0) {
|
||||
debug_printf (1, "[%d] %s (no value)", i, name, len);
|
||||
|
||||
if ((nvalue = fs_strdup_len (name, len)) == NULL)
|
||||
return FISH_SOUND_ERR_OUT_OF_MEMORY;
|
||||
|
||||
- if ((comment = fs_comment_new (nvalue, NULL)) == NULL) {
|
||||
+ if ((comment = fs_comment_new (nvalue, "")) == NULL) {
|
||||
fs_free (nvalue);
|
||||
return FISH_SOUND_ERR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
if (_fs_comment_add (fsound, comment) == NULL) {
|
||||
fs_free (nvalue);
|
||||
return FISH_SOUND_ERR_OUT_OF_MEMORY;
|
||||
}
|
|
@ -1,26 +0,0 @@
|
|||
diff --git a/media/libfishsound/include/fishsound/config.h b/media/libfishsound/include/fishsound/config.h
|
||||
index 573822f..b7cae62 100644
|
||||
--- a/media/libfishsound/include/fishsound/config.h
|
||||
+++ b/media/libfishsound/include/fishsound/config.h
|
||||
@@ -104,3 +104,8 @@
|
||||
#undef HAVE_VORBISENC
|
||||
#define HAVE_VORBISENC 0
|
||||
#undef DEBUG
|
||||
+
|
||||
+#include "prcpucfg.h"
|
||||
+#ifdef IS_BIG_ENDIAN
|
||||
+#define WORDS_BIGENDIAN
|
||||
+#endif
|
||||
diff --git a/media/libfishsound/src/libfishsound/config.h b/media/libfishsound/src/libfishsound/config.h
|
||||
index 573822f..b7cae62 100644
|
||||
--- a/media/libfishsound/src/libfishsound/config.h
|
||||
+++ b/media/libfishsound/src/libfishsound/config.h
|
||||
@@ -104,3 +104,8 @@
|
||||
#undef HAVE_VORBISENC
|
||||
#define HAVE_VORBISENC 0
|
||||
#undef DEBUG
|
||||
+
|
||||
+#include "prcpucfg.h"
|
||||
+#ifdef IS_BIG_ENDIAN
|
||||
+#define WORDS_BIGENDIAN
|
||||
+#endif
|
|
@ -1,12 +0,0 @@
|
|||
diff --git a/media/libfishsound/src/libfishsound/fishsound_vorbis.c b/media/libfishsound/src/libfishsound/fishsound_vorbis.c
|
||||
--- a/media/libfishsound/src/libfishsound/fishsound_vorbis.c
|
||||
+++ b/media/libfishsound/src/libfishsound/fishsound_vorbis.c
|
||||
@@ -412,7 +412,7 @@
|
||||
FishSoundVorbisInfo * fsv = (FishSoundVorbisInfo *)fsound->codec_data;
|
||||
|
||||
vorbis_block_init (&fsv->vd, &fsv->vb);
|
||||
-
|
||||
+ fsv->packetno = 0;
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1,47 +0,0 @@
|
|||
# ***** BEGIN LICENSE BLOCK *****
|
||||
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
#
|
||||
# The contents of this file are subject to the Mozilla Public License Version
|
||||
# 1.1 (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
# http://www.mozilla.org/MPL/
|
||||
#
|
||||
# Software distributed under the License is distributed on an "AS IS" basis,
|
||||
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
# for the specific language governing rights and limitations under the
|
||||
# License.
|
||||
#
|
||||
# The Original Code is Mozilla code.
|
||||
#
|
||||
# The Initial Developer of the Original Code is the Mozilla Corporation.
|
||||
# Portions created by the Initial Developer are Copyright (C) 2007
|
||||
# the Initial Developer. All Rights Reserved.
|
||||
#
|
||||
# Contributor(s):
|
||||
# Chris Double <chris.double@double.co.nz>
|
||||
#
|
||||
# Alternatively, the contents of this file may be used under the terms of
|
||||
# either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
# in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
# of those above. If you wish to allow use of your version of this file only
|
||||
# under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
# use your version of this file under the terms of the MPL, indicate your
|
||||
# decision by deleting the provisions above and replace them with the notice
|
||||
# and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
# the provisions above, a recipient may use your version of this file under
|
||||
# the terms of any one of the MPL, the GPL or the LGPL.
|
||||
#
|
||||
# ***** END LICENSE BLOCK *****
|
||||
|
||||
DEPTH = ../../..
|
||||
topsrcdir = @top_srcdir@
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
|
||||
include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
MODULE = fishsound
|
||||
DIRS = fishsound
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
|
@ -1,55 +0,0 @@
|
|||
# ***** BEGIN LICENSE BLOCK *****
|
||||
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
#
|
||||
# The contents of this file are subject to the Mozilla Public License Version
|
||||
# 1.1 (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
# http://www.mozilla.org/MPL/
|
||||
#
|
||||
# Software distributed under the License is distributed on an "AS IS" basis,
|
||||
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
# for the specific language governing rights and limitations under the
|
||||
# License.
|
||||
#
|
||||
# The Original Code is Mozilla code.
|
||||
#
|
||||
# The Initial Developer of the Original Code is the Mozilla Corporation.
|
||||
# Portions created by the Initial Developer are Copyright (C) 2007
|
||||
# the Initial Developer. All Rights Reserved.
|
||||
#
|
||||
# Contributor(s):
|
||||
# Chris Double <chris.double@double.co.nz>
|
||||
#
|
||||
# Alternatively, the contents of this file may be used under the terms of
|
||||
# either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
# in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
# of those above. If you wish to allow use of your version of this file only
|
||||
# under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
# use your version of this file under the terms of the MPL, indicate your
|
||||
# decision by deleting the provisions above and replace them with the notice
|
||||
# and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
# the provisions above, a recipient may use your version of this file under
|
||||
# the terms of any one of the MPL, the GPL or the LGPL.
|
||||
#
|
||||
# ***** END LICENSE BLOCK *****
|
||||
|
||||
DEPTH = ../../../..
|
||||
topsrcdir = @top_srcdir@
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
|
||||
include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
EXPORTS_NAMESPACES = fishsound
|
||||
|
||||
EXPORTS_fishsound = \
|
||||
comments.h \
|
||||
constants.h \
|
||||
decode.h \
|
||||
deprecated.h \
|
||||
encode.h \
|
||||
fishsound.h \
|
||||
$(NULL)
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
|
@ -1,211 +0,0 @@
|
|||
/*
|
||||
Copyright (C) 2003 Commonwealth Scientific and Industrial Research
|
||||
Organisation (CSIRO) Australia
|
||||
|
||||
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.
|
||||
|
||||
- Neither the name of CSIRO Australia nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
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 ORGANISATION 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 __FISH_SOUND_COMMENT_H__
|
||||
#define __FISH_SOUND_COMMENT_H__
|
||||
|
||||
/** \file
|
||||
* Encoding and decoding of comments.
|
||||
*
|
||||
* Vorbis and Speex bitstreams
|
||||
* use a comment format called "Vorbiscomment", defined
|
||||
* <a href="http://www.xiph.org/ogg/vorbis/doc/v-comment.html">here</a>.
|
||||
* Many standard comment names (such as TITLE, COPYRIGHT and GENRE) are
|
||||
* defined in that document.
|
||||
*
|
||||
* The following general features of Vorbiscomment are relevant to this API:
|
||||
* - Each stream has one comment packet, which occurs before any encoded
|
||||
* audio data in the stream.
|
||||
* - When encoding, FishSound will generate the comment block and pass it
|
||||
* to the encoded() callback in sequence, just like any other packet.
|
||||
* Hence, all comments must be set before any call to fish_sound_encode_*().
|
||||
* - When decoding, FishSound will decode the comment block before calling
|
||||
* the first decoded() callback. Hence, retrieving comment data is possible
|
||||
* from as soon as the decoded() callback is first called.
|
||||
*
|
||||
* Each comment block contains one Vendor string, which can be retrieved
|
||||
* with fish_sound_comment_get_vendor(). When encoding, this string is
|
||||
* effectively fixed by the codec libraries; it cannot be set by the
|
||||
* application.
|
||||
*
|
||||
* The rest of a comment block consists of \a name = \a value pairs, with
|
||||
* the following restrictions:
|
||||
* - Both the \a name and \a value must be non-empty
|
||||
* - The \a name is case-insensitive and must consist of ASCII within the
|
||||
* range 0x20 to 0x7D inclusive, 0x3D ('=') excluded.
|
||||
* - The \a name is not unique; multiple entries may exist with equivalent
|
||||
* \a name within a Vorbiscomment block.
|
||||
* - The \a value may be any UTF-8 string.
|
||||
*
|
||||
* \section comments_get Retrieving comments
|
||||
*
|
||||
* FishSound contains API methods to iterate through all comments associated
|
||||
* with a FishSound* handle (fish_sound_comment_first() and
|
||||
* fish_sound_comment_next(), and to iterate through comments matching a
|
||||
* particular name (fish_sound_comment_first_byname() and
|
||||
* fish_sound_comment_next_byname()). Given that multiple comments may exist
|
||||
* with the same \a name, you should not use
|
||||
* fish_sound_comment_first_byname() as a simple "get" function.
|
||||
*
|
||||
* \section comments_set Encoding comments
|
||||
*
|
||||
* For encoding, FishSound contains API methods for adding comments
|
||||
* (fish_sound_comment_add() and fish_sound_comment_add_byname()
|
||||
* and for removing comments
|
||||
* (fish_sound_comment_remove() and fish_sound_comment_remove_byname()).
|
||||
*/
|
||||
|
||||
#include <fishsound/fishsound.h>
|
||||
|
||||
/**
|
||||
* A comment.
|
||||
*/
|
||||
typedef struct {
|
||||
/** The name of the comment, eg. "AUTHOR" */
|
||||
char * name;
|
||||
|
||||
/** The value of the comment, as UTF-8 */
|
||||
char * value;
|
||||
} FishSoundComment;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Retrieve the vendor string.
|
||||
* \param fsound A FishSound* handle
|
||||
* \returns A read-only copy of the vendor string
|
||||
* \retval NULL No vendor string is associated with \a fsound,
|
||||
* or \a fsound is NULL.
|
||||
*/
|
||||
const char *
|
||||
fish_sound_comment_get_vendor (FishSound * fsound);
|
||||
|
||||
|
||||
/**
|
||||
* Retrieve the first comment.
|
||||
* \param fsound A FishSound* handle
|
||||
* \returns A read-only copy of the first comment, or NULL if no comments
|
||||
* exist for this FishSound* object.
|
||||
*/
|
||||
const FishSoundComment *
|
||||
fish_sound_comment_first (FishSound * fsound);
|
||||
|
||||
/**
|
||||
* Retrieve the next comment.
|
||||
* \param fsound A FishSound* handle
|
||||
* \param comment The previous comment.
|
||||
* \returns A read-only copy of the comment immediately following the given
|
||||
* comment.
|
||||
*/
|
||||
const FishSoundComment *
|
||||
fish_sound_comment_next (FishSound * fsound, const FishSoundComment * comment);
|
||||
|
||||
/**
|
||||
* Retrieve the first comment with a given name.
|
||||
* \param fsound A FishSound* handle
|
||||
* \param name the name of the comment to retrieve.
|
||||
* \returns A read-only copy of the first comment matching the given \a name.
|
||||
* \retval NULL no match was found.
|
||||
* \note If \a name is NULL, the behaviour is the same as for
|
||||
* fish_sound_comment_first()
|
||||
*/
|
||||
const FishSoundComment *
|
||||
fish_sound_comment_first_byname (FishSound * fsound, char * name);
|
||||
|
||||
/**
|
||||
* Retrieve the next comment following and with the same name as a given
|
||||
* comment.
|
||||
* \param fsound A FishSound* handle
|
||||
* \param comment A comment
|
||||
* \returns A read-only copy of the next comment with the same name as
|
||||
* \a comment.
|
||||
* \retval NULL no further comments with the same name exist for
|
||||
* this FishSound* object.
|
||||
*/
|
||||
const FishSoundComment *
|
||||
fish_sound_comment_next_byname (FishSound * fsound,
|
||||
const FishSoundComment * comment);
|
||||
|
||||
/**
|
||||
* Add a comment
|
||||
* \param fsound A FishSound* handle (created with mode FISH_SOUND_ENCODE)
|
||||
* \param comment The comment to add
|
||||
* \retval 0 Success
|
||||
* \retval FISH_SOUND_ERR_BAD \a fsound is not a valid FishSound* handle
|
||||
* \retval FISH_SOUND_ERR_INVALID Operation not suitable for this FishSound
|
||||
*/
|
||||
int
|
||||
fish_sound_comment_add (FishSound * fsound, FishSoundComment * comment);
|
||||
|
||||
/**
|
||||
* Add a comment by name and value.
|
||||
* \param fsound A FishSound* handle (created with mode FISH_SOUND_ENCODE)
|
||||
* \param name The name of the comment to add
|
||||
* \param value The contents of the comment to add
|
||||
* \retval 0 Success
|
||||
* \retval FISH_SOUND_ERR_BAD \a fsound is not a valid FishSound* handle
|
||||
* \retval FISH_SOUND_ERR_INVALID Operation not suitable for this FishSound
|
||||
*/
|
||||
int
|
||||
fish_sound_comment_add_byname (FishSound * fsound, const char * name,
|
||||
const char * value);
|
||||
|
||||
/**
|
||||
* Remove a comment
|
||||
* \param fsound A FishSound* handle (created with FISH_SOUND_ENCODE)
|
||||
* \param comment The comment to remove.
|
||||
* \retval 1 Success: comment removed
|
||||
* \retval 0 No-op: comment not found, nothing to remove
|
||||
* \retval FISH_SOUND_ERR_BAD \a fsound is not a valid FishSound* handle
|
||||
* \retval FISH_SOUND_ERR_INVALID Operation not suitable for this FishSound
|
||||
*/
|
||||
int
|
||||
fish_sound_comment_remove (FishSound * fsound, FishSoundComment * comment);
|
||||
|
||||
/**
|
||||
* Remove all comments with a given name.
|
||||
* \param fsound A FishSound* handle (created with FISH_SOUND_ENCODE)
|
||||
* \param name The name of the comments to remove
|
||||
* \retval ">= 0" The number of comments removed
|
||||
* \retval FISH_SOUND_ERR_BAD \a fsound is not a valid FishSound* handle
|
||||
* \retval FISH_SOUND_ERR_INVALID Operation not suitable for this FishSound
|
||||
*/
|
||||
int
|
||||
fish_sound_comment_remove_byname (FishSound * fsound, char * name);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __FISH_SOUND_COMMENTS_H__ */
|
|
@ -1,138 +0,0 @@
|
|||
/* config.h. Generated from config.h.in by configure. */
|
||||
/* config.h.in. Generated from configure.ac by autoheader. */
|
||||
|
||||
/* Define if building universal (internal helper macro) */
|
||||
/* #undef AC_APPLE_UNIVERSAL_BUILD */
|
||||
|
||||
/* Do not build decoding support */
|
||||
#define FS_DECODE 1
|
||||
|
||||
/* Do not build encoding support */
|
||||
#define FS_ENCODE 0
|
||||
|
||||
/* Define to build experimental code */
|
||||
/* #undef FS_EXPERIMENTAL */
|
||||
|
||||
/* Define to 1 if you have the <dlfcn.h> header file. */
|
||||
#define HAVE_DLFCN_H 1
|
||||
|
||||
/* Define to 1 if you have libFLAC */
|
||||
#define HAVE_FLAC 0
|
||||
|
||||
/* Define to 1 if you have libFLAC 1.1.2 */
|
||||
/* #undef HAVE_FLAC_1_1_2 */
|
||||
|
||||
/* Define to 1 if you have libFLAC 1.1.3 */
|
||||
/* #undef HAVE_FLAC_1_1_3 */
|
||||
|
||||
/* Define to 1 if you have the <inttypes.h> header file. */
|
||||
#define HAVE_INTTYPES_H 1
|
||||
|
||||
/* Define if have libsndfile */
|
||||
/* #undef HAVE_LIBSNDFILE1 */
|
||||
|
||||
/* Define to 1 if you have the <memory.h> header file. */
|
||||
#define HAVE_MEMORY_H 1
|
||||
|
||||
/* Define if have liboggz */
|
||||
/* #undef HAVE_OGGZ */
|
||||
|
||||
/* Define to 1 if you have libspeex */
|
||||
#define HAVE_SPEEX 0
|
||||
|
||||
/* Define to 1 if you have libspeex 1.1.x */
|
||||
/* #undef HAVE_SPEEX_1_1 */
|
||||
|
||||
/* Define to 1 if speex_lib_get_mode() exists in libspeex */
|
||||
/* #undef HAVE_SPEEX_LIB_GET_MODE */
|
||||
|
||||
/* Define to 1 if you have the <stdint.h> header file. */
|
||||
/* #define HAVE_STDINT_H 1 */
|
||||
|
||||
/* Define to 1 if you have the <stdlib.h> header file. */
|
||||
#define HAVE_STDLIB_H 1
|
||||
|
||||
/* Define to 1 if you have the <strings.h> header file. */
|
||||
#define HAVE_STRINGS_H 1
|
||||
|
||||
/* Define to 1 if you have the <string.h> header file. */
|
||||
#define HAVE_STRING_H 1
|
||||
|
||||
/* Define to 1 if you have the <sys/stat.h> header file. */
|
||||
#define HAVE_SYS_STAT_H 1
|
||||
|
||||
/* Define to 1 if you have the <sys/types.h> header file. */
|
||||
#define HAVE_SYS_TYPES_H 1
|
||||
|
||||
/* Define to 1 if the system has the type `uintptr_t'. */
|
||||
/* #define HAVE_UINTPTR_T 1 */
|
||||
|
||||
/* Define to 1 if you have the <unistd.h> header file. */
|
||||
#define HAVE_UNISTD_H 1
|
||||
|
||||
/* Define to 1 if you have libvorbis */
|
||||
#define HAVE_VORBIS 1
|
||||
|
||||
/* Define to 1 if you have libvorbisenc */
|
||||
#define HAVE_VORBISENC 0
|
||||
|
||||
/* Define to the sub-directory in which libtool stores uninstalled libraries.
|
||||
*/
|
||||
#define LT_OBJDIR ".libs/"
|
||||
|
||||
/* Name of package */
|
||||
#define PACKAGE "libfishsound"
|
||||
|
||||
/* Define to the address where bug reports for this package should be sent. */
|
||||
#define PACKAGE_BUGREPORT ""
|
||||
|
||||
/* Define to the full name of this package. */
|
||||
#define PACKAGE_NAME ""
|
||||
|
||||
/* Define to the full name and version of this package. */
|
||||
#define PACKAGE_STRING ""
|
||||
|
||||
/* Define to the one symbol short name of this package. */
|
||||
#define PACKAGE_TARNAME ""
|
||||
|
||||
/* Define to the version of this package. */
|
||||
#define PACKAGE_VERSION ""
|
||||
|
||||
/* Define to 1 if you have the ANSI C header files. */
|
||||
#define STDC_HEADERS 1
|
||||
|
||||
/* Version number of package */
|
||||
#define VERSION "0.9.2"
|
||||
|
||||
/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most
|
||||
significant byte first (like Motorola and SPARC, unlike Intel). */
|
||||
#if defined AC_APPLE_UNIVERSAL_BUILD
|
||||
# if defined __BIG_ENDIAN__
|
||||
# define WORDS_BIGENDIAN 1
|
||||
# endif
|
||||
#else
|
||||
# ifndef WORDS_BIGENDIAN
|
||||
/* # undef WORDS_BIGENDIAN */
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* Define to empty if `const' does not conform to ANSI C. */
|
||||
/* #undef const */
|
||||
#undef FS_ENCODE
|
||||
#define FS_ENCODE 0
|
||||
#undef HAVE_FLAC
|
||||
#define HAVE_FLAC 0
|
||||
#undef HAVE_OGGZ
|
||||
#define HAVE_OGGZ 1
|
||||
#undef HAVE_SPEEX
|
||||
#define HAVE_SPEEX 0
|
||||
#undef HAVE_VORBIS
|
||||
#define HAVE_VORBIS 1
|
||||
#undef HAVE_VORBISENC
|
||||
#define HAVE_VORBISENC 0
|
||||
#undef DEBUG
|
||||
|
||||
#include "prcpucfg.h"
|
||||
#ifdef IS_BIG_ENDIAN
|
||||
#define WORDS_BIGENDIAN
|
||||
#endif
|
|
@ -1,122 +0,0 @@
|
|||
/*
|
||||
Copyright (C) 2003 Commonwealth Scientific and Industrial Research
|
||||
Organisation (CSIRO) Australia
|
||||
|
||||
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.
|
||||
|
||||
- Neither the name of CSIRO Australia nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
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 ORGANISATION 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 __FISH_SOUND_CONSTANTS_H__
|
||||
#define __FISH_SOUND_CONSTANTS_H__
|
||||
|
||||
/** \file
|
||||
* Constants used by libfishsound
|
||||
*/
|
||||
|
||||
/** Mode of operation (encode or decode) */
|
||||
typedef enum _FishSoundMode {
|
||||
/** Decode */
|
||||
FISH_SOUND_DECODE = 0x10,
|
||||
|
||||
/** Encode */
|
||||
FISH_SOUND_ENCODE = 0x20
|
||||
} FishSoundMode;
|
||||
|
||||
/** Identifiers for supported codecs */
|
||||
typedef enum _FishSoundCodecID {
|
||||
/** Unknown */
|
||||
FISH_SOUND_UNKNOWN = 0x00,
|
||||
|
||||
/** Vorbis */
|
||||
FISH_SOUND_VORBIS = 0x01,
|
||||
|
||||
/** Speex */
|
||||
FISH_SOUND_SPEEX = 0x02,
|
||||
|
||||
/** Flac */
|
||||
FISH_SOUND_FLAC = 0x03
|
||||
} FishSoundCodecID;
|
||||
|
||||
/** Decode callback return values */
|
||||
typedef enum _FishSoundStopCtl {
|
||||
/** Continue calling decode callbacks */
|
||||
FISH_SOUND_CONTINUE = 0,
|
||||
|
||||
/** Stop calling callbacks, but retain buffered data */
|
||||
FISH_SOUND_STOP_OK = 1,
|
||||
|
||||
/** Stop calling callbacks, and purge buffered data */
|
||||
FISH_SOUND_STOP_ERR = -1
|
||||
} FishSoundStopCtl;
|
||||
|
||||
/** Command codes */
|
||||
typedef enum _FishSoundCommand {
|
||||
/** No operation */
|
||||
FISH_SOUND_COMMAND_NOP = 0x0000,
|
||||
|
||||
/** Retrieve the FishSoundInfo */
|
||||
FISH_SOUND_GET_INFO = 0x1000,
|
||||
|
||||
/** Query if multichannel audio should be interpreted as interleaved */
|
||||
FISH_SOUND_GET_INTERLEAVE = 0x2000,
|
||||
|
||||
/** Set to 1 to interleave, 0 to non-interleave */
|
||||
FISH_SOUND_SET_INTERLEAVE = 0x2001,
|
||||
|
||||
FISH_SOUND_SET_ENCODE_VBR = 0x4000,
|
||||
|
||||
FISH_SOUND_COMMAND_MAX
|
||||
} FishSoundCommand;
|
||||
|
||||
/** Error values */
|
||||
typedef enum _FishSoundError {
|
||||
/** No error */
|
||||
FISH_SOUND_OK = 0,
|
||||
|
||||
/** generic error */
|
||||
FISH_SOUND_ERR_GENERIC = -1,
|
||||
|
||||
/** Not a valid FishSound* handle */
|
||||
FISH_SOUND_ERR_BAD = -2,
|
||||
|
||||
/** The requested operation is not suitable for this FishSound* handle */
|
||||
FISH_SOUND_ERR_INVALID = -3,
|
||||
|
||||
/** Out of memory */
|
||||
FISH_SOUND_ERR_OUT_OF_MEMORY = -4,
|
||||
|
||||
/** Functionality disabled at build time */
|
||||
FISH_SOUND_ERR_DISABLED = -10,
|
||||
|
||||
/** Too few bytes passed to fish_sound_identify() */
|
||||
FISH_SOUND_ERR_SHORT_IDENTIFY = -20,
|
||||
|
||||
/** Comment violates VorbisComment restrictions */
|
||||
FISH_SOUND_ERR_COMMENT_INVALID = -21
|
||||
} FishSoundError;
|
||||
|
||||
#endif /* __FISH_SOUND_CONSTANTS_H__ */
|
|
@ -1,129 +0,0 @@
|
|||
/*
|
||||
Copyright (C) 2003 Commonwealth Scientific and Industrial Research
|
||||
Organisation (CSIRO) Australia
|
||||
|
||||
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.
|
||||
|
||||
- Neither the name of CSIRO Australia nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
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 ORGANISATION 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 __FISH_SOUND_DECODE_H__
|
||||
#define __FISH_SOUND_DECODE_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** \file
|
||||
* Decode functions and callback prototypes
|
||||
*/
|
||||
|
||||
/**
|
||||
* Signature of a callback for libfishsound to call when it has decoded
|
||||
* PCM audio data, and you want this provided as non-interleaved floats.
|
||||
* \param fsound The FishSound* handle
|
||||
* \param pcm The decoded audio
|
||||
* \param frames The count of frames decoded
|
||||
* \param user_data Arbitrary user data
|
||||
* \retval FISH_SOUND_CONTINUE Continue decoding
|
||||
* \retval FISH_SOUND_STOP_OK Stop decoding immediately and
|
||||
* return control to the fish_sound_decode() caller
|
||||
* \retval FISH_SOUND_STOP_ERR Stop decoding immediately, purge buffered
|
||||
* data, and return control to the fish_sound_decode() caller
|
||||
*/
|
||||
typedef int (*FishSoundDecoded_Float) (FishSound * fsound, float * pcm[],
|
||||
long frames, void * user_data);
|
||||
|
||||
/**
|
||||
* Signature of a callback for libfishsound to call when it has decoded
|
||||
* PCM audio data, and you want this provided as interleaved floats.
|
||||
* \param fsound The FishSound* handle
|
||||
* \param pcm The decoded audio
|
||||
* \param frames The count of frames decoded
|
||||
* \param user_data Arbitrary user data
|
||||
* \retval FISH_SOUND_CONTINUE Continue decoding
|
||||
* \retval FISH_SOUND_STOP_OK Stop decoding immediately and
|
||||
* return control to the fish_sound_decode() caller
|
||||
* \retval FISH_SOUND_STOP_ERR Stop decoding immediately, purge buffered
|
||||
* data, and return control to the fish_sound_decode() caller
|
||||
*/
|
||||
typedef int (*FishSoundDecoded_FloatIlv) (FishSound * fsound, float ** pcm,
|
||||
long frames, void * user_data);
|
||||
|
||||
/**
|
||||
* Set the callback for libfishsound to call when it has a block of decoded
|
||||
* PCM audio ready, and you want this provided as non-interleaved floats.
|
||||
* \param fsound A FishSound* handle (created with mode FISH_SOUND_DECODE)
|
||||
* \param decoded The callback to call
|
||||
* \param user_data Arbitrary user data to pass to the callback
|
||||
* \retval 0 Success
|
||||
* \retval FISH_SOUND_ERR_BAD Not a valid FishSound* handle
|
||||
* \retval FISH_SOUND_ERR_OUT_OF_MEMORY Out of memory
|
||||
*/
|
||||
int fish_sound_set_decoded_float (FishSound * fsound,
|
||||
FishSoundDecoded_Float decoded,
|
||||
void * user_data);
|
||||
|
||||
/**
|
||||
* Set the callback for libfishsound to call when it has a block of decoded
|
||||
* PCM audio ready, and you want this provided as interleaved floats.
|
||||
* \param fsound A FishSound* handle (created with mode FISH_SOUND_DECODE)
|
||||
* \param decoded The callback to call
|
||||
* \param user_data Arbitrary user data to pass to the callback
|
||||
* \retval 0 Success
|
||||
* \retval FISH_SOUND_ERR_BAD Not a valid FishSound* handle
|
||||
* \retval FISH_SOUND_ERR_OUT_OF_MEMORY Out of memory
|
||||
*/
|
||||
int fish_sound_set_decoded_float_ilv (FishSound * fsound,
|
||||
FishSoundDecoded_FloatIlv decoded,
|
||||
void * user_data);
|
||||
|
||||
/**
|
||||
* Decode a block of compressed data.
|
||||
* No internal buffering is done, so a complete compressed audio packet
|
||||
* must be passed each time.
|
||||
* \param fsound A FishSound* handle (created with mode FISH_SOUND_DECODE)
|
||||
* \param buf A buffer containing a compressed audio packet
|
||||
* \param bytes A count of bytes to decode (i.e. the length of buf)
|
||||
* \returns The number of bytes consumed
|
||||
* \retval FISH_SOUND_ERR_STOP_OK Decoding was stopped by a FishSoundDecode*
|
||||
* callback returning FISH_SOUND_STOP_OK before any input bytes were consumed.
|
||||
* This will occur when PCM is decoded from previously buffered input, and
|
||||
* stopping is immediately requested.
|
||||
* \retval FISH_SOUND_ERR_STOP_ERR Decoding was stopped by a FishSoundDecode*
|
||||
* callback returning FISH_SOUND_STOP_ERR before any input bytes were consumed.
|
||||
* This will occur when PCM is decoded from previously buffered input, and
|
||||
* stopping is immediately requested.
|
||||
* \retval FISH_SOUND_ERR_BAD Not a valid FishSound* handle
|
||||
* \retval FISH_SOUND_ERR_OUT_OF_MEMORY Out of memory
|
||||
*/
|
||||
long fish_sound_decode (FishSound * fsound, unsigned char * buf, long bytes);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __FISH_SOUND_DECODE_H__ */
|
|
@ -1,107 +0,0 @@
|
|||
/*
|
||||
Copyright (C) 2003 Commonwealth Scientific and Industrial Research
|
||||
Organisation (CSIRO) Australia
|
||||
|
||||
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.
|
||||
|
||||
- Neither the name of CSIRO Australia nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
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 ORGANISATION 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 __FISH_SOUND_DEPRECATED_H__
|
||||
#define __FISH_SOUND_DEPRECATED_H__
|
||||
|
||||
/** \file
|
||||
* Deprecated interfaces
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* DEPRECATED TYPE.
|
||||
* Signature of a callback for libfishsound to call when it has decoded
|
||||
* PCM audio data, and you want this provided as floats using the current
|
||||
* interleave method as set by fish_sound_set_interleave().
|
||||
*/
|
||||
typedef FishSoundDecoded_Float FishSoundDecoded;
|
||||
|
||||
/**
|
||||
* DEPRECATED FUNCTION.
|
||||
* Set the callback for libfishsound to call when it has a block of decoded
|
||||
* PCM audio ready, and you want this provided as floats using the current
|
||||
* interleave method as set by fish_sound_set_interleave().
|
||||
* This function, and fish_sound_set_interleave(), have been superceded by
|
||||
* the typesafe fish_sound_set_decoded_TYPE() callbacks, such as
|
||||
* fish_sound_set_decoded_float() or fish_sound_set_decoded_float_ilv().
|
||||
*
|
||||
* \param fsound A FishSound* handle (created with mode FISH_SOUND_DECODE)
|
||||
* \param decoded The callback to call
|
||||
* \param user_data Arbitrary user data to pass to the callback
|
||||
* \returns 0 on success, -1 on failure
|
||||
*/
|
||||
int fish_sound_set_decoded_callback (FishSound * fsound,
|
||||
FishSoundDecoded decoded,
|
||||
void * user_data);
|
||||
|
||||
/**
|
||||
* DEPRECATED FUNCTION.
|
||||
* Set the PCM format used by a FishSound object. The default value is
|
||||
* non-interleaved.
|
||||
* Prior to libfishsound 0.7.0, you would (optionally) specify whether you
|
||||
* wanted to receive interleaved or per-channel PCM data using
|
||||
* fish_sound_set_interleave(), the default being per-channel
|
||||
* (non-interleaved) PCM.
|
||||
* Whether or not your decoded callback expects interleaved or
|
||||
* non-interleaved data is now implied by the particular
|
||||
* fish_sound_set_decoded_TYPE() method you use to set it, such as
|
||||
* fish_sound_set_decoded_float() or fish_sound_set_decoded_float_ilv().
|
||||
*
|
||||
* \param fsound A FishSound* handle
|
||||
* \param interleave Whether to use interleaved PCM or not. Valid values are
|
||||
* 0 for non-interleaved, and 1 for interleaved.
|
||||
* \retval 0 Success
|
||||
* \retval -1 Invalid \a fsound
|
||||
*/
|
||||
int fish_sound_set_interleave (FishSound * fsound, int interleave);
|
||||
|
||||
/**
|
||||
* DEPRECATED FUNCTION.
|
||||
* Encode a block of audio
|
||||
* \param fsound A FishSound* handle (created with mode FISH_SOUND_ENCODE)
|
||||
* \param pcm The audio data to encode
|
||||
* \param frames A count of frames to encode
|
||||
* \returns The number of frames encoded
|
||||
* \note For multichannel audio, the audio data is interpreted according
|
||||
* to the current PCM style
|
||||
*/
|
||||
long fish_sound_encode (FishSound * fsound, float ** pcm, long frames);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __FISH_SOUND_DEPRECATED_H__ */
|
|
@ -1,97 +0,0 @@
|
|||
/*
|
||||
Copyright (C) 2003 Commonwealth Scientific and Industrial Research
|
||||
Organisation (CSIRO) Australia
|
||||
|
||||
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.
|
||||
|
||||
- Neither the name of CSIRO Australia nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
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 ORGANISATION 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 __FISH_SOUND_ENCODE_H__
|
||||
#define __FISH_SOUND_ENCODE_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** \file
|
||||
* Encode functions and callback prototypes
|
||||
*/
|
||||
|
||||
/**
|
||||
* Signature of a callback for libfishsound to call when it has encoded
|
||||
* data.
|
||||
* \param fsound The FishSound* handle
|
||||
* \param buf The encoded data
|
||||
* \param bytes The count of bytes encoded
|
||||
* \param user_data Arbitrary user data
|
||||
* \retval 0 to continue
|
||||
* \retval non-zero to stop encoding immediately and
|
||||
* return control to the fish_sound_encode() caller
|
||||
*/
|
||||
typedef int (*FishSoundEncoded) (FishSound * fsound, unsigned char * buf,
|
||||
long bytes, void * user_data);
|
||||
|
||||
/**
|
||||
* Set the callback for libfishsound to call when it has a block of
|
||||
* encoded data ready
|
||||
* \param fsound A FishSound* handle (created with mode FISH_SOUND_ENCODE)
|
||||
* \param encoded The callback to call
|
||||
* \param user_data Arbitrary user data to pass to the callback
|
||||
* \returns 0 on success, -1 on failure
|
||||
*/
|
||||
int fish_sound_set_encoded_callback (FishSound * fsound,
|
||||
FishSoundEncoded encoded,
|
||||
void * user_data);
|
||||
|
||||
/**
|
||||
* Encode a block of PCM audio given as non-interleaved floats.
|
||||
* \param fsound A FishSound* handle (created with mode FISH_SOUND_ENCODE)
|
||||
* \param pcm The audio data to encode
|
||||
* \param frames A count of frames to encode
|
||||
* \returns The number of frames encoded
|
||||
* \note For multichannel audio, the audio data is interpreted according
|
||||
* to the current PCM style
|
||||
*/
|
||||
long fish_sound_encode_float (FishSound * fsound, float * pcm[], long frames);
|
||||
|
||||
/**
|
||||
* Encode a block of audio given as interleaved floats.
|
||||
* \param fsound A FishSound* handle (created with mode FISH_SOUND_ENCODE)
|
||||
* \param pcm The audio data to encode
|
||||
* \param frames A count of frames to encode
|
||||
* \returns The number of frames encoded
|
||||
* \note For multichannel audio, the audio data is interpreted according
|
||||
* to the current PCM style
|
||||
*/
|
||||
long fish_sound_encode_float_ilv (FishSound * fsound, float ** pcm,
|
||||
long frames);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __FISH_SOUND_ENCODE_H__ */
|
|
@ -1,589 +0,0 @@
|
|||
/*
|
||||
Copyright (C) 2003 Commonwealth Scientific and Industrial Research
|
||||
Organisation (CSIRO) Australia
|
||||
|
||||
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.
|
||||
|
||||
- Neither the name of CSIRO Australia nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
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 ORGANISATION 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 __FISH_SOUND_H__
|
||||
#define __FISH_SOUND_H__
|
||||
|
||||
#include <fishsound/constants.h>
|
||||
|
||||
/** \mainpage
|
||||
*
|
||||
* \section intro FishSound, the sound of fish!
|
||||
*
|
||||
* This is the documentation for the FishSound C API. FishSound provides
|
||||
* a simple programming interface for decoding and encoding audio data
|
||||
* using Xiph.Org codecs (FLAC, Speex and Vorbis).
|
||||
*
|
||||
* libfishsound by itself is designed to handle raw codec streams from
|
||||
* a lower level layer such as UDP datagrams.
|
||||
* When these codecs are used in files, they are commonly encapsulated in
|
||||
* <a href="http://www.xiph.org/ogg/">Ogg</a> to produce
|
||||
* <em>Ogg FLAC</em>, <em>Speex</em> and <em>Ogg Vorbis</em> files.
|
||||
* Example C programs using
|
||||
* <a href="http://www.annodex.net/software/liboggz/">liboggz</a> to
|
||||
* read and write these files are provided in the libfishsound sources.
|
||||
*
|
||||
* For more information on the design and history of libfishsound, see the
|
||||
* \link about About \endlink section of this documentation, and the
|
||||
* <a href="http://www.annodex.net/software/libfishsound/">libfishsound</a>
|
||||
* homepage.
|
||||
*
|
||||
* \subsection contents Contents
|
||||
*
|
||||
* - \link fishsound.h fishsound.h \endlink:
|
||||
* Documentation of the FishSound API.
|
||||
*
|
||||
* - \link comments.h Handling comments \endlink:
|
||||
* How to add and retrieve \a name = \a value metadata in Vorbis and Speex
|
||||
* streams.
|
||||
*
|
||||
* - \link decode Decoding audio data \endlink:
|
||||
* How to decode audio data with FishSound, including source for a fully
|
||||
* working Ogg FLAC, Speex and Ogg Vorbis decoder.
|
||||
*
|
||||
* - \link encode Encoding audio data \endlink:
|
||||
* How to encode audio data with FishSound, including source for a fully
|
||||
* working Ogg FLAC, Speex and Ogg Vorbis encoder.
|
||||
*
|
||||
* - \link configuration Configuration \endlink:
|
||||
* Customizing libfishsound to only decode or encode,
|
||||
* or to disable support for a particular codec.
|
||||
*
|
||||
* - \link building Building \endlink:
|
||||
* Information related to building software that uses libfishsound.
|
||||
*
|
||||
* - \link about About \endlink:
|
||||
* Design, motivation, history and acknowledgements.
|
||||
*
|
||||
* \section Licensing
|
||||
*
|
||||
* libfishsound is provided under the following BSD-style open source license:
|
||||
*
|
||||
* \include COPYING
|
||||
*
|
||||
*/
|
||||
|
||||
/** \defgroup about About
|
||||
*
|
||||
* \section design Design
|
||||
* libfishsound provides a simple programming interface for decoding and
|
||||
* encoding audio data using codecs from
|
||||
* <a href="http://www.xiph.org/">Xiph.Org</a>.
|
||||
*
|
||||
* libfishsound by itself is designed to handle raw codec streams from
|
||||
* a lower level layer such as UDP datagrams.
|
||||
* When these codecs are used in files, they are commonly encapsulated in
|
||||
* <a href="http://www.xiph.org/ogg/">Ogg</a> to produce
|
||||
* <em>Ogg FLAC</em>, <em>Speex</em> and <em>Ogg Vorbis</em> files.
|
||||
* Example C programs using
|
||||
* <a href="http://www.annodex.net/software/liboggz/">liboggz</a> to
|
||||
* read and write these files are provided in the libfishsound sources.
|
||||
*
|
||||
* libfishsound is implemented as a wrapper around the existing codec
|
||||
* libraries and provides a consistent, higher-level programming
|
||||
* interface. The motivation for this is twofold: to simplify the task
|
||||
* of developing application software that supports these codecs,
|
||||
* and to ensure that valid codec streams are generated.
|
||||
*
|
||||
* \section history History
|
||||
* libfishsound was designed and developed by Conrad Parker on the
|
||||
* weekend of October 18-19 2003. Previously the author had implemented
|
||||
* Vorbis and Speex support in the following software:
|
||||
* - <a href="http://www.metadecks.org/software/sweep/">Sweep</a>, a
|
||||
* digital audio editor with decoding and GUI control of all encoding
|
||||
* options of Vorbis and Speex
|
||||
* - Speex support in the <a href="http://www.xinehq.org/">xine</a>
|
||||
* multimedia player
|
||||
* - Vorbis and Speex importers for
|
||||
* <a href="http://www.annodex.net/software/libannodex/">libannodex</a>,
|
||||
the basic library for reading and writing
|
||||
* <a href="http://www.annodex.net/">Annodex.net</a> media files.
|
||||
*
|
||||
* The implementation of libfishsound draws heavily on these sources, and
|
||||
* in turn the original example sources of libvorbis and libvorbisenc by
|
||||
* Monty, and libspeex by Jean-Marc Valin.
|
||||
*
|
||||
* The naming of libfishsound reflects both the Xiph.Org logo and
|
||||
* the author's reputation as a dirty, smelly old fish.
|
||||
*
|
||||
* \section limitations Limitations
|
||||
*
|
||||
* libfishsound has been designed to accomodate the various decoding and
|
||||
* encoding styles required by a wide variety of software. However, as it
|
||||
* is an abstraction of the underlying libvorbis, libvorbisenc and libspeex
|
||||
* libraries, it may not be possible to implement some low-level techniques
|
||||
* that these libraries enable, such as parallelization of Vorbis sub-block
|
||||
* decoding. Nevertheless it is expected that libfishsound is a useful
|
||||
* API for most software requiring Vorbis or Speex support, including most
|
||||
* applications the author has encountered.
|
||||
*
|
||||
* \section acknowledgements Acknowledgements
|
||||
* Much of the API design follows the style of
|
||||
* <a href="http://www.zip.com.au/~erikd/libsndfile/">libsndfile</a>.
|
||||
* The author would like to thank Erik de Castro Lopo for feedback on the
|
||||
* design of libfishsound.
|
||||
*/
|
||||
|
||||
/** \defgroup configuration Configuration
|
||||
*
|
||||
* \section platforms Platform-specific configuration
|
||||
*
|
||||
* FishSound can be configured on most platforms using the GNU autoconf
|
||||
* ./configure system described below.
|
||||
*
|
||||
* For Win32, see the \link win32 README.win32 \endlink section. You will
|
||||
* need to edit <tt>win32/config.h</tt> by hand to achieve the customizations
|
||||
* described below.
|
||||
*
|
||||
* \section ./configure ./configure
|
||||
*
|
||||
* It is possible to customize the functionality of libfishsound
|
||||
* by using various ./configure flags when
|
||||
* building it from source; for example you can build a smaller
|
||||
* version of libfishsound to only decode or encode, or and you can
|
||||
* choose to disable support for a particular codec.
|
||||
* By default, both decoding and encoding support is built for all
|
||||
* codecs found on the system.
|
||||
*
|
||||
* For general information about using ./configure, see the file
|
||||
* \link install INSTALL \endlink
|
||||
*
|
||||
* \subsection no_encode Removing encoding support
|
||||
*
|
||||
* Configuring with \a --disable-encode will remove all support for encoding:
|
||||
* - All internal encoding related functions will not be built
|
||||
* - Any attempt to call fish_sound_new() with \a mode == FISH_SOUND_ENCODE
|
||||
* will fail, returning NULL
|
||||
* - Any attempt to call fish_sound_encode_*() will return
|
||||
* FISH_SOUND_ERR_DISABLED
|
||||
* - The resulting library will not be linked against libvorbisenc
|
||||
*
|
||||
* \subsection no_decode Removing decoding support
|
||||
*
|
||||
* Configuring with \a --disable-decode will remove all support for decoding:
|
||||
* - All internal decoding related functions will not be built
|
||||
* - Any attempt to call fish_sound_new() with \a mode == FISH_SOUND_DECODE
|
||||
* will fail, returning NULL
|
||||
* - Any attempt to call fish_sound_decode() will return
|
||||
* FISH_SOUND_ERR_DISABLED
|
||||
*
|
||||
* \subsection no_flac Removing FLAC support
|
||||
*
|
||||
* Configuring with \a --disable-flac will remove all support for FLAC:
|
||||
* - All internal FLAC related functions will not be built
|
||||
* - Any attempt to call fish_sound_new() with \a mode == FISH_SOUND_ENCODE
|
||||
* and \a fsinfo->format == FISH_SOUND_FLAC will fail, returning NULL
|
||||
* - The resulting library will not be linked against libFLAC
|
||||
*
|
||||
* \subsection no_speex Removing Speex support
|
||||
*
|
||||
* Configuring with \a --disable-speex will remove all support for Speex:
|
||||
* - All internal Speex related functions will not be built
|
||||
* - Any attempt to call fish_sound_new() with \a mode == FISH_SOUND_ENCODE
|
||||
* and \a fsinfo->format == FISH_SOUND_SPEEX will fail, returning NULL
|
||||
* - The resulting library will not be linked against libspeex
|
||||
*
|
||||
* \subsection no_vorbis Removing Vorbis support
|
||||
*
|
||||
* Configuring with \a --disable-vorbis will remove all support for Vorbis:
|
||||
* - All internal Vorbis related functions will not be built
|
||||
* - Any attempt to call fish_sound_new() with \a mode == FISH_SOUND_ENCODE
|
||||
* and \a fsinfo->format == FISH_SOUND_VORBIS will fail, returning NULL
|
||||
* - The resulting library will not be linked against libvorbis or libvorbisenc
|
||||
*
|
||||
* \subsection summary Configuration summary
|
||||
*
|
||||
* Upon successful configuration, you should see something like this:
|
||||
<pre>
|
||||
------------------------------------------------------------------------
|
||||
libfishsound 0.9.0: Automatic configuration OK.
|
||||
|
||||
General configuration:
|
||||
|
||||
Experimental code: ........... no
|
||||
Decoding support: ............ yes
|
||||
Encoding support: ............ yes
|
||||
|
||||
Library configuration (./src/libfishsound):
|
||||
|
||||
FLAC support: ................ yes
|
||||
Speex support: ............... yes (1.1.x)
|
||||
Vorbis support: .............. yes
|
||||
|
||||
Example programs (./src/examples):
|
||||
|
||||
fishsound-identify fishsound-decode fishsound-encode
|
||||
|
||||
Installation paths:
|
||||
|
||||
libfishsound: ................ /usr/local/lib
|
||||
C header files: .............. /usr/local/include/fishsound
|
||||
Documentation: ............... /usr/local/share/doc/libfishsound
|
||||
|
||||
Building:
|
||||
|
||||
Type 'make' to compile libfishsound.
|
||||
|
||||
Type 'make install' to install libfishsound.
|
||||
|
||||
Type 'make check' to run test suite (Valgrind testing not enabled)
|
||||
|
||||
Example programs will be built but not installed.
|
||||
------------------------------------------------------------------------
|
||||
</pre>
|
||||
*/
|
||||
|
||||
/** \defgroup install Installation
|
||||
* \section install INSTALL
|
||||
*
|
||||
* \include INSTALL
|
||||
*/
|
||||
|
||||
/** \defgroup win32 Building on Win32
|
||||
* \section win32 README.Win32
|
||||
*
|
||||
* \include README.win32
|
||||
*/
|
||||
|
||||
/** \defgroup building Building against libfishsound
|
||||
*
|
||||
*
|
||||
* \section autoconf Using GNU autoconf
|
||||
*
|
||||
* If you are using GNU autoconf, you do not need to call pkg-config
|
||||
* directly. Use the following macro to determine if libfishsound is
|
||||
* available:
|
||||
*
|
||||
<pre>
|
||||
PKG_CHECK_MODULES(FISHSOUND, fishsound >= 0.6.0,
|
||||
HAVE_FISHSOUND="yes", HAVE_FISHSOUND="no")
|
||||
if test "x$HAVE_FISHSOUND" = "xyes" ; then
|
||||
AC_SUBST(FISHSOUND_CFLAGS)
|
||||
AC_SUBST(FISHSOUND_LIBS)
|
||||
fi
|
||||
</pre>
|
||||
* (Note that if your application requires FLAC support, you should check
|
||||
* for a version of fishsound >= 0.9.0).
|
||||
*
|
||||
* If libfishsound is found, HAVE_FISHSOUND will be set to "yes", and
|
||||
* the autoconf variables FISHSOUND_CFLAGS and FISHSOUND_LIBS will
|
||||
* be set appropriately.
|
||||
*
|
||||
* \section pkg-config Determining compiler options with pkg-config
|
||||
*
|
||||
* If you are not using GNU autoconf in your project, you can use the
|
||||
* pkg-config tool directly to determine the correct compiler options.
|
||||
*
|
||||
<pre>
|
||||
FISHSOUND_CFLAGS=`pkg-config --cflags fishsound`
|
||||
|
||||
FISHSOUND_LIBS=`pkg-config --libs fishsound`
|
||||
</pre>
|
||||
*
|
||||
*/
|
||||
|
||||
/** \file
|
||||
* The libfishsound C API.
|
||||
*
|
||||
* \section general General usage
|
||||
*
|
||||
* All access is managed via a FishSound* handle. This is instantiated
|
||||
* using fish_sound_new() and should be deleted with fish_sound_delete()
|
||||
* when no longer required. If there is a discontinuity in the input
|
||||
* data (eg. after seeking in an input file), call fish_sound_reset() to
|
||||
* reset the internal codec state.
|
||||
*
|
||||
* \section decoding Decoding
|
||||
*
|
||||
* libfishsound provides callback based decoding: you feed it encoded audio
|
||||
* data, and it will call your callback with decoded PCM. A more detailed
|
||||
* explanation and a full example of decoding Ogg FLAC, Speex and Ogg Vorbis
|
||||
* files is provided in the \link decode Decoding audio data \endlink section.
|
||||
*
|
||||
* \section encoding Encoding
|
||||
*
|
||||
* libfishsound provides callback based encoding: you feed it PCM audio,
|
||||
* and it will call your callback with encoded audio data. A more detailed
|
||||
* explanation and a full example of encoding Ogg FLAC, Speex and Ogg Vorbis
|
||||
* files is provided in the \link encode Encoding audio data \endlink section.
|
||||
*/
|
||||
|
||||
/** \defgroup decode Decoding audio data
|
||||
*
|
||||
* To decode audio data using libfishsound:
|
||||
*
|
||||
* - create a FishSound* object with mode FISH_SOUND_DECODE. fish_sound_new()
|
||||
* will return a new FishSound* object, initialised for decoding, and the
|
||||
* FishSoundInfo structure will be cleared.
|
||||
* - provide a FishSoundDecoded_* callback for libfishsound to call when it has
|
||||
* decoded audio.
|
||||
* - (optionally) specify whether you want to receive interleaved or
|
||||
* per-channel PCM data, using a fish_sound_set_interleave().
|
||||
* The default is for per-channel (non-interleaved) PCM.
|
||||
* - feed encoded audio data to libfishsound via fish_sound_decode().
|
||||
* libfishsound will decode the audio for you, calling the FishSoundDecoded_*
|
||||
* callback you provided earlier each time it has a block of audio ready.
|
||||
* - when finished, call fish_sound_delete().
|
||||
*
|
||||
* This procedure is illustrated in src/examples/fishsound-decode.c.
|
||||
* Note that this example additionally:
|
||||
* - uses <a href="http://www.annodex.net/software/liboggz/">liboggz</a> to
|
||||
* demultiplex audio data from an Ogg encapsulated FLAC, Speex or Vorbis
|
||||
* stream. The step of feeding encoded data to libfishsound is done within
|
||||
* the OggzReadPacket callback.
|
||||
* - uses <a href="http://www.mega-nerd.com/libsndfile/">libsndfile</a> to
|
||||
* write the decoded audio to a WAV file.
|
||||
*
|
||||
* Hence this example code demonstrates all that is needed to decode
|
||||
* Ogg FLAC, Speex or Ogg Vorbis files:
|
||||
*
|
||||
* \include fishsound-decode.c
|
||||
*/
|
||||
|
||||
/** \defgroup encode Encoding audio data
|
||||
*
|
||||
* To encode audio data using libfishsound:
|
||||
*
|
||||
* - create a FishSound* object with mode FISH_SOUND_ENCODE, and with a
|
||||
* FishSoundInfo structure filled in with the required encoding parameters.
|
||||
* fish_sound_new() will return a new FishSound* object initialised for
|
||||
* encoding.
|
||||
* - provide a FishSoundEncoded callback for libfishsound to call when it
|
||||
* has a block of encoded audio
|
||||
* - feed raw PCM audio data to libfishsound via fish_sound_encode_*().
|
||||
* libfishsound will encode the audio for you, calling the FishSoundEncoded
|
||||
* callback you provided earlier each time it has a block of encoded audio
|
||||
* ready.
|
||||
* - when finished, call fish_sound_delete().
|
||||
*
|
||||
* This procedure is illustrated in src/examples/fishsound-encode.c.
|
||||
* Note that this example additionally:
|
||||
* - uses <a href="http://www.mega-nerd.com/libsndfile/">libsndfile</a> to
|
||||
* read input from a PCM audio file (WAV, AIFF, etc.)
|
||||
* - uses <a href="http://www.annodex.net/software/liboggz/">liboggz</a> to
|
||||
* encapsulate the encoded FLAC, Speex or Vorbis data in an Ogg stream.
|
||||
*
|
||||
* Hence this example code demonstrates all that is needed to encode
|
||||
* Ogg FLAC, Speex and Ogg Vorbis files:
|
||||
*
|
||||
* \include fishsound-encode.c
|
||||
*/
|
||||
|
||||
/**
|
||||
* Info about a particular encoder/decoder instance
|
||||
*/
|
||||
typedef struct {
|
||||
/** Sample rate of audio data in Hz */
|
||||
int samplerate;
|
||||
|
||||
/** Count of channels */
|
||||
int channels;
|
||||
|
||||
/** FISH_SOUND_VORBIS, FISH_SOUND_SPEEX, FISH_SOUND_FLAC etc. */
|
||||
int format;
|
||||
} FishSoundInfo;
|
||||
|
||||
/**
|
||||
* Info about a particular sound format
|
||||
*/
|
||||
typedef struct {
|
||||
/** FISH_SOUND_VORBIS, FISH_SOUND_SPEEX, FISH_SOUND_FLAC etc. */
|
||||
int format;
|
||||
|
||||
/** Printable name */
|
||||
const char * name;
|
||||
|
||||
/** Commonly used file extension */
|
||||
const char * extension;
|
||||
} FishSoundFormat;
|
||||
|
||||
/**
|
||||
* An opaque handle to a FishSound. This is returned by fishsound_new()
|
||||
* and is passed to all other fish_sound_*() functions.
|
||||
*/
|
||||
typedef void * FishSound;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Identify a codec based on the first few bytes of data.
|
||||
* \param buf A pointer to the first few bytes of the data
|
||||
* \param bytes The count of bytes available at buf
|
||||
* \retval FISH_SOUND_xxxxxx FISH_SOUND_VORBIS, FISH_SOUND_SPEEX or
|
||||
* FISH_SOUND_FLAC if \a buf was identified as the initial bytes of a
|
||||
* supported codec
|
||||
* \retval FISH_SOUND_UNKNOWN if the codec could not be identified
|
||||
* \retval FISH_SOUND_ERR_SHORT_IDENTIFY if \a bytes is less than 8
|
||||
* \note If \a bytes is exactly 8, then only a weak check is performed,
|
||||
* which is fast but may return a false positive.
|
||||
* \note If \a bytes is greater than 8, then a stronger check is performed
|
||||
* in which an attempt is made to decode \a buf as the initial header of
|
||||
* each supported codec. This is unlikely to return a false positive but
|
||||
* is only useful if \a buf is the entire payload of a packet derived from
|
||||
* a lower layer such as Ogg framing or UDP datagrams.
|
||||
*/
|
||||
int
|
||||
fish_sound_identify (unsigned char * buf, long bytes);
|
||||
|
||||
/**
|
||||
* Instantiate a new FishSound* handle
|
||||
* \param mode FISH_SOUND_DECODE or FISH_SOUND_ENCODE
|
||||
* \param fsinfo Encoder configuration, may be NULL for FISH_SOUND_DECODE
|
||||
* \returns A new FishSound* handle, or NULL on error
|
||||
*/
|
||||
FishSound * fish_sound_new (int mode, FishSoundInfo * fsinfo);
|
||||
|
||||
/**
|
||||
* Flush any internally buffered data, forcing encode
|
||||
* \param fsound A FishSound* handle
|
||||
* \returns 0 on success, -1 on failure
|
||||
*/
|
||||
long fish_sound_flush (FishSound * fsound);
|
||||
|
||||
/**
|
||||
* Reset the codec state of a FishSound object.
|
||||
*
|
||||
* When decoding from a seekable file, fish_sound_reset() should be called
|
||||
* after any seek operations. See also fish_sound_set_frameno().
|
||||
*
|
||||
* \param fsound A FishSound* handle
|
||||
* \returns 0 on success, -1 on failure
|
||||
*/
|
||||
int fish_sound_reset (FishSound * fsound);
|
||||
|
||||
/**
|
||||
* Delete a FishSound object
|
||||
* \param fsound A FishSound* handle
|
||||
* \returns 0 on success, -1 on failure
|
||||
*/
|
||||
int fish_sound_delete (FishSound * fsound);
|
||||
|
||||
/**
|
||||
* Command interface
|
||||
* \param fsound A FishSound* handle
|
||||
* \param command The command action
|
||||
* \param data Command data
|
||||
* \param datasize Size of the data in bytes
|
||||
* \returns 0 on success, -1 on failure
|
||||
*/
|
||||
int fish_sound_command (FishSound * fsound, int command, void * data,
|
||||
int datasize);
|
||||
|
||||
/**
|
||||
* Query whether a FishSound object is using interleaved PCM
|
||||
* \param fsound A FishSound* handle
|
||||
* \retval 0 \a fsound uses non-interleaved PCM
|
||||
* \retval 1 \a fsound uses interleaved PCM
|
||||
* \retval -1 Invalid \a fsound, or out of memory.
|
||||
*/
|
||||
int fish_sound_get_interleave (FishSound * fsound);
|
||||
|
||||
/**
|
||||
* Query the current frame number of a FishSound object.
|
||||
*
|
||||
* For decoding, this is the greatest frame index that has been decoded and
|
||||
* made available to a FishSoundDecoded callback. This function is safe to
|
||||
* call from within a FishSoundDecoded callback, and corresponds to the frame
|
||||
* number of the last frame in the current decoded block.
|
||||
*
|
||||
* For encoding, this is the greatest frame index that has been encoded. This
|
||||
* function is safe to call from within a FishSoundEncoded callback, and
|
||||
* corresponds to the frame number of the last frame encoded in the current
|
||||
* block.
|
||||
*
|
||||
* \param fsound A FishSound* handle
|
||||
* \returns The current frame number
|
||||
* \retval -1 Invalid \a fsound
|
||||
*/
|
||||
long fish_sound_get_frameno (FishSound * fsound);
|
||||
|
||||
/**
|
||||
* Set the current frame number of a FishSound object.
|
||||
*
|
||||
* When decoding from a seekable file, fish_sound_set_frameno() should be
|
||||
* called after any seek operations, otherwise the value returned by
|
||||
* fish_sound_get_frameno() will simply continue to increment. See also
|
||||
* fish_sound_reset().
|
||||
*
|
||||
* \param fsound A FishSound* handle
|
||||
* \param frameno The current frame number.
|
||||
* \retval 0 Success
|
||||
* \retval -1 Invalid \a fsound
|
||||
*/
|
||||
int fish_sound_set_frameno (FishSound * fsound, long frameno);
|
||||
|
||||
/**
|
||||
* Prepare truncation details for the next block of data.
|
||||
* The semantics of these parameters derives directly from Ogg encapsulation
|
||||
* of Vorbis, described
|
||||
* <a href="http://www.xiph.org/ogg/vorbis/doc/Vorbis_I_spec.html#vorbis-over-ogg">here</a>.
|
||||
*
|
||||
* When decoding from Ogg, you should call this function with the \a granulepos
|
||||
* and \a eos of the \a ogg_packet structure. This call should be made before
|
||||
* passing the packet's data to fish_sound_decode(). Failure to do so may
|
||||
* result in minor decode errors on the first and/or last packet of the stream.
|
||||
*
|
||||
* When encoding into Ogg, you should call this function with the \a granulepos
|
||||
* and \a eos that will be used for the \a ogg_packet structure. This call
|
||||
* should be made before passing the block of audio data to
|
||||
* fish_sound_encode_*(). Failure to do so may result in minor encoding errors
|
||||
* on the first and/or last packet of the stream.
|
||||
*
|
||||
* \param fsound A FishSound* handle
|
||||
* \param next_granulepos The "granulepos" for the next block to decode.
|
||||
* If unknown, set \a next_granulepos to -1. Otherwise,
|
||||
* \a next_granulepos specifies the frameno of the final frame in the
|
||||
* block. This is authoritative, hence can be used to indicate
|
||||
* various forms of truncation at the beginning or end of a stream.
|
||||
* Mid-stream, a later-than-expected "granulepos" indicates that some
|
||||
* data was missing.
|
||||
* \param next_eos A boolean indicating whether the next data block will be
|
||||
* the last in the stream.
|
||||
* \retval 0 Success
|
||||
* \retval -1 Invalid \a fsound
|
||||
*/
|
||||
int fish_sound_prepare_truncation (FishSound * fsound, long next_granulepos,
|
||||
int next_eos);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#include <fishsound/decode.h>
|
||||
#include <fishsound/encode.h>
|
||||
#include <fishsound/comments.h>
|
||||
|
||||
#include <fishsound/deprecated.h>
|
||||
|
||||
#endif /* __FISH_SOUND_H__ */
|
|
@ -1,47 +0,0 @@
|
|||
# ***** BEGIN LICENSE BLOCK *****
|
||||
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
#
|
||||
# The contents of this file are subject to the Mozilla Public License Version
|
||||
# 1.1 (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
# http://www.mozilla.org/MPL/
|
||||
#
|
||||
# Software distributed under the License is distributed on an "AS IS" basis,
|
||||
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
# for the specific language governing rights and limitations under the
|
||||
# License.
|
||||
#
|
||||
# The Original Code is Mozilla code.
|
||||
#
|
||||
# The Initial Developer of the Original Code is the Mozilla Corporation.
|
||||
# Portions created by the Initial Developer are Copyright (C) 2007
|
||||
# the Initial Developer. All Rights Reserved.
|
||||
#
|
||||
# Contributor(s):
|
||||
# Chris Double <chris.double@double.co.nz>
|
||||
#
|
||||
# Alternatively, the contents of this file may be used under the terms of
|
||||
# either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
# in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
# of those above. If you wish to allow use of your version of this file only
|
||||
# under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
# use your version of this file under the terms of the MPL, indicate your
|
||||
# decision by deleting the provisions above and replace them with the notice
|
||||
# and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
# the provisions above, a recipient may use your version of this file under
|
||||
# the terms of any one of the MPL, the GPL or the LGPL.
|
||||
#
|
||||
# ***** END LICENSE BLOCK *****
|
||||
|
||||
DEPTH = ../../..
|
||||
topsrcdir = @top_srcdir@
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
|
||||
include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
MODULE = fishsound
|
||||
DIRS = libfishsound
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
|
@ -1,58 +0,0 @@
|
|||
# ***** BEGIN LICENSE BLOCK *****
|
||||
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
#
|
||||
# The contents of this file are subject to the Mozilla Public License Version
|
||||
# 1.1 (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
# http://www.mozilla.org/MPL/
|
||||
#
|
||||
# Software distributed under the License is distributed on an "AS IS" basis,
|
||||
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
# for the specific language governing rights and limitations under the
|
||||
# License.
|
||||
#
|
||||
# The Original Code is Mozilla code.
|
||||
#
|
||||
# The Initial Developer of the Original Code is the Mozilla Corporation.
|
||||
# Portions created by the Initial Developer are Copyright (C) 2007
|
||||
# the Initial Developer. All Rights Reserved.
|
||||
#
|
||||
# Contributor(s):
|
||||
# Chris Double <chris.double@double.co.nz>
|
||||
#
|
||||
# Alternatively, the contents of this file may be used under the terms of
|
||||
# either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
# in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
# of those above. If you wish to allow use of your version of this file only
|
||||
# under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
# use your version of this file under the terms of the MPL, indicate your
|
||||
# decision by deleting the provisions above and replace them with the notice
|
||||
# and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
# the provisions above, a recipient may use your version of this file under
|
||||
# the terms of any one of the MPL, the GPL or the LGPL.
|
||||
#
|
||||
# ***** END LICENSE BLOCK *****
|
||||
|
||||
DEPTH = ../../../..
|
||||
topsrcdir = @top_srcdir@
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
|
||||
include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
MODULE = fishsound
|
||||
LIBRARY_NAME = fishsound
|
||||
FORCE_STATIC_LIB= 1
|
||||
|
||||
CSRCS = \
|
||||
fishsound_comments.c \
|
||||
fishsound_decode.c \
|
||||
fishsound.c \
|
||||
fs_vector.c \
|
||||
fishsound_speex.c \
|
||||
fishsound_vorbis.c \
|
||||
fishsound_flac.c \
|
||||
$(NULL)
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
|
@ -1,138 +0,0 @@
|
|||
/* config.h. Generated from config.h.in by configure. */
|
||||
/* config.h.in. Generated from configure.ac by autoheader. */
|
||||
|
||||
/* Define if building universal (internal helper macro) */
|
||||
/* #undef AC_APPLE_UNIVERSAL_BUILD */
|
||||
|
||||
/* Do not build decoding support */
|
||||
#define FS_DECODE 1
|
||||
|
||||
/* Do not build encoding support */
|
||||
#define FS_ENCODE 0
|
||||
|
||||
/* Define to build experimental code */
|
||||
/* #undef FS_EXPERIMENTAL */
|
||||
|
||||
/* Define to 1 if you have the <dlfcn.h> header file. */
|
||||
#define HAVE_DLFCN_H 1
|
||||
|
||||
/* Define to 1 if you have libFLAC */
|
||||
#define HAVE_FLAC 0
|
||||
|
||||
/* Define to 1 if you have libFLAC 1.1.2 */
|
||||
/* #undef HAVE_FLAC_1_1_2 */
|
||||
|
||||
/* Define to 1 if you have libFLAC 1.1.3 */
|
||||
/* #undef HAVE_FLAC_1_1_3 */
|
||||
|
||||
/* Define to 1 if you have the <inttypes.h> header file. */
|
||||
#define HAVE_INTTYPES_H 1
|
||||
|
||||
/* Define if have libsndfile */
|
||||
/* #undef HAVE_LIBSNDFILE1 */
|
||||
|
||||
/* Define to 1 if you have the <memory.h> header file. */
|
||||
#define HAVE_MEMORY_H 1
|
||||
|
||||
/* Define if have liboggz */
|
||||
/* #undef HAVE_OGGZ */
|
||||
|
||||
/* Define to 1 if you have libspeex */
|
||||
#define HAVE_SPEEX 0
|
||||
|
||||
/* Define to 1 if you have libspeex 1.1.x */
|
||||
/* #undef HAVE_SPEEX_1_1 */
|
||||
|
||||
/* Define to 1 if speex_lib_get_mode() exists in libspeex */
|
||||
/* #undef HAVE_SPEEX_LIB_GET_MODE */
|
||||
|
||||
/* Define to 1 if you have the <stdint.h> header file. */
|
||||
/* #define HAVE_STDINT_H 1 */
|
||||
|
||||
/* Define to 1 if you have the <stdlib.h> header file. */
|
||||
#define HAVE_STDLIB_H 1
|
||||
|
||||
/* Define to 1 if you have the <strings.h> header file. */
|
||||
#define HAVE_STRINGS_H 1
|
||||
|
||||
/* Define to 1 if you have the <string.h> header file. */
|
||||
#define HAVE_STRING_H 1
|
||||
|
||||
/* Define to 1 if you have the <sys/stat.h> header file. */
|
||||
#define HAVE_SYS_STAT_H 1
|
||||
|
||||
/* Define to 1 if you have the <sys/types.h> header file. */
|
||||
#define HAVE_SYS_TYPES_H 1
|
||||
|
||||
/* Define to 1 if the system has the type `uintptr_t'. */
|
||||
/* #define HAVE_UINTPTR_T 1 */
|
||||
|
||||
/* Define to 1 if you have the <unistd.h> header file. */
|
||||
#define HAVE_UNISTD_H 1
|
||||
|
||||
/* Define to 1 if you have libvorbis */
|
||||
#define HAVE_VORBIS 1
|
||||
|
||||
/* Define to 1 if you have libvorbisenc */
|
||||
#define HAVE_VORBISENC 0
|
||||
|
||||
/* Define to the sub-directory in which libtool stores uninstalled libraries.
|
||||
*/
|
||||
#define LT_OBJDIR ".libs/"
|
||||
|
||||
/* Name of package */
|
||||
#define PACKAGE "libfishsound"
|
||||
|
||||
/* Define to the address where bug reports for this package should be sent. */
|
||||
#define PACKAGE_BUGREPORT ""
|
||||
|
||||
/* Define to the full name of this package. */
|
||||
#define PACKAGE_NAME ""
|
||||
|
||||
/* Define to the full name and version of this package. */
|
||||
#define PACKAGE_STRING ""
|
||||
|
||||
/* Define to the one symbol short name of this package. */
|
||||
#define PACKAGE_TARNAME ""
|
||||
|
||||
/* Define to the version of this package. */
|
||||
#define PACKAGE_VERSION ""
|
||||
|
||||
/* Define to 1 if you have the ANSI C header files. */
|
||||
#define STDC_HEADERS 1
|
||||
|
||||
/* Version number of package */
|
||||
#define VERSION "0.9.2"
|
||||
|
||||
/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most
|
||||
significant byte first (like Motorola and SPARC, unlike Intel). */
|
||||
#if defined AC_APPLE_UNIVERSAL_BUILD
|
||||
# if defined __BIG_ENDIAN__
|
||||
# define WORDS_BIGENDIAN 1
|
||||
# endif
|
||||
#else
|
||||
# ifndef WORDS_BIGENDIAN
|
||||
/* # undef WORDS_BIGENDIAN */
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* Define to empty if `const' does not conform to ANSI C. */
|
||||
/* #undef const */
|
||||
#undef FS_ENCODE
|
||||
#define FS_ENCODE 0
|
||||
#undef HAVE_FLAC
|
||||
#define HAVE_FLAC 0
|
||||
#undef HAVE_OGGZ
|
||||
#define HAVE_OGGZ 1
|
||||
#undef HAVE_SPEEX
|
||||
#define HAVE_SPEEX 0
|
||||
#undef HAVE_VORBIS
|
||||
#define HAVE_VORBIS 1
|
||||
#undef HAVE_VORBISENC
|
||||
#define HAVE_VORBISENC 0
|
||||
#undef DEBUG
|
||||
|
||||
#include "prcpucfg.h"
|
||||
#ifdef IS_BIG_ENDIAN
|
||||
#define WORDS_BIGENDIAN
|
||||
#endif
|
|
@ -1,68 +0,0 @@
|
|||
/*
|
||||
Copyright (C) 2003 Commonwealth Scientific and Industrial Research
|
||||
Organisation (CSIRO) Australia
|
||||
|
||||
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.
|
||||
|
||||
- Neither the name of CSIRO Australia nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
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 ORGANISATION 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 __FISH_SOUND_CONVERT_H__
|
||||
#define __FISH_SOUND_CONVERT_H__
|
||||
|
||||
/* inline functions */
|
||||
|
||||
static inline void
|
||||
_fs_deinterleave (float ** src, float * dest[],
|
||||
long frames, int channels, float mult_factor)
|
||||
{
|
||||
int i, j;
|
||||
float * d, * s = (float *)src;
|
||||
|
||||
for (i = 0; i < frames; i++) {
|
||||
for (j = 0; j < channels; j++) {
|
||||
d = dest[j];
|
||||
d[i] = s[i*channels + j] * mult_factor;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
_fs_interleave (float * src[], float ** dest,
|
||||
long frames, int channels, float mult_factor)
|
||||
{
|
||||
int i, j;
|
||||
float * s, * d = (float *)dest;
|
||||
|
||||
for (i = 0; i < frames; i++) {
|
||||
for (j = 0; j < channels; j++) {
|
||||
s = src[j];
|
||||
d[i*channels + j] = s[i] * mult_factor;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* __FISH_SOUND_CONVERT_H__ */
|
|
@ -1,415 +0,0 @@
|
|||
/*
|
||||
Copyright (C) 2003 Commonwealth Scientific and Industrial Research
|
||||
Organisation (CSIRO) Australia
|
||||
|
||||
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.
|
||||
|
||||
- Neither the name of CSIRO Australia nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
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 ORGANISATION 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 __FISH_SOUND_CONVERT_C_H__
|
||||
#define __FISH_SOUND_CONVERT_C_H__
|
||||
|
||||
#include <string.h>
|
||||
#include <ogg/ogg.h>
|
||||
|
||||
/* inline functions */
|
||||
|
||||
static inline void
|
||||
_fs_deinterleave_s_s (short ** src, short * dest[],
|
||||
long frames, int channels)
|
||||
{
|
||||
int i, j;
|
||||
short * d, * s = (short *)src;
|
||||
|
||||
for (i = 0; i < frames; i++) {
|
||||
for (j = 0; j < channels; j++) {
|
||||
d = dest[j];
|
||||
d[i] = s[i*channels + j];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
_fs_deinterleave_s_i (short ** src, int * dest[], long frames, int channels)
|
||||
{
|
||||
int i, j;
|
||||
short * s = (short *)src;
|
||||
int * d;
|
||||
|
||||
for (i = 0; i < frames; i++) {
|
||||
for (j = 0; j < channels; j++) {
|
||||
d = dest[j];
|
||||
d[i] = (int) s[i*channels + j];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
_fs_deinterleave_s_f (short ** src, float * dest[], long frames, int channels,
|
||||
float mult)
|
||||
{
|
||||
int i, j;
|
||||
short * s = (short *)src;
|
||||
float * d;
|
||||
|
||||
for (i = 0; i < frames; i++) {
|
||||
for (j = 0; j < channels; j++) {
|
||||
d = dest[j];
|
||||
d[i] = ((float) s[i*channels + j]) * mult;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
_fs_deinterleave_s_d (short ** src, double * dest[], long frames, int channels,
|
||||
double mult)
|
||||
{
|
||||
int i, j;
|
||||
short * s = (short *)src;
|
||||
double * d;
|
||||
|
||||
for (i = 0; i < frames; i++) {
|
||||
for (j = 0; j < channels; j++) {
|
||||
d = dest[j];
|
||||
d[i] = ((double) s[i*channels + j]) * mult;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
_fs_deinterleave_f_s (float ** src, short * dest[],
|
||||
long frames, int channels, float mult)
|
||||
{
|
||||
int i, j;
|
||||
float * s = (float *)src;
|
||||
short * d;
|
||||
|
||||
for (i = 0; i < frames; i++) {
|
||||
for (j = 0; j < channels; j++) {
|
||||
d = dest[j];
|
||||
d[i] = (short) (s[i*channels + j] * mult);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
_fs_deinterleave_f_i (float ** src, int * dest[],
|
||||
long frames, int channels, float mult)
|
||||
{
|
||||
int i, j;
|
||||
float * s = (float *)src;
|
||||
int * d;
|
||||
|
||||
for (i = 0; i < frames; i++) {
|
||||
for (j = 0; j < channels; j++) {
|
||||
d = dest[j];
|
||||
d[i] = (int) (s[i*channels + j] * mult);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
_fs_deinterleave_f_f (float ** src, float * dest[],
|
||||
long frames, int channels, float mult)
|
||||
{
|
||||
int i, j;
|
||||
float * s = (float *)src, * d;
|
||||
|
||||
for (i = 0; i < frames; i++) {
|
||||
for (j = 0; j < channels; j++) {
|
||||
d = dest[j];
|
||||
d[i] = s[i*channels + j] * mult;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
_fs_deinterleave_f_d (float ** src, double * dest[],
|
||||
long frames, int channels, double mult)
|
||||
{
|
||||
int i, j;
|
||||
float * s = (float *)src;
|
||||
double * d;
|
||||
|
||||
for (i = 0; i < frames; i++) {
|
||||
for (j = 0; j < channels; j++) {
|
||||
d = dest[j];
|
||||
d[i] = (double) s[i*channels + j] * mult;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
_fs_interleave_f_s (float * src[], short ** dest,
|
||||
long frames, int channels, float mult)
|
||||
{
|
||||
int i, j;
|
||||
float * s;
|
||||
short * d = (short *)dest;
|
||||
|
||||
for (i = 0; i < frames; i++) {
|
||||
for (j = 0; j < channels; j++) {
|
||||
s = src[j];
|
||||
d[i*channels + j] = (short) (s[i] * mult);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
_fs_interleave_s_s (short * src[], short ** dest,
|
||||
long frames, int channels)
|
||||
{
|
||||
int i, j;
|
||||
short * s, * d = (short *)dest;
|
||||
|
||||
for (i = 0; i < frames; i++) {
|
||||
for (j = 0; j < channels; j++) {
|
||||
s = src[j];
|
||||
d[i*channels + j] = s[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
_fs_interleave_s_f (short * src[], float ** dest,
|
||||
long frames, int channels, float mult)
|
||||
{
|
||||
int i, j;
|
||||
short * s;
|
||||
float * d = (float *)dest;
|
||||
|
||||
for (i = 0; i < frames; i++) {
|
||||
for (j = 0; j < channels; j++) {
|
||||
s = src[j];
|
||||
d[i*channels + j] = (float) (s[i] * mult);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline ogg_int32_t CLIP_TO_15(ogg_int32_t x) {
|
||||
int ret=x;
|
||||
ret-= ((x<=32767)-1)&(x-32767);
|
||||
ret-= ((x>=-32768)-1)&(x+32768);
|
||||
return(ret);
|
||||
}
|
||||
|
||||
static inline void
|
||||
_fs_interleave_i_s (ogg_int32_t * src[], short ** dest,
|
||||
long frames, int channels, int shift)
|
||||
{
|
||||
int i, j;
|
||||
ogg_int32_t * s;
|
||||
short * d = (short *)dest;
|
||||
|
||||
for (i = 0; i < frames; i++) {
|
||||
for (j = 0; j < channels; j++) {
|
||||
s = src[j];
|
||||
d[i*channels + j] = (short) CLIP_TO_15(s[i]>>9);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
_fs_interleave_i_f (int * src[], float ** dest,
|
||||
long frames, int channels, float mult)
|
||||
{
|
||||
int i, j;
|
||||
int * s;
|
||||
float * d = (float *)dest;
|
||||
|
||||
for (i = 0; i < frames; i++) {
|
||||
for (j = 0; j < channels; j++) {
|
||||
s = src[j];
|
||||
d[i*channels + j] = (float) (s[i] * mult);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
_fs_interleave_f_f (float * src[], float ** dest,
|
||||
long frames, int channels, float mult)
|
||||
{
|
||||
int i, j;
|
||||
float * s, * d = (float *)dest;
|
||||
|
||||
for (i = 0; i < frames; i++) {
|
||||
for (j = 0; j < channels; j++) {
|
||||
s = src[j];
|
||||
d[i*channels + j] = s[i] * mult;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
_fs_interleave_d_s (double * src[], short ** dest,
|
||||
long frames, int channels, double mult)
|
||||
{
|
||||
int i, j;
|
||||
double * s;
|
||||
short * d = (short *)dest;
|
||||
|
||||
for (i = 0; i < frames; i++) {
|
||||
for (j = 0; j < channels; j++) {
|
||||
s = src[j];
|
||||
d[i*channels + j] = (short) (s[i] * mult);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
_fs_interleave_d_f (double * src[], float ** dest,
|
||||
long frames, int channels, float mult)
|
||||
{
|
||||
int i, j;
|
||||
double * s;
|
||||
float * d = (float *)dest;
|
||||
|
||||
for (i = 0; i < frames; i++) {
|
||||
for (j = 0; j < channels; j++) {
|
||||
s = src[j];
|
||||
d[i*channels + j] = (float) s[i] * mult;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
_fs_convert_s_s (short * src, short * dest, long samples)
|
||||
{
|
||||
memcpy (dest, src, samples * sizeof (short));
|
||||
}
|
||||
|
||||
static inline void
|
||||
_fs_convert_s_i (short * src, int * dest, long samples)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < samples; i++) {
|
||||
dest[i] = (int) src[i];
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
_fs_convert_s_f (short * src, float * dest, long samples, float mult)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < samples; i++) {
|
||||
dest[i] = (float) src[i] * mult;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
_fs_convert_s_d (short * src, double * dest, long samples, double mult)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < samples; i++) {
|
||||
dest[i] = ((double)src[i]) * mult;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
_fs_convert_i_s (int * src, short * dest, long samples)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < samples; i++) {
|
||||
dest[i] = (short) src[i];
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
_fs_convert_i_f (int * src, float * dest, long samples, float mult)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < samples; i++) {
|
||||
dest[i] = (float) src[i] * mult;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
_fs_convert_f_s (float * src, short * dest, long samples, float mult)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < samples; i++) {
|
||||
dest[i] = (short) (src[i] * mult);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
_fs_convert_f_i (float * src, int * dest, long samples, float mult)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < samples; i++) {
|
||||
dest[i] = (int) (src[i] * mult);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
_fs_convert_f_f (float * src, float * dest, long samples, float mult)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < samples; i++) {
|
||||
dest[i] = src[i] * mult;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
_fs_convert_f_d (float * src, double * dest, long samples, double mult)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < samples; i++) {
|
||||
dest[i] = (double)src[i] * mult;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
_fs_convert_d_s (double * src, short * dest, long samples, double mult)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < samples; i++) {
|
||||
dest[i] = (short) (src[i] * mult);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
_fs_convert_d_f (double * src, float * dest, long samples, float mult)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < samples; i++) {
|
||||
dest[i] = (float)src[i] * mult;
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* __FISH_SOUND_CONVERT_C_H__ */
|
|
@ -1,393 +0,0 @@
|
|||
/*
|
||||
Copyright (C) 2003 Commonwealth Scientific and Industrial Research
|
||||
Organisation (CSIRO) Australia
|
||||
|
||||
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.
|
||||
|
||||
- Neither the name of CSIRO Australia nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
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 ORGANISATION 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* David Schleef, ds@schleef.org
|
||||
* January, 2005
|
||||
*/
|
||||
|
||||
#ifndef __FISH_SOUND_CONVERT_OIL_H__
|
||||
#define __FISH_SOUND_CONVERT_OIL_H__
|
||||
|
||||
#include <string.h>
|
||||
#include <ogg/ogg.h>
|
||||
#include <liboil/liboil.h>
|
||||
|
||||
/* inline functions */
|
||||
|
||||
static inline void
|
||||
_fs_deinterleave_s_s (short ** src, short * dest[],
|
||||
long frames, int channels)
|
||||
{
|
||||
int j;
|
||||
short * s = (short *)src;
|
||||
|
||||
#define oil_restride_s16(a,b,c,d,e) oil_conv_u16_s16((uint16_t *)a,b,c,d,e)
|
||||
for (j = 0; j < channels; j++) {
|
||||
oil_restride_s16 (dest[j], sizeof(short), s + j,
|
||||
channels * sizeof(short), frames);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
_fs_deinterleave_s_i (short ** src, int * dest[], long frames, int channels)
|
||||
{
|
||||
int j;
|
||||
short * s = (short *)src;
|
||||
|
||||
for (j = 0; j < channels; j++) {
|
||||
oil_conv_s32_s16 (dest[j], sizeof(int), s + j,
|
||||
channels * sizeof(short), frames);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
_fs_deinterleave_s_f (short ** src, float * dest[], long frames, int channels,
|
||||
float mult)
|
||||
{
|
||||
int j;
|
||||
short * s = (short *)src;
|
||||
|
||||
for (j = 0; j < channels; j++) {
|
||||
oil_conv_f32_s16 (dest[j], sizeof(float), s + j,
|
||||
channels * sizeof(short), frames);
|
||||
oil_scalarmult_f32 (dest[j], sizeof (float), dest[j], sizeof(float),
|
||||
&mult, frames);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
_fs_deinterleave_s_d (short ** src, double * dest[], long frames, int channels,
|
||||
double mult)
|
||||
{
|
||||
int j;
|
||||
short * s = (short *)src;
|
||||
|
||||
for (j = 0; j < channels; j++) {
|
||||
oil_conv_f64_s16 (dest[j], sizeof(double), s + j,
|
||||
channels * sizeof(short), frames);
|
||||
oil_scalarmult_f64 (dest[j], sizeof (double), dest[j], sizeof (double),
|
||||
&mult, frames);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
_fs_deinterleave_f_s (float ** src, short * dest[],
|
||||
long frames, int channels, float mult)
|
||||
{
|
||||
int i, j;
|
||||
float * s = (float *)src;
|
||||
short * d;
|
||||
|
||||
/* FIXME: this needs a temporary buffer for liboil */
|
||||
for (i = 0; i < frames; i++) {
|
||||
for (j = 0; j < channels; j++) {
|
||||
d = dest[j];
|
||||
d[i] = (short) (s[i*channels + j] * mult);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
_fs_deinterleave_f_i (float ** src, int * dest[],
|
||||
long frames, int channels, float mult)
|
||||
{
|
||||
int i, j;
|
||||
float * s = (float *)src;
|
||||
int * d;
|
||||
|
||||
/* FIXME: this needs a temporary buffer for liboil */
|
||||
for (i = 0; i < frames; i++) {
|
||||
for (j = 0; j < channels; j++) {
|
||||
d = dest[j];
|
||||
d[i] = (int) (s[i*channels + j] * mult);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
_fs_deinterleave_f_f (float ** src, float * dest[],
|
||||
long frames, int channels, float mult)
|
||||
{
|
||||
int j;
|
||||
float * s = (float *)src;
|
||||
|
||||
for (j = 0; j < channels; j++) {
|
||||
oil_scalarmult_f32 (dest[j], sizeof(float), s + j,
|
||||
channels * sizeof(float), &mult, frames);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
_fs_deinterleave_f_d (float ** src, double * dest[],
|
||||
long frames, int channels, double mult)
|
||||
{
|
||||
int j;
|
||||
float * s = (float *)src;
|
||||
|
||||
for (j = 0; j < channels; j++) {
|
||||
oil_conv_f64_f32 (dest[j], sizeof(double), s + j,
|
||||
channels * sizeof(float), frames);
|
||||
oil_scalarmult_f64 (dest[j], sizeof(double), dest[j],
|
||||
sizeof(double), &mult, frames);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
_fs_interleave_f_s (float * src[], short ** dest,
|
||||
long frames, int channels, float mult)
|
||||
{
|
||||
int i, j;
|
||||
float * s;
|
||||
short * d = (short *)dest;
|
||||
|
||||
/* FIXME: this needs a temporary buffer for liboil */
|
||||
for (i = 0; i < frames; i++) {
|
||||
for (j = 0; j < channels; j++) {
|
||||
s = src[j];
|
||||
d[i*channels + j] = (short) (s[i] * mult);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
_fs_interleave_s_s (short * src[], short ** dest,
|
||||
long frames, int channels)
|
||||
{
|
||||
int j;
|
||||
short * d = (short *)dest;
|
||||
|
||||
for (j = 0; j < channels; j++) {
|
||||
oil_restride_s16 (d + j, sizeof (short) * channels, src[j],
|
||||
sizeof (short), frames);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
_fs_interleave_s_f (short * src[], float ** dest,
|
||||
long frames, int channels, float mult)
|
||||
{
|
||||
int j;
|
||||
float * d = (float *)dest;
|
||||
|
||||
for (j = 0; j < channels; j++) {
|
||||
oil_conv_f32_s16 (d + j, sizeof (float) * channels, src[j],
|
||||
sizeof (short), frames);
|
||||
}
|
||||
oil_scalarmult_f32 (d, sizeof(float), d, sizeof(float), &mult,
|
||||
channels * frames);
|
||||
}
|
||||
|
||||
static inline ogg_int32_t CLIP_TO_15(ogg_int32_t x) {
|
||||
int ret=x;
|
||||
ret-= ((x<=32767)-1)&(x-32767);
|
||||
ret-= ((x>=-32768)-1)&(x+32768);
|
||||
return(ret);
|
||||
}
|
||||
|
||||
static inline void
|
||||
_fs_interleave_i_s (ogg_int32_t * src[], short ** dest,
|
||||
long frames, int channels, int shift)
|
||||
{
|
||||
int i, j;
|
||||
ogg_int32_t * s;
|
||||
short * d = (short *)dest;
|
||||
|
||||
/* FIXME: shouldn't this use shift? */
|
||||
for (i = 0; i < frames; i++) {
|
||||
for (j = 0; j < channels; j++) {
|
||||
s = src[j];
|
||||
d[i*channels + j] = (short) CLIP_TO_15(s[i]>>9);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
_fs_interleave_i_f (int * src[], float ** dest,
|
||||
long frames, int channels, float mult)
|
||||
{
|
||||
int j;
|
||||
float * d = (float *)dest;
|
||||
|
||||
for (j = 0; j < channels; j++) {
|
||||
oil_conv_f32_s32 (d + j, sizeof (float) * channels, src[j],
|
||||
sizeof (int), frames);
|
||||
}
|
||||
oil_scalarmult_f32 (d, sizeof(float), d, sizeof(float), &mult,
|
||||
channels * frames);
|
||||
}
|
||||
|
||||
static inline void
|
||||
_fs_interleave_f_f (float * src[], float ** dest,
|
||||
long frames, int channels, float mult)
|
||||
{
|
||||
int j;
|
||||
float * d = (float *)dest;
|
||||
|
||||
for (j = 0; j < channels; j++) {
|
||||
oil_scalarmult_f32 (d + j, sizeof (float) * channels, src[j],
|
||||
sizeof (float), &mult, frames);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
_fs_interleave_d_s (double * src[], short ** dest,
|
||||
long frames, int channels, double mult)
|
||||
{
|
||||
int i, j;
|
||||
double * s;
|
||||
short * d = (short *)dest;
|
||||
|
||||
/* FIXME: needs temporary buffer */
|
||||
for (i = 0; i < frames; i++) {
|
||||
for (j = 0; j < channels; j++) {
|
||||
s = src[j];
|
||||
d[i*channels + j] = (short) (s[i] * mult);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
_fs_interleave_d_f (double * src[], float ** dest,
|
||||
long frames, int channels, float mult)
|
||||
{
|
||||
int j;
|
||||
float * d = (float *)dest;
|
||||
|
||||
for (j = 0; j < channels; j++) {
|
||||
oil_conv_f32_f64 (d + j, sizeof (float) * channels, src[j],
|
||||
sizeof (double), frames);
|
||||
}
|
||||
oil_scalarmult_f32 (d, sizeof(float), d, sizeof(float), &mult,
|
||||
channels * frames);
|
||||
}
|
||||
|
||||
static inline void
|
||||
_fs_convert_s_s (short * src, short * dest, long samples)
|
||||
{
|
||||
memcpy (dest, src, samples * sizeof (short));
|
||||
}
|
||||
|
||||
static inline void
|
||||
_fs_convert_s_i (short * src, int * dest, long samples)
|
||||
{
|
||||
oil_conv_s32_s16 (dest, sizeof(int), src, sizeof(short), samples);
|
||||
}
|
||||
|
||||
static inline void
|
||||
_fs_convert_s_f (short * src, float * dest, long samples, float mult)
|
||||
{
|
||||
oil_conv_f32_s16 (dest, sizeof(float), src, sizeof(short), samples);
|
||||
oil_scalarmult_f32 (dest, sizeof(float), dest, sizeof(float), &mult, samples);
|
||||
}
|
||||
|
||||
static inline void
|
||||
_fs_convert_s_d (short * src, double * dest, long samples, double mult)
|
||||
{
|
||||
oil_conv_f64_s16 (dest, sizeof(double), src, sizeof(short), samples);
|
||||
oil_scalarmult_f64 (dest, sizeof(double), dest, sizeof(double), &mult,
|
||||
samples);
|
||||
}
|
||||
|
||||
static inline void
|
||||
_fs_convert_i_s (int * src, short * dest, long samples)
|
||||
{
|
||||
/* FIXME: should this clip? */
|
||||
oil_conv_s16_s32 (dest, sizeof(dest), src, sizeof(int), samples);
|
||||
/* oil_clipconv_s16_s32 (dest, sizeof(dest), src, sizeof(int), samples); */
|
||||
}
|
||||
|
||||
static inline void
|
||||
_fs_convert_i_f (int * src, float * dest, long samples, float mult)
|
||||
{
|
||||
oil_conv_f32_s32 (dest, sizeof(float), src, sizeof(int), samples);
|
||||
oil_scalarmult_f32 (dest, sizeof(float), dest, sizeof(float), &mult, samples);
|
||||
}
|
||||
|
||||
static inline void
|
||||
_fs_convert_f_s (float * src, short * dest, long samples, float mult)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* FIXME: needs temp buffer */
|
||||
for (i = 0; i < samples; i++) {
|
||||
dest[i] = (short) (src[i] * mult);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
_fs_convert_f_i (float * src, int * dest, long samples, float mult)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* FIXME: needs temp buffer */
|
||||
for (i = 0; i < samples; i++) {
|
||||
dest[i] = (int) (src[i] * mult);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
_fs_convert_f_f (float * src, float * dest, long samples, float mult)
|
||||
{
|
||||
oil_scalarmult_f32 (dest, sizeof(float), src, sizeof(float), &mult, samples);
|
||||
}
|
||||
|
||||
static inline void
|
||||
_fs_convert_f_d (float * src, double * dest, long samples, double mult)
|
||||
{
|
||||
oil_conv_f64_f32 (dest, sizeof(double), src, sizeof(float), samples);
|
||||
oil_scalarmult_f64 (dest, sizeof(double), dest, sizeof(double), &mult, samples);
|
||||
}
|
||||
|
||||
static inline void
|
||||
_fs_convert_d_s (double * src, short * dest, long samples, double mult)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* FIXME: needs temp buffer */
|
||||
for (i = 0; i < samples; i++) {
|
||||
dest[i] = (short) (src[i] * mult);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
_fs_convert_d_f (double * src, float * dest, long samples, float mult)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* FIXME: needs temp buffer */
|
||||
for (i = 0; i < samples; i++) {
|
||||
dest[i] = (float)src[i] * mult;
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* __FISH_SOUND_CONVERT_OIL_H__ */
|
|
@ -1,92 +0,0 @@
|
|||
/*
|
||||
* A generic debugging printer.
|
||||
*
|
||||
* Conrad Parker <conrad@metadecks.org>, May 2009
|
||||
*
|
||||
* Usage:
|
||||
*
|
||||
* #define DEBUG_LEVEL 3
|
||||
* #include "debug.h"
|
||||
*
|
||||
* ...
|
||||
* debug_printf (2, "Something went wrong");
|
||||
* ...
|
||||
*
|
||||
* The macro print_debug(level, fmt) prints a formatted debugging message
|
||||
* of level 'level' to stderr. You should set the maximum tolerable debug
|
||||
* level before including debug.h. If it is 0, or if neither DEBUG_LEVEL
|
||||
* nor DEBUG are defined, then the debug_printf() macro is ignored, and
|
||||
* none of this file is included.
|
||||
*/
|
||||
#ifndef __DEBUG_H__
|
||||
#define __DEBUG_H__
|
||||
|
||||
/* MSVC can't handle C99 */
|
||||
#if (defined (_MSCVER) || defined (_MSC_VER))
|
||||
#define debug_printf //
|
||||
#else
|
||||
|
||||
#ifdef DEBUG
|
||||
#ifndef DEBUG_LEVEL
|
||||
#define DEBUG_LEVEL 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if (DEBUG_LEVEL > 0)
|
||||
|
||||
#define DEBUG_MAXLINE 4096
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
/*
|
||||
* debug_print_err (func, line, fmt)
|
||||
*
|
||||
* Print a formatted error message to stderr.
|
||||
*/
|
||||
static void
|
||||
debug_print_err (const char * func, int line, const char * fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
int errno_save;
|
||||
char buf[DEBUG_MAXLINE];
|
||||
int n=0;
|
||||
|
||||
errno_save = errno;
|
||||
|
||||
va_start (ap, fmt);
|
||||
|
||||
if (func) {
|
||||
snprintf (buf+n, DEBUG_MAXLINE-n, "%s():%d: ", func, line);
|
||||
n = strlen (buf);
|
||||
}
|
||||
|
||||
vsnprintf (buf+n, DEBUG_MAXLINE-n, fmt, ap);
|
||||
n = strlen (buf);
|
||||
|
||||
fflush (stdout); /* in case stdout and stderr are the same */
|
||||
fputs (buf, stderr);
|
||||
fputc ('\n', stderr);
|
||||
fflush (NULL);
|
||||
|
||||
va_end (ap);
|
||||
}
|
||||
|
||||
/*
|
||||
* debug_printf (level, fmt)
|
||||
*
|
||||
* Print a formatted debugging message of level 'level' to stderr
|
||||
*/
|
||||
#define debug_printf(x,y...) {if (x <= DEBUG_LEVEL) debug_print_err (__func__, __LINE__, y);}
|
||||
|
||||
#undef MAXLINE
|
||||
|
||||
#else
|
||||
#define debug_printf(x,y...)
|
||||
#endif
|
||||
|
||||
#endif /* non-C99 */
|
||||
|
||||
#endif /* __DEBUG_H__ */
|
|
@ -1,254 +0,0 @@
|
|||
/*
|
||||
Copyright (C) 2003 Commonwealth Scientific and Industrial Research
|
||||
Organisation (CSIRO) Australia
|
||||
|
||||
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.
|
||||
|
||||
- Neither the name of CSIRO Australia nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
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 ORGANISATION 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.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "private.h"
|
||||
|
||||
int
|
||||
fish_sound_identify (unsigned char * buf, long bytes)
|
||||
{
|
||||
if (bytes < 8) return FISH_SOUND_ERR_SHORT_IDENTIFY;
|
||||
|
||||
if (HAVE_VORBIS &&
|
||||
fish_sound_vorbis_identify (buf, bytes) != FISH_SOUND_UNKNOWN)
|
||||
return FISH_SOUND_VORBIS;
|
||||
|
||||
if (HAVE_SPEEX &&
|
||||
fish_sound_speex_identify (buf, bytes) != FISH_SOUND_UNKNOWN)
|
||||
return FISH_SOUND_SPEEX;
|
||||
|
||||
if (fish_sound_flac_identify (buf, bytes) != FISH_SOUND_UNKNOWN)
|
||||
return FISH_SOUND_FLAC;
|
||||
|
||||
return FISH_SOUND_UNKNOWN;
|
||||
}
|
||||
|
||||
int
|
||||
fish_sound_set_format (FishSound * fsound, int format)
|
||||
{
|
||||
if (format == FISH_SOUND_VORBIS) {
|
||||
fsound->codec = fish_sound_vorbis_codec ();
|
||||
} else if (format == FISH_SOUND_SPEEX) {
|
||||
fsound->codec = fish_sound_speex_codec ();
|
||||
} else if (format == FISH_SOUND_FLAC) {
|
||||
fsound->codec = fish_sound_flac_codec ();
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (fsound->codec && fsound->codec->init)
|
||||
if (fsound->codec->init (fsound) == NULL) return -1;
|
||||
|
||||
fsound->info.format = format;
|
||||
|
||||
return format;
|
||||
}
|
||||
|
||||
FishSound *
|
||||
fish_sound_new (int mode, FishSoundInfo * fsinfo)
|
||||
{
|
||||
FishSound * fsound;
|
||||
|
||||
if (!FS_DECODE && mode == FISH_SOUND_DECODE) return NULL;
|
||||
|
||||
if (!FS_ENCODE && mode == FISH_SOUND_ENCODE) return NULL;
|
||||
|
||||
if (mode == FISH_SOUND_ENCODE) {
|
||||
if (fsinfo == NULL) {
|
||||
return NULL;
|
||||
} else {
|
||||
if (!(HAVE_VORBIS && HAVE_VORBISENC)) {
|
||||
if (fsinfo->format == FISH_SOUND_VORBIS) return NULL;
|
||||
}
|
||||
if (!HAVE_SPEEX) {
|
||||
if (fsinfo->format == FISH_SOUND_SPEEX) return NULL;
|
||||
}
|
||||
if (!HAVE_FLAC) {
|
||||
if (fsinfo->format == FISH_SOUND_FLAC) return NULL;
|
||||
}
|
||||
}
|
||||
} else if (mode != FISH_SOUND_DECODE) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fsound = fs_malloc (sizeof (FishSound));
|
||||
if (fsound == NULL) return NULL;
|
||||
|
||||
fsound->mode = mode;
|
||||
fsound->interleave = 0;
|
||||
fsound->frameno = 0;
|
||||
fsound->next_granulepos = -1;
|
||||
fsound->next_eos = 0;
|
||||
fsound->codec = NULL;
|
||||
fsound->codec_data = NULL;
|
||||
fsound->callback.encoded = NULL;
|
||||
fsound->user_data = NULL;
|
||||
|
||||
fish_sound_comments_init (fsound);
|
||||
|
||||
if (mode == FISH_SOUND_DECODE) {
|
||||
fsound->info.samplerate = 0;
|
||||
fsound->info.channels = 0;
|
||||
fsound->info.format = FISH_SOUND_UNKNOWN;
|
||||
} else if (mode == FISH_SOUND_ENCODE) {
|
||||
fsound->info.samplerate = fsinfo->samplerate;
|
||||
fsound->info.channels = fsinfo->channels;
|
||||
fsound->info.format = fsinfo->format;
|
||||
|
||||
if (fish_sound_set_format (fsound, fsinfo->format) == -1) {
|
||||
fs_free (fsound);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return fsound;
|
||||
}
|
||||
|
||||
long
|
||||
fish_sound_flush (FishSound * fsound)
|
||||
{
|
||||
if (fsound == NULL) return -1;
|
||||
|
||||
if (fsound->codec && fsound->codec->flush)
|
||||
return fsound->codec->flush (fsound);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
fish_sound_reset (FishSound * fsound)
|
||||
{
|
||||
if (fsound == NULL) return -1;
|
||||
|
||||
if (fsound->codec && fsound->codec->reset)
|
||||
return fsound->codec->reset (fsound);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
FishSound *
|
||||
fish_sound_delete (FishSound * fsound)
|
||||
{
|
||||
if (fsound == NULL) return NULL;
|
||||
|
||||
if (fsound->codec && fsound->codec->del)
|
||||
fsound->codec->del (fsound);
|
||||
|
||||
fs_free (fsound->codec);
|
||||
|
||||
fish_sound_comments_free (fsound);
|
||||
|
||||
fs_free (fsound);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int
|
||||
fish_sound_command (FishSound * fsound, int command, void * data, int datasize)
|
||||
{
|
||||
FishSoundInfo * fsinfo = (FishSoundInfo *)data;
|
||||
int * pi = (int *)data;
|
||||
|
||||
if (fsound == NULL) return -1;
|
||||
|
||||
switch (command) {
|
||||
case FISH_SOUND_GET_INFO:
|
||||
memcpy (fsinfo, &fsound->info, sizeof (FishSoundInfo));
|
||||
break;
|
||||
case FISH_SOUND_GET_INTERLEAVE:
|
||||
*pi = fsound->interleave;
|
||||
break;
|
||||
case FISH_SOUND_SET_INTERLEAVE:
|
||||
fsound->interleave = (*pi ? 1 : 0);
|
||||
break;
|
||||
default:
|
||||
if (fsound->codec && fsound->codec->command)
|
||||
return fsound->codec->command (fsound, command, data, datasize);
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
fish_sound_get_interleave (FishSound * fsound)
|
||||
{
|
||||
if (fsound == NULL) return -1;
|
||||
|
||||
return fsound->interleave;
|
||||
}
|
||||
|
||||
#ifndef FS_DISABLE_DEPRECATED
|
||||
int
|
||||
fish_sound_set_interleave (FishSound * fsound, int interleave)
|
||||
{
|
||||
if (fsound == NULL) return -1;
|
||||
|
||||
fsound->interleave = (interleave ? 1 : 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
long
|
||||
fish_sound_get_frameno (FishSound * fsound)
|
||||
{
|
||||
if (fsound == NULL) return -1L;
|
||||
|
||||
return fsound->frameno;
|
||||
}
|
||||
|
||||
int
|
||||
fish_sound_set_frameno (FishSound * fsound, long frameno)
|
||||
{
|
||||
if (fsound == NULL) return -1;
|
||||
|
||||
fsound->frameno = frameno;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
fish_sound_prepare_truncation (FishSound * fsound, long next_granulepos,
|
||||
int next_eos)
|
||||
{
|
||||
if (fsound == NULL) return -1;
|
||||
|
||||
fsound->next_granulepos = next_granulepos;
|
||||
fsound->next_eos = next_eos;
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -1,654 +0,0 @@
|
|||
/*
|
||||
Copyright (C) 2003 Commonwealth Scientific and Industrial Research
|
||||
Organisation (CSIRO) Australia
|
||||
|
||||
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.
|
||||
|
||||
- Neither the name of CSIRO Australia nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
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 ORGANISATION 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.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <limits.h> /* ULONG_MAX */
|
||||
#ifndef WIN32
|
||||
#include <strings.h>
|
||||
#endif
|
||||
|
||||
#include "private.h"
|
||||
|
||||
/*#define DEBUG*/
|
||||
#include "debug.h"
|
||||
|
||||
/* Ensure comment vector length can be expressed in 32 bits
|
||||
* including space for the trailing NUL */
|
||||
#define MAX_COMMENT_LENGTH 0xFFFFFFFE
|
||||
#define fs_comment_clamp(c) MIN((c),MAX_COMMENT_LENGTH)
|
||||
|
||||
static size_t
|
||||
fs_comment_len (const char * s)
|
||||
{
|
||||
size_t len;
|
||||
|
||||
if (s == NULL) return 0;
|
||||
|
||||
len = strlen (s);
|
||||
return fs_comment_clamp(len);
|
||||
}
|
||||
|
||||
static char *
|
||||
fs_strdup (const char * s)
|
||||
{
|
||||
char * ret;
|
||||
if (s == NULL) return NULL;
|
||||
ret = fs_malloc (fs_comment_len(s) + 1);
|
||||
if (ret == NULL) return NULL;
|
||||
return strcpy (ret, s);
|
||||
}
|
||||
|
||||
static char *
|
||||
fs_strdup_len (const char * s, size_t len)
|
||||
{
|
||||
char * ret;
|
||||
if (s == NULL) return NULL;
|
||||
if (len == 0) return NULL;
|
||||
len = fs_comment_clamp(len);
|
||||
ret = fs_malloc (len + 1);
|
||||
if (ret == NULL) return NULL;
|
||||
if (strncpy (ret, s, len) == NULL) {
|
||||
fs_free (ret);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ret[len] = '\0';
|
||||
return ret;
|
||||
}
|
||||
|
||||
static char *
|
||||
fs_index_len (const char * s, char c, int len)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; *s && i < len; i++, s++) {
|
||||
if (*s == c) return (char *)s;
|
||||
}
|
||||
|
||||
if (i < len) return (char *)s;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
Comments will be stored in the Vorbis style.
|
||||
It is describled in the "Structure" section of
|
||||
http://www.xiph.org/ogg/vorbis/doc/v-comment.html
|
||||
|
||||
The comment header is decoded as follows:
|
||||
1) [vendor_length] = read an unsigned integer of 32 bits
|
||||
2) [vendor_string] = read a UTF-8 vector as [vendor_length] octets
|
||||
3) [user_comment_list_length] = read an unsigned integer of 32 bits
|
||||
4) iterate [user_comment_list_length] times {
|
||||
5) [length] = read an unsigned integer of 32 bits
|
||||
6) this iteration's user comment = read a UTF-8 vector as [length] octets
|
||||
}
|
||||
7) [framing_bit] = read a single bit as boolean
|
||||
8) if ( [framing_bit] unset or end of packet ) then ERROR
|
||||
9) done.
|
||||
|
||||
If you have troubles, please write to ymnk@jcraft.com.
|
||||
*/
|
||||
|
||||
#define readint(buf, base) (((buf[base+3]<<24)&0xff000000)| \
|
||||
((buf[base+2]<<16)&0xff0000)| \
|
||||
((buf[base+1]<<8)&0xff00)| \
|
||||
(buf[base]&0xff))
|
||||
#define writeint(buf, base, val) do{ buf[base+3]=((val)>>24)&0xff; \
|
||||
buf[base+2]=((val)>>16)&0xff; \
|
||||
buf[base+1]=((val)>>8)&0xff; \
|
||||
buf[base]=(val)&0xff; \
|
||||
}while(0)
|
||||
|
||||
static int
|
||||
fs_comment_validate_byname (const char * name, const char * value)
|
||||
{
|
||||
const char * c;
|
||||
|
||||
if (!name || !value) return 0;
|
||||
|
||||
for (c = name; *c; c++) {
|
||||
if (*c < 0x20 || *c > 0x7D || *c == 0x3D) {
|
||||
debug_printf (1, "XXX char %c in %s invalid", *c, name);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* XXX: we really should validate value as UTF-8 here, but ... */
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static FishSoundComment *
|
||||
fs_comment_new (const char * name, const char * value)
|
||||
{
|
||||
FishSoundComment * comment;
|
||||
|
||||
if (!fs_comment_validate_byname (name, value)) return NULL;
|
||||
/* Ensures that name != NULL, value != NULL, and validates strings */
|
||||
|
||||
comment = fs_malloc (sizeof (FishSoundComment));
|
||||
if (comment == NULL) return NULL;
|
||||
|
||||
comment->name = fs_strdup (name);
|
||||
if (comment->name == NULL) {
|
||||
fs_free (comment);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
comment->value = fs_strdup (value);
|
||||
if (comment->value == NULL) {
|
||||
fs_free (comment->name);
|
||||
fs_free (comment);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return comment;
|
||||
}
|
||||
|
||||
static void
|
||||
fs_comment_free (FishSoundComment * comment)
|
||||
{
|
||||
if (!comment) return;
|
||||
if (comment->name) fs_free (comment->name);
|
||||
if (comment->value) fs_free (comment->value);
|
||||
fs_free (comment);
|
||||
}
|
||||
|
||||
static int
|
||||
fs_comment_cmp (const FishSoundComment * comment1, const FishSoundComment * comment2)
|
||||
{
|
||||
if (comment1 == comment2) return 1;
|
||||
if (!comment1 || !comment2) return 0;
|
||||
|
||||
if (strcasecmp (comment1->name, comment2->name)) return 0;
|
||||
if (strcmp (comment1->value, comment2->value)) return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
fish_sound_comment_set_vendor (FishSound * fsound, const char * vendor_string)
|
||||
{
|
||||
if (fsound == NULL) return FISH_SOUND_ERR_BAD;
|
||||
|
||||
if (fsound->vendor) fs_free (fsound->vendor);
|
||||
|
||||
if ((fsound->vendor = fs_strdup (vendor_string)) == NULL)
|
||||
return FISH_SOUND_ERR_OUT_OF_MEMORY;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Public API */
|
||||
|
||||
const char *
|
||||
fish_sound_comment_get_vendor (FishSound * fsound)
|
||||
{
|
||||
if (fsound == NULL) return NULL;
|
||||
|
||||
return fsound->vendor;
|
||||
}
|
||||
|
||||
const FishSoundComment *
|
||||
fish_sound_comment_first (FishSound * fsound)
|
||||
{
|
||||
if (fsound == NULL) return NULL;
|
||||
|
||||
return fs_vector_nth (fsound->comments, 0);
|
||||
}
|
||||
|
||||
const FishSoundComment *
|
||||
fish_sound_comment_first_byname (FishSound * fsound, char * name)
|
||||
{
|
||||
FishSoundComment * comment;
|
||||
int i;
|
||||
|
||||
if (fsound == NULL) return NULL;
|
||||
|
||||
if (name == NULL) return fs_vector_nth (fsound->comments, 0);
|
||||
|
||||
if (!fs_comment_validate_byname (name, ""))
|
||||
return NULL;
|
||||
|
||||
for (i = 0; i < fs_vector_size (fsound->comments); i++) {
|
||||
comment = (FishSoundComment *) fs_vector_nth (fsound->comments, i);
|
||||
if (comment->name && !strcasecmp (name, comment->name))
|
||||
return comment;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const FishSoundComment *
|
||||
fish_sound_comment_next (FishSound * fsound, const FishSoundComment * comment)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (fsound == NULL || comment == NULL) return NULL;
|
||||
|
||||
i = fs_vector_find_index (fsound->comments, comment);
|
||||
|
||||
return fs_vector_nth (fsound->comments, i+1);
|
||||
}
|
||||
|
||||
const FishSoundComment *
|
||||
fish_sound_comment_next_byname (FishSound * fsound,
|
||||
const FishSoundComment * comment)
|
||||
{
|
||||
FishSoundComment * v_comment;
|
||||
int i;
|
||||
|
||||
if (fsound == NULL || comment == NULL) return NULL;
|
||||
|
||||
i = fs_vector_find_index (fsound->comments, comment);
|
||||
|
||||
for (i++; i < fs_vector_size (fsound->comments); i++) {
|
||||
v_comment = (FishSoundComment *) fs_vector_nth (fsound->comments, i);
|
||||
if (v_comment->name && !strcasecmp (comment->name, v_comment->name))
|
||||
return v_comment;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#define _fs_comment_add(f,c) fs_vector_insert ((f)->comments, (c))
|
||||
|
||||
int
|
||||
fish_sound_comment_add (FishSound * fsound, FishSoundComment * comment)
|
||||
{
|
||||
#if FS_ENCODE
|
||||
FishSoundComment * new_comment;
|
||||
#endif
|
||||
|
||||
if (fsound == NULL) return FISH_SOUND_ERR_BAD;
|
||||
|
||||
if (fsound->mode != FISH_SOUND_ENCODE)
|
||||
return FISH_SOUND_ERR_INVALID;
|
||||
|
||||
#if FS_ENCODE
|
||||
if (!fs_comment_validate_byname (comment->name, comment->value))
|
||||
return FISH_SOUND_ERR_COMMENT_INVALID;
|
||||
|
||||
if ((new_comment = fs_comment_new (comment->name, comment->value)) == NULL)
|
||||
return FISH_SOUND_ERR_OUT_OF_MEMORY;
|
||||
|
||||
if (_fs_comment_add (fsound, new_comment) == NULL)
|
||||
return FISH_SOUND_ERR_OUT_OF_MEMORY;
|
||||
|
||||
return FISH_SOUND_OK;
|
||||
#else
|
||||
return FISH_SOUND_ERR_DISABLED;
|
||||
#endif
|
||||
}
|
||||
|
||||
int
|
||||
fish_sound_comment_add_byname (FishSound * fsound, const char * name,
|
||||
const char * value)
|
||||
{
|
||||
#if FS_ENCODE
|
||||
FishSoundComment * comment;
|
||||
#endif
|
||||
|
||||
if (fsound == NULL) return FISH_SOUND_ERR_BAD;
|
||||
|
||||
if (fsound->mode != FISH_SOUND_ENCODE)
|
||||
return FISH_SOUND_ERR_INVALID;
|
||||
|
||||
#if FS_ENCODE
|
||||
if (!fs_comment_validate_byname (name, value))
|
||||
return FISH_SOUND_ERR_COMMENT_INVALID;
|
||||
|
||||
if ((comment = fs_comment_new (name, value)) == NULL)
|
||||
return FISH_SOUND_ERR_OUT_OF_MEMORY;
|
||||
|
||||
if (_fs_comment_add (fsound, comment) == NULL)
|
||||
return FISH_SOUND_ERR_OUT_OF_MEMORY;
|
||||
|
||||
return FISH_SOUND_OK;
|
||||
|
||||
return 0;
|
||||
|
||||
#else
|
||||
return FISH_SOUND_ERR_DISABLED;
|
||||
#endif
|
||||
}
|
||||
|
||||
int
|
||||
fish_sound_comment_remove (FishSound * fsound, FishSoundComment * comment)
|
||||
{
|
||||
#if FS_ENCODE
|
||||
FishSoundComment * v_comment;
|
||||
#endif
|
||||
|
||||
if (fsound == NULL) return FISH_SOUND_ERR_BAD;
|
||||
|
||||
if (fsound->mode != FISH_SOUND_ENCODE)
|
||||
return FISH_SOUND_ERR_INVALID;
|
||||
|
||||
#if FS_ENCODE
|
||||
|
||||
v_comment = fs_vector_find (fsound->comments, comment);
|
||||
|
||||
if (v_comment == NULL) return 0;
|
||||
|
||||
fs_vector_remove (fsound->comments, v_comment);
|
||||
fs_comment_free (v_comment);
|
||||
|
||||
return 1;
|
||||
|
||||
#else
|
||||
return FISH_SOUND_ERR_DISABLED;
|
||||
#endif
|
||||
}
|
||||
|
||||
int
|
||||
fish_sound_comment_remove_byname (FishSound * fsound, char * name)
|
||||
{
|
||||
#if FS_ENCODE
|
||||
FishSoundComment * comment;
|
||||
int i;
|
||||
#endif
|
||||
int ret = 0;
|
||||
|
||||
if (fsound == NULL) return FISH_SOUND_ERR_BAD;
|
||||
|
||||
if (fsound->mode != FISH_SOUND_ENCODE)
|
||||
return FISH_SOUND_ERR_INVALID;
|
||||
|
||||
#if FS_ENCODE
|
||||
for (i = 0; i < fs_vector_size (fsound->comments); i++) {
|
||||
comment = (FishSoundComment *) fs_vector_nth (fsound->comments, i);
|
||||
if (!strcasecmp (name, comment->name)) {
|
||||
fish_sound_comment_remove (fsound, comment);
|
||||
i--;
|
||||
ret++;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
#else
|
||||
return FISH_SOUND_ERR_DISABLED;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Internal API */
|
||||
int
|
||||
fish_sound_comments_init (FishSound * fsound)
|
||||
{
|
||||
fsound->vendor = NULL;
|
||||
fsound->comments = fs_vector_new ((FishSoundCmpFunc) fs_comment_cmp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
fish_sound_comments_free (FishSound * fsound)
|
||||
{
|
||||
fs_vector_foreach (fsound->comments, (FishSoundFunc)fs_comment_free);
|
||||
fs_vector_delete (fsound->comments);
|
||||
fsound->comments = NULL;
|
||||
|
||||
if (fsound->vendor) fs_free (fsound->vendor);
|
||||
fsound->vendor = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
fish_sound_comments_decode (FishSound * fsound, unsigned char * comments,
|
||||
long length)
|
||||
{
|
||||
char *c= (char *)comments;
|
||||
int i, nb_fields, n;
|
||||
size_t len;
|
||||
char *end;
|
||||
char * name, * value, * nvalue = NULL;
|
||||
FishSoundComment * comment;
|
||||
|
||||
if (length<8)
|
||||
return -1;
|
||||
|
||||
end = c+length;
|
||||
len=readint(c, 0);
|
||||
|
||||
c+=4;
|
||||
if (len > (unsigned long) length - 4) return -1;
|
||||
|
||||
/* Vendor */
|
||||
if (len > 0) {
|
||||
if ((nvalue = fs_strdup_len (c, len)) == NULL)
|
||||
return FISH_SOUND_ERR_OUT_OF_MEMORY;
|
||||
if (fish_sound_comment_set_vendor (fsound, nvalue) == FISH_SOUND_ERR_OUT_OF_MEMORY) {
|
||||
fs_free (nvalue);
|
||||
return FISH_SOUND_ERR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
fs_free (nvalue);
|
||||
}
|
||||
#ifdef DEBUG
|
||||
fwrite(c, 1, len, stderr); fputc ('\n', stderr);
|
||||
#endif
|
||||
c+=len;
|
||||
|
||||
if (c+4>end) return -1;
|
||||
|
||||
/* This value gets checked effectively by the 'for' condition
|
||||
and the checks within the loop for c running off the end. */
|
||||
nb_fields=readint(c, 0);
|
||||
debug_printf (1, "%d comments", nb_fields);
|
||||
|
||||
c+=4;
|
||||
for (i=0;i<nb_fields;i++)
|
||||
{
|
||||
if (c+4>end) return -1;
|
||||
|
||||
len=readint(c, 0);
|
||||
debug_printf (1, "[%d] len %d\n", i, len);
|
||||
|
||||
c+=4;
|
||||
if (len > (unsigned long) (end-c)) return -1;
|
||||
|
||||
name = c;
|
||||
value = fs_index_len (c, '=', len);
|
||||
n = 0;
|
||||
if (value) {
|
||||
*value = '\0';
|
||||
value++;
|
||||
n = c+len - value;
|
||||
|
||||
}
|
||||
if (n) {
|
||||
if ((nvalue = fs_strdup_len (value, n)) == NULL)
|
||||
return FISH_SOUND_ERR_OUT_OF_MEMORY;
|
||||
|
||||
debug_printf (1, "%s -> %s (length %d)", name, nvalue, n);
|
||||
|
||||
if ((comment = fs_comment_new (name, nvalue)) == NULL) {
|
||||
fs_free (nvalue);
|
||||
return FISH_SOUND_ERR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
if (_fs_comment_add (fsound, comment) == NULL) {
|
||||
fs_free (nvalue);
|
||||
return FISH_SOUND_ERR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
fs_free (nvalue);
|
||||
} else if (len > 0) {
|
||||
debug_printf (1, "[%d] %s (no value)", i, name, len);
|
||||
|
||||
if ((nvalue = fs_strdup_len (name, len)) == NULL)
|
||||
return FISH_SOUND_ERR_OUT_OF_MEMORY;
|
||||
|
||||
if ((comment = fs_comment_new (nvalue, "")) == NULL) {
|
||||
fs_free (nvalue);
|
||||
return FISH_SOUND_ERR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
if (_fs_comment_add (fsound, comment) == NULL) {
|
||||
fs_free (nvalue);
|
||||
return FISH_SOUND_ERR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
fs_free (nvalue);
|
||||
}
|
||||
|
||||
c+=len;
|
||||
}
|
||||
|
||||
debug_printf (1, "OUT");
|
||||
|
||||
return FISH_SOUND_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* Pre-condition: at least one of accum, delta are non-zero,
|
||||
* ie. don't call accum_length (0, 0);
|
||||
* \retval 0 Failure: integer overflow
|
||||
*/
|
||||
static unsigned long
|
||||
accum_length (unsigned long * accum, unsigned long delta)
|
||||
{
|
||||
/* Pre-condition: don't call accum_length (0, 0) */
|
||||
if (*accum == 0 && delta == 0)
|
||||
return 0;
|
||||
|
||||
/* Check for integer overflow */
|
||||
if (delta > ULONG_MAX - (*accum))
|
||||
return 0;
|
||||
|
||||
*accum += delta;
|
||||
|
||||
return *accum;
|
||||
}
|
||||
|
||||
long
|
||||
fish_sound_comments_encode (FishSound * fsound, unsigned char * buf,
|
||||
long length)
|
||||
{
|
||||
char * c = (char *)buf;
|
||||
const FishSoundComment * comment;
|
||||
int nb_fields = 0, vendor_length = 0;
|
||||
unsigned long actual_length = 0, remaining = length, field_length;
|
||||
|
||||
/* Vendor string */
|
||||
if (fsound->vendor)
|
||||
vendor_length = fs_comment_len (fsound->vendor);
|
||||
if (accum_length (&actual_length, 4 + vendor_length) == 0)
|
||||
return 0;
|
||||
|
||||
/* user comment list length */
|
||||
if (accum_length (&actual_length, 4) == 0)
|
||||
return 0;
|
||||
|
||||
for (comment = fish_sound_comment_first (fsound); comment;
|
||||
comment = fish_sound_comment_next (fsound, comment)) {
|
||||
/* [size]"name" */
|
||||
if (accum_length (&actual_length, 4 + fs_comment_len (comment->name)) == 0)
|
||||
return 0;
|
||||
if (comment->value) {
|
||||
/* "=value" */
|
||||
if (accum_length (&actual_length, 1 + fs_comment_len (comment->value)) == 0)
|
||||
return 0;
|
||||
}
|
||||
|
||||
debug_printf (1, "%s = %s", comment->name, comment->value);
|
||||
|
||||
nb_fields++;
|
||||
}
|
||||
|
||||
/* framing bit */
|
||||
if (accum_length (&actual_length, 1) == 0)
|
||||
return 0;
|
||||
|
||||
/* NB. actual_length is not modified from here onwards */
|
||||
|
||||
if (buf == NULL) return actual_length;
|
||||
|
||||
remaining -= 4;
|
||||
if (remaining <= 0) return actual_length;
|
||||
writeint (c, 0, vendor_length);
|
||||
c += 4;
|
||||
|
||||
if (fsound->vendor) {
|
||||
field_length = fs_comment_len (fsound->vendor);
|
||||
memcpy (c, fsound->vendor, MIN (field_length, remaining));
|
||||
c += field_length; remaining -= field_length;
|
||||
if (remaining <= 0) return actual_length;
|
||||
}
|
||||
|
||||
remaining -= 4;
|
||||
if (remaining <= 0) return actual_length;
|
||||
writeint (c, 0, nb_fields);
|
||||
c += 4;
|
||||
|
||||
for (comment = fish_sound_comment_first (fsound); comment;
|
||||
comment = fish_sound_comment_next (fsound, comment)) {
|
||||
|
||||
field_length = fs_comment_len (comment->name); /* [size]"name" */
|
||||
if (comment->value)
|
||||
field_length += 1 + fs_comment_len (comment->value); /* "=value" */
|
||||
|
||||
remaining -= 4;
|
||||
if (remaining <= 0) return actual_length;
|
||||
writeint (c, 0, field_length);
|
||||
c += 4;
|
||||
|
||||
field_length = fs_comment_len (comment->name);
|
||||
memcpy (c, comment->name, MIN (field_length, remaining));
|
||||
c += field_length; remaining -= field_length;
|
||||
if (remaining <= 0) return actual_length;
|
||||
|
||||
if (comment->value) {
|
||||
remaining --;
|
||||
if (remaining <= 0) return actual_length;
|
||||
*c = '=';
|
||||
c++;
|
||||
|
||||
field_length = fs_comment_len (comment->value);
|
||||
memcpy (c, comment->value, MIN (field_length, remaining));
|
||||
c += field_length; remaining -= field_length;
|
||||
if (remaining <= 0) return actual_length;
|
||||
}
|
||||
}
|
||||
|
||||
if (remaining <= 0) return actual_length;
|
||||
*c = 0x01;
|
||||
|
||||
return actual_length;
|
||||
}
|
|
@ -1,136 +0,0 @@
|
|||
/*
|
||||
Copyright (C) 2003 Commonwealth Scientific and Industrial Research
|
||||
Organisation (CSIRO) Australia
|
||||
|
||||
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.
|
||||
|
||||
- Neither the name of CSIRO Australia nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
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 ORGANISATION 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.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "private.h"
|
||||
|
||||
static int
|
||||
fs_decode_update (FishSound * fsound, int interleave)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (fsound->codec && fsound->codec->update)
|
||||
ret = fsound->codec->update (fsound, interleave);
|
||||
|
||||
if (ret >= 0) {
|
||||
fsound->interleave = interleave;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int fish_sound_set_decoded_float (FishSound * fsound,
|
||||
FishSoundDecoded_Float decoded,
|
||||
void * user_data)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (fsound == NULL) return FISH_SOUND_ERR_BAD;
|
||||
|
||||
#if FS_DECODE
|
||||
ret = fs_decode_update (fsound, 0);
|
||||
|
||||
if (ret >= 0) {
|
||||
fsound->callback.decoded_float = decoded;
|
||||
fsound->user_data = user_data;
|
||||
}
|
||||
#else
|
||||
return FISH_SOUND_ERR_DISABLED;
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int fish_sound_set_decoded_float_ilv (FishSound * fsound,
|
||||
FishSoundDecoded_FloatIlv decoded,
|
||||
void * user_data)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (fsound == NULL) return FISH_SOUND_ERR_BAD;
|
||||
|
||||
#if FS_DECODE
|
||||
ret = fs_decode_update (fsound, 1);
|
||||
|
||||
if (ret >= 0) {
|
||||
fsound->callback.decoded_float_ilv = decoded;
|
||||
fsound->user_data = user_data;
|
||||
}
|
||||
#else
|
||||
return FISH_SOUND_ERR_DISABLED;
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
long
|
||||
fish_sound_decode (FishSound * fsound, unsigned char * buf, long bytes)
|
||||
{
|
||||
int format;
|
||||
|
||||
if (fsound == NULL) return FISH_SOUND_ERR_BAD;
|
||||
|
||||
#if FS_DECODE
|
||||
if (fsound->info.format == FISH_SOUND_UNKNOWN) {
|
||||
format = fish_sound_identify (buf, bytes);
|
||||
if (format == FISH_SOUND_UNKNOWN) return -1;
|
||||
|
||||
fish_sound_set_format (fsound, format);
|
||||
}
|
||||
|
||||
/*printf ("format: %s\n", fsound->codec->format->name);*/
|
||||
|
||||
if (fsound->codec && fsound->codec->decode)
|
||||
return fsound->codec->decode (fsound, buf, bytes);
|
||||
#else
|
||||
return FISH_SOUND_ERR_DISABLED;
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* DEPRECATED */
|
||||
int fish_sound_set_decoded_callback (FishSound * fsound,
|
||||
FishSoundDecoded_Float decoded,
|
||||
void * user_data)
|
||||
{
|
||||
if (fsound == NULL) return -1;
|
||||
|
||||
return fsound->interleave ?
|
||||
fish_sound_set_decoded_float_ilv (fsound, decoded, user_data) :
|
||||
fish_sound_set_decoded_float (fsound, decoded, user_data);
|
||||
}
|
|
@ -1,106 +0,0 @@
|
|||
/*
|
||||
Copyright (C) 2003 Commonwealth Scientific and Industrial Research
|
||||
Organisation (CSIRO) Australia
|
||||
|
||||
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.
|
||||
|
||||
- Neither the name of CSIRO Australia nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
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 ORGANISATION 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.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "private.h"
|
||||
|
||||
int
|
||||
fish_sound_set_encoded_callback (FishSound * fsound,
|
||||
FishSoundEncoded encoded,
|
||||
void * user_data)
|
||||
{
|
||||
if (fsound == NULL) return -1;
|
||||
|
||||
#if FS_ENCODE
|
||||
fsound->callback.encoded = (void *)encoded;
|
||||
fsound->user_data = user_data;
|
||||
#else
|
||||
return FISH_SOUND_ERR_DISABLED;
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
long fish_sound_encode_float (FishSound * fsound, float * pcm[], long frames)
|
||||
{
|
||||
if (fsound == NULL) return -1;
|
||||
|
||||
#if FS_ENCODE
|
||||
if (fsound->codec && fsound->codec->encode_f)
|
||||
return fsound->codec->encode_f (fsound, pcm, frames);
|
||||
#else
|
||||
return FISH_SOUND_ERR_DISABLED;
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
long fish_sound_encode_float_ilv (FishSound * fsound, float ** pcm,
|
||||
long frames)
|
||||
{
|
||||
if (fsound == NULL) return -1;
|
||||
|
||||
#if FS_ENCODE
|
||||
if (fsound->codec && fsound->codec->encode_f_ilv)
|
||||
return fsound->codec->encode_f_ilv (fsound, pcm, frames);
|
||||
#else
|
||||
return FISH_SOUND_ERR_DISABLED;
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifndef FS_DISABLE_DEPRECATED
|
||||
long
|
||||
fish_sound_encode (FishSound * fsound, float ** pcm, long frames)
|
||||
{
|
||||
if (fsound == NULL) return -1;
|
||||
|
||||
#if FS_ENCODE
|
||||
if (fsound->interleave) {
|
||||
if (fsound->codec && fsound->codec->encode_f_ilv)
|
||||
return fsound->codec->encode_f_ilv (fsound, pcm, frames);
|
||||
} else {
|
||||
if (fsound->codec && fsound->codec->encode_f)
|
||||
return fsound->codec->encode_f (fsound, pcm, frames);
|
||||
}
|
||||
#else
|
||||
return FISH_SOUND_ERR_DISABLED;
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* DEPRECATED */
|
|
@ -1,851 +0,0 @@
|
|||
/*
|
||||
Copyright (C) 2007 Annodex Association
|
||||
|
||||
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.
|
||||
|
||||
- Neither the name of the Annodex Association nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
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 ASSOCIATION 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.
|
||||
*/
|
||||
|
||||
/* Original patches by Tobias Gehrig, 2005
|
||||
* http://www.annodex.net/software/libfishsound/libfishsound-flac/
|
||||
*
|
||||
* The Ogg FLAC mapping is documented in:
|
||||
* http://flac.sourceforge.net/ogg_mapping.html
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "private.h"
|
||||
#include "convert.h"
|
||||
|
||||
#define DEBUG_VERBOSE 2
|
||||
/* #define DEBUG */
|
||||
/* #define DEBUG_LEVEL DEBUG_VERBOSE */
|
||||
#include "debug.h"
|
||||
|
||||
#if HAVE_FLAC
|
||||
|
||||
#include "FLAC/all.h"
|
||||
|
||||
#define BITS_PER_SAMPLE 24
|
||||
|
||||
typedef struct _FishSoundFlacInfo {
|
||||
FLAC__StreamDecoder *fsd;
|
||||
FLAC__StreamEncoder *fse;
|
||||
unsigned char * buffer;
|
||||
char header;
|
||||
long bufferlength;
|
||||
unsigned long packetno;
|
||||
struct {
|
||||
unsigned char major, minor;
|
||||
} version;
|
||||
unsigned short header_packets;
|
||||
void * ipcm;
|
||||
#if FS_DECODE
|
||||
float * pcm_out[8]; /* non-interleaved pcm, output (decode only);
|
||||
* FLAC does max 8 channels */
|
||||
#endif
|
||||
#if FS_ENCODE
|
||||
FLAC__StreamMetadata * enc_vc_metadata; /* FLAC metadata structure for
|
||||
* vorbiscomments (encode only) */
|
||||
#endif
|
||||
} FishSoundFlacInfo;
|
||||
|
||||
int
|
||||
fish_sound_flac_identify (unsigned char * buf, long bytes)
|
||||
{
|
||||
if (bytes < 8) return FISH_SOUND_UNKNOWN;
|
||||
if (buf[0] != 0x7f) return FISH_SOUND_UNKNOWN;
|
||||
if (!strncmp ((char *)buf+1, "FLAC", 4)) {
|
||||
debug_printf(1, "flac found");
|
||||
/* if only a short buffer was passed, do a weak identify */
|
||||
if (bytes == 8) return FISH_SOUND_FLAC;
|
||||
|
||||
/* otherwise, look for the fLaC header preceding STREAMINFO */
|
||||
if (!strncmp ((char *)buf+9, "fLaC", 4)) {
|
||||
return FISH_SOUND_FLAC;
|
||||
}
|
||||
}
|
||||
|
||||
return FISH_SOUND_UNKNOWN;
|
||||
}
|
||||
|
||||
static int
|
||||
fs_flac_command (FishSound * fsound, int command, void * data, int datasize)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if FS_DECODE
|
||||
static FLAC__StreamDecoderReadStatus
|
||||
fs_flac_read_callback(const FLAC__StreamDecoder *decoder,
|
||||
FLAC__byte buffer[], unsigned *bytes,
|
||||
void *client_data)
|
||||
{
|
||||
FishSound* fsound = (FishSound*)client_data;
|
||||
FishSoundFlacInfo* fi = (FishSoundFlacInfo *)fsound->codec_data;
|
||||
debug_printf(DEBUG_VERBOSE, "fs_flac_read_callback: IN");
|
||||
if (fi->bufferlength > *bytes) {
|
||||
debug_printf(1, "too much data");
|
||||
return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
|
||||
} else if (fi->bufferlength < 1) {
|
||||
debug_printf(1, "no data, %ld",fi->bufferlength);
|
||||
return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM;
|
||||
}
|
||||
|
||||
memcpy(buffer, fi->buffer, fi->bufferlength);
|
||||
*bytes = fi->bufferlength;
|
||||
fi->bufferlength = 0;
|
||||
return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
|
||||
}
|
||||
|
||||
static FLAC__StreamDecoderWriteStatus
|
||||
fs_flac_write_callback(const FLAC__StreamDecoder *decoder,
|
||||
const FLAC__Frame *frame,
|
||||
const FLAC__int32 * const buffer[],
|
||||
void *client_data)
|
||||
{
|
||||
FishSound* fsound = (FishSound*)client_data;
|
||||
FishSoundFlacInfo* fi = (FishSoundFlacInfo *)fsound->codec_data;
|
||||
int i, j, channels, blocksize, offset;
|
||||
float * ipcm;
|
||||
|
||||
channels = frame->header.channels;
|
||||
blocksize = frame->header.blocksize;
|
||||
|
||||
debug_printf(DEBUG_VERBOSE, "IN, blocksize %d", blocksize);
|
||||
|
||||
fsound->frameno += blocksize;
|
||||
|
||||
if (fsound->callback.decoded_float) {
|
||||
float norm = 1.0 / ((1 << (frame->header.bits_per_sample - 1)));
|
||||
|
||||
if (fsound->interleave) {
|
||||
FishSoundDecoded_FloatIlv dfi;
|
||||
float* retpcm;
|
||||
|
||||
if ((ipcm = realloc(fi->ipcm, sizeof(float) * channels * blocksize)) == NULL)
|
||||
return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
|
||||
|
||||
fi->ipcm = ipcm;
|
||||
retpcm = (float*) fi->ipcm;
|
||||
for (i = 0; i < blocksize; i++) {
|
||||
offset = i * channels;
|
||||
for (j = 0; j < channels; j++)
|
||||
retpcm[offset + j] = buffer[j][i] * norm;
|
||||
}
|
||||
dfi = (FishSoundDecoded_FloatIlv)fsound->callback.decoded_float_ilv;
|
||||
dfi (fsound, (float **)retpcm, blocksize, fsound->user_data);
|
||||
} else {
|
||||
FishSoundDecoded_Float df;
|
||||
FLAC__int32 * s = (FLAC__int32 *)buffer; /* de-interleave source */
|
||||
float *d; /* de-interleave dest */
|
||||
|
||||
for (j = 0; j < channels; j++) {
|
||||
if ((ipcm = realloc(fi->pcm_out[j], sizeof(float) * blocksize)) == NULL)
|
||||
return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
|
||||
fi->pcm_out[j] = ipcm;
|
||||
}
|
||||
for (i = 0; i < blocksize; i++)
|
||||
for (j = 0; j < channels; j++) {
|
||||
d = fi->pcm_out[j];
|
||||
d[i] = s[i*channels + j] * norm;
|
||||
}
|
||||
df = (FishSoundDecoded_Float)fsound->callback.decoded_float;
|
||||
df (fsound, fi->pcm_out, blocksize, fsound->user_data);
|
||||
}
|
||||
}
|
||||
return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
|
||||
}
|
||||
|
||||
static void
|
||||
fs_flac_meta_callback(const FLAC__StreamDecoder *decoder,
|
||||
const FLAC__StreamMetadata *metadata,
|
||||
void *client_data)
|
||||
{
|
||||
FishSound* fsound = (FishSound*)client_data;
|
||||
/* FishSoundFlacInfo* fi = (FishSoundFlacInfo *)fsound->codec_data; */
|
||||
debug_printf(1, "IN");
|
||||
|
||||
switch (metadata->type) {
|
||||
case FLAC__METADATA_TYPE_STREAMINFO:
|
||||
debug_printf(1, "channels %d, samplerate %d",
|
||||
metadata->data.stream_info.channels,
|
||||
metadata->data.stream_info.sample_rate);
|
||||
fsound->info.channels = metadata->data.stream_info.channels;
|
||||
fsound->info.samplerate = metadata->data.stream_info.sample_rate;
|
||||
break;
|
||||
default:
|
||||
debug_printf(1, "not yet implemented type");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
fs_flac_error_callback(const FLAC__StreamDecoder *decoder,
|
||||
FLAC__StreamDecoderErrorStatus status,
|
||||
void *client_data)
|
||||
{
|
||||
debug_printf(1, "IN");
|
||||
fprintf(stderr, "FLAC ERROR: %s\n", FLAC__StreamDecoderErrorStatusString[status]);
|
||||
}
|
||||
#endif
|
||||
#if FS_DECODE
|
||||
static void*
|
||||
fs_flac_decode_header (FishSound * fsound, unsigned char *buf, long bytes)
|
||||
{
|
||||
FishSoundFlacInfo *fi = fsound->codec_data;
|
||||
|
||||
if (bytes < 9) return NULL;
|
||||
if (buf[0] != 0x7f) return NULL;
|
||||
if (strncmp((char *)buf+1, "FLAC", 4) != 0) return NULL;
|
||||
fi->version.major = buf[5];
|
||||
fi->version.minor = buf[6];
|
||||
debug_printf(1, "Flac Ogg Mapping Version: %d.%d",
|
||||
fi->version.major, fi->version.minor);
|
||||
fi->header_packets = buf[7] << 8 | buf[8];
|
||||
debug_printf(1, "Number of Header packets: %d", fi->header_packets);
|
||||
|
||||
if ((fi->fsd = FLAC__stream_decoder_new()) == NULL) {
|
||||
debug_printf (1, "unable to create new stream_decoder");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#if defined (HAVE_FLAC_1_1_2)
|
||||
FLAC__stream_decoder_set_read_callback(fi->fsd, fs_flac_read_callback);
|
||||
FLAC__stream_decoder_set_write_callback(fi->fsd, fs_flac_write_callback);
|
||||
FLAC__stream_decoder_set_metadata_callback(fi->fsd, fs_flac_meta_callback);
|
||||
FLAC__stream_decoder_set_error_callback(fi->fsd, fs_flac_error_callback);
|
||||
FLAC__stream_decoder_set_client_data(fi->fsd, fsound);
|
||||
|
||||
if (FLAC__stream_decoder_init(fi->fsd) != FLAC__STREAM_DECODER_SEARCH_FOR_METADATA)
|
||||
return NULL;
|
||||
#elif defined (HAVE_FLAC_1_1_3)
|
||||
if (FLAC__stream_decoder_init_stream
|
||||
(fi->fsd,
|
||||
fs_flac_read_callback,
|
||||
NULL, /* seek callback */
|
||||
NULL, /* tell callback */
|
||||
NULL, /* length callback */
|
||||
NULL, /* EOF callback */
|
||||
fs_flac_write_callback,
|
||||
fs_flac_meta_callback,
|
||||
fs_flac_error_callback,
|
||||
fsound
|
||||
) != FLAC__STREAM_DECODER_SEARCH_FOR_METADATA)
|
||||
return NULL;
|
||||
#endif
|
||||
|
||||
return fi->fsd;
|
||||
}
|
||||
|
||||
static long
|
||||
fs_flac_decode (FishSound * fsound, unsigned char * buf, long bytes)
|
||||
{
|
||||
FishSoundFlacInfo *fi = fsound->codec_data;
|
||||
|
||||
debug_printf(DEBUG_VERBOSE, "IN, fi->packetno = %ld", fi->packetno);
|
||||
|
||||
if (fi->packetno == 0) {
|
||||
if (fs_flac_decode_header (fsound, buf, bytes) == NULL) {
|
||||
debug_printf(1, "Error reading header");
|
||||
return -1;
|
||||
}
|
||||
if ((fi->buffer = fs_malloc(sizeof(unsigned char)*bytes)) == NULL)
|
||||
return FISH_SOUND_ERR_OUT_OF_MEMORY;
|
||||
|
||||
memcpy(fi->buffer, buf+9, bytes-9);
|
||||
fi->bufferlength = bytes-9;
|
||||
}
|
||||
else if (fi->packetno <= fi->header_packets){
|
||||
unsigned char* tmp;
|
||||
debug_printf(1, "handling header (fi->header_packets = %d)",
|
||||
fi->header_packets);
|
||||
|
||||
#if 0
|
||||
if (fi->packetno == 1) fish_sound_comments_decode (fsound, buf, bytes);
|
||||
#endif
|
||||
|
||||
if ((buf[0] & 0x7) == 4) {
|
||||
int len = (buf[1]<<16) + (buf[2]<<8) + buf[3];
|
||||
debug_printf (1, "got vorbiscomments len %d", len);
|
||||
|
||||
if (fish_sound_comments_decode (fsound, buf+4, len) == FISH_SOUND_ERR_OUT_OF_MEMORY) {
|
||||
fi->packetno++;
|
||||
return FISH_SOUND_ERR_OUT_OF_MEMORY;
|
||||
}
|
||||
}
|
||||
|
||||
if ((tmp = fs_malloc(sizeof(unsigned char)*(fi->bufferlength+bytes))) == NULL)
|
||||
return FISH_SOUND_ERR_OUT_OF_MEMORY;
|
||||
|
||||
memcpy(tmp, fi->buffer, fi->bufferlength);
|
||||
memcpy(tmp+fi->bufferlength, buf, bytes);
|
||||
fi->bufferlength += bytes;
|
||||
fs_free(fi->buffer);
|
||||
fi->buffer = tmp;
|
||||
if (fi->packetno == fi->header_packets) {
|
||||
if (FLAC__stream_decoder_process_until_end_of_metadata(fi->fsd) == false) {
|
||||
goto dec_err;
|
||||
}
|
||||
fs_free(fi->buffer);
|
||||
}
|
||||
} else {
|
||||
fi->buffer = buf;
|
||||
fi->bufferlength = bytes;
|
||||
if (FLAC__stream_decoder_process_single(fi->fsd) == false) {
|
||||
goto dec_err;
|
||||
}
|
||||
}
|
||||
fi->packetno++;
|
||||
|
||||
return 0;
|
||||
|
||||
dec_err:
|
||||
switch (FLAC__stream_decoder_get_state(fi->fsd)) {
|
||||
case FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR:
|
||||
return FISH_SOUND_ERR_OUT_OF_MEMORY;
|
||||
default:
|
||||
return FISH_SOUND_ERR_GENERIC;
|
||||
}
|
||||
}
|
||||
#else /* !FS_DECODE */
|
||||
|
||||
#define fs_flac_decode NULL
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#if FS_ENCODE
|
||||
static FLAC__StreamEncoderWriteStatus
|
||||
fs_flac_enc_write_callback(const FLAC__StreamEncoder *encoder,
|
||||
const FLAC__byte buffer[], unsigned bytes,
|
||||
unsigned samples, unsigned current_frame,
|
||||
void *client_data)
|
||||
{
|
||||
FishSound* fsound = (FishSound*)client_data;
|
||||
FishSoundFlacInfo *fi = fsound->codec_data;
|
||||
|
||||
debug_printf(1, "IN");
|
||||
debug_printf(1, "bytes: %d, samples: %d", bytes, samples);
|
||||
|
||||
if (fsound->callback.encoded) {
|
||||
FishSoundEncoded encoded = (FishSoundEncoded) fsound->callback.encoded;
|
||||
if (fi->packetno == 0 && fi->header <= 1) {
|
||||
if (fi->header == 0) {
|
||||
/* libFLAC has called us with data containing the normal fLaC header
|
||||
* and a STREAMINFO block. Prepend the FLAC Ogg mapping header,
|
||||
* as described in http://flac.sourceforge.net/ogg_mapping.html.
|
||||
*/
|
||||
debug_printf(1, "generating FLAC header packet: %c%c%c%c",
|
||||
buffer[0], buffer[1], buffer[2], buffer[3]);
|
||||
|
||||
if ((fi->buffer = (unsigned char*)fs_malloc(sizeof(unsigned char)*(bytes+9))) == NULL)
|
||||
return FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR;
|
||||
|
||||
fi->buffer[0] = 0x7f;
|
||||
fi->buffer[1] = 0x46; /* 'F' */
|
||||
fi->buffer[2] = 0x4c; /* 'L' */
|
||||
fi->buffer[3] = 0x41; /* 'A' */
|
||||
fi->buffer[4] = 0x43; /* 'C' */
|
||||
fi->buffer[5] = 1; /* Version major generated by this file */
|
||||
fi->buffer[6] = 0; /* Version minor generated by this file */
|
||||
fi->buffer[7] = 0; /* MSB(be): Nr. other non-audio header packets */
|
||||
fi->buffer[8] = 1; /* LSB(be): Nr. other non-audio header packets */
|
||||
memcpy (fi->buffer+9, buffer, bytes); /* fLaC header ++ STREAMINFO */
|
||||
fi->bufferlength = bytes+9;
|
||||
|
||||
fi->header++;
|
||||
} else {
|
||||
/* Make a temporary copy of the metadata header to pass to the user
|
||||
* callback.
|
||||
*/
|
||||
unsigned char* tmp;
|
||||
|
||||
if ((tmp = (unsigned char*)fs_malloc(sizeof(unsigned char)*(bytes+fi->bufferlength))) == NULL)
|
||||
return FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR;
|
||||
|
||||
memcpy (tmp, fi->buffer, fi->bufferlength);
|
||||
memcpy (tmp+fi->bufferlength, buffer, bytes);
|
||||
fs_free(fi->buffer);
|
||||
fi->buffer = tmp;
|
||||
fi->bufferlength += bytes;
|
||||
fi->header++;
|
||||
encoded (fsound, (unsigned char *)fi->buffer, (long)fi->bufferlength,
|
||||
fsound->user_data);
|
||||
}
|
||||
} else {
|
||||
fsound->frameno += samples;
|
||||
encoded (fsound, (unsigned char *)buffer, (long)bytes,
|
||||
fsound->user_data);
|
||||
}
|
||||
}
|
||||
|
||||
return FLAC__STREAM_ENCODER_WRITE_STATUS_OK;
|
||||
}
|
||||
|
||||
static void
|
||||
fs_flac_enc_meta_callback(const FLAC__StreamEncoder *encoder,
|
||||
const FLAC__StreamMetadata *metadata,
|
||||
void *client_data)
|
||||
{
|
||||
/* FishSound* fsound = (FishSound*)client_data; */
|
||||
/* FishSoundFlacInfo* fi = (FishSoundFlacInfo *)fsound->codec_data; */
|
||||
debug_printf(1, "IN");
|
||||
|
||||
switch (metadata->type) {
|
||||
case FLAC__METADATA_TYPE_STREAMINFO:
|
||||
debug_printf(1, "channels %d, samplerate %d",
|
||||
metadata->data.stream_info.channels,
|
||||
metadata->data.stream_info.sample_rate);
|
||||
/*
|
||||
fsound->info.channels = metadata->data.stream_info.channels;
|
||||
fsound->info.samplerate = metadata->data.stream_info.sample_rate;
|
||||
*/
|
||||
break;
|
||||
default:
|
||||
debug_printf(1, "metadata type not yet implemented");
|
||||
break;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* Create a local alias for an unwieldy type name */
|
||||
typedef FLAC__StreamMetadata_VorbisComment_Entry FLAC__VCEntry;
|
||||
|
||||
static void
|
||||
fs_flac_metadata_free (FLAC__StreamMetadata * metadata)
|
||||
{
|
||||
unsigned int i, length;
|
||||
FLAC__VCEntry * comments;
|
||||
|
||||
if (metadata == NULL) return;
|
||||
|
||||
length = metadata->data.vorbis_comment.num_comments;
|
||||
comments = metadata->data.vorbis_comment.comments;
|
||||
|
||||
for (i = 0; i < length; i++) {
|
||||
fs_free (comments[i].entry);
|
||||
}
|
||||
|
||||
fs_free (comments);
|
||||
fs_free (metadata);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static FLAC__byte *
|
||||
fs_flac_encode_vcentry (const FishSoundComment * comment)
|
||||
{
|
||||
FLAC__byte * entry;
|
||||
FLAC__uint32 length;
|
||||
size_t name_len=0, value_len=0;
|
||||
|
||||
name_len = strlen(comment->name);
|
||||
length = name_len + 1;
|
||||
|
||||
if (comment->value) {
|
||||
value_len = strlen (comment->value);
|
||||
length += value_len + 1;
|
||||
}
|
||||
|
||||
if ((entry = fs_malloc (length)) == NULL)
|
||||
return NULL;
|
||||
|
||||
/* We assume that comment->name, value are NUL terminated, as they were
|
||||
* produced by our own comments.c */
|
||||
strcpy ((char *)entry, comment->name);
|
||||
|
||||
if (comment->value) {
|
||||
entry[name_len] = '=';
|
||||
strcpy ((char *)&entry[name_len+1], comment->value);
|
||||
}
|
||||
|
||||
entry[length-1] = '\0';
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
static FLAC__StreamMetadata *
|
||||
fs_flac_encode_vorbiscomments (FishSound * fsound)
|
||||
{
|
||||
FishSoundFlacInfo * fi = fsound->codec_data;
|
||||
FLAC__StreamMetadata * metadata = NULL;
|
||||
const FishSoundComment * comment;
|
||||
unsigned int i=0, length=0, total_length;
|
||||
FLAC__VCEntry * comments;
|
||||
|
||||
/* libFLAC seems to require us to know the total length of the generated
|
||||
* vorbiscomment packet, even though it will silently generate the
|
||||
* vendor string. Hence, this value was determined by inspection for
|
||||
* the version "reference libFLAC 1.1.2"
|
||||
*/
|
||||
total_length = 40;
|
||||
|
||||
/* Count the number of comments */
|
||||
for (comment = fish_sound_comment_first (fsound); comment;
|
||||
comment = fish_sound_comment_next (fsound, comment)) {
|
||||
length++;
|
||||
}
|
||||
|
||||
if (length == 0) return NULL;
|
||||
|
||||
if ((comments = (FLAC__VCEntry *)fs_malloc (sizeof(FLAC__VCEntry) * length)) == NULL)
|
||||
goto encode_vc_oom;
|
||||
|
||||
for (comment = fish_sound_comment_first (fsound); comment;
|
||||
comment = fish_sound_comment_next (fsound, comment)) {
|
||||
if ((comments[i].entry = fs_flac_encode_vcentry (comment)) == NULL) {
|
||||
}
|
||||
comments[i].length = strlen((char *)comments[i].entry);
|
||||
|
||||
/* In the generated vorbiscomment data, each entry is preceded by a
|
||||
* 32bit length specifier. */
|
||||
total_length += 4 + comments[i].length;
|
||||
i++;
|
||||
}
|
||||
|
||||
if ((metadata = (FLAC__StreamMetadata *) fs_malloc (sizeof (*metadata))) == NULL)
|
||||
goto encode_vc_oom;
|
||||
|
||||
metadata->type = FLAC__METADATA_TYPE_VORBIS_COMMENT;
|
||||
metadata->is_last = true;
|
||||
metadata->length = total_length;
|
||||
/* Don't bother setting the vendor_string, as libFLAC ignores it */
|
||||
metadata->data.vorbis_comment.num_comments = length;
|
||||
metadata->data.vorbis_comment.comments = comments;
|
||||
|
||||
/* Remember the allocated metadata */
|
||||
fi->enc_vc_metadata = metadata;
|
||||
|
||||
return metadata;
|
||||
|
||||
encode_vc_oom:
|
||||
if (metadata != NULL)
|
||||
fs_free (metadata);
|
||||
|
||||
/* Unwind allocated comment entries */
|
||||
for (i--; i >= 0; i--) {
|
||||
if (comments[i].entry != NULL)
|
||||
fs_free (comments[i].entry);
|
||||
}
|
||||
|
||||
if (comments != NULL)
|
||||
fs_free (comments);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static FishSound *
|
||||
fs_flac_enc_headers (FishSound * fsound)
|
||||
{
|
||||
FishSoundFlacInfo * fi = fsound->codec_data;
|
||||
FLAC__StreamMetadata * metadata;
|
||||
|
||||
fi->fse = FLAC__stream_encoder_new();
|
||||
FLAC__stream_encoder_set_channels(fi->fse, fsound->info.channels);
|
||||
FLAC__stream_encoder_set_sample_rate(fi->fse, fsound->info.samplerate);
|
||||
FLAC__stream_encoder_set_bits_per_sample(fi->fse, BITS_PER_SAMPLE);
|
||||
|
||||
#if defined (HAVE_FLAC_1_1_2)
|
||||
FLAC__stream_encoder_set_write_callback(fi->fse, fs_flac_enc_write_callback);
|
||||
FLAC__stream_encoder_set_metadata_callback(fi->fse, fs_flac_enc_meta_callback);
|
||||
FLAC__stream_encoder_set_client_data(fi->fse, fsound);
|
||||
#endif
|
||||
|
||||
metadata = fs_flac_encode_vorbiscomments (fsound);
|
||||
if (metadata != NULL)
|
||||
FLAC__stream_encoder_set_metadata (fi->fse, &metadata, 1);
|
||||
|
||||
/* FLAC__stream_encoder_set_total_samples_estimate(fi->fse, ...);*/
|
||||
|
||||
#if defined (HAVE_FLAC_1_1_2)
|
||||
if (FLAC__stream_encoder_init(fi->fse) != FLAC__STREAM_ENCODER_OK)
|
||||
return NULL;
|
||||
#elif defined (HAVE_FLAC_1_1_3)
|
||||
if (FLAC__stream_encoder_init_stream
|
||||
(fi->fse,
|
||||
fs_flac_enc_write_callback,
|
||||
NULL, /* seek callback */
|
||||
NULL, /* tell callback */
|
||||
fs_flac_enc_meta_callback,
|
||||
fsound
|
||||
) != FLAC__STREAM_ENCODER_OK)
|
||||
return NULL;
|
||||
|
||||
#endif
|
||||
|
||||
return fsound;
|
||||
}
|
||||
|
||||
static long
|
||||
fs_flac_encode_fatal (FishSoundFlacInfo *fi, long err)
|
||||
{
|
||||
FLAC__stream_encoder_delete (fi->fse);
|
||||
fi->fse = NULL;
|
||||
return err;
|
||||
}
|
||||
|
||||
static long
|
||||
fs_flac_encode_f (FishSound * fsound, float * pcm[], long frames)
|
||||
{
|
||||
FishSoundFlacInfo *fi = fsound->codec_data;
|
||||
FLAC__int32 *buffer, *ipcm;
|
||||
float * p, norm = (1 << (BITS_PER_SAMPLE - 1));
|
||||
long i;
|
||||
int j, channels = fsound->info.channels;
|
||||
|
||||
debug_printf("IN, frames = %ld", frames);
|
||||
|
||||
if ((ipcm = realloc(fi->ipcm, sizeof(FLAC__int32) * channels * frames)) == NULL)
|
||||
return FISH_SOUND_ERR_OUT_OF_MEMORY;
|
||||
|
||||
fi->ipcm = ipcm;
|
||||
buffer = (FLAC__int32*) fi->ipcm;
|
||||
for (i = 0; i < frames; i++) {
|
||||
for (j = 0; j < channels; j++) {
|
||||
p = pcm[j];
|
||||
buffer[i*channels + j] = (FLAC__int32) (p[i] * norm);
|
||||
}
|
||||
}
|
||||
|
||||
if (fi->packetno == 0)
|
||||
fs_flac_enc_headers (fsound);
|
||||
|
||||
/* We could have used FLAC__stream_encoder_process() and a more direct
|
||||
* conversion loop above, rather than converting and interleaving. */
|
||||
if (FLAC__stream_encoder_process_interleaved(fi->fse, buffer, frames) == false) {
|
||||
switch (FLAC__stream_encoder_get_state (fi->fse)) {
|
||||
case FLAC__STREAM_ENCODER_OK:
|
||||
case FLAC__STREAM_ENCODER_UNINITIALIZED:
|
||||
break;
|
||||
case FLAC__STREAM_ENCODER_MEMORY_ALLOCATION_ERROR:
|
||||
return fs_flac_encode_fatal (fi, FISH_SOUND_ERR_OUT_OF_MEMORY);
|
||||
default:
|
||||
return fs_flac_encode_fatal (fi, FISH_SOUND_ERR_GENERIC);
|
||||
}
|
||||
}
|
||||
|
||||
fi->packetno++;
|
||||
|
||||
return frames;
|
||||
}
|
||||
|
||||
static long
|
||||
fs_flac_encode_f_ilv (FishSound * fsound, float ** pcm, long frames)
|
||||
{
|
||||
FishSoundFlacInfo *fi = fsound->codec_data;
|
||||
FLAC__int32 *buffer, *ipcm;
|
||||
float * p = (float*)pcm, norm = (1 << (BITS_PER_SAMPLE - 1));
|
||||
long i, length = frames * fsound->info.channels;
|
||||
|
||||
debug_printf(1, "IN, frames = %ld", frames);
|
||||
|
||||
if ((ipcm = realloc(fi->ipcm, sizeof(FLAC__int32)*fsound->info.channels*frames)) == NULL)
|
||||
return FISH_SOUND_ERR_OUT_OF_MEMORY;
|
||||
|
||||
fi->ipcm = ipcm;
|
||||
buffer = (FLAC__int32*) fi->ipcm;
|
||||
for (i=0; i<length; i++)
|
||||
buffer[i] = p[i] * norm;
|
||||
|
||||
if (fi->packetno == 0)
|
||||
fs_flac_enc_headers (fsound);
|
||||
|
||||
if (FLAC__stream_encoder_process_interleaved(fi->fse, buffer, frames) == false) {
|
||||
switch (FLAC__stream_encoder_get_state (fi->fse)) {
|
||||
case FLAC__STREAM_ENCODER_OK:
|
||||
case FLAC__STREAM_ENCODER_UNINITIALIZED:
|
||||
break;
|
||||
case FLAC__STREAM_ENCODER_MEMORY_ALLOCATION_ERROR:
|
||||
return fs_flac_encode_fatal (fi, FISH_SOUND_ERR_OUT_OF_MEMORY);
|
||||
default:
|
||||
return fs_flac_encode_fatal (fi, FISH_SOUND_ERR_GENERIC);
|
||||
}
|
||||
}
|
||||
|
||||
fi->packetno++;
|
||||
|
||||
return frames;
|
||||
}
|
||||
#else /* ! FS_ENCODE */
|
||||
|
||||
#define fs_flac_encode_f NULL
|
||||
#define fs_flac_encode_f_ilv NULL
|
||||
|
||||
#endif /* ! FS_ENCODE */
|
||||
|
||||
|
||||
static FishSound *
|
||||
fs_flac_delete (FishSound * fsound)
|
||||
{
|
||||
FishSoundFlacInfo * fi = (FishSoundFlacInfo *)fsound->codec_data;
|
||||
int i;
|
||||
|
||||
debug_printf("IN");
|
||||
|
||||
if (fsound->mode == FISH_SOUND_DECODE) {
|
||||
if (fi->fsd) {
|
||||
FLAC__stream_decoder_finish(fi->fsd);
|
||||
FLAC__stream_decoder_delete(fi->fsd);
|
||||
}
|
||||
} else if (fsound->mode == FISH_SOUND_ENCODE) {
|
||||
if (fi->fse) {
|
||||
FLAC__stream_encoder_finish(fi->fse);
|
||||
FLAC__stream_encoder_delete(fi->fse);
|
||||
}
|
||||
if (fi->buffer) {
|
||||
fs_free(fi->buffer);
|
||||
fi->buffer = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (fi->ipcm) fs_free(fi->ipcm);
|
||||
for (i = 0; i < 8; i++) {
|
||||
if (fi->pcm_out[i]) fs_free (fi->pcm_out[i]);
|
||||
}
|
||||
|
||||
#if FS_ENCODE
|
||||
if (fi->enc_vc_metadata) {
|
||||
fs_flac_metadata_free (fi->enc_vc_metadata);
|
||||
}
|
||||
#endif
|
||||
|
||||
fs_free (fi);
|
||||
fsound->codec_data = NULL;
|
||||
|
||||
return fsound;
|
||||
}
|
||||
|
||||
static int
|
||||
fs_flac_update (FishSound * fsound, int interleave)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
fs_flac_reset (FishSound * fsound)
|
||||
{
|
||||
/*FishSoundFlacInfo * fi = (FishSoundFlacInfo *)fsound->codec_data;*/
|
||||
#if 0
|
||||
if (fsound->mode == FISH_SOUND_DECODE) {
|
||||
FLAC__stream_decoder_reset(fi->fsd);
|
||||
} else if (fsound->mode == FISH_SOUND_ENCODE) {
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
static long
|
||||
fs_flac_flush (FishSound * fsound)
|
||||
{
|
||||
FishSoundFlacInfo * fi = (FishSoundFlacInfo *)fsound->codec_data;
|
||||
|
||||
debug_printf("IN (%s)", fsound->mode == FISH_SOUND_DECODE ? "decode" : "encode");
|
||||
|
||||
if (fsound->mode == FISH_SOUND_DECODE) {
|
||||
FLAC__stream_decoder_finish(fi->fsd);
|
||||
} else if (fsound->mode == FISH_SOUND_ENCODE) {
|
||||
FLAC__stream_encoder_finish(fi->fse);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static FishSound *
|
||||
fs_flac_init (FishSound * fsound)
|
||||
{
|
||||
FishSoundFlacInfo *fi;
|
||||
int i;
|
||||
|
||||
fi = fs_malloc (sizeof (FishSoundFlacInfo));
|
||||
if (fi == NULL) return NULL;
|
||||
fi->fsd = NULL;
|
||||
fi->fse = NULL;
|
||||
fi->buffer = NULL;
|
||||
fi->packetno = 0;
|
||||
fi->header = 0;
|
||||
fi->header_packets = 0;
|
||||
|
||||
fi->ipcm = NULL;
|
||||
for (i = 0; i < 8; i++) {
|
||||
fi->pcm_out[i] = NULL;
|
||||
}
|
||||
|
||||
#if FS_ENCODE
|
||||
fi->enc_vc_metadata = NULL;
|
||||
#endif
|
||||
|
||||
fsound->codec_data = fi;
|
||||
|
||||
return fsound;
|
||||
}
|
||||
|
||||
FishSoundCodec *
|
||||
fish_sound_flac_codec (void)
|
||||
{
|
||||
FishSoundCodec * codec;
|
||||
|
||||
codec = (FishSoundCodec *) fs_malloc (sizeof (FishSoundCodec));
|
||||
if (codec == NULL) return NULL;
|
||||
|
||||
codec->format.format = FISH_SOUND_FLAC;
|
||||
codec->format.name = "Flac (Xiph.Org)";
|
||||
codec->format.extension = "ogg";
|
||||
|
||||
codec->init = fs_flac_init;
|
||||
codec->del = fs_flac_delete;
|
||||
codec->reset = fs_flac_reset;
|
||||
codec->update = fs_flac_update;
|
||||
codec->command = fs_flac_command;
|
||||
codec->decode = fs_flac_decode;
|
||||
codec->encode_f = fs_flac_encode_f;
|
||||
codec->encode_f_ilv = fs_flac_encode_f_ilv;
|
||||
codec->flush = fs_flac_flush;
|
||||
|
||||
return codec;
|
||||
}
|
||||
|
||||
#else /* !HAVE_FLAC */
|
||||
|
||||
int
|
||||
fish_sound_flac_identify (unsigned char * buf, long bytes)
|
||||
{
|
||||
return FISH_SOUND_UNKNOWN;
|
||||
}
|
||||
|
||||
FishSoundCodec *
|
||||
fish_sound_flac_codec (void)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,802 +0,0 @@
|
|||
/*
|
||||
Copyright (C) 2003 Commonwealth Scientific and Industrial Research
|
||||
Organisation (CSIRO) Australia
|
||||
|
||||
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.
|
||||
|
||||
- Neither the name of CSIRO Australia nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
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 ORGANISATION 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.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#if HAVE_STDINT_H
|
||||
#include <stdint.h>
|
||||
#endif
|
||||
|
||||
#include <ctype.h>
|
||||
|
||||
#include "private.h"
|
||||
#include "convert.h"
|
||||
|
||||
/*#define DEBUG*/
|
||||
#include "debug.h"
|
||||
|
||||
#if HAVE_SPEEX
|
||||
|
||||
#if HAVE_SPEEX_1_1
|
||||
#include <speex/speex.h>
|
||||
#include <speex/speex_header.h>
|
||||
#include <speex/speex_stereo.h>
|
||||
#include <speex/speex_callbacks.h>
|
||||
|
||||
#else /* Speex 1.0 */
|
||||
|
||||
#include <speex.h>
|
||||
#include <speex_header.h>
|
||||
#include <speex_stereo.h>
|
||||
#include <speex_callbacks.h>
|
||||
#endif
|
||||
|
||||
/* Format for the vendor string: "Encoded with Speex VERSION", where VERSION
|
||||
* is the libspeex version as read from a newly-generated Speex header.
|
||||
*/
|
||||
#define VENDOR_FORMAT "Encoded with Speex %s"
|
||||
|
||||
#define DEFAULT_ENH_ENABLED 1
|
||||
|
||||
#define MAX_FRAME_BYTES 2000
|
||||
|
||||
typedef struct _FishSoundSpeexEnc {
|
||||
int frame_offset; /* number of speex frames done in this packet */
|
||||
int pcm_offset;
|
||||
char cbits[MAX_FRAME_BYTES];
|
||||
int id;
|
||||
} FishSoundSpeexEnc;
|
||||
|
||||
typedef struct _FishSoundSpeexInfo {
|
||||
int packetno;
|
||||
void * st;
|
||||
SpeexBits bits;
|
||||
int frame_size;
|
||||
int nframes;
|
||||
int extra_headers;
|
||||
SpeexStereoState stereo;
|
||||
int pcm_len; /* nr frames in pcm */
|
||||
float * ipcm; /* interleaved pcm */
|
||||
float * pcm[2]; /* Speex does max 2 channels */
|
||||
FishSoundSpeexEnc * enc;
|
||||
} FishSoundSpeexInfo;
|
||||
|
||||
int
|
||||
fish_sound_speex_identify (unsigned char * buf, long bytes)
|
||||
{
|
||||
SpeexHeader * header;
|
||||
|
||||
if (bytes < 8) return FISH_SOUND_UNKNOWN;
|
||||
|
||||
if (!strncmp ((char *)buf, "Speex ", 8)) {
|
||||
/* if only a short buffer was passed, do a weak identify */
|
||||
if (bytes == 8) return FISH_SOUND_SPEEX;
|
||||
|
||||
/* otherwise, assume the buffer is an entire initial header and
|
||||
* feed it to speex_packet_to_header() */
|
||||
if ((header = speex_packet_to_header ((char *)buf, (int)bytes)) != NULL) {
|
||||
fs_free(header);
|
||||
return FISH_SOUND_SPEEX;
|
||||
}
|
||||
}
|
||||
|
||||
return FISH_SOUND_UNKNOWN;
|
||||
}
|
||||
|
||||
static int
|
||||
fs_speex_command (FishSound * fsound, int command, void * data, int datasize)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if FS_DECODE
|
||||
static void *
|
||||
process_header(unsigned char * buf, long bytes, int enh_enabled,
|
||||
int * frame_size, int * rate,
|
||||
int * nframes, int forceMode, int * channels,
|
||||
SpeexStereoState * stereo, int * extra_headers)
|
||||
{
|
||||
void *st;
|
||||
SpeexMode *mode;
|
||||
SpeexHeader *header;
|
||||
int modeID;
|
||||
SpeexCallback callback;
|
||||
|
||||
header = speex_packet_to_header((char*)buf, (int)bytes);
|
||||
if (!header) {
|
||||
/* cannot read header */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (header->mode >= SPEEX_NB_MODES || header->mode < 0) {
|
||||
/* Mode number does not (any longer) exist in this version */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
modeID = header->mode;
|
||||
if (forceMode!=-1)
|
||||
modeID = forceMode;
|
||||
|
||||
#if HAVE_SPEEX_LIB_GET_MODE
|
||||
mode = (SpeexMode *) speex_lib_get_mode (modeID);
|
||||
#else
|
||||
/* speex_mode_list[] is declared const in speex 1.1.x, hence the cast */
|
||||
mode = (SpeexMode *)speex_mode_list[modeID];
|
||||
#endif
|
||||
|
||||
if (header->speex_version_id > 1) {
|
||||
/* Unknown bitstream version */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (mode->bitstream_version < header->mode_bitstream_version) {
|
||||
/* The file was encoded with a newer version of Speex,
|
||||
* need to upgrade in order to play it */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (mode->bitstream_version > header->mode_bitstream_version) {
|
||||
/* The file was encoded with an older version of Speex.
|
||||
* You would need to downgrade the version in order to play it */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
st = speex_decoder_init(mode);
|
||||
if (!st) {
|
||||
/* Decoder initialization failed */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
speex_decoder_ctl(st, SPEEX_SET_ENH, &enh_enabled);
|
||||
speex_decoder_ctl(st, SPEEX_GET_FRAME_SIZE, frame_size);
|
||||
|
||||
if (!(*channels==1))
|
||||
{
|
||||
callback.callback_id = SPEEX_INBAND_STEREO;
|
||||
callback.func = speex_std_stereo_request_handler;
|
||||
callback.data = stereo;
|
||||
speex_decoder_ctl(st, SPEEX_SET_HANDLER, &callback);
|
||||
}
|
||||
if (!*rate)
|
||||
*rate = header->rate;
|
||||
/* Adjust rate if --force-* options are used */
|
||||
if (forceMode!=-1)
|
||||
{
|
||||
if (header->mode < forceMode)
|
||||
*rate <<= (forceMode - header->mode);
|
||||
if (header->mode > forceMode)
|
||||
*rate >>= (header->mode - forceMode);
|
||||
}
|
||||
|
||||
speex_decoder_ctl(st, SPEEX_SET_SAMPLING_RATE, rate);
|
||||
|
||||
*nframes = header->frames_per_packet;
|
||||
|
||||
if (*channels == -1)
|
||||
*channels = header->nb_channels;
|
||||
|
||||
debug_printf (1, "Decoding %d Hz audio using %s mode",
|
||||
*rate, mode->modeName);
|
||||
|
||||
#ifdef DEBUG
|
||||
if (*channels==1)
|
||||
fprintf (stderr, " (mono");
|
||||
else
|
||||
fprintf (stderr, " (stereo");
|
||||
|
||||
if (header->vbr)
|
||||
fprintf (stderr, " (VBR)\n");
|
||||
else
|
||||
fprintf(stderr, "\n");
|
||||
#endif
|
||||
|
||||
*extra_headers = header->extra_headers;
|
||||
|
||||
fs_free(header);
|
||||
|
||||
return st;
|
||||
}
|
||||
|
||||
static int
|
||||
fs_speex_free_buffers (FishSound * fsound)
|
||||
{
|
||||
FishSoundSpeexInfo * fss = (FishSoundSpeexInfo *)fsound->codec_data;
|
||||
|
||||
if (fsound->mode == FISH_SOUND_DECODE) {
|
||||
if (fss->ipcm && fss->ipcm != fss->pcm[0]) fs_free (fss->ipcm);
|
||||
if (fss->pcm[0]) fs_free (fss->pcm[0]);
|
||||
if (fss->pcm[1]) fs_free (fss->pcm[1]);
|
||||
} else {
|
||||
if (fss->ipcm) fs_free (fss->ipcm);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int
|
||||
fs_speex_float_dispatch (FishSound * fsound)
|
||||
{
|
||||
FishSoundSpeexInfo * fss = (FishSoundSpeexInfo *)fsound->codec_data;
|
||||
FishSoundDecoded_FloatIlv df;
|
||||
FishSoundDecoded_Float dfi;
|
||||
int retval;
|
||||
|
||||
if (fsound->interleave) {
|
||||
dfi = (FishSoundDecoded_FloatIlv)fsound->callback.decoded_float_ilv;
|
||||
retval = dfi (fsound, (float **)fss->ipcm, fss->frame_size,
|
||||
fsound->user_data);
|
||||
} else {
|
||||
df = (FishSoundDecoded_Float)fsound->callback.decoded_float;
|
||||
retval = df (fsound, fss->pcm, fss->frame_size, fsound->user_data);
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static long
|
||||
fs_speex_decode (FishSound * fsound, unsigned char * buf, long bytes)
|
||||
{
|
||||
FishSoundSpeexInfo * fss = (FishSoundSpeexInfo *)fsound->codec_data;
|
||||
int enh_enabled = DEFAULT_ENH_ENABLED;
|
||||
int rate = 0;
|
||||
int channels = -1;
|
||||
int forceMode = -1;
|
||||
int i, j;
|
||||
|
||||
if (fss->packetno == 0) {
|
||||
fss->st = process_header (buf, bytes, enh_enabled,
|
||||
&fss->frame_size, &rate,
|
||||
&fss->nframes, forceMode, &channels,
|
||||
&fss->stereo,
|
||||
&fss->extra_headers);
|
||||
|
||||
if (fss->st == NULL) {
|
||||
/* TODO: Return more specific error identifiers for invalid header fields */
|
||||
return FISH_SOUND_ERR_GENERIC;
|
||||
}
|
||||
|
||||
debug_printf (1, "speex: got %d channels, %d Hz", channels, rate);
|
||||
|
||||
fsound->info.samplerate = rate;
|
||||
fsound->info.channels = channels;
|
||||
|
||||
/* Sanity check the channels value, as we will use it to determine buffer
|
||||
sizes below.
|
||||
*/
|
||||
if (channels < 1 || channels > 2)
|
||||
return FISH_SOUND_ERR_GENERIC;
|
||||
|
||||
#if HAVE_UINTPTR_T
|
||||
/* Sanity check: frame_size is not so large that the buffer size calculations
|
||||
* would wrap. In reality, frame_size is set by libspeex according to the
|
||||
* mode index specified in the file header, and is usually equal to 320.
|
||||
*/
|
||||
if (fss->frame_size > UINTPTR_MAX / (sizeof(float) * channels))
|
||||
return FISH_SOUND_ERR_GENERIC;
|
||||
#endif
|
||||
|
||||
fss->ipcm = fs_malloc (sizeof (float) * fss->frame_size * channels);
|
||||
if (fss->ipcm == NULL) {
|
||||
return FISH_SOUND_ERR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
if (channels == 1) {
|
||||
fss->pcm[0] = fss->ipcm;
|
||||
} else if (channels == 2) {
|
||||
fss->pcm[0] = fs_malloc (sizeof (float) * fss->frame_size);
|
||||
if (fss->pcm[0] == NULL) {
|
||||
fs_free (fss->ipcm);
|
||||
return FISH_SOUND_ERR_OUT_OF_MEMORY;
|
||||
}
|
||||
fss->pcm[1] = fs_malloc (sizeof (float) * fss->frame_size);
|
||||
if (fss->pcm[1] == NULL) {
|
||||
fs_free (fss->pcm[0]);
|
||||
fs_free (fss->ipcm);
|
||||
return FISH_SOUND_ERR_OUT_OF_MEMORY;
|
||||
}
|
||||
}
|
||||
|
||||
if (fss->nframes == 0) fss->nframes = 1;
|
||||
|
||||
} else if (fss->packetno == 1) {
|
||||
/* Comments */
|
||||
if (fish_sound_comments_decode (fsound, buf, bytes) == FISH_SOUND_ERR_OUT_OF_MEMORY) {
|
||||
fss->packetno++;
|
||||
return FISH_SOUND_ERR_OUT_OF_MEMORY;
|
||||
}
|
||||
} else if (fss->packetno <= 1+fss->extra_headers) {
|
||||
/* Unknown extra headers */
|
||||
} else {
|
||||
speex_bits_read_from (&fss->bits, (char *)buf, (int)bytes);
|
||||
|
||||
for (i = 0; i < fss->nframes; i++) {
|
||||
/* Decode frame */
|
||||
speex_decode (fss->st, &fss->bits, fss->ipcm);
|
||||
|
||||
if (fsound->info.channels == 2) {
|
||||
speex_decode_stereo (fss->ipcm, fss->frame_size, &fss->stereo);
|
||||
if (fsound->interleave) {
|
||||
for (j = 0; j < fss->frame_size * fsound->info.channels; j++) {
|
||||
fss->ipcm[j] /= 32767.0;
|
||||
}
|
||||
} else {
|
||||
_fs_deinterleave ((float **)fss->ipcm, fss->pcm,
|
||||
fss->frame_size, 2, (float)(1/32767.0));
|
||||
}
|
||||
} else {
|
||||
for (j = 0; j < fss->frame_size; j++) {
|
||||
fss->ipcm[j] /= 32767.0;
|
||||
}
|
||||
}
|
||||
|
||||
fsound->frameno += fss->frame_size;
|
||||
|
||||
fs_speex_float_dispatch (fsound);
|
||||
}
|
||||
}
|
||||
|
||||
fss->packetno++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#else /* !FS_DECODE */
|
||||
|
||||
#define fs_speex_decode NULL
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#if FS_ENCODE
|
||||
static FishSound *
|
||||
fs_speex_enc_headers (FishSound * fsound)
|
||||
{
|
||||
FishSoundSpeexInfo * fss = (FishSoundSpeexInfo *)fsound->codec_data;
|
||||
int modeID;
|
||||
SpeexMode * mode = NULL;
|
||||
SpeexHeader header;
|
||||
unsigned char * header_buf = NULL, * comments_buf = NULL;
|
||||
int header_bytes, comments_bytes;
|
||||
size_t buflen;
|
||||
|
||||
modeID = 1;
|
||||
|
||||
#if HAVE_SPEEX_LIB_GET_MODE
|
||||
mode = (SpeexMode *) speex_lib_get_mode (modeID);
|
||||
#else
|
||||
/* speex_mode_list[] is declared const in speex 1.1.x, hence the cast */
|
||||
mode = (SpeexMode *)speex_mode_list[modeID];
|
||||
#endif
|
||||
|
||||
speex_init_header (&header, fsound->info.samplerate, 1, mode);
|
||||
header.frames_per_packet = fss->nframes; /* XXX: frames per packet */
|
||||
header.vbr = 1; /* XXX: VBR */
|
||||
header.nb_channels = fsound->info.channels;
|
||||
|
||||
fss->st = speex_encoder_init (mode);
|
||||
|
||||
if (fsound->callback.encoded) {
|
||||
char vendor_string[128];
|
||||
|
||||
/* Allocate and create header */
|
||||
header_buf = (unsigned char *) speex_header_to_packet (&header, &header_bytes);
|
||||
if (header_buf == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Allocate and create comments */
|
||||
snprintf (vendor_string, 128, VENDOR_FORMAT, header.speex_version);
|
||||
if (fish_sound_comment_set_vendor (fsound, vendor_string) == FISH_SOUND_ERR_OUT_OF_MEMORY) {
|
||||
fs_free (header_buf);
|
||||
return NULL;
|
||||
}
|
||||
comments_bytes = fish_sound_comments_encode (fsound, NULL, 0);
|
||||
comments_buf = fs_malloc (comments_bytes);
|
||||
if (comments_buf == NULL) {
|
||||
fs_free (header_buf);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
speex_encoder_ctl (fss->st, SPEEX_SET_SAMPLING_RATE,
|
||||
&fsound->info.samplerate);
|
||||
|
||||
speex_encoder_ctl (fss->st, SPEEX_GET_FRAME_SIZE, &fss->frame_size);
|
||||
|
||||
debug_printf (1, "got frame size %d", fss->frame_size);
|
||||
|
||||
/* XXX: set VBR etc. */
|
||||
|
||||
buflen = fss->frame_size * fsound->info.channels * sizeof (float);
|
||||
fss->ipcm = fs_malloc (buflen);
|
||||
if (fss->ipcm == NULL) {
|
||||
if (comments_buf) fs_free (comments_buf);
|
||||
if (header_buf) fs_free (header_buf);
|
||||
return NULL;
|
||||
}
|
||||
memset (fss->ipcm, 0, buflen);
|
||||
|
||||
/* Allocations succeeded, actually call encoded callback for headers */
|
||||
if (fsound->callback.encoded) {
|
||||
FishSoundEncoded encoded = (FishSoundEncoded)fsound->callback.encoded;
|
||||
|
||||
/* header */
|
||||
encoded (fsound, header_buf, (long)header_bytes, fsound->user_data);
|
||||
fss->packetno++;
|
||||
fs_free (header_buf);
|
||||
|
||||
/* comments */
|
||||
comments_bytes = fish_sound_comments_encode (fsound, comments_buf, comments_bytes);
|
||||
encoded (fsound, comments_buf, (long)comments_bytes, fsound->user_data);
|
||||
fss->packetno++;
|
||||
fs_free (comments_buf);
|
||||
}
|
||||
|
||||
return fsound;
|
||||
}
|
||||
|
||||
static long
|
||||
fs_speex_encode_write (FishSound * fsound)
|
||||
{
|
||||
FishSoundSpeexInfo * fss = (FishSoundSpeexInfo *)fsound->codec_data;
|
||||
FishSoundSpeexEnc * fse = (FishSoundSpeexEnc *)fss->enc;
|
||||
int bytes;
|
||||
|
||||
speex_bits_insert_terminator (&fss->bits);
|
||||
bytes = speex_bits_write (&fss->bits, fse->cbits, MAX_FRAME_BYTES);
|
||||
speex_bits_reset (&fss->bits);
|
||||
|
||||
if (fsound->callback.encoded) {
|
||||
FishSoundEncoded encoded = (FishSoundEncoded)fsound->callback.encoded;
|
||||
|
||||
encoded (fsound, (unsigned char *)fse->cbits, (long)bytes,
|
||||
fsound->user_data);
|
||||
}
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
||||
static long
|
||||
fs_speex_encode_block (FishSound * fsound)
|
||||
{
|
||||
FishSoundSpeexInfo * fss = (FishSoundSpeexInfo *)fsound->codec_data;
|
||||
FishSoundSpeexEnc * fse = (FishSoundSpeexEnc *)fss->enc;
|
||||
long nencoded = fse->pcm_offset;
|
||||
|
||||
if (fsound->info.channels == 2)
|
||||
speex_encode_stereo (fss->ipcm, fse->pcm_offset, &fss->bits);
|
||||
|
||||
speex_encode (fss->st, fss->ipcm, &fss->bits);
|
||||
|
||||
fsound->frameno += fse->pcm_offset;
|
||||
fse->frame_offset++;
|
||||
|
||||
if (fse->frame_offset == fss->nframes) {
|
||||
fs_speex_encode_write (fsound);
|
||||
fse->frame_offset = 0;
|
||||
}
|
||||
|
||||
fse->pcm_offset = 0;
|
||||
|
||||
return nencoded;
|
||||
}
|
||||
|
||||
static long
|
||||
fs_speex_encode_f_ilv (FishSound * fsound, float ** pcm, long frames)
|
||||
{
|
||||
FishSoundSpeexInfo * fss = (FishSoundSpeexInfo *)fsound->codec_data;
|
||||
FishSoundSpeexEnc * fse = (FishSoundSpeexEnc *)fss->enc;
|
||||
long remaining = frames, len, nencoded = 0;
|
||||
int j, start, end;
|
||||
int channels = fsound->info.channels;
|
||||
float * p = (float *)pcm;
|
||||
|
||||
if (fss->packetno == 0)
|
||||
fs_speex_enc_headers (fsound);
|
||||
|
||||
while (remaining > 0) {
|
||||
len = MIN (remaining, fss->frame_size - fse->pcm_offset);
|
||||
|
||||
start = fse->pcm_offset * channels;
|
||||
end = (len + fse->pcm_offset) * channels;
|
||||
for (j = start; j < end; j++) {
|
||||
fss->ipcm[j] = *p++ * (float)32767.0;
|
||||
}
|
||||
|
||||
fse->pcm_offset += len;
|
||||
|
||||
if (fse->pcm_offset == fss->frame_size) {
|
||||
nencoded += fs_speex_encode_block (fsound);
|
||||
}
|
||||
|
||||
remaining -= len;
|
||||
}
|
||||
|
||||
return frames - remaining;
|
||||
}
|
||||
|
||||
static long
|
||||
fs_speex_encode_f (FishSound * fsound, float * pcm[], long frames)
|
||||
{
|
||||
FishSoundSpeexInfo * fss = (FishSoundSpeexInfo *)fsound->codec_data;
|
||||
FishSoundSpeexEnc * fse = (FishSoundSpeexEnc *)fss->enc;
|
||||
long remaining = frames, len, n = 0, nencoded = 0;
|
||||
int j, start;
|
||||
|
||||
if (fss->packetno == 0)
|
||||
fs_speex_enc_headers (fsound);
|
||||
|
||||
while (remaining > 0) {
|
||||
len = MIN (remaining, fss->frame_size - fse->pcm_offset);
|
||||
|
||||
start = fse->pcm_offset;
|
||||
fss->pcm[0] = &pcm[0][n];
|
||||
|
||||
if (fsound->info.channels == 2) {
|
||||
fss->pcm[1] = &pcm[1][n];
|
||||
_fs_interleave (fss->pcm, (float **)&fss->ipcm[start*2],
|
||||
len, 2, 32767.0);
|
||||
} else {
|
||||
for (j = 0; j < len; j++) {
|
||||
fss->ipcm[start + j] = fss->pcm[0][j] * (float)32767.0;
|
||||
}
|
||||
}
|
||||
|
||||
fse->pcm_offset += len;
|
||||
|
||||
if (fse->pcm_offset == fss->frame_size) {
|
||||
nencoded += fs_speex_encode_block (fsound);
|
||||
}
|
||||
|
||||
remaining -= len;
|
||||
n += len;
|
||||
}
|
||||
|
||||
return frames - remaining;
|
||||
}
|
||||
|
||||
static long
|
||||
fs_speex_flush (FishSound * fsound)
|
||||
{
|
||||
FishSoundSpeexInfo * fss = (FishSoundSpeexInfo *)fsound->codec_data;
|
||||
FishSoundSpeexEnc * fse = (FishSoundSpeexEnc *)fss->enc;
|
||||
long nencoded = 0;
|
||||
|
||||
if (fsound->mode != FISH_SOUND_ENCODE)
|
||||
return 0;
|
||||
|
||||
if (fse->pcm_offset > 0) {
|
||||
nencoded += fs_speex_encode_block (fsound);
|
||||
}
|
||||
|
||||
/* If, at this point, fse->frame_offset == 0, then either:
|
||||
- all remaining encoded data has just been flushed out via
|
||||
fs_speex_encode_block(), OR
|
||||
- there was no data remaining to flush at the beginning of this
|
||||
function (fse->pcm_offset == 0 && fse->frame_offset == 0)
|
||||
*/
|
||||
if (fse->frame_offset == 0) return 0;
|
||||
|
||||
while (fse->frame_offset < fss->nframes) {
|
||||
speex_bits_pack (&fss->bits, 15, 5);
|
||||
fse->frame_offset++;
|
||||
}
|
||||
|
||||
nencoded += fs_speex_encode_write (fsound);
|
||||
fse->frame_offset = 0;
|
||||
|
||||
return nencoded;
|
||||
}
|
||||
|
||||
#else /* !FS_ENCODE */
|
||||
|
||||
#define fs_speex_encode_f NULL
|
||||
#define fs_speex_encode_f_ilv NULL
|
||||
#define fs_speex_flush NULL
|
||||
|
||||
#endif
|
||||
|
||||
static int
|
||||
fs_speex_reset (FishSound * fsound)
|
||||
{
|
||||
/*FishSoundSpeexInfo * fss = (FishSoundSpeexInfo *)fsound->codec_data;*/
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
fs_speex_update (FishSound * fsound, int interleave)
|
||||
{
|
||||
FishSoundSpeexInfo * fss = (FishSoundSpeexInfo *)fsound->codec_data;
|
||||
size_t pcm_size = sizeof (float);
|
||||
float *ipcm_new, *pcm0, *pcm1;
|
||||
|
||||
ipcm_new = (float *)fs_realloc (fss->ipcm,
|
||||
pcm_size * fss->frame_size * fsound->info.channels);
|
||||
if (ipcm_new == NULL) return FISH_SOUND_ERR_OUT_OF_MEMORY;
|
||||
|
||||
fss->ipcm = ipcm_new;
|
||||
|
||||
if (interleave) {
|
||||
/* if transitioning from non-interleave to interleave,
|
||||
free non-ilv buffers */
|
||||
if (!fsound->interleave && fsound->info.channels == 2) {
|
||||
if (fss->pcm[0]) fs_free (fss->pcm[0]);
|
||||
if (fss->pcm[1]) fs_free (fss->pcm[1]);
|
||||
fss->pcm[0] = NULL;
|
||||
fss->pcm[1] = NULL;
|
||||
}
|
||||
} else {
|
||||
if (fsound->info.channels == 1) {
|
||||
fss->pcm[0] = (float *) fss->ipcm;
|
||||
} else if (fsound->info.channels == 2) {
|
||||
#if HAVE_UINTPTR_T
|
||||
/* Sanity check: frame_size is not so large that the buffer size calculations
|
||||
* would wrap. In reality, frame_size is set by libspeex according to the
|
||||
* mode index specified in the file header, and is usually equal to 320.
|
||||
*/
|
||||
if (fss->frame_size > UINTPTR_MAX / pcm_size)
|
||||
return FISH_SOUND_ERR_GENERIC;
|
||||
#endif
|
||||
|
||||
pcm0 = fs_realloc (fss->pcm[0], pcm_size * fss->frame_size);
|
||||
if (pcm0 == NULL) {
|
||||
return FISH_SOUND_ERR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
pcm1 = fs_realloc (fss->pcm[1], pcm_size * fss->frame_size);
|
||||
if (pcm1 == NULL) {
|
||||
fs_free (pcm0);
|
||||
return FISH_SOUND_ERR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
fss->pcm[0] = pcm0;
|
||||
fss->pcm[1] = pcm1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static FishSound *
|
||||
fs_speex_enc_init (FishSound * fsound)
|
||||
{
|
||||
FishSoundSpeexInfo * fss = (FishSoundSpeexInfo *)fsound->codec_data;
|
||||
FishSoundSpeexEnc * fse;
|
||||
|
||||
fse = fs_malloc (sizeof (FishSoundSpeexEnc));
|
||||
if (fse == NULL) return NULL;
|
||||
|
||||
fse->frame_offset = 0;
|
||||
fse->pcm_offset = 0;
|
||||
fse->id = 0;
|
||||
|
||||
fss->enc = fse;
|
||||
|
||||
return fsound;
|
||||
}
|
||||
|
||||
static FishSound *
|
||||
fs_speex_init (FishSound * fsound)
|
||||
{
|
||||
FishSoundSpeexInfo * fss;
|
||||
SpeexStereoState stereo_init = SPEEX_STEREO_STATE_INIT;
|
||||
|
||||
fss = fs_malloc (sizeof (FishSoundSpeexInfo));
|
||||
if (fss == NULL) return NULL;
|
||||
|
||||
fss->packetno = 0;
|
||||
fss->st = NULL;
|
||||
fss->frame_size = 0;
|
||||
fss->nframes = 1;
|
||||
fss->pcm_len = 0;
|
||||
fss->ipcm = NULL;
|
||||
fss->pcm[0] = NULL;
|
||||
fss->pcm[1] = NULL;
|
||||
|
||||
memcpy (&fss->stereo, &stereo_init, sizeof (SpeexStereoState));
|
||||
|
||||
speex_bits_init (&fss->bits);
|
||||
|
||||
fsound->codec_data = fss;
|
||||
|
||||
if (fsound->mode == FISH_SOUND_ENCODE)
|
||||
fs_speex_enc_init (fsound);
|
||||
|
||||
return fsound;
|
||||
}
|
||||
|
||||
static FishSound *
|
||||
fs_speex_delete (FishSound * fsound)
|
||||
{
|
||||
FishSoundSpeexInfo * fss = (FishSoundSpeexInfo *)fsound->codec_data;
|
||||
|
||||
fs_speex_free_buffers (fsound);
|
||||
|
||||
if (fsound->mode == FISH_SOUND_DECODE) {
|
||||
if (fss->st) speex_decoder_destroy (fss->st);
|
||||
} else if (fsound->mode == FISH_SOUND_ENCODE) {
|
||||
if (fss->st) speex_encoder_destroy (fss->st);
|
||||
if (fss->enc) fs_free (fss->enc);
|
||||
}
|
||||
speex_bits_destroy (&fss->bits);
|
||||
|
||||
fs_free (fss);
|
||||
fsound->codec_data = NULL;
|
||||
|
||||
return fsound;
|
||||
}
|
||||
|
||||
FishSoundCodec *
|
||||
fish_sound_speex_codec (void)
|
||||
{
|
||||
FishSoundCodec * codec;
|
||||
|
||||
codec = (FishSoundCodec *) fs_malloc (sizeof (FishSoundCodec));
|
||||
if (codec == NULL) return NULL;
|
||||
|
||||
codec->format.format = FISH_SOUND_SPEEX;
|
||||
codec->format.name = "Speex (Xiph.Org)";
|
||||
codec->format.extension = "spx";
|
||||
|
||||
codec->init = fs_speex_init;
|
||||
codec->del = fs_speex_delete;
|
||||
codec->reset = fs_speex_reset;
|
||||
codec->update = fs_speex_update;
|
||||
codec->command = fs_speex_command;
|
||||
codec->decode = fs_speex_decode;
|
||||
codec->encode_f = fs_speex_encode_f;
|
||||
codec->encode_f_ilv = fs_speex_encode_f_ilv;
|
||||
codec->flush = fs_speex_flush;
|
||||
|
||||
return codec;
|
||||
}
|
||||
|
||||
#else /* !HAVE_SPEEX */
|
||||
|
||||
int
|
||||
fish_sound_speex_identify (unsigned char * buf, long bytes)
|
||||
{
|
||||
return FISH_SOUND_UNKNOWN;
|
||||
}
|
||||
|
||||
FishSoundCodec *
|
||||
fish_sound_speex_codec (void)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -1,511 +0,0 @@
|
|||
/*
|
||||
Copyright (C) 2003 Commonwealth Scientific and Industrial Research
|
||||
Organisation (CSIRO) Australia
|
||||
|
||||
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.
|
||||
|
||||
- Neither the name of CSIRO Australia nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
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 ORGANISATION 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.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <ctype.h>
|
||||
|
||||
#include "private.h"
|
||||
#include "convert.h"
|
||||
|
||||
/*#define DEBUG*/
|
||||
#include "debug.h"
|
||||
|
||||
#if HAVE_VORBIS
|
||||
|
||||
#include <vorbis/codec.h>
|
||||
#if HAVE_VORBISENC
|
||||
#include <vorbis/vorbisenc.h>
|
||||
#endif
|
||||
|
||||
typedef struct _FishSoundVorbisInfo {
|
||||
int packetno;
|
||||
int finished;
|
||||
vorbis_info vi;
|
||||
vorbis_comment vc;
|
||||
vorbis_dsp_state vd; /** central working state for the PCM->packet encoder */
|
||||
vorbis_block vb; /** local working space for PCM->packet encode */
|
||||
float ** pcm; /** ongoing pcm working space for decoder (stateful) */
|
||||
float * ipcm; /** interleaved pcm for interfacing with user */
|
||||
long max_pcm;
|
||||
} FishSoundVorbisInfo;
|
||||
|
||||
int
|
||||
fish_sound_vorbis_identify (unsigned char * buf, long bytes)
|
||||
{
|
||||
struct vorbis_info vi;
|
||||
struct vorbis_comment vc;
|
||||
ogg_packet op;
|
||||
int ret, id = FISH_SOUND_UNKNOWN;
|
||||
|
||||
if (!strncmp ((char *)&buf[1], "vorbis", 6)) {
|
||||
/* if only a short buffer was passed, do a weak identify */
|
||||
if (bytes == 8) return FISH_SOUND_VORBIS;
|
||||
|
||||
/* otherwise, assume the buffer is an entire initial header and
|
||||
* feed it to vorbis_synthesis_headerin() */
|
||||
|
||||
vorbis_info_init (&vi);
|
||||
vorbis_comment_init (&vc);
|
||||
|
||||
op.packet = buf;
|
||||
op.bytes = bytes;
|
||||
op.b_o_s = 1;
|
||||
op.e_o_s = 0;
|
||||
op.granulepos = 0;
|
||||
op.packetno = 0;
|
||||
|
||||
if ((ret = vorbis_synthesis_headerin (&vi, &vc, &op)) == 0) {
|
||||
if (vi.rate != 0) id = FISH_SOUND_VORBIS;
|
||||
} else {
|
||||
debug_printf (1, "vorbis_synthesis_headerin returned %d", ret);
|
||||
}
|
||||
|
||||
vorbis_info_clear (&vi);
|
||||
}
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
static int
|
||||
fs_vorbis_command (FishSound * fsound, int command, void * data,
|
||||
int datasize)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if FS_DECODE
|
||||
static long
|
||||
fs_vorbis_decode (FishSound * fsound, unsigned char * buf, long bytes)
|
||||
{
|
||||
FishSoundVorbisInfo * fsv = (FishSoundVorbisInfo *)fsound->codec_data;
|
||||
ogg_packet op;
|
||||
long samples;
|
||||
float * pcm_new;
|
||||
int ret;
|
||||
|
||||
/* Make an ogg_packet structure to pass the data to libvorbis */
|
||||
op.packet = buf;
|
||||
op.bytes = bytes;
|
||||
op.b_o_s = (fsv->packetno == 0) ? 1 : 0;
|
||||
op.e_o_s = fsound->next_eos;
|
||||
op.granulepos = fsound->next_granulepos;
|
||||
op.packetno = fsv->packetno;
|
||||
|
||||
if (fsv->packetno < 3) {
|
||||
|
||||
if ((ret = vorbis_synthesis_headerin (&fsv->vi, &fsv->vc, &op)) == 0) {
|
||||
if (fsv->vi.rate != 0) {
|
||||
debug_printf (1, "Got vorbis info: version %d\tchannels %d\trate %ld",
|
||||
fsv->vi.version, fsv->vi.channels, fsv->vi.rate);
|
||||
fsound->info.samplerate = fsv->vi.rate;
|
||||
fsound->info.channels = fsv->vi.channels;
|
||||
}
|
||||
}
|
||||
|
||||
/* Decode comments from packet 1. Vorbis has 7 bytes of marker at the
|
||||
* start of vorbiscomment packet. */
|
||||
if (fsv->packetno == 1 && bytes > 7 && buf[0] == 0x03 &&
|
||||
!strncmp ((char *)&buf[1], "vorbis", 6)) {
|
||||
if (fish_sound_comments_decode (fsound, buf+7, bytes-7) == FISH_SOUND_ERR_OUT_OF_MEMORY) {
|
||||
fsv->packetno++;
|
||||
return FISH_SOUND_ERR_OUT_OF_MEMORY;
|
||||
}
|
||||
} else if (fsv->packetno == 2) {
|
||||
vorbis_synthesis_init (&fsv->vd, &fsv->vi);
|
||||
vorbis_block_init (&fsv->vd, &fsv->vb);
|
||||
}
|
||||
} else {
|
||||
FishSoundDecoded_FloatIlv df;
|
||||
FishSoundDecoded_Float dfi;
|
||||
int r;
|
||||
if ((r = vorbis_synthesis (&fsv->vb, &op)) == 0)
|
||||
vorbis_synthesis_blockin (&fsv->vd, &fsv->vb);
|
||||
|
||||
if (r == OV_EBADPACKET) {
|
||||
return FISH_SOUND_ERR_GENERIC;
|
||||
}
|
||||
|
||||
while ((samples = vorbis_synthesis_pcmout (&fsv->vd, &fsv->pcm)) > 0) {
|
||||
vorbis_synthesis_read (&fsv->vd, samples);
|
||||
|
||||
if (fsound->frameno != -1)
|
||||
fsound->frameno += samples;
|
||||
|
||||
if (fsound->interleave) {
|
||||
if (samples > fsv->max_pcm) {
|
||||
pcm_new = realloc (fsv->ipcm, sizeof(float) * samples *
|
||||
fsound->info.channels);
|
||||
if (pcm_new == NULL) {
|
||||
/* Allocation failure; just truncate here, fail gracefully elsewhere */
|
||||
samples = fsv->max_pcm;
|
||||
} else {
|
||||
fsv->ipcm = pcm_new;
|
||||
fsv->max_pcm = samples;
|
||||
}
|
||||
}
|
||||
_fs_interleave (fsv->pcm, (float **)fsv->ipcm, samples,
|
||||
fsound->info.channels, 1.0);
|
||||
|
||||
dfi = (FishSoundDecoded_FloatIlv)fsound->callback.decoded_float_ilv;
|
||||
dfi (fsound, (float **)fsv->ipcm, samples, fsound->user_data);
|
||||
} else {
|
||||
df = (FishSoundDecoded_Float)fsound->callback.decoded_float;
|
||||
df (fsound, fsv->pcm, samples, fsound->user_data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (fsound->next_granulepos != -1) {
|
||||
fsound->frameno = fsound->next_granulepos;
|
||||
fsound->next_granulepos = -1;
|
||||
}
|
||||
|
||||
fsv->packetno++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#else /* !FS_DECODE */
|
||||
|
||||
#define fs_vorbis_decode NULL
|
||||
|
||||
#endif
|
||||
|
||||
#if FS_ENCODE && HAVE_VORBISENC
|
||||
|
||||
static FishSound *
|
||||
fs_vorbis_enc_headers (FishSound * fsound)
|
||||
{
|
||||
FishSoundVorbisInfo * fsv = (FishSoundVorbisInfo *)fsound->codec_data;
|
||||
const FishSoundComment * comment;
|
||||
ogg_packet header;
|
||||
ogg_packet header_comm;
|
||||
ogg_packet header_code;
|
||||
|
||||
/* Vorbis streams begin with three headers:
|
||||
* 1. The initial header (with most of the codec setup parameters),
|
||||
* which is mandated by the Ogg bitstream spec,
|
||||
* 2. The second header which holds any comment fields,
|
||||
* 3. The third header which contains the bitstream codebook.
|
||||
* We merely need to make the headers, then pass them to libvorbis one at
|
||||
* a time; libvorbis handles the additional Ogg bitstream constraints.
|
||||
*/
|
||||
|
||||
/* Update the comments */
|
||||
for (comment = fish_sound_comment_first (fsound); comment;
|
||||
comment = fish_sound_comment_next (fsound, comment)) {
|
||||
debug_printf (1, "%s = %s", comment->name, comment->value);
|
||||
vorbis_comment_add_tag (&fsv->vc, comment->name, comment->value);
|
||||
}
|
||||
|
||||
/* Generate the headers */
|
||||
vorbis_analysis_headerout(&fsv->vd, &fsv->vc,
|
||||
&header, &header_comm, &header_code);
|
||||
|
||||
/* Pass the generated headers to the user */
|
||||
if (fsound->callback.encoded) {
|
||||
FishSoundEncoded encoded = (FishSoundEncoded)fsound->callback.encoded;
|
||||
|
||||
encoded (fsound, header.packet, header.bytes, fsound->user_data);
|
||||
encoded (fsound, header_comm.packet, header_comm.bytes,
|
||||
fsound->user_data);
|
||||
encoded (fsound, header_code.packet, header_code.bytes,
|
||||
fsound->user_data);
|
||||
fsv->packetno = 3;
|
||||
}
|
||||
|
||||
return fsound;
|
||||
}
|
||||
|
||||
static long
|
||||
fs_vorbis_encode_write (FishSound * fsound, long len)
|
||||
{
|
||||
FishSoundVorbisInfo * fsv = (FishSoundVorbisInfo *)fsound->codec_data;
|
||||
ogg_packet op;
|
||||
|
||||
vorbis_analysis_wrote (&fsv->vd, len);
|
||||
|
||||
while (vorbis_analysis_blockout (&fsv->vd, &fsv->vb) == 1) {
|
||||
vorbis_analysis (&fsv->vb, NULL);
|
||||
vorbis_bitrate_addblock (&fsv->vb);
|
||||
|
||||
while (vorbis_bitrate_flushpacket (&fsv->vd, &op)) {
|
||||
if (fsound->callback.encoded) {
|
||||
FishSoundEncoded encoded = (FishSoundEncoded)fsound->callback.encoded;
|
||||
|
||||
if (op.granulepos != -1)
|
||||
fsound->frameno = op.granulepos;
|
||||
|
||||
encoded (fsound, op.packet, op.bytes, fsound->user_data);
|
||||
|
||||
fsv->packetno++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static int
|
||||
fs_vorbis_finish (FishSound * fsound)
|
||||
{
|
||||
FishSoundVorbisInfo * fsv = (FishSoundVorbisInfo *)fsound->codec_data;
|
||||
|
||||
if (!fsv->finished) {
|
||||
if (fsound->mode == FISH_SOUND_ENCODE) {
|
||||
fs_vorbis_encode_write (fsound, 0);
|
||||
}
|
||||
fsv->finished = 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static long
|
||||
fs_vorbis_encode_f_ilv (FishSound * fsound, float ** pcm, long frames)
|
||||
{
|
||||
FishSoundVorbisInfo * fsv = (FishSoundVorbisInfo *)fsound->codec_data;
|
||||
float ** vpcm;
|
||||
long len, remaining = frames;
|
||||
float * d = (float *)pcm;
|
||||
|
||||
if (fsv->packetno == 0) {
|
||||
fs_vorbis_enc_headers (fsound);
|
||||
}
|
||||
|
||||
if (frames == 0) {
|
||||
fs_vorbis_finish (fsound);
|
||||
return 0;
|
||||
}
|
||||
|
||||
while (remaining > 0) {
|
||||
len = MIN (1024, remaining);
|
||||
|
||||
/* expose the buffer to submit data */
|
||||
vpcm = vorbis_analysis_buffer (&fsv->vd, 1024);
|
||||
|
||||
_fs_deinterleave ((float **)d, vpcm, len, fsound->info.channels, 1.0);
|
||||
|
||||
d += (len * fsound->info.channels);
|
||||
|
||||
fs_vorbis_encode_write (fsound, len);
|
||||
|
||||
remaining -= len;
|
||||
}
|
||||
|
||||
/**
|
||||
* End of input. Tell libvorbis we're at the end of stream so that it can
|
||||
* handle the last frame and mark the end of stream in the output properly.
|
||||
*/
|
||||
if (fsound->next_eos)
|
||||
fs_vorbis_finish (fsound);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static long
|
||||
fs_vorbis_encode_f (FishSound * fsound, float * pcm[], long frames)
|
||||
{
|
||||
FishSoundVorbisInfo * fsv = (FishSoundVorbisInfo *)fsound->codec_data;
|
||||
float ** vpcm;
|
||||
long len, remaining = frames;
|
||||
int i;
|
||||
|
||||
if (fsv->packetno == 0) {
|
||||
fs_vorbis_enc_headers (fsound);
|
||||
}
|
||||
|
||||
if (frames == 0) {
|
||||
fs_vorbis_finish (fsound);
|
||||
return 0;
|
||||
}
|
||||
|
||||
while (remaining > 0) {
|
||||
len = MIN (1024, remaining);
|
||||
|
||||
debug_printf (1, "processing %ld frames", len);
|
||||
|
||||
/* expose the buffer to submit data */
|
||||
vpcm = vorbis_analysis_buffer (&fsv->vd, 1024);
|
||||
|
||||
for (i = 0; i < fsound->info.channels; i++) {
|
||||
memcpy (vpcm[i], pcm[i], sizeof (float) * len);
|
||||
}
|
||||
|
||||
fs_vorbis_encode_write (fsound, len);
|
||||
|
||||
remaining -= len;
|
||||
}
|
||||
|
||||
/**
|
||||
* End of input. Tell libvorbis we're at the end of stream so that it can
|
||||
* handle the last frame and mark the end of stream in the output properly.
|
||||
*/
|
||||
if (fsound->next_eos)
|
||||
fs_vorbis_finish (fsound);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static FishSound *
|
||||
fs_vorbis_enc_init (FishSound * fsound)
|
||||
{
|
||||
FishSoundVorbisInfo * fsv = (FishSoundVorbisInfo *)fsound->codec_data;
|
||||
|
||||
debug_printf (1, "Vorbis enc init: %d channels, %d Hz", fsound->info.channels,
|
||||
fsound->info.samplerate);
|
||||
|
||||
vorbis_encode_init_vbr (&fsv->vi, fsound->info.channels,
|
||||
fsound->info.samplerate, (float)0.3 /* quality */);
|
||||
|
||||
/* set up the analysis state and auxiliary encoding storage */
|
||||
vorbis_analysis_init (&fsv->vd, &fsv->vi);
|
||||
vorbis_block_init (&fsv->vd, &fsv->vb);
|
||||
|
||||
return fsound;
|
||||
}
|
||||
|
||||
#else /* ! FS_ENCODE && HAVE_VORBISENC */
|
||||
|
||||
#define fs_vorbis_encode_f NULL
|
||||
#define fs_vorbis_encode_f_ilv NULL
|
||||
#define fs_vorbis_finish NULL
|
||||
|
||||
#endif /* ! FS_ENCODE && HAVE_VORBISENC */
|
||||
|
||||
static int
|
||||
fs_vorbis_reset (FishSound * fsound)
|
||||
{
|
||||
FishSoundVorbisInfo * fsv = (FishSoundVorbisInfo *)fsound->codec_data;
|
||||
|
||||
vorbis_block_init (&fsv->vd, &fsv->vb);
|
||||
fsv->packetno = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static FishSound *
|
||||
fs_vorbis_init (FishSound * fsound)
|
||||
{
|
||||
FishSoundVorbisInfo * fsv;
|
||||
|
||||
fsv = fs_malloc (sizeof (FishSoundVorbisInfo));
|
||||
if (fsv == NULL) return NULL;
|
||||
|
||||
fsv->packetno = 0;
|
||||
fsv->finished = 0;
|
||||
vorbis_info_init (&fsv->vi);
|
||||
vorbis_comment_init (&fsv->vc);
|
||||
memset(&fsv->vd, 0, sizeof(fsv->vd));
|
||||
vorbis_block_init (&fsv->vd, &fsv->vb);
|
||||
fsv->pcm = NULL;
|
||||
fsv->ipcm = NULL;
|
||||
fsv->max_pcm = 0;
|
||||
|
||||
fsound->codec_data = fsv;
|
||||
|
||||
#if FS_ENCODE && HAVE_VORBISENC
|
||||
|
||||
if (fsound->mode == FISH_SOUND_ENCODE) {
|
||||
fs_vorbis_enc_init (fsound);
|
||||
}
|
||||
|
||||
#endif /* FS_ENCODE && HAVE_VORBISENC */
|
||||
|
||||
return fsound;
|
||||
}
|
||||
|
||||
static FishSound *
|
||||
fs_vorbis_delete (FishSound * fsound)
|
||||
{
|
||||
FishSoundVorbisInfo * fsv = (FishSoundVorbisInfo *)fsound->codec_data;
|
||||
|
||||
#if FS_ENCODE && HAVE_VORBISENC
|
||||
fs_vorbis_finish (fsound);
|
||||
#endif /* FS_ENCODE && HAVE_VORBISENC */
|
||||
|
||||
if (fsv->ipcm) fs_free (fsv->ipcm);
|
||||
|
||||
vorbis_block_clear (&fsv->vb);
|
||||
vorbis_dsp_clear (&fsv->vd);
|
||||
vorbis_comment_clear (&fsv->vc);
|
||||
vorbis_info_clear (&fsv->vi);
|
||||
|
||||
fs_free (fsv);
|
||||
fsound->codec_data = NULL;
|
||||
|
||||
return fsound;
|
||||
}
|
||||
|
||||
FishSoundCodec *
|
||||
fish_sound_vorbis_codec (void)
|
||||
{
|
||||
FishSoundCodec * codec;
|
||||
|
||||
codec = (FishSoundCodec *) fs_malloc (sizeof (FishSoundCodec));
|
||||
if (codec == NULL) return NULL;
|
||||
|
||||
codec->format.format = FISH_SOUND_VORBIS;
|
||||
codec->format.name = "Vorbis (Xiph.Org)";
|
||||
codec->format.extension = "ogg";
|
||||
|
||||
codec->init = fs_vorbis_init;
|
||||
codec->del = fs_vorbis_delete;
|
||||
codec->reset = fs_vorbis_reset;
|
||||
codec->update = NULL; /* XXX */
|
||||
codec->command = fs_vorbis_command;
|
||||
codec->decode = fs_vorbis_decode;
|
||||
codec->encode_f = fs_vorbis_encode_f;
|
||||
codec->encode_f_ilv = fs_vorbis_encode_f_ilv;
|
||||
codec->flush = NULL;
|
||||
|
||||
return codec;
|
||||
}
|
||||
|
||||
#else /* !HAVE_VORBIS */
|
||||
|
||||
int
|
||||
fish_sound_vorbis_identify (unsigned char * buf, long bytes)
|
||||
{
|
||||
return FISH_SOUND_UNKNOWN;
|
||||
}
|
||||
|
||||
FishSoundCodec *
|
||||
fish_sound_vorbis_codec (void)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,57 +0,0 @@
|
|||
/*
|
||||
Copyright (C) 2003 Commonwealth Scientific and Industrial Research
|
||||
Organisation (CSIRO) Australia
|
||||
|
||||
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.
|
||||
|
||||
- Neither the name of CSIRO Australia nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
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 ORGANISATION 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.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
/* WINDOWS */
|
||||
#ifdef _WIN32
|
||||
#define inline __inline
|
||||
#define alloca _alloca
|
||||
#define strncasecmp _strnicmp
|
||||
#define snprintf _snprintf
|
||||
#ifndef __SYMBIAN32__
|
||||
#define strcasecmp _stricmp
|
||||
#endif /* ! __SYMBIAN32__ */
|
||||
#endif
|
||||
|
||||
/* malloc/realloc/free macros */
|
||||
#ifndef fs_malloc
|
||||
#define fs_malloc malloc
|
||||
#endif
|
||||
|
||||
#ifndef fs_realloc
|
||||
#define fs_realloc realloc
|
||||
#endif
|
||||
|
||||
#ifndef fs_free
|
||||
#define fs_free free
|
||||
#endif
|
|
@ -1,237 +0,0 @@
|
|||
/*
|
||||
Copyright (C) 2003 Commonwealth Scientific and Industrial Research
|
||||
Organisation (CSIRO) Australia
|
||||
|
||||
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.
|
||||
|
||||
- Neither the name of CSIRO Australia nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
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 ORGANISATION 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.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "fs_compat.h"
|
||||
|
||||
typedef int (*FishSoundFunc) (void * data);
|
||||
typedef int (*FishSoundCmpFunc) (const void * data1, const void * data2);
|
||||
|
||||
typedef struct _FishSoundVector FishSoundVector;
|
||||
|
||||
struct _FishSoundVector {
|
||||
int max_elements;
|
||||
int nr_elements;
|
||||
FishSoundCmpFunc cmp;
|
||||
void ** data;
|
||||
};
|
||||
|
||||
/*
|
||||
* A vector of void *. New elements will be appended at the tail.
|
||||
*/
|
||||
|
||||
FishSoundVector *
|
||||
fs_vector_new (FishSoundCmpFunc cmp)
|
||||
{
|
||||
FishSoundVector * vector;
|
||||
|
||||
vector = fs_malloc (sizeof (FishSoundVector));
|
||||
if (vector == NULL) return NULL;
|
||||
|
||||
vector->max_elements = 0;
|
||||
vector->nr_elements = 0;
|
||||
vector->cmp = cmp;
|
||||
vector->data = NULL;
|
||||
|
||||
return vector;
|
||||
}
|
||||
|
||||
static void
|
||||
fs_vector_clear (FishSoundVector * vector)
|
||||
{
|
||||
fs_free (vector->data);
|
||||
vector->data = NULL;
|
||||
vector->nr_elements = 0;
|
||||
vector->max_elements = 0;
|
||||
}
|
||||
|
||||
void
|
||||
fs_vector_delete (FishSoundVector * vector)
|
||||
{
|
||||
fs_vector_clear (vector);
|
||||
fs_free (vector);
|
||||
}
|
||||
|
||||
int
|
||||
fs_vector_size (FishSoundVector * vector)
|
||||
{
|
||||
if (vector == NULL) return 0;
|
||||
|
||||
return vector->nr_elements;
|
||||
}
|
||||
|
||||
void *
|
||||
fs_vector_nth (FishSoundVector * vector, int n)
|
||||
{
|
||||
if (vector == NULL) return NULL;
|
||||
|
||||
if (n >= vector->nr_elements) return NULL;
|
||||
|
||||
return vector->data[n];
|
||||
}
|
||||
|
||||
int
|
||||
fs_vector_find_index (FishSoundVector * vector, const void * data)
|
||||
{
|
||||
void * v_data;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < vector->nr_elements; i++) {
|
||||
v_data = vector->data[i];
|
||||
if (vector->cmp (v_data, data))
|
||||
return i;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
void *
|
||||
fs_vector_find (FishSoundVector * vector, const void * data)
|
||||
{
|
||||
void * v_data;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < vector->nr_elements; i++) {
|
||||
v_data = vector->data[i];
|
||||
if (vector->cmp (v_data, data))
|
||||
return v_data;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int
|
||||
fs_vector_foreach (FishSoundVector * vector, FishSoundFunc func)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < vector->nr_elements; i++) {
|
||||
func (vector->data[i]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static FishSoundVector *
|
||||
fs_vector_grow (FishSoundVector * vector)
|
||||
{
|
||||
void * new_elements;
|
||||
int new_max_elements;
|
||||
|
||||
vector->nr_elements++;
|
||||
|
||||
if (vector->nr_elements > vector->max_elements) {
|
||||
if (vector->max_elements == 0) {
|
||||
new_max_elements = 1;
|
||||
} else {
|
||||
new_max_elements = vector->max_elements * 2;
|
||||
}
|
||||
|
||||
new_elements =
|
||||
fs_realloc (vector->data, (size_t)new_max_elements * sizeof (void *));
|
||||
|
||||
if (new_elements == NULL) {
|
||||
vector->nr_elements--;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
vector->max_elements = new_max_elements;
|
||||
vector->data = new_elements;
|
||||
}
|
||||
|
||||
return vector;
|
||||
}
|
||||
|
||||
void *
|
||||
fs_vector_insert (FishSoundVector * vector, void * data)
|
||||
{
|
||||
if (vector == NULL) return NULL;
|
||||
|
||||
if (fs_vector_grow (vector) == NULL)
|
||||
return NULL;
|
||||
|
||||
vector->data[vector->nr_elements-1] = data;
|
||||
|
||||
return data;
|
||||
|
||||
}
|
||||
|
||||
static void *
|
||||
fs_vector_remove_nth (FishSoundVector * vector, int n)
|
||||
{
|
||||
int i;
|
||||
void * new_elements;
|
||||
int new_max_elements;
|
||||
|
||||
vector->nr_elements--;
|
||||
|
||||
if (vector->nr_elements == 0) {
|
||||
fs_vector_clear (vector);
|
||||
} else {
|
||||
for (i = n; i < vector->nr_elements; i++) {
|
||||
vector->data[i] = vector->data[i+1];
|
||||
}
|
||||
|
||||
if (vector->nr_elements < vector->max_elements/2) {
|
||||
new_max_elements = vector->max_elements/2;
|
||||
|
||||
new_elements =
|
||||
fs_realloc (vector->data,
|
||||
(size_t)new_max_elements * sizeof (void *));
|
||||
|
||||
if (new_elements == NULL)
|
||||
return NULL;
|
||||
|
||||
vector->max_elements = new_max_elements;
|
||||
vector->data = new_elements;
|
||||
}
|
||||
}
|
||||
|
||||
return vector;
|
||||
}
|
||||
|
||||
FishSoundVector *
|
||||
fs_vector_remove (FishSoundVector * vector, void * data)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < vector->nr_elements; i++) {
|
||||
if (vector->data[i] == data) {
|
||||
return fs_vector_remove_nth (vector, i);
|
||||
}
|
||||
}
|
||||
|
||||
return vector;
|
||||
}
|
|
@ -1,80 +0,0 @@
|
|||
/*
|
||||
Copyright (C) 2003 Commonwealth Scientific and Industrial Research
|
||||
Organisation (CSIRO) Australia
|
||||
|
||||
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.
|
||||
|
||||
- Neither the name of CSIRO Australia nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
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 ORGANISATION 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 __FS_VECTOR_H__
|
||||
#define __FS_VECTOR_H__
|
||||
|
||||
typedef void FishSoundVector;
|
||||
|
||||
typedef int (*FishSoundFunc) (void * data);
|
||||
typedef int (*FishSoundCmpFunc) (void * data1, void * data2);
|
||||
|
||||
FishSoundVector *
|
||||
fs_vector_new (FishSoundCmpFunc cmp);
|
||||
|
||||
void
|
||||
fs_vector_delete (FishSoundVector * vector);
|
||||
|
||||
void *
|
||||
fs_vector_nth (FishSoundVector * vector, int n);
|
||||
|
||||
int
|
||||
fs_vector_find_index (FishSoundVector * vector, const void * data);
|
||||
|
||||
void *
|
||||
fs_vector_find (FishSoundVector * vector, const void * data);
|
||||
|
||||
int
|
||||
fs_vector_foreach (FishSoundVector * vector, FishSoundFunc func);
|
||||
|
||||
int
|
||||
fs_vector_size (FishSoundVector * vector);
|
||||
|
||||
/**
|
||||
* Add an element to a vector.
|
||||
* \param vector An FishSoundVector
|
||||
* \param data The new element to add
|
||||
* \retval data If the element was successfully added
|
||||
* \retval NULL If adding the element failed due to a realloc() error
|
||||
*/
|
||||
void *
|
||||
fs_vector_insert (FishSoundVector * vector, void * data);
|
||||
|
||||
/**
|
||||
* Remove a (void *) element of a vector
|
||||
* \retval \a vector on success
|
||||
* \retval NULL on failure (realloc error)
|
||||
*/
|
||||
FishSoundVector *
|
||||
fs_vector_remove (FishSoundVector * vector, void * data);
|
||||
|
||||
#endif /* __FS_VECTOR_H__ */
|
|
@ -1,189 +0,0 @@
|
|||
/*
|
||||
Copyright (C) 2003 Commonwealth Scientific and Industrial Research
|
||||
Organisation (CSIRO) Australia
|
||||
|
||||
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.
|
||||
|
||||
- Neither the name of CSIRO Australia nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
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 ORGANISATION 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 __FISH_SOUND_PRIVATE_H__
|
||||
#define __FISH_SOUND_PRIVATE_H__
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "fs_compat.h"
|
||||
#include "fs_vector.h"
|
||||
|
||||
#include <fishsound/constants.h>
|
||||
|
||||
#undef MIN
|
||||
#define MIN(a,b) (((a)<(b))?(a):(b))
|
||||
|
||||
typedef struct _FishSound FishSound;
|
||||
typedef struct _FishSoundInfo FishSoundInfo;
|
||||
typedef struct _FishSoundCodec FishSoundCodec;
|
||||
typedef struct _FishSoundFormat FishSoundFormat;
|
||||
typedef struct _FishSoundComment FishSoundComment;
|
||||
|
||||
typedef int (*FSCodecIdentify) (unsigned char * buf, long bytes);
|
||||
typedef FishSound * (*FSCodecInit) (FishSound * fsound);
|
||||
typedef FishSound * (*FSCodecDelete) (FishSound * fsound);
|
||||
typedef int (*FSCodecReset) (FishSound * fsound);
|
||||
typedef int (*FSCodecUpdate) (FishSound * fsound, int interleave);
|
||||
typedef int (*FSCodecCommand) (FishSound * fsound, int command,
|
||||
void * data, int datasize);
|
||||
typedef long (*FSCodecDecode) (FishSound * fsound, unsigned char * buf,
|
||||
long bytes);
|
||||
typedef long (*FSCodecEncode_Float) (FishSound * fsound, float * pcm[],
|
||||
long frames);
|
||||
typedef long (*FSCodecEncode_FloatIlv) (FishSound * fsound,
|
||||
float ** pcm, long frames);
|
||||
typedef long (*FSCodecFlush) (FishSound * fsound);
|
||||
|
||||
#include <fishsound/decode.h>
|
||||
#include <fishsound/encode.h>
|
||||
|
||||
struct _FishSoundFormat {
|
||||
int format;
|
||||
const char * name;
|
||||
const char * extension;
|
||||
};
|
||||
|
||||
struct _FishSoundCodec {
|
||||
struct _FishSoundFormat format;
|
||||
FSCodecInit init;
|
||||
FSCodecDelete del;
|
||||
FSCodecReset reset;
|
||||
FSCodecUpdate update;
|
||||
FSCodecCommand command;
|
||||
FSCodecDecode decode;
|
||||
FSCodecEncode_FloatIlv encode_f_ilv;
|
||||
FSCodecEncode_Float encode_f;
|
||||
FSCodecFlush flush;
|
||||
};
|
||||
|
||||
struct _FishSoundInfo {
|
||||
int samplerate;
|
||||
int channels;
|
||||
int format;
|
||||
};
|
||||
|
||||
struct _FishSoundComment {
|
||||
char * name;
|
||||
char * value;
|
||||
};
|
||||
|
||||
union FishSoundCallback {
|
||||
FishSoundDecoded_Float decoded_float;
|
||||
FishSoundDecoded_FloatIlv decoded_float_ilv;
|
||||
FishSoundEncoded encoded;
|
||||
};
|
||||
|
||||
struct _FishSound {
|
||||
/** FISH_SOUND_DECODE or FISH_SOUND_ENCODE */
|
||||
FishSoundMode mode;
|
||||
|
||||
/** General info related to sound */
|
||||
FishSoundInfo info;
|
||||
|
||||
/** Interleave boolean */
|
||||
int interleave;
|
||||
|
||||
/**
|
||||
* Current frameno.
|
||||
*/
|
||||
long frameno;
|
||||
|
||||
/**
|
||||
* Truncation frameno for the next block of data sent to decode.
|
||||
* In Ogg encapsulation, this is represented by the Ogg packet's
|
||||
* "granulepos" field.
|
||||
*/
|
||||
long next_granulepos;
|
||||
|
||||
/**
|
||||
* Flag if the next block of data sent to decode will be the last one
|
||||
* for this stream (eos = End Of Stream).
|
||||
* In Ogg encapsulation, this is represented by the Ogg packet's
|
||||
* "eos" field.
|
||||
*/
|
||||
int next_eos;
|
||||
|
||||
/** The codec class structure */
|
||||
FishSoundCodec * codec;
|
||||
|
||||
/** codec specific data */
|
||||
void * codec_data;
|
||||
|
||||
/* encode or decode callback */
|
||||
union FishSoundCallback callback;
|
||||
|
||||
/** user data for encode/decode callback */
|
||||
void * user_data;
|
||||
|
||||
/** The comments */
|
||||
char * vendor;
|
||||
FishSoundVector * comments;
|
||||
};
|
||||
|
||||
int fish_sound_identify (unsigned char * buf, long bytes);
|
||||
int fish_sound_set_format (FishSound * fsound, int format);
|
||||
|
||||
/* Format specific interfaces */
|
||||
int fish_sound_vorbis_identify (unsigned char * buf, long bytes);
|
||||
FishSoundCodec * fish_sound_vorbis_codec (void);
|
||||
|
||||
int fish_sound_speex_identify (unsigned char * buf, long bytes);
|
||||
FishSoundCodec * fish_sound_speex_codec (void);
|
||||
|
||||
int fish_sound_flac_identify (unsigned char * buf, long bytes);
|
||||
FishSoundCodec * fish_sound_flac_codec (void);
|
||||
|
||||
/* comments */
|
||||
int fish_sound_comments_init (FishSound * fsound);
|
||||
int fish_sound_comments_free (FishSound * fsound);
|
||||
int fish_sound_comments_decode (FishSound * fsound, unsigned char * buf,
|
||||
long bytes);
|
||||
long fish_sound_comments_encode (FishSound * fsound, unsigned char * buf,
|
||||
long length);
|
||||
|
||||
/**
|
||||
* Set the vendor string.
|
||||
* \param fsound A FishSound* handle (created with FISH_SOUND_ENCODE)
|
||||
* \param vendor The vendor string.
|
||||
* \retval 0 Success
|
||||
* \retval FISH_SOUND_ERR_BAD \a fsound is not a valid FishSound* handle
|
||||
* \retval FISH_SOUND_ERR_INVALID Operation not suitable for this FishSound
|
||||
*/
|
||||
int
|
||||
fish_sound_comment_set_vendor (FishSound * fsound, const char * vendor);
|
||||
|
||||
const FishSoundComment * fish_sound_comment_first (FishSound * fsound);
|
||||
const FishSoundComment *
|
||||
fish_sound_comment_next (FishSound * fsound, const FishSoundComment * comment);
|
||||
|
||||
#endif /* __FISH_SOUND_PRIVATE_H__ */
|
|
@ -1,47 +0,0 @@
|
|||
diff --git a/media/libfishsound/src/libfishsound/fishsound_comments.c b/media/libfishsound/src/libfishsound/fishsound_comments.c
|
||||
index b71164f..414e210 100644
|
||||
--- a/media/libfishsound/src/libfishsound/fishsound_comments.c
|
||||
+++ b/media/libfishsound/src/libfishsound/fishsound_comments.c
|
||||
@@ -290,7 +290,9 @@ fish_sound_comment_next_byname (FishSound * fsound,
|
||||
int
|
||||
fish_sound_comment_add (FishSound * fsound, FishSoundComment * comment)
|
||||
{
|
||||
+#if FS_ENCODE
|
||||
FishSoundComment * new_comment;
|
||||
+#endif
|
||||
|
||||
if (fsound == NULL) return FISH_SOUND_ERR_BAD;
|
||||
|
||||
@@ -317,7 +319,9 @@ int
|
||||
fish_sound_comment_add_byname (FishSound * fsound, const char * name,
|
||||
const char * value)
|
||||
{
|
||||
+#if FS_ENCODE
|
||||
FishSoundComment * comment;
|
||||
+#endif
|
||||
|
||||
if (fsound == NULL) return FISH_SOUND_ERR_BAD;
|
||||
|
||||
@@ -346,7 +350,9 @@ fish_sound_comment_add_byname (FishSound * fsound, const char * name,
|
||||
int
|
||||
fish_sound_comment_remove (FishSound * fsound, FishSoundComment * comment)
|
||||
{
|
||||
+#if FS_ENCODE
|
||||
FishSoundComment * v_comment;
|
||||
+#endif
|
||||
|
||||
if (fsound == NULL) return FISH_SOUND_ERR_BAD;
|
||||
|
||||
@@ -372,8 +378,11 @@ fish_sound_comment_remove (FishSound * fsound, FishSoundComment * comment)
|
||||
int
|
||||
fish_sound_comment_remove_byname (FishSound * fsound, char * name)
|
||||
{
|
||||
+#if FS_ENCODE
|
||||
FishSoundComment * comment;
|
||||
- int i, ret = 0;
|
||||
+ int i;
|
||||
+#endif
|
||||
+ int ret = 0;
|
||||
|
||||
if (fsound == NULL) return FISH_SOUND_ERR_BAD;
|
||||
|
|
@ -1,46 +0,0 @@
|
|||
# Usage: cp $1/update.sh <libfishsound_src_directory>
|
||||
#
|
||||
# Copies the needed files from a directory containing the original
|
||||
# libfishsound source that we need for the Mozilla HTML5 media support.
|
||||
cp $1/config.h ./include/fishsound/config.h
|
||||
echo "#undef FS_ENCODE" >>./include/fishsound/config.h
|
||||
echo "#define FS_ENCODE 0" >>./include/fishsound/config.h
|
||||
echo "#undef HAVE_FLAC" >>./include/fishsound/config.h
|
||||
echo "#define HAVE_FLAC 0" >>./include/fishsound/config.h
|
||||
echo "#undef HAVE_OGGZ" >>./include/fishsound/config.h
|
||||
echo "#define HAVE_OGGZ 1" >>./include/fishsound/config.h
|
||||
echo "#undef HAVE_SPEEX" >>./include/fishsound/config.h
|
||||
echo "#define HAVE_SPEEX 0" >>./include/fishsound/config.h
|
||||
echo "#undef HAVE_VORBIS" >>./include/fishsound/config.h
|
||||
echo "#define HAVE_VORBIS 1" >>./include/fishsound/config.h
|
||||
echo "#undef HAVE_VORBISENC" >>./include/fishsound/config.h
|
||||
echo "#define HAVE_VORBISENC 0" >>./include/fishsound/config.h
|
||||
echo "#undef DEBUG" >>./include/fishsound/config.h
|
||||
cp $1/include/fishsound/encode.h ./include/fishsound/encode.h
|
||||
cp $1/include/fishsound/comments.h ./include/fishsound/comments.h
|
||||
cp $1/include/fishsound/deprecated.h ./include/fishsound/deprecated.h
|
||||
cp $1/include/fishsound/fishsound.h ./include/fishsound/fishsound.h
|
||||
cp $1/include/fishsound/constants.h ./include/fishsound/constants.h
|
||||
cp $1/include/fishsound/decode.h ./include/fishsound/decode.h
|
||||
cp $1/COPYING ./COPYING
|
||||
cp $1/README ./README
|
||||
cp ./include/fishsound/config.h ./src/libfishsound/config.h
|
||||
cp $1/src/libfishsound/decode.c ./src/libfishsound/fishsound_decode.c
|
||||
cp $1/src/libfishsound/fishsound.c ./src/libfishsound/fishsound.c
|
||||
sed s/\#include\ \<vorbis\\/vorbisenc.h\>/\#if\ HAVE_VORBISENC\\n\#include\ \<vorbis\\/vorbisenc.h\>\\n\#endif/g $1/src/libfishsound/vorbis.c >./src/libfishsound/fishsound_vorbis.c
|
||||
cp $1/src/libfishsound/flac.c ./src/libfishsound/fishsound_flac.c
|
||||
cp $1/src/libfishsound/comments.c ./src/libfishsound/fishsound_comments.c
|
||||
cp $1/src/libfishsound/private.h ./src/libfishsound/private.h
|
||||
cp $1/src/libfishsound/fs_compat.h ./src/libfishsound/fs_compat.h
|
||||
cp $1/src/libfishsound/speex.c ./src/libfishsound/fishsound_speex.c
|
||||
cp $1/src/libfishsound/encode.c ./src/libfishsound/fishsound_encode.c
|
||||
cp $1/src/libfishsound/fs_vector.h ./src/libfishsound/fs_vector.h
|
||||
cp $1/src/libfishsound/fs_vector.c ./src/libfishsound/fs_vector.c
|
||||
cp $1/src/libfishsound/convert.h ./src/libfishsound/convert.h
|
||||
cp $1/src/libfishsound/debug.h ./src/libfishsound/debug.h
|
||||
cp $1/AUTHORS ./AUTHORS
|
||||
patch -p3 <endian.patch
|
||||
patch -p3 <bug487519.patch
|
||||
patch -p3 <trac497.patch
|
||||
patch -p3 <fishsound_reset.patch
|
||||
patch -p3 <bug520500.patch
|
|
@ -1,29 +0,0 @@
|
|||
Copyright (C) 2003 CSIRO Australia
|
||||
|
||||
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.
|
||||
|
||||
- Neither the name of the CSIRO nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
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 ORGANISATION 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.
|
||||
|
|
@ -1,51 +0,0 @@
|
|||
# ***** BEGIN LICENSE BLOCK *****
|
||||
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
#
|
||||
# The contents of this file are subject to the Mozilla Public License Version
|
||||
# 1.1 (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
# http://www.mozilla.org/MPL/
|
||||
#
|
||||
# Software distributed under the License is distributed on an "AS IS" basis,
|
||||
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
# for the specific language governing rights and limitations under the
|
||||
# License.
|
||||
#
|
||||
# The Original Code is Mozilla code.
|
||||
#
|
||||
# The Initial Developer of the Original Code is the Mozilla Corporation.
|
||||
# Portions created by the Initial Developer are Copyright (C) 2007
|
||||
# the Initial Developer. All Rights Reserved.
|
||||
#
|
||||
# Contributor(s):
|
||||
# Chris Double <chris.double@double.co.nz>
|
||||
#
|
||||
# Alternatively, the contents of this file may be used under the terms of
|
||||
# either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
# in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
# of those above. If you wish to allow use of your version of this file only
|
||||
# under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
# use your version of this file under the terms of the MPL, indicate your
|
||||
# decision by deleting the provisions above and replace them with the notice
|
||||
# and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
# the provisions above, a recipient may use your version of this file under
|
||||
# the terms of any one of the MPL, the GPL or the LGPL.
|
||||
#
|
||||
# ***** END LICENSE BLOCK *****
|
||||
|
||||
DEPTH = ../..
|
||||
topsrcdir = @top_srcdir@
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
|
||||
include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
MODULE = oggplay
|
||||
|
||||
DIRS = \
|
||||
include \
|
||||
src \
|
||||
$(NULL)
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
|
@ -1,68 +0,0 @@
|
|||
OggPlay: a library for playing Ogg multimedia
|
||||
|
||||
Overview
|
||||
--------
|
||||
|
||||
The current version of the plugin is still under development therefore
|
||||
the setup requires manual installation of the plugin. For more information,
|
||||
see also:
|
||||
|
||||
http://wiki.xiph.org/index.php/OggPlay
|
||||
|
||||
Dependencies
|
||||
------------
|
||||
|
||||
For the core library (liboggplay), you need
|
||||
|
||||
* libogg, libvorbis, libtheora, optionally libspeex -- from http://www.xiph.org/
|
||||
|
||||
svn co http://svn.xiph.org/trunk/ogg/ ogg
|
||||
svn co http://svn.xiph.org/trunk/vorbis/ vorbis
|
||||
svn co http://svn.xiph.org/trunk/theora/ theora
|
||||
|
||||
* liboggz and libfishsound -- from svn.annodex.net:
|
||||
|
||||
git clone git://git.xiph.org/liboggz.git
|
||||
git clone git://git.xiph.org/libfishsound.git
|
||||
|
||||
Optionally, for Kate stream support, you need
|
||||
|
||||
* libkate -- from http://libkate.googlecode.com/
|
||||
|
||||
To render Kate streams as video overlays, you need
|
||||
|
||||
* libtiger -- from http://libtiger.googlecode.com/
|
||||
|
||||
Note that libtiger needs Pango and Cairo:
|
||||
|
||||
* Pango -- http://www.pango.org/
|
||||
* Cairo -- http://cairographics.com/
|
||||
|
||||
See the README files associated with these libraries for installation
|
||||
instructions.
|
||||
|
||||
To build src/examples/glut-player, you need:
|
||||
* The core liboggplay dependencies (listed above)
|
||||
* GLUT -- see http://www.opengl.org/resources/libraries/
|
||||
|
||||
To build src/examples/dump-all-streams, you need:
|
||||
* The core liboggplay dependencies (listed above)
|
||||
* libsndfile -- from http://www.mega-nerd.com/libsndfile/
|
||||
|
||||
To build src/tools/oggplay-dump-first-frame, you need:
|
||||
* The core liboggplay dependencies (listed above)
|
||||
* Imlib2 -- from your distribution or from
|
||||
http://sourceforge.net/project/showfiles.php?group_id=2&package_id=11130
|
||||
|
||||
On Debian, the required packages for all these additional libraries are:
|
||||
g++ libogg-dev libvorbis-dev libspeex-dev libtheora-dev libsndfile1-dev
|
||||
libimlib2-dev libglut-dev
|
||||
|
||||
Compile and Install liboggplay
|
||||
------------------------------
|
||||
|
||||
./autogen.sh
|
||||
./configure
|
||||
make && make install
|
||||
|
||||
|
|
@ -1,48 +0,0 @@
|
|||
The source from this directory was copied from the liboggplay svn
|
||||
source using the update.sh script. The only changes made were those
|
||||
applied by update.sh and the addition/upate of Makefile.in files for
|
||||
the Mozilla build system.
|
||||
|
||||
git://git.xiph.org/liboggplay.git
|
||||
|
||||
The git commit ID used was 404316e5957370b3c854a86910c237c90746c325.
|
||||
|
||||
The following local patches have been applied:
|
||||
|
||||
endian: pick up NSPR's little/big endian defines in oggplay's config.h.
|
||||
|
||||
bug481921: fix a crash in oggplay_callback_info_prepare().
|
||||
|
||||
aspect-ratio: Adds oggplay_get_video_aspect_ratio, used for bug 480058.
|
||||
|
||||
bug493678.patch: fix for infinite loop in oggplay_step_decode. See bug 493678.
|
||||
|
||||
seek_to_key_frame.patch: Adds oggplay_seek_to_keyframe(), as per bug 463358.
|
||||
|
||||
oggplay_os2.patch: Bug 448918 - add OS/2 support (this patch should be
|
||||
removed when OS/2 support is added upstream)
|
||||
|
||||
bug496529.patch: Fix bug 496529.
|
||||
|
||||
bug500311.patch: Fix crash during decoder initialization.
|
||||
|
||||
faster_seek.patch: Fix for bug 501031, make seeking faster over HTTP.
|
||||
|
||||
fix-17ef4ca82df28.patch: Fix oggplay_callback_predetected() to return
|
||||
value interpreted as success upon success.
|
||||
Fixes liboggplay changeset 17ef4ca82df28.
|
||||
|
||||
handle-read-errors.patch: Make oggplay_initialise() handle closing of stream
|
||||
while reading. Prevents infinite loop. Further fix
|
||||
to 17ef4ca82df28.
|
||||
|
||||
bug515217.patch: Fix crash where presentation thread releases a buffer just
|
||||
before decode thread tries to set that buffer as the last at EOF.
|
||||
bug504843.patch: Abort when decoding video excessively large video frames.
|
||||
|
||||
fishsound_reset.patch: Fixes bug 516323.
|
||||
|
||||
bug520493.patch: Ensure liboggplay returns data when all tracks
|
||||
are deactivated when a callback reaches EOF.
|
||||
|
||||
bug523816.patch: Correct CMML data buffer size calculation.
|
|
@ -1,72 +0,0 @@
|
|||
diff --git a/media/liboggplay/include/oggplay/oggplay.h b/media/liboggplay/include/oggplay/oggplay.h
|
||||
--- a/media/liboggplay/include/oggplay/oggplay.h
|
||||
+++ b/media/liboggplay/include/oggplay/oggplay.h
|
||||
@@ -226,16 +226,19 @@ oggplay_get_audio_samplerate(OggPlay *me
|
||||
* @retval E_OGGPLAY_BAD_TRACK the given track number does not exists
|
||||
* @retval E_OGGPLAY_WRONG_TRACK_TYPE the given track is not an audio track
|
||||
* @retval E_OGGPLAY_UNINITIALISED the OggPlay handle is uninitalised.
|
||||
*/
|
||||
OggPlayErrorCode
|
||||
oggplay_get_video_fps(OggPlay *me, int track, int* fps_denom, int* fps_num);
|
||||
|
||||
OggPlayErrorCode
|
||||
+oggplay_get_video_aspect_ratio(OggPlay *me, int track, int* aspect_denom, int* aspect_num);
|
||||
+
|
||||
+OggPlayErrorCode
|
||||
oggplay_convert_video_to_rgb(OggPlay *me, int track, int convert, int swap_rgb);
|
||||
|
||||
OggPlayErrorCode
|
||||
oggplay_get_kate_category(OggPlay *me, int track, const char** category);
|
||||
|
||||
OggPlayErrorCode
|
||||
oggplay_get_kate_language(OggPlay *me, int track, const char** language);
|
||||
|
||||
diff --git a/media/liboggplay/src/liboggplay/oggplay.c b/media/liboggplay/src/liboggplay/oggplay.c
|
||||
--- a/media/liboggplay/src/liboggplay/oggplay.c
|
||||
+++ b/media/liboggplay/src/liboggplay/oggplay.c
|
||||
@@ -297,16 +297,45 @@ oggplay_get_video_fps(OggPlay *me, int t
|
||||
|
||||
(*fps_denom) = decode->video_info.fps_denominator;
|
||||
(*fps_num) = decode->video_info.fps_numerator;
|
||||
|
||||
return E_OGGPLAY_OK;
|
||||
}
|
||||
|
||||
OggPlayErrorCode
|
||||
+oggplay_get_video_aspect_ratio(OggPlay *me, int track, int* aspect_denom, int* aspect_num) {
|
||||
+ OggPlayTheoraDecode *decode;
|
||||
+
|
||||
+ if (me == NULL) {
|
||||
+ return E_OGGPLAY_BAD_OGGPLAY;
|
||||
+ }
|
||||
+
|
||||
+ if (track < 0 || track >= me->num_tracks) {
|
||||
+ return E_OGGPLAY_BAD_TRACK;
|
||||
+ }
|
||||
+
|
||||
+ if (me->decode_data[track]->decoded_type != OGGPLAY_YUV_VIDEO) {
|
||||
+ return E_OGGPLAY_WRONG_TRACK_TYPE;
|
||||
+ }
|
||||
+
|
||||
+ decode = (OggPlayTheoraDecode *)(me->decode_data[track]);
|
||||
+
|
||||
+ if ((decode->video_info.aspect_denominator == 0)
|
||||
+ || (decode->video_info.aspect_numerator == 0)) {
|
||||
+ return E_OGGPLAY_UNINITIALISED;
|
||||
+ }
|
||||
+
|
||||
+ (*aspect_denom) = decode->video_info.aspect_denominator;
|
||||
+ (*aspect_num) = decode->video_info.aspect_numerator;
|
||||
+
|
||||
+ return E_OGGPLAY_OK;
|
||||
+}
|
||||
+
|
||||
+OggPlayErrorCode
|
||||
oggplay_convert_video_to_rgb(OggPlay *me, int track, int convert, int swap_rgb) {
|
||||
OggPlayTheoraDecode *decode;
|
||||
|
||||
if (me == NULL) {
|
||||
return E_OGGPLAY_BAD_OGGPLAY;
|
||||
}
|
||||
|
||||
if (track < 0 || track >= me->num_tracks) {
|
|
@ -1,32 +0,0 @@
|
|||
diff --git a/media/liboggplay/src/liboggplay/oggplay_callback_info.c b/media/liboggplay/src/liboggplay/oggplay_callback_info.c
|
||||
--- a/media/liboggplay/src/liboggplay/oggplay_callback_info.c
|
||||
+++ b/media/liboggplay/src/liboggplay/oggplay_callback_info.c
|
||||
@@ -133,21 +133,23 @@ oggplay_callback_info_prepare(OggPlay *m
|
||||
|
||||
track_info->available_records = count;
|
||||
track_info->required_records = 0;
|
||||
|
||||
track_info->data_type = track->decoded_type;
|
||||
|
||||
count = 0;
|
||||
for (p = q; p != NULL; p = p->next) {
|
||||
- track_info->records[count++] = p;
|
||||
- if (p->presentation_time <= me->target + track->offset) {
|
||||
- track_info->required_records++;
|
||||
- p->has_been_presented = 1;
|
||||
- //lpt = p->presentation_time;
|
||||
+ if (!p->has_been_presented) {
|
||||
+ track_info->records[count++] = p;
|
||||
+ if (p->presentation_time <= me->target + track->offset) {
|
||||
+ track_info->required_records++;
|
||||
+ p->has_been_presented = 1;
|
||||
+ //lpt = p->presentation_time;
|
||||
+ }
|
||||
}
|
||||
}
|
||||
|
||||
if (track_info->required_records > 0) {
|
||||
/*
|
||||
* if the StreamState is FIRST_DATA then update it to INITIALISED,
|
||||
* as we've marked the first data instance
|
||||
*/
|
|
@ -1,30 +0,0 @@
|
|||
diff --git a/media/liboggplay/src/liboggplay/oggplay_callback.c b/media/liboggplay/src/liboggplay/oggplay_callback.c
|
||||
--- a/media/liboggplay/src/liboggplay/oggplay_callback.c
|
||||
+++ b/media/liboggplay/src/liboggplay/oggplay_callback.c
|
||||
@@ -543,16 +543,26 @@ oggplay_callback_audio (OGGZ * oggz, ogg
|
||||
}
|
||||
|
||||
default:
|
||||
/* there was no problem with decoding */
|
||||
if (!common->num_header_packets) common->initialised |= 1;
|
||||
break;
|
||||
}
|
||||
|
||||
+ if (bytes_read < 0) {
|
||||
+ printf("\nERROR HADNLING MISMATCH BETWEEN liboggplay AND mozilla\n\n");
|
||||
+ // Unrecoverable error, disable track
|
||||
+ op->e_o_s = 1;
|
||||
+ common->active = 0;
|
||||
+ common->player->active_tracks--;
|
||||
+ return OGGZ_ERR_HOLE_IN_DATA;
|
||||
+ }
|
||||
+
|
||||
+
|
||||
if (decoder->sound_info.channels == 0) {
|
||||
fish_sound_command(decoder->sound_handle, FISH_SOUND_GET_INFO,
|
||||
&(decoder->sound_info), sizeof(FishSoundInfo));
|
||||
}
|
||||
|
||||
if (op->e_o_s) {
|
||||
common->active = 0;
|
||||
common->player->active_tracks--;
|
|
@ -1,13 +0,0 @@
|
|||
diff --git a/media/liboggplay/src/liboggplay/oggplay_callback.c b/media/liboggplay/src/liboggplay/oggplay_callback.c
|
||||
index 7683b80..ad127a0 100644
|
||||
--- a/media/liboggplay/src/liboggplay/oggplay_callback.c
|
||||
+++ b/media/liboggplay/src/liboggplay/oggplay_callback.c
|
||||
@@ -536,7 +536,7 @@ oggplay_initialise_decoder(OggPlay *me, int content_type, int serialno) {
|
||||
decoder->content_type = content_type;
|
||||
decoder->content_type_name =
|
||||
oggz_stream_get_content_type (me->oggz, serialno);
|
||||
- decoder->active = 1;
|
||||
+ decoder->active = 0;
|
||||
decoder->final_granulepos = -1;
|
||||
decoder->player = me;
|
||||
decoder->decoded_type = OGGPLAY_TYPE_UNKNOWN;
|
|
@ -1,22 +0,0 @@
|
|||
diff --git a/media/liboggplay/src/liboggplay/oggplay_yuv2rgb.c b/media/liboggplay/src/liboggplay/oggplay_yuv2rgb.c
|
||||
--- a/media/liboggplay/src/liboggplay/oggplay_yuv2rgb.c
|
||||
+++ b/media/liboggplay/src/liboggplay/oggplay_yuv2rgb.c
|
||||
@@ -174,17 +174,17 @@ YUV_CONVERT(yuv444_to_argb_vanilla, CONV
|
||||
* macros as there's no way e.g. we could compile a x86 asm code
|
||||
* on a ppc machine and vica-versa
|
||||
*/
|
||||
#if defined(i386) || defined(__x86__) || defined(__x86_64__) || defined(_M_IX86) || defined(_M_AMD64)
|
||||
#if !defined(_M_AMD64)
|
||||
#define ENABLE_MMX
|
||||
#endif
|
||||
#include "x86/oggplay_yuv2rgb_x86.c"
|
||||
-#if defined(ATTRIBUTE_ALIGNED_MAX) && ATTRIBUTE_ALIGNED_MAX >= 16
|
||||
+#if defined(_MSC_VER) || defined(ATTRIBUTE_ALIGNED_MAX) && ATTRIBUTE_ALIGNED_MAX >= 16
|
||||
#define ENABLE_SSE2
|
||||
#endif
|
||||
#elif defined(__ppc__) || defined(__ppc64__)
|
||||
#define ENABLE_ALTIVEC
|
||||
//altivec intristics only working with -maltivec gcc flag,
|
||||
//but we want runtime altivec detection, hence this has to be
|
||||
//fixed!
|
||||
//#include "oggplay_yuv2rgb_altivec.c"
|
|
@ -1,79 +0,0 @@
|
|||
diff --git a/media/liboggplay/src/liboggplay/oggplay.c b/media/liboggplay/src/liboggplay/oggplay.c
|
||||
--- a/media/liboggplay/src/liboggplay/oggplay.c
|
||||
+++ b/media/liboggplay/src/liboggplay/oggplay.c
|
||||
@@ -149,16 +149,17 @@ oggplay_initialise(OggPlay *me, int bloc
|
||||
}
|
||||
|
||||
/*
|
||||
* set all the tracks to inactive
|
||||
*/
|
||||
for (i = 0; i < me->num_tracks; i++) {
|
||||
me->decode_data[i]->active = 0;
|
||||
}
|
||||
+ me->active_tracks = 0;
|
||||
|
||||
/*
|
||||
* if the buffer was set up before initialisation, prepare it now
|
||||
*/
|
||||
if (me->buffer != NULL) {
|
||||
oggplay_buffer_prepare(me);
|
||||
}
|
||||
|
||||
diff --git a/media/liboggplay/src/liboggplay/oggplay_callback.c b/media/liboggplay/src/liboggplay/oggplay_callback.c
|
||||
--- a/media/liboggplay/src/liboggplay/oggplay_callback.c
|
||||
+++ b/media/liboggplay/src/liboggplay/oggplay_callback.c
|
||||
@@ -60,16 +60,17 @@ oggplay_init_theora(void *user_data) {
|
||||
theora_info_init(&(decoder->video_info));
|
||||
theora_comment_init(&(decoder->video_comment));
|
||||
decoder->granulepos_seen = 0;
|
||||
decoder->frame_delta = 0;
|
||||
decoder->y_width = 0;
|
||||
decoder->convert_to_rgb = 0;
|
||||
decoder->swap_rgb = 0;
|
||||
decoder->decoder.decoded_type = OGGPLAY_YUV_VIDEO;
|
||||
+ decoder->decoder.player->active_tracks++;
|
||||
}
|
||||
|
||||
void
|
||||
oggplay_shutdown_theora(void *user_data) {
|
||||
OggPlayDecode * common;
|
||||
OggPlayTheoraDecode * decoder = (OggPlayTheoraDecode *)user_data;
|
||||
|
||||
if (decoder == NULL) {
|
||||
@@ -499,16 +500,17 @@ oggplay_init_audio (void * user_data) {
|
||||
}
|
||||
|
||||
decoder->sound_info.channels = 0;
|
||||
fish_sound_set_decoded_float_ilv(decoder->sound_handle,
|
||||
oggplay_fish_sound_callback_floats,
|
||||
(void *)decoder);
|
||||
|
||||
decoder->decoder.decoded_type = OGGPLAY_FLOATS_AUDIO;
|
||||
+ decoder->decoder.player->active_tracks++;
|
||||
}
|
||||
|
||||
void
|
||||
oggplay_shutdown_audio(void *user_data) {
|
||||
|
||||
OggPlayAudioDecode * decoder = (OggPlayAudioDecode *)user_data;
|
||||
|
||||
if (decoder == NULL) {
|
||||
@@ -814,17 +816,17 @@ oggplay_initialise_decoder(OggPlay *me,
|
||||
|
||||
if (decoder == NULL)
|
||||
return NULL;
|
||||
|
||||
decoder->serialno = serialno;
|
||||
decoder->content_type = content_type;
|
||||
decoder->content_type_name =
|
||||
oggz_stream_get_content_type (me->oggz, serialno);
|
||||
- decoder->active = 0;
|
||||
+ decoder->active = 1;
|
||||
decoder->final_granulepos = -1;
|
||||
decoder->player = me;
|
||||
decoder->decoded_type = OGGPLAY_TYPE_UNKNOWN;
|
||||
decoder->num_header_packets =
|
||||
oggz_stream_get_numheaders (me->oggz, serialno);
|
||||
|
||||
/*
|
||||
* set the StreamInfo to unitialised until we get some real data in
|
|
@ -1,185 +0,0 @@
|
|||
diff --git a/media/liboggplay/include/oggplay/oggplay.h b/media/liboggplay/include/oggplay/oggplay.h
|
||||
--- a/media/liboggplay/include/oggplay/oggplay.h
|
||||
+++ b/media/liboggplay/include/oggplay/oggplay.h
|
||||
@@ -116,17 +116,17 @@ oggplay_new_with_reader(OggPlayReader *r
|
||||
*
|
||||
* @param me OggPlay handle
|
||||
* @param block passed as the second argument to the OggPlayReader's initialise
|
||||
* function. E.g. in case of OggPlayTCPReader block == 0 sets the socket to non-blocking
|
||||
* mode.
|
||||
* @retval E_OGGPLAY_OK on success
|
||||
* @retval E_OGGPLAY_OGGZ_UNHAPPY something went wrong while calling oggz_io_set_* functions.
|
||||
* @retval E_OGGPLAY_BAD_INPUT got EOF or OGGZ_ERR_HOLE_IN_DATA occured.
|
||||
- * @retval E_OGGPLAY_OUT_OF_MEMORY ran out of memory
|
||||
+ * @retval E_OGGPLAY_OUT_OF_MEMORY ran out of memory or video frame too large.
|
||||
* @retval E_OGGPLAY_BAD_OGGPLAY invalid OggPlay handle.
|
||||
*/
|
||||
OggPlayErrorCode
|
||||
oggplay_initialise(OggPlay *me, int block);
|
||||
|
||||
/**
|
||||
* Sets a user defined OggPlayDataCallback function for the OggPlay handle.
|
||||
*
|
||||
@@ -344,13 +344,31 @@ oggplay_get_available(OggPlay *player);
|
||||
* @retval E_OGGPLAY_BAD_OGGPLAY invalid OggPlay handle
|
||||
*/
|
||||
ogg_int64_t
|
||||
oggplay_get_duration(OggPlay * player);
|
||||
|
||||
int
|
||||
oggplay_media_finished_retrieving(OggPlay * player);
|
||||
|
||||
+/**
|
||||
+ * Sets the maximum video frame size, in pixels, which OggPlay will attempt to
|
||||
+ * decode. Call this after oggplay_new_with_reader() but before
|
||||
+ * oggplay_initialise() to prevent crashes with excessivly large video frame
|
||||
+ * sizes. oggplay_initialise() will return E_OGGPLAY_OUT_OF_MEMORY if the
|
||||
+ * decoded video's frame requires more than max_frame_pixels. Unless
|
||||
+ * oggplay_set_max_video_size() is called, default maximum number of pixels
|
||||
+ * per frame is INT_MAX.
|
||||
+ *
|
||||
+ * @param player OggPlay handle.
|
||||
+ * @param max_frame_pixels max number of pixels per frame.
|
||||
+ * @retval E_OGGPLAY_OK on success.
|
||||
+ * @retval E_OGGPLAY_BAD_OGGPLAY invalid OggPlay handle.
|
||||
+ */
|
||||
+int
|
||||
+oggplay_set_max_video_frame_pixels(OggPlay *player,
|
||||
+ int max_frame_pixels);
|
||||
+
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __OGGPLAY_H__ */
|
||||
diff --git a/media/liboggplay/src/liboggplay/oggplay.c b/media/liboggplay/src/liboggplay/oggplay.c
|
||||
--- a/media/liboggplay/src/liboggplay/oggplay.c
|
||||
+++ b/media/liboggplay/src/liboggplay/oggplay.c
|
||||
@@ -68,16 +68,17 @@ oggplay_new_with_reader(OggPlayReader *r
|
||||
me->target = 0L;
|
||||
me->active_tracks = 0;
|
||||
me->buffer = NULL;
|
||||
me->shutdown = 0;
|
||||
me->trash = NULL;
|
||||
me->oggz = NULL;
|
||||
me->pt_update_valid = 1;
|
||||
me->duration = -1;
|
||||
+ me->max_video_frame_pixels = OGGPLAY_TYPE_MAX_SIGNED(int);
|
||||
|
||||
return me;
|
||||
|
||||
}
|
||||
|
||||
OggPlayErrorCode
|
||||
oggplay_initialise(OggPlay *me, int block) {
|
||||
|
||||
@@ -958,8 +959,16 @@ oggplay_media_finished_retrieving(OggPla
|
||||
if (me->reader == NULL) {
|
||||
return E_OGGPLAY_BAD_READER;
|
||||
}
|
||||
|
||||
return me->reader->finished_retrieving(me->reader);
|
||||
|
||||
}
|
||||
|
||||
+int
|
||||
+oggplay_set_max_video_frame_pixels(OggPlay *player,
|
||||
+ int max_frame_pixels) {
|
||||
+ if (!player)
|
||||
+ return E_OGGPLAY_BAD_OGGPLAY;
|
||||
+ player->max_video_frame_pixels = max_frame_pixels;
|
||||
+ return E_OGGPLAY_OK;
|
||||
+}
|
||||
diff --git a/media/liboggplay/src/liboggplay/oggplay_callback.c b/media/liboggplay/src/liboggplay/oggplay_callback.c
|
||||
--- a/media/liboggplay/src/liboggplay/oggplay_callback.c
|
||||
+++ b/media/liboggplay/src/liboggplay/oggplay_callback.c
|
||||
@@ -83,16 +83,42 @@ oggplay_shutdown_theora(void *user_data)
|
||||
|
||||
if (common->initialised == 1 && decoder->decoder.num_header_packets == 0) {
|
||||
theora_clear(&(decoder->video_handle));
|
||||
}
|
||||
theora_info_clear(&(decoder->video_info));
|
||||
theora_comment_clear(&(decoder->video_comment));
|
||||
}
|
||||
|
||||
+/**
|
||||
+ * Returns 1 if the video as described by |info| requires more than
|
||||
+ * max_video_pixels pixels per frame, otherwise returns 0.
|
||||
+ */
|
||||
+static int
|
||||
+frame_is_too_large(theora_info *info, long max_video_pixels) {
|
||||
+ int overflow = 0;
|
||||
+ long frame_pixels = 0;
|
||||
+ long display_pixels = 0;
|
||||
+ if (!info) {
|
||||
+ return 1;
|
||||
+ }
|
||||
+ overflow |= oggplay_mul_signed_overflow(info->frame_width,
|
||||
+ info->frame_height,
|
||||
+ &frame_pixels);
|
||||
+ overflow |= oggplay_mul_signed_overflow(info->width,
|
||||
+ info->height,
|
||||
+ &display_pixels);
|
||||
+ if (overflow ||
|
||||
+ frame_pixels > max_video_pixels ||
|
||||
+ display_pixels > max_video_pixels) {
|
||||
+ return 1;
|
||||
+ }
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
int
|
||||
oggplay_callback_theora (OGGZ * oggz, ogg_packet * op, long serialno,
|
||||
void * user_data) {
|
||||
|
||||
OggPlayTheoraDecode * decoder = (OggPlayTheoraDecode *)user_data;
|
||||
OggPlayDecode * common = NULL;
|
||||
ogg_int64_t granulepos = oggz_tell_granulepos(oggz);
|
||||
yuv_buffer buffer;
|
||||
@@ -184,17 +210,24 @@ oggplay_callback_theora (OGGZ * oggz, og
|
||||
((decoder->video_info.height - decoder->video_info.offset_y)<decoder->video_info.frame_height)
|
||||
||
|
||||
((decoder->video_info.width - decoder->video_info.offset_x)<decoder->video_info.frame_width)
|
||||
)
|
||||
{
|
||||
common->initialised |= -1;
|
||||
return OGGZ_CONTINUE;
|
||||
}
|
||||
-
|
||||
+
|
||||
+ /* Ensure the video frames don't require more pixels than our
|
||||
+ * allowed maximum. */
|
||||
+ if (frame_is_too_large(&decoder->video_info,
|
||||
+ common->player->max_video_frame_pixels)) {
|
||||
+ return OGGZ_ERR_OUT_OF_MEMORY;
|
||||
+ }
|
||||
+
|
||||
if (theora_decode_init(&(decoder->video_handle), &(decoder->video_info))) {
|
||||
common->initialised |= -1;
|
||||
return OGGZ_CONTINUE;
|
||||
}
|
||||
|
||||
common->initialised |= 1;
|
||||
}
|
||||
return OGGZ_CONTINUE;
|
||||
diff --git a/media/liboggplay/src/liboggplay/oggplay_private.h b/media/liboggplay/src/liboggplay/oggplay_private.h
|
||||
--- a/media/liboggplay/src/liboggplay/oggplay_private.h
|
||||
+++ b/media/liboggplay/src/liboggplay/oggplay_private.h
|
||||
@@ -256,16 +256,17 @@ struct _OggPlay {
|
||||
ogg_int64_t target; /**< */
|
||||
int active_tracks; /**< number of active tracks */
|
||||
volatile OggPlayBuffer * buffer; /**< @see OggPlayBuffer */
|
||||
ogg_int64_t presentation_time; /**< */
|
||||
OggPlaySeekTrash * trash; /**< @see OggPlaySeekTrash */
|
||||
int shutdown; /**< "= 1" indicates shutdown event */
|
||||
int pt_update_valid; /**< */
|
||||
ogg_int64_t duration; /**< The value of the duration the last time it was retrieved.*/
|
||||
+ int max_video_frame_pixels; /**< Maximum number of pixels we'll allow in a video frame.*/
|
||||
};
|
||||
|
||||
void
|
||||
oggplay_set_data_callback_force(OggPlay *me, OggPlayDataCallback callback,
|
||||
void *user);
|
||||
|
||||
void
|
||||
oggplay_take_out_trash(OggPlay *me, OggPlaySeekTrash *trash);
|
|
@ -1,98 +0,0 @@
|
|||
diff --git a/media/liboggplay/src/liboggplay/oggplay.c b/media/liboggplay/src/liboggplay/oggplay.c
|
||||
--- a/media/liboggplay/src/liboggplay/oggplay.c
|
||||
+++ b/media/liboggplay/src/liboggplay/oggplay.c
|
||||
@@ -746,29 +746,27 @@ read_more_data:
|
||||
* set all of the tracks to inactive
|
||||
*/
|
||||
for (i = 0; i < me->num_tracks; i++) {
|
||||
me->decode_data[i]->active = 0;
|
||||
}
|
||||
me->active_tracks = 0;
|
||||
|
||||
if (info != NULL) {
|
||||
+ /* ensure all tracks have their final data packet set to end_of_stream */
|
||||
+ OggPlayCallbackInfo *p = info[0];
|
||||
+ for (i = 0; i < me->num_tracks; i++) {
|
||||
+ p->stream_info = OGGPLAY_STREAM_LAST_DATA;
|
||||
+ p++;
|
||||
+ }
|
||||
+
|
||||
me->callback (me, num_records, info, me->callback_user_ptr);
|
||||
oggplay_callback_info_destroy(me, info);
|
||||
}
|
||||
|
||||
- /*
|
||||
- * ensure all tracks have their final data packet set to end_of_stream
|
||||
- * But skip doing this if we're shutting down --- me->buffer may not
|
||||
- * be in a safe state.
|
||||
- */
|
||||
- if (me->buffer != NULL && !me->shutdown) {
|
||||
- oggplay_buffer_set_last_data(me, me->buffer);
|
||||
- }
|
||||
-
|
||||
/* we reached the end of the stream */
|
||||
return E_OGGPLAY_OK;
|
||||
|
||||
case OGGZ_ERR_HOLE_IN_DATA:
|
||||
/* there was a whole in the data */
|
||||
return E_OGGPLAY_BAD_INPUT;
|
||||
|
||||
case OGGZ_ERR_STOP_ERR:
|
||||
diff --git a/media/liboggplay/src/liboggplay/oggplay_buffer.c b/media/liboggplay/src/liboggplay/oggplay_buffer.c
|
||||
--- a/media/liboggplay/src/liboggplay/oggplay_buffer.c
|
||||
+++ b/media/liboggplay/src/liboggplay/oggplay_buffer.c
|
||||
@@ -138,38 +138,16 @@ oggplay_buffer_is_full(volatile OggPlayB
|
||||
buffer->buffer_list[WRAP_INC(buffer->last_filled, buffer->buffer_size)]
|
||||
!=
|
||||
NULL
|
||||
)
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
-void
|
||||
-oggplay_buffer_set_last_data(OggPlay *me, volatile OggPlayBuffer *buffer)
|
||||
-{
|
||||
-
|
||||
- int i;
|
||||
- OggPlayCallbackInfo *p;
|
||||
-
|
||||
- /*
|
||||
- * we're at last data before we've even started!
|
||||
- */
|
||||
- if (buffer->last_filled == -1) {
|
||||
- return;
|
||||
- }
|
||||
-
|
||||
- p = (OggPlayCallbackInfo *)buffer->buffer_list[buffer->last_filled];
|
||||
-
|
||||
- for (i = 0; i < me->num_tracks; i++) {
|
||||
- p->stream_info = OGGPLAY_STREAM_LAST_DATA;
|
||||
- p++;
|
||||
- }
|
||||
-}
|
||||
-
|
||||
int
|
||||
oggplay_buffer_callback(OggPlay *me, int tracks,
|
||||
OggPlayCallbackInfo **track_info, void *user) {
|
||||
|
||||
int i;
|
||||
int j;
|
||||
int k;
|
||||
OggPlayDataHeader ** headers;
|
||||
diff --git a/media/liboggplay/src/liboggplay/oggplay_buffer.h b/media/liboggplay/src/liboggplay/oggplay_buffer.h
|
||||
--- a/media/liboggplay/src/liboggplay/oggplay_buffer.h
|
||||
+++ b/media/liboggplay/src/liboggplay/oggplay_buffer.h
|
||||
@@ -53,12 +53,9 @@ int
|
||||
oggplay_buffer_is_full(volatile OggPlayBuffer *buffer);
|
||||
|
||||
void
|
||||
oggplay_buffer_shutdown(OggPlay *me, volatile OggPlayBuffer *buffer);
|
||||
|
||||
void
|
||||
oggplay_buffer_prepare(OggPlay *me);
|
||||
|
||||
-void
|
||||
-oggplay_buffer_set_last_data(OggPlay *me, volatile OggPlayBuffer *buffer);
|
||||
-
|
||||
#endif
|
|
@ -1,66 +0,0 @@
|
|||
diff --git a/media/liboggplay/src/liboggplay/oggplay.c b/media/liboggplay/src/liboggplay/oggplay.c
|
||||
--- a/media/liboggplay/src/liboggplay/oggplay.c
|
||||
+++ b/media/liboggplay/src/liboggplay/oggplay.c
|
||||
@@ -638,16 +638,17 @@ OggPlayErrorCode
|
||||
oggplay_step_decoding(OggPlay *me) {
|
||||
|
||||
OggPlayCallbackInfo ** info;
|
||||
int num_records;
|
||||
int r;
|
||||
int i;
|
||||
int need_data = 0;
|
||||
int chunk_count = 0;
|
||||
+ int read_data = 0;
|
||||
|
||||
if (me == NULL) {
|
||||
return E_OGGPLAY_BAD_OGGPLAY;
|
||||
}
|
||||
|
||||
/*
|
||||
* check whether the OggPlayDataCallback is set for the given
|
||||
* OggPlay handle. If not return with error as there's no callback
|
||||
@@ -686,17 +687,21 @@ read_more_data:
|
||||
if (me->active_tracks == 0) {
|
||||
int remaining = 0;
|
||||
for (i = 0; i < me->num_tracks; i++) {
|
||||
if (me->decode_data[i]->current_loc +
|
||||
me->decode_data[i]->granuleperiod >= me->target + me->decode_data[i]->offset) {
|
||||
remaining++;
|
||||
}
|
||||
}
|
||||
- if (remaining == 0) {
|
||||
+ if (remaining == 0 && !read_data) {
|
||||
+ /*
|
||||
+ * There's no more data to read, and we've not read any that needs
|
||||
+ * to be sent to the buffer list via a callback, so exit.
|
||||
+ */
|
||||
return E_OGGPLAY_OK;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* if any of the tracks have not yet met the target (modified by that
|
||||
* track's offset), then retrieve more data
|
||||
*/
|
||||
@@ -783,16 +788,21 @@ read_more_data:
|
||||
* e.g. some buffer overflow.
|
||||
*/
|
||||
|
||||
case OGGZ_ERR_OUT_OF_MEMORY:
|
||||
/* ran out of memory during decoding! */
|
||||
return E_OGGPLAY_OUT_OF_MEMORY;
|
||||
|
||||
default:
|
||||
+ /*
|
||||
+ * We read some data. Set a flag so that we're guaranteed to try to
|
||||
+ * send it to the buffer list via a callback.
|
||||
+ */
|
||||
+ read_data = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* prepare a callback
|
||||
*/
|
||||
num_records = oggplay_callback_info_prepare (me, &info);
|
||||
if (info != NULL) {
|
|
@ -1,29 +0,0 @@
|
|||
diff --git a/media/liboggplay/src/liboggplay/oggplay_data.c b/media/liboggplay/src/liboggplay/oggplay_data.c
|
||||
--- a/media/liboggplay/src/liboggplay/oggplay_data.c
|
||||
+++ b/media/liboggplay/src/liboggplay/oggplay_data.c
|
||||
@@ -353,22 +353,19 @@ oggplay_data_handle_audio_data (OggPlayD
|
||||
OggPlayErrorCode
|
||||
oggplay_data_handle_cmml_data(OggPlayDecode *decode,
|
||||
unsigned char *data,
|
||||
long size) {
|
||||
|
||||
OggPlayTextRecord * record = NULL;
|
||||
size_t record_size = sizeof(OggPlayTextRecord);
|
||||
|
||||
- /* check that the size we want to allocate doesn't overflow */
|
||||
- if ((size < 0) || (size+1 < 0)) {
|
||||
- return E_OGGPLAY_TYPE_OVERFLOW;
|
||||
- }
|
||||
- size += 1;
|
||||
-
|
||||
+ /* Include extra byte for null terminating record data buffer */
|
||||
+ record_size += 1;
|
||||
+
|
||||
if
|
||||
(
|
||||
oggplay_check_add_overflow (record_size, size, &record_size)
|
||||
==
|
||||
E_OGGPLAY_TYPE_OVERFLOW
|
||||
)
|
||||
{
|
||||
return E_OGGPLAY_TYPE_OVERFLOW;
|
|
@ -1,18 +0,0 @@
|
|||
diff --git a/media/liboggplay/src/liboggplay/config.h b/media/liboggplay/src/liboggplay/config.h
|
||||
--- a/media/liboggplay/src/liboggplay/config.h
|
||||
+++ b/media/liboggplay/src/liboggplay/config.h
|
||||
@@ -102,8 +102,14 @@
|
||||
# ifndef WORDS_BIGENDIAN
|
||||
/* # undef WORDS_BIGENDIAN */
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* Define to empty if `const' does not conform to ANSI C. */
|
||||
/* #undef const */
|
||||
#undef HAVE_GLUT
|
||||
+
|
||||
+#include "prcpucfg.h"
|
||||
+#ifdef IS_BIG_ENDIAN
|
||||
+#define WORDS_BIGENDIAN 1
|
||||
+#endif
|
||||
+
|
|
@ -1,78 +0,0 @@
|
|||
diff --git a/media/liboggplay/include/oggplay/oggplay_seek.h b/media/liboggplay/include/oggplay/oggplay_seek.h
|
||||
--- a/media/liboggplay/include/oggplay/oggplay_seek.h
|
||||
+++ b/media/liboggplay/include/oggplay/oggplay_seek.h
|
||||
@@ -53,15 +53,13 @@
|
||||
OggPlayErrorCode
|
||||
oggplay_seek(OggPlay *me, ogg_int64_t milliseconds);
|
||||
|
||||
/**
|
||||
* Seeks to key frame before |milliseconds|.
|
||||
*/
|
||||
OggPlayErrorCode
|
||||
oggplay_seek_to_keyframe(OggPlay *me,
|
||||
- int* tracks,
|
||||
- int num_tracks,
|
||||
ogg_int64_t milliseconds,
|
||||
ogg_int64_t offset_begin,
|
||||
ogg_int64_t offset_end);
|
||||
|
||||
#endif
|
||||
diff --git a/media/liboggplay/src/liboggplay/oggplay_seek.c b/media/liboggplay/src/liboggplay/oggplay_seek.c
|
||||
--- a/media/liboggplay/src/liboggplay/oggplay_seek.c
|
||||
+++ b/media/liboggplay/src/liboggplay/oggplay_seek.c
|
||||
@@ -186,54 +186,39 @@ oggplay_take_out_trash(OggPlay *me, OggP
|
||||
|
||||
if (p != NULL) {
|
||||
oggplay_free(p);
|
||||
}
|
||||
}
|
||||
|
||||
OggPlayErrorCode
|
||||
oggplay_seek_to_keyframe(OggPlay *me,
|
||||
- int* tracks,
|
||||
- int num_tracks,
|
||||
ogg_int64_t milliseconds,
|
||||
ogg_int64_t offset_begin,
|
||||
ogg_int64_t offset_end)
|
||||
{
|
||||
- long *serial_nos;
|
||||
- int i;
|
||||
ogg_int64_t eof, time;
|
||||
|
||||
if (me == NULL) {
|
||||
return E_OGGPLAY_BAD_OGGPLAY;
|
||||
}
|
||||
|
||||
- if (num_tracks > me->num_tracks || milliseconds < 0)
|
||||
+ if (milliseconds < 0)
|
||||
return E_OGGPLAY_CANT_SEEK;
|
||||
|
||||
eof = oggplay_get_duration(me);
|
||||
if (eof > -1 && milliseconds > eof) {
|
||||
return E_OGGPLAY_CANT_SEEK;
|
||||
}
|
||||
|
||||
- // Get the serialnos for the tracks we're seeking.
|
||||
- serial_nos = (long*)oggplay_malloc(sizeof(long)*num_tracks);
|
||||
- if (!serial_nos) {
|
||||
- return E_OGGPLAY_CANT_SEEK;
|
||||
- }
|
||||
- for (i=0; i<num_tracks; i++) {
|
||||
- serial_nos[i] = me->decode_data[tracks[i]]->serialno;
|
||||
- }
|
||||
|
||||
time = oggz_keyframe_seek_set(me->oggz,
|
||||
- serial_nos,
|
||||
- num_tracks,
|
||||
milliseconds,
|
||||
offset_begin,
|
||||
offset_end);
|
||||
- oggplay_free(serial_nos);
|
||||
|
||||
if (time == -1) {
|
||||
return E_OGGPLAY_CANT_SEEK;
|
||||
}
|
||||
|
||||
oggplay_seek_cleanup(me, time);
|
||||
|
||||
return E_OGGPLAY_OK;
|
|
@ -1,24 +0,0 @@
|
|||
diff --git a/media/liboggplay/src/liboggplay/oggplay_seek.c b/media/liboggplay/src/liboggplay/oggplay_seek.c
|
||||
--- a/media/liboggplay/src/liboggplay/oggplay_seek.c
|
||||
+++ b/media/liboggplay/src/liboggplay/oggplay_seek.c
|
||||
@@ -166,6 +166,20 @@ oggplay_seek_cleanup(OggPlay* me, ogg_in
|
||||
|
||||
*p = trash;
|
||||
|
||||
+ if (milliseconds == 0) {
|
||||
+ for (i = 0; i < me->num_tracks; i++) {
|
||||
+ OggPlayDecode *track = me->decode_data[i];
|
||||
+ FishSound *sound_handle;
|
||||
+ OggPlayAudioDecode *audio_decode;
|
||||
+ if (track->content_type != OGGZ_CONTENT_VORBIS) {
|
||||
+ continue;
|
||||
+ }
|
||||
+ audio_decode = (OggPlayAudioDecode*)track;
|
||||
+ sound_handle = audio_decode->sound_handle;
|
||||
+ fish_sound_reset(sound_handle);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
return E_OGGPLAY_OK;
|
||||
}
|
||||
|
|
@ -1,15 +0,0 @@
|
|||
diff --git a/media/liboggplay/src/liboggplay/oggplay_callback.c b/media/liboggplay/src/liboggplay/oggplay_callback.c
|
||||
--- a/media/liboggplay/src/liboggplay/oggplay_callback.c
|
||||
+++ b/media/liboggplay/src/liboggplay/oggplay_callback.c
|
||||
@@ -977,10 +982,10 @@ oggplay_callback_predetected (OGGZ *oggz
|
||||
}
|
||||
}
|
||||
|
||||
/* disable the callback for unforeseen streams */
|
||||
oggz_set_read_callback (me->oggz, -1, NULL, NULL);
|
||||
}
|
||||
|
||||
/* read the header part of the ogg content in a packet-by-packet manner */
|
||||
- return ((ret < 0) ? ret : OGGZ_STOP_OK);
|
||||
+ return ((ret < 0) ? ret : OGGZ_CONTINUE);
|
||||
}
|
|
@ -1,26 +0,0 @@
|
|||
diff --git a/media/liboggplay/src/liboggplay/oggplay.c b/media/liboggplay/src/liboggplay/oggplay.c
|
||||
--- a/media/liboggplay/src/liboggplay/oggplay.c
|
||||
+++ b/media/liboggplay/src/liboggplay/oggplay.c
|
||||
@@ -136,16 +136,22 @@ oggplay_initialise(OggPlay *me, int bloc
|
||||
|
||||
case OGGZ_ERR_OUT_OF_MEMORY:
|
||||
/* ran out of memory during decoding! */
|
||||
return E_OGGPLAY_OUT_OF_MEMORY;
|
||||
|
||||
case OGGZ_ERR_STOP_ERR:
|
||||
/* */
|
||||
return E_OGGPLAY_BAD_OGGPLAY;
|
||||
+
|
||||
+ default:
|
||||
+ /* If the read otherwise failed, bail out. */
|
||||
+ if (i < 0)
|
||||
+ return E_OGGPLAY_BAD_INPUT;
|
||||
+ break;
|
||||
}
|
||||
|
||||
if (me->all_tracks_initialised) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
|
@ -1,47 +0,0 @@
|
|||
# ***** BEGIN LICENSE BLOCK *****
|
||||
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
#
|
||||
# The contents of this file are subject to the Mozilla Public License Version
|
||||
# 1.1 (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
# http://www.mozilla.org/MPL/
|
||||
#
|
||||
# Software distributed under the License is distributed on an "AS IS" basis,
|
||||
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
# for the specific language governing rights and limitations under the
|
||||
# License.
|
||||
#
|
||||
# The Original Code is Mozilla code.
|
||||
#
|
||||
# The Initial Developer of the Original Code is the Mozilla Corporation.
|
||||
# Portions created by the Initial Developer are Copyright (C) 2007
|
||||
# the Initial Developer. All Rights Reserved.
|
||||
#
|
||||
# Contributor(s):
|
||||
# Chris Double <chris.double@double.co.nz>
|
||||
#
|
||||
# Alternatively, the contents of this file may be used under the terms of
|
||||
# either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
# in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
# of those above. If you wish to allow use of your version of this file only
|
||||
# under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
# use your version of this file under the terms of the MPL, indicate your
|
||||
# decision by deleting the provisions above and replace them with the notice
|
||||
# and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
# the provisions above, a recipient may use your version of this file under
|
||||
# the terms of any one of the MPL, the GPL or the LGPL.
|
||||
#
|
||||
# ***** END LICENSE BLOCK *****
|
||||
|
||||
DEPTH = ../../..
|
||||
topsrcdir = @top_srcdir@
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
|
||||
include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
MODULE = oggplay
|
||||
DIRS = oggplay
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
|
@ -1,57 +0,0 @@
|
|||
# ***** BEGIN LICENSE BLOCK *****
|
||||
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
#
|
||||
# The contents of this file are subject to the Mozilla Public License Version
|
||||
# 1.1 (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
# http://www.mozilla.org/MPL/
|
||||
#
|
||||
# Software distributed under the License is distributed on an "AS IS" basis,
|
||||
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
# for the specific language governing rights and limitations under the
|
||||
# License.
|
||||
#
|
||||
# The Original Code is Mozilla code.
|
||||
#
|
||||
# The Initial Developer of the Original Code is the Mozilla Corporation.
|
||||
# Portions created by the Initial Developer are Copyright (C) 2007
|
||||
# the Initial Developer. All Rights Reserved.
|
||||
#
|
||||
# Contributor(s):
|
||||
# Chris Double <chris.double@double.co.nz>
|
||||
#
|
||||
# Alternatively, the contents of this file may be used under the terms of
|
||||
# either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
# in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
# of those above. If you wish to allow use of your version of this file only
|
||||
# under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
# use your version of this file under the terms of the MPL, indicate your
|
||||
# decision by deleting the provisions above and replace them with the notice
|
||||
# and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
# the provisions above, a recipient may use your version of this file under
|
||||
# the terms of any one of the MPL, the GPL or the LGPL.
|
||||
#
|
||||
# ***** END LICENSE BLOCK *****
|
||||
|
||||
DEPTH = ../../../..
|
||||
topsrcdir = @top_srcdir@
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
|
||||
include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
EXPORTS_NAMESPACES = oggplay
|
||||
|
||||
EXPORTS_oggplay = \
|
||||
config_win32.h \
|
||||
oggplay.h \
|
||||
oggplay_callback_info.h \
|
||||
oggplay_enums.h \
|
||||
oggplay_reader.h \
|
||||
oggplay_tools.h \
|
||||
oggplay_seek.h \
|
||||
oggplay_query.h \
|
||||
$(NULL)
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
|
@ -1,78 +0,0 @@
|
|||
/* config.h. Generated from config.h.in by configure. */
|
||||
/* config.h.in. Generated from configure.ac by autoheader. */
|
||||
|
||||
/* Define to 1 if you have the <dlfcn.h> header file. */
|
||||
/* #undef HAVE_DLFCN_H */
|
||||
|
||||
/* Define to 1 if you have the <inttypes.h> header file. */
|
||||
/* #undef HAVE_INTTYPES_H */
|
||||
|
||||
/* Define to 1 if you have the <memory.h> header file. */
|
||||
/* #undef HAVE_MEMORY_H */
|
||||
|
||||
/* Define if have liboggz */
|
||||
#define HAVE_OGGZ 1
|
||||
|
||||
/* Define to 1 if you have the <stdint.h> header file. */
|
||||
/* #undef HAVE_STDINT_H */
|
||||
|
||||
/* Define to 1 if you have the <stdlib.h> header file. */
|
||||
#define HAVE_STDLIB_H 1
|
||||
|
||||
/* Define to 1 if you have the <strings.h> header file. */
|
||||
/* #undef HAVE_STRINGS_H */
|
||||
|
||||
/* Define to 1 if you have the <string.h> header file. */
|
||||
#define HAVE_STRING_H 1
|
||||
|
||||
/* Define to 1 if you have the <sys/stat.h> header file. */
|
||||
/* #undef HAVE_SYS_STAT_H */
|
||||
|
||||
/* Define to 1 if you have the <sys/types.h> header file. */
|
||||
/* #undef HAVE_SYS_TYPES_H */
|
||||
|
||||
/* Define to 1 if you have the <unistd.h> header file. */
|
||||
/* #undef HAVE_UNISTD_H */
|
||||
|
||||
/* Name of package */
|
||||
#define PACKAGE "liboggplay"
|
||||
|
||||
/* Define to the address where bug reports for this package should be sent. */
|
||||
#define PACKAGE_BUGREPORT ""
|
||||
|
||||
/* Define to the full name of this package. */
|
||||
#define PACKAGE_NAME ""
|
||||
|
||||
/* Define to the full name and version of this package. */
|
||||
#define PACKAGE_STRING ""
|
||||
|
||||
/* Define to the one symbol short name of this package. */
|
||||
#define PACKAGE_TARNAME ""
|
||||
|
||||
/* Define to the version of this package. */
|
||||
#define PACKAGE_VERSION ""
|
||||
|
||||
/* Define to 1 if you have the ANSI C header files. */
|
||||
#define STDC_HEADERS 1
|
||||
|
||||
/* Version number of package */
|
||||
#define VERSION "0.2.0"
|
||||
|
||||
/* Request Winsock 2.2 */
|
||||
#define HAVE_WINSOCK2 1
|
||||
|
||||
/* Make sure inline is treated properly */
|
||||
#define inline __inline
|
||||
|
||||
/* snprintf portability */
|
||||
#define snprintf _snprintf
|
||||
|
||||
/* Define to 1 if your processor stores words with the most significant byte
|
||||
first (like Motorola and SPARC, unlike Intel and VAX). */
|
||||
/* #undef WORDS_BIGENDIAN */
|
||||
|
||||
/* Define to empty if `const' does not conform to ANSI C. */
|
||||
/* #undef const */
|
||||
|
||||
/* Maximum supported data alignment */
|
||||
#define ATTRIBUTE_ALIGNED_MAX 16
|
|
@ -1,374 +0,0 @@
|
|||
/*
|
||||
Copyright (C) 2003 Commonwealth Scientific and Industrial Research
|
||||
Organisation (CSIRO) Australia
|
||||
|
||||
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.
|
||||
|
||||
- Neither the name of CSIRO Australia nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
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 ORGANISATION 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.
|
||||
*/
|
||||
|
||||
/** @file
|
||||
*
|
||||
* The liboggplay C API.
|
||||
*
|
||||
* @authors
|
||||
* Shane Stephens <shane.stephens@annodex.net>
|
||||
* Michael Martin
|
||||
* Viktor Gal
|
||||
*/
|
||||
|
||||
#ifndef __OGGPLAY_H__
|
||||
#define __OGGPLAY_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <oggplay/oggplay_enums.h>
|
||||
#include <oggplay/oggplay_reader.h>
|
||||
|
||||
/**
|
||||
* This is returned by oggplay_open_with_reader() or oggplay_new_with_reader().
|
||||
*/
|
||||
typedef struct _OggPlay OggPlay;
|
||||
|
||||
/**
|
||||
* A structure for storing the decoded frames for the various streams in the
|
||||
* Ogg container.
|
||||
*/
|
||||
typedef struct _OggPlayCallbackInfo OggPlayCallbackInfo;
|
||||
|
||||
/**
|
||||
* This is the signature of a callback which you must provide for OggPlay
|
||||
* to call whenever there's any unpresented decoded frame available.
|
||||
*
|
||||
* @see oggplay_step_decoding
|
||||
* @param player The OggPlay handle
|
||||
* @param num_records size of the OggPlayCallbackInfo array
|
||||
* @param records array of OggPlayCallbackInfo
|
||||
* @param user A generic pointer for the data the user provided earlier.
|
||||
* @returns 0 to continue, non-zero to instruct OggPlay to stop.
|
||||
*
|
||||
*/
|
||||
typedef int (OggPlayDataCallback) (OggPlay *player, int num_records,
|
||||
OggPlayCallbackInfo **records, void *user);
|
||||
|
||||
#include <oggplay/oggplay_query.h>
|
||||
#include <oggplay/oggplay_callback_info.h>
|
||||
#include <oggplay/oggplay_tools.h>
|
||||
#include <oggplay/oggplay_seek.h>
|
||||
|
||||
/**
|
||||
* Create an OggPlay handle associated with the given reader.
|
||||
*
|
||||
* This functions creates a new OggPlay handle associated with
|
||||
* the OggPlayReader and it calls oggplay_initialise to
|
||||
* read the header packets of the Ogg container.
|
||||
*
|
||||
* @param reader an OggPlayReader handle associated with the Ogg content
|
||||
* @return A new OggPlay handle
|
||||
* @retval NULL in case of error.
|
||||
*/
|
||||
OggPlay *
|
||||
oggplay_open_with_reader(OggPlayReader *reader);
|
||||
|
||||
/**
|
||||
* Create a new OggPlay handle associated with the given reader.
|
||||
*
|
||||
* @param reader OggPlayReader handle associated with the Ogg content
|
||||
* @return A new OggPlay handle
|
||||
* @retval NULL in case of error.
|
||||
*/
|
||||
OggPlay *
|
||||
oggplay_new_with_reader(OggPlayReader *reader);
|
||||
|
||||
|
||||
/**
|
||||
* Initialise the OggPlay handle.
|
||||
*
|
||||
* This function creates an Oggz handle and sets it's OggzIO*
|
||||
* functions to the OggPlayReader's io_* functions. Moreover
|
||||
* it reads the Ogg container's content until it hasn't got
|
||||
* all the streams' headers.
|
||||
*
|
||||
* @param me OggPlay handle
|
||||
* @param block passed as the second argument to the OggPlayReader's initialise
|
||||
* function. E.g. in case of OggPlayTCPReader block == 0 sets the socket to non-blocking
|
||||
* mode.
|
||||
* @retval E_OGGPLAY_OK on success
|
||||
* @retval E_OGGPLAY_OGGZ_UNHAPPY something went wrong while calling oggz_io_set_* functions.
|
||||
* @retval E_OGGPLAY_BAD_INPUT got EOF or OGGZ_ERR_HOLE_IN_DATA occured.
|
||||
* @retval E_OGGPLAY_OUT_OF_MEMORY ran out of memory or video frame too large.
|
||||
* @retval E_OGGPLAY_BAD_OGGPLAY invalid OggPlay handle.
|
||||
*/
|
||||
OggPlayErrorCode
|
||||
oggplay_initialise(OggPlay *me, int block);
|
||||
|
||||
/**
|
||||
* Sets a user defined OggPlayDataCallback function for the OggPlay handle.
|
||||
*
|
||||
* @param me OggPlay handle.
|
||||
* @param callback A custom callback function.
|
||||
* @param user Arbitrary data one wishes to pass to the callback function.
|
||||
* @retval E_OGGPLAY_OK on success
|
||||
* @retval E_OGGPLAY_BUFFER_MODE We are running in buffer mode, i.e. oggplay_use_buffer
|
||||
* has been called earlier.
|
||||
* @retval E_OGGPLAY_BAD_OGGPLAY Invalid OggPlay handle.
|
||||
*/
|
||||
OggPlayErrorCode
|
||||
oggplay_set_data_callback(OggPlay *me, OggPlayDataCallback callback,
|
||||
void *user);
|
||||
|
||||
|
||||
OggPlayErrorCode
|
||||
oggplay_set_callback_num_frames(OggPlay *me, int stream, int frames);
|
||||
|
||||
OggPlayErrorCode
|
||||
oggplay_set_callback_period(OggPlay *me, int stream, int milliseconds);
|
||||
|
||||
OggPlayErrorCode
|
||||
oggplay_set_offset(OggPlay *me, int track, ogg_int64_t offset);
|
||||
|
||||
/**
|
||||
* Get the given video track's Y-plane's width and height.
|
||||
*
|
||||
* @param me OggPlay handle
|
||||
* @param track the track number of the video track
|
||||
* @param y_width the width of the Y-plane
|
||||
* @param y_height the height of the Y-plane
|
||||
* @retval E_OGGPLAY_OK on success.
|
||||
* @retval E_OGGPLAY_BAD_OGGPLAY invalid OggPlay handle
|
||||
* @retval E_OGGPLAY_BAD_TRACK the given track number does not exists
|
||||
* @retval E_OGGPLAY_WRONG_TRACK_TYPE the given track is not an audio track
|
||||
* @retval E_OGGPLAY_UNINITIALISED the OggPlay handle is uninitalised.
|
||||
*/
|
||||
OggPlayErrorCode
|
||||
oggplay_get_video_y_size(OggPlay *me, int track, int *y_width, int *y_height);
|
||||
|
||||
/**
|
||||
* Get the given video track's UV-plane's width and height.
|
||||
*
|
||||
* @param me OggPlay handle
|
||||
* @param track the track number of the video track
|
||||
* @param uv_width the width of the UV-plane
|
||||
* @param uv_height the height of the UV-plane
|
||||
* @retval E_OGGPLAY_OK on success.
|
||||
* @retval E_OGGPLAY_BAD_OGGPLAY invalid OggPlay handle
|
||||
* @retval E_OGGPLAY_BAD_TRACK the given track number does not exists
|
||||
* @retval E_OGGPLAY_WRONG_TRACK_TYPE the given track is not an audio track
|
||||
* @retval E_OGGPLAY_UNINITIALISED the OggPlay handle is uninitalised.
|
||||
*/
|
||||
OggPlayErrorCode
|
||||
oggplay_get_video_uv_size(OggPlay *me, int track, int *uv_width, int *uv_height);
|
||||
|
||||
/**
|
||||
* Get the number of channels of the audio track.
|
||||
*
|
||||
* @param me OggPlay handle
|
||||
* @param track the track number of the audio track
|
||||
* @param channels the number of channels of the given audio track.
|
||||
* @retval E_OGGPLAY_OK on success.
|
||||
* @retval E_OGGPLAY_BAD_OGGPLAY invalid OggPlay handle
|
||||
* @retval E_OGGPLAY_BAD_TRACK the given track number does not exists
|
||||
* @retval E_OGGPLAY_WRONG_TRACK_TYPE the given track is not an audio track
|
||||
* @retval E_OGGPLAY_UNINITIALISED the OggPlay handle is uninitalised.
|
||||
*/
|
||||
OggPlayErrorCode
|
||||
oggplay_get_audio_channels(OggPlay *me, int track, int *channels);
|
||||
|
||||
/**
|
||||
* Get the sample rate of the of the audio track
|
||||
*
|
||||
* @param me OggPlay handle
|
||||
* @param track the track number of the audio track
|
||||
* @param samplerate the sample rate of the audio track.
|
||||
* @retval E_OGGPLAY_OK on success.
|
||||
* @retval E_OGGPLAY_BAD_OGGPLAY invalid OggPlay handle
|
||||
* @retval E_OGGPLAY_BAD_TRACK the given track number does not exists
|
||||
* @retval E_OGGPLAY_WRONG_TRACK_TYPE the given track is not an audio track
|
||||
* @retval E_OGGPLAY_UNINITIALISED the OggPlay handle is uninitalised.
|
||||
*/
|
||||
OggPlayErrorCode
|
||||
oggplay_get_audio_samplerate(OggPlay *me, int track, int *samplerate);
|
||||
|
||||
/**
|
||||
* Get the frame-per-second value the of a given video track.
|
||||
*
|
||||
* @param me OggPlay handle
|
||||
* @param track the track number of the audio track
|
||||
* @param fps_denom the denumerator of the FPS
|
||||
* @param fps_num the numerator of the FPS
|
||||
* @retval E_OGGPLAY_OK on success.
|
||||
* @retval E_OGGPLAY_BAD_OGGPLAY invalid OggPlay handle
|
||||
* @retval E_OGGPLAY_BAD_TRACK the given track number does not exists
|
||||
* @retval E_OGGPLAY_WRONG_TRACK_TYPE the given track is not an audio track
|
||||
* @retval E_OGGPLAY_UNINITIALISED the OggPlay handle is uninitalised.
|
||||
*/
|
||||
OggPlayErrorCode
|
||||
oggplay_get_video_fps(OggPlay *me, int track, int* fps_denom, int* fps_num);
|
||||
|
||||
OggPlayErrorCode
|
||||
oggplay_get_video_aspect_ratio(OggPlay *me, int track, int* aspect_denom, int* aspect_num);
|
||||
|
||||
OggPlayErrorCode
|
||||
oggplay_convert_video_to_rgb(OggPlay *me, int track, int convert, int swap_rgb);
|
||||
|
||||
OggPlayErrorCode
|
||||
oggplay_get_kate_category(OggPlay *me, int track, const char** category);
|
||||
|
||||
OggPlayErrorCode
|
||||
oggplay_get_kate_language(OggPlay *me, int track, const char** language);
|
||||
|
||||
OggPlayErrorCode
|
||||
oggplay_set_kate_tiger_rendering(OggPlay *me, int track, int use_tiger, int swap_rgb, int default_width, int default_height);
|
||||
|
||||
OggPlayErrorCode
|
||||
oggplay_overlay_kate_track_on_video(OggPlay *me, int kate_track, int video_track);
|
||||
|
||||
OggPlayErrorCode
|
||||
oggplay_start_decoding(OggPlay *me);
|
||||
|
||||
/**
|
||||
* Decode the streams in the Ogg container until we find data that hasn't
|
||||
* been presented, yet.
|
||||
*
|
||||
* Whenever there is data that hasn't been presented the OggPlayDataCallback
|
||||
* function will be called.
|
||||
*
|
||||
* @param me OggPlay handle
|
||||
* @retval E_OGGPLAY_OK reached the end of the stream or shutdown detected
|
||||
* @retval E_OGGPLAY_CONTINUE successfully decoded the frames.
|
||||
* @retval E_OGGPLAY_BAD_INPUT OGGZ_ERR_HOLE_IN_DATA occured while decoding
|
||||
* @retval E_OGGPLAY_UNINITIALISED the OggPlayDataCallback of the OggPlay handle is not set.
|
||||
* @retval E_OGGPLAY_USER_INTERRUPT user interrupted the decoding
|
||||
* @retval E_OGGPLAY_OUT_OF_MEMORY ran out of memory while decoding
|
||||
*/
|
||||
OggPlayErrorCode
|
||||
oggplay_step_decoding(OggPlay *me);
|
||||
|
||||
/**
|
||||
* Use the built-in OggPlayBuffer for buffering the decoded frames
|
||||
*
|
||||
* The built-in OggPlayBuffer implements a simple lock-free FIFO for
|
||||
* storing the decoded frames.
|
||||
*
|
||||
* It tries to set the OggPlay handle's OggPlayDataCallback function to it's
|
||||
* own implementation (oggplay_buffer_callback). Thus it will fail if
|
||||
* a user already set OggPlayDataCallback of the OggPlay handle
|
||||
* with oggplay_set_data_callback.
|
||||
*
|
||||
* One can retrive the next record in the queue by
|
||||
* calling oggplay_buffer_retrieve_next.
|
||||
*
|
||||
* @param player the OggPlay handle
|
||||
* @param size The size of the buffer, i.e. the number of records it can store
|
||||
* @retval E_OGGPLAY_OK on succsess
|
||||
* @retval E_OGGPLAY_BAD_OGGPLAY The supplied OggPlay handle is not valid
|
||||
* @retval E_OGGPLAY_CALLBACK_MODE The given OggPlay handle's OggPlayDataCallback
|
||||
* function is already set, i.e. running in callback-mode.
|
||||
* @retval E_OGGPLAY_OUT_OF_MEMORY Ran out of memory while trying to allocate memory for the buffer.
|
||||
*/
|
||||
OggPlayErrorCode
|
||||
oggplay_use_buffer(OggPlay *player, int size);
|
||||
|
||||
/**
|
||||
* Retrive the next element in the buffer.
|
||||
*
|
||||
* @param player OggPlay handle
|
||||
* @return array of OggPlayCallbackInfo - one per track.
|
||||
* @retval NULL if there was no available.
|
||||
*/
|
||||
OggPlayCallbackInfo **
|
||||
oggplay_buffer_retrieve_next(OggPlay *player);
|
||||
|
||||
/**
|
||||
* Release the given buffer item.
|
||||
*
|
||||
* After retrieving and processing one buffer item, in order
|
||||
* to remove the given item from the queue and release the
|
||||
* memory allocated by the buffer item one needs to call this
|
||||
* function.
|
||||
*
|
||||
* @param player OggPlay handle
|
||||
* @param track_info OggPlayCallbackInfo array to release.
|
||||
* @retval E_OGGPLAY_OK on success.
|
||||
* @retval E_OGGPLAY_BAD_OGGPLAY invalid OggPlay handle.
|
||||
*/
|
||||
OggPlayErrorCode
|
||||
oggplay_buffer_release(OggPlay *player, OggPlayCallbackInfo **track_info);
|
||||
|
||||
void
|
||||
oggplay_prepare_for_close(OggPlay *me);
|
||||
|
||||
/**
|
||||
* Destroys the OggPlay handle along with the associated OggPlayReader
|
||||
* and clears out the buffer and shuts down the callback function.
|
||||
*
|
||||
* @param player an OggPlay handle
|
||||
* @retval E_OGGPLAY_OK on success
|
||||
*/
|
||||
OggPlayErrorCode
|
||||
oggplay_close(OggPlay *player);
|
||||
|
||||
int
|
||||
oggplay_get_available(OggPlay *player);
|
||||
|
||||
/**
|
||||
* Get the duration of the Ogg content.
|
||||
*
|
||||
* @param player OggPlay handle.
|
||||
* @return The duration of the content in milliseconds.
|
||||
* @retval E_OGGPLAY_BAD_OGGPLAY invalid OggPlay handle
|
||||
*/
|
||||
ogg_int64_t
|
||||
oggplay_get_duration(OggPlay * player);
|
||||
|
||||
int
|
||||
oggplay_media_finished_retrieving(OggPlay * player);
|
||||
|
||||
/**
|
||||
* Sets the maximum video frame size, in pixels, which OggPlay will attempt to
|
||||
* decode. Call this after oggplay_new_with_reader() but before
|
||||
* oggplay_initialise() to prevent crashes with excessivly large video frame
|
||||
* sizes. oggplay_initialise() will return E_OGGPLAY_OUT_OF_MEMORY if the
|
||||
* decoded video's frame requires more than max_frame_pixels. Unless
|
||||
* oggplay_set_max_video_size() is called, default maximum number of pixels
|
||||
* per frame is INT_MAX.
|
||||
*
|
||||
* @param player OggPlay handle.
|
||||
* @param max_frame_pixels max number of pixels per frame.
|
||||
* @retval E_OGGPLAY_OK on success.
|
||||
* @retval E_OGGPLAY_BAD_OGGPLAY invalid OggPlay handle.
|
||||
*/
|
||||
int
|
||||
oggplay_set_max_video_frame_pixels(OggPlay *player,
|
||||
int max_frame_pixels);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __OGGPLAY_H__ */
|
|
@ -1,173 +0,0 @@
|
|||
/*
|
||||
Copyright (C) 2003 Commonwealth Scientific and Industrial Research
|
||||
Organisation (CSIRO) Australia
|
||||
|
||||
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.
|
||||
|
||||
- Neither the name of CSIRO Australia nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
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 ORGANISATION 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.
|
||||
*/
|
||||
|
||||
/** @file
|
||||
* oggplay_callback_info.h
|
||||
*
|
||||
* @authors
|
||||
* Shane Stephens <shane.stephens@annodex.net>
|
||||
* Michael Martin
|
||||
* Viktor Gal
|
||||
*/
|
||||
|
||||
#ifndef __OGGPLAY_CALLBACK_INFO__
|
||||
#define __OGGPLAY_CALLBACK_INFO__
|
||||
|
||||
/** structure for storing a YUV video frame */
|
||||
typedef struct {
|
||||
unsigned char * y; /**< Y-plane */
|
||||
unsigned char * u; /**< U-plane*/
|
||||
unsigned char * v; /**< V-plane */
|
||||
} OggPlayVideoData;
|
||||
|
||||
/** structure for storing a video frame in RGB fromat */
|
||||
typedef struct {
|
||||
unsigned char * rgba; /**< may be NULL if no alpha */
|
||||
unsigned char * rgb; /**< may be NULL if alpha */
|
||||
size_t width; /**< width in pixels */
|
||||
size_t height; /**< height in pixels */
|
||||
size_t stride; /**< stride */
|
||||
} OggPlayOverlayData;
|
||||
|
||||
/** Type for representing audio data */
|
||||
typedef void * OggPlayAudioData;
|
||||
|
||||
/** Type for representing text data */
|
||||
typedef char OggPlayTextData;
|
||||
|
||||
struct _OggPlayDataHeader;
|
||||
/** Header for the various data formats */
|
||||
typedef struct _OggPlayDataHeader OggPlayDataHeader;
|
||||
|
||||
/**
|
||||
* Get the data type of the given OggPlayCallbackInfo.
|
||||
*
|
||||
* @param info
|
||||
* @returns The data type of the given OggPlayCallbackInfo
|
||||
* @see OggPlayDataType
|
||||
*/
|
||||
OggPlayDataType
|
||||
oggplay_callback_info_get_type(OggPlayCallbackInfo *info);
|
||||
|
||||
int
|
||||
oggplay_callback_info_get_available(OggPlayCallbackInfo *info);
|
||||
|
||||
|
||||
int
|
||||
oggplay_callback_info_get_required(OggPlayCallbackInfo *info);
|
||||
|
||||
/**
|
||||
* Get the array of records stored in the OggPlayCallbackInfo
|
||||
*
|
||||
* @param info
|
||||
* @returns array of records
|
||||
* @retval NULL if the supplied OggPlayCallbackInfo is a NULL pointer
|
||||
*/
|
||||
OggPlayDataHeader **
|
||||
oggplay_callback_info_get_headers(OggPlayCallbackInfo *info);
|
||||
|
||||
/**
|
||||
* Get the size of the given record.
|
||||
*
|
||||
* @param header
|
||||
* @returns The number of samples in the record.
|
||||
*/
|
||||
ogg_int64_t
|
||||
oggplay_callback_info_get_record_size(OggPlayDataHeader *header);
|
||||
|
||||
/**
|
||||
* Extract the video frame from the supplied record.
|
||||
*
|
||||
* @param header
|
||||
* @returns the video frame
|
||||
* @retval NULL if the supplied OggPlayCallbackInfo is a NULL pointer
|
||||
*/
|
||||
OggPlayVideoData *
|
||||
oggplay_callback_info_get_video_data(OggPlayDataHeader *header);
|
||||
|
||||
/**
|
||||
* Extract the overlay data from the supplied record.
|
||||
*
|
||||
* @param header
|
||||
* @returns OggPlayOverlayData
|
||||
* @retval NULL if the supplied OggPlayCallbackInfo is a NULL pointer
|
||||
*/
|
||||
OggPlayOverlayData *
|
||||
oggplay_callback_info_get_overlay_data(OggPlayDataHeader *header);
|
||||
|
||||
/**
|
||||
* Extract the audio data from the supplied record.
|
||||
*
|
||||
* @param header
|
||||
* @returns OggPlayAudioData.
|
||||
* @retval NULL if the supplied OggPlayCallbackInfo is a NULL pointer
|
||||
*/
|
||||
OggPlayAudioData *
|
||||
oggplay_callback_info_get_audio_data(OggPlayDataHeader *header);
|
||||
|
||||
/**
|
||||
* Extract the text data from the supplied record.
|
||||
*
|
||||
* @param header
|
||||
* @returns OggPlayTextData
|
||||
* @retval NULL if the supplied OggPlayCallbackInfo is a NULL pointer
|
||||
*/
|
||||
OggPlayTextData *
|
||||
oggplay_callback_info_get_text_data(OggPlayDataHeader *header);
|
||||
|
||||
/**
|
||||
* Get the state of the stream.
|
||||
*
|
||||
* @param info
|
||||
* @returns State of the given stream.
|
||||
* @see OggPlayStreamInfo
|
||||
*/
|
||||
OggPlayStreamInfo
|
||||
oggplay_callback_info_get_stream_info(OggPlayCallbackInfo *info);
|
||||
|
||||
|
||||
void
|
||||
oggplay_callback_info_lock_item(OggPlayDataHeader *header);
|
||||
|
||||
void
|
||||
oggplay_callback_info_unlock_item(OggPlayDataHeader *header);
|
||||
|
||||
/**
|
||||
* Get the presentation time of the given record.
|
||||
*
|
||||
* @param header
|
||||
* @returns presentation time of the given frame in milliseconds.
|
||||
*/
|
||||
long
|
||||
oggplay_callback_info_get_presentation_time(OggPlayDataHeader *header);
|
||||
|
||||
#endif
|
|
@ -1,103 +0,0 @@
|
|||
/*
|
||||
Copyright (C) 2003 Commonwealth Scientific and Industrial Research
|
||||
Organisation (CSIRO) Australia
|
||||
|
||||
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.
|
||||
|
||||
- Neither the name of CSIRO Australia nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
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 ORGANISATION 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.
|
||||
*/
|
||||
|
||||
/** @file
|
||||
* General constants used by liboggplay
|
||||
*
|
||||
* @authors
|
||||
* Shane Stephens <shane.stephens@annodex.net>
|
||||
* Michael Martin
|
||||
* Viktor Gal
|
||||
*/
|
||||
|
||||
#ifndef __OGGPLAY_ENUMS_H__
|
||||
#define __OGGPLAY_ENUMS_H__
|
||||
|
||||
/**
|
||||
* Definitions of error return values.
|
||||
*/
|
||||
typedef enum OggPlayErrorCode {
|
||||
E_OGGPLAY_CONTINUE = 1,
|
||||
E_OGGPLAY_OK = 0, /**< No error */
|
||||
E_OGGPLAY_BAD_OGGPLAY = -1, /**< supplied oggplay is not a valid OggPlay */
|
||||
E_OGGPLAY_BAD_READER = -2, /**< OggPlayReader is invalid */
|
||||
E_OGGPLAY_BAD_INPUT = -3, /**< Error in the input */
|
||||
E_OGGPLAY_NO_SUCH_CHUNK = -4,
|
||||
E_OGGPLAY_BAD_TRACK = -5, /**< The requested track number does not exists */
|
||||
E_OGGPLAY_TRACK_IS_SKELETON = -6, /**< Trying to activate a Skeleton track */
|
||||
E_OGGPLAY_OGGZ_UNHAPPY = -7, /**< OGGZ error occured */
|
||||
E_OGGPLAY_END_OF_FILE = -8, /**< End of file */
|
||||
E_OGGPLAY_TRACK_IS_OVER = -9, /**< A given track has ended */
|
||||
E_OGGPLAY_BAD_CALLBACK_INFO = -10, /**< Invalid OggPlayCallbackInfo */
|
||||
E_OGGPLAY_WRONG_TRACK_TYPE = -11, /**< */
|
||||
E_OGGPLAY_UNINITIALISED = -12, /**< The OggPlay handle is not initialised */
|
||||
E_OGGPLAY_CALLBACK_MODE = -13, /**< OggPlay is used in callback mode */
|
||||
E_OGGPLAY_BUFFER_MODE = -14, /**< OggPlay is used in buffer mode */
|
||||
E_OGGPLAY_USER_INTERRUPT = -15, /**< User interrupt received */
|
||||
E_OGGPLAY_SOCKET_ERROR = -16, /**< Error while creating socket */
|
||||
E_OGGPLAY_TIMEOUT = -17, /**< TCP connection timeouted */
|
||||
E_OGGPLAY_CANT_SEEK = -18, /**< Could not performed the requested seek */
|
||||
E_OGGPLAY_NO_KATE_SUPPORT = -19, /**< LibKate is not supported */
|
||||
E_OGGPLAY_NO_TIGER_SUPPORT = -20, /**< LibTiger is not supported */
|
||||
E_OGGPLAY_OUT_OF_MEMORY = -21, /**< Out of memory */
|
||||
E_OGGPLAY_TYPE_OVERFLOW = -22, /**< Integer overflow detected */
|
||||
E_OGGPLAY_TRACK_IS_UNKNOWN = -23, /**< The selected track's content type is UNKNOWN */
|
||||
E_OGGPLAY_TRACK_UNINITIALISED = -24, /**< Track is not initialised, i.e. bad headers or haven't seen them */
|
||||
E_OGGPLAY_NOTCHICKENPAYBACK = -777
|
||||
} OggPlayErrorCode;
|
||||
|
||||
/**
|
||||
* Definitions of the various record types
|
||||
*/
|
||||
typedef enum OggPlayDataType {
|
||||
OGGPLAY_INACTIVE = -1, /**< record is inactive */
|
||||
OGGPLAY_YUV_VIDEO = 0, /**< record is a YUV format video */
|
||||
OGGPLAY_RGBA_VIDEO = 1, /**< record is a video in RGB format */
|
||||
OGGPLAY_SHORTS_AUDIO = 1000, /**< audio record in short format */
|
||||
OGGPLAY_FLOATS_AUDIO = 1001, /**< audio record in float format */
|
||||
OGGPLAY_CMML = 2000, /**< CMML record */
|
||||
OGGPLAY_KATE = 3000, /**< KATE record */
|
||||
OGGPLAY_TYPE_UNKNOWN = 9000 /**< content type of the record is unknown */
|
||||
} OggPlayDataType;
|
||||
|
||||
/**
|
||||
* Definitions of the various states of a stream.
|
||||
*/
|
||||
typedef enum OggPlayStreamInfo {
|
||||
OGGPLAY_STREAM_UNINITIALISED = 0, /**< Stream is not initialised */
|
||||
OGGPLAY_STREAM_FIRST_DATA = 1, /**< Stream received it's first data frame */
|
||||
OGGPLAY_STREAM_INITIALISED = 2, /**< Stream is initialised */
|
||||
OGGPLAY_STREAM_LAST_DATA = 3, /**< Stream received it's last data frame */
|
||||
OGGPLAY_STREAM_JUST_SEEKED = 4 /**< We've just seeked in the stream */
|
||||
} OggPlayStreamInfo;
|
||||
|
||||
#endif
|
|
@ -1,116 +0,0 @@
|
|||
/*
|
||||
Copyright (C) 2003 Commonwealth Scientific and Industrial Research
|
||||
Organisation (CSIRO) Australia
|
||||
|
||||
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.
|
||||
|
||||
- Neither the name of CSIRO Australia nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
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 ORGANISATION 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.
|
||||
*/
|
||||
|
||||
/** @file
|
||||
* oggplay_query.h
|
||||
*
|
||||
* @authors
|
||||
* Shane Stephens <shane.stephens@annodex.net>
|
||||
* Viktor Gal
|
||||
*/
|
||||
|
||||
#ifndef __OGGPLAY_QUERY_H__
|
||||
#define __OGGPLAY_QUERY_H__
|
||||
|
||||
#include <oggz/oggz.h>
|
||||
|
||||
/**
|
||||
* Get the number of tracks in the Ogg container.
|
||||
*
|
||||
* @param me OggPlay handle
|
||||
* @retval "> 0" number of tracks
|
||||
* @retval E_OGGPLAY_BAD_OGGPLAY the supplied OggPlay
|
||||
* @retval E_OGGPLAY_BAD_READER
|
||||
* @retval E_OGGPLAY_UNINITIALISED the is not initialised.
|
||||
*/
|
||||
int
|
||||
oggplay_get_num_tracks (OggPlay * me);
|
||||
|
||||
/**
|
||||
* Retrieve the type of a track.
|
||||
*
|
||||
* @param me OggPlay handle
|
||||
* @param track_num the desired track's number
|
||||
* @retval "> 0" the track's type (see OggzStreamContent)
|
||||
* @retval "< 0" error occured
|
||||
*/
|
||||
OggzStreamContent
|
||||
oggplay_get_track_type (OggPlay * me, int track_num);
|
||||
|
||||
/**
|
||||
* Get a track's type name.
|
||||
*
|
||||
* @param me OggPlay handle
|
||||
* @param track_num the desired track's number
|
||||
* @retval typa name of the track
|
||||
* @retval NULL in case of error.
|
||||
*/
|
||||
const char *
|
||||
oggplay_get_track_typename (OggPlay * me, int track_num);
|
||||
|
||||
/**
|
||||
* Set a track active.
|
||||
*
|
||||
* @param me OggPlay handle
|
||||
* @param track_num the desired track's number for activation
|
||||
* @retval E_OGGPLAY_OK on success
|
||||
* @retval E_OGGPLAY_BAD_OGGPLAY the supplied OggPlay is invalid
|
||||
* @retval E_OGGPLAY_BAD_READER the OggPlayReader associated with the Ogg
|
||||
* container is invalid
|
||||
* @retval E_OGGPLAY_UNINITIALISED the tracks are not initialised
|
||||
* @retval E_OGGPLAY_BAD_TRACK invalid track number
|
||||
* @retval E_OGGPLAY_TRACK_IS_SKELETON the chosen track is a Skeleton track
|
||||
* @retval E_OGGPLAY_TRACK_IS_UNKNOWN the chosen track's content type is unknown
|
||||
* @retval E_OGGPLAY_TRACK_UNINITIALISED the chosen track was not initialised
|
||||
* @retval E_OGGPLAY_TRACK_IS_OVER the track is over.
|
||||
*/
|
||||
OggPlayErrorCode
|
||||
oggplay_set_track_active(OggPlay *me, int track_num);
|
||||
|
||||
/**
|
||||
* Inactivate a given track.
|
||||
*
|
||||
* @param me OggPlay handle
|
||||
* @param track_num the desired track's number for inactivation
|
||||
* @retval E_OGGPLAY_OK on success
|
||||
* @retval E_OGGPLAY_BAD_OGGPLAY the supplied OggPlay is invalid
|
||||
* @retval E_OGGPLAY_BAD_READER the OggPlayReader associated with the Ogg
|
||||
* container is invalid
|
||||
* @retval E_OGGPLAY_UNINITIALISED the tracks are not initialised
|
||||
* @retval E_OGGPLAY_BAD_TRACK invalid track number
|
||||
* @retval E_OGGPLAY_TRACK_IS_SKELETON the chosen track is a Skeleton track
|
||||
* @retval E_OGGPLAY_TRACK_IS_UNKNOWN the chosen track's content type is unknown
|
||||
*/
|
||||
OggPlayErrorCode
|
||||
oggplay_set_track_inactive(OggPlay *me, int track_num);
|
||||
|
||||
#endif
|
|
@ -1,90 +0,0 @@
|
|||
/*
|
||||
Copyright (C) 2003 Commonwealth Scientific and Industrial Research
|
||||
Organisation (CSIRO) Australia
|
||||
|
||||
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.
|
||||
|
||||
- Neither the name of CSIRO Australia nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
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 ORGANISATION 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.
|
||||
*/
|
||||
|
||||
/** @file
|
||||
* oggplay_reader.h
|
||||
*
|
||||
* @authors
|
||||
* Shane Stephens <shane.stephens@annodex.net>
|
||||
* Michael Martin
|
||||
*/
|
||||
|
||||
#ifndef __OGGPLAY_READER_H__
|
||||
#define __OGGPLAY_READER_H__
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <oggz/oggz.h>
|
||||
#include <ogg/ogg.h>
|
||||
|
||||
struct _OggPlayReader;
|
||||
|
||||
/** */
|
||||
typedef struct _OggPlayReader {
|
||||
OggPlayErrorCode (*initialise) (struct _OggPlayReader * me, int block);
|
||||
OggPlayErrorCode (*destroy) (struct _OggPlayReader * me);
|
||||
OggPlayErrorCode (*seek) (struct _OggPlayReader *me, OGGZ *oggz,
|
||||
ogg_int64_t milliseconds);
|
||||
int (*available) (struct _OggPlayReader *me,
|
||||
ogg_int64_t current_bytes,
|
||||
ogg_int64_t current_time);
|
||||
ogg_int64_t (*duration) (struct _OggPlayReader *me);
|
||||
int (*finished_retrieving)(struct _OggPlayReader *me);
|
||||
|
||||
/* low-level io functions for oggz */
|
||||
size_t (*io_read)(void *user_handle, void *buf, size_t n);
|
||||
int (*io_seek)(void *user_handle, long offset, int whence);
|
||||
long (*io_tell)(void *user_handle);
|
||||
} OggPlayReader;
|
||||
|
||||
/**
|
||||
* Create and initialise an OggPlayReader for a given Ogg file.
|
||||
*
|
||||
* @param filename The file to open
|
||||
* @return A new OggPlayReader handle
|
||||
* @retval NULL if error occured.
|
||||
*/
|
||||
OggPlayReader *
|
||||
oggplay_file_reader_new(const char *filename);
|
||||
|
||||
/**
|
||||
* Create and initialise an OggPlayReader for an Ogg content at a given URI.
|
||||
*
|
||||
* @param uri The URI to the Ogg file.
|
||||
* @param proxy Proxy
|
||||
* @param proxy_port Proxy port.
|
||||
* @return A new OggPlayReader handle
|
||||
* @retval NULL on error.
|
||||
*/
|
||||
OggPlayReader *
|
||||
oggplay_tcp_reader_new(const char *uri, const char *proxy, int proxy_port);
|
||||
|
||||
#endif
|
|
@ -1,65 +0,0 @@
|
|||
/*
|
||||
Copyright (C) 2003 Commonwealth Scientific and Industrial Research
|
||||
Organisation (CSIRO) Australia
|
||||
|
||||
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.
|
||||
|
||||
- Neither the name of CSIRO Australia nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
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 ORGANISATION 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.
|
||||
*/
|
||||
|
||||
/** @file
|
||||
* oggplay_seek.h
|
||||
*
|
||||
* @authors
|
||||
* Shane Stephens <shane.stephens@annodex.net>
|
||||
*/
|
||||
|
||||
#ifndef __OGGPLAY_SEEK_H__
|
||||
#define __OGGPLAY_SEEK_H__
|
||||
|
||||
/**
|
||||
* Seeks to a requested position.
|
||||
*
|
||||
* @param me OggPlay handle associated with the stream
|
||||
* @param milliseconds
|
||||
* @retval E_OGGPLAY_OK on success
|
||||
* @retval E_OGGPLAY_BAD_OGGPLAY the supplied OggPlay handle was invalid
|
||||
* @retval E_OGGPLAY_CANT_SEEK error occured while trying to seek
|
||||
* @retval E_OGGPLAY_OUT_OF_MEMORY ran out of memory while trying to allocate the new buffer and trash.
|
||||
*/
|
||||
OggPlayErrorCode
|
||||
oggplay_seek(OggPlay *me, ogg_int64_t milliseconds);
|
||||
|
||||
/**
|
||||
* Seeks to key frame before |milliseconds|.
|
||||
*/
|
||||
OggPlayErrorCode
|
||||
oggplay_seek_to_keyframe(OggPlay *me,
|
||||
ogg_int64_t milliseconds,
|
||||
ogg_int64_t offset_begin,
|
||||
ogg_int64_t offset_end);
|
||||
|
||||
#endif
|
|
@ -1,96 +0,0 @@
|
|||
/*
|
||||
Copyright (C) 2003 Commonwealth Scientific and Industrial Research
|
||||
Organisation (CSIRO) Australia
|
||||
|
||||
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.
|
||||
|
||||
- Neither the name of CSIRO Australia nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
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 ORGANISATION 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.
|
||||
*/
|
||||
|
||||
/** @file
|
||||
* oggplay_tools.h
|
||||
*
|
||||
* @authors
|
||||
* Shane Stephens <shane.stephens@annodex.net>
|
||||
* Michael Martin
|
||||
*/
|
||||
|
||||
#ifndef __OGGPLAY_TOOLS_H__
|
||||
#define __OGGPLAY_TOOLS_H__
|
||||
|
||||
#include <ogg/ogg.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifdef WIN32
|
||||
#include <time.h>
|
||||
#else
|
||||
#include <sys/time.h>
|
||||
#include <time.h>
|
||||
#endif
|
||||
|
||||
/** structure holds pointers to y, u, v channels */
|
||||
typedef struct _OggPlayYUVChannels {
|
||||
unsigned char * ptry; /**< Y channel */
|
||||
unsigned char * ptru; /**< U channel */
|
||||
unsigned char * ptrv; /**< V channel*/
|
||||
int y_width; /**< the width of the Y plane */
|
||||
int y_height; /**< the height of the Y plane */
|
||||
int uv_width; /**< the width of the U/V plane */
|
||||
int uv_height; /**< the height of the U/V plane*/
|
||||
} OggPlayYUVChannels;
|
||||
|
||||
/** structure holds pointers to RGB packets */
|
||||
typedef struct _OggPlayRGBChannels {
|
||||
unsigned char * ptro; /**< the RGB stream in the requested packaging format */
|
||||
int rgb_width; /**< width of the RGB frame */
|
||||
int rgb_height; /**< height of the RGB frame */
|
||||
} OggPlayRGBChannels;
|
||||
|
||||
|
||||
void
|
||||
oggplay_yuv2rgba(const OggPlayYUVChannels *yuv, OggPlayRGBChannels * rgb);
|
||||
|
||||
void
|
||||
oggplay_yuv2bgra(const OggPlayYUVChannels* yuv, OggPlayRGBChannels * rgb);
|
||||
|
||||
void
|
||||
oggplay_yuv2argb(const OggPlayYUVChannels *yuv, OggPlayRGBChannels * rgb);
|
||||
|
||||
ogg_int64_t
|
||||
oggplay_sys_time_in_ms(void);
|
||||
|
||||
void
|
||||
oggplay_millisleep(long ms);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /*__OGGPLAY_TOOLS_H__*/
|
||||
|
|
@ -1,50 +0,0 @@
|
|||
commit 199a8cea6c4fd6d765254e7a384ac9df21ee2656
|
||||
Author: Viktor Gal <viktor.gal@maeth.com>
|
||||
Date: Fri May 8 15:44:51 2009 +1000
|
||||
|
||||
In the commit of 34c82de a bug was introduced in 'oggplay_data_handle_audio_data' function:
|
||||
the number of samples in the record was not the correct value! The value of it
|
||||
was incorrectly the size of the samples in the record.
|
||||
|
||||
diff --git a/src/liboggplay/oggplay_data.c b/src/liboggplay/oggplay_data.c
|
||||
index 4df5275..9376938 100644
|
||||
--- a/src/liboggplay/oggplay_data.c
|
||||
+++ b/src/liboggplay/oggplay_data.c
|
||||
@@ -301,6 +301,7 @@ oggplay_data_handle_audio_data (OggPlayDecode *decode, void *data,
|
||||
|
||||
int num_channels, ret;
|
||||
size_t record_size = sizeof(OggPlayAudioRecord);
|
||||
+ long samples_size;
|
||||
OggPlayAudioRecord * record = NULL;
|
||||
|
||||
num_channels = ((OggPlayAudioDecode *)decode)->sound_info.channels;
|
||||
@@ -310,17 +311,17 @@ oggplay_data_handle_audio_data (OggPlayDecode *decode, void *data,
|
||||
return E_OGGPLAY_TYPE_OVERFLOW;
|
||||
}
|
||||
|
||||
- ret = oggplay_mul_signed_overflow (samples, num_channels, &samples);
|
||||
+ ret = oggplay_mul_signed_overflow (samples, num_channels, &samples_size);
|
||||
if (ret == E_OGGPLAY_TYPE_OVERFLOW) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
- ret = oggplay_mul_signed_overflow (samples, samplesize, &samples);
|
||||
+ ret = oggplay_mul_signed_overflow (samples_size, samplesize, &samples_size);
|
||||
if (ret == E_OGGPLAY_TYPE_OVERFLOW) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
- ret = oggplay_check_add_overflow (record_size, samples, &record_size);
|
||||
+ ret = oggplay_check_add_overflow (record_size, samples_size, &record_size);
|
||||
if (ret == E_OGGPLAY_TYPE_OVERFLOW) {
|
||||
return ret;
|
||||
}
|
||||
@@ -339,7 +340,7 @@ oggplay_data_handle_audio_data (OggPlayDecode *decode, void *data,
|
||||
record->data = (void *)(record + 1);
|
||||
|
||||
/* copy the received data - the header has been initialised! */
|
||||
- memcpy (record->data, data, samples);
|
||||
+ memcpy (record->data, data, samples_size);
|
||||
/*
|
||||
printf("[%f%f%f]\n", ((float *)record->data)[0], ((float *)record->data)[1],
|
||||
((float *)record->data)[2]);
|
|
@ -1,304 +0,0 @@
|
|||
diff --git a/media/liboggplay/src/liboggplay/oggplay_private.h b/media/liboggplay/src/liboggplay/oggplay_private.h
|
||||
--- a/media/liboggplay/src/liboggplay/oggplay_private.h
|
||||
+++ b/media/liboggplay/src/liboggplay/oggplay_private.h
|
||||
@@ -62,16 +62,22 @@
|
||||
|
||||
#ifdef WIN32
|
||||
|
||||
#ifdef HAVE_WINSOCK2
|
||||
#include <winsock2.h>
|
||||
#else
|
||||
#include <winsock.h>
|
||||
#endif
|
||||
+#endif
|
||||
+
|
||||
+#ifdef OS2
|
||||
+#define INCL_DOSSEMAPHORES
|
||||
+#define INCL_DOSPROCESS
|
||||
+#include <os2.h>
|
||||
#endif
|
||||
|
||||
// for Win32 <windows.h> has to be included last
|
||||
#include "std_semaphore.h"
|
||||
|
||||
/**
|
||||
*
|
||||
* has_been_presented: 0 until the data has been added as a "required" element,
|
||||
diff --git a/media/liboggplay/src/liboggplay/oggplay_tools.c b/media/liboggplay/src/liboggplay/oggplay_tools.c
|
||||
--- a/media/liboggplay/src/liboggplay/oggplay_tools.c
|
||||
+++ b/media/liboggplay/src/liboggplay/oggplay_tools.c
|
||||
@@ -53,15 +53,17 @@ oggplay_sys_time_in_ms(void) {
|
||||
return (ogg_int64_t)tv.tv_sec * 1000 + (ogg_int64_t)tv.tv_usec / 1000;
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
oggplay_millisleep(long ms) {
|
||||
#ifdef WIN32
|
||||
Sleep(ms);
|
||||
+#elif defined(OS2)
|
||||
+ DosSleep(ms);
|
||||
#else
|
||||
struct timespec ts = {0, (ogg_int64_t)ms * 1000000LL};
|
||||
nanosleep(&ts, NULL);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
diff --git a/media/liboggplay/src/liboggplay/os2_semaphore.c b/media/liboggplay/src/liboggplay/os2_semaphore.c
|
||||
new file mode 100644
|
||||
--- /dev/null
|
||||
+++ b/media/liboggplay/src/liboggplay/os2_semaphore.c
|
||||
@@ -0,0 +1,163 @@
|
||||
+/* ***** BEGIN LICENSE BLOCK *****
|
||||
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
+ *
|
||||
+ * The contents of this file are subject to the Mozilla Public License Version
|
||||
+ * 1.1 (the "License"); you may not use this file except in compliance with
|
||||
+ * the License. You may obtain a copy of the License at
|
||||
+ * http://www.mozilla.org/MPL/
|
||||
+ *
|
||||
+ * Software distributed under the License is distributed on an "AS IS" basis,
|
||||
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
+ * for the specific language governing rights and limitations under the
|
||||
+ * License.
|
||||
+ *
|
||||
+ * The Original Code is the Mozilla browser.
|
||||
+ *
|
||||
+ * The Initial Developer of the Original Code is
|
||||
+ * Richard Walsh
|
||||
+ * Portions created by the Initial Developer are Copyright (c) 2008
|
||||
+ * the Initial Developer. All Rights Reserved.
|
||||
+ *
|
||||
+ * Contributor(s):
|
||||
+ *
|
||||
+ * Alternatively, the contents of this file may be used under the terms of
|
||||
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
+ * in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
+ * of those above. If you wish to allow use of your version of this file only
|
||||
+ * under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
+ * use your version of this file under the terms of the MPL, indicate your
|
||||
+ * decision by deleting the provisions above and replace them with the notice
|
||||
+ * and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
+ * the provisions above, a recipient may use your version of this file under
|
||||
+ * the terms of any one of the MPL, the GPL or the LGPL.
|
||||
+ *
|
||||
+ * ***** END LICENSE BLOCK ***** *
|
||||
+ */
|
||||
+/*****************************************************************************/
|
||||
+/*
|
||||
+ * This is a conservative implementation of a posix counting semaphore.
|
||||
+ * It relies on the state of the underlying OS/2 event semaphore to
|
||||
+ * control whether sem_wait() blocks or returns immediately, and only
|
||||
+ * uses its count to change the sem's state from posted to reset.
|
||||
+ * (A more "activist" approach would use the count to decide whether
|
||||
+ * to return immediately or to call DosWaitEventSem().)
|
||||
+ *
|
||||
+ */
|
||||
+/*****************************************************************************/
|
||||
+
|
||||
+#include <stdlib.h>
|
||||
+#define INCL_DOS
|
||||
+#include <os2.h>
|
||||
+#include "os2_semaphore.h"
|
||||
+
|
||||
+#ifndef ERROR_SEM_BUSY
|
||||
+#define ERROR_SEM_BUSY 301
|
||||
+#endif
|
||||
+
|
||||
+#define SEM_WAIT 20000
|
||||
+
|
||||
+/*****************************************************************************/
|
||||
+
|
||||
+int sem_init(sem_t *sem, int pshared, unsigned value)
|
||||
+{
|
||||
+ OS2SEM * psem;
|
||||
+
|
||||
+ if (!sem)
|
||||
+ return -1;
|
||||
+ *sem = 0;
|
||||
+
|
||||
+ psem = (OS2SEM*)malloc(sizeof(OS2SEM));
|
||||
+ if (!psem)
|
||||
+ return -1;
|
||||
+
|
||||
+ if (DosCreateMutexSem(0, &psem->hmtx, 0, 0)) {
|
||||
+ free(psem);
|
||||
+ return -1;
|
||||
+ }
|
||||
+
|
||||
+ if (DosCreateEventSem(0, &psem->hev, 0, (value ? 1 : 0))) {
|
||||
+ DosCloseMutexSem(psem->hmtx);
|
||||
+ free(psem);
|
||||
+ return -1;
|
||||
+ }
|
||||
+
|
||||
+ psem->cnt = value;
|
||||
+ *sem = psem;
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+/*****************************************************************************/
|
||||
+
|
||||
+int sem_wait(sem_t *sem)
|
||||
+{
|
||||
+ OS2SEM * psem;
|
||||
+ ULONG cnt;
|
||||
+
|
||||
+ if (!sem || !*sem)
|
||||
+ return -1;
|
||||
+ psem = *sem;
|
||||
+
|
||||
+ if (DosWaitEventSem(psem->hev, -1))
|
||||
+ return -1;
|
||||
+
|
||||
+ if (DosRequestMutexSem(psem->hmtx, SEM_WAIT))
|
||||
+ return -1;
|
||||
+
|
||||
+ if (psem->cnt)
|
||||
+ psem->cnt--;
|
||||
+ if (!psem->cnt)
|
||||
+ DosResetEventSem(psem->hev, &cnt);
|
||||
+ DosReleaseMutexSem(psem->hmtx);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+/*****************************************************************************/
|
||||
+
|
||||
+int sem_post(sem_t *sem)
|
||||
+{
|
||||
+ OS2SEM * psem;
|
||||
+
|
||||
+ if (!sem || !*sem)
|
||||
+ return -1;
|
||||
+ psem = *sem;
|
||||
+
|
||||
+ if (!DosRequestMutexSem(psem->hmtx, SEM_WAIT)) {
|
||||
+ psem->cnt++;
|
||||
+ DosPostEventSem(psem->hev);
|
||||
+ DosReleaseMutexSem(psem->hmtx);
|
||||
+ return 0;
|
||||
+ }
|
||||
+
|
||||
+ return -1;
|
||||
+}
|
||||
+
|
||||
+/*****************************************************************************/
|
||||
+
|
||||
+int sem_destroy(sem_t *sem)
|
||||
+{
|
||||
+ OS2SEM * psem;
|
||||
+
|
||||
+ if (!sem || !*sem)
|
||||
+ return -1;
|
||||
+ psem = *sem;
|
||||
+
|
||||
+ if (DosCloseMutexSem(psem->hmtx) == ERROR_SEM_BUSY) {
|
||||
+ DosRequestMutexSem(psem->hmtx, SEM_WAIT);
|
||||
+ DosReleaseMutexSem(psem->hmtx);
|
||||
+ DosCloseMutexSem(psem->hmtx);
|
||||
+ }
|
||||
+
|
||||
+ if (DosCloseEventSem(psem->hev) == ERROR_SEM_BUSY) {
|
||||
+ DosPostEventSem(psem->hev);
|
||||
+ DosSleep(1);
|
||||
+ DosCloseEventSem(psem->hev);
|
||||
+ }
|
||||
+
|
||||
+ free(psem);
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+/*****************************************************************************/
|
||||
+
|
||||
diff --git a/media/liboggplay/src/liboggplay/os2_semaphore.h b/media/liboggplay/src/liboggplay/os2_semaphore.h
|
||||
new file mode 100644
|
||||
--- /dev/null
|
||||
+++ b/media/liboggplay/src/liboggplay/os2_semaphore.h
|
||||
@@ -0,0 +1,57 @@
|
||||
+/* ***** BEGIN LICENSE BLOCK *****
|
||||
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
+ *
|
||||
+ * The contents of this file are subject to the Mozilla Public License Version
|
||||
+ * 1.1 (the "License"); you may not use this file except in compliance with
|
||||
+ * the License. You may obtain a copy of the License at
|
||||
+ * http://www.mozilla.org/MPL/
|
||||
+ *
|
||||
+ * Software distributed under the License is distributed on an "AS IS" basis,
|
||||
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
+ * for the specific language governing rights and limitations under the
|
||||
+ * License.
|
||||
+ *
|
||||
+ * The Original Code is the Mozilla browser.
|
||||
+ *
|
||||
+ * The Initial Developer of the Original Code is
|
||||
+ * Richard Walsh
|
||||
+ * Portions created by the Initial Developer are Copyright (c) 2008
|
||||
+ * the Initial Developer. All Rights Reserved.
|
||||
+ *
|
||||
+ * Contributor(s):
|
||||
+ *
|
||||
+ * Alternatively, the contents of this file may be used under the terms of
|
||||
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
+ * in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
+ * of those above. If you wish to allow use of your version of this file only
|
||||
+ * under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
+ * use your version of this file under the terms of the MPL, indicate your
|
||||
+ * decision by deleting the provisions above and replace them with the notice
|
||||
+ * and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
+ * the provisions above, a recipient may use your version of this file under
|
||||
+ * the terms of any one of the MPL, the GPL or the LGPL.
|
||||
+ *
|
||||
+ * ***** END LICENSE BLOCK ***** *
|
||||
+ */
|
||||
+/*****************************************************************************/
|
||||
+
|
||||
+#ifndef _os2_semaphore_
|
||||
+#define _os2_semaphore_
|
||||
+
|
||||
+typedef struct _OS2SEM {
|
||||
+ HMTX hmtx;
|
||||
+ HEV hev;
|
||||
+ ULONG cnt;
|
||||
+} OS2SEM;
|
||||
+
|
||||
+typedef OS2SEM * sem_t;
|
||||
+
|
||||
+int sem_init(sem_t *sem, int pshared, unsigned value);
|
||||
+int sem_wait(sem_t *sem);
|
||||
+int sem_post(sem_t *sem);
|
||||
+int sem_destroy(sem_t *sem);
|
||||
+
|
||||
+#endif
|
||||
+/*****************************************************************************/
|
||||
+
|
||||
diff --git a/media/liboggplay/src/liboggplay/std_semaphore.h b/media/liboggplay/src/liboggplay/std_semaphore.h
|
||||
--- a/media/liboggplay/src/liboggplay/std_semaphore.h
|
||||
+++ b/media/liboggplay/src/liboggplay/std_semaphore.h
|
||||
@@ -83,16 +83,23 @@ typedef sem_t semaphore;
|
||||
typedef sem_t semaphore;
|
||||
#elif defined(WIN32)
|
||||
#include <windows.h>
|
||||
#define SEM_CREATE(p,s) (!(p = CreateSemaphore(NULL, (long)(s), (long)(s), NULL)))
|
||||
#define SEM_SIGNAL(p) (!ReleaseSemaphore(p, 1, NULL))
|
||||
#define SEM_WAIT(p) WaitForSingleObject(p, INFINITE)
|
||||
#define SEM_CLOSE(p) (!CloseHandle(p))
|
||||
typedef HANDLE semaphore;
|
||||
+#elif defined(OS2)
|
||||
+#include "os2_semaphore.h"
|
||||
+#define SEM_CREATE(p,s) sem_init(&(p), 1, s)
|
||||
+#define SEM_SIGNAL(p) sem_post(&(p))
|
||||
+#define SEM_WAIT(p) sem_wait(&(p))
|
||||
+#define SEM_CLOSE(p) sem_destroy(&(p))
|
||||
+typedef sem_t semaphore;
|
||||
#elif defined(__APPLE__)
|
||||
#include <Carbon/Carbon.h>
|
||||
#define SEM_CREATE(p,s) MPCreateSemaphore(s, s, &(p))
|
||||
#define SEM_SIGNAL(p) MPSignalSemaphore(p)
|
||||
#define SEM_WAIT(p) MPWaitOnSemaphore(p, kDurationForever)
|
||||
#define SEM_CLOSE(p) MPDeleteSemaphore(p)
|
||||
typedef MPSemaphoreID semaphore;
|
||||
#endif
|
|
@ -1,87 +0,0 @@
|
|||
diff --git a/media/liboggplay/include/oggplay/oggplay_seek.h b/media/liboggplay/include/oggplay/oggplay_seek.h
|
||||
--- a/media/liboggplay/include/oggplay/oggplay_seek.h
|
||||
+++ b/media/liboggplay/include/oggplay/oggplay_seek.h
|
||||
@@ -48,9 +48,20 @@
|
||||
* @retval E_OGGPLAY_OK on success
|
||||
* @retval E_OGGPLAY_BAD_OGGPLAY the supplied OggPlay handle was invalid
|
||||
* @retval E_OGGPLAY_CANT_SEEK error occured while trying to seek
|
||||
* @retval E_OGGPLAY_OUT_OF_MEMORY ran out of memory while trying to allocate the new buffer and trash.
|
||||
*/
|
||||
OggPlayErrorCode
|
||||
oggplay_seek(OggPlay *me, ogg_int64_t milliseconds);
|
||||
|
||||
+/**
|
||||
+ * Seeks to key frame before |milliseconds|.
|
||||
+ */
|
||||
+OggPlayErrorCode
|
||||
+oggplay_seek_to_keyframe(OggPlay *me,
|
||||
+ int* tracks,
|
||||
+ int num_tracks,
|
||||
+ ogg_int64_t milliseconds,
|
||||
+ ogg_int64_t offset_begin,
|
||||
+ ogg_int64_t offset_end);
|
||||
+
|
||||
#endif
|
||||
diff --git a/media/liboggplay/src/liboggplay/oggplay_seek.c b/media/liboggplay/src/liboggplay/oggplay_seek.c
|
||||
--- a/media/liboggplay/src/liboggplay/oggplay_seek.c
|
||||
+++ b/media/liboggplay/src/liboggplay/oggplay_seek.c
|
||||
@@ -183,8 +183,59 @@ oggplay_take_out_trash(OggPlay *me, OggP
|
||||
}
|
||||
p = trash;
|
||||
}
|
||||
|
||||
if (p != NULL) {
|
||||
oggplay_free(p);
|
||||
}
|
||||
}
|
||||
+
|
||||
+OggPlayErrorCode
|
||||
+oggplay_seek_to_keyframe(OggPlay *me,
|
||||
+ int* tracks,
|
||||
+ int num_tracks,
|
||||
+ ogg_int64_t milliseconds,
|
||||
+ ogg_int64_t offset_begin,
|
||||
+ ogg_int64_t offset_end)
|
||||
+{
|
||||
+ long *serial_nos;
|
||||
+ int i;
|
||||
+ ogg_int64_t eof, time;
|
||||
+
|
||||
+ if (me == NULL) {
|
||||
+ return E_OGGPLAY_BAD_OGGPLAY;
|
||||
+ }
|
||||
+
|
||||
+ if (num_tracks > me->num_tracks || milliseconds < 0)
|
||||
+ return E_OGGPLAY_CANT_SEEK;
|
||||
+
|
||||
+ eof = oggplay_get_duration(me);
|
||||
+ if (eof > -1 && milliseconds > eof) {
|
||||
+ return E_OGGPLAY_CANT_SEEK;
|
||||
+ }
|
||||
+
|
||||
+ // Get the serialnos for the tracks we're seeking.
|
||||
+ serial_nos = (long*)oggplay_malloc(sizeof(long)*num_tracks);
|
||||
+ if (!serial_nos) {
|
||||
+ return E_OGGPLAY_CANT_SEEK;
|
||||
+ }
|
||||
+ for (i=0; i<num_tracks; i++) {
|
||||
+ serial_nos[i] = me->decode_data[tracks[i]]->serialno;
|
||||
+ }
|
||||
+
|
||||
+ time = oggz_keyframe_seek_set(me->oggz,
|
||||
+ serial_nos,
|
||||
+ num_tracks,
|
||||
+ milliseconds,
|
||||
+ offset_begin,
|
||||
+ offset_end);
|
||||
+ oggplay_free(serial_nos);
|
||||
+
|
||||
+ if (time == -1) {
|
||||
+ return E_OGGPLAY_CANT_SEEK;
|
||||
+ }
|
||||
+
|
||||
+ oggplay_seek_cleanup(me, time);
|
||||
+
|
||||
+ return E_OGGPLAY_OK;
|
||||
+
|
||||
+}
|
|
@ -1,47 +0,0 @@
|
|||
# ***** BEGIN LICENSE BLOCK *****
|
||||
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
#
|
||||
# The contents of this file are subject to the Mozilla Public License Version
|
||||
# 1.1 (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
# http://www.mozilla.org/MPL/
|
||||
#
|
||||
# Software distributed under the License is distributed on an "AS IS" basis,
|
||||
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
# for the specific language governing rights and limitations under the
|
||||
# License.
|
||||
#
|
||||
# The Original Code is Mozilla code.
|
||||
#
|
||||
# The Initial Developer of the Original Code is the Mozilla Corporation.
|
||||
# Portions created by the Initial Developer are Copyright (C) 2007
|
||||
# the Initial Developer. All Rights Reserved.
|
||||
#
|
||||
# Contributor(s):
|
||||
# Chris Double <chris.double@double.co.nz>
|
||||
#
|
||||
# Alternatively, the contents of this file may be used under the terms of
|
||||
# either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
# in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
# of those above. If you wish to allow use of your version of this file only
|
||||
# under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
# use your version of this file under the terms of the MPL, indicate your
|
||||
# decision by deleting the provisions above and replace them with the notice
|
||||
# and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
# the provisions above, a recipient may use your version of this file under
|
||||
# the terms of any one of the MPL, the GPL or the LGPL.
|
||||
#
|
||||
# ***** END LICENSE BLOCK *****
|
||||
|
||||
DEPTH = ../../..
|
||||
topsrcdir = @top_srcdir@
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
|
||||
include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
MODULE = oggplay
|
||||
DIRS = liboggplay
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
|
@ -1,81 +0,0 @@
|
|||
# ***** BEGIN LICENSE BLOCK *****
|
||||
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
#
|
||||
# The contents of this file are subject to the Mozilla Public License Version
|
||||
# 1.1 (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
# http://www.mozilla.org/MPL/
|
||||
#
|
||||
# Software distributed under the License is distributed on an "AS IS" basis,
|
||||
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
# for the specific language governing rights and limitations under the
|
||||
# License.
|
||||
#
|
||||
# The Original Code is Mozilla code.
|
||||
#
|
||||
# The Initial Developer of the Original Code is the Mozilla Corporation.
|
||||
# Portions created by the Initial Developer are Copyright (C) 2007
|
||||
# the Initial Developer. All Rights Reserved.
|
||||
#
|
||||
# Contributor(s):
|
||||
# Chris Double <chris.double@double.co.nz>
|
||||
#
|
||||
# Alternatively, the contents of this file may be used under the terms of
|
||||
# either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
# in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
# of those above. If you wish to allow use of your version of this file only
|
||||
# under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
# use your version of this file under the terms of the MPL, indicate your
|
||||
# decision by deleting the provisions above and replace them with the notice
|
||||
# and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
# the provisions above, a recipient may use your version of this file under
|
||||
# the terms of any one of the MPL, the GPL or the LGPL.
|
||||
#
|
||||
# ***** END LICENSE BLOCK *****
|
||||
|
||||
DEPTH = ../../../..
|
||||
topsrcdir = @top_srcdir@
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
|
||||
include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
DEFINES += -DHAVE_CONFIG_H
|
||||
|
||||
MODULE = oggplay
|
||||
LIBRARY_NAME = oggplay
|
||||
FORCE_STATIC_LIB= 1
|
||||
|
||||
EXPORTS = \
|
||||
oggplay_buffer.h \
|
||||
oggplay_callback.h \
|
||||
oggplay_data.h \
|
||||
std_semaphore.h \
|
||||
$(NULL)
|
||||
|
||||
CSRCS = \
|
||||
oggplay.c \
|
||||
oggplay_callback.c \
|
||||
oggplay_query.c \
|
||||
oggplay_data.c \
|
||||
oggplay_callback_info.c \
|
||||
oggplay_buffer.c \
|
||||
oggplay_seek.c \
|
||||
oggplay_yuv2rgb.c \
|
||||
oggplay_tools.c \
|
||||
$(NULL)
|
||||
|
||||
ifeq ($(OS_ARCH),OS2)
|
||||
EXPORTS += \
|
||||
os2_semaphore.h \
|
||||
$(NULL)
|
||||
|
||||
CSRCS += \
|
||||
os2_semaphore.c \
|
||||
$(NULL)
|
||||
endif
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
||||
LOCAL_INCLUDES += -I$(srcdir)/../../include/oggplay
|
|
@ -1,115 +0,0 @@
|
|||
/* config.h. Generated from config.h.in by configure. */
|
||||
/* config.h.in. Generated from configure.ac by autoheader. */
|
||||
|
||||
/* Define if building universal (internal helper macro) */
|
||||
/* #undef AC_APPLE_UNIVERSAL_BUILD */
|
||||
|
||||
/* Maximum supported data alignment */
|
||||
|
||||
|
||||
/* Define to 1 if you have the `assert' function. */
|
||||
/* #undef HAVE_ASSERT */
|
||||
|
||||
/* Define to 1 if you have the <dlfcn.h> header file. */
|
||||
#define HAVE_DLFCN_H 1
|
||||
|
||||
/* Define if have libfishsound */
|
||||
#define HAVE_FISHSOUND /**/
|
||||
|
||||
/* Define if we have GLUT. */
|
||||
/* #undef HAVE_GLUT */
|
||||
|
||||
/* Define if have Imlib2 */
|
||||
/* #undef HAVE_IMLIB2 */
|
||||
|
||||
/* Define to 1 if you have the <inttypes.h> header file. */
|
||||
#define HAVE_INTTYPES_H 1
|
||||
|
||||
/* Define if have libkate */
|
||||
/* #undef HAVE_KATE */
|
||||
|
||||
/* Define if have libsndfile */
|
||||
/* #undef HAVE_LIBSNDFILE1 */
|
||||
|
||||
/* Define to 1 if you have the <memory.h> header file. */
|
||||
#define HAVE_MEMORY_H 1
|
||||
|
||||
/* Define if have liboggz */
|
||||
#define HAVE_OGGZ /**/
|
||||
|
||||
/* Define to 1 if you have the <stdint.h> header file. */
|
||||
#define HAVE_STDINT_H 1
|
||||
|
||||
/* Define to 1 if you have the <stdlib.h> header file. */
|
||||
#define HAVE_STDLIB_H 1
|
||||
|
||||
/* Define to 1 if you have the <strings.h> header file. */
|
||||
#define HAVE_STRINGS_H 1
|
||||
|
||||
/* Define to 1 if you have the <string.h> header file. */
|
||||
#define HAVE_STRING_H 1
|
||||
|
||||
/* Define to 1 if you have the <sys/stat.h> header file. */
|
||||
#define HAVE_SYS_STAT_H 1
|
||||
|
||||
/* Define to 1 if you have the <sys/types.h> header file. */
|
||||
#define HAVE_SYS_TYPES_H 1
|
||||
|
||||
/* Define if have libtiger */
|
||||
/* #undef HAVE_TIGER */
|
||||
|
||||
/* Define to 1 if you have the <unistd.h> header file. */
|
||||
#define HAVE_UNISTD_H 1
|
||||
|
||||
/* Define to the sub-directory in which libtool stores uninstalled libraries.
|
||||
*/
|
||||
#define LT_OBJDIR ".libs/"
|
||||
|
||||
/* Define to 1 if your C compiler doesn't accept -c and -o together. */
|
||||
/* #undef NO_MINUS_C_MINUS_O */
|
||||
|
||||
/* Name of package */
|
||||
#define PACKAGE "liboggplay"
|
||||
|
||||
/* Define to the address where bug reports for this package should be sent. */
|
||||
#define PACKAGE_BUGREPORT ""
|
||||
|
||||
/* Define to the full name of this package. */
|
||||
#define PACKAGE_NAME ""
|
||||
|
||||
/* Define to the full name and version of this package. */
|
||||
#define PACKAGE_STRING ""
|
||||
|
||||
/* Define to the one symbol short name of this package. */
|
||||
#define PACKAGE_TARNAME ""
|
||||
|
||||
/* Define to the version of this package. */
|
||||
#define PACKAGE_VERSION ""
|
||||
|
||||
/* Define to 1 if you have the ANSI C header files. */
|
||||
#define STDC_HEADERS 1
|
||||
|
||||
/* Version number of package */
|
||||
#define VERSION "0.2.0"
|
||||
|
||||
/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most
|
||||
significant byte first (like Motorola and SPARC, unlike Intel). */
|
||||
#if defined AC_APPLE_UNIVERSAL_BUILD
|
||||
# if defined __BIG_ENDIAN__
|
||||
# define WORDS_BIGENDIAN 1
|
||||
# endif
|
||||
#else
|
||||
# ifndef WORDS_BIGENDIAN
|
||||
/* # undef WORDS_BIGENDIAN */
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* Define to empty if `const' does not conform to ANSI C. */
|
||||
/* #undef const */
|
||||
#undef HAVE_GLUT
|
||||
|
||||
#include "prcpucfg.h"
|
||||
#ifdef IS_BIG_ENDIAN
|
||||
#define WORDS_BIGENDIAN 1
|
||||
#endif
|
||||
|
|
@ -1,284 +0,0 @@
|
|||
/********************************************************************
|
||||
* *
|
||||
* THIS FILE IS PART OF THE OggTheora SOFTWARE CODEC SOURCE CODE. *
|
||||
* USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
|
||||
* GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
|
||||
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
|
||||
* *
|
||||
* THE Theora SOURCE CODE IS COPYRIGHT (C) 2002-2008 *
|
||||
* by the Xiph.Org Foundation and contributors http://www.xiph.org/ *
|
||||
* *
|
||||
********************************************************************
|
||||
|
||||
CPU capability detection for x86 processors.
|
||||
Originally written by Rudolf Marek.
|
||||
|
||||
function:
|
||||
last mod: $Id$
|
||||
|
||||
********************************************************************/
|
||||
|
||||
#include "cpu.h"
|
||||
|
||||
/* for detecting AltiVec support */
|
||||
# if (defined(__ppc__) || defined(__ppc64__))
|
||||
# if defined(__APPLE__) || defined(__MACOSX__)
|
||||
#include <sys/sysctl.h>
|
||||
# else
|
||||
#include <signal.h>
|
||||
#include <setjmp.h>
|
||||
# endif
|
||||
# endif
|
||||
|
||||
# if (defined(__ppc__) || defined(__ppc64__)) && !(defined(__APPLE__) || defined(__MACOSX__))
|
||||
static jmp_buf jmpbuf;
|
||||
|
||||
static void illegal_instruction(int sig)
|
||||
{
|
||||
longjmp(jmpbuf, 1);
|
||||
}
|
||||
# endif
|
||||
|
||||
#if defined(i386) || defined(__x86_64__) || defined(_M_IX86) || defined(_M_AMD64)
|
||||
# if !defined(_MSC_VER)
|
||||
# if defined(__amd64__)||defined(__x86_64__)
|
||||
/*On x86-64, gcc seems to be able to figure out how to save %rbx for us when
|
||||
compiling with -fPIC.*/
|
||||
# define cpuid(_op,_eax,_ebx,_ecx,_edx) \
|
||||
__asm__ __volatile__( \
|
||||
"cpuid\n\t" \
|
||||
:[eax]"=a"(_eax),[ebx]"=b"(_ebx),[ecx]"=c"(_ecx),[edx]"=d"(_edx) \
|
||||
:"a"(_op) \
|
||||
:"cc" \
|
||||
)
|
||||
# else
|
||||
/*On x86-32, not so much.*/
|
||||
# define cpuid(_op,_eax,_ebx,_ecx,_edx) \
|
||||
__asm__ __volatile__( \
|
||||
"xchgl %%ebx,%[ebx]\n\t" \
|
||||
"cpuid\n\t" \
|
||||
"xchgl %%ebx,%[ebx]\n\t" \
|
||||
:[eax]"=a"(_eax),[ebx]"=r"(_ebx),[ecx]"=c"(_ecx),[edx]"=d"(_edx) \
|
||||
:"a"(_op) \
|
||||
:"cc" \
|
||||
)
|
||||
# endif
|
||||
# else
|
||||
# if defined(_M_IX86)
|
||||
/*Why does MSVC need this complicated rigamarole?
|
||||
At this point I honestly do not care.*/
|
||||
|
||||
/*Visual C cpuid helper function.
|
||||
For VS2005 we could as well use the _cpuid builtin, but that wouldn't work
|
||||
for VS2003 users, so we do it in inline assembler.*/
|
||||
static void oc_cpuid_helper(ogg_uint32_t _cpu_info[4],ogg_uint32_t _op){
|
||||
_asm {
|
||||
mov eax,[_op]
|
||||
mov esi,_cpu_info
|
||||
cpuid
|
||||
mov [esi+0],eax
|
||||
mov [esi+4],ebx
|
||||
mov [esi+8],ecx
|
||||
mov [esi+12],edx
|
||||
}
|
||||
}
|
||||
|
||||
# define cpuid(_op,_eax,_ebx,_ecx,_edx) \
|
||||
do{ \
|
||||
ogg_uint32_t cpu_info[4]; \
|
||||
oc_cpuid_helper(cpu_info,_op); \
|
||||
(_eax)=cpu_info[0]; \
|
||||
(_ebx)=cpu_info[1]; \
|
||||
(_ecx)=cpu_info[2]; \
|
||||
(_edx)=cpu_info[3]; \
|
||||
}while(0)
|
||||
|
||||
static void oc_detect_cpuid_helper(ogg_uint32_t *_eax,ogg_uint32_t *_ebx){
|
||||
_asm{
|
||||
pushfd
|
||||
pushfd
|
||||
pop eax
|
||||
mov ebx,eax
|
||||
xor eax,200000h
|
||||
push eax
|
||||
popfd
|
||||
pushfd
|
||||
pop eax
|
||||
popfd
|
||||
mov ecx,_eax
|
||||
mov [ecx],eax
|
||||
mov ecx,_ebx
|
||||
mov [ecx],ebx
|
||||
}
|
||||
}
|
||||
# elif defined(_M_AMD64)
|
||||
# include <intrin.h>
|
||||
# define cpuid(_op,_eax,_ebx,_ecx,_edx) \
|
||||
do{ \
|
||||
int cpu_info[4]; \
|
||||
__cpuid(cpu_info,_op); \
|
||||
(_eax)=cpu_info[0]; \
|
||||
(_ebx)=cpu_info[1]; \
|
||||
(_ecx)=cpu_info[2]; \
|
||||
(_edx)=cpu_info[3]; \
|
||||
}while(0)
|
||||
# endif
|
||||
# endif
|
||||
#endif /* x86-only cpuid */
|
||||
|
||||
static ogg_uint32_t oc_parse_intel_flags(ogg_uint32_t _edx,ogg_uint32_t _ecx){
|
||||
ogg_uint32_t flags;
|
||||
/*If there isn't even MMX, give up.*/
|
||||
if(!(_edx&0x00800000))return 0;
|
||||
flags=OC_CPU_X86_MMX;
|
||||
if(_edx&0x02000000)flags|=OC_CPU_X86_MMXEXT|OC_CPU_X86_SSE;
|
||||
if(_edx&0x04000000)flags|=OC_CPU_X86_SSE2;
|
||||
if(_ecx&0x00000001)flags|=OC_CPU_X86_PNI;
|
||||
if(_ecx&0x00000100)flags|=OC_CPU_X86_SSSE3;
|
||||
if(_ecx&0x00080000)flags|=OC_CPU_X86_SSE4_1;
|
||||
if(_ecx&0x00100000)flags|=OC_CPU_X86_SSE4_2;
|
||||
return flags;
|
||||
}
|
||||
|
||||
static ogg_uint32_t oc_parse_amd_flags(ogg_uint32_t _edx,ogg_uint32_t _ecx){
|
||||
ogg_uint32_t flags;
|
||||
/*If there isn't even MMX, give up.*/
|
||||
if(!(_edx&0x00800000))return 0;
|
||||
flags=OC_CPU_X86_MMX;
|
||||
if(_edx&0x00400000)flags|=OC_CPU_X86_MMXEXT;
|
||||
if(_edx&0x80000000)flags|=OC_CPU_X86_3DNOW;
|
||||
if(_edx&0x40000000)flags|=OC_CPU_X86_3DNOWEXT;
|
||||
if(_ecx&0x00000040)flags|=OC_CPU_X86_SSE4A;
|
||||
if(_ecx&0x00000800)flags|=OC_CPU_X86_SSE5;
|
||||
return flags;
|
||||
}
|
||||
|
||||
static ogg_uint32_t oc_cpu_flags_get(void){
|
||||
ogg_uint32_t flags = 0;
|
||||
# if defined(__ppc__) || defined(__ppc64__)
|
||||
/* detect AltiVec extension if compiling it for ppc */
|
||||
# if defined(__APPLE__) || defined(__MACOSX__) || defined(__DARWIN__)
|
||||
int selectors[2] = { CTL_HW, HW_VECTORUNIT };
|
||||
int i_has_altivec = 0;
|
||||
size_t i_length = sizeof( i_has_altivec );
|
||||
int i_error = sysctl( selectors, 2, &i_has_altivec, &i_length, NULL, 0);
|
||||
|
||||
if( i_error == 0 && i_has_altivec != 0 )
|
||||
flags |= OC_CPU_PPC_ALTIVEC;
|
||||
# else
|
||||
void (*handler) (int sig);
|
||||
handler = signal(SIGILL, illegal_instruction);
|
||||
if (setjmp(jmpbuf) == 0)
|
||||
{
|
||||
__asm__ __volatile__ (
|
||||
"mtspr 256, %0\n\t"
|
||||
"vand %%v0, %%v0, %%v0"
|
||||
: : "r"(-1) );
|
||||
|
||||
flags |= OC_CPU_PPC_ALTIVEC;
|
||||
}
|
||||
signal(SIGILL, handler);
|
||||
# endif
|
||||
/* detect x86 CPU extensions */
|
||||
# elif defined(i386) || defined(__x86_64__) || defined(_M_IX86) || defined(_M_AMD64)
|
||||
ogg_uint32_t eax;
|
||||
ogg_uint32_t ebx;
|
||||
ogg_uint32_t ecx;
|
||||
ogg_uint32_t edx;
|
||||
# if !defined(__amd64__)&&!defined(__x86_64__)&&!defined(_M_AMD64)
|
||||
/*Not all x86-32 chips support cpuid, so we have to check.*/
|
||||
# if !defined(_MSC_VER)
|
||||
__asm__ __volatile__(
|
||||
"pushfl\n\t"
|
||||
"pushfl\n\t"
|
||||
"popl %[a]\n\t"
|
||||
"movl %[a],%[b]\n\t"
|
||||
"xorl $0x200000,%[a]\n\t"
|
||||
"pushl %[a]\n\t"
|
||||
"popfl\n\t"
|
||||
"pushfl\n\t"
|
||||
"popl %[a]\n\t"
|
||||
"popfl\n\t"
|
||||
:[a]"=r"(eax),[b]"=r"(ebx)
|
||||
:
|
||||
:"cc"
|
||||
);
|
||||
# else
|
||||
oc_detect_cpuid_helper(&eax,&ebx);
|
||||
# endif
|
||||
/*No cpuid.*/
|
||||
if(eax==ebx)return 0;
|
||||
# endif
|
||||
cpuid(0,eax,ebx,ecx,edx);
|
||||
/* l e t n I e n i u n e G*/
|
||||
if((ecx==0x6C65746E&&edx==0x49656E69&&ebx==0x756E6547)||
|
||||
/* 6 8 x M T e n i u n e G*/
|
||||
(ecx==0x3638784D&&edx==0x54656E69&&ebx==0x756E6547)) {
|
||||
/*Intel, Transmeta (tested with Crusoe TM5800):*/
|
||||
cpuid(1,eax,ebx,ecx,edx);
|
||||
flags=oc_parse_intel_flags(edx,ecx);
|
||||
}
|
||||
/* D M A c i t n e h t u A*/
|
||||
else if((ecx==0x444D4163&&edx==0x69746E65&&ebx==0x68747541)||
|
||||
/* C S N y b e d o e G*/
|
||||
(ecx==0x43534E20&&edx==0x79622065&&ebx==0x646F6547)){
|
||||
/*AMD, Geode:*/
|
||||
cpuid(0x80000000,eax,ebx,ecx,edx);
|
||||
if(eax<0x80000001)flags=0;
|
||||
else{
|
||||
cpuid(0x80000001,eax,ebx,ecx,edx);
|
||||
flags=oc_parse_amd_flags(edx,ecx);
|
||||
}
|
||||
/*Also check for SSE.*/
|
||||
cpuid(1,eax,ebx,ecx,edx);
|
||||
flags|=oc_parse_intel_flags(edx,ecx);
|
||||
}
|
||||
/*Technically some VIA chips can be configured in the BIOS to return any
|
||||
string here the user wants.
|
||||
There is a special detection method that can be used to identify such
|
||||
processors, but in my opinion, if the user really wants to change it, they
|
||||
deserve what they get.*/
|
||||
/* s l u a H r u a t n e C*/
|
||||
else if(ecx==0x736C7561&&edx==0x48727561&&ebx==0x746E6543){
|
||||
/*VIA:*/
|
||||
/*I only have documentation for the C7 (Esther) and Isaiah (forthcoming)
|
||||
chips (thanks to the engineers from Centaur Technology who provided it).
|
||||
These chips support Intel-like cpuid info.
|
||||
The C3-2 (Nehemiah) cores appear to, as well.*/
|
||||
cpuid(1,eax,ebx,ecx,edx);
|
||||
flags=oc_parse_intel_flags(edx,ecx);
|
||||
cpuid(0x80000000,eax,ebx,ecx,edx);
|
||||
if(eax>=0x80000001){
|
||||
/*The (non-Nehemiah) C3 processors support AMD-like cpuid info.
|
||||
We need to check this even if the Intel test succeeds to pick up 3DNow!
|
||||
support on these processors.
|
||||
Unlike actual AMD processors, we cannot _rely_ on this info, since
|
||||
some cores (e.g., the 693 stepping of the Nehemiah) claim to support
|
||||
this function, yet return edx=0, despite the Intel test indicating
|
||||
MMX support.
|
||||
Therefore the features detected here are strictly added to those
|
||||
detected by the Intel test.*/
|
||||
/*TODO: How about earlier chips?*/
|
||||
cpuid(0x80000001,eax,ebx,ecx,edx);
|
||||
/*Note: As of the C7, this function returns Intel-style extended feature
|
||||
flags, not AMD-style.
|
||||
Currently, this only defines bits 11, 20, and 29 (0x20100800), which
|
||||
do not conflict with any of the AMD flags we inspect.
|
||||
For the remaining bits, Intel tells us, "Do not count on their value",
|
||||
but VIA assures us that they will all be zero (at least on the C7 and
|
||||
Isaiah chips).
|
||||
In the (unlikely) event a future processor uses bits 18, 19, 30, or 31
|
||||
(0xC0C00000) for something else, we will have to add code to detect
|
||||
the model to decide when it is appropriate to inspect them.*/
|
||||
flags|=oc_parse_amd_flags(edx,ecx);
|
||||
}
|
||||
}
|
||||
else{
|
||||
/*Implement me.*/
|
||||
flags=0;
|
||||
}
|
||||
# else
|
||||
/* not x86 or ppc */
|
||||
# endif
|
||||
return flags;
|
||||
}
|
|
@ -1,34 +0,0 @@
|
|||
/********************************************************************
|
||||
* *
|
||||
* THIS FILE IS PART OF THE OggTheora SOFTWARE CODEC SOURCE CODE. *
|
||||
* USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
|
||||
* GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
|
||||
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
|
||||
* *
|
||||
* THE Theora SOURCE CODE IS COPYRIGHT (C) 2002-2007 *
|
||||
* by the Xiph.Org Foundation and contributors http://www.xiph.org/ *
|
||||
* *
|
||||
********************************************************************
|
||||
function:
|
||||
last mod: $Id$
|
||||
|
||||
********************************************************************/
|
||||
|
||||
#ifndef __CPU_H__
|
||||
#define __CPU_H__
|
||||
|
||||
#define OC_CPU_X86_MMX (1<<0)
|
||||
#define OC_CPU_X86_3DNOW (1<<1)
|
||||
#define OC_CPU_X86_3DNOWEXT (1<<2)
|
||||
#define OC_CPU_X86_MMXEXT (1<<3)
|
||||
#define OC_CPU_X86_SSE (1<<4)
|
||||
#define OC_CPU_X86_SSE2 (1<<5)
|
||||
#define OC_CPU_X86_PNI (1<<6)
|
||||
#define OC_CPU_X86_SSSE3 (1<<7)
|
||||
#define OC_CPU_X86_SSE4_1 (1<<8)
|
||||
#define OC_CPU_X86_SSE4_2 (1<<9)
|
||||
#define OC_CPU_X86_SSE4A (1<<10)
|
||||
#define OC_CPU_X86_SSE5 (1<<11)
|
||||
#define OC_CPU_PPC_ALTIVEC (1<<12)
|
||||
|
||||
#endif
|
|
@ -1,982 +0,0 @@
|
|||
/*
|
||||
Copyright (C) 2003 Commonwealth Scientific and Industrial Research
|
||||
Organisation (CSIRO) Australia
|
||||
|
||||
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.
|
||||
|
||||
- Neither the name of CSIRO Australia nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
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 ORGANISATION 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* oggplay.c
|
||||
*
|
||||
* Shane Stephens <shane.stephens@annodex.net>
|
||||
* Michael Martin
|
||||
*/
|
||||
|
||||
#include "oggplay_private.h"
|
||||
#include "oggplay_buffer.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define OGGZ_READ_CHUNK_SIZE 8192
|
||||
|
||||
OggPlay *
|
||||
oggplay_new_with_reader(OggPlayReader *reader) {
|
||||
|
||||
OggPlay * me = NULL;
|
||||
|
||||
/* check whether the reader is valid. */
|
||||
if (reader == NULL)
|
||||
return NULL;
|
||||
|
||||
me = (OggPlay *)oggplay_malloc (sizeof(OggPlay));
|
||||
if (me == NULL)
|
||||
return NULL;
|
||||
|
||||
me->reader = reader;
|
||||
me->decode_data = NULL;
|
||||
me->callback_info = NULL;
|
||||
me->num_tracks = 0;
|
||||
me->all_tracks_initialised = 0;
|
||||
me->callback_period = 0;
|
||||
me->callback = NULL;
|
||||
me->target = 0L;
|
||||
me->active_tracks = 0;
|
||||
me->buffer = NULL;
|
||||
me->shutdown = 0;
|
||||
me->trash = NULL;
|
||||
me->oggz = NULL;
|
||||
me->pt_update_valid = 1;
|
||||
me->duration = -1;
|
||||
me->max_video_frame_pixels = OGGPLAY_TYPE_MAX_SIGNED(int);
|
||||
|
||||
return me;
|
||||
|
||||
}
|
||||
|
||||
OggPlayErrorCode
|
||||
oggplay_initialise(OggPlay *me, int block) {
|
||||
|
||||
OggPlayErrorCode return_val;
|
||||
int i;
|
||||
|
||||
if (me == NULL) {
|
||||
return E_OGGPLAY_BAD_OGGPLAY;
|
||||
}
|
||||
|
||||
return_val = me->reader->initialise(me->reader, block);
|
||||
|
||||
if (return_val != E_OGGPLAY_OK) {
|
||||
return return_val;
|
||||
}
|
||||
|
||||
/*
|
||||
* this is the cut-off time value below which packets will be ignored. Initialise it to 0 here.
|
||||
* We'll reinitialise it when/if we encounter a skeleton header
|
||||
*/
|
||||
me->presentation_time = 0;
|
||||
|
||||
/*
|
||||
* start to retrieve data, until we get all of the track info. We need
|
||||
* to do this now so that the user can query us for this info before entering
|
||||
* the main loop
|
||||
*/
|
||||
me->oggz = oggz_new(OGGZ_READ | OGGZ_AUTO);
|
||||
if (me->oggz == NULL)
|
||||
return E_OGGPLAY_OGGZ_UNHAPPY;
|
||||
|
||||
if (oggz_io_set_read(me->oggz, me->reader->io_read, me->reader) != 0)
|
||||
return E_OGGPLAY_OGGZ_UNHAPPY;
|
||||
|
||||
if (oggz_io_set_seek(me->oggz, me->reader->io_seek, me->reader) != 0)
|
||||
return E_OGGPLAY_OGGZ_UNHAPPY;
|
||||
|
||||
if (oggz_io_set_tell(me->oggz, me->reader->io_tell, me->reader) != 0)
|
||||
return E_OGGPLAY_OGGZ_UNHAPPY;
|
||||
|
||||
if (oggz_set_read_callback(me->oggz, -1, oggplay_callback_predetected, me))
|
||||
return E_OGGPLAY_OGGZ_UNHAPPY;
|
||||
|
||||
while (1) {
|
||||
i = oggz_read (me->oggz, OGGZ_READ_CHUNK_SIZE);
|
||||
|
||||
switch (i) {
|
||||
case 0:
|
||||
/*
|
||||
* EOF reached while processing headers,
|
||||
* possible erroneous file, mark it as such.
|
||||
*/
|
||||
case OGGZ_ERR_HOLE_IN_DATA:
|
||||
/* there was a whole in the data */
|
||||
return E_OGGPLAY_BAD_INPUT;
|
||||
|
||||
case OGGZ_ERR_OUT_OF_MEMORY:
|
||||
/* ran out of memory during decoding! */
|
||||
return E_OGGPLAY_OUT_OF_MEMORY;
|
||||
|
||||
case OGGZ_ERR_STOP_ERR:
|
||||
/* */
|
||||
return E_OGGPLAY_BAD_OGGPLAY;
|
||||
|
||||
default:
|
||||
/* If the read otherwise failed, bail out. */
|
||||
if (i < 0)
|
||||
return E_OGGPLAY_BAD_INPUT;
|
||||
break;
|
||||
}
|
||||
|
||||
if (me->all_tracks_initialised) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* set all the tracks to inactive
|
||||
*/
|
||||
for (i = 0; i < me->num_tracks; i++) {
|
||||
me->decode_data[i]->active = 0;
|
||||
}
|
||||
me->active_tracks = 0;
|
||||
|
||||
/*
|
||||
* if the buffer was set up before initialisation, prepare it now
|
||||
*/
|
||||
if (me->buffer != NULL) {
|
||||
oggplay_buffer_prepare(me);
|
||||
}
|
||||
|
||||
return E_OGGPLAY_OK;
|
||||
|
||||
}
|
||||
|
||||
OggPlay *
|
||||
oggplay_open_with_reader(OggPlayReader *reader) {
|
||||
|
||||
OggPlay *me = NULL;
|
||||
int r = E_OGGPLAY_TIMEOUT;
|
||||
|
||||
if ((me = oggplay_new_with_reader(reader)) == NULL)
|
||||
return NULL;
|
||||
|
||||
while (r == E_OGGPLAY_TIMEOUT) {
|
||||
r = oggplay_initialise(me, 0);
|
||||
}
|
||||
|
||||
if (r != E_OGGPLAY_OK) {
|
||||
|
||||
/* in case of error close the OggPlay handle */
|
||||
oggplay_close(me);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return me;
|
||||
}
|
||||
|
||||
/*
|
||||
* API function to prevent bad input, and to prevent data callbacks being registered
|
||||
* in buffer mode
|
||||
*/
|
||||
OggPlayErrorCode
|
||||
oggplay_set_data_callback(OggPlay *me, OggPlayDataCallback callback,
|
||||
void *user) {
|
||||
|
||||
if (me == NULL) {
|
||||
return E_OGGPLAY_BAD_OGGPLAY;
|
||||
}
|
||||
|
||||
if (me->buffer != NULL) {
|
||||
return E_OGGPLAY_BUFFER_MODE;
|
||||
}
|
||||
|
||||
oggplay_set_data_callback_force(me, callback, user);
|
||||
return E_OGGPLAY_OK;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* internal function that doesn't perform error checking. Used so the buffer
|
||||
* can register a callback!
|
||||
*/
|
||||
void
|
||||
oggplay_set_data_callback_force(OggPlay *me, OggPlayDataCallback callback,
|
||||
void *user) {
|
||||
|
||||
me->callback = callback;
|
||||
me->callback_user_ptr = user;
|
||||
|
||||
}
|
||||
|
||||
|
||||
OggPlayErrorCode
|
||||
oggplay_set_callback_num_frames(OggPlay *me, int track, int frames) {
|
||||
|
||||
if (me == NULL) {
|
||||
return E_OGGPLAY_BAD_OGGPLAY;
|
||||
}
|
||||
|
||||
if (track < 0 || track >= me->num_tracks) {
|
||||
return E_OGGPLAY_BAD_TRACK;
|
||||
}
|
||||
|
||||
me->callback_period = me->decode_data[track]->granuleperiod * frames;
|
||||
me->target = me->presentation_time + me->callback_period - 1;
|
||||
|
||||
return E_OGGPLAY_OK;
|
||||
}
|
||||
|
||||
OggPlayErrorCode
|
||||
oggplay_set_callback_period(OggPlay *me, int track, int milliseconds) {
|
||||
|
||||
if (me == NULL) {
|
||||
return E_OGGPLAY_BAD_OGGPLAY;
|
||||
}
|
||||
|
||||
if (track < 0 || track >= me->num_tracks) {
|
||||
return E_OGGPLAY_BAD_TRACK;
|
||||
}
|
||||
|
||||
me->callback_period = OGGPLAY_TIME_INT_TO_FP(((ogg_int64_t)milliseconds))/1000;
|
||||
me->target = me->presentation_time + me->callback_period - 1;
|
||||
|
||||
return E_OGGPLAY_OK;
|
||||
}
|
||||
|
||||
OggPlayErrorCode
|
||||
oggplay_set_offset(OggPlay *me, int track, ogg_int64_t offset) {
|
||||
|
||||
if (me == NULL) {
|
||||
return E_OGGPLAY_BAD_OGGPLAY;
|
||||
}
|
||||
|
||||
if (track < 0 || track >= me->num_tracks) {
|
||||
return E_OGGPLAY_BAD_TRACK;
|
||||
}
|
||||
|
||||
me->decode_data[track]->offset = OGGPLAY_TIME_INT_TO_FP(offset) / 1000;
|
||||
|
||||
return E_OGGPLAY_OK;
|
||||
|
||||
}
|
||||
|
||||
OggPlayErrorCode
|
||||
oggplay_get_video_fps(OggPlay *me, int track, int* fps_denom, int* fps_num) {
|
||||
OggPlayTheoraDecode *decode;
|
||||
|
||||
if (me == NULL) {
|
||||
return E_OGGPLAY_BAD_OGGPLAY;
|
||||
}
|
||||
|
||||
if (track < 0 || track >= me->num_tracks) {
|
||||
return E_OGGPLAY_BAD_TRACK;
|
||||
}
|
||||
|
||||
if (me->decode_data[track]->decoded_type != OGGPLAY_YUV_VIDEO) {
|
||||
return E_OGGPLAY_WRONG_TRACK_TYPE;
|
||||
}
|
||||
|
||||
decode = (OggPlayTheoraDecode *)(me->decode_data[track]);
|
||||
|
||||
if ((decode->video_info.fps_denominator == 0)
|
||||
|| (decode->video_info.fps_numerator == 0)) {
|
||||
return E_OGGPLAY_UNINITIALISED;
|
||||
}
|
||||
|
||||
(*fps_denom) = decode->video_info.fps_denominator;
|
||||
(*fps_num) = decode->video_info.fps_numerator;
|
||||
|
||||
return E_OGGPLAY_OK;
|
||||
}
|
||||
|
||||
OggPlayErrorCode
|
||||
oggplay_get_video_aspect_ratio(OggPlay *me, int track, int* aspect_denom, int* aspect_num) {
|
||||
OggPlayTheoraDecode *decode;
|
||||
|
||||
if (me == NULL) {
|
||||
return E_OGGPLAY_BAD_OGGPLAY;
|
||||
}
|
||||
|
||||
if (track < 0 || track >= me->num_tracks) {
|
||||
return E_OGGPLAY_BAD_TRACK;
|
||||
}
|
||||
|
||||
if (me->decode_data[track]->decoded_type != OGGPLAY_YUV_VIDEO) {
|
||||
return E_OGGPLAY_WRONG_TRACK_TYPE;
|
||||
}
|
||||
|
||||
decode = (OggPlayTheoraDecode *)(me->decode_data[track]);
|
||||
|
||||
if ((decode->video_info.aspect_denominator == 0)
|
||||
|| (decode->video_info.aspect_numerator == 0)) {
|
||||
return E_OGGPLAY_UNINITIALISED;
|
||||
}
|
||||
|
||||
(*aspect_denom) = decode->video_info.aspect_denominator;
|
||||
(*aspect_num) = decode->video_info.aspect_numerator;
|
||||
|
||||
return E_OGGPLAY_OK;
|
||||
}
|
||||
|
||||
OggPlayErrorCode
|
||||
oggplay_convert_video_to_rgb(OggPlay *me, int track, int convert, int swap_rgb) {
|
||||
OggPlayTheoraDecode *decode;
|
||||
|
||||
if (me == NULL) {
|
||||
return E_OGGPLAY_BAD_OGGPLAY;
|
||||
}
|
||||
|
||||
if (track < 0 || track >= me->num_tracks) {
|
||||
return E_OGGPLAY_BAD_TRACK;
|
||||
}
|
||||
|
||||
if (me->decode_data[track]->content_type != OGGZ_CONTENT_THEORA) {
|
||||
return E_OGGPLAY_WRONG_TRACK_TYPE;
|
||||
}
|
||||
|
||||
decode = (OggPlayTheoraDecode *)(me->decode_data[track]);
|
||||
|
||||
if (decode->convert_to_rgb != convert || decode->swap_rgb != swap_rgb) {
|
||||
decode->convert_to_rgb = convert;
|
||||
decode->swap_rgb = swap_rgb;
|
||||
me->decode_data[track]->decoded_type = convert ? OGGPLAY_RGBA_VIDEO : OGGPLAY_YUV_VIDEO;
|
||||
|
||||
/* flush any records created with previous type */
|
||||
oggplay_data_free_list(me->decode_data[track]->data_list);
|
||||
me->decode_data[track]->data_list = NULL;
|
||||
}
|
||||
|
||||
return E_OGGPLAY_OK;
|
||||
}
|
||||
|
||||
OggPlayErrorCode
|
||||
oggplay_get_video_y_size(OggPlay *me, int track, int *y_width, int *y_height) {
|
||||
|
||||
OggPlayTheoraDecode *decode;
|
||||
|
||||
if (me == NULL) {
|
||||
return E_OGGPLAY_BAD_OGGPLAY;
|
||||
}
|
||||
|
||||
if (track < 0 || track >= me->num_tracks) {
|
||||
return E_OGGPLAY_BAD_TRACK;
|
||||
}
|
||||
|
||||
if (me->decode_data[track]->decoded_type != OGGPLAY_YUV_VIDEO) {
|
||||
return E_OGGPLAY_WRONG_TRACK_TYPE;
|
||||
}
|
||||
|
||||
decode = (OggPlayTheoraDecode *)(me->decode_data[track]);
|
||||
|
||||
if (decode->y_width == 0) {
|
||||
return E_OGGPLAY_UNINITIALISED;
|
||||
}
|
||||
|
||||
(*y_width) = decode->y_width;
|
||||
(*y_height) = decode->y_height;
|
||||
|
||||
return E_OGGPLAY_OK;
|
||||
|
||||
}
|
||||
|
||||
OggPlayErrorCode
|
||||
oggplay_get_video_uv_size(OggPlay *me, int track, int *uv_width, int *uv_height)
|
||||
{
|
||||
|
||||
OggPlayTheoraDecode *decode;
|
||||
|
||||
if (me == NULL) {
|
||||
return E_OGGPLAY_BAD_OGGPLAY;
|
||||
}
|
||||
|
||||
if (track < 0 || track >= me->num_tracks) {
|
||||
return E_OGGPLAY_BAD_TRACK;
|
||||
}
|
||||
|
||||
if (me->decode_data[track]->decoded_type != OGGPLAY_YUV_VIDEO) {
|
||||
return E_OGGPLAY_WRONG_TRACK_TYPE;
|
||||
}
|
||||
|
||||
decode = (OggPlayTheoraDecode *)(me->decode_data[track]);
|
||||
|
||||
if (decode->y_width == 0) {
|
||||
return E_OGGPLAY_UNINITIALISED;
|
||||
}
|
||||
|
||||
(*uv_width) = decode->uv_width;
|
||||
(*uv_height) = decode->uv_height;
|
||||
|
||||
return E_OGGPLAY_OK;
|
||||
|
||||
}
|
||||
|
||||
OggPlayErrorCode
|
||||
oggplay_get_audio_channels(OggPlay *me, int track, int* channels) {
|
||||
|
||||
OggPlayAudioDecode *decode;
|
||||
|
||||
if (me == NULL) {
|
||||
return E_OGGPLAY_BAD_OGGPLAY;
|
||||
}
|
||||
|
||||
if (track < 0 || track >= me->num_tracks) {
|
||||
return E_OGGPLAY_BAD_TRACK;
|
||||
}
|
||||
|
||||
if (me->decode_data[track]->decoded_type != OGGPLAY_FLOATS_AUDIO) {
|
||||
return E_OGGPLAY_WRONG_TRACK_TYPE;
|
||||
}
|
||||
|
||||
decode = (OggPlayAudioDecode *)(me->decode_data[track]);
|
||||
|
||||
if (decode->sound_info.channels == 0) {
|
||||
return E_OGGPLAY_UNINITIALISED;
|
||||
}
|
||||
(*channels) = decode->sound_info.channels;
|
||||
return E_OGGPLAY_OK;
|
||||
|
||||
}
|
||||
|
||||
OggPlayErrorCode
|
||||
oggplay_get_audio_samplerate(OggPlay *me, int track, int* rate) {
|
||||
|
||||
OggPlayAudioDecode * decode;
|
||||
|
||||
if (me == NULL) {
|
||||
return E_OGGPLAY_BAD_OGGPLAY;
|
||||
}
|
||||
|
||||
if (track < 0 || track >= me->num_tracks) {
|
||||
return E_OGGPLAY_BAD_TRACK;
|
||||
}
|
||||
|
||||
if (me->decode_data[track]->decoded_type != OGGPLAY_FLOATS_AUDIO) {
|
||||
return E_OGGPLAY_WRONG_TRACK_TYPE;
|
||||
}
|
||||
|
||||
decode = (OggPlayAudioDecode *)(me->decode_data[track]);
|
||||
|
||||
if (decode->sound_info.channels == 0) {
|
||||
return E_OGGPLAY_UNINITIALISED;
|
||||
}
|
||||
(*rate) = decode->sound_info.samplerate;
|
||||
return E_OGGPLAY_OK;
|
||||
|
||||
}
|
||||
|
||||
OggPlayErrorCode
|
||||
oggplay_get_kate_category(OggPlay *me, int track, const char** category) {
|
||||
|
||||
OggPlayKateDecode * decode;
|
||||
|
||||
if (me == NULL) {
|
||||
return E_OGGPLAY_BAD_OGGPLAY;
|
||||
}
|
||||
|
||||
if (track < 0 || track >= me->num_tracks) {
|
||||
return E_OGGPLAY_BAD_TRACK;
|
||||
}
|
||||
|
||||
if (me->decode_data[track]->content_type != OGGZ_CONTENT_KATE) {
|
||||
return E_OGGPLAY_WRONG_TRACK_TYPE;
|
||||
}
|
||||
|
||||
decode = (OggPlayKateDecode *)(me->decode_data[track]);
|
||||
|
||||
#ifdef HAVE_KATE
|
||||
if (decode->decoder.initialised) {
|
||||
(*category) = decode->k_state.ki->category;
|
||||
return E_OGGPLAY_OK;
|
||||
}
|
||||
else return E_OGGPLAY_UNINITIALISED;
|
||||
#else
|
||||
return E_OGGPLAY_NO_KATE_SUPPORT;
|
||||
#endif
|
||||
}
|
||||
|
||||
OggPlayErrorCode
|
||||
oggplay_get_kate_language(OggPlay *me, int track, const char** language) {
|
||||
|
||||
OggPlayKateDecode * decode;
|
||||
|
||||
if (me == NULL) {
|
||||
return E_OGGPLAY_BAD_OGGPLAY;
|
||||
}
|
||||
|
||||
if (track < 0 || track >= me->num_tracks) {
|
||||
return E_OGGPLAY_BAD_TRACK;
|
||||
}
|
||||
|
||||
if (me->decode_data[track]->content_type != OGGZ_CONTENT_KATE) {
|
||||
return E_OGGPLAY_WRONG_TRACK_TYPE;
|
||||
}
|
||||
|
||||
decode = (OggPlayKateDecode *)(me->decode_data[track]);
|
||||
|
||||
#ifdef HAVE_KATE
|
||||
if (decode->decoder.initialised) {
|
||||
(*language) = decode->k_state.ki->language;
|
||||
return E_OGGPLAY_OK;
|
||||
}
|
||||
else return E_OGGPLAY_UNINITIALISED;
|
||||
#else
|
||||
return E_OGGPLAY_NO_KATE_SUPPORT;
|
||||
#endif
|
||||
}
|
||||
|
||||
OggPlayErrorCode
|
||||
oggplay_set_kate_tiger_rendering(OggPlay *me, int track, int use_tiger, int swap_rgb, int default_width, int default_height) {
|
||||
|
||||
OggPlayKateDecode * decode;
|
||||
|
||||
if (me == NULL) {
|
||||
return E_OGGPLAY_BAD_OGGPLAY;
|
||||
}
|
||||
|
||||
if (track < 0 || track >= me->num_tracks) {
|
||||
return E_OGGPLAY_BAD_TRACK;
|
||||
}
|
||||
|
||||
if (me->decode_data[track]->content_type != OGGZ_CONTENT_KATE) {
|
||||
return E_OGGPLAY_WRONG_TRACK_TYPE;
|
||||
}
|
||||
|
||||
decode = (OggPlayKateDecode *)(me->decode_data[track]);
|
||||
|
||||
#ifdef HAVE_KATE
|
||||
#ifdef HAVE_TIGER
|
||||
if (decode->decoder.initialised && decode->tr) {
|
||||
decode->use_tiger = use_tiger;
|
||||
decode->swap_rgb = swap_rgb;
|
||||
decode->default_width = default_width;
|
||||
decode->default_height = default_height;
|
||||
decode->decoder.decoded_type = use_tiger ? OGGPLAY_RGBA_VIDEO : OGGPLAY_KATE;
|
||||
return E_OGGPLAY_OK;
|
||||
}
|
||||
else return E_OGGPLAY_UNINITIALISED;
|
||||
#else
|
||||
return E_OGGPLAY_NO_TIGER_SUPPORT;
|
||||
#endif
|
||||
#else
|
||||
return E_OGGPLAY_NO_KATE_SUPPORT;
|
||||
#endif
|
||||
}
|
||||
|
||||
OggPlayErrorCode
|
||||
oggplay_overlay_kate_track_on_video(OggPlay *me, int kate_track, int video_track) {
|
||||
|
||||
OggPlayKateDecode * decode;
|
||||
|
||||
if (me == NULL) {
|
||||
return E_OGGPLAY_BAD_OGGPLAY;
|
||||
}
|
||||
|
||||
if (kate_track < 0 || kate_track >= me->num_tracks) {
|
||||
return E_OGGPLAY_BAD_TRACK;
|
||||
}
|
||||
if (video_track < 0 || video_track >= me->num_tracks) {
|
||||
return E_OGGPLAY_BAD_TRACK;
|
||||
}
|
||||
|
||||
if (me->decode_data[kate_track]->content_type != OGGZ_CONTENT_KATE) {
|
||||
return E_OGGPLAY_WRONG_TRACK_TYPE;
|
||||
}
|
||||
|
||||
if (me->decode_data[kate_track]->decoded_type != OGGPLAY_RGBA_VIDEO) {
|
||||
return E_OGGPLAY_WRONG_TRACK_TYPE;
|
||||
}
|
||||
|
||||
if (me->decode_data[video_track]->content_type != OGGZ_CONTENT_THEORA) {
|
||||
return E_OGGPLAY_WRONG_TRACK_TYPE;
|
||||
}
|
||||
|
||||
if (me->decode_data[video_track]->decoded_type != OGGPLAY_RGBA_VIDEO) {
|
||||
return E_OGGPLAY_WRONG_TRACK_TYPE;
|
||||
}
|
||||
|
||||
decode = (OggPlayKateDecode *)(me->decode_data[kate_track]);
|
||||
|
||||
#ifdef HAVE_KATE
|
||||
#ifdef HAVE_TIGER
|
||||
decode->overlay_dest = video_track;
|
||||
return E_OGGPLAY_OK;
|
||||
#else
|
||||
return E_OGGPLAY_NO_TIGER_SUPPORT;
|
||||
#endif
|
||||
#else
|
||||
return E_OGGPLAY_NO_KATE_SUPPORT;
|
||||
#endif
|
||||
}
|
||||
|
||||
#define MAX_CHUNK_COUNT 10
|
||||
|
||||
OggPlayErrorCode
|
||||
oggplay_step_decoding(OggPlay *me) {
|
||||
|
||||
OggPlayCallbackInfo ** info;
|
||||
int num_records;
|
||||
int r;
|
||||
int i;
|
||||
int need_data = 0;
|
||||
int chunk_count = 0;
|
||||
int read_data = 0;
|
||||
|
||||
if (me == NULL) {
|
||||
return E_OGGPLAY_BAD_OGGPLAY;
|
||||
}
|
||||
|
||||
/*
|
||||
* check whether the OggPlayDataCallback is set for the given
|
||||
* OggPlay handle. If not return with error as there's no callback
|
||||
* function processing the decoded data.
|
||||
*/
|
||||
if (me->callback == NULL) {
|
||||
return E_OGGPLAY_UNINITIALISED;
|
||||
}
|
||||
|
||||
/*
|
||||
* clean up any trash pointers. As soon as the current buffer has a
|
||||
* frame taken out, we know the old buffer will no longer be used.
|
||||
*/
|
||||
|
||||
if
|
||||
(
|
||||
me->trash != NULL
|
||||
&&
|
||||
(me->buffer == NULL || me->buffer->last_emptied > -1)
|
||||
)
|
||||
{
|
||||
oggplay_take_out_trash(me, me->trash);
|
||||
me->trash = NULL;
|
||||
}
|
||||
|
||||
read_more_data:
|
||||
|
||||
while (1) {
|
||||
/*
|
||||
* if there are no active tracks, we might need to return some data
|
||||
* left over at the end of a once-active track that has had all of its
|
||||
* data processed. Look through the tracks to find these overhangs
|
||||
*/
|
||||
int r;
|
||||
|
||||
if (me->active_tracks == 0) {
|
||||
int remaining = 0;
|
||||
for (i = 0; i < me->num_tracks; i++) {
|
||||
if (me->decode_data[i]->current_loc +
|
||||
me->decode_data[i]->granuleperiod >= me->target + me->decode_data[i]->offset) {
|
||||
remaining++;
|
||||
}
|
||||
}
|
||||
if (remaining == 0 && !read_data) {
|
||||
/*
|
||||
* There's no more data to read, and we've not read any that needs
|
||||
* to be sent to the buffer list via a callback, so exit.
|
||||
*/
|
||||
return E_OGGPLAY_OK;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* if any of the tracks have not yet met the target (modified by that
|
||||
* track's offset), then retrieve more data
|
||||
*/
|
||||
need_data = 0;
|
||||
for (i = 0; i < me->num_tracks; i++) {
|
||||
if (me->decode_data[i]->active == 0)
|
||||
continue;
|
||||
if (me->decode_data[i]->content_type == OGGZ_CONTENT_CMML)
|
||||
continue;
|
||||
if (me->decode_data[i]->content_type == OGGZ_CONTENT_KATE)
|
||||
continue;
|
||||
if
|
||||
(
|
||||
me->decode_data[i]->current_loc
|
||||
<
|
||||
me->target + me->decode_data[i]->offset
|
||||
)
|
||||
{
|
||||
need_data = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!need_data) {
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* get a chunk of data. If we're at the end of the file, then we must
|
||||
* have some final frames to render (?). E_OGGPLAY_END_OF_FILE is
|
||||
* only returned if there is *no* more data.
|
||||
*/
|
||||
|
||||
if (chunk_count > MAX_CHUNK_COUNT) {
|
||||
return E_OGGPLAY_TIMEOUT;
|
||||
}
|
||||
|
||||
chunk_count += 1;
|
||||
|
||||
r = oggz_read(me->oggz, OGGZ_READ_CHUNK_SIZE);
|
||||
|
||||
switch (r) {
|
||||
case 0:
|
||||
/* end-of-file */
|
||||
|
||||
num_records = oggplay_callback_info_prepare(me, &info);
|
||||
/*
|
||||
* set all of the tracks to inactive
|
||||
*/
|
||||
for (i = 0; i < me->num_tracks; i++) {
|
||||
me->decode_data[i]->active = 0;
|
||||
}
|
||||
me->active_tracks = 0;
|
||||
|
||||
if (info != NULL) {
|
||||
/* ensure all tracks have their final data packet set to end_of_stream */
|
||||
OggPlayCallbackInfo *p = info[0];
|
||||
for (i = 0; i < me->num_tracks; i++) {
|
||||
p->stream_info = OGGPLAY_STREAM_LAST_DATA;
|
||||
p++;
|
||||
}
|
||||
|
||||
me->callback (me, num_records, info, me->callback_user_ptr);
|
||||
oggplay_callback_info_destroy(me, info);
|
||||
}
|
||||
|
||||
/* we reached the end of the stream */
|
||||
return E_OGGPLAY_OK;
|
||||
|
||||
case OGGZ_ERR_HOLE_IN_DATA:
|
||||
/* there was a whole in the data */
|
||||
return E_OGGPLAY_BAD_INPUT;
|
||||
|
||||
case OGGZ_ERR_STOP_ERR:
|
||||
/*
|
||||
* one of the callback functions requested us to stop.
|
||||
* as this currently happens only when one of the
|
||||
* OggzReadPacket callback functions does not receive
|
||||
* the user provided data, i.e. the OggPlayDecode struct
|
||||
* for the track mark it as a memory problem, since this
|
||||
* could happen only if something is wrong with the memory,
|
||||
* e.g. some buffer overflow.
|
||||
*/
|
||||
|
||||
case OGGZ_ERR_OUT_OF_MEMORY:
|
||||
/* ran out of memory during decoding! */
|
||||
return E_OGGPLAY_OUT_OF_MEMORY;
|
||||
|
||||
default:
|
||||
/*
|
||||
* We read some data. Set a flag so that we're guaranteed to try to
|
||||
* send it to the buffer list via a callback.
|
||||
*/
|
||||
read_data = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* prepare a callback
|
||||
*/
|
||||
num_records = oggplay_callback_info_prepare (me, &info);
|
||||
if (info != NULL) {
|
||||
r = me->callback (me, num_records, info, me->callback_user_ptr);
|
||||
oggplay_callback_info_destroy (me, info);
|
||||
} else {
|
||||
r = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* clean the data lists
|
||||
*/
|
||||
for (i = 0; i < me->num_tracks; i++) {
|
||||
oggplay_data_clean_list (me->decode_data[i]);
|
||||
}
|
||||
|
||||
/*
|
||||
* there was an error during info prepare!
|
||||
* abort decoding!
|
||||
*/
|
||||
if (num_records < 0) {
|
||||
return num_records;
|
||||
}
|
||||
|
||||
/* if we received an shutdown event, dont try to read more data...*/
|
||||
if (me->shutdown) {
|
||||
return E_OGGPLAY_OK;
|
||||
}
|
||||
|
||||
/* we require more data for decoding */
|
||||
if (info == NULL) {
|
||||
goto read_more_data;
|
||||
}
|
||||
|
||||
me->target += me->callback_period;
|
||||
if (r == -1) {
|
||||
return E_OGGPLAY_USER_INTERRUPT;
|
||||
}
|
||||
|
||||
return E_OGGPLAY_CONTINUE;
|
||||
|
||||
}
|
||||
|
||||
OggPlayErrorCode
|
||||
oggplay_start_decoding(OggPlay *me) {
|
||||
|
||||
int r;
|
||||
|
||||
while (1) {
|
||||
r = oggplay_step_decoding(me);
|
||||
if (r == E_OGGPLAY_CONTINUE || r == E_OGGPLAY_TIMEOUT) {
|
||||
continue;
|
||||
}
|
||||
return (OggPlayErrorCode)r;
|
||||
}
|
||||
}
|
||||
|
||||
OggPlayErrorCode
|
||||
oggplay_close(OggPlay *me) {
|
||||
|
||||
int i;
|
||||
|
||||
if (me == NULL) {
|
||||
return E_OGGPLAY_BAD_OGGPLAY;
|
||||
}
|
||||
|
||||
if (me->reader != NULL) {
|
||||
me->reader->destroy(me->reader);
|
||||
}
|
||||
|
||||
/* */
|
||||
if (me->decode_data != NULL) {
|
||||
for (i = 0; i < me->num_tracks; i++) {
|
||||
oggplay_callback_shutdown(me->decode_data[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if (me->oggz)
|
||||
oggz_close(me->oggz);
|
||||
|
||||
if (me->buffer != NULL) {
|
||||
oggplay_buffer_shutdown(me, me->buffer);
|
||||
}
|
||||
|
||||
if (me->callback_info != NULL) {
|
||||
oggplay_free(me->callback_info);
|
||||
}
|
||||
|
||||
oggplay_free(me->decode_data);
|
||||
oggplay_free(me);
|
||||
|
||||
return E_OGGPLAY_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* this function is required to release the frame_sem in the buffer, if
|
||||
* the buffer is being used.
|
||||
*/
|
||||
void
|
||||
oggplay_prepare_for_close(OggPlay *me) {
|
||||
|
||||
me->shutdown = 1;
|
||||
if (me->buffer != NULL) {
|
||||
SEM_SIGNAL(((OggPlayBuffer *)(me->buffer))->frame_sem);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
oggplay_get_available(OggPlay *me) {
|
||||
|
||||
ogg_int64_t current_time, current_byte;
|
||||
|
||||
if (me == NULL) {
|
||||
return E_OGGPLAY_BAD_OGGPLAY;
|
||||
}
|
||||
|
||||
current_time = oggz_tell_units(me->oggz);
|
||||
current_byte = (ogg_int64_t)oggz_tell(me->oggz);
|
||||
|
||||
return me->reader->available(me->reader, current_byte, current_time);
|
||||
|
||||
}
|
||||
|
||||
ogg_int64_t
|
||||
oggplay_get_duration(OggPlay *me) {
|
||||
|
||||
if (me == NULL) {
|
||||
return E_OGGPLAY_BAD_OGGPLAY;
|
||||
}
|
||||
|
||||
/* If the reader has a duration function we always call that
|
||||
* function to find the duration. We never cache the result
|
||||
* of that function.
|
||||
*
|
||||
* If there is no reader duration function we use our cached
|
||||
* duration value, or do a liboggz seek to find it and cache
|
||||
* that.
|
||||
*/
|
||||
if (me->reader->duration) {
|
||||
ogg_int64_t d = me->reader->duration(me->reader);
|
||||
if (d >= 0) {
|
||||
me->duration = d;
|
||||
}
|
||||
}
|
||||
|
||||
if (me->duration < 0) {
|
||||
ogg_int64_t pos;
|
||||
pos = oggz_tell_units(me->oggz);
|
||||
me->duration = oggz_seek_units(me->oggz, 0, SEEK_END);
|
||||
oggz_seek_units(me->oggz, pos, SEEK_SET);
|
||||
oggplay_seek_cleanup(me, pos);
|
||||
}
|
||||
|
||||
return me->duration;
|
||||
}
|
||||
|
||||
int
|
||||
oggplay_media_finished_retrieving(OggPlay *me) {
|
||||
|
||||
if (me == NULL) {
|
||||
return E_OGGPLAY_BAD_OGGPLAY;
|
||||
}
|
||||
|
||||
if (me->reader == NULL) {
|
||||
return E_OGGPLAY_BAD_READER;
|
||||
}
|
||||
|
||||
return me->reader->finished_retrieving(me->reader);
|
||||
|
||||
}
|
||||
|
||||
int
|
||||
oggplay_set_max_video_frame_pixels(OggPlay *player,
|
||||
int max_frame_pixels) {
|
||||
if (!player)
|
||||
return E_OGGPLAY_BAD_OGGPLAY;
|
||||
player->max_video_frame_pixels = max_frame_pixels;
|
||||
return E_OGGPLAY_OK;
|
||||
}
|
|
@ -1,372 +0,0 @@
|
|||
/*
|
||||
Copyright (C) 2003 Commonwealth Scientific and Industrial Research
|
||||
Organisation (CSIRO) Australia
|
||||
|
||||
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.
|
||||
|
||||
- Neither the name of CSIRO Australia nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
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 ORGANISATION 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* oggplay_buffer.c
|
||||
*
|
||||
* Shane Stephens <shane.stephens@annodex.net>
|
||||
*/
|
||||
|
||||
#include "oggplay_private.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#define OGGPLAY_DEFAULT_BUFFER_SIZE 20
|
||||
#define WRAP_INC(c, s) ((c + 1) % s)
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Call this function to initialise the oggplay lock-free buffer. Do not use
|
||||
* the buffer and the callback together!
|
||||
*/
|
||||
OggPlayBuffer *
|
||||
oggplay_buffer_new_buffer(int size) {
|
||||
|
||||
OggPlayBuffer *buffer = NULL;
|
||||
if (size < 0) {
|
||||
size = OGGPLAY_DEFAULT_BUFFER_SIZE;
|
||||
}
|
||||
|
||||
buffer = (OggPlayBuffer*)oggplay_calloc(1, sizeof (OggPlayBuffer));
|
||||
|
||||
if (buffer == NULL)
|
||||
return NULL;
|
||||
|
||||
buffer->buffer_list = oggplay_calloc(size, sizeof (void *));
|
||||
if (buffer->buffer_list == NULL)
|
||||
goto error;
|
||||
|
||||
buffer->buffer_mirror = oggplay_calloc(size, sizeof (void *));
|
||||
if (buffer->buffer_mirror == NULL)
|
||||
goto error;
|
||||
|
||||
buffer->buffer_size = size;
|
||||
buffer->last_filled = -1;
|
||||
buffer->last_emptied = -1;
|
||||
|
||||
if (SEM_CREATE(buffer->frame_sem, size) != 0)
|
||||
goto error;
|
||||
|
||||
return buffer;
|
||||
|
||||
error:
|
||||
if (buffer->buffer_list != NULL)
|
||||
oggplay_free (buffer->buffer_list);
|
||||
|
||||
if (buffer->buffer_mirror != NULL)
|
||||
oggplay_free (buffer->buffer_mirror);
|
||||
|
||||
oggplay_free (buffer);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
oggplay_buffer_shutdown(OggPlay *me, volatile OggPlayBuffer *vbuffer) {
|
||||
|
||||
int i;
|
||||
int j;
|
||||
|
||||
OggPlayBuffer *buffer = (OggPlayBuffer *)vbuffer;
|
||||
|
||||
if (buffer == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (buffer->buffer_mirror != NULL) {
|
||||
for (i = 0; i < buffer->buffer_size; i++) {
|
||||
|
||||
if (buffer->buffer_mirror[i] != NULL) {
|
||||
OggPlayCallbackInfo *ti = (OggPlayCallbackInfo *)buffer->buffer_mirror[i];
|
||||
for (j = 0; j < me->num_tracks; j++) {
|
||||
if ( (ti+j) != NULL) {
|
||||
oggplay_free((ti + j)->records);
|
||||
}
|
||||
}
|
||||
oggplay_free(ti);
|
||||
}
|
||||
|
||||
}
|
||||
oggplay_free(buffer->buffer_mirror);
|
||||
}
|
||||
|
||||
if (buffer->buffer_list != NULL)
|
||||
oggplay_free(buffer->buffer_list);
|
||||
|
||||
SEM_CLOSE(buffer->frame_sem);
|
||||
oggplay_free(buffer);
|
||||
buffer = NULL;
|
||||
}
|
||||
|
||||
int
|
||||
oggplay_buffer_is_full(volatile OggPlayBuffer *buffer) {
|
||||
|
||||
return
|
||||
(
|
||||
(buffer == NULL) || (
|
||||
buffer->buffer_list[WRAP_INC(buffer->last_filled, buffer->buffer_size)]
|
||||
!=
|
||||
NULL
|
||||
)
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
int
|
||||
oggplay_buffer_callback(OggPlay *me, int tracks,
|
||||
OggPlayCallbackInfo **track_info, void *user) {
|
||||
|
||||
int i;
|
||||
int j;
|
||||
int k;
|
||||
OggPlayDataHeader ** headers;
|
||||
OggPlayBuffer * buffer;
|
||||
OggPlayCallbackInfo * ptr = track_info[0];
|
||||
int required;
|
||||
|
||||
if (me == NULL)
|
||||
return -1;
|
||||
|
||||
buffer = (OggPlayBuffer *)me->buffer;
|
||||
|
||||
if (buffer == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
SEM_WAIT(buffer->frame_sem);
|
||||
|
||||
if (me->shutdown) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* lock the item going into the buffer so that it doesn't get cleaned up
|
||||
*/
|
||||
for (i = 0; i < tracks; i++) {
|
||||
headers = oggplay_callback_info_get_headers(track_info[i]);
|
||||
required = oggplay_callback_info_get_required(track_info[i]);
|
||||
for (j = 0; j < required; j++) {
|
||||
oggplay_callback_info_lock_item(headers[j]);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* check for and clean up empties
|
||||
*/
|
||||
for (k = 0; k < buffer->buffer_size; k++) {
|
||||
if
|
||||
(
|
||||
(buffer->buffer_list[k] == NULL)
|
||||
&&
|
||||
(buffer->buffer_mirror[k] != NULL)
|
||||
)
|
||||
{
|
||||
OggPlayCallbackInfo *ti = (OggPlayCallbackInfo *)buffer->buffer_mirror[k];
|
||||
for (i = 0; i < tracks; i++) {
|
||||
headers = oggplay_callback_info_get_headers(ti + i);
|
||||
required = oggplay_callback_info_get_required(ti + i);
|
||||
for (j = 0; j < required; j++) {
|
||||
oggplay_callback_info_unlock_item(headers[j]);
|
||||
}
|
||||
/* free these here, because we couldn't free them in
|
||||
* oggplay_callback_info_destroy for buffer mode
|
||||
*/
|
||||
if ((ti + i) != NULL) {
|
||||
oggplay_free((ti + i)->records);
|
||||
}
|
||||
}
|
||||
oggplay_free(ti);
|
||||
buffer->buffer_mirror[k] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* replace the decode_data buffer for the next callback
|
||||
*/
|
||||
me->callback_info =
|
||||
(OggPlayCallbackInfo *)oggplay_calloc(me->num_tracks, sizeof (OggPlayCallbackInfo));
|
||||
if (me->callback_info == NULL)
|
||||
return -1;
|
||||
|
||||
/*
|
||||
* fill both mirror and list, mirror first to avoid getting inconsistencies
|
||||
*/
|
||||
|
||||
buffer->last_filled = WRAP_INC(buffer->last_filled, buffer->buffer_size);
|
||||
|
||||
/*
|
||||
* set the buffer pointer in the first record
|
||||
*/
|
||||
ptr->buffer = buffer;
|
||||
|
||||
buffer->buffer_mirror[buffer->last_filled] = ptr;
|
||||
buffer->buffer_list[buffer->last_filled] = ptr;
|
||||
|
||||
|
||||
if (oggplay_buffer_is_full(buffer)) {
|
||||
/*
|
||||
* user interrupt when we fill the buffer rather than when we have a
|
||||
* decoded frame and the buffer is already full
|
||||
*/
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
OggPlayCallbackInfo **
|
||||
oggplay_buffer_retrieve_next(OggPlay *me) {
|
||||
|
||||
OggPlayBuffer * buffer = NULL;
|
||||
int next_loc;
|
||||
OggPlayCallbackInfo * next_item;
|
||||
OggPlayCallbackInfo ** return_val;
|
||||
int i;
|
||||
|
||||
if (me == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
buffer = (OggPlayBuffer *)me->buffer;
|
||||
|
||||
if (buffer == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
next_loc = WRAP_INC(buffer->last_emptied, buffer->buffer_size);
|
||||
|
||||
if (buffer->buffer_list[next_loc] == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
next_item = (OggPlayCallbackInfo*)buffer->buffer_list[next_loc];
|
||||
buffer->last_emptied = next_loc;
|
||||
|
||||
return_val = oggplay_calloc(me->num_tracks, sizeof (OggPlayCallbackInfo *));
|
||||
if (return_val == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (i = 0; i < me->num_tracks; i++) {
|
||||
return_val[i] = next_item + i;
|
||||
}
|
||||
|
||||
return return_val;
|
||||
|
||||
}
|
||||
|
||||
OggPlayErrorCode
|
||||
oggplay_buffer_release(OggPlay *me, OggPlayCallbackInfo **track_info) {
|
||||
|
||||
OggPlayBuffer *buffer = NULL;
|
||||
|
||||
if (me == NULL) {
|
||||
return E_OGGPLAY_BAD_OGGPLAY;
|
||||
}
|
||||
|
||||
if (track_info == NULL) {
|
||||
return E_OGGPLAY_OK;
|
||||
}
|
||||
|
||||
buffer = (OggPlayBuffer *)track_info[0]->buffer;
|
||||
|
||||
if (buffer == NULL) {
|
||||
return E_OGGPLAY_CALLBACK_MODE;
|
||||
}
|
||||
|
||||
if (buffer->buffer_list[buffer->last_emptied] == NULL) {
|
||||
return E_OGGPLAY_UNINITIALISED;
|
||||
}
|
||||
|
||||
if (track_info != NULL) {
|
||||
oggplay_free(track_info);
|
||||
}
|
||||
|
||||
buffer->buffer_list[buffer->last_emptied] = NULL;
|
||||
|
||||
SEM_SIGNAL(buffer->frame_sem);
|
||||
|
||||
return E_OGGPLAY_OK;
|
||||
|
||||
}
|
||||
|
||||
OggPlayErrorCode
|
||||
oggplay_use_buffer(OggPlay *me, int size) {
|
||||
|
||||
if (me == NULL) {
|
||||
return E_OGGPLAY_BAD_OGGPLAY;
|
||||
}
|
||||
|
||||
if (me->callback != NULL) {
|
||||
return E_OGGPLAY_CALLBACK_MODE;
|
||||
}
|
||||
|
||||
if (me->buffer != NULL) {
|
||||
/*
|
||||
* we should check sizes, and maybe clear and reallocate the buffer?
|
||||
*/
|
||||
return E_OGGPLAY_OK;
|
||||
}
|
||||
|
||||
if( (me->buffer = oggplay_buffer_new_buffer(size)) == NULL)
|
||||
return E_OGGPLAY_OUT_OF_MEMORY;
|
||||
|
||||
/*
|
||||
* if oggplay is already initialised, then prepare the buffer now
|
||||
*/
|
||||
if (me->all_tracks_initialised) {
|
||||
oggplay_buffer_prepare(me);
|
||||
}
|
||||
|
||||
return E_OGGPLAY_OK;
|
||||
}
|
||||
|
||||
void
|
||||
oggplay_buffer_prepare(OggPlay *me) {
|
||||
|
||||
int i;
|
||||
|
||||
if (me == NULL)
|
||||
return;
|
||||
|
||||
oggplay_set_data_callback_force(me, &oggplay_buffer_callback, NULL);
|
||||
|
||||
for (i = 0; i < me->num_tracks; i++) {
|
||||
if (oggplay_get_track_type(me, i) == OGGZ_CONTENT_THEORA) {
|
||||
oggplay_set_callback_num_frames(me, i, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,61 +0,0 @@
|
|||
/*
|
||||
Copyright (C) 2003 Commonwealth Scientific and Industrial Research
|
||||
Organisation (CSIRO) Australia
|
||||
|
||||
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.
|
||||
|
||||
- Neither the name of CSIRO Australia nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
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 ORGANISATION 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* oggplay_buffer.h
|
||||
*
|
||||
* Shane Stephens <shane.stephens@annodex.net>
|
||||
*/
|
||||
|
||||
#ifndef __OGGPLAY_BUFFER_H__
|
||||
#define __OGGPLAY_BUFFER_H__
|
||||
|
||||
/**
|
||||
* Creates a new buffer with the given size.
|
||||
*
|
||||
* @param size The number of frames the buffer can store.
|
||||
* @return A new OggPlayBuffer.
|
||||
* @retval NULL in case of error.
|
||||
*/
|
||||
OggPlayBuffer *
|
||||
oggplay_buffer_new_buffer(int size);
|
||||
|
||||
int
|
||||
oggplay_buffer_is_full(volatile OggPlayBuffer *buffer);
|
||||
|
||||
void
|
||||
oggplay_buffer_shutdown(OggPlay *me, volatile OggPlayBuffer *buffer);
|
||||
|
||||
void
|
||||
oggplay_buffer_prepare(OggPlay *me);
|
||||
|
||||
#endif
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -1,70 +0,0 @@
|
|||
/*
|
||||
Copyright (C) 2003 Commonwealth Scientific and Industrial Research
|
||||
Organisation (CSIRO) Australia
|
||||
|
||||
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.
|
||||
|
||||
- Neither the name of CSIRO Australia nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
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 ORGANISATION 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* oggplay_callback.h
|
||||
*
|
||||
* Shane Stephens <shane.stephens@annodex.net>
|
||||
*/
|
||||
#ifndef __OGGPLAY_CALLBACK_H__
|
||||
#define __OGGPLAY_CALLBACK_H__
|
||||
|
||||
int
|
||||
oggplay_callback_predetected (OGGZ *oggz, ogg_packet *op, long serialno,
|
||||
void *user_data);
|
||||
|
||||
void
|
||||
oggplay_process_leftover_packet(OggPlay *me);
|
||||
|
||||
/**
|
||||
* Create and initialise an OggPlayDecode handle.
|
||||
*
|
||||
*
|
||||
*
|
||||
* @param me OggPlay
|
||||
* @param content_type
|
||||
* @param serialno
|
||||
* @return A new OggPlayDecode handle
|
||||
* @retval NULL in case of error.
|
||||
*/
|
||||
OggPlayDecode *
|
||||
oggplay_initialise_decoder(OggPlay *me, int content_type, long serialno);
|
||||
|
||||
int
|
||||
oggplay_callback_info_prepare(OggPlay *me, OggPlayCallbackInfo ***info);
|
||||
|
||||
void
|
||||
oggplay_callback_info_destroy(OggPlay *me, OggPlayCallbackInfo **info);
|
||||
|
||||
void
|
||||
oggplay_callback_shutdown(OggPlayDecode *decoder);
|
||||
#endif
|
|
@ -1,506 +0,0 @@
|
|||
/*
|
||||
Copyright (C) 2003 Commonwealth Scientific and Industrial Research
|
||||
Organisation (CSIRO) Australia
|
||||
|
||||
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.
|
||||
|
||||
- Neither the name of CSIRO Australia nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
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 ORGANISATION 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* oggplay_callback_info.c
|
||||
*
|
||||
* Shane Stephens <shane.stephens@annodex.net>
|
||||
*/
|
||||
#include "oggplay_private.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
extern void _print_list(char *name, OggPlayDataHeader *p);
|
||||
|
||||
static void
|
||||
clear_callback_info (OggPlay *me, OggPlayCallbackInfo ***info) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < me->num_tracks; ++i) {
|
||||
if (((*info)[i] != NULL) && ((*info)[i]->records != NULL)) {
|
||||
oggplay_free ((*info)[i]->records);
|
||||
}
|
||||
}
|
||||
oggplay_free (*info);
|
||||
*info = NULL;
|
||||
}
|
||||
|
||||
int
|
||||
oggplay_callback_info_prepare(OggPlay *me, OggPlayCallbackInfo ***info) {
|
||||
|
||||
int i;
|
||||
int tcount = 0;
|
||||
|
||||
int added_required_record = me->num_tracks;
|
||||
ogg_int64_t diff;
|
||||
ogg_int64_t latest_first_record = 0x0LL;
|
||||
//ogg_int64_t lpt = 0;
|
||||
|
||||
/*
|
||||
* allocate the structure for return to the user
|
||||
*/
|
||||
(*info) = oggplay_calloc (me->num_tracks, sizeof (OggPlayCallbackInfo *));
|
||||
if ((*info) == NULL)
|
||||
return E_OGGPLAY_OUT_OF_MEMORY;
|
||||
|
||||
/*
|
||||
* fill in each active track. Leave gaps for inactive tracks.
|
||||
*/
|
||||
for (i = 0; i < me->num_tracks; i++) {
|
||||
OggPlayDecode * track = me->decode_data[i];
|
||||
OggPlayCallbackInfo * track_info = me->callback_info + i;
|
||||
size_t count = 0;
|
||||
OggPlayDataHeader * p;
|
||||
OggPlayDataHeader * q = NULL;
|
||||
|
||||
(*info)[i] = track_info;
|
||||
|
||||
#ifdef HAVE_TIGER
|
||||
/* not so nice to have this here, but the tiger_renderer needs updating regularly
|
||||
* as some items may be animated, so would yield data without the stream actually
|
||||
* receiving any packets.
|
||||
* In addition, Kate streams can now be overlayed on top of a video, so this needs
|
||||
* calling to render the overlay.
|
||||
* FIXME: is this the best place to put this ? Might do too much work if the info
|
||||
* is going to be destroyed ?
|
||||
*/
|
||||
if (track->content_type == OGGZ_CONTENT_KATE) {
|
||||
OggPlayKateDecode *decode = (OggPlayKateDecode *)track;
|
||||
OggPlayCallbackInfo * video_info = NULL;
|
||||
if (decode->overlay_dest >= 0)
|
||||
video_info = me->callback_info + decode->overlay_dest;
|
||||
oggplay_data_update_tiger(decode, track->active, me->target, video_info);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* this track is inactive and has no data - create an empty record
|
||||
* for it
|
||||
*/
|
||||
if (track->active == 0 && track->data_list == NULL) {
|
||||
track_info->data_type = OGGPLAY_INACTIVE;
|
||||
track_info->available_records = track_info->required_records = 0;
|
||||
track_info->records = NULL;
|
||||
track_info->stream_info = OGGPLAY_STREAM_UNINITIALISED;
|
||||
added_required_record --;
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* find the first not presented packet of data, count the total number that
|
||||
* have not been presented
|
||||
*/
|
||||
for (p = track->data_list; p != NULL; p = p->next) {
|
||||
if (!p->has_been_presented) {
|
||||
if (q == NULL) {
|
||||
q = p;
|
||||
}
|
||||
|
||||
/* check for overflow */
|
||||
if
|
||||
(
|
||||
oggplay_check_add_overflow (count, 1, &count)
|
||||
==
|
||||
E_OGGPLAY_TYPE_OVERFLOW
|
||||
)
|
||||
{
|
||||
clear_callback_info (me, info);
|
||||
return E_OGGPLAY_TYPE_OVERFLOW;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* tcount is set if any of the tracks have unpresented data
|
||||
*/
|
||||
if (count > 0) {
|
||||
tcount = 1;
|
||||
|
||||
/*
|
||||
* set this track's StreamState. If the track isn't active and there's
|
||||
* only one timestamp's worth of data in the data list, then this is
|
||||
* the last data!
|
||||
*/
|
||||
if
|
||||
(
|
||||
track->active == 0
|
||||
&&
|
||||
(
|
||||
track->end_of_data_list->presentation_time
|
||||
<=
|
||||
me->target + track->offset
|
||||
)
|
||||
)
|
||||
{
|
||||
track_info->stream_info = OGGPLAY_STREAM_LAST_DATA;
|
||||
} else {
|
||||
track_info->stream_info = track->stream_info;
|
||||
}
|
||||
|
||||
} else {
|
||||
track_info->stream_info = OGGPLAY_STREAM_UNINITIALISED;
|
||||
}
|
||||
|
||||
if ((count+1) < count) {
|
||||
clear_callback_info (me, info);
|
||||
return E_OGGPLAY_TYPE_OVERFLOW;
|
||||
}
|
||||
/* null-terminate the record list for the python interface */
|
||||
track_info->records =
|
||||
oggplay_calloc ((count+1), sizeof (OggPlayDataHeader *));
|
||||
if (track_info->records == NULL) {
|
||||
clear_callback_info (me, info);
|
||||
return E_OGGPLAY_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
track_info->records[count] = NULL;
|
||||
|
||||
track_info->available_records = count;
|
||||
track_info->required_records = 0;
|
||||
|
||||
track_info->data_type = track->decoded_type;
|
||||
|
||||
count = 0;
|
||||
for (p = q; p != NULL; p = p->next) {
|
||||
if (!p->has_been_presented) {
|
||||
track_info->records[count++] = p;
|
||||
if (p->presentation_time <= me->target + track->offset) {
|
||||
track_info->required_records++;
|
||||
p->has_been_presented = 1;
|
||||
//lpt = p->presentation_time;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (track_info->required_records > 0) {
|
||||
/*
|
||||
* if the StreamState is FIRST_DATA then update it to INITIALISED,
|
||||
* as we've marked the first data instance
|
||||
*/
|
||||
if
|
||||
(
|
||||
track->stream_info == OGGPLAY_STREAM_FIRST_DATA
|
||||
||
|
||||
track->stream_info == OGGPLAY_STREAM_JUST_SEEKED
|
||||
)
|
||||
{
|
||||
track->stream_info = OGGPLAY_STREAM_INITIALISED;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
printf("%d: %d/%d\t", i,
|
||||
track_info->required_records, count);
|
||||
|
||||
if (q != NULL) {
|
||||
printf("fst: %lld lst: %lld sz: %lld pt: %lld\n",
|
||||
q->presentation_time >> 32, lpt >> 32,
|
||||
(lpt - q->presentation_time) >> 32,
|
||||
me->presentation_time >> 32);
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
* this statement detects if this track needs records but has none.
|
||||
* We need to be careful - there are 2 cases where this could happen. The
|
||||
* first is where the presentation time is less than it should be, and
|
||||
* there is no data available between now and the target. In this case
|
||||
* we want to set added_required_record to 0 and trigger the presentation
|
||||
* time update code below.
|
||||
* <-------data----------...
|
||||
* ^ ^ ^
|
||||
* pt target current_loc
|
||||
*
|
||||
* The second case occurs when the packet from the last timestamp contained
|
||||
* so much data that there *is* none in this timestamp. In this case we
|
||||
* don't want to set added_required_record to 0.
|
||||
*
|
||||
* <----------data---------------|--------...
|
||||
* <-timeslice1-><-timeslice2-><-timeslice3->
|
||||
* ^ ^ ^
|
||||
* pt target current_loc
|
||||
*
|
||||
* How do we discriminate between these two cases? We assume the pt update
|
||||
* needs to be explicitly required (e.g. by seeking or start of movie), and
|
||||
* create a new member in the player struct called pt_update_valid
|
||||
*/
|
||||
// TODO: I don't think that pt_update_valid is necessary any more, as this will only
|
||||
// trigger now if there's no data in *ANY* of the tracks. Hence the audio timeslice case
|
||||
// doesn't apply.
|
||||
if
|
||||
(
|
||||
track->decoded_type == OGGPLAY_CMML
|
||||
||
|
||||
track->decoded_type == OGGPLAY_KATE // TODO: check this is the right thing to do
|
||||
||
|
||||
(
|
||||
track_info->required_records == 0
|
||||
&&
|
||||
track->active == 1
|
||||
&&
|
||||
me->pt_update_valid
|
||||
)
|
||||
) {
|
||||
added_required_record --;
|
||||
}
|
||||
|
||||
} /* end of for loop, that fills each track */
|
||||
|
||||
me->pt_update_valid = 0;
|
||||
|
||||
//printf("\n");
|
||||
|
||||
/*
|
||||
* there are no required records! This means that we need to advance the
|
||||
* target to the period before the first actual record - the bitstream has
|
||||
* lied about the presence of data here.
|
||||
*
|
||||
* This happens for example with some Annodex streams (a bug in libannodex
|
||||
* causes incorrect timestamping)
|
||||
*
|
||||
* What we actually need is the first timestamp *just before* a timestamp
|
||||
* with valid data on all active tracks that are not CMML tracks.
|
||||
*/
|
||||
latest_first_record = 0x0LL;
|
||||
if (tcount > 0 && added_required_record == 0) {
|
||||
for (i = 0; i < me->num_tracks; i++) {
|
||||
OggPlayCallbackInfo * track_info = me->callback_info + i;
|
||||
if (track_info->data_type == OGGPLAY_CMML || track_info->data_type == OGGPLAY_KATE) {
|
||||
continue;
|
||||
}
|
||||
if (track_info->available_records > 0) {
|
||||
if (track_info->records[0]->presentation_time > latest_first_record) {
|
||||
latest_first_record = track_info->records[0]->presentation_time;
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
* update target to the time-period before the first record. This is
|
||||
* independent of the offset (after all, we want to maintain synchronisation
|
||||
* between the streams).
|
||||
*/
|
||||
diff = latest_first_record - me->target;
|
||||
diff = (diff / me->callback_period) * me->callback_period;
|
||||
me->target += diff + me->callback_period;
|
||||
|
||||
|
||||
/*
|
||||
* update the presentation_time to the latest_first_record. This ensures
|
||||
* that we don't play material for timestamps that only exist in one track.
|
||||
*/
|
||||
me->presentation_time = me->target - me->callback_period;
|
||||
|
||||
/*
|
||||
* indicate that we need to go through another round of fragment collection
|
||||
* and callback creation
|
||||
*/
|
||||
for (i = 0; i < me->num_tracks; i++) {
|
||||
if ((*info)[i]->records != NULL)
|
||||
oggplay_free((*info)[i]->records);
|
||||
}
|
||||
oggplay_free(*info);
|
||||
(*info) = NULL;
|
||||
|
||||
}
|
||||
|
||||
if (tcount == 0) {
|
||||
for (i = 0; i < me->num_tracks; i++) {
|
||||
if ((*info)[i]->records != NULL)
|
||||
oggplay_free((*info)[i]->records);
|
||||
}
|
||||
oggplay_free(*info);
|
||||
(*info) = NULL;
|
||||
}
|
||||
|
||||
return me->num_tracks;
|
||||
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
oggplay_callback_info_destroy(OggPlay *me, OggPlayCallbackInfo **info) {
|
||||
|
||||
int i;
|
||||
OggPlayCallbackInfo * p;
|
||||
|
||||
for (i = 0; i < me->num_tracks; i++) {
|
||||
p = info[i];
|
||||
if (me->buffer == NULL && p->records != NULL)
|
||||
oggplay_free(p->records);
|
||||
}
|
||||
|
||||
oggplay_free(info);
|
||||
|
||||
}
|
||||
|
||||
OggPlayDataType
|
||||
oggplay_callback_info_get_type(OggPlayCallbackInfo *info) {
|
||||
|
||||
if (info == NULL) {
|
||||
return (OggPlayDataType)E_OGGPLAY_BAD_CALLBACK_INFO;
|
||||
}
|
||||
|
||||
return info->data_type;
|
||||
|
||||
}
|
||||
|
||||
int
|
||||
oggplay_callback_info_get_available(OggPlayCallbackInfo *info) {
|
||||
|
||||
if (info == NULL) {
|
||||
return E_OGGPLAY_BAD_CALLBACK_INFO;
|
||||
}
|
||||
|
||||
return info->available_records;
|
||||
|
||||
}
|
||||
|
||||
int
|
||||
oggplay_callback_info_get_required(OggPlayCallbackInfo *info) {
|
||||
|
||||
if (info == NULL) {
|
||||
return E_OGGPLAY_BAD_CALLBACK_INFO;
|
||||
}
|
||||
|
||||
return info->required_records;
|
||||
|
||||
}
|
||||
|
||||
OggPlayStreamInfo
|
||||
oggplay_callback_info_get_stream_info(OggPlayCallbackInfo *info) {
|
||||
|
||||
if (info == NULL) {
|
||||
return E_OGGPLAY_BAD_CALLBACK_INFO;
|
||||
}
|
||||
|
||||
return info->stream_info;
|
||||
}
|
||||
|
||||
OggPlayDataHeader **
|
||||
oggplay_callback_info_get_headers(OggPlayCallbackInfo *info) {
|
||||
|
||||
if (info == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return info->records;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns number of samples in the record
|
||||
* Note: the resulting data include samples for all audio channels */
|
||||
ogg_int64_t
|
||||
oggplay_callback_info_get_record_size(OggPlayDataHeader *header) {
|
||||
|
||||
if (header == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return header->samples_in_record;
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
oggplay_callback_info_lock_item(OggPlayDataHeader *header) {
|
||||
|
||||
if (header == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
header->lock += 1;
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
oggplay_callback_info_unlock_item(OggPlayDataHeader *header) {
|
||||
|
||||
if (header == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
header->lock -= 1;
|
||||
}
|
||||
|
||||
long
|
||||
oggplay_callback_info_get_presentation_time(OggPlayDataHeader *header) {
|
||||
|
||||
if (header == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return OGGPLAY_TIME_FP_TO_INT(header->presentation_time);
|
||||
}
|
||||
|
||||
OggPlayVideoData *
|
||||
oggplay_callback_info_get_video_data(OggPlayDataHeader *header) {
|
||||
|
||||
if (header == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return &((OggPlayVideoRecord *)header)->data;
|
||||
|
||||
}
|
||||
|
||||
OggPlayOverlayData *
|
||||
oggplay_callback_info_get_overlay_data(OggPlayDataHeader *header) {
|
||||
|
||||
if (header == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return &((OggPlayOverlayRecord *)header)->data;
|
||||
|
||||
}
|
||||
|
||||
OggPlayAudioData *
|
||||
oggplay_callback_info_get_audio_data(OggPlayDataHeader *header) {
|
||||
|
||||
if (header == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return (OggPlayAudioData *)((OggPlayAudioRecord *)header)->data;
|
||||
}
|
||||
|
||||
OggPlayTextData *
|
||||
oggplay_callback_info_get_text_data(OggPlayDataHeader *header) {
|
||||
|
||||
if (header == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return ((OggPlayTextRecord *)header)->data;
|
||||
|
||||
}
|
||||
|
|
@ -1,736 +0,0 @@
|
|||
/*
|
||||
Copyright (C) 2003 Commonwealth Scientific and Industrial Research
|
||||
Organisation (CSIRO) Australia
|
||||
|
||||
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.
|
||||
|
||||
- Neither the name of CSIRO Australia nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
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 ORGANISATION 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* oggplay_data.c
|
||||
*
|
||||
* Shane Stephens <shane.stephens@annodex.net>
|
||||
*/
|
||||
|
||||
#include "oggplay_private.h"
|
||||
#include "oggplay/oggplay_callback_info.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#if HAVE_INTTYPES_H
|
||||
#include <inttypes.h>
|
||||
#else
|
||||
#if LONG_MAX==2147483647L
|
||||
#define PRId64 "lld"
|
||||
#else
|
||||
#define PRId64 "ld"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
* the normal lifecycle for a frame is:
|
||||
*
|
||||
* (1) frame gets decoded and added to list with a locking value of 1
|
||||
* (2) frame gets delivered to user
|
||||
* (3) frame becomes out-of-date (its presentation time expires) and its
|
||||
* lock is decremented
|
||||
* (4) frame is removed from list and freed
|
||||
*
|
||||
* This can be modified by:
|
||||
* (a) early consumption by user (user calls oggplay_mark_record_consumed)
|
||||
* (b) frame locking by user (user calls oggplay_mark_record_locked) and
|
||||
* subsequent unlocking (user calls oggplay_mark_record_consumed)
|
||||
*/
|
||||
|
||||
void
|
||||
oggplay_data_initialise_list (OggPlayDecode *decode) {
|
||||
|
||||
if (decode == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
decode->data_list = decode->end_of_data_list = NULL;
|
||||
decode->untimed_data_list = NULL;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* helper function to append data packets to end of data_list
|
||||
*/
|
||||
void
|
||||
oggplay_data_add_to_list_end(OggPlayDecode *decode, OggPlayDataHeader *data) {
|
||||
|
||||
if (decode == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
data->next = NULL;
|
||||
|
||||
if (decode->data_list == NULL) {
|
||||
decode->data_list = data;
|
||||
decode->end_of_data_list = data;
|
||||
} else {
|
||||
decode->end_of_data_list->next = data;
|
||||
decode->end_of_data_list = data;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* helper function to append data packets to front of data_list
|
||||
*/
|
||||
void
|
||||
oggplay_data_add_to_list_front(OggPlayDecode *decode, OggPlayDataHeader *data) {
|
||||
if (decode == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (decode->data_list == NULL) {
|
||||
decode->data_list = decode->end_of_data_list = data;
|
||||
data->next = NULL;
|
||||
} else {
|
||||
data->next = decode->data_list;
|
||||
decode->data_list = data;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
_print_list(char *name, OggPlayDataHeader *p) {
|
||||
printf("%s: ", name);
|
||||
for (; p != NULL; p = p->next) {
|
||||
printf("%"PRId64"[%d]", OGGPLAY_TIME_FP_TO_INT (p->presentation_time), p->lock);
|
||||
if (p->next != NULL) printf("->");
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
oggplay_data_add_to_list (OggPlayDecode *decode, OggPlayDataHeader *data) {
|
||||
|
||||
/*
|
||||
* if this is a packet with an unknown display time, prepend it to
|
||||
* the untimed_data_list for later timestamping.
|
||||
*/
|
||||
|
||||
ogg_int64_t samples_in_next_in_list;
|
||||
|
||||
if ((decode == NULL) || (data == NULL)) {
|
||||
return;
|
||||
}
|
||||
|
||||
//_print_list("before", decode->data_list);
|
||||
//_print_list("untimed before", decode->untimed_data_list);
|
||||
|
||||
if (data->presentation_time == -1) {
|
||||
data->next = decode->untimed_data_list;
|
||||
decode->untimed_data_list = data;
|
||||
} else {
|
||||
/*
|
||||
* process the untimestamped data into the timestamped data list.
|
||||
*
|
||||
* First store any old data.
|
||||
*/
|
||||
ogg_int64_t presentation_time = data->presentation_time;
|
||||
samples_in_next_in_list = data->samples_in_record;
|
||||
|
||||
|
||||
while (decode->untimed_data_list != NULL) {
|
||||
OggPlayDataHeader *untimed = decode->untimed_data_list;
|
||||
|
||||
presentation_time -=
|
||||
samples_in_next_in_list * decode->granuleperiod;
|
||||
untimed->presentation_time = presentation_time;
|
||||
decode->untimed_data_list = untimed->next;
|
||||
samples_in_next_in_list = untimed->samples_in_record;
|
||||
|
||||
if (untimed->presentation_time >= decode->player->presentation_time) {
|
||||
oggplay_data_add_to_list_front(decode, untimed);
|
||||
} else {
|
||||
oggplay_free(untimed);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
oggplay_data_add_to_list_end(decode, data);
|
||||
|
||||
/*
|
||||
* if the StreamInfo is still at uninitialised, then this is the first
|
||||
* meaningful data packet! StreamInfo will be updated to
|
||||
* OGGPLAY_STREAM_INITIALISED in oggplay_callback_info.c as part of the
|
||||
* callback process.
|
||||
*/
|
||||
if (decode->stream_info == OGGPLAY_STREAM_UNINITIALISED) {
|
||||
decode->stream_info = OGGPLAY_STREAM_FIRST_DATA;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//_print_list("after", decode->data_list);
|
||||
//_print_list("untimed after", decode->untimed_data_list);
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
oggplay_data_free_list(OggPlayDataHeader *list) {
|
||||
OggPlayDataHeader *p;
|
||||
|
||||
while (list != NULL) {
|
||||
p = list;
|
||||
list = list->next;
|
||||
oggplay_free(p);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
oggplay_data_shutdown_list (OggPlayDecode *decode) {
|
||||
|
||||
if (decode == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
oggplay_data_free_list(decode->data_list);
|
||||
oggplay_data_free_list(decode->untimed_data_list);
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* this function removes any displayed, unlocked frames from the list.
|
||||
*
|
||||
* this function also removes any undisplayed frames that are before the
|
||||
* global presentation time.
|
||||
*/
|
||||
void
|
||||
oggplay_data_clean_list (OggPlayDecode *decode) {
|
||||
|
||||
ogg_int64_t target;
|
||||
OggPlayDataHeader * header = NULL;
|
||||
OggPlayDataHeader * p = NULL;
|
||||
|
||||
if (decode == NULL) {
|
||||
return;
|
||||
}
|
||||
header = decode->data_list;
|
||||
target = decode->player->target;
|
||||
|
||||
while (header != NULL) {
|
||||
if
|
||||
(
|
||||
header->lock == 0
|
||||
&&
|
||||
(
|
||||
(
|
||||
(header->presentation_time < (target + decode->offset))
|
||||
&&
|
||||
header->has_been_presented
|
||||
)
|
||||
||
|
||||
(
|
||||
(header->presentation_time < decode->player->presentation_time)
|
||||
)
|
||||
)
|
||||
|
||||
)
|
||||
{
|
||||
if (p == NULL) {
|
||||
decode->data_list = decode->data_list->next;
|
||||
if (decode->data_list == NULL)
|
||||
decode->end_of_data_list = NULL;
|
||||
oggplay_free (header);
|
||||
header = decode->data_list;
|
||||
} else {
|
||||
if (header->next == NULL)
|
||||
decode->end_of_data_list = p;
|
||||
p->next = header->next;
|
||||
oggplay_free (header);
|
||||
header = p->next;
|
||||
}
|
||||
} else {
|
||||
p = header;
|
||||
header = header->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
oggplay_data_initialise_header (const OggPlayDecode *decode,
|
||||
OggPlayDataHeader *header) {
|
||||
|
||||
if ((decode == NULL) || (header == NULL)) {
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* the frame is not cleaned until its presentation time has passed. We'll
|
||||
* check presentation times in oggplay_data_clean_list.
|
||||
*/
|
||||
header->lock = 0;
|
||||
header->next = NULL;
|
||||
header->presentation_time = decode->current_loc;
|
||||
header->has_been_presented = 0;
|
||||
}
|
||||
|
||||
OggPlayErrorCode
|
||||
oggplay_data_handle_audio_data (OggPlayDecode *decode, void *data,
|
||||
long samples, size_t samplesize) {
|
||||
|
||||
int num_channels, ret;
|
||||
size_t record_size = sizeof(OggPlayAudioRecord);
|
||||
long samples_size;
|
||||
OggPlayAudioRecord * record = NULL;
|
||||
|
||||
num_channels = ((OggPlayAudioDecode *)decode)->sound_info.channels;
|
||||
|
||||
/* check for possible integer overflows....*/
|
||||
if ((samples < 0) || (num_channels < 0)) {
|
||||
return E_OGGPLAY_TYPE_OVERFLOW;
|
||||
}
|
||||
|
||||
ret = oggplay_mul_signed_overflow (samples, num_channels, &samples_size);
|
||||
if (ret == E_OGGPLAY_TYPE_OVERFLOW) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = oggplay_mul_signed_overflow (samples_size, samplesize, &samples_size);
|
||||
if (ret == E_OGGPLAY_TYPE_OVERFLOW) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = oggplay_check_add_overflow (record_size, samples_size, &record_size);
|
||||
if (ret == E_OGGPLAY_TYPE_OVERFLOW) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* try to allocate the memory for the record */
|
||||
record = (OggPlayAudioRecord*)oggplay_calloc(record_size, 1);
|
||||
if (record == NULL) {
|
||||
return E_OGGPLAY_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
/* initialise the header of OggPlayAudioRecord struct */
|
||||
oggplay_data_initialise_header(decode, &(record->header));
|
||||
|
||||
record->header.samples_in_record = samples;
|
||||
|
||||
record->data = (void *)(record + 1);
|
||||
|
||||
/* copy the received data - the header has been initialised! */
|
||||
memcpy (record->data, data, samples_size);
|
||||
/*
|
||||
printf("[%f%f%f]\n", ((float *)record->data)[0], ((float *)record->data)[1],
|
||||
((float *)record->data)[2]);
|
||||
*/
|
||||
oggplay_data_add_to_list(decode, &(record->header));
|
||||
|
||||
return E_OGGPLAY_CONTINUE;
|
||||
}
|
||||
|
||||
OggPlayErrorCode
|
||||
oggplay_data_handle_cmml_data(OggPlayDecode *decode,
|
||||
unsigned char *data,
|
||||
long size) {
|
||||
|
||||
OggPlayTextRecord * record = NULL;
|
||||
size_t record_size = sizeof(OggPlayTextRecord);
|
||||
|
||||
/* Include extra byte for null terminating record data buffer */
|
||||
record_size += 1;
|
||||
|
||||
if
|
||||
(
|
||||
oggplay_check_add_overflow (record_size, size, &record_size)
|
||||
==
|
||||
E_OGGPLAY_TYPE_OVERFLOW
|
||||
)
|
||||
{
|
||||
return E_OGGPLAY_TYPE_OVERFLOW;
|
||||
}
|
||||
|
||||
/* allocate the memory for the record */
|
||||
record = (OggPlayTextRecord*)oggplay_calloc (record_size, 1);
|
||||
if (record == NULL) {
|
||||
return E_OGGPLAY_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
/* initialise the record's header */
|
||||
oggplay_data_initialise_header(decode, &(record->header));
|
||||
|
||||
record->header.samples_in_record = 1;
|
||||
record->data = (char *)(record + 1);
|
||||
|
||||
/* copy the data */
|
||||
memcpy(record->data, data, size);
|
||||
record->data[size] = '\0';
|
||||
|
||||
oggplay_data_add_to_list(decode, &(record->header));
|
||||
|
||||
return E_OGGPLAY_CONTINUE;
|
||||
}
|
||||
|
||||
static int
|
||||
get_uv_offset(OggPlayTheoraDecode *decode, yuv_buffer *buffer)
|
||||
{
|
||||
int xo=0, yo = 0;
|
||||
if (decode->y_width != 0 &&
|
||||
decode->uv_width != 0 &&
|
||||
decode->y_width/decode->uv_width != 0) {
|
||||
xo = (decode->video_info.offset_x/(decode->y_width/decode->uv_width));
|
||||
}
|
||||
if (decode->y_height != 0 &&
|
||||
decode->uv_height != 0 &&
|
||||
decode->y_height/decode->uv_height != 0) {
|
||||
yo = (buffer->uv_stride)*(decode->video_info.offset_y/(decode->y_height/decode->uv_height));
|
||||
}
|
||||
return xo + yo;
|
||||
}
|
||||
|
||||
int
|
||||
oggplay_data_handle_theora_frame (OggPlayTheoraDecode *decode,
|
||||
const yuv_buffer *buffer) {
|
||||
|
||||
size_t size = sizeof (OggPlayVideoRecord);
|
||||
int i, ret;
|
||||
long y_size, uv_size, y_offset, uv_offset;
|
||||
unsigned char * p;
|
||||
unsigned char * q;
|
||||
unsigned char * p2;
|
||||
unsigned char * q2;
|
||||
OggPlayVideoRecord * record;
|
||||
OggPlayVideoData * data;
|
||||
|
||||
/* check for possible integer overflows */
|
||||
ret =
|
||||
oggplay_mul_signed_overflow (buffer->y_height, buffer->y_stride, &y_size);
|
||||
if (ret == E_OGGPLAY_TYPE_OVERFLOW) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret =
|
||||
oggplay_mul_signed_overflow (buffer->uv_height, buffer->uv_stride, &uv_size);
|
||||
if (ret == E_OGGPLAY_TYPE_OVERFLOW) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = oggplay_mul_signed_overflow (uv_size, 2, &uv_size);
|
||||
if (ret == E_OGGPLAY_TYPE_OVERFLOW) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (buffer->y_stride < 0) {
|
||||
y_size *= -1;
|
||||
uv_size *= -1;
|
||||
}
|
||||
|
||||
ret = oggplay_check_add_overflow (size, y_size, &size);
|
||||
if (ret == E_OGGPLAY_TYPE_OVERFLOW) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = oggplay_check_add_overflow (size, uv_size, &size);
|
||||
if (ret == E_OGGPLAY_TYPE_OVERFLOW) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* we need to set the output strides to the input widths because we are
|
||||
* trying not to pass negative output stride issues on to the poor user.
|
||||
*/
|
||||
record = (OggPlayVideoRecord*)oggplay_malloc (size);
|
||||
|
||||
if (record == NULL) {
|
||||
return E_OGGPLAY_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
record->header.samples_in_record = 1;
|
||||
data = &(record->data);
|
||||
|
||||
data->y = (unsigned char *)(record + 1);
|
||||
data->u = data->y + (decode->y_stride * decode->y_height);
|
||||
data->v = data->u + (decode->uv_stride * decode->uv_height);
|
||||
|
||||
/*
|
||||
* *grumble* theora plays silly buggers with pointers so we need to do
|
||||
* a row-by-row copy (stride may be negative)
|
||||
*/
|
||||
y_offset = (decode->video_info.offset_x&~1)
|
||||
+ buffer->y_stride*(decode->video_info.offset_y&~1);
|
||||
p = data->y;
|
||||
q = buffer->y + y_offset;
|
||||
for (i = 0; i < decode->y_height; i++) {
|
||||
memcpy(p, q, decode->y_width);
|
||||
p += decode->y_width;
|
||||
q += buffer->y_stride;
|
||||
}
|
||||
|
||||
uv_offset = get_uv_offset(decode, buffer);
|
||||
p = data->u;
|
||||
q = buffer->u + uv_offset;
|
||||
p2 = data->v;
|
||||
q2 = buffer->v + uv_offset;
|
||||
for (i = 0; i < decode->uv_height; i++) {
|
||||
memcpy(p, q, decode->uv_width);
|
||||
memcpy(p2, q2, decode->uv_width);
|
||||
p += decode->uv_width;
|
||||
p2 += decode->uv_width;
|
||||
q += buffer->uv_stride;
|
||||
q2 += buffer->uv_stride;
|
||||
}
|
||||
|
||||
/* if we're to send RGB video, convert here */
|
||||
if (decode->convert_to_rgb) {
|
||||
OggPlayYUVChannels yuv;
|
||||
OggPlayRGBChannels rgb;
|
||||
OggPlayOverlayRecord * orecord;
|
||||
OggPlayOverlayData * odata;
|
||||
long overlay_size;
|
||||
|
||||
yuv.ptry = data->y;
|
||||
yuv.ptru = data->u;
|
||||
yuv.ptrv = data->v;
|
||||
yuv.y_width = decode->y_width;
|
||||
yuv.y_height = decode->y_height;
|
||||
yuv.uv_width = decode->uv_width;
|
||||
yuv.uv_height = decode->uv_height;
|
||||
|
||||
size = sizeof(OggPlayOverlayRecord);
|
||||
/* check for possible integer oveflows */
|
||||
ret = oggplay_mul_signed_overflow(decode->y_width, decode->y_height,
|
||||
&overlay_size);
|
||||
if (ret == E_OGGPLAY_TYPE_OVERFLOW) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = oggplay_mul_signed_overflow(overlay_size, 4, &overlay_size);
|
||||
if (ret == E_OGGPLAY_TYPE_OVERFLOW) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = oggplay_check_add_overflow (size, overlay_size, &size);
|
||||
if (ret == E_OGGPLAY_TYPE_OVERFLOW) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* allocate memory for the overlay record */
|
||||
orecord = (OggPlayOverlayRecord*) oggplay_malloc (size);
|
||||
if (orecord != NULL) {
|
||||
oggplay_data_initialise_header((OggPlayDecode *)decode, &(orecord->header));
|
||||
orecord->header.samples_in_record = 1;
|
||||
odata = &(orecord->data);
|
||||
|
||||
rgb.ptro = (unsigned char*)(orecord+1);
|
||||
rgb.rgb_width = yuv.y_width;
|
||||
rgb.rgb_height = yuv.y_height;
|
||||
|
||||
if (!decode->swap_rgb) {
|
||||
oggplay_yuv2bgra(&yuv, &rgb);
|
||||
} else {
|
||||
oggplay_yuv2rgba(&yuv, &rgb);
|
||||
}
|
||||
|
||||
odata->rgb = rgb.ptro;
|
||||
odata->rgba = NULL;
|
||||
odata->width = rgb.rgb_width;
|
||||
odata->height = rgb.rgb_height;
|
||||
odata->stride = rgb.rgb_width*4;
|
||||
|
||||
oggplay_free(record);
|
||||
|
||||
oggplay_data_add_to_list((OggPlayDecode *)decode, &(orecord->header));
|
||||
} else {
|
||||
/* memory allocation failed! */
|
||||
oggplay_free (record);
|
||||
|
||||
return E_OGGPLAY_OUT_OF_MEMORY;
|
||||
}
|
||||
}
|
||||
else {
|
||||
oggplay_data_initialise_header((OggPlayDecode *)decode, &(record->header));
|
||||
oggplay_data_add_to_list((OggPlayDecode *)decode, &(record->header));
|
||||
}
|
||||
|
||||
return E_OGGPLAY_CONTINUE;
|
||||
}
|
||||
|
||||
#ifdef HAVE_KATE
|
||||
OggPlayErrorCode
|
||||
oggplay_data_handle_kate_data(OggPlayKateDecode *decode, const kate_event *ev) {
|
||||
|
||||
OggPlayTextRecord * record = NULL;
|
||||
size_t rec_size = sizeof(OggPlayTextRecord);
|
||||
|
||||
if (decode == NULL) {
|
||||
return -1;
|
||||
}
|
||||
#ifdef HAVE_TIGER
|
||||
tiger_renderer_add_event(decode->tr, ev->ki, ev);
|
||||
|
||||
if (decode->use_tiger) {
|
||||
/* if rendering with Tiger, we don't add an event, a synthetic one will be
|
||||
generated each "tick" with an updated tracker state */
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
/* check for integer overflow */
|
||||
if
|
||||
(
|
||||
oggplay_check_add_overflow (rec_size, ev->len0, &rec_size)
|
||||
==
|
||||
E_OGGPLAY_TYPE_OVERFLOW
|
||||
)
|
||||
{
|
||||
return E_OGGPLAY_TYPE_OVERFLOW;
|
||||
}
|
||||
|
||||
record = (OggPlayTextRecord*)oggplay_calloc (rec_size, 1);
|
||||
if (!record) {
|
||||
return E_OGGPLAY_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
oggplay_data_initialise_header(&decode->decoder, &(record->header));
|
||||
|
||||
//record->header.presentation_time = (ogg_int64_t)(ev->start_time*1000);
|
||||
record->header.samples_in_record = (ev->end_time-ev->start_time)*1000;
|
||||
record->data = (char *)(record + 1);
|
||||
|
||||
memcpy(record->data, ev->text, ev->len0);
|
||||
|
||||
oggplay_data_add_to_list(&decode->decoder, &(record->header));
|
||||
}
|
||||
|
||||
return E_OGGPLAY_CONTINUE;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_TIGER
|
||||
OggPlayErrorCode
|
||||
oggplay_data_update_tiger(OggPlayKateDecode *decode, int active, ogg_int64_t presentation_time, OggPlayCallbackInfo *info) {
|
||||
|
||||
OggPlayOverlayRecord * record = NULL;
|
||||
OggPlayOverlayData * data = NULL;
|
||||
size_t size = sizeof (OggPlayOverlayRecord);
|
||||
int track = active && decode->use_tiger;
|
||||
int ret;
|
||||
kate_float t = OGGPLAY_TIME_FP_TO_INT(presentation_time) / 1000.0f;
|
||||
|
||||
if (!decode->decoder.initialised) return -1;
|
||||
|
||||
if (track) {
|
||||
if (info) {
|
||||
if (info->required_records>0) {
|
||||
OggPlayDataHeader *header = info->records[0];
|
||||
data = (OggPlayOverlayData*)(header+1);
|
||||
if (decode->tr && data->rgb) {
|
||||
#if WORDS_BIGENDIAN || IS_BIG_ENDIAN
|
||||
tiger_renderer_set_buffer(decode->tr, data->rgb, data->width, data->height, data->stride, 0);
|
||||
#else
|
||||
tiger_renderer_set_buffer(decode->tr, data->rgb, data->width, data->height, data->stride, 1);
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
/* we're supposed to overlay on a frame, but the available frame has no RGB buffer */
|
||||
/* fprintf(stderr,"no RGB buffer found for video frame\n"); */
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* we're supposed to overlay on a frame, but there is no frame available */
|
||||
/* fprintf(stderr,"no video frame to overlay on\n"); */
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// TODO: some way of knowing the size of the video we'll be drawing onto, if any
|
||||
int width = decode->k_state.ki->original_canvas_width;
|
||||
int height = decode->k_state.ki->original_canvas_height;
|
||||
long overlay_size;
|
||||
if (width <= 0 || height <= 0) {
|
||||
/* some default resolution if we're not overlaying onto a video and the canvas size is unknown */
|
||||
if (decode->default_width > 0 && decode->default_height > 0) {
|
||||
width = decode->default_width;
|
||||
height = decode->default_height;
|
||||
}
|
||||
else {
|
||||
width = 640;
|
||||
height = 480;
|
||||
}
|
||||
}
|
||||
/* check for integer overflow */
|
||||
ret = oggplay_mul_signed_overflow (width, height, &overlay_size);
|
||||
if (ret == E_OGGPLAY_TYPE_OVERFLOW) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = oggplay_mul_signed_overflow (overlay_size, 4, &overlay_size);
|
||||
if (ret == E_OGGPLAY_TYPE_OVERFLOW) {
|
||||
return E_OGGPLAY_TYPE_OVERFLOW;
|
||||
}
|
||||
|
||||
ret = oggplay_check_add_overflow (size, overlay_size, &size);
|
||||
if (ret == E_OGGPLAY_TYPE_OVERFLOW) {
|
||||
return E_OGGPLAY_TYPE_OVERFLOW;
|
||||
}
|
||||
|
||||
record = (OggPlayOverlayRecord*)oggplay_calloc (1, size);
|
||||
if (!record)
|
||||
return E_OGGPLAY_OUT_OF_MEMORY;
|
||||
|
||||
record->header.samples_in_record = 1;
|
||||
data= &(record->data);
|
||||
oggplay_data_initialise_header((OggPlayDecode *)decode, &(record->header));
|
||||
|
||||
data->rgba = (unsigned char*)(record+1);
|
||||
data->rgb = NULL;
|
||||
data->width = width;
|
||||
data->height = height;
|
||||
data->stride = width*4;
|
||||
|
||||
if (decode->tr && data->rgba) {
|
||||
tiger_renderer_set_buffer(decode->tr, data->rgba, data->width, data->height, data->stride, decode->swap_rgb);
|
||||
}
|
||||
|
||||
oggplay_data_add_to_list(&decode->decoder, &(record->header));
|
||||
record->header.presentation_time=presentation_time;
|
||||
}
|
||||
}
|
||||
|
||||
if (decode->tr) {
|
||||
tiger_renderer_update(decode->tr, t, track);
|
||||
}
|
||||
|
||||
if (track) {
|
||||
/* buffer was either calloced, so already cleared, or already filled with video, so no clearing */
|
||||
if (decode->tr) {
|
||||
tiger_renderer_render(decode->tr);
|
||||
}
|
||||
}
|
||||
|
||||
return E_OGGPLAY_CONTINUE;
|
||||
}
|
||||
#endif
|
||||
|
|
@ -1,77 +0,0 @@
|
|||
/*
|
||||
Copyright (C) 2003 Commonwealth Scientific and Industrial Research
|
||||
Organisation (CSIRO) Australia
|
||||
|
||||
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.
|
||||
|
||||
- Neither the name of CSIRO Australia nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
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 ORGANISATION 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* oggplay_data.h
|
||||
*
|
||||
* Shane Stephens <shane.stephens@annodex.net>
|
||||
*/
|
||||
#ifndef __OGGPLAY_DATA_H__
|
||||
#define __OGGPLAY_DATA_H__
|
||||
|
||||
void
|
||||
oggplay_data_initialise_list (OggPlayDecode *decode);
|
||||
|
||||
OggPlayErrorCode
|
||||
oggplay_data_handle_theora_frame (OggPlayTheoraDecode *decode,
|
||||
const yuv_buffer *buffer);
|
||||
|
||||
OggPlayErrorCode
|
||||
oggplay_data_handle_audio_data (OggPlayDecode *decode,
|
||||
void *data, long samples, size_t samplesize);
|
||||
|
||||
OggPlayErrorCode
|
||||
oggplay_data_handle_cmml_data(OggPlayDecode *decode,
|
||||
unsigned char *data, long size);
|
||||
|
||||
#ifdef HAVE_KATE
|
||||
OggPlayErrorCode
|
||||
oggplay_data_handle_kate_data(OggPlayKateDecode *decode,
|
||||
const kate_event *ev);
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_TIGER
|
||||
OggPlayErrorCode
|
||||
oggplay_data_update_tiger(OggPlayKateDecode *decode,
|
||||
int active, ogg_int64_t presentation_time,
|
||||
OggPlayCallbackInfo *info);
|
||||
#endif
|
||||
|
||||
void
|
||||
oggplay_data_clean_list (OggPlayDecode *decode);
|
||||
|
||||
void
|
||||
oggplay_data_free_list(OggPlayDataHeader *list);
|
||||
|
||||
void
|
||||
oggplay_data_shutdown_list (OggPlayDecode *decode);
|
||||
#endif
|
|
@ -1,185 +0,0 @@
|
|||
/*
|
||||
Copyright (C) 2003 Commonwealth Scientific and Industrial Research
|
||||
Organisation (CSIRO) Australia
|
||||
|
||||
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.
|
||||
|
||||
- Neither the name of CSIRO Australia nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
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 ORGANISATION 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* oggplay_file_reader.c
|
||||
*
|
||||
* Shane Stephens <shane.stephens@annodex.net>
|
||||
* Michael Martin
|
||||
*/
|
||||
|
||||
#include "oggplay_private.h"
|
||||
#include "oggplay_file_reader.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
OggPlayErrorCode
|
||||
oggplay_file_reader_initialise(OggPlayReader * opr, int block) {
|
||||
|
||||
OggPlayFileReader * me = (OggPlayFileReader *)opr;
|
||||
(void)block; /* unused for file readers */
|
||||
|
||||
if (me == NULL) {
|
||||
return E_OGGPLAY_BAD_READER;
|
||||
}
|
||||
|
||||
me->file = fopen(me->file_name, "rb");
|
||||
|
||||
if (me->file == NULL) {
|
||||
return E_OGGPLAY_BAD_INPUT;
|
||||
}
|
||||
|
||||
fseek(me->file, 0L, SEEK_END);
|
||||
me->size = ftell(me->file);
|
||||
fseek(me->file, 0L, SEEK_SET);
|
||||
|
||||
me->current_position = 0;
|
||||
|
||||
return E_OGGPLAY_OK;
|
||||
}
|
||||
|
||||
OggPlayErrorCode
|
||||
oggplay_file_reader_destroy(OggPlayReader * opr) {
|
||||
|
||||
OggPlayFileReader * me;
|
||||
|
||||
if (opr == NULL) {
|
||||
return E_OGGPLAY_BAD_READER;
|
||||
}
|
||||
|
||||
me = (OggPlayFileReader *)opr;
|
||||
|
||||
if (me->file != NULL) {
|
||||
fclose(me->file);
|
||||
}
|
||||
|
||||
oggplay_free(me);
|
||||
|
||||
return E_OGGPLAY_OK;
|
||||
}
|
||||
|
||||
int
|
||||
oggplay_file_reader_available(OggPlayReader * opr, ogg_int64_t current_bytes,
|
||||
ogg_int64_t current_time) {
|
||||
|
||||
OggPlayFileReader *me = (OggPlayFileReader *)opr;
|
||||
|
||||
if (me == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return me->size;
|
||||
|
||||
}
|
||||
|
||||
int
|
||||
oggplay_file_reader_finished_retrieving(OggPlayReader *opr) {
|
||||
|
||||
return 1;
|
||||
|
||||
}
|
||||
|
||||
|
||||
static size_t
|
||||
oggplay_file_reader_io_read(void * user_handle, void * buf, size_t n) {
|
||||
|
||||
OggPlayFileReader *me = (OggPlayFileReader *)user_handle;
|
||||
int r;
|
||||
|
||||
if (me == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
r = fread(buf, 1, n, me->file);
|
||||
if (r > 0) {
|
||||
me->current_position += r;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int
|
||||
oggplay_file_reader_io_seek(void * user_handle, long offset, int whence) {
|
||||
|
||||
OggPlayFileReader * me = (OggPlayFileReader *)user_handle;
|
||||
int r;
|
||||
|
||||
if (me == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
r = fseek(me->file, offset, whence);
|
||||
me->current_position = ftell(me->file);
|
||||
return r;
|
||||
|
||||
}
|
||||
|
||||
static long
|
||||
oggplay_file_reader_io_tell(void * user_handle) {
|
||||
|
||||
OggPlayFileReader * me = (OggPlayFileReader *)user_handle;
|
||||
|
||||
if (me == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return ftell(me->file);
|
||||
|
||||
}
|
||||
|
||||
OggPlayReader *
|
||||
oggplay_file_reader_new(const char *file_name) {
|
||||
|
||||
OggPlayFileReader * me = oggplay_malloc (sizeof (OggPlayFileReader));
|
||||
|
||||
if (me == NULL)
|
||||
return NULL;
|
||||
|
||||
me->current_position = 0;
|
||||
me->file_name = file_name;
|
||||
me->file = NULL;
|
||||
|
||||
me->functions.initialise = &oggplay_file_reader_initialise;
|
||||
me->functions.destroy = &oggplay_file_reader_destroy;
|
||||
me->functions.available = &oggplay_file_reader_available;
|
||||
me->functions.finished_retrieving = &oggplay_file_reader_finished_retrieving;
|
||||
me->functions.seek = NULL;
|
||||
me->functions.duration = NULL;
|
||||
me->functions.io_read = &oggplay_file_reader_io_read;
|
||||
me->functions.io_seek = &oggplay_file_reader_io_seek;
|
||||
me->functions.io_tell = &oggplay_file_reader_io_tell;
|
||||
me->functions.duration = NULL;
|
||||
|
||||
return (OggPlayReader *)me;
|
||||
|
||||
}
|
|
@ -1,56 +0,0 @@
|
|||
/*
|
||||
Copyright (C) 2003 Commonwealth Scientific and Industrial Research
|
||||
Organisation (CSIRO) Australia
|
||||
|
||||
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.
|
||||
|
||||
- Neither the name of CSIRO Australia nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
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 ORGANISATION 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* oggplay_file_reader.h
|
||||
*
|
||||
* Shane Stephens <shane.stephens@annodex.net>
|
||||
* Michael Martin
|
||||
*/
|
||||
|
||||
#ifndef __OGGPLAY_FILE_READER_H__
|
||||
#define __OGGPLAY_FILE_READER_H__
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#define FILE_READER_CHUNK_SIZE 8192
|
||||
#define FILE_READER_INITIAL_NUM_BUFFERS 8
|
||||
|
||||
typedef struct {
|
||||
OggPlayReader functions;
|
||||
const char * file_name;
|
||||
FILE * file;
|
||||
long current_position;
|
||||
long size;
|
||||
} OggPlayFileReader;
|
||||
|
||||
#endif
|
|
@ -1,458 +0,0 @@
|
|||
/*
|
||||
Copyright (C) 2003 Commonwealth Scientific and Industrial Research
|
||||
Organisation (CSIRO) Australia
|
||||
|
||||
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.
|
||||
|
||||
- Neither the name of CSIRO Australia nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
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 ORGANISATION 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* oggplay_private.h
|
||||
*
|
||||
* Shane Stephens <shane.stephens@annodex.net>
|
||||
* Michael Martin
|
||||
*/
|
||||
#ifndef __OGGPLAY_PRIVATE_H__
|
||||
#define __OGGPLAY_PRIVATE_H__
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#ifdef WIN32
|
||||
#include "config_win32.h"
|
||||
#else
|
||||
#include <config.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include <oggplay/oggplay.h>
|
||||
|
||||
#include <oggz/oggz.h>
|
||||
#include <theora/theora.h>
|
||||
#include <fishsound/fishsound.h>
|
||||
|
||||
#ifdef HAVE_KATE
|
||||
#include <kate/kate.h>
|
||||
#endif
|
||||
#ifdef HAVE_TIGER
|
||||
#include <tiger/tiger.h>
|
||||
#endif
|
||||
|
||||
#ifdef WIN32
|
||||
|
||||
#ifdef HAVE_WINSOCK2
|
||||
#include <winsock2.h>
|
||||
#else
|
||||
#include <winsock.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef OS2
|
||||
#define INCL_DOSSEMAPHORES
|
||||
#define INCL_DOSPROCESS
|
||||
#include <os2.h>
|
||||
#endif
|
||||
|
||||
// for Win32 <windows.h> has to be included last
|
||||
#include "std_semaphore.h"
|
||||
|
||||
/**
|
||||
*
|
||||
* has_been_presented: 0 until the data has been added as a "required" element,
|
||||
* then 1.
|
||||
*/
|
||||
struct _OggPlayDataHeader {
|
||||
int lock;
|
||||
struct _OggPlayDataHeader * next;
|
||||
ogg_int64_t presentation_time;
|
||||
ogg_int64_t samples_in_record;
|
||||
int has_been_presented;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
OggPlayDataHeader header;
|
||||
OggPlayVideoData data;
|
||||
} OggPlayVideoRecord;
|
||||
|
||||
typedef struct {
|
||||
OggPlayDataHeader header;
|
||||
OggPlayOverlayData data;
|
||||
} OggPlayOverlayRecord;
|
||||
|
||||
typedef struct {
|
||||
OggPlayDataHeader header;
|
||||
void * data;
|
||||
} OggPlayAudioRecord;
|
||||
|
||||
typedef struct {
|
||||
OggPlayDataHeader header;
|
||||
char * data;
|
||||
} OggPlayTextRecord;
|
||||
|
||||
struct _OggPlay;
|
||||
|
||||
typedef struct {
|
||||
void ** buffer_list;
|
||||
void ** buffer_mirror;
|
||||
int buffer_size;
|
||||
int last_filled;
|
||||
int last_emptied;
|
||||
semaphore frame_sem;
|
||||
} OggPlayBuffer;
|
||||
|
||||
struct _OggPlayCallbackInfo {
|
||||
OggPlayDataType data_type;
|
||||
int available_records;
|
||||
int required_records;
|
||||
OggPlayStreamInfo stream_info;
|
||||
OggPlayDataHeader ** records;
|
||||
OggPlayBuffer * buffer;
|
||||
};
|
||||
|
||||
/**
|
||||
* OggPlayDecode
|
||||
*
|
||||
* A structure that contains information about a single track within the Ogg
|
||||
* file.
|
||||
*
|
||||
* data_list, end_of_data_list: Contain decoded data packets for this track.
|
||||
* These packets are time-ordered, and have a
|
||||
* known presentation time
|
||||
*
|
||||
* untimed_data_list: Contains decoded data packets for this track.
|
||||
* These packets are reverse time-ordered, and
|
||||
* have not got a known presentation time. This
|
||||
* list gets constructed when a new Ogg file is
|
||||
* first being read, and gets torn down as soon as
|
||||
* the first packet with a granulepos is processed
|
||||
*
|
||||
* granuleperiod The period between adjacent samples in this
|
||||
* track
|
||||
*/
|
||||
typedef struct {
|
||||
long serialno; /**< identifies the logical bit stream */
|
||||
int content_type;
|
||||
const char * content_type_name;
|
||||
OggPlayDataType decoded_type; /**< type of the track @see OggPlayDataType */
|
||||
ogg_int64_t granuleperiod;
|
||||
ogg_int64_t last_granulepos; /**< last seen granule position */
|
||||
ogg_int64_t offset; /**< */
|
||||
ogg_int64_t current_loc; /**< current location in the stream (in ) */
|
||||
int active; /**< indicates whether the track is active or not */
|
||||
ogg_int64_t final_granulepos; /**< */
|
||||
struct _OggPlay * player; /**< reference to the OggPlay handle */
|
||||
OggPlayDataHeader * data_list;
|
||||
OggPlayDataHeader * end_of_data_list;
|
||||
OggPlayDataHeader * untimed_data_list;
|
||||
OggPlayStreamInfo stream_info; /**< @see OggPlayStreamInfo */
|
||||
int preroll; /**< num. of past content packets to take into account when decoding the current Ogg page */
|
||||
short initialised; /**< */
|
||||
int num_header_packets; /**< number of header packets left to process for the stream.*/
|
||||
} OggPlayDecode;
|
||||
|
||||
typedef struct {
|
||||
OggPlayDecode decoder;
|
||||
theora_state video_handle;
|
||||
theora_info video_info;
|
||||
theora_comment video_comment;
|
||||
int granulepos_seen;
|
||||
int frame_delta;
|
||||
int y_width;
|
||||
int y_height;
|
||||
int y_stride;
|
||||
int uv_width;
|
||||
int uv_height;
|
||||
int uv_stride;
|
||||
int cached_keyframe;
|
||||
int convert_to_rgb;
|
||||
int swap_rgb;
|
||||
} OggPlayTheoraDecode;
|
||||
|
||||
typedef struct {
|
||||
OggPlayDecode decoder;
|
||||
FishSound * sound_handle;
|
||||
FishSoundInfo sound_info;
|
||||
} OggPlayAudioDecode;
|
||||
|
||||
typedef struct {
|
||||
OggPlayDecode decoder;
|
||||
int granuleshift;
|
||||
} OggPlayCmmlDecode;
|
||||
|
||||
/**
|
||||
* OggPlaySkeletonDecode
|
||||
*/
|
||||
typedef struct {
|
||||
OggPlayDecode decoder;
|
||||
ogg_int64_t presentation_time;
|
||||
ogg_int64_t base_time;
|
||||
} OggPlaySkeletonDecode;
|
||||
|
||||
typedef struct {
|
||||
OggPlayDecode decoder;
|
||||
#ifdef HAVE_KATE
|
||||
int granuleshift;
|
||||
kate_state k_state;
|
||||
kate_info k_info;
|
||||
kate_comment k_comment;
|
||||
int init;
|
||||
#ifdef HAVE_TIGER
|
||||
int use_tiger;
|
||||
int overlay_dest;
|
||||
tiger_renderer *tr;
|
||||
int default_width;
|
||||
int default_height;
|
||||
int swap_rgb;
|
||||
#endif
|
||||
#endif
|
||||
} OggPlayKateDecode;
|
||||
|
||||
struct OggPlaySeekTrash;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
typedef struct OggPlaySeekTrash {
|
||||
OggPlayDataHeader * old_data;
|
||||
OggPlayBuffer * old_buffer;
|
||||
struct OggPlaySeekTrash * next;
|
||||
} OggPlaySeekTrash;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
struct _OggPlay {
|
||||
OggPlayReader * reader; /**< @see OggPlayReader */
|
||||
OGGZ * oggz; /**< @see OGGZ */
|
||||
OggPlayDecode ** decode_data; /**< */
|
||||
OggPlayCallbackInfo * callback_info; /**< */
|
||||
int num_tracks; /**< number of tracks in the Ogg container */
|
||||
int all_tracks_initialised; /**< "= 1" indicates that all tracks are initialised */
|
||||
ogg_int64_t callback_period; /**< */
|
||||
OggPlayDataCallback * callback; /**< */
|
||||
void * callback_user_ptr; /**< */
|
||||
ogg_int64_t target; /**< */
|
||||
int active_tracks; /**< number of active tracks */
|
||||
volatile OggPlayBuffer * buffer; /**< @see OggPlayBuffer */
|
||||
ogg_int64_t presentation_time; /**< */
|
||||
OggPlaySeekTrash * trash; /**< @see OggPlaySeekTrash */
|
||||
int shutdown; /**< "= 1" indicates shutdown event */
|
||||
int pt_update_valid; /**< */
|
||||
ogg_int64_t duration; /**< The value of the duration the last time it was retrieved.*/
|
||||
int max_video_frame_pixels; /**< Maximum number of pixels we'll allow in a video frame.*/
|
||||
};
|
||||
|
||||
void
|
||||
oggplay_set_data_callback_force(OggPlay *me, OggPlayDataCallback callback,
|
||||
void *user);
|
||||
|
||||
void
|
||||
oggplay_take_out_trash(OggPlay *me, OggPlaySeekTrash *trash);
|
||||
|
||||
OggPlayErrorCode
|
||||
oggplay_seek_cleanup(OggPlay *me, ogg_int64_t milliseconds);
|
||||
|
||||
typedef struct {
|
||||
void (*init) (void *user_data);
|
||||
int (*callback) (OGGZ * oggz, ogg_packet * op, long serialno,
|
||||
void * user_data);
|
||||
void (*shutdown) (void *user_data);
|
||||
int size;
|
||||
} OggPlayCallbackFunctions;
|
||||
|
||||
/**
|
||||
* Conversion function for fixed point 32.32 representation of time.
|
||||
*
|
||||
* OGGPLAY_TIME_INT_TO_FP(x)
|
||||
* converts 'x' to a 32.32 fixed point integer
|
||||
*
|
||||
* OGGPLAY_TIME_FP_TO_INT
|
||||
* converts 'x' - a 32.32 fixed point integer - back to normal integer representation
|
||||
* + changes the order of magnitude by 1000
|
||||
* e.g. if the fixed point number - 32.32 format - represents seconds
|
||||
* then the macro will convert it to milliseconds.
|
||||
*/
|
||||
#define OGGPLAY_TIME_INT_TO_FP(x) ((x) << 32)
|
||||
#define OGGPLAY_TIME_FP_TO_INT(x) (((((x) >> 16) * 1000) >> 16) & 0xFFFFFFFF)
|
||||
|
||||
/* Allocate and free dynamic memory used by ogg.
|
||||
* By default they are the ones from stdlib */
|
||||
#define oggplay_malloc _ogg_malloc
|
||||
#define oggplay_calloc _ogg_calloc
|
||||
#define oggplay_realloc _ogg_realloc
|
||||
#define oggplay_free _ogg_free
|
||||
|
||||
/**
|
||||
* macros for obtaining a type's max and min values
|
||||
* http://www.fefe.de/intof.html
|
||||
*/
|
||||
#define OGGPLAY_TYPE_HALF_MAX_SIGNED(type) ((type)1 << (sizeof(type)*8-2))
|
||||
#define OGGPLAY_TYPE_MAX_SIGNED(type) (OGGPLAY_TYPE_HALF_MAX_SIGNED(type) - 1 + OGGPLAY_TYPE_HALF_MAX_SIGNED(type))
|
||||
#define OGGPLAY_TYPE_MIN_SIGNED(type) (-1 - OGGPLAY_TYPE_MAX_SIGNED(type))
|
||||
#define OGGPLAY_TYPE_MIN(type) ((type)-1 < 1?OGGPLAY_TYPE_MIN_SIGNED(type):(type)0)
|
||||
#define OGGPLAY_TYPE_MAX(type) ((type)~OGGPLAY_TYPE_MIN(type))
|
||||
|
||||
static inline int
|
||||
oggplay_check_add_overflow (size_t a, long b, size_t* r) {
|
||||
/* we cannot assume that sizeof(size_t) >= sizeof(long) !!! */
|
||||
if (sizeof(size_t) < sizeof(long)) {
|
||||
/* check whether the number fits into a size_t */
|
||||
if
|
||||
(
|
||||
(b < 0) ?
|
||||
((OGGPLAY_TYPE_MAX(size_t)+b >= 0) ? 0 : 1) :
|
||||
((OGGPLAY_TYPE_MAX(size_t)-b >= 0) ? 0 : 1)
|
||||
)
|
||||
{
|
||||
return E_OGGPLAY_TYPE_OVERFLOW;
|
||||
}
|
||||
}
|
||||
/* check whether the sum of the 'a' and 'b' fits into a size_t */
|
||||
if
|
||||
(
|
||||
(b < 0) ?
|
||||
((OGGPLAY_TYPE_MIN(size_t)-b <= a) ? 0 : 1) :
|
||||
((OGGPLAY_TYPE_MAX(size_t)-b >= a) ? 0 : 1)
|
||||
)
|
||||
{
|
||||
return E_OGGPLAY_TYPE_OVERFLOW;
|
||||
}
|
||||
|
||||
/* if 'r' is supplied give back the sum of 'a' and 'b' */
|
||||
if (r != NULL)
|
||||
*r = a+b;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int
|
||||
oggplay_mul_signed_overflow_generic(long a, long b, long *re) {
|
||||
long _a, _b, ah, bh, x, y, r = 0;
|
||||
int sign = 1;
|
||||
|
||||
_a = a;
|
||||
_b = b;
|
||||
ah = _a >> (sizeof(long)*4);
|
||||
bh = _b >> (sizeof(long)*4);
|
||||
|
||||
if (a < 0) {
|
||||
_a = -_a;
|
||||
if (_a < 0) {
|
||||
if (_b == 0 || _b == 1) {
|
||||
r = _a*_b;
|
||||
goto ok;
|
||||
} else {
|
||||
goto overflow;
|
||||
}
|
||||
}
|
||||
sign = -sign;
|
||||
ah = _a >> (sizeof(long)*4);
|
||||
}
|
||||
|
||||
if (_b < 0) {
|
||||
_b = -_b;
|
||||
if (_b < 0) {
|
||||
if (_a == 0 || (_a == 1 && sign == 1)) {
|
||||
r = _a*_b;
|
||||
goto ok;
|
||||
} else {
|
||||
goto overflow;
|
||||
}
|
||||
}
|
||||
sign = -sign;
|
||||
bh = _b >> (sizeof(long)*4);
|
||||
}
|
||||
|
||||
if (ah != 0 && bh != 0) {
|
||||
goto overflow;
|
||||
}
|
||||
|
||||
if (ah == 0 && bh == 0) {
|
||||
r = _a*_b;
|
||||
if (r < 0)
|
||||
goto overflow;
|
||||
|
||||
goto ok;
|
||||
}
|
||||
|
||||
if (_a < _b) {
|
||||
x = _a;
|
||||
_a = _b;
|
||||
_b = x;
|
||||
ah = bh;
|
||||
}
|
||||
|
||||
y = ah*_b;
|
||||
if (y >= (1L << (sizeof(long)*4 - 1)))
|
||||
goto overflow;
|
||||
_a &= (1L << sizeof(long)*4) - 1;
|
||||
x = _a*_b;
|
||||
if (x < 0)
|
||||
goto overflow;
|
||||
x += (y << sizeof(long)*4);
|
||||
if (x < 0)
|
||||
goto overflow;
|
||||
|
||||
ok:
|
||||
if (re != NULL) {
|
||||
*re = sign*r;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
overflow:
|
||||
return E_OGGPLAY_TYPE_OVERFLOW;
|
||||
}
|
||||
|
||||
static inline int
|
||||
oggplay_mul_signed_overflow(long a, long b, long *r) {
|
||||
if (sizeof(long) > 4) {
|
||||
return oggplay_mul_signed_overflow_generic (a, b, r);
|
||||
} else {
|
||||
ogg_int64_t c = (ogg_int64_t) a*b;
|
||||
|
||||
/* check whether the result fits in a long bit */
|
||||
if
|
||||
(
|
||||
(c < 1) ?
|
||||
((OGGPLAY_TYPE_MIN (long) > c) ? 1 : 0) :
|
||||
((OGGPLAY_TYPE_MAX (long) < c) ? 1 : 0)
|
||||
)
|
||||
{
|
||||
return E_OGGPLAY_TYPE_OVERFLOW;
|
||||
}
|
||||
|
||||
if (r != NULL) {
|
||||
*r = (long)c;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
#include "oggplay_callback.h"
|
||||
#include "oggplay_data.h"
|
||||
#include "oggplay_buffer.h"
|
||||
|
||||
#endif
|
|
@ -1,207 +0,0 @@
|
|||
/*
|
||||
Copyright (C) 2003 Commonwealth Scientific and Industrial Research
|
||||
Organisation (CSIRO) Australia
|
||||
|
||||
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.
|
||||
|
||||
- Neither the name of CSIRO Australia nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
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 ORGANISATION 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* oggplay_query.c
|
||||
*
|
||||
* Shane Stephens <shane.stephens@annodex.net>
|
||||
*/
|
||||
|
||||
#include "oggplay_private.h"
|
||||
|
||||
int
|
||||
oggplay_get_num_tracks (OggPlay * me) {
|
||||
|
||||
if (me == NULL) {
|
||||
return E_OGGPLAY_BAD_OGGPLAY;
|
||||
}
|
||||
|
||||
if (me->reader == NULL) {
|
||||
return E_OGGPLAY_BAD_READER;
|
||||
}
|
||||
|
||||
if (me->all_tracks_initialised == 0) {
|
||||
return E_OGGPLAY_UNINITIALISED;
|
||||
}
|
||||
|
||||
return me->num_tracks;
|
||||
|
||||
}
|
||||
|
||||
OggzStreamContent
|
||||
oggplay_get_track_type (OggPlay * me, int track_num) {
|
||||
|
||||
if (me == NULL) {
|
||||
return (OggzStreamContent)E_OGGPLAY_BAD_OGGPLAY;
|
||||
}
|
||||
|
||||
if (me->reader == NULL) {
|
||||
return (OggzStreamContent)E_OGGPLAY_BAD_READER;
|
||||
}
|
||||
|
||||
if (me->all_tracks_initialised == 0) {
|
||||
return E_OGGPLAY_UNINITIALISED;
|
||||
}
|
||||
|
||||
if (track_num < 0 || track_num >= me->num_tracks) {
|
||||
return (OggzStreamContent)E_OGGPLAY_BAD_TRACK;
|
||||
}
|
||||
|
||||
return (OggzStreamContent)me->decode_data[track_num]->content_type;
|
||||
}
|
||||
|
||||
const char *
|
||||
oggplay_get_track_typename (OggPlay * me, int track_num) {
|
||||
|
||||
if (me == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (me->reader == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (me->all_tracks_initialised == 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (track_num < 0 || track_num >= me->num_tracks) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return me->decode_data[track_num]->content_type_name;
|
||||
}
|
||||
|
||||
OggPlayErrorCode
|
||||
oggplay_set_track_active(OggPlay *me, int track_num) {
|
||||
|
||||
ogg_int64_t p;
|
||||
|
||||
if (me == NULL) {
|
||||
return E_OGGPLAY_BAD_OGGPLAY;
|
||||
}
|
||||
|
||||
if (me->reader == NULL) {
|
||||
return E_OGGPLAY_BAD_READER;
|
||||
}
|
||||
|
||||
if (me->all_tracks_initialised == 0) {
|
||||
return E_OGGPLAY_UNINITIALISED;
|
||||
}
|
||||
|
||||
if (track_num < 0 || track_num >= me->num_tracks) {
|
||||
return E_OGGPLAY_BAD_TRACK;
|
||||
}
|
||||
|
||||
/*
|
||||
* Skeleton tracks should not be set active - data in them should be queried
|
||||
* using alternative mechanisms (there is no concept of time-synced data
|
||||
* in a skeleton track)
|
||||
*/
|
||||
if (me->decode_data[track_num]->content_type == OGGZ_CONTENT_SKELETON) {
|
||||
return E_OGGPLAY_TRACK_IS_SKELETON;
|
||||
}
|
||||
|
||||
if (me->decode_data[track_num]->content_type == OGGZ_CONTENT_UNKNOWN) {
|
||||
return E_OGGPLAY_TRACK_IS_UNKNOWN;
|
||||
}
|
||||
|
||||
/* there was an error while decoding the headers of this track! */
|
||||
if (me->decode_data[track_num]->initialised != 1) {
|
||||
return E_OGGPLAY_TRACK_UNINITIALISED;
|
||||
}
|
||||
|
||||
if ((p = me->decode_data[track_num]->final_granulepos) != -1) {
|
||||
if (p * me->decode_data[track_num]->granuleperiod > me->target) {
|
||||
return E_OGGPLAY_TRACK_IS_OVER;
|
||||
}
|
||||
}
|
||||
|
||||
if (me->decode_data[track_num]->active == 0) {
|
||||
me->decode_data[track_num]->active = 1;
|
||||
|
||||
/*
|
||||
* CMML tracks aren't counted when deciding whether we've read enough data
|
||||
* from the stream. This is because CMML data is not continuous, and
|
||||
* determining that we've read enough data from each other stream is enough
|
||||
* to determing that we've read any CMML data that is available.
|
||||
* This also applies to Kate streams.
|
||||
*/
|
||||
if (me->decode_data[track_num]->content_type != OGGZ_CONTENT_CMML && me->decode_data[track_num]->content_type != OGGZ_CONTENT_KATE) {
|
||||
me->active_tracks ++;
|
||||
}
|
||||
}
|
||||
|
||||
return E_OGGPLAY_OK;
|
||||
|
||||
}
|
||||
|
||||
OggPlayErrorCode
|
||||
oggplay_set_track_inactive(OggPlay *me, int track_num) {
|
||||
|
||||
if (me == NULL) {
|
||||
return E_OGGPLAY_BAD_OGGPLAY;
|
||||
}
|
||||
|
||||
if (me->reader == NULL) {
|
||||
return E_OGGPLAY_BAD_READER;
|
||||
}
|
||||
|
||||
if (me->all_tracks_initialised == 0) {
|
||||
return E_OGGPLAY_UNINITIALISED;
|
||||
}
|
||||
|
||||
if (track_num < 0 || track_num >= me->num_tracks) {
|
||||
return E_OGGPLAY_BAD_TRACK;
|
||||
}
|
||||
|
||||
if (me->decode_data[track_num]->content_type == OGGZ_CONTENT_SKELETON) {
|
||||
return E_OGGPLAY_TRACK_IS_SKELETON;
|
||||
}
|
||||
|
||||
if (me->decode_data[track_num]->content_type == OGGZ_CONTENT_UNKNOWN) {
|
||||
return E_OGGPLAY_TRACK_IS_UNKNOWN;
|
||||
}
|
||||
|
||||
if (me->decode_data[track_num]->active == 1) {
|
||||
me->decode_data[track_num]->active = 0;
|
||||
|
||||
/*
|
||||
* see above comment in oggplay_set_track_active
|
||||
*/
|
||||
if (me->decode_data[track_num]->content_type != OGGZ_CONTENT_CMML && me->decode_data[track_num]->content_type != OGGZ_CONTENT_KATE) {
|
||||
me->active_tracks --;
|
||||
}
|
||||
}
|
||||
|
||||
return E_OGGPLAY_OK;
|
||||
}
|
|
@ -1,240 +0,0 @@
|
|||
/*
|
||||
Copyright (C) 2003 Commonwealth Scientific and Industrial Research
|
||||
Organisation (CSIRO) Australia
|
||||
|
||||
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.
|
||||
|
||||
- Neither the name of CSIRO Australia nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
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 ORGANISATION 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* oggplay_enums.h
|
||||
*
|
||||
* Shane Stephens <shane.stephens@annodex.net>
|
||||
*/
|
||||
|
||||
#include "oggplay_private.h"
|
||||
|
||||
OggPlayErrorCode
|
||||
oggplay_seek(OggPlay *me, ogg_int64_t milliseconds) {
|
||||
|
||||
ogg_int64_t eof;
|
||||
|
||||
if (me == NULL) {
|
||||
return E_OGGPLAY_BAD_OGGPLAY;
|
||||
}
|
||||
|
||||
if (milliseconds < 0) {
|
||||
return E_OGGPLAY_CANT_SEEK;
|
||||
}
|
||||
|
||||
eof = oggplay_get_duration(me);
|
||||
if (eof > -1 && milliseconds > eof) {
|
||||
return E_OGGPLAY_CANT_SEEK;
|
||||
}
|
||||
|
||||
if (me->reader->seek != NULL) {
|
||||
if
|
||||
(
|
||||
me->reader->seek(me->reader, me->oggz, milliseconds)
|
||||
==
|
||||
E_OGGPLAY_CANT_SEEK
|
||||
)
|
||||
{
|
||||
return E_OGGPLAY_CANT_SEEK;
|
||||
}
|
||||
} else {
|
||||
if (oggz_seek_units(me->oggz, milliseconds, SEEK_SET) == -1) {
|
||||
return E_OGGPLAY_CANT_SEEK;
|
||||
}
|
||||
}
|
||||
|
||||
return oggplay_seek_cleanup(me, milliseconds);
|
||||
}
|
||||
|
||||
OggPlayErrorCode
|
||||
oggplay_seek_cleanup(OggPlay* me, ogg_int64_t milliseconds)
|
||||
{
|
||||
|
||||
OggPlaySeekTrash * trash;
|
||||
OggPlaySeekTrash ** p;
|
||||
OggPlayDataHeader ** end_of_list_p;
|
||||
int i;
|
||||
|
||||
if (me == NULL)
|
||||
return E_OGGPLAY_BAD_OGGPLAY;
|
||||
|
||||
/*
|
||||
* first, create a trash object to store the context that we want to
|
||||
* delete but can't until the presentation thread is no longer using it -
|
||||
* this will occur as soon as the thread calls oggplay_buffer_release_next
|
||||
*/
|
||||
|
||||
trash = oggplay_calloc(1, sizeof(OggPlaySeekTrash));
|
||||
|
||||
if (trash == NULL)
|
||||
return E_OGGPLAY_OUT_OF_MEMORY;
|
||||
|
||||
/*
|
||||
* store the old buffer in it next.
|
||||
*/
|
||||
if (me->buffer != NULL) {
|
||||
|
||||
trash->old_buffer = (OggPlayBuffer *)me->buffer;
|
||||
|
||||
/*
|
||||
* replace the buffer with a new one. From here on, the presentation thread
|
||||
* will start using this buffer instead.
|
||||
*/
|
||||
me->buffer = oggplay_buffer_new_buffer(me->buffer->buffer_size);
|
||||
|
||||
if (me->buffer == NULL)
|
||||
{
|
||||
return E_OGGPLAY_OUT_OF_MEMORY;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* strip all of the data packets out of the streams and put them into the
|
||||
* trash. We can free the untimed packets immediately - they are USELESS
|
||||
* SCUM OF THE EARTH (and also unreferenced by the buffer).
|
||||
*/
|
||||
end_of_list_p = &trash->old_data;
|
||||
for (i = 0; i < me->num_tracks; i++) {
|
||||
OggPlayDecode *track = me->decode_data[i];
|
||||
if (track->data_list != NULL) {
|
||||
*(end_of_list_p) = track->data_list;
|
||||
end_of_list_p = &(track->end_of_data_list->next);
|
||||
oggplay_data_free_list(track->untimed_data_list);
|
||||
}
|
||||
track->data_list = track->end_of_data_list = NULL;
|
||||
track->untimed_data_list = NULL;
|
||||
track->current_loc = -1;
|
||||
track->last_granulepos = -1;
|
||||
track->stream_info = OGGPLAY_STREAM_JUST_SEEKED;
|
||||
}
|
||||
|
||||
/*
|
||||
* we need to notify the tiger renderer that we seeked, so that
|
||||
* now obsolete events are discarded
|
||||
*/
|
||||
#ifdef HAVE_TIGER
|
||||
for (i = 0; i < me->num_tracks; i++) {
|
||||
OggPlayDecode *track = me->decode_data[i];
|
||||
if (track && track->content_type == OGGZ_CONTENT_KATE) {
|
||||
OggPlayKateDecode *decode = (OggPlayKateDecode *)(me->decode_data[i]);
|
||||
if (decode->use_tiger) tiger_renderer_seek(decode->tr, milliseconds/1000.0);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* set the presentation time
|
||||
*/
|
||||
me->presentation_time = milliseconds;
|
||||
me->target = me->callback_period - 1;
|
||||
me->pt_update_valid = 1;
|
||||
|
||||
trash->next = NULL;
|
||||
|
||||
p = &(me->trash);
|
||||
while (*p != NULL) {
|
||||
p = &((*p)->next);
|
||||
}
|
||||
|
||||
*p = trash;
|
||||
|
||||
if (milliseconds == 0) {
|
||||
for (i = 0; i < me->num_tracks; i++) {
|
||||
OggPlayDecode *track = me->decode_data[i];
|
||||
FishSound *sound_handle;
|
||||
OggPlayAudioDecode *audio_decode;
|
||||
if (track->content_type != OGGZ_CONTENT_VORBIS) {
|
||||
continue;
|
||||
}
|
||||
audio_decode = (OggPlayAudioDecode*)track;
|
||||
sound_handle = audio_decode->sound_handle;
|
||||
fish_sound_reset(sound_handle);
|
||||
}
|
||||
}
|
||||
|
||||
return E_OGGPLAY_OK;
|
||||
}
|
||||
|
||||
void
|
||||
oggplay_take_out_trash(OggPlay *me, OggPlaySeekTrash *trash) {
|
||||
|
||||
OggPlaySeekTrash *p = NULL;
|
||||
|
||||
for (; trash != NULL; trash = trash->next) {
|
||||
|
||||
oggplay_buffer_shutdown(me, trash->old_buffer);
|
||||
oggplay_data_free_list(trash->old_data);
|
||||
if (p != NULL) {
|
||||
oggplay_free(p);
|
||||
}
|
||||
p = trash;
|
||||
}
|
||||
|
||||
if (p != NULL) {
|
||||
oggplay_free(p);
|
||||
}
|
||||
}
|
||||
|
||||
OggPlayErrorCode
|
||||
oggplay_seek_to_keyframe(OggPlay *me,
|
||||
ogg_int64_t milliseconds,
|
||||
ogg_int64_t offset_begin,
|
||||
ogg_int64_t offset_end)
|
||||
{
|
||||
ogg_int64_t eof, time;
|
||||
|
||||
if (me == NULL) {
|
||||
return E_OGGPLAY_BAD_OGGPLAY;
|
||||
}
|
||||
|
||||
if (milliseconds < 0)
|
||||
return E_OGGPLAY_CANT_SEEK;
|
||||
|
||||
eof = oggplay_get_duration(me);
|
||||
if (eof > -1 && milliseconds > eof) {
|
||||
return E_OGGPLAY_CANT_SEEK;
|
||||
}
|
||||
|
||||
|
||||
time = oggz_keyframe_seek_set(me->oggz,
|
||||
milliseconds,
|
||||
offset_begin,
|
||||
offset_end);
|
||||
|
||||
if (time == -1) {
|
||||
return E_OGGPLAY_CANT_SEEK;
|
||||
}
|
||||
|
||||
oggplay_seek_cleanup(me, time);
|
||||
|
||||
return E_OGGPLAY_OK;
|
||||
|
||||
}
|
|
@ -1,773 +0,0 @@
|
|||
/*
|
||||
Copyright (C) 2003 Commonwealth Scientific and Industrial Research
|
||||
Organisation (CSIRO) Australia
|
||||
|
||||
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.
|
||||
|
||||
- Neither the name of CSIRO Australia nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
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 ORGANISATION 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* oggplay_tcp_reader.c
|
||||
*
|
||||
* Shane Stephens <shane.stephens@annodex.net>
|
||||
* Michael Martin
|
||||
*/
|
||||
|
||||
#include "oggplay_private.h"
|
||||
#include "oggplay_tcp_reader.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef WIN32
|
||||
#include <process.h>
|
||||
#include <io.h>
|
||||
|
||||
#else
|
||||
#include <sys/types.h>
|
||||
#include <sys/select.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/fcntl.h>
|
||||
#include <sys/errno.h>
|
||||
#include <sys/time.h>
|
||||
#include <time.h>
|
||||
#include <netdb.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#if HAVE_ASSERT
|
||||
#include <assert.h>
|
||||
#else
|
||||
#define assert(x)
|
||||
#endif
|
||||
|
||||
#define PRINT_BUFFER(s,m) \
|
||||
printf("%s: in_mem: %d size: %d pos: %d stored: %d\n", \
|
||||
s, m->amount_in_memory, m->buffer_size, \
|
||||
m->current_position, m->stored_offset);
|
||||
|
||||
#ifndef WIN32
|
||||
typedef int SOCKET;
|
||||
#define INVALID_SOCKET -1
|
||||
#endif
|
||||
|
||||
#define START_TIMEOUT(ref) \
|
||||
(ref) = oggplay_sys_time_in_ms()
|
||||
|
||||
#ifdef WIN32
|
||||
#define CHECK_ERROR(error) \
|
||||
(WSAGetLastError() == WSA##error)
|
||||
#else
|
||||
#define CHECK_ERROR(error) \
|
||||
(errno == error)
|
||||
#endif
|
||||
|
||||
#define RETURN_ON_TIMEOUT_OR_CONTINUE(ref) \
|
||||
if (oggplay_sys_time_in_ms() - (ref) > 500) { \
|
||||
return E_OGGPLAY_TIMEOUT; \
|
||||
} else { \
|
||||
oggplay_millisleep(10); \
|
||||
continue; \
|
||||
}
|
||||
|
||||
#ifdef WIN32
|
||||
int
|
||||
oggplay_set_socket_blocking_state(SOCKET socket, int is_blocking) {
|
||||
u_long io_mode = !is_blocking;
|
||||
if (ioctlsocket(socket, FIONBIO, &io_mode) == SOCKET_ERROR) {
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
#else
|
||||
int
|
||||
oggplay_set_socket_blocking_state(SOCKET socket, int is_blocking) {
|
||||
if (fcntl(socket, F_SETFL, is_blocking ? 0 : O_NONBLOCK) == -1) {
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
SOCKET
|
||||
oggplay_create_socket() {
|
||||
SOCKET sock;
|
||||
|
||||
#ifdef WIN32
|
||||
WORD wVersionRequested;
|
||||
WSADATA wsaData;
|
||||
#ifdef HAVE_WINSOCK2
|
||||
wVersionRequested = MAKEWORD(2,2);
|
||||
#else
|
||||
wVersionRequested = MAKEWORD(1,1);
|
||||
#endif
|
||||
if (WSAStartup(wVersionRequested, &wsaData) == -1) {
|
||||
printf("Socket open error\n");
|
||||
return INVALID_SOCKET;
|
||||
}
|
||||
if (wsaData.wVersion != wVersionRequested) {
|
||||
printf("Incorrect winsock version [%d]\n", wVersionRequested);
|
||||
WSACleanup();
|
||||
return INVALID_SOCKET;
|
||||
}
|
||||
#endif
|
||||
|
||||
sock = socket(PF_INET, SOCK_STREAM, 0);
|
||||
if (sock == INVALID_SOCKET) {
|
||||
printf("Could not create socket\n");
|
||||
#ifdef WIN32
|
||||
WSACleanup();
|
||||
#endif
|
||||
return INVALID_SOCKET;
|
||||
}
|
||||
|
||||
return sock;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function guarantees it will return malloced versions of host and
|
||||
* path
|
||||
*
|
||||
* @param location Location of the Ogg content
|
||||
* @param proxy The proxy if there's any.
|
||||
* @param proxy_port The port of the proxy if there's any.
|
||||
* @param host The host to connect to; using proxy if set.
|
||||
* @param port The port to connect to;
|
||||
* @param path The path where the content resides on the server.
|
||||
* @retval -1 in case of error, 0 otherwise.
|
||||
*/
|
||||
int
|
||||
oggplay_hostname_and_path(const char *location, const char *proxy, int proxy_port,
|
||||
char **host, int *port, char **path) {
|
||||
|
||||
|
||||
char * colon;
|
||||
char * slash;
|
||||
char * end_of_host;
|
||||
|
||||
/* if we have a proxy installed this is all dead simple */
|
||||
if (proxy != NULL) {
|
||||
if ((*host = strdup(proxy)) == NULL)
|
||||
goto error;
|
||||
|
||||
*port = proxy_port;
|
||||
|
||||
if ((*path = strdup(location)) == NULL)
|
||||
goto error;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* find start_pos */
|
||||
if (strncmp(location, "http://", 7) == 0) {
|
||||
location += 7;
|
||||
}
|
||||
|
||||
colon = strchr(location, ':');
|
||||
slash = strchr(location, '/');
|
||||
|
||||
/*
|
||||
* if both are null, then just set the simple defaults and return
|
||||
*/
|
||||
if (colon == NULL && slash == NULL) {
|
||||
if ((*host = strdup(location)) == NULL)
|
||||
goto error;
|
||||
|
||||
*port = 80;
|
||||
|
||||
if ((*path = strdup("/")) == NULL)
|
||||
goto error;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* if there's a slash and it's before colon, there's no port. Hence, after
|
||||
* this code, the only time that there's a port is when colon is non-NULL
|
||||
*/
|
||||
if (slash != NULL && colon > slash) {
|
||||
colon = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* we might as well extract the port now. We can also work out where
|
||||
* the end of the hostname is, as it's either the colon (if there's a port)
|
||||
* or the slash (if there's no port)
|
||||
*/
|
||||
if (colon != NULL) {
|
||||
*port = (int)strtol(colon+1, NULL, 10);
|
||||
end_of_host = colon;
|
||||
} else {
|
||||
*port = 80;
|
||||
end_of_host = slash;
|
||||
}
|
||||
|
||||
if ((*host = strdup(location)) == NULL)
|
||||
goto error;
|
||||
|
||||
(*host)[end_of_host - location] = '\0';
|
||||
|
||||
if (slash == NULL) {
|
||||
if ((*path = strdup("/")) == NULL)
|
||||
goto error;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((*path = strdup(slash)) == NULL)
|
||||
goto error;
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
/* there has been an error while copying strings... */
|
||||
if (*host != NULL)
|
||||
oggplay_free(*host);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
OggPlayErrorCode
|
||||
oggplay_connect_to_host(SOCKET socket, struct sockaddr *addr) {
|
||||
|
||||
ogg_int64_t time_ref;
|
||||
|
||||
START_TIMEOUT(time_ref);
|
||||
|
||||
while (connect(socket, addr, sizeof(struct sockaddr_in)) < 0) {
|
||||
if (
|
||||
CHECK_ERROR(EINPROGRESS) || CHECK_ERROR(EALREADY)
|
||||
#ifdef WIN32
|
||||
/* see http://msdn2.microsoft.com/en-us/library/ms737625.aspx */
|
||||
|| CHECK_ERROR(EWOULDBLOCK) || CHECK_ERROR(EINVAL)
|
||||
#endif
|
||||
) {
|
||||
RETURN_ON_TIMEOUT_OR_CONTINUE(time_ref);
|
||||
}
|
||||
else if CHECK_ERROR(EISCONN)
|
||||
{
|
||||
break;
|
||||
}
|
||||
printf("Could not connect to host; error code is %d\n", errno);
|
||||
return CHECK_ERROR(ETIMEDOUT) ? E_OGGPLAY_TIMEOUT :
|
||||
E_OGGPLAY_SOCKET_ERROR;
|
||||
}
|
||||
|
||||
return E_OGGPLAY_OK;
|
||||
|
||||
}
|
||||
|
||||
|
||||
OggPlayErrorCode
|
||||
oggplay_tcp_reader_initialise(OggPlayReader * opr, int block) {
|
||||
|
||||
OggPlayTCPReader * me = (OggPlayTCPReader *)opr;
|
||||
struct hostent * he;
|
||||
struct sockaddr_in addr;
|
||||
char * host;
|
||||
char * path;
|
||||
int port;
|
||||
int nbytes;
|
||||
int remaining;
|
||||
char http_request_header[1024];
|
||||
ogg_int64_t time_ref;
|
||||
int r;
|
||||
|
||||
char * pos;
|
||||
size_t len;
|
||||
|
||||
if (me == NULL) {
|
||||
return E_OGGPLAY_BAD_READER;
|
||||
}
|
||||
if (me->state == OTRS_INIT_COMPLETE) {
|
||||
return E_OGGPLAY_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* Create the socket.
|
||||
*/
|
||||
if (me->state == OTRS_UNINITIALISED) {
|
||||
assert(me->socket == INVALID_SOCKET);
|
||||
|
||||
me->socket = oggplay_create_socket();
|
||||
if (me->socket == INVALID_SOCKET) {
|
||||
return E_OGGPLAY_SOCKET_ERROR;
|
||||
}
|
||||
|
||||
me->state = OTRS_SOCKET_CREATED;
|
||||
}
|
||||
|
||||
/*
|
||||
* If required, set the socket to non-blocking mode so we can
|
||||
* timeout and return control to the caller.
|
||||
*/
|
||||
if (!block) {
|
||||
if (!oggplay_set_socket_blocking_state(me->socket, 0)) {
|
||||
return E_OGGPLAY_SOCKET_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Extract the host name and the path from the location.
|
||||
*/
|
||||
if (oggplay_hostname_and_path(me->location, me->proxy, me->proxy_port,
|
||||
&host, &port, &path) != 0)
|
||||
return E_OGGPLAY_OUT_OF_MEMORY;
|
||||
|
||||
|
||||
/*
|
||||
* Prepare the HTTP request header now, so we can free all our
|
||||
* allocated memory before returning on any errors.
|
||||
*/
|
||||
snprintf(http_request_header, 1024,
|
||||
"GET %s HTTP/1.0\n"
|
||||
"Host: %s\n"
|
||||
"User-Agent: AnnodexFirefoxPlugin/0.1\n"
|
||||
"Accept: */*\n"
|
||||
"Connection: Keep-Alive\n\n", path, host);
|
||||
|
||||
he = gethostbyname(host);
|
||||
|
||||
oggplay_free(host);
|
||||
oggplay_free(path);
|
||||
|
||||
if (he == NULL) {
|
||||
printf("Host not found\n");
|
||||
return E_OGGPLAY_BAD_INPUT;
|
||||
}
|
||||
/*
|
||||
* currently we only support IPv4
|
||||
* TODO: switch to getaddrinfo and support IPv6!
|
||||
*/
|
||||
if (sizeof(addr.sin_addr.s_addr) != he->h_length) {
|
||||
printf("No IPv6 support, yet!\n");
|
||||
return E_OGGPLAY_BAD_INPUT;
|
||||
}
|
||||
|
||||
memcpy(&addr.sin_addr.s_addr, he->h_addr, he->h_length);
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_port = htons(port);
|
||||
|
||||
/*
|
||||
* Connect to the host.
|
||||
*/
|
||||
if (me->state == OTRS_SOCKET_CREATED) {
|
||||
r = oggplay_connect_to_host(me->socket, (struct sockaddr *)&addr);
|
||||
if (r != E_OGGPLAY_OK) {
|
||||
return r;
|
||||
}
|
||||
|
||||
me->state = OTRS_CONNECTED;
|
||||
}
|
||||
|
||||
/*
|
||||
* Send the HTTP request header.
|
||||
*
|
||||
* If this times out after sending some, but not all, of the request header,
|
||||
* we'll end up sending the entire header string again. This is probably not
|
||||
* the best idea, so we may want to rework it at some time...
|
||||
*/
|
||||
if (me->state == OTRS_CONNECTED) {
|
||||
oggplay_set_socket_blocking_state(me->socket, 1);
|
||||
pos = http_request_header;
|
||||
len = strlen(http_request_header);
|
||||
#ifdef WIN32
|
||||
nbytes = send(me->socket, pos, len, 0);
|
||||
#else
|
||||
nbytes = write(me->socket, pos, len);
|
||||
#endif
|
||||
assert(nbytes == len);
|
||||
if (nbytes < 0) {
|
||||
return E_OGGPLAY_SOCKET_ERROR;
|
||||
}
|
||||
me->state = OTRS_SENT_HEADER;
|
||||
}
|
||||
|
||||
/*
|
||||
* Strip out the HTTP response by finding the first Ogg packet.
|
||||
*/
|
||||
if (me->state == OTRS_SENT_HEADER) {
|
||||
int offset;
|
||||
int found_http_response = 0;
|
||||
|
||||
if (me->buffer == NULL) {
|
||||
me->buffer = (unsigned char*)oggplay_malloc(TCP_READER_MAX_IN_MEMORY);
|
||||
if (me->buffer == NULL)
|
||||
return E_OGGPLAY_OUT_OF_MEMORY;
|
||||
|
||||
me->buffer_size = TCP_READER_MAX_IN_MEMORY;
|
||||
me->amount_in_memory = 0;
|
||||
}
|
||||
|
||||
while (1) {
|
||||
char *dpos;
|
||||
|
||||
remaining = TCP_READER_MAX_IN_MEMORY - me->amount_in_memory - 1;
|
||||
#ifdef WIN32
|
||||
nbytes = recv(me->socket, (char*)(me->buffer + me->amount_in_memory),
|
||||
remaining, 0);
|
||||
#else
|
||||
nbytes = read(me->socket, (char*)(me->buffer + me->amount_in_memory),
|
||||
remaining);
|
||||
#endif
|
||||
if (nbytes < 0) {
|
||||
return E_OGGPLAY_SOCKET_ERROR;
|
||||
} else if (nbytes == 0) {
|
||||
/*
|
||||
* End-of-file is an error here, because we should at least be able
|
||||
* to read a complete HTTP response header.
|
||||
*/
|
||||
return E_OGGPLAY_END_OF_FILE;
|
||||
}
|
||||
|
||||
me->amount_in_memory += nbytes;
|
||||
me->buffer[me->amount_in_memory] = '\0';
|
||||
|
||||
if (me->amount_in_memory < 15) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if
|
||||
(
|
||||
(!found_http_response)
|
||||
&&
|
||||
strncmp((char *)me->buffer, "HTTP/1.1 200 ", 13) != 0
|
||||
&&
|
||||
strncmp((char *)me->buffer, "HTTP/1.0 200 ", 13) != 0
|
||||
)
|
||||
{
|
||||
return E_OGGPLAY_BAD_INPUT;
|
||||
} else {
|
||||
found_http_response = 1;
|
||||
}
|
||||
|
||||
dpos = strstr((char *)me->buffer, "X-Content-Duration:");
|
||||
if (dpos != NULL) {
|
||||
me->duration = (int)(strtod(dpos + 20, NULL) * 1000);
|
||||
}
|
||||
|
||||
pos = strstr((char *)(me->buffer), "OggS");
|
||||
if (pos != NULL) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
offset = pos - (char *)(me->buffer);
|
||||
memmove(me->buffer, pos, me->amount_in_memory - offset);
|
||||
me->amount_in_memory -= offset;
|
||||
me->backing_store = tmpfile();
|
||||
fwrite(me->buffer, 1, me->amount_in_memory, me->backing_store);
|
||||
me->current_position = 0;
|
||||
me->stored_offset = me->amount_in_memory;
|
||||
me->amount_in_memory = 0;
|
||||
me->state = OTRS_HTTP_RESPONDED;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Read in enough data to fill the buffer.
|
||||
*/
|
||||
if (!block) {
|
||||
oggplay_set_socket_blocking_state(me->socket, 0);
|
||||
}
|
||||
|
||||
if (me->state == OTRS_HTTP_RESPONDED) {
|
||||
remaining = TCP_READER_MAX_IN_MEMORY - me->amount_in_memory;
|
||||
START_TIMEOUT(time_ref);
|
||||
while (remaining > 0) {
|
||||
#ifdef WIN32
|
||||
nbytes = recv(me->socket, (char*)(me->buffer + me->amount_in_memory),
|
||||
remaining, 0);
|
||||
#else
|
||||
nbytes = read(me->socket, me->buffer + me->amount_in_memory, remaining);
|
||||
#endif
|
||||
if (nbytes < 0) {
|
||||
#ifdef WIN32
|
||||
if CHECK_ERROR(EWOULDBLOCK) {
|
||||
#else
|
||||
if CHECK_ERROR(EAGAIN) {
|
||||
#endif
|
||||
RETURN_ON_TIMEOUT_OR_CONTINUE(time_ref);
|
||||
}
|
||||
return E_OGGPLAY_SOCKET_ERROR;
|
||||
} else if (nbytes == 0) {
|
||||
/*
|
||||
* End-of-file is *not* an error here, it's just a really small file.
|
||||
*/
|
||||
break;
|
||||
}
|
||||
me->amount_in_memory += nbytes;
|
||||
remaining -= nbytes;
|
||||
}
|
||||
fwrite(me->buffer, 1, me->amount_in_memory, me->backing_store);
|
||||
me->stored_offset += me->amount_in_memory;
|
||||
me->amount_in_memory = 0;
|
||||
me->state = OTRS_INIT_COMPLETE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the socket back to blocking mode.
|
||||
*/
|
||||
if (!oggplay_set_socket_blocking_state(me->socket, 1)) {
|
||||
return E_OGGPLAY_SOCKET_ERROR;
|
||||
}
|
||||
|
||||
return E_OGGPLAY_OK;
|
||||
}
|
||||
|
||||
|
||||
OggPlayErrorCode
|
||||
oggplay_tcp_reader_destroy(OggPlayReader * opr) {
|
||||
|
||||
OggPlayTCPReader * me = (OggPlayTCPReader *)opr;
|
||||
|
||||
if (me == NULL) {
|
||||
return E_OGGPLAY_BAD_READER;
|
||||
}
|
||||
|
||||
if (me->socket != INVALID_SOCKET) {
|
||||
#ifdef WIN32
|
||||
#ifdef HAVE_WINSOCK2
|
||||
shutdown(me->socket, SD_BOTH);
|
||||
#endif
|
||||
closesocket(me->socket);
|
||||
WSACleanup();
|
||||
#else
|
||||
close(me->socket);
|
||||
#endif
|
||||
}
|
||||
|
||||
if (me->buffer != NULL) oggplay_free(me->buffer);
|
||||
if (me->location != NULL) oggplay_free(me->location);
|
||||
if (me->backing_store != NULL) {
|
||||
fclose(me->backing_store);
|
||||
}
|
||||
oggplay_free(me);
|
||||
return E_OGGPLAY_OK;
|
||||
}
|
||||
|
||||
OggPlayErrorCode
|
||||
grab_some_data(OggPlayTCPReader *me, int block) {
|
||||
|
||||
int remaining;
|
||||
int r;
|
||||
|
||||
if (me == NULL) {
|
||||
return E_OGGPLAY_BAD_READER;
|
||||
}
|
||||
|
||||
if (me->socket == INVALID_SOCKET) return E_OGGPLAY_OK;
|
||||
|
||||
/*
|
||||
* see if we can grab some more data
|
||||
* if we're not blocking, make sure there's some available data
|
||||
*/
|
||||
if (!block) {
|
||||
struct timeval tv;
|
||||
fd_set reads;
|
||||
fd_set empty;
|
||||
|
||||
tv.tv_sec = 0;
|
||||
tv.tv_usec = 0;
|
||||
FD_ZERO(&reads);
|
||||
FD_ZERO(&empty);
|
||||
FD_SET(me->socket, &reads);
|
||||
if (select(me->socket + 1, &reads, &empty, &empty, &tv) == 0) {
|
||||
return E_OGGPLAY_OK;
|
||||
}
|
||||
}
|
||||
|
||||
remaining = me->buffer_size;
|
||||
#ifdef WIN32
|
||||
r = recv(me->socket, (char*)(me->buffer + me->amount_in_memory),
|
||||
remaining, 0);
|
||||
#else
|
||||
r = read(me->socket, me->buffer + me->amount_in_memory, remaining);
|
||||
#endif
|
||||
|
||||
if (!block && r <= 0) {
|
||||
#ifdef WIN32
|
||||
#ifdef HAVE_WINSOCK2
|
||||
shutdown(me->socket, SD_BOTH);
|
||||
#endif
|
||||
closesocket(me->socket);
|
||||
WSACleanup();
|
||||
#else
|
||||
close(me->socket);
|
||||
#endif
|
||||
me->socket = INVALID_SOCKET;
|
||||
}
|
||||
|
||||
fwrite(me->buffer, 1, r, me->backing_store);
|
||||
me->stored_offset += r;
|
||||
|
||||
return E_OGGPLAY_OK;
|
||||
}
|
||||
|
||||
#define MIN(a,b) ((a)<(b)?(a):(b))
|
||||
|
||||
int
|
||||
oggplay_tcp_reader_available(OggPlayReader * opr, ogg_int64_t current_bytes,
|
||||
ogg_int64_t current_time) {
|
||||
|
||||
OggPlayTCPReader * me;
|
||||
ogg_int64_t tpb = (current_time << 16) / current_bytes;
|
||||
|
||||
me = (OggPlayTCPReader *)opr;
|
||||
|
||||
if (me == NULL) {
|
||||
return E_OGGPLAY_BAD_READER;
|
||||
}
|
||||
|
||||
if (me->socket == INVALID_SOCKET) {
|
||||
return me->duration;
|
||||
}
|
||||
|
||||
grab_some_data(me, 0);
|
||||
if (me->duration > -1 && ((tpb * me->stored_offset) >> 16) > me->duration)
|
||||
{
|
||||
return me->duration;
|
||||
}
|
||||
return (int)((tpb * me->stored_offset) >> 16);
|
||||
|
||||
}
|
||||
|
||||
ogg_int64_t
|
||||
oggplay_tcp_reader_duration(OggPlayReader * opr) {
|
||||
OggPlayTCPReader *me = (OggPlayTCPReader *)opr;
|
||||
|
||||
if (me == NULL) {
|
||||
return E_OGGPLAY_BAD_READER;
|
||||
}
|
||||
|
||||
return me->duration;
|
||||
}
|
||||
|
||||
static size_t
|
||||
oggplay_tcp_reader_io_read(void * user_handle, void * buf, size_t n) {
|
||||
|
||||
OggPlayTCPReader * me = (OggPlayTCPReader *)user_handle;
|
||||
int len;
|
||||
|
||||
if (me == NULL) {
|
||||
return E_OGGPLAY_BAD_READER;
|
||||
}
|
||||
|
||||
grab_some_data(me, 0);
|
||||
|
||||
fseek(me->backing_store, me->current_position, SEEK_SET);
|
||||
len = fread(buf, 1, n, me->backing_store);
|
||||
if (len == 0) {
|
||||
fseek(me->backing_store, 0, SEEK_END);
|
||||
grab_some_data(me, 1);
|
||||
fseek(me->backing_store, me->current_position, SEEK_SET);
|
||||
len = fread(buf, 1, n, me->backing_store);
|
||||
}
|
||||
me->current_position += len;
|
||||
fseek(me->backing_store, 0, SEEK_END);
|
||||
return len;
|
||||
}
|
||||
|
||||
int
|
||||
oggplay_tcp_reader_finished_retrieving(OggPlayReader *opr) {
|
||||
OggPlayTCPReader *me = (OggPlayTCPReader *)opr;
|
||||
return (me->socket == INVALID_SOCKET);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
oggplay_tcp_reader_io_seek(void * user_handle, long offset, int whence) {
|
||||
|
||||
OggPlayTCPReader * me = (OggPlayTCPReader *)user_handle;
|
||||
int r;
|
||||
|
||||
if (me == NULL) {
|
||||
return E_OGGPLAY_BAD_READER;
|
||||
}
|
||||
|
||||
fseek(me->backing_store, me->current_position, SEEK_SET);
|
||||
r = fseek(me->backing_store, offset, whence);
|
||||
me->current_position = ftell(me->backing_store);
|
||||
fseek(me->backing_store, 0, SEEK_END);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static long
|
||||
oggplay_tcp_reader_io_tell(void * user_handle) {
|
||||
|
||||
OggPlayTCPReader * me = (OggPlayTCPReader *)user_handle;
|
||||
|
||||
if (me == NULL) {
|
||||
return E_OGGPLAY_BAD_READER;
|
||||
}
|
||||
|
||||
return me->current_position;
|
||||
|
||||
}
|
||||
|
||||
OggPlayReader *
|
||||
oggplay_tcp_reader_new(const char *location, const char *proxy, int proxy_port) {
|
||||
|
||||
OggPlayTCPReader * me = (OggPlayTCPReader *)oggplay_malloc (sizeof (OggPlayTCPReader));
|
||||
|
||||
if (me == NULL)
|
||||
return NULL;
|
||||
|
||||
me->state = OTRS_UNINITIALISED;
|
||||
me->socket = INVALID_SOCKET;
|
||||
me->buffer = NULL;
|
||||
me->buffer_size = 0;
|
||||
me->current_position = 0;
|
||||
/* if there's not enough memory to copy the URI cancel the initialisation */
|
||||
if ( (me->location = strdup(location)) == NULL)
|
||||
{
|
||||
oggplay_tcp_reader_destroy ((OggPlayReader*)me);
|
||||
return NULL;
|
||||
}
|
||||
me->amount_in_memory = 0;
|
||||
me->backing_store = NULL;
|
||||
me->stored_offset = 0;
|
||||
|
||||
me->proxy = proxy;
|
||||
me->proxy_port = proxy_port;
|
||||
|
||||
me->functions.initialise = &oggplay_tcp_reader_initialise;
|
||||
me->functions.destroy = &oggplay_tcp_reader_destroy;
|
||||
me->functions.seek = NULL;
|
||||
me->functions.available = &oggplay_tcp_reader_available;
|
||||
me->functions.duration = &oggplay_tcp_reader_duration;
|
||||
me->functions.finished_retrieving = &oggplay_tcp_reader_finished_retrieving;
|
||||
me->functions.io_read = &oggplay_tcp_reader_io_read;
|
||||
me->functions.io_seek = &oggplay_tcp_reader_io_seek;
|
||||
me->functions.io_tell = &oggplay_tcp_reader_io_tell;
|
||||
|
||||
return (OggPlayReader *)me;
|
||||
}
|
||||
|
||||
|
|
@ -1,86 +0,0 @@
|
|||
/*
|
||||
Copyright (C) 2003 Commonwealth Scientific and Industrial Research
|
||||
Organisation (CSIRO) Australia
|
||||
|
||||
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.
|
||||
|
||||
- Neither the name of CSIRO Australia nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
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 ORGANISATION 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* oggplay_tcp_reader.h
|
||||
*
|
||||
* Shane Stephens <shane.stephens@annodex.net>
|
||||
* Michael Martin
|
||||
*/
|
||||
|
||||
#ifndef __OGGPLAY_FILE_READER_H__
|
||||
#define __OGGPLAY_FILE_READER_H__
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
/* we'll fill to the MAX_IN_MEMORY line, then write out to the
|
||||
* WRITE_THRESHOLD line
|
||||
*/
|
||||
#define TCP_READER_MAX_IN_MEMORY 128*1024
|
||||
#define TCP_READER_WRITE_THRESHOLD 64*1024
|
||||
|
||||
typedef enum {
|
||||
TCP_READER_FROM_MEMORY,
|
||||
TCP_READER_FROM_FILE
|
||||
} dataLocation;
|
||||
|
||||
typedef enum {
|
||||
OTRS_UNINITIALISED,
|
||||
OTRS_SOCKET_CREATED,
|
||||
OTRS_CONNECTED,
|
||||
OTRS_SENT_HEADER,
|
||||
OTRS_HTTP_RESPONDED,
|
||||
OTRS_INIT_COMPLETE
|
||||
} OPTCPReaderState;
|
||||
|
||||
typedef struct {
|
||||
OggPlayReader functions;
|
||||
OPTCPReaderState state;
|
||||
#ifdef _WIN32
|
||||
SOCKET socket;
|
||||
#else
|
||||
int socket;
|
||||
#endif
|
||||
unsigned char * buffer;
|
||||
int buffer_size;
|
||||
int current_position;
|
||||
char * location;
|
||||
const char * proxy;
|
||||
int proxy_port;
|
||||
int amount_in_memory;
|
||||
FILE * backing_store;
|
||||
int stored_offset;
|
||||
dataLocation mode;
|
||||
int duration;
|
||||
} OggPlayTCPReader;
|
||||
|
||||
#endif
|
|
@ -1,69 +0,0 @@
|
|||
/*
|
||||
Copyright (C) 2003 Commonwealth Scientific and Industrial Research
|
||||
Organisation (CSIRO) Australia
|
||||
|
||||
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.
|
||||
|
||||
- Neither the name of CSIRO Australia nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
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 ORGANISATION 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* oggplay_tools.c
|
||||
*
|
||||
* Shane Stephens <shane.stephens@annodex.net>
|
||||
* Michael Martin
|
||||
*/
|
||||
|
||||
|
||||
#include "oggplay_private.h"
|
||||
#include <string.h>
|
||||
|
||||
ogg_int64_t
|
||||
oggplay_sys_time_in_ms(void) {
|
||||
#ifdef WIN32
|
||||
FILETIME ft;
|
||||
GetSystemTimeAsFileTime(&ft);
|
||||
return ((ogg_int64_t)ft.dwHighDateTime << 32 | ft.dwLowDateTime) / 10000;
|
||||
#else
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv, NULL);
|
||||
return (ogg_int64_t)tv.tv_sec * 1000 + (ogg_int64_t)tv.tv_usec / 1000;
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
oggplay_millisleep(long ms) {
|
||||
#ifdef WIN32
|
||||
Sleep(ms);
|
||||
#elif defined(OS2)
|
||||
DosSleep(ms);
|
||||
#else
|
||||
struct timespec ts = {0, (ogg_int64_t)ms * 1000000LL};
|
||||
nanosleep(&ts, NULL);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
@ -1,360 +0,0 @@
|
|||
/*
|
||||
Copyright (C) 2003 Commonwealth Scientific and Industrial Research
|
||||
Organisation (CSIRO) Australia
|
||||
|
||||
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.
|
||||
|
||||
- Neither the name of CSIRO Australia nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
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 ORGANISATION 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* yuv2rgb.c
|
||||
*
|
||||
* YUV->RGB function, using platform-specific optimisations where possible.
|
||||
*
|
||||
* Shane Stephens <shane.stephens@annodex.net>
|
||||
* Michael Martin
|
||||
* Marcin Lubonski
|
||||
* Viktor Gal
|
||||
* Makoto Kato <m_kato@ga2.so-net.ne.jp>
|
||||
*/
|
||||
|
||||
#include "oggplay_private.h"
|
||||
#include "oggplay_yuv2rgb_template.h"
|
||||
|
||||
#ifdef __SUNPRO_C
|
||||
#define DISABLE_CPU_FEATURES
|
||||
/* gcc inline asm and intristics have problems with Sun Studio.
|
||||
* We need to fix it.
|
||||
*/
|
||||
#else
|
||||
/* cpu extension detection */
|
||||
#include "cpu.c"
|
||||
#endif
|
||||
|
||||
/**
|
||||
* yuv_convert_fptr type is a function pointer type for
|
||||
* the various yuv-rgb converters
|
||||
*/
|
||||
typedef void (*yuv_convert_fptr) (const OggPlayYUVChannels *yuv,
|
||||
OggPlayRGBChannels *rgb);
|
||||
|
||||
/* it is useless to determine each YUV conversion run
|
||||
* the cpu type/featurs, thus we save the conversion function
|
||||
* pointers
|
||||
*/
|
||||
static struct OggPlayYUVConverters {
|
||||
yuv_convert_fptr yuv420rgba; /**< YUV420 to RGBA */
|
||||
yuv_convert_fptr yuv420bgra; /**< YUV420 to BGRA */
|
||||
yuv_convert_fptr yuv420argb; /**< YUV420 to ARGB */
|
||||
yuv_convert_fptr yuv422rgba; /**< YUV422 to RGBA */
|
||||
yuv_convert_fptr yuv422bgra; /**< YUV422 to BGRA */
|
||||
yuv_convert_fptr yuv422argb; /**< YUV422 to ARGB */
|
||||
yuv_convert_fptr yuv444rgba; /**< YUV444 to RGBA */
|
||||
yuv_convert_fptr yuv444bgra; /**< YUV444 to BGRA */
|
||||
yuv_convert_fptr yuv444argb; /**< YUV444 to ARGB */
|
||||
} yuv_conv = {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL};
|
||||
|
||||
/**
|
||||
* vanilla implementation of YUV-to-RGB conversion.
|
||||
*
|
||||
* - using table-lookups instead of multiplication
|
||||
* - avoid CLAMPing by incorporating
|
||||
*
|
||||
*/
|
||||
|
||||
#define prec 15
|
||||
static const int CoY = (int)(1.164 * (1 << prec) + 0.5);
|
||||
static const int CoRV = (int)(1.596 * (1 << prec) + 0.5);
|
||||
static const int CoGU = (int)(0.391 * (1 << prec) + 0.5);
|
||||
static const int CoGV = (int)(0.813 * (1 << prec) + 0.5);
|
||||
static const int CoBU = (int)(2.018 * (1 << prec) + 0.5);
|
||||
|
||||
static int CoefsGU[256] = {0};
|
||||
static int CoefsGV[256];
|
||||
static int CoefsBU[256];
|
||||
static int CoefsRV[256];
|
||||
static int CoefsY[256];
|
||||
|
||||
#define CLAMP(v) ((v) > 255 ? 255 : (v) < 0 ? 0 : (v))
|
||||
|
||||
#define VANILLA_YUV2RGB_PIXEL(y, ruv, guv, buv) \
|
||||
r = (CoefsY[y] + ruv) >> prec; \
|
||||
g = (CoefsY[y] + guv) >> prec; \
|
||||
b = (CoefsY[y] + buv) >> prec; \
|
||||
|
||||
#define VANILLA_RGBA_OUT(out, r, g, b) \
|
||||
out[0] = CLAMP(r); \
|
||||
out[1] = CLAMP(g); \
|
||||
out[2] = CLAMP(b); \
|
||||
out[3] = 255;
|
||||
|
||||
#define VANILLA_BGRA_OUT(out, r, g, b) \
|
||||
out[0] = CLAMP(b); \
|
||||
out[1] = CLAMP(g); \
|
||||
out[2] = CLAMP(r); \
|
||||
out[3] = 255;
|
||||
|
||||
#define VANILLA_ARGB_OUT(out, r, g, b) \
|
||||
out[0] = 255; \
|
||||
out[1] = CLAMP(r); \
|
||||
out[2] = CLAMP(g); \
|
||||
out[3] = CLAMP(b);
|
||||
|
||||
#define VANILLA_ABGR_OUT(out, r, g, b) \
|
||||
out[0] = 255; \
|
||||
out[1] = CLAMP(b); \
|
||||
out[2] = CLAMP(g); \
|
||||
out[3] = CLAMP(r);
|
||||
|
||||
#define LOOKUP_COEFFS int ruv = CoefsRV[*pv]; \
|
||||
int guv = CoefsGU[*pu] + CoefsGV[*pv]; \
|
||||
int buv = CoefsBU[*pu]; \
|
||||
int r, g, b;
|
||||
|
||||
/* yuv420p, yuv422p -> */
|
||||
#define CONVERT(OUTPUT_FUNC) LOOKUP_COEFFS \
|
||||
VANILLA_YUV2RGB_PIXEL(py[0], ruv, guv, buv) \
|
||||
OUTPUT_FUNC(dst, r, g, b) \
|
||||
VANILLA_YUV2RGB_PIXEL(py[1], ruv, guv, buv) \
|
||||
OUTPUT_FUNC((dst+4), r, g, b)
|
||||
|
||||
#define CLEANUP
|
||||
|
||||
YUV_CONVERT(yuv420_to_rgba_vanilla, CONVERT(VANILLA_RGBA_OUT), VANILLA_RGBA_OUT, 2, 8, 2, 1, 2)
|
||||
YUV_CONVERT(yuv420_to_bgra_vanilla, CONVERT(VANILLA_BGRA_OUT), VANILLA_BGRA_OUT, 2, 8, 2, 1, 2)
|
||||
YUV_CONVERT(yuv420_to_abgr_vanilla, CONVERT(VANILLA_ABGR_OUT), VANILLA_ABGR_OUT, 2, 8, 2, 1, 2)
|
||||
YUV_CONVERT(yuv420_to_argb_vanilla, CONVERT(VANILLA_ARGB_OUT), VANILLA_ARGB_OUT, 2, 8, 2, 1, 2)
|
||||
|
||||
YUV_CONVERT(yuv422_to_rgba_vanilla, CONVERT(VANILLA_RGBA_OUT), VANILLA_RGBA_OUT, 2, 8, 2, 1, 1)
|
||||
YUV_CONVERT(yuv422_to_bgra_vanilla, CONVERT(VANILLA_BGRA_OUT), VANILLA_BGRA_OUT, 2, 8, 2, 1, 1)
|
||||
YUV_CONVERT(yuv422_to_abgr_vanilla, CONVERT(VANILLA_ABGR_OUT), VANILLA_ABGR_OUT, 2, 8, 2, 1, 1)
|
||||
YUV_CONVERT(yuv422_to_argb_vanilla, CONVERT(VANILLA_ARGB_OUT), VANILLA_ARGB_OUT, 2, 8, 2, 1, 1)
|
||||
|
||||
#undef CONVERT
|
||||
|
||||
/* yuv444p -> */
|
||||
#define CONVERT(OUTPUT_FUNC) LOOKUP_COEFFS \
|
||||
VANILLA_YUV2RGB_PIXEL(py[0], ruv, guv, buv) \
|
||||
OUTPUT_FUNC(dst, r, g, b)
|
||||
|
||||
YUV_CONVERT(yuv444_to_rgba_vanilla, CONVERT(VANILLA_RGBA_OUT), VANILLA_RGBA_OUT, 1, 4, 1, 1, 1)
|
||||
YUV_CONVERT(yuv444_to_bgra_vanilla, CONVERT(VANILLA_BGRA_OUT), VANILLA_BGRA_OUT, 1, 4, 1, 1, 1)
|
||||
YUV_CONVERT(yuv444_to_abgr_vanilla, CONVERT(VANILLA_ABGR_OUT), VANILLA_ABGR_OUT, 1, 4, 1, 1, 1)
|
||||
YUV_CONVERT(yuv444_to_argb_vanilla, CONVERT(VANILLA_ARGB_OUT), VANILLA_ARGB_OUT, 1, 4, 1, 1, 1)
|
||||
|
||||
#undef CONVERT
|
||||
#undef CLEANUP
|
||||
|
||||
#ifndef DISABLE_CPU_FEATURES
|
||||
/* although we use cpu runtime detection, we still need these
|
||||
* macros as there's no way e.g. we could compile a x86 asm code
|
||||
* on a ppc machine and vica-versa
|
||||
*/
|
||||
#if defined(i386) || defined(__x86__) || defined(__x86_64__) || defined(_M_IX86) || defined(_M_AMD64)
|
||||
#if !defined(_M_AMD64)
|
||||
#define ENABLE_MMX
|
||||
#endif
|
||||
#include "x86/oggplay_yuv2rgb_x86.c"
|
||||
#if defined(_MSC_VER) || defined(ATTRIBUTE_ALIGNED_MAX) && ATTRIBUTE_ALIGNED_MAX >= 16
|
||||
#define ENABLE_SSE2
|
||||
#endif
|
||||
#elif defined(__ppc__) || defined(__ppc64__)
|
||||
#define ENABLE_ALTIVEC
|
||||
//altivec intristics only working with -maltivec gcc flag,
|
||||
//but we want runtime altivec detection, hence this has to be
|
||||
//fixed!
|
||||
//#include "oggplay_yuv2rgb_altivec.c"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* Initialize the lookup-table for vanilla yuv to rgb conversion.
|
||||
*/
|
||||
static void
|
||||
init_vanilla_coeffs (void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i = 0; i < 256; ++i)
|
||||
{
|
||||
CoefsGU[i] = -CoGU * (i - 128);
|
||||
CoefsGV[i] = -CoGV * (i - 128);
|
||||
CoefsBU[i] = CoBU * (i - 128);
|
||||
CoefsRV[i] = CoRV * (i - 128);
|
||||
CoefsY[i] = CoY * (i - 16) + (prec/2);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the function pointers in yuv_conv.
|
||||
*
|
||||
* Initialize the function pointers in yuv_conv, based on the
|
||||
* the available CPU extensions.
|
||||
*/
|
||||
static void
|
||||
init_yuv_converters(void)
|
||||
{
|
||||
ogg_uint32_t features = 0;
|
||||
|
||||
if ( yuv_conv.yuv420rgba == NULL )
|
||||
{
|
||||
init_vanilla_coeffs ();
|
||||
#ifndef DISABLE_CPU_FEATURES
|
||||
features = oc_cpu_flags_get();
|
||||
#endif
|
||||
#ifdef ENABLE_SSE2
|
||||
if (features & OC_CPU_X86_SSE2)
|
||||
{
|
||||
yuv_conv.yuv420rgba = yuv420_to_rgba_sse2;
|
||||
yuv_conv.yuv420bgra = yuv420_to_bgra_sse2;
|
||||
yuv_conv.yuv420argb = yuv420_to_argb_sse2;
|
||||
yuv_conv.yuv422rgba = yuv422_to_rgba_sse2;
|
||||
yuv_conv.yuv422bgra = yuv422_to_bgra_sse2;
|
||||
yuv_conv.yuv422argb = yuv422_to_argb_sse2;
|
||||
yuv_conv.yuv444rgba = yuv444_to_rgba_sse2;
|
||||
yuv_conv.yuv444bgra = yuv444_to_bgra_sse2;
|
||||
yuv_conv.yuv444argb = yuv444_to_argb_sse2;
|
||||
return;
|
||||
}
|
||||
#endif /* SSE2 */
|
||||
#ifdef ENABLE_MMX
|
||||
#ifdef ENABLE_SSE2
|
||||
else
|
||||
#endif
|
||||
if (features & OC_CPU_X86_MMXEXT)
|
||||
{
|
||||
yuv_conv.yuv420rgba = yuv420_to_rgba_sse;
|
||||
yuv_conv.yuv420bgra = yuv420_to_bgra_sse;
|
||||
yuv_conv.yuv420argb = yuv420_to_argb_sse;
|
||||
yuv_conv.yuv422rgba = yuv422_to_rgba_sse;
|
||||
yuv_conv.yuv422bgra = yuv422_to_bgra_sse;
|
||||
yuv_conv.yuv422argb = yuv422_to_argb_sse;
|
||||
yuv_conv.yuv444rgba = yuv444_to_rgba_sse;
|
||||
yuv_conv.yuv444bgra = yuv444_to_bgra_sse;
|
||||
yuv_conv.yuv444argb = yuv444_to_argb_sse;
|
||||
return;
|
||||
}
|
||||
else if (features & OC_CPU_X86_MMX)
|
||||
{
|
||||
yuv_conv.yuv420rgba = yuv420_to_rgba_mmx;
|
||||
yuv_conv.yuv420bgra = yuv420_to_bgra_mmx;
|
||||
yuv_conv.yuv420argb = yuv420_to_argb_mmx;
|
||||
yuv_conv.yuv422rgba = yuv422_to_rgba_mmx;
|
||||
yuv_conv.yuv422bgra = yuv422_to_bgra_mmx;
|
||||
yuv_conv.yuv422argb = yuv422_to_argb_mmx;
|
||||
yuv_conv.yuv444rgba = yuv444_to_rgba_mmx;
|
||||
yuv_conv.yuv444bgra = yuv444_to_bgra_mmx;
|
||||
yuv_conv.yuv444argb = yuv444_to_argb_mmx;
|
||||
return;
|
||||
}
|
||||
#elif defined(ENABLE_ALTIVEC)
|
||||
if (features & OC_CPU_PPC_ALTIVEC)
|
||||
{
|
||||
yuv_conv.yuv420rgba = yuv420_to_abgr_vanilla;
|
||||
yuv_conv.yuv420bgra = yuv420_to_argb_vanilla;
|
||||
yuv_conv.yuv420argb = yuv420_to_bgra_vanilla;
|
||||
yuv_conv.yuv422rgba = yuv422_to_abgr_vanilla;
|
||||
yuv_conv.yuv422bgra = yuv422_to_argb_vanilla;
|
||||
yuv_conv.yuv422argb = yuv422_to_bgra_vanilla;
|
||||
yuv_conv.yuv444rgba = yuv444_to_abgr_vanilla;
|
||||
yuv_conv.yuv444bgra = yuv444_to_argb_vanilla;
|
||||
yuv_conv.yuv444argb = yuv444_to_bgra_vanilla;
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* no CPU extension was found... using vanilla converter, with respect
|
||||
* to the endianness of the host
|
||||
*/
|
||||
#if WORDS_BIGENDIAN || IS_BIG_ENDIAN
|
||||
yuv_conv.yuv420rgba = yuv420_to_abgr_vanilla;
|
||||
yuv_conv.yuv420bgra = yuv420_to_argb_vanilla;
|
||||
yuv_conv.yuv420argb = yuv420_to_bgra_vanilla;
|
||||
yuv_conv.yuv422rgba = yuv422_to_abgr_vanilla;
|
||||
yuv_conv.yuv422bgra = yuv422_to_argb_vanilla;
|
||||
yuv_conv.yuv422argb = yuv422_to_bgra_vanilla;
|
||||
yuv_conv.yuv444rgba = yuv444_to_abgr_vanilla;
|
||||
yuv_conv.yuv444bgra = yuv444_to_argb_vanilla;
|
||||
yuv_conv.yuv444argb = yuv444_to_bgra_vanilla;
|
||||
#else
|
||||
yuv_conv.yuv420rgba = yuv420_to_rgba_vanilla;
|
||||
yuv_conv.yuv420bgra = yuv420_to_bgra_vanilla;
|
||||
yuv_conv.yuv420argb = yuv420_to_argb_vanilla;
|
||||
yuv_conv.yuv422rgba = yuv422_to_rgba_vanilla;
|
||||
yuv_conv.yuv422bgra = yuv422_to_bgra_vanilla;
|
||||
yuv_conv.yuv422argb = yuv422_to_argb_vanilla;
|
||||
yuv_conv.yuv444rgba = yuv444_to_rgba_vanilla;
|
||||
yuv_conv.yuv444bgra = yuv444_to_bgra_vanilla;
|
||||
yuv_conv.yuv444argb = yuv444_to_argb_vanilla;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
oggplay_yuv2rgba(const OggPlayYUVChannels* yuv, OggPlayRGBChannels* rgb)
|
||||
{
|
||||
if (yuv_conv.yuv420rgba == NULL)
|
||||
init_yuv_converters();
|
||||
|
||||
if (yuv->y_height!=yuv->uv_height)
|
||||
yuv_conv.yuv420rgba(yuv, rgb);
|
||||
else if (yuv->y_width!=yuv->uv_width)
|
||||
yuv_conv.yuv422rgba(yuv,rgb);
|
||||
else
|
||||
yuv_conv.yuv444rgba(yuv,rgb);
|
||||
}
|
||||
|
||||
void
|
||||
oggplay_yuv2bgra(const OggPlayYUVChannels* yuv, OggPlayRGBChannels * rgb)
|
||||
{
|
||||
if (yuv_conv.yuv420bgra == NULL)
|
||||
init_yuv_converters();
|
||||
|
||||
if (yuv->y_height!=yuv->uv_height)
|
||||
yuv_conv.yuv420bgra(yuv, rgb);
|
||||
else if (yuv->y_width!=yuv->uv_width)
|
||||
yuv_conv.yuv422bgra(yuv,rgb);
|
||||
else
|
||||
yuv_conv.yuv444bgra(yuv,rgb);}
|
||||
|
||||
void
|
||||
oggplay_yuv2argb(const OggPlayYUVChannels* yuv, OggPlayRGBChannels * rgb)
|
||||
{
|
||||
if (yuv_conv.yuv420argb == NULL)
|
||||
init_yuv_converters();
|
||||
|
||||
if (yuv->y_height!=yuv->uv_height)
|
||||
yuv_conv.yuv420argb(yuv, rgb);
|
||||
else if (yuv->y_width!=yuv->uv_width)
|
||||
yuv_conv.yuv422argb(yuv,rgb);
|
||||
else
|
||||
yuv_conv.yuv444argb(yuv,rgb);
|
||||
}
|
||||
|
|
@ -1,108 +0,0 @@
|
|||
#ifndef __OGGPLAY_YUV2RGB_TEMPLATE_H__
|
||||
#define __OGGPLAY_YUV2RGB_TEMPLATE_H__
|
||||
|
||||
#if defined(WIN32)
|
||||
#define restrict
|
||||
#else
|
||||
#ifndef restrict
|
||||
#define restrict __restrict__
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Template for YUV to RGB conversion
|
||||
*
|
||||
* @param FUNC function name
|
||||
* @param CONVERT a macro that defines the actual conversion function
|
||||
* @param VANILLA_OUT
|
||||
* @param NUM_PIXELS number of pixels processed in one iteration
|
||||
* @param OUT_SHIFT number of pixels to shift after one iteration in rgb data stream
|
||||
* @param Y_SHIFT number of pixels to shift after one iteration in Y data stream
|
||||
* @param UV_SHIFT
|
||||
* @param UV_VERT_SUB
|
||||
*/
|
||||
#define YUV_CONVERT(FUNC, CONVERT, VANILLA_OUT, NUM_PIXELS, OUT_SHIFT, Y_SHIFT, UV_SHIFT, UV_VERT_SUB)\
|
||||
static void \
|
||||
(FUNC)(const OggPlayYUVChannels* yuv, OggPlayRGBChannels* rgb) \
|
||||
{ \
|
||||
int i,j, w, h, r; \
|
||||
unsigned char* restrict ptry; \
|
||||
unsigned char* restrict ptru; \
|
||||
unsigned char* restrict ptrv; \
|
||||
unsigned char* restrict ptro; \
|
||||
unsigned char *dst, *py, *pu, *pv; \
|
||||
\
|
||||
ptro = rgb->ptro; \
|
||||
ptry = yuv->ptry; \
|
||||
ptru = yuv->ptru; \
|
||||
ptrv = yuv->ptrv; \
|
||||
\
|
||||
w = yuv->y_width / NUM_PIXELS; \
|
||||
h = yuv->y_height; \
|
||||
r = yuv->y_width % NUM_PIXELS; \
|
||||
for (i = 0; i < h; ++i) \
|
||||
{ \
|
||||
py = ptry; \
|
||||
pu = ptru; \
|
||||
pv = ptrv; \
|
||||
dst = ptro; \
|
||||
for (j = 0; j < w; ++j, \
|
||||
dst += OUT_SHIFT, \
|
||||
py += Y_SHIFT, \
|
||||
pu += UV_SHIFT, \
|
||||
pv += UV_SHIFT) \
|
||||
{ \
|
||||
/* use the given conversion function */ \
|
||||
CONVERT \
|
||||
} \
|
||||
/* \
|
||||
* the video frame is not the multiple of NUM_PIXELS, \
|
||||
* thus we have to deal with remaning pixels using \
|
||||
* vanilla implementation. \
|
||||
*/ \
|
||||
if (r) { \
|
||||
if (r==1 && yuv->y_width&1) { \
|
||||
pu -= 1; pv -= 1; \
|
||||
} \
|
||||
\
|
||||
for \
|
||||
( \
|
||||
j=(yuv->y_width-r); j < yuv->y_width; \
|
||||
++j, \
|
||||
dst += 4, \
|
||||
py += 1 \
|
||||
) \
|
||||
{ \
|
||||
LOOKUP_COEFFS \
|
||||
VANILLA_YUV2RGB_PIXEL(py[0], ruv, guv, buv) \
|
||||
VANILLA_OUT(dst, r, g, b) \
|
||||
if \
|
||||
( \
|
||||
(j%2 && !(j+1==yuv->y_width-1 && yuv->y_width&1)) \
|
||||
|| \
|
||||
UV_VERT_SUB==1 \
|
||||
) { \
|
||||
pu += 1; pv += 1; \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
ptro += rgb->rgb_width * 4; \
|
||||
ptry += yuv->y_width; \
|
||||
\
|
||||
if \
|
||||
( \
|
||||
(i & 0x1 && !(i+1==h-1 && h&1)) \
|
||||
|| \
|
||||
UV_VERT_SUB==1 \
|
||||
) \
|
||||
{ \
|
||||
ptru += yuv->uv_width; \
|
||||
ptrv += yuv->uv_width; \
|
||||
} \
|
||||
} \
|
||||
CLEANUP \
|
||||
}
|
||||
|
||||
#endif
|
||||
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче