зеркало из https://github.com/mozilla/pjs.git
Bug 477899 - Requests for the duration of a media resource are cached by liboggplay - r+sr=roc
This commit is contained in:
Родитель
da34fe4fbe
Коммит
9512778100
|
@ -73,6 +73,11 @@ public:
|
|||
// Resume any downloads that have been suspended.
|
||||
void Resume();
|
||||
|
||||
// Set the duration of the media resource. Call with decoder lock
|
||||
// obtained so that the decoder thread does not request the duration
|
||||
// while it is changing.
|
||||
void SetDuration(PRInt64 aDuration);
|
||||
|
||||
nsIPrincipal* GetCurrentPrincipal();
|
||||
|
||||
// Implementation of OggPlay Reader API.
|
||||
|
@ -81,9 +86,13 @@ public:
|
|||
size_t io_read(char* aBuffer, size_t aCount);
|
||||
int io_seek(long aOffset, int aWhence);
|
||||
long io_tell();
|
||||
ogg_int64_t duration();
|
||||
|
||||
public:
|
||||
nsMediaStream mStream;
|
||||
|
||||
// Duration of the media resource. -1 if not known.
|
||||
PRInt64 mDuration;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -69,6 +69,11 @@ void nsChannelReader::Resume()
|
|||
mStream.Resume();
|
||||
}
|
||||
|
||||
void nsChannelReader::SetDuration(PRInt64 aDuration)
|
||||
{
|
||||
mDuration = aDuration;
|
||||
}
|
||||
|
||||
size_t nsChannelReader::io_read(char* aBuffer, size_t aCount)
|
||||
{
|
||||
PRUint32 bytes = 0;
|
||||
|
@ -93,6 +98,11 @@ long nsChannelReader::io_tell()
|
|||
return mStream.Tell();
|
||||
}
|
||||
|
||||
ogg_int64_t nsChannelReader::duration()
|
||||
{
|
||||
return mDuration;
|
||||
}
|
||||
|
||||
static OggPlayErrorCode oggplay_channel_reader_initialise(OggPlayReader* aReader, int aBlock)
|
||||
{
|
||||
nsChannelReader * me = static_cast<nsChannelReader*>(aReader);
|
||||
|
@ -127,6 +137,12 @@ static long oggplay_channel_reader_io_tell(void* 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();
|
||||
}
|
||||
|
||||
nsresult nsChannelReader::Init(nsMediaDecoder* aDecoder, nsIURI* aURI,
|
||||
nsIChannel* aChannel,
|
||||
nsIStreamListener** aStreamListener)
|
||||
|
@ -139,7 +155,8 @@ nsChannelReader::~nsChannelReader()
|
|||
MOZ_COUNT_DTOR(nsChannelReader);
|
||||
}
|
||||
|
||||
nsChannelReader::nsChannelReader()
|
||||
nsChannelReader::nsChannelReader() :
|
||||
mDuration(-1)
|
||||
{
|
||||
MOZ_COUNT_CTOR(nsChannelReader);
|
||||
OggPlayReader* reader = this;
|
||||
|
@ -149,7 +166,7 @@ nsChannelReader::nsChannelReader()
|
|||
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 = nsnull;
|
||||
reader->duration = &oggplay_channel_reader_duration;
|
||||
}
|
||||
|
||||
nsIPrincipal*
|
||||
|
|
|
@ -653,7 +653,6 @@ private:
|
|||
nsresult nsHttpStreamStrategy::Seek(PRInt32 aWhence, PRInt64 aOffset)
|
||||
{
|
||||
PRInt64 totalBytes = mDecoder->GetStatistics().mTotalBytes;
|
||||
|
||||
{
|
||||
nsAutoLock lock(mLock);
|
||||
if (!mChannel || !mPipeInput)
|
||||
|
@ -719,7 +718,6 @@ nsresult nsHttpStreamStrategy::Seek(PRInt32 aWhence, PRInt64 aOffset)
|
|||
nsAutoArrayPtr<char> data(new char[bytesAhead]);
|
||||
if (!data)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
// Read until the read cursor reaches new seek point. If Cancel() is
|
||||
// called then the read will fail with an error so we can bail out of
|
||||
// the blocking call.
|
||||
|
|
|
@ -674,6 +674,7 @@ void nsOggDecodeStateMachine::PlayFrame() {
|
|||
// Reset the play start time.
|
||||
mPlayStartTime = PR_IntervalNow();
|
||||
mPauseDuration = 0;
|
||||
frame->mState = OGGPLAY_STREAM_INITIALISED;
|
||||
}
|
||||
|
||||
double time = (PR_IntervalToMilliseconds(PR_IntervalNow()-mPlayStartTime-mPauseDuration)/1000.0);
|
||||
|
@ -1228,6 +1229,7 @@ void nsOggDecodeStateMachine::LoadOggHeaders(nsChannelReader* aReader)
|
|||
// and blocks until these are completed.
|
||||
mon.Exit();
|
||||
PRInt64 d = oggplay_get_duration(mPlayer);
|
||||
oggplay_seek(mPlayer, 0);
|
||||
mon.Enter();
|
||||
mDuration = d;
|
||||
mDecoder->StartProgressUpdates();
|
||||
|
@ -1946,6 +1948,10 @@ void nsOggDecoder::SetDuration(PRInt64 aDuration)
|
|||
if (mDecodeStateMachine) {
|
||||
nsAutoMonitor mon(mMonitor);
|
||||
mDecodeStateMachine->SetDuration(mDuration);
|
||||
|
||||
if (mReader) {
|
||||
mReader->SetDuration(mDuration);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -5,10 +5,7 @@ the Mozilla build system.
|
|||
|
||||
http://svn.annodex.net/liboggplay/trunk/
|
||||
|
||||
The svn revision number used was r3774.
|
||||
|
||||
The patch from Annodex trac ticket 421 is applied to fix bug 459938:
|
||||
http://trac.annodex.net/ticket/421
|
||||
The svn revision number used was r3848.
|
||||
|
||||
The patch from Bug 468327 (yuv_disable_optimized.patch) is applied
|
||||
to disable optimized yuv to rgb routines.
|
||||
|
|
|
@ -41,6 +41,8 @@ VPATH = @srcdir@
|
|||
|
||||
include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
DEFINES += -DHAVE_CONFIG_H
|
||||
|
||||
MODULE = oggplay
|
||||
LIBRARY_NAME = oggplay
|
||||
FORCE_STATIC_LIB= 1
|
||||
|
|
|
@ -64,6 +64,7 @@ oggplay_new_with_reader(OggPlayReader *reader) {
|
|||
me->trash = NULL;
|
||||
me->oggz = NULL;
|
||||
me->pt_update_valid = 1;
|
||||
me->duration = -1;
|
||||
|
||||
return me;
|
||||
|
||||
|
@ -210,7 +211,7 @@ oggplay_set_offset(OggPlay *me, int track, ogg_int64_t offset) {
|
|||
return E_OGGPLAY_BAD_TRACK;
|
||||
}
|
||||
|
||||
me->decode_data[track]->offset = (offset << 32);
|
||||
me->decode_data[track]->offset = (offset << 32) / 1000;
|
||||
|
||||
return E_OGGPLAY_OK;
|
||||
|
||||
|
@ -509,7 +510,7 @@ read_more_data:
|
|||
if (r == 0) {
|
||||
num_records = oggplay_callback_info_prepare(me, &info);
|
||||
/*
|
||||
* set all of the tracks to active
|
||||
* set all of the tracks to inactive
|
||||
*/
|
||||
for (i = 0; i < me->num_tracks; i++) {
|
||||
me->decode_data[i]->active = 0;
|
||||
|
@ -574,8 +575,11 @@ oggplay_start_decoding(OggPlay *me) {
|
|||
int r;
|
||||
|
||||
while (1) {
|
||||
if ((r = oggplay_step_decoding(me)) != E_OGGPLAY_CONTINUE)
|
||||
return (OggPlayErrorCode)r;
|
||||
r = oggplay_step_decoding(me);
|
||||
if (r == E_OGGPLAY_CONTINUE || r == E_OGGPLAY_TIMEOUT) {
|
||||
continue;
|
||||
}
|
||||
return (OggPlayErrorCode)r;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -643,17 +647,30 @@ oggplay_get_duration(OggPlay *me) {
|
|||
return E_OGGPLAY_BAD_OGGPLAY;
|
||||
}
|
||||
|
||||
if (me->reader->duration)
|
||||
return me->reader->duration(me->reader);
|
||||
else {
|
||||
/* 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;
|
||||
ogg_int64_t duration;
|
||||
pos = oggz_tell_units(me->oggz);
|
||||
duration = oggz_seek_units(me->oggz, 0, SEEK_END);
|
||||
me->duration = oggz_seek_units(me->oggz, 0, SEEK_END);
|
||||
oggz_seek_units(me->oggz, pos, SEEK_SET);
|
||||
oggplay_seek_cleanup(me, pos);
|
||||
return duration;
|
||||
}
|
||||
|
||||
return me->duration;
|
||||
}
|
||||
|
||||
int
|
||||
|
|
|
@ -48,7 +48,7 @@ oggplay_callback_info_prepare(OggPlay *me, OggPlayCallbackInfo ***info) {
|
|||
int i;
|
||||
int tcount = 0;
|
||||
|
||||
int added_required_record = 1;
|
||||
int added_required_record = me->num_tracks;
|
||||
ogg_int64_t diff;
|
||||
ogg_int64_t latest_first_record = 0x0LL;
|
||||
//ogg_int64_t lpt = 0;
|
||||
|
@ -79,6 +79,7 @@ oggplay_callback_info_prepare(OggPlay *me, OggPlayCallbackInfo ***info) {
|
|||
track_info->available_records = track_info->required_records = 0;
|
||||
track_info->records = NULL;
|
||||
track_info->stream_info = OGGPLAY_STREAM_UNINITIALISED;
|
||||
added_required_record --;
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -144,7 +145,6 @@ oggplay_callback_info_prepare(OggPlay *me, OggPlayCallbackInfo ***info) {
|
|||
//lpt = p->presentation_time;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (track_info->required_records > 0) {
|
||||
/*
|
||||
|
@ -199,24 +199,30 @@ oggplay_callback_info_prepare(OggPlay *me, OggPlayCallbackInfo ***info) {
|
|||
* 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
|
||||
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 = 0;
|
||||
me->pt_update_valid = 0;
|
||||
added_required_record --;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
me->pt_update_valid = 0;
|
||||
|
||||
//printf("\n");
|
||||
|
||||
/*
|
||||
|
@ -397,7 +403,7 @@ oggplay_callback_info_get_presentation_time(OggPlayDataHeader *header) {
|
|||
}
|
||||
|
||||
/* SGS: is this correct? */
|
||||
return (header->presentation_time >> 32) & 0xFFFFFFFF;
|
||||
return (((header->presentation_time >> 16) * 1000) >> 16) & 0xFFFFFFFF;
|
||||
}
|
||||
|
||||
OggPlayVideoData *
|
||||
|
|
|
@ -59,9 +59,9 @@ oggplay_file_reader_initialise(OggPlayReader * opr, int block) {
|
|||
return E_OGGPLAY_BAD_INPUT;
|
||||
}
|
||||
|
||||
fseek(me->file, SEEK_END, 0);
|
||||
fseek(me->file, 0L, SEEK_END);
|
||||
me->size = ftell(me->file);
|
||||
fseek(me->file, SEEK_SET, 0);
|
||||
fseek(me->file, 0L, SEEK_SET);
|
||||
|
||||
me->current_position = 0;
|
||||
|
||||
|
@ -146,6 +146,7 @@ oggplay_file_reader_new(char *file_name) {
|
|||
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;
|
||||
|
|
|
@ -49,8 +49,8 @@ typedef struct {
|
|||
OggPlayReader functions;
|
||||
char * file_name;
|
||||
FILE * file;
|
||||
int current_position;
|
||||
int size;
|
||||
long current_position;
|
||||
long size;
|
||||
} OggPlayFileReader;
|
||||
|
||||
#endif
|
||||
|
|
|
@ -39,11 +39,14 @@
|
|||
#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>
|
||||
|
@ -220,6 +223,7 @@ struct _OggPlay {
|
|||
OggPlaySeekTrash * trash;
|
||||
int shutdown;
|
||||
int pt_update_valid;
|
||||
ogg_int64_t duration; /**< The value of the duration the last time it was retrieved.*/
|
||||
};
|
||||
|
||||
void
|
||||
|
|
|
@ -59,7 +59,11 @@
|
|||
#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", \
|
||||
|
|
|
@ -76,6 +76,7 @@ void oggplay_yuv2rgb(OggPlayYUVChannels * yuv, OggPlayRGBChannels * rgb) {
|
|||
unsigned char * restrict ptry;
|
||||
unsigned char * restrict ptru;
|
||||
unsigned char * restrict ptrv;
|
||||
unsigned char * ptro;
|
||||
|
||||
register __m64 *y, *o;
|
||||
register __m64 zero, ut, vt, imm, imm2;
|
||||
|
@ -84,14 +85,15 @@ void oggplay_yuv2rgb(OggPlayYUVChannels * yuv, OggPlayRGBChannels * rgb) {
|
|||
|
||||
zero = _mm_setzero_si64();
|
||||
|
||||
ptro = rgb->ptro;
|
||||
ptry = yuv->ptry;
|
||||
ptru = yuv->ptru;
|
||||
ptrv = yuv->ptrv;
|
||||
|
||||
for (i = 0; i < yuv->y_height; i++) {
|
||||
int j;
|
||||
o = (__m64*)rgb->ptro;
|
||||
rgb->ptro += rgb->rgb_width * 4;
|
||||
o = (__m64*)ptro;
|
||||
ptro += rgb->rgb_width * 4;
|
||||
for (j = 0; j < yuv->y_width; j += 8) {
|
||||
|
||||
y = (__m64*)&ptry[j];
|
||||
|
@ -206,6 +208,7 @@ void oggplay_yuv2bgr(OggPlayYUVChannels * yuv, OggPlayRGBChannels * rgb) {
|
|||
unsigned char * restrict ptry;
|
||||
unsigned char * restrict ptru;
|
||||
unsigned char * restrict ptrv;
|
||||
unsigned char * ptro;
|
||||
|
||||
register __m64 *y, *o;
|
||||
register __m64 zero, ut, vt, imm, imm2;
|
||||
|
@ -217,11 +220,12 @@ void oggplay_yuv2bgr(OggPlayYUVChannels * yuv, OggPlayRGBChannels * rgb) {
|
|||
ptry = yuv->ptry;
|
||||
ptru = yuv->ptru;
|
||||
ptrv = yuv->ptrv;
|
||||
ptro = rgb->ptro;
|
||||
|
||||
for (i = 0; i < yuv->y_height; i++) {
|
||||
int j;
|
||||
o = (__m64*)rgb->ptro;
|
||||
rgb->ptro += rgb->rgb_width * 4;
|
||||
o = (__m64*)ptro;
|
||||
ptro += rgb->rgb_width * 4;
|
||||
for (j = 0; j < yuv->y_width; j += 8) {
|
||||
|
||||
y = (__m64*)&ptry[j];
|
||||
|
|
|
@ -35,8 +35,7 @@ sed s/\#include\ \<config.h\>/\#ifdef\ WIN32\\n\#include\ \"config_win32.h\"\\n\
|
|||
rm ./src/liboggplay/oggplay_private.h1
|
||||
sed s/\#ifdef\ HAVE_INTTYPES_H/\#if\ HAVE_INTTYPES_H/g $1/src/liboggplay/oggplay_data.c >./src/liboggplay/oggplay_data.c
|
||||
cd ./src/liboggplay
|
||||
patch <../../yuv2rgb-vanilla-fix.patch
|
||||
patch <../../yuv_disable_optimized.patch
|
||||
cd ../..
|
||||
patch -p4 <yuv2argb.patch
|
||||
patch -p3 <yuv2argb.patch
|
||||
patch -p3 <bug464007.patch
|
||||
|
|
|
@ -1,88 +0,0 @@
|
|||
Index: oggplay_yuv2rgb.c
|
||||
===================================================================
|
||||
--- oggplay_yuv2rgb.c (revision 3733)
|
||||
+++ oggplay_yuv2rgb.c (working copy)
|
||||
@@ -357,29 +357,27 @@
|
||||
ptro2 = ptro;
|
||||
for (j = 0; j < yuv->y_width; j += 2) {
|
||||
|
||||
- short pr, pg, pb;
|
||||
+ short pr, pg, pb, y;
|
||||
short r, g, b;
|
||||
|
||||
- //pr = ((128 + (ptrv[j/2] - 128) * 292) >> 8) - 16; /* 1.14 * 256 */
|
||||
- pr = (-41344 + ptrv[j/2] * 292) >> 8;
|
||||
- //pg = ((128 - (ptru[j/2] - 128) * 101 - (ptrv[j/2] - 128) * 149) >> 8)-16;
|
||||
- // /* 0.395 & 0.581 */
|
||||
- pg = (28032 - ptru[j/2] * 101 - ptrv[j/2] * 149) >> 8;
|
||||
- //pb = ((128 + (ptru[j/2] - 128) * 520) >> 8) - 16; /* 2.032 */
|
||||
- pb = (-70528 + ptru[j/2] * 520) >> 8;
|
||||
+ pr = (-56992 + ptrv[j/2] * 409) >> 8;
|
||||
+ pg = (34784 - ptru[j/2] * 100 - ptrv[j/2] * 208) >> 8;
|
||||
+ pb = (-70688 + ptru[j/2] * 516) >> 8;
|
||||
|
||||
- r = ptry[j] + pr;
|
||||
- g = ptry[j] + pg;
|
||||
- b = ptry[j] + pb;
|
||||
+ y = 298*ptry[j] >> 8;
|
||||
+ r = y + pr;
|
||||
+ g = y + pg;
|
||||
+ b = y + pb;
|
||||
|
||||
*ptro2++ = CLAMP(r);
|
||||
*ptro2++ = CLAMP(g);
|
||||
*ptro2++ = CLAMP(b);
|
||||
*ptro2++ = 255;
|
||||
|
||||
- r = ptry[j + 1] + pr;
|
||||
- g = ptry[j + 1] + pg;
|
||||
- b = ptry[j + 1] + pb;
|
||||
+ y = 298*ptry[j + 1] >> 8;
|
||||
+ r = y + pr;
|
||||
+ g = y + pg;
|
||||
+ b = y + pb;
|
||||
|
||||
*ptro2++ = CLAMP(r);
|
||||
*ptro2++ = CLAMP(g);
|
||||
@@ -409,29 +407,27 @@
|
||||
ptro2 = ptro;
|
||||
for (j = 0; j < yuv->y_width; j += 2) {
|
||||
|
||||
- short pr, pg, pb;
|
||||
+ short pr, pg, pb, y;
|
||||
short r, g, b;
|
||||
|
||||
- //pr = ((128 + (ptrv[j/2] - 128) * 292) >> 8) - 16; /* 1.14 * 256 */
|
||||
- pr = (-41344 + ptrv[j/2] * 292) >> 8;
|
||||
- //pg = ((128 - (ptru[j/2] - 128) * 101 - (ptrv[j/2] - 128) * 149) >> 8)-16;
|
||||
- // /* 0.395 & 0.581 */
|
||||
- pg = (28032 - ptru[j/2] * 101 - ptrv[j/2] * 149) >> 8;
|
||||
- //pb = ((128 + (ptru[j/2] - 128) * 520) >> 8) - 16; /* 2.032 */
|
||||
- pb = (-70528 + ptru[j/2] * 520) >> 8;
|
||||
+ pr = (-56992 + ptrv[j/2] * 409) >> 8;
|
||||
+ pg = (34784 - ptru[j/2] * 100 - ptrv[j/2] * 208) >> 8;
|
||||
+ pb = (-70688 + ptru[j/2] * 516) >> 8;
|
||||
|
||||
- r = ptry[j] + pr;
|
||||
- g = ptry[j] + pg;
|
||||
- b = ptry[j] + pb;
|
||||
+ y = 298*ptry[j] >> 8;
|
||||
+ r = y + pr;
|
||||
+ g = y + pg;
|
||||
+ b = y + pb;
|
||||
|
||||
*ptro2++ = CLAMP(b);
|
||||
*ptro2++ = CLAMP(g);
|
||||
*ptro2++ = CLAMP(r);
|
||||
*ptro2++ = 255;
|
||||
|
||||
- r = ptry[j + 1] + pr;
|
||||
- g = ptry[j + 1] + pg;
|
||||
- b = ptry[j + 1] + pb;
|
||||
+ y = 298*ptry[j + 1] >> 8;
|
||||
+ r = y + pr;
|
||||
+ g = y + pg;
|
||||
+ b = y + pb;
|
||||
|
||||
*ptro2++ = CLAMP(b);
|
||||
*ptro2++ = CLAMP(g);
|
|
@ -1,13 +1,17 @@
|
|||
About Oggz
|
||||
----------
|
||||
|
||||
Oggz comprises liboggz and the command-line tools oggzinfo, oggzdump,
|
||||
oggzdiff, oggzmerge, oggzrip, oggz-comment, oggz-scan and oggz-validate.
|
||||
Oggz comprises liboggz and the tool oggz, which provides commands to
|
||||
inspect, edit and validate Ogg files. The oggz-chop tool can also be
|
||||
used to serve time ranges of Ogg media over HTTP by any web server that
|
||||
supports CGI.
|
||||
|
||||
liboggz is a C library providing a simple programming interface for reading
|
||||
and writing Ogg files and streams. Ogg is an interleaving data container
|
||||
developed by Monty at Xiph.Org, originally to support the Ogg Vorbis audio
|
||||
format.
|
||||
liboggz is a C library for reading and writing Ogg files and streams.
|
||||
It offers various improvements over the reference libogg, including
|
||||
support for seeking, validation and timestamp interpretation. Ogg is
|
||||
an interleaving data container developed by Monty at Xiph.Org,
|
||||
originally to support the Ogg Vorbis audio format but now used for
|
||||
many free codecs including Dirac, FLAC, Speex and Theora.
|
||||
|
||||
Dependencies
|
||||
------------
|
||||
|
@ -16,20 +20,22 @@ Oggz depends only on libogg, available in most free software
|
|||
distributions, or in source form at: http://xiph.org/downloads/
|
||||
|
||||
Support is built-in for parsing the headers of and seeking to time
|
||||
positions in Ogg Speex, Vorbis, FLAC, Theora, PCM and CMML. Oggz is also
|
||||
positions in Ogg Dirac, FLAC, Speex, Theora and Vorbis. Oggz is also
|
||||
compatible with Annodex streams, and supports seeking on all tracks
|
||||
described in an Ogg Skeleton track.
|
||||
|
||||
Installation
|
||||
------------
|
||||
|
||||
This library can be installed using the conventional commands:
|
||||
Release archives can be installed using the conventional commands:
|
||||
|
||||
$ ./configure
|
||||
$ make check
|
||||
$ sudo make install
|
||||
|
||||
sequence. Full details in the file INSTALL.
|
||||
sequence. Configuration details are in the file INSTALL. If you obtained
|
||||
this source by svn, first run "./autogen.sh" to create the configure script,
|
||||
then run the above commands.
|
||||
|
||||
Read the file README.win32 for installing under MS Windows, and
|
||||
README.symbian for information about building for Symbian devices.
|
||||
|
@ -104,26 +110,57 @@ Tools
|
|||
The Oggz source tarball also contains the following command-line tools,
|
||||
which are useful for debugging and testing Ogg bitstreams:
|
||||
|
||||
* oggzinfo: Display information about one or more Ogg files and
|
||||
their bitstreams.
|
||||
|
||||
* oggzdump: Hexdump packets of an Ogg file, or revert an Ogg file
|
||||
from such a hexdump.
|
||||
|
||||
* oggzdiff: Hexdump the packets of two Ogg files and output
|
||||
differences.
|
||||
|
||||
* oggzmerge: Merge Ogg files together, interleaving pages in order
|
||||
of presentation time.
|
||||
|
||||
* oggzrip: Extract one or more logical bitstreams from an Ogg file.
|
||||
* oggz-chop: Extract the part of an Ogg file between given start
|
||||
and/or end times.
|
||||
|
||||
* oggz-comment: List or edit comments in an Ogg file.
|
||||
|
||||
* oggz-diff: Hexdump the packets of two Ogg files and output
|
||||
differences.
|
||||
|
||||
* oggz-dump: Hexdump packets of an Ogg file, or revert an Ogg file
|
||||
from such a hexdump.
|
||||
|
||||
* oggz-info: Display information about one or more Ogg files and
|
||||
their bitstreams.
|
||||
|
||||
* oggz-merge: Merge Ogg files together, interleaving pages in order
|
||||
of presentation time.
|
||||
|
||||
* oggz-rip: Extract one or more logical bitstreams from an Ogg file.
|
||||
|
||||
* oggz-scan: Scan an Ogg file and output characteristic landmarks.
|
||||
|
||||
* oggz-sort: Sort the pages of an Ogg file in order of presentation time.
|
||||
|
||||
* oggz-validate: Validate the Ogg framing of one or more files.
|
||||
|
||||
The script bash-completion/oggz enables completion of tool options and codec
|
||||
names when using the bash shell. Source it from your .profile, or install it
|
||||
in /etc/bash_completion.d to enable it system-wide.
|
||||
|
||||
|
||||
oggz-chop: General usage and CGI installation
|
||||
---------------------------------------------
|
||||
|
||||
oggz-chop extracts the part of an Ogg file between given start and/or end
|
||||
times. The output file contains copies of the headers of the input file, and
|
||||
all the codec data required to correctly decode the content between the start
|
||||
and end times specified on the commandline. For codecs with data dependencies
|
||||
like video keyframes, the keyframe prior to the starting time will be included
|
||||
in the output.
|
||||
|
||||
An Apache server can be configured to use oggz-chop to handle all Ogg files
|
||||
(or, all Ogg files in a particular directory). An example Apache configuration
|
||||
is in the liboggz source tree, along with a script for installing it on a
|
||||
Debian server.
|
||||
|
||||
The oggz-chop binary checks if it is being run as a CGI script (by checking
|
||||
some environment variables), and if so acts based on the CGI query parameter
|
||||
t=, much like mod_annodex. It accepts all the time specifications that
|
||||
mod_annodex accepts (npt and various smpte framerates), and start and end
|
||||
times separated by a /.
|
||||
|
||||
License
|
||||
-------
|
||||
|
||||
|
@ -137,5 +174,4 @@ enjoy :)
|
|||
|
||||
--
|
||||
Conrad Parker
|
||||
Senior Software Engineer, Continuous Media Web, CSIRO Australia
|
||||
http://www.annodex.net/ http://www.ict.csiro.au/cmweb/
|
||||
http://www.annodex.net/
|
||||
|
|
|
@ -1,21 +1,12 @@
|
|||
The source from this directory was copied from the liboggz-0.9.7
|
||||
source distribution using the update.sh script. The only changes made
|
||||
were those applied by update.sh, which applies a patch from
|
||||
seek.patch, and the addition/upate of Makefile.in files for the
|
||||
The source from this directory was copied from the liboggz svn
|
||||
source repository using the update.sh script. The only changes made
|
||||
were those applied by update.sh, which applies patches described
|
||||
below, and the addition/upate of Makefile.in files for the
|
||||
Mozilla build system.
|
||||
|
||||
The seek.patch address a bug in liboggz when a seek call returns an
|
||||
error. It also addresses an issue where the guess for the seek
|
||||
position can exceed the file size. These will be upstreamed to liboggz.
|
||||
The svn revision number used was r3867.
|
||||
|
||||
The warning.patch addresses a printf in liboggz that is not wrapped
|
||||
in a DEBUG #ifdef. See Mozilla bug 450891 and Annodex ticket 431:
|
||||
|
||||
http://trac.annodex.net/ticket/431
|
||||
|
||||
The oggz_off_t.patch fixes a compile error on Solaris see bug 449754
|
||||
for details
|
||||
|
||||
The wince.patch addresses the lack of posix file IO suppor on windows ce see bug 461844 for details.
|
||||
The wince.patch addresses the lack of posix file IO support on windows ce,
|
||||
see bug 461844 for details.
|
||||
|
||||
endian.patch is applied to fix bug 452698.
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
/* 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 */
|
||||
|
||||
/* Define to 1 if you have the <dlfcn.h> header file. */
|
||||
#define HAVE_DLFCN_H 1
|
||||
|
||||
|
@ -8,7 +11,7 @@
|
|||
#define HAVE_FCNTL_H 1
|
||||
|
||||
/* Define to 1 if you have the 'getopt_long' function */
|
||||
#define HAVE_GETOPT_LONG
|
||||
#define HAVE_GETOPT_LONG /**/
|
||||
|
||||
/* Define to 1 if you have the <inttypes.h> header file. */
|
||||
#define HAVE_INTTYPES_H 1
|
||||
|
@ -47,6 +50,10 @@
|
|||
/* 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 build experimental code */
|
||||
/* #undef OGGZ_CONFIG_EXPERIMENTAL */
|
||||
|
||||
|
@ -101,9 +108,17 @@
|
|||
/* Version number of package */
|
||||
#define VERSION "0.9.8"
|
||||
|
||||
/* 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 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
|
||||
|
||||
/* Number of bits in a file offset, on hosts where this is settable. */
|
||||
#define _FILE_OFFSET_BITS 64
|
||||
|
@ -114,6 +129,9 @@
|
|||
/* Define for large files, on AIX-style hosts. */
|
||||
/* #undef _LARGE_FILES */
|
||||
|
||||
/* Some systems need _XOPEN_SOURCE for timezone */
|
||||
/* #undef _XOPEN_SOURCE */
|
||||
|
||||
/* Define to empty if `const' does not conform to ANSI C. */
|
||||
/* #undef const */
|
||||
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
#define HAVE_SSIZE_T 1
|
||||
|
||||
/* Define to 1 if you have the <stdint.h> header file. */
|
||||
#define HAVE_STDINT_H 1
|
||||
#undef HAVE_STDINT_H
|
||||
|
||||
/* Define to 1 if you have the <stdlib.h> header file. */
|
||||
#define HAVE_STDLIB_H 1
|
||||
|
@ -131,4 +131,8 @@
|
|||
|
||||
/* Define to `unsigned' if <sys/types.h> does not define. */
|
||||
#undef size_t
|
||||
#undef DEBUG
|
||||
|
||||
/* Define for MSVC as <stdint.h> is unavailable there */
|
||||
typedef unsigned char uint8_t;
|
||||
|
||||
#define inline __inline // MSVC
|
|
@ -563,6 +563,15 @@ int oggz_get_numtracks (OGGZ * oggz);
|
|||
*/
|
||||
long oggz_serialno_new (OGGZ * oggz);
|
||||
|
||||
/**
|
||||
* Return human-readable string representation of a content type
|
||||
*
|
||||
* \retval string the name of the content type
|
||||
* \retval NULL \a content invalid
|
||||
*/
|
||||
const char *
|
||||
oggz_content_type (OggzStreamContent content);
|
||||
|
||||
#include <oggz/oggz_off_t.h>
|
||||
#include <oggz/oggz_read.h>
|
||||
#include <oggz/oggz_stream.h>
|
||||
|
|
|
@ -120,6 +120,7 @@ oggz_comment_get_vendor (OGGZ * oggz, long serialno);
|
|||
* \retval 0 Success
|
||||
* \retval OGGZ_ERR_BAD \a oggz is not a valid OGGZ* handle
|
||||
* \retval OGGZ_ERR_INVALID Operation not suitable for this OGGZ
|
||||
* \retval OGGZ_ERR_OUT_OF_MEMORY Out of memory
|
||||
* \note The vendor string should identify the library used to produce
|
||||
* the stream, e.g. libvorbis 1.0 used "Xiph.Org libVorbis I 20020717".
|
||||
* If copying a bitstream it should be the same as the source.
|
||||
|
@ -190,6 +191,7 @@ oggz_comment_next_byname (OGGZ * oggz, long serialno,
|
|||
* \retval 0 Success
|
||||
* \retval OGGZ_ERR_BAD \a oggz is not a valid OGGZ* handle
|
||||
* \retval OGGZ_ERR_INVALID Operation not suitable for this OGGZ
|
||||
* \retval OGGZ_ERR_OUT_OF_MEMORY Out of memory
|
||||
*/
|
||||
int
|
||||
oggz_comment_add (OGGZ * oggz, long serialno, OggzComment * comment);
|
||||
|
@ -203,6 +205,7 @@ oggz_comment_add (OGGZ * oggz, long serialno, OggzComment * comment);
|
|||
* \retval 0 Success
|
||||
* \retval OGGZ_ERR_BAD \a oggz is not a valid OGGZ* handle
|
||||
* \retval OGGZ_ERR_INVALID Operation not suitable for this OGGZ
|
||||
* \retval OGGZ_ERR_OUT_OF_MEMORY Out of memory
|
||||
*/
|
||||
int
|
||||
oggz_comment_add_byname (OGGZ * oggz, long serialno,
|
||||
|
|
|
@ -41,7 +41,7 @@
|
|||
* Flags to oggz_new(), oggz_open(), and oggz_openfd().
|
||||
* Can be or'ed together in the following combinations:
|
||||
* - OGGZ_READ | OGGZ_AUTO
|
||||
* - OGGZ_WRITE | OGGZ_NONSTRICT
|
||||
* - OGGZ_WRITE | OGGZ_NONSTRICT | OGGZ_PREFIX | OGGZ_SUFFIX
|
||||
*/
|
||||
enum OggzFlags {
|
||||
/** Read only */
|
||||
|
@ -63,12 +63,16 @@ enum OggzFlags {
|
|||
OGGZ_AUTO = 0x20,
|
||||
|
||||
/**
|
||||
* Prefix
|
||||
* Write Prefix: Assume that we are only writing the prefix of an
|
||||
* Ogg stream, ie. disable checking for conformance with end-of-stream
|
||||
* constraints.
|
||||
*/
|
||||
OGGZ_PREFIX = 0x40,
|
||||
|
||||
/**
|
||||
* Suffix
|
||||
* Write Suffix: Assume that we are only writing the suffix of an
|
||||
* Ogg stream, ie. disable checking for conformance with
|
||||
* beginning-of-stream constraints.
|
||||
*/
|
||||
OGGZ_SUFFIX = 0x80
|
||||
|
||||
|
@ -112,6 +116,7 @@ typedef enum OggzStreamContent {
|
|||
OGGZ_CONTENT_ANXDATA,
|
||||
OGGZ_CONTENT_CELT,
|
||||
OGGZ_CONTENT_KATE,
|
||||
OGGZ_CONTENT_DIRAC,
|
||||
OGGZ_CONTENT_UNKNOWN
|
||||
} OggzStreamContent;
|
||||
|
||||
|
@ -165,6 +170,12 @@ enum OggzError {
|
|||
/** no data available from IO, try again */
|
||||
OGGZ_ERR_IO_AGAIN = -16,
|
||||
|
||||
/** Hole (sequence number gap) detected in input data */
|
||||
OGGZ_ERR_HOLE_IN_DATA = -17,
|
||||
|
||||
/** Out of memory */
|
||||
OGGZ_ERR_OUT_OF_MEMORY = -18,
|
||||
|
||||
/** The requested serialno does not exist in this OGGZ */
|
||||
OGGZ_ERR_BAD_SERIALNO = -20,
|
||||
|
||||
|
|
|
@ -125,6 +125,7 @@ typedef int (*OggzIOFlush) (void * user_handle);
|
|||
* \retval OGGZ_ERR_BAD_OGGZ \a oggz does not refer to an existing OGGZ
|
||||
* \retval OGGZ_ERR_INVALID Operation not suitable for this OGGZ; \a oggz not
|
||||
* open for reading.
|
||||
* \retval OGGZ_ERR_OUT_OF_MEMORY Out of memory
|
||||
*/
|
||||
int oggz_io_set_read (OGGZ * oggz, OggzIORead read, void * user_handle);
|
||||
|
||||
|
@ -147,6 +148,7 @@ void * oggz_io_get_read_user_handle (OGGZ * oggz);
|
|||
* \retval OGGZ_ERR_BAD_OGGZ \a oggz does not refer to an existing OGGZ
|
||||
* \retval OGGZ_ERR_INVALID Operation not suitable for this OGGZ; \a oggz not
|
||||
* open for writing.
|
||||
* \retval OGGZ_ERR_OUT_OF_MEMORY Out of memory
|
||||
*/
|
||||
int oggz_io_set_write (OGGZ * oggz, OggzIOWrite write, void * user_handle);
|
||||
|
||||
|
@ -168,6 +170,7 @@ void * oggz_io_get_write_user_handle (OGGZ * oggz);
|
|||
* \retval 0 Success
|
||||
* \retval OGGZ_ERR_BAD_OGGZ \a oggz does not refer to an existing OGGZ
|
||||
* \retval OGGZ_ERR_INVALID Operation not suitable for this OGGZ
|
||||
* \retval OGGZ_ERR_OUT_OF_MEMORY Out of memory
|
||||
*
|
||||
* \note If you provide an OggzIOSeek function, you MUST also provide
|
||||
* an OggzIOTell function, or else all your seeks will fail.
|
||||
|
@ -193,6 +196,7 @@ void * oggz_io_get_seek_user_handle (OGGZ * oggz);
|
|||
* \retval 0 Success
|
||||
* \retval OGGZ_ERR_BAD_OGGZ \a oggz does not refer to an existing OGGZ
|
||||
* \retval OGGZ_ERR_INVALID Operation not suitable for this OGGZ
|
||||
* \retval OGGZ_ERR_OUT_OF_MEMORY Out of memory
|
||||
*/
|
||||
int oggz_io_set_tell (OGGZ * oggz, OggzIOTell tell, void * user_handle);
|
||||
|
||||
|
@ -216,6 +220,7 @@ void * oggz_io_get_tell_user_handle (OGGZ * oggz);
|
|||
* \retval OGGZ_ERR_BAD_OGGZ \a oggz does not refer to an existing OGGZ
|
||||
* \retval OGGZ_ERR_INVALID Operation not suitable for this OGGZ; \a oggz not
|
||||
* open for writing.
|
||||
* \retval OGGZ_ERR_OUT_OF_MEMORY Out of memory
|
||||
*/
|
||||
int oggz_io_set_flush (OGGZ * oggz, OggzIOFlush flush, void * user_handle);
|
||||
|
||||
|
|
|
@ -94,6 +94,7 @@ typedef int (*OggzReadPacket) (OGGZ * oggz, ogg_packet * op, long serialno,
|
|||
* logical bitstream in \a oggz.
|
||||
* \retval OGGZ_ERR_BAD_OGGZ \a oggz does not refer to an existing OGGZ
|
||||
* \retval OGGZ_ERR_INVALID Operation not suitable for this OGGZ
|
||||
* \retval OGGZ_ERR_OUT_OF_MEMORY Out of memory
|
||||
*
|
||||
* \note Values of \a serialno other than -1 allows you to specify different
|
||||
* callback functions for each logical bitstream.
|
||||
|
@ -131,6 +132,7 @@ typedef int (*OggzReadPage) (OGGZ * oggz, const ogg_page * og,
|
|||
* \retval 0 Success
|
||||
* \retval OGGZ_ERR_BAD_OGGZ \a oggz does not refer to an existing OGGZ
|
||||
* \retval OGGZ_ERR_INVALID Operation not suitable for this OGGZ
|
||||
* \retval OGGZ_ERR_OUT_OF_MEMORY Out of memory
|
||||
*
|
||||
* \note Values of \a serialno other than -1 allows you to specify different
|
||||
* callback functions for each logical bitstream.
|
||||
|
@ -156,6 +158,7 @@ int oggz_set_read_page (OGGZ * oggz, long serialno,
|
|||
* returning OGGZ_STOP_OK
|
||||
* \retval OGGZ_ERR_STOP_ERR Reading was stopped by a user callback
|
||||
* returning OGGZ_STOP_ERR
|
||||
* \retval OGGZ_ERR_OUT_OF_MEMORY Out of memory
|
||||
*/
|
||||
long oggz_read (OGGZ * oggz, long n);
|
||||
|
||||
|
|
|
@ -258,6 +258,30 @@ long oggz_seek_packets (OGGZ * oggz, long serialno, long packets, int whence);
|
|||
* \{
|
||||
*/
|
||||
|
||||
/**
|
||||
* Retrieve the preroll of a logical bitstream.
|
||||
* \param oggz An OGGZ handle
|
||||
* \param serialno Identify the logical bitstream in \a oggz
|
||||
* \returns The preroll of the specified logical bitstream.
|
||||
* \retval OGGZ_ERR_BAD_SERIALNO \a serialno does not identify an existing
|
||||
* logical bitstream in \a oggz.
|
||||
* \retval OGGZ_ERR_BAD_OGGZ \a oggz does not refer to an existing OGGZ
|
||||
*/
|
||||
int oggz_get_preroll (OGGZ * oggz, long serialno);
|
||||
|
||||
/**
|
||||
* Specify the preroll of a logical bitstream.
|
||||
* \param oggz An OGGZ handle
|
||||
* \param serialno Identify the logical bitstream in \a oggz to attach
|
||||
* this preroll to.
|
||||
* \param preroll The preroll
|
||||
* \returns 0 Success
|
||||
* \retval OGGZ_ERR_BAD_SERIALNO \a serialno does not identify an existing
|
||||
* logical bitstream in \a oggz.
|
||||
* \retval OGGZ_ERR_BAD_OGGZ \a oggz does not refer to an existing OGGZ
|
||||
*/
|
||||
int oggz_set_preroll (OGGZ * oggz, long serialno, int preroll);
|
||||
|
||||
/**
|
||||
* Retrieve the granuleshift of a logical bitstream.
|
||||
* \param oggz An OGGZ handle
|
||||
|
@ -424,6 +448,8 @@ typedef int (*OggzOrder) (OGGZ * oggz, ogg_packet * op, void * target,
|
|||
* \retval 0 Success
|
||||
* \retval OGGZ_ERR_BAD_OGGZ \a oggz does not refer to an existing OGGZ
|
||||
* \retval OGGZ_ERR_INVALID Operation not suitable for this OGGZ
|
||||
* \retval OGGZ_ERR_BAD_SERIALNO \a serialno does not identify an existing
|
||||
* logical bitstream in \a oggz, and is not -1
|
||||
*/
|
||||
int oggz_set_order (OGGZ * oggz, long serialno, OggzOrder order,
|
||||
void * user_data);
|
||||
|
|
|
@ -48,6 +48,7 @@ typedef void OggzTable;
|
|||
/**
|
||||
* Instantiate a new OggzTable
|
||||
* \returns A new OggzTable
|
||||
* \retval NULL Could not allocate memory for table
|
||||
*/
|
||||
OggzTable *
|
||||
oggz_table_new (void);
|
||||
|
|
|
@ -177,6 +177,7 @@ int oggz_write_set_hungry_callback (OGGZ * oggz,
|
|||
* 32 bits, ie. within the range (-(2^31), (2^31)-1)
|
||||
* \retval OGGZ_ERR_BAD_OGGZ \a oggz does not refer to an existing OGGZ
|
||||
* \retval OGGZ_ERR_INVALID Operation not suitable for this OGGZ
|
||||
* \retval OGGZ_ERR_OUT_OF_MEMORY Unable to allocate memory to queue packet
|
||||
*
|
||||
* \note If \a op->b_o_s is initialized to \a -1 before calling
|
||||
* oggz_write_feed(), Oggz will fill it in with the appropriate
|
||||
|
|
|
@ -1,12 +0,0 @@
|
|||
diff -r 070e364189c8 media/liboggz/include/oggz/oggz_off_t_generated.h
|
||||
--- a/media/liboggz/include/oggz/oggz_off_t_generated.h Wed Nov 26 09:04:13 2008 -0600
|
||||
+++ b/media/liboggz/include/oggz/oggz_off_t_generated.h Thu Nov 27 17:56:54 2008 +0800
|
||||
@@ -59,7 +59,7 @@
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
-#ifdef __APPLE__
|
||||
+#if defined(__APPLE__) || defined(SOLARIS)
|
||||
typedef off_t oggz_off_t;
|
||||
#else
|
||||
typedef loff_t oggz_off_t;
|
|
@ -46,6 +46,7 @@ LIBRARY_NAME = oggz
|
|||
FORCE_STATIC_LIB= 1
|
||||
|
||||
CSRCS = \
|
||||
dirac.c \
|
||||
metric_internal.c \
|
||||
oggz.c \
|
||||
oggz_auto.c \
|
||||
|
|
|
@ -0,0 +1,194 @@
|
|||
/*
|
||||
dirac.c
|
||||
*/
|
||||
|
||||
#ifdef WIN32
|
||||
#include "config_win32.h"
|
||||
#else
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_STDINT_H
|
||||
#include <stdint.h>
|
||||
#endif
|
||||
|
||||
#include "dirac.h"
|
||||
|
||||
|
||||
typedef struct
|
||||
dirac_bs_s
|
||||
{
|
||||
uint8_t *p_start;
|
||||
uint8_t *p;
|
||||
uint8_t *p_end;
|
||||
|
||||
int i_left; /* i_count number of available bits */
|
||||
} dirac_bs_t;
|
||||
|
||||
static inline void
|
||||
dirac_bs_init( dirac_bs_t *s, void *p_data, int i_data )
|
||||
{
|
||||
s->p_start = p_data;
|
||||
s->p = p_data;
|
||||
s->p_end = s->p + i_data;
|
||||
s->i_left = 8;
|
||||
}
|
||||
|
||||
static inline ogg_uint32_t
|
||||
dirac_bs_read( dirac_bs_t *s, int i_count )
|
||||
{
|
||||
static ogg_uint32_t i_mask[33] =
|
||||
{ 0x00,
|
||||
0x01, 0x03, 0x07, 0x0f,
|
||||
0x1f, 0x3f, 0x7f, 0xff,
|
||||
0x1ff, 0x3ff, 0x7ff, 0xfff,
|
||||
0x1fff, 0x3fff, 0x7fff, 0xffff,
|
||||
0x1ffff, 0x3ffff, 0x7ffff, 0xfffff,
|
||||
0x1fffff, 0x3fffff, 0x7fffff, 0xffffff,
|
||||
0x1ffffff, 0x3ffffff, 0x7ffffff, 0xfffffff,
|
||||
0x1fffffff,0x3fffffff,0x7fffffff,0xffffffff};
|
||||
int i_shr;
|
||||
ogg_uint32_t i_result = 0;
|
||||
|
||||
while( i_count > 0 )
|
||||
{
|
||||
if( s->p >= s->p_end )
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if( ( i_shr = s->i_left - i_count ) >= 0 )
|
||||
{
|
||||
/* more in the buffer than requested */
|
||||
i_result |= ( *s->p >> i_shr )&i_mask[i_count];
|
||||
s->i_left -= i_count;
|
||||
if( s->i_left == 0 )
|
||||
{
|
||||
s->p++;
|
||||
s->i_left = 8;
|
||||
}
|
||||
return( i_result );
|
||||
}
|
||||
else
|
||||
{
|
||||
/* less in the buffer than requested */
|
||||
i_result |= (*s->p&i_mask[s->i_left]) << -i_shr;
|
||||
i_count -= s->i_left;
|
||||
s->p++;
|
||||
s->i_left = 8;
|
||||
}
|
||||
}
|
||||
|
||||
return( i_result );
|
||||
}
|
||||
|
||||
static inline void
|
||||
dirac_bs_skip( dirac_bs_t *s, int i_count )
|
||||
{
|
||||
s->i_left -= i_count;
|
||||
|
||||
while( s->i_left <= 0 )
|
||||
{
|
||||
s->p++;
|
||||
s->i_left += 8;
|
||||
}
|
||||
}
|
||||
|
||||
static ogg_uint32_t
|
||||
dirac_uint ( dirac_bs_t *p_bs )
|
||||
{
|
||||
ogg_uint32_t count = 0, value = 0;
|
||||
while( !dirac_bs_read ( p_bs, 1 ) ) {
|
||||
count++;
|
||||
value <<= 1;
|
||||
value |= dirac_bs_read ( p_bs, 1 );
|
||||
}
|
||||
|
||||
return (1<<count) - 1 + value;
|
||||
}
|
||||
|
||||
static int
|
||||
dirac_bool ( dirac_bs_t *p_bs )
|
||||
{
|
||||
return dirac_bs_read ( p_bs, 1 );
|
||||
}
|
||||
|
||||
void
|
||||
dirac_parse_info (dirac_info *info, unsigned char * data, long len)
|
||||
{
|
||||
dirac_bs_t bs;
|
||||
ogg_uint32_t video_format;
|
||||
|
||||
static const struct {
|
||||
ogg_uint32_t fps_numerator, fps_denominator;
|
||||
} dirac_frate_tbl[] = { /* table 10.3 */
|
||||
{1,1}, /* this first value is never used */
|
||||
{24000,1001}, {24,1}, {25,1}, {30000,1001}, {30,1},
|
||||
{50,1}, {60000,1001}, {60,1}, {15000,1001}, {25,2}
|
||||
};
|
||||
|
||||
static const ogg_uint32_t dirac_vidfmt_frate[] = { /* table C.1 */
|
||||
1, 9, 10, 9, 10, 9, 10, 4, 3, 7, 6, 4, 3, 7, 6, 2, 2, 7, 6, 7, 6
|
||||
};
|
||||
|
||||
static const int dirac_source_sampling[] = { /* extracted from table C.1 */
|
||||
0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0
|
||||
};
|
||||
static const int dirac_top_field_first[] = { /* from table C.1 */
|
||||
0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
|
||||
};
|
||||
|
||||
static const struct {
|
||||
ogg_uint32_t width, height;
|
||||
} dirac_fsize_tbl[] = { /* table 10.3 framesize */
|
||||
{640,460}, {24,1}, {176,120}, {352,240}, {352,288},
|
||||
{704,480}, {704,576}, {720,480}, {720,576},
|
||||
{1280, 720}, {1280, 720}, {1920, 1080}, {1920, 1080},
|
||||
{1920, 1080}, {1920, 1080}, {2048, 1080}, {4096, 2160}
|
||||
};
|
||||
|
||||
/* read in useful bits from sequence header */
|
||||
dirac_bs_init( &bs, data, len);
|
||||
dirac_bs_skip( &bs, 13*8); /* parse_info_header */
|
||||
info->major_version = dirac_uint( &bs ); /* major_version */
|
||||
info->minor_version = dirac_uint( &bs ); /* minor_version */
|
||||
info->profile = dirac_uint( &bs ); /* profile */
|
||||
info->level = dirac_uint( &bs ); /* level */
|
||||
info->video_format = video_format = dirac_uint( &bs ); /* index */
|
||||
|
||||
info->width = dirac_fsize_tbl[video_format].width;
|
||||
info->height = dirac_fsize_tbl[video_format].height;
|
||||
if (dirac_bool( &bs )) {
|
||||
info->width = dirac_uint( &bs ); /* frame_width */
|
||||
info->height = dirac_uint( &bs ); /* frame_height */
|
||||
}
|
||||
|
||||
if (dirac_bool( &bs )) {
|
||||
info->chroma_format = dirac_uint( &bs ); /* chroma_format */
|
||||
}
|
||||
|
||||
if (dirac_bool( &bs )) { /* custom_scan_format_flag */
|
||||
int scan_format = dirac_uint( &bs ); /* scan_format */
|
||||
if (scan_format < 2) {
|
||||
info->interlaced = scan_format;
|
||||
} else { /* other scan_format values are reserved */
|
||||
info->interlaced = 0;
|
||||
}
|
||||
} else { /* no custom scan_format, use the preset value */
|
||||
info->interlaced = dirac_source_sampling[video_format];
|
||||
}
|
||||
/* field order is set by video_format and cannot be custom */
|
||||
info->top_field_first = dirac_top_field_first[video_format];
|
||||
|
||||
info->fps_numerator = dirac_frate_tbl[dirac_vidfmt_frate[video_format]].fps_numerator;
|
||||
info->fps_denominator = dirac_frate_tbl[dirac_vidfmt_frate[video_format]].fps_denominator;
|
||||
if (dirac_bool( &bs )) {
|
||||
ogg_uint32_t frame_rate_index = dirac_uint( &bs );
|
||||
info->fps_numerator = dirac_frate_tbl[frame_rate_index].fps_numerator;
|
||||
info->fps_denominator = dirac_frate_tbl[frame_rate_index].fps_denominator;
|
||||
if (frame_rate_index == 0) {
|
||||
info->fps_numerator = dirac_uint( &bs );
|
||||
info->fps_denominator = dirac_uint( &bs );
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* dirac.h
|
||||
*/
|
||||
|
||||
#ifndef _DIRAC_H
|
||||
#define _DIRAC_H
|
||||
|
||||
#include <ogg/ogg.h>
|
||||
|
||||
typedef struct {
|
||||
ogg_uint32_t major_version;
|
||||
ogg_uint32_t minor_version;
|
||||
ogg_uint32_t profile;
|
||||
ogg_uint32_t level;
|
||||
ogg_uint32_t chroma_format;
|
||||
ogg_uint32_t video_format;
|
||||
|
||||
ogg_uint32_t width;
|
||||
ogg_uint32_t height;
|
||||
ogg_uint32_t fps_numerator;
|
||||
ogg_uint32_t fps_denominator;
|
||||
|
||||
ogg_uint32_t interlaced;
|
||||
ogg_uint32_t top_field_first;
|
||||
} dirac_info;
|
||||
|
||||
extern void dirac_parse_info (dirac_info *info, unsigned char *data, long len);
|
||||
|
||||
#endif
|
|
@ -38,6 +38,37 @@
|
|||
|
||||
#include "oggz_private.h"
|
||||
|
||||
static ogg_int64_t
|
||||
oggz_metric_dirac (OGGZ * oggz, long serialno,
|
||||
ogg_int64_t granulepos, void * user_data)
|
||||
{
|
||||
oggz_stream_t * stream;
|
||||
ogg_int64_t iframe, pframe;
|
||||
ogg_uint32_t pt;
|
||||
ogg_uint16_t dist;
|
||||
ogg_uint16_t delay;
|
||||
ogg_int64_t dt;
|
||||
ogg_int64_t units;
|
||||
|
||||
stream = oggz_get_stream (oggz, serialno);
|
||||
if (stream == NULL) return -1;
|
||||
|
||||
iframe = granulepos >> stream->granuleshift;
|
||||
pframe = granulepos - (iframe << stream->granuleshift);
|
||||
pt = (iframe + pframe) >> 9;
|
||||
delay = pframe >> 9;
|
||||
dt = (ogg_int64_t)pt - delay;
|
||||
|
||||
units = dt * stream->granulerate_d / stream->granulerate_n;
|
||||
|
||||
#ifdef DEBUG
|
||||
printf ("oggz_..._granuleshift: serialno %010lu Got frame or field %lld (%lld + %lld): %lld units\n",
|
||||
serialno, dt, iframe, pframe, units);
|
||||
#endif
|
||||
|
||||
return units;
|
||||
}
|
||||
|
||||
static ogg_int64_t
|
||||
oggz_metric_default_granuleshift (OGGZ * oggz, long serialno,
|
||||
ogg_int64_t granulepos, void * user_data)
|
||||
|
@ -56,7 +87,7 @@ oggz_metric_default_granuleshift (OGGZ * oggz, long serialno,
|
|||
units = granulepos * stream->granulerate_d / stream->granulerate_n;
|
||||
|
||||
#ifdef DEBUG
|
||||
printf ("oggz_..._granuleshift: serialno %010ld Got frame %lld (%lld + %lld): %lld units\n",
|
||||
printf ("oggz_..._granuleshift: serialno %010lu Got frame %lld (%lld + %lld): %lld units\n",
|
||||
serialno, granulepos, iframe, pframe, units);
|
||||
#endif
|
||||
|
||||
|
@ -96,6 +127,10 @@ oggz_metric_update (OGGZ * oggz, long serialno)
|
|||
return oggz_set_metric_internal (oggz, serialno,
|
||||
oggz_metric_default_linear,
|
||||
NULL, 1);
|
||||
} else if (oggz_stream_get_content (oggz, serialno) == OGGZ_CONTENT_DIRAC) {
|
||||
return oggz_set_metric_internal (oggz, serialno,
|
||||
oggz_metric_dirac,
|
||||
NULL, 1);
|
||||
} else {
|
||||
return oggz_set_metric_internal (oggz, serialno,
|
||||
oggz_metric_default_granuleshift,
|
||||
|
@ -162,7 +197,7 @@ oggz_get_granulerate (OGGZ * oggz, long serialno,
|
|||
if (stream == NULL) return OGGZ_ERR_BAD_SERIALNO;
|
||||
|
||||
*granulerate_n = stream->granulerate_n;
|
||||
*granulerate_d = stream->granulerate_d;
|
||||
*granulerate_d = stream->granulerate_d / OGGZ_AUTO_MULT;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -96,6 +96,10 @@ oggz_new (int flags)
|
|||
oggz->cb_next = 0;
|
||||
|
||||
oggz->streams = oggz_vector_new ();
|
||||
if (oggz->streams == NULL) {
|
||||
goto err_oggz_new;
|
||||
}
|
||||
|
||||
oggz->all_at_eos = 0;
|
||||
|
||||
oggz->metric = NULL;
|
||||
|
@ -106,14 +110,26 @@ oggz_new (int flags)
|
|||
oggz->order_user_data = NULL;
|
||||
|
||||
oggz->packet_buffer = oggz_dlist_new ();
|
||||
if (oggz->packet_buffer == NULL) {
|
||||
goto err_streams_new;
|
||||
}
|
||||
|
||||
if (OGGZ_CONFIG_WRITE && (oggz->flags & OGGZ_WRITE)) {
|
||||
oggz_write_init (oggz);
|
||||
if (oggz_write_init (oggz) == NULL)
|
||||
goto err_packet_buffer_new;
|
||||
} else if (OGGZ_CONFIG_READ) {
|
||||
oggz_read_init (oggz);
|
||||
}
|
||||
|
||||
return oggz;
|
||||
|
||||
err_packet_buffer_new:
|
||||
oggz_free (oggz->packet_buffer);
|
||||
err_streams_new:
|
||||
oggz_free (oggz->streams);
|
||||
err_oggz_new:
|
||||
oggz_free (oggz);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
OGGZ *
|
||||
|
@ -325,7 +341,10 @@ oggz_add_stream (OGGZ * oggz, long serialno)
|
|||
|
||||
ogg_stream_init (&stream->ogg_stream, (int)serialno);
|
||||
|
||||
oggz_comments_init (stream);
|
||||
if (oggz_comments_init (stream) == -1) {
|
||||
oggz_free (stream);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
stream->content = OGGZ_CONTENT_UNKNOWN;
|
||||
stream->numheaders = 3; /* Default to 3 headers for Ogg logical bitstreams */
|
||||
|
@ -598,6 +617,8 @@ oggz_set_order (OGGZ * oggz, long serialno,
|
|||
oggz->order_user_data = user_data;
|
||||
} else {
|
||||
stream = oggz_get_stream (oggz, serialno);
|
||||
if (stream == NULL) return OGGZ_ERR_BAD_SERIALNO;
|
||||
|
||||
stream->order = order;
|
||||
stream->order_user_data = user_data;
|
||||
}
|
||||
|
@ -621,3 +642,28 @@ oggz_map_return_value_to_error (int cb_ret)
|
|||
}
|
||||
}
|
||||
|
||||
const char *
|
||||
oggz_content_type (OggzStreamContent content)
|
||||
{
|
||||
/* 20080805:
|
||||
* Re: http://lists.xiph.org/pipermail/ogg-dev/2008-July/001108.html
|
||||
*
|
||||
* "The ISO C standard, in section 6.7.2.2 "enumeration specifiers",
|
||||
* paragraph 4, says
|
||||
*
|
||||
* Each enumerated type shall be compatible with *char*, a signed
|
||||
* integer type, or an unsigned integer type. The choice of type is
|
||||
* implementation-defined, but shall be capable of representing the
|
||||
* values of all the members of the declaration."
|
||||
*
|
||||
* -- http://gcc.gnu.org/ml/gcc-bugs/2000-09/msg00271.html
|
||||
*
|
||||
* Hence, we cannot remove the (content < 0) guard, even though current
|
||||
* GCC gives a warning for it -- other compilers (including earlier GCC
|
||||
* versions) may use a signed type for enum OggzStreamContent.
|
||||
*/
|
||||
if (content < 0 || content >= OGGZ_CONTENT_UNKNOWN)
|
||||
return NULL;
|
||||
|
||||
return oggz_auto_codec_ident[content].content_type;
|
||||
}
|
||||
|
|
|
@ -47,6 +47,7 @@
|
|||
|
||||
#include "oggz_private.h"
|
||||
#include "oggz_byteorder.h"
|
||||
#include "dirac.h"
|
||||
|
||||
#include <oggz/oggz_stream.h>
|
||||
|
||||
|
@ -66,8 +67,6 @@ int oggz_set_metric_linear (OGGZ * oggz, long serialno,
|
|||
#define INT32_BE_AT(x) _be_32((*(ogg_int32_t *)(x)))
|
||||
#define INT64_LE_AT(x) _le_64((*(ogg_int64_t *)(x)))
|
||||
|
||||
#define OGGZ_AUTO_MULT 1000Ull
|
||||
|
||||
static int
|
||||
oggz_stream_set_numheaders (OGGZ * oggz, long serialno, int numheaders)
|
||||
{
|
||||
|
@ -84,13 +83,13 @@ oggz_stream_set_numheaders (OGGZ * oggz, long serialno, int numheaders)
|
|||
}
|
||||
|
||||
static int
|
||||
auto_speex (OGGZ * oggz, ogg_packet * op, long serialno, void * user_data)
|
||||
auto_speex (OGGZ * oggz, long serialno, unsigned char * data, long length, void * user_data)
|
||||
{
|
||||
unsigned char * header = op->packet;
|
||||
unsigned char * header = data;
|
||||
ogg_int64_t granule_rate = 0;
|
||||
int numheaders;
|
||||
|
||||
if (op->bytes < 68) return 0;
|
||||
if (length < 68) return 0;
|
||||
|
||||
granule_rate = (ogg_int64_t) INT32_LE_AT(&header[36]);
|
||||
#ifdef DEBUG
|
||||
|
@ -99,6 +98,8 @@ auto_speex (OGGZ * oggz, ogg_packet * op, long serialno, void * user_data)
|
|||
|
||||
oggz_set_granulerate (oggz, serialno, granule_rate, OGGZ_AUTO_MULT);
|
||||
|
||||
oggz_set_preroll (oggz, serialno, 3);
|
||||
|
||||
numheaders = (ogg_int64_t) INT32_LE_AT(&header[68]) + 2;
|
||||
oggz_stream_set_numheaders (oggz, serialno, numheaders);
|
||||
|
||||
|
@ -106,12 +107,12 @@ auto_speex (OGGZ * oggz, ogg_packet * op, long serialno, void * user_data)
|
|||
}
|
||||
|
||||
static int
|
||||
auto_vorbis (OGGZ * oggz, ogg_packet * op, long serialno, void * user_data)
|
||||
auto_vorbis (OGGZ * oggz, long serialno, unsigned char * data, long length, void * user_data)
|
||||
{
|
||||
unsigned char * header = op->packet;
|
||||
unsigned char * header = data;
|
||||
ogg_int64_t granule_rate = 0;
|
||||
|
||||
if (op->bytes < 30) return 0;
|
||||
if (length < 30) return 0;
|
||||
|
||||
granule_rate = (ogg_int64_t) INT32_LE_AT(&header[12]);
|
||||
#ifdef DEBUG
|
||||
|
@ -120,6 +121,8 @@ auto_vorbis (OGGZ * oggz, ogg_packet * op, long serialno, void * user_data)
|
|||
|
||||
oggz_set_granulerate (oggz, serialno, granule_rate, OGGZ_AUTO_MULT);
|
||||
|
||||
oggz_set_preroll (oggz, serialno, 2);
|
||||
|
||||
oggz_stream_set_numheaders (oggz, serialno, 3);
|
||||
|
||||
return 1;
|
||||
|
@ -137,15 +140,15 @@ static int intlog(int num) {
|
|||
#endif
|
||||
|
||||
static int
|
||||
auto_theora (OGGZ * oggz, ogg_packet * op, long serialno, void * user_data)
|
||||
auto_theora (OGGZ * oggz, long serialno, unsigned char * data, long length, void * user_data)
|
||||
{
|
||||
unsigned char * header = op->packet;
|
||||
unsigned char * header = data;
|
||||
ogg_int32_t fps_numerator, fps_denominator;
|
||||
char keyframe_granule_shift = 0;
|
||||
int keyframe_shift;
|
||||
|
||||
/* TODO: this should check against 42 for the relevant version numbers */
|
||||
if (op->bytes < 41) return 0;
|
||||
if (length < 41) return 0;
|
||||
|
||||
fps_numerator = INT32_BE_AT(&header[22]);
|
||||
fps_denominator = INT32_BE_AT(&header[26]);
|
||||
|
@ -175,13 +178,14 @@ auto_theora (OGGZ * oggz, ogg_packet * op, long serialno, void * user_data)
|
|||
OGGZ_AUTO_MULT * (ogg_int64_t)fps_denominator);
|
||||
oggz_set_granuleshift (oggz, serialno, keyframe_shift);
|
||||
|
||||
|
||||
oggz_stream_set_numheaders (oggz, serialno, 3);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
auto_annodex (OGGZ * oggz, ogg_packet * op, long serialno, void * user_data)
|
||||
auto_annodex (OGGZ * oggz, long serialno, unsigned char * data, long length, void * user_data)
|
||||
{
|
||||
/* Apply a zero metric */
|
||||
oggz_set_granulerate (oggz, serialno, 0, 1);
|
||||
|
@ -190,12 +194,12 @@ auto_annodex (OGGZ * oggz, ogg_packet * op, long serialno, void * user_data)
|
|||
}
|
||||
|
||||
static int
|
||||
auto_anxdata (OGGZ * oggz, ogg_packet * op, long serialno, void * user_data)
|
||||
auto_anxdata (OGGZ * oggz, long serialno, unsigned char * data, long length, void * user_data)
|
||||
{
|
||||
unsigned char * header = op->packet;
|
||||
unsigned char * header = data;
|
||||
ogg_int64_t granule_rate_numerator = 0, granule_rate_denominator = 0;
|
||||
|
||||
if (op->bytes < 28) return 0;
|
||||
if (length < 28) return 0;
|
||||
|
||||
granule_rate_numerator = INT64_LE_AT(&header[8]);
|
||||
granule_rate_denominator = INT64_LE_AT(&header[16]);
|
||||
|
@ -212,17 +216,17 @@ auto_anxdata (OGGZ * oggz, ogg_packet * op, long serialno, void * user_data)
|
|||
}
|
||||
|
||||
static int
|
||||
auto_flac0 (OGGZ * oggz, ogg_packet * op, long serialno, void * user_data)
|
||||
auto_flac0 (OGGZ * oggz, long serialno, unsigned char * data, long length, void * user_data)
|
||||
{
|
||||
unsigned char * header = op->packet;
|
||||
unsigned char * header = data;
|
||||
ogg_int64_t granule_rate = 0;
|
||||
|
||||
granule_rate = (ogg_int64_t) (header[14] << 12) | (header[15] << 4) |
|
||||
granule_rate = (ogg_int64_t) (header[14] << 12) | (header[15] << 4) |
|
||||
((header[16] >> 4)&0xf);
|
||||
#ifdef DEBUG
|
||||
printf ("Got flac rate %d\n", (int)granule_rate);
|
||||
#endif
|
||||
|
||||
|
||||
oggz_set_granulerate (oggz, serialno, granule_rate, OGGZ_AUTO_MULT);
|
||||
|
||||
oggz_stream_set_numheaders (oggz, serialno, 3);
|
||||
|
@ -231,15 +235,15 @@ auto_flac0 (OGGZ * oggz, ogg_packet * op, long serialno, void * user_data)
|
|||
}
|
||||
|
||||
static int
|
||||
auto_flac (OGGZ * oggz, ogg_packet * op, long serialno, void * user_data)
|
||||
auto_flac (OGGZ * oggz, long serialno, unsigned char * data, long length, void * user_data)
|
||||
{
|
||||
unsigned char * header = op->packet;
|
||||
unsigned char * header = data;
|
||||
ogg_int64_t granule_rate = 0;
|
||||
int numheaders;
|
||||
|
||||
if (op->bytes < 51) return 0;
|
||||
if (length < 51) return 0;
|
||||
|
||||
granule_rate = (ogg_int64_t) (header[27] << 12) | (header[28] << 4) |
|
||||
granule_rate = (ogg_int64_t) (header[27] << 12) | (header[28] << 4) |
|
||||
((header[29] >> 4)&0xf);
|
||||
#ifdef DEBUG
|
||||
printf ("Got flac rate %d\n", (int)granule_rate);
|
||||
|
@ -258,12 +262,12 @@ auto_flac (OGGZ * oggz, ogg_packet * op, long serialno, void * user_data)
|
|||
* http://wiki.xiph.org/index.php/OggPCM2
|
||||
*/
|
||||
static int
|
||||
auto_oggpcm2 (OGGZ * oggz, ogg_packet * op, long serialno, void * user_data)
|
||||
auto_oggpcm2 (OGGZ * oggz, long serialno, unsigned char * data, long length, void * user_data)
|
||||
{
|
||||
unsigned char * header = op->packet;
|
||||
unsigned char * header = data;
|
||||
ogg_int64_t granule_rate;
|
||||
|
||||
if (op->bytes < 28) return 0;
|
||||
if (length < 28) return 0;
|
||||
|
||||
granule_rate = (ogg_int64_t) INT32_BE_AT(&header[16]);
|
||||
#ifdef DEBUG
|
||||
|
@ -278,13 +282,13 @@ auto_oggpcm2 (OGGZ * oggz, ogg_packet * op, long serialno, void * user_data)
|
|||
}
|
||||
|
||||
static int
|
||||
auto_celt (OGGZ * oggz, ogg_packet * op, long serialno, void * user_data)
|
||||
auto_celt (OGGZ * oggz, long serialno, unsigned char * data, long length, void * user_data)
|
||||
{
|
||||
unsigned char * header = op->packet;
|
||||
unsigned char * header = data;
|
||||
ogg_int64_t granule_rate = 0;
|
||||
int numheaders;
|
||||
|
||||
if (op->bytes < 56) return 0;
|
||||
if (length < 56) return 0;
|
||||
|
||||
granule_rate = (ogg_int64_t) INT32_LE_AT(&header[40]);
|
||||
#ifdef DEBUG
|
||||
|
@ -300,17 +304,17 @@ auto_celt (OGGZ * oggz, ogg_packet * op, long serialno, void * user_data)
|
|||
}
|
||||
|
||||
static int
|
||||
auto_cmml (OGGZ * oggz, ogg_packet * op, long serialno, void * user_data)
|
||||
auto_cmml (OGGZ * oggz, long serialno, unsigned char * data, long length, void * user_data)
|
||||
{
|
||||
unsigned char * header = op->packet;
|
||||
unsigned char * header = data;
|
||||
ogg_int64_t granule_rate_numerator = 0, granule_rate_denominator = 0;
|
||||
int granuleshift;
|
||||
|
||||
if (op->bytes < 28) return 0;
|
||||
if (length < 28) return 0;
|
||||
|
||||
granule_rate_numerator = INT64_LE_AT(&header[12]);
|
||||
granule_rate_denominator = INT64_LE_AT(&header[20]);
|
||||
if (op->bytes > 28)
|
||||
if (length > 28)
|
||||
granuleshift = (int)header[28];
|
||||
else
|
||||
granuleshift = 0;
|
||||
|
@ -331,14 +335,14 @@ auto_cmml (OGGZ * oggz, ogg_packet * op, long serialno, void * user_data)
|
|||
}
|
||||
|
||||
static int
|
||||
auto_kate (OGGZ * oggz, ogg_packet * op, long serialno, void * user_data)
|
||||
auto_kate (OGGZ * oggz, long serialno, unsigned char * data, long length, void * user_data)
|
||||
{
|
||||
unsigned char * header = op->packet;
|
||||
unsigned char * header = data;
|
||||
ogg_int32_t gps_numerator, gps_denominator;
|
||||
unsigned char granule_shift = 0;
|
||||
int numheaders;
|
||||
|
||||
if (op->bytes < 64) return 0;
|
||||
if (length < 64) return 0;
|
||||
|
||||
gps_numerator = INT32_LE_AT(&header[24]);
|
||||
gps_denominator = INT32_LE_AT(&header[28]);
|
||||
|
@ -354,21 +358,49 @@ auto_kate (OGGZ * oggz, ogg_packet * op, long serialno, void * user_data)
|
|||
oggz_set_granulerate (oggz, serialno, gps_numerator,
|
||||
OGGZ_AUTO_MULT * gps_denominator);
|
||||
oggz_set_granuleshift (oggz, serialno, granule_shift);
|
||||
|
||||
|
||||
oggz_stream_set_numheaders (oggz, serialno, numheaders);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
auto_fisbone (OGGZ * oggz, ogg_packet * op, long serialno, void * user_data)
|
||||
auto_dirac (OGGZ * oggz, long serialno, unsigned char * data, long length, void * user_data)
|
||||
{
|
||||
unsigned char * header = op->packet;
|
||||
int granule_shift = 22; /* not a typo */
|
||||
dirac_info *info;
|
||||
|
||||
info = oggz_malloc(sizeof(dirac_info));
|
||||
if (info == NULL) return -1;
|
||||
|
||||
dirac_parse_info(info, data, length);
|
||||
|
||||
#ifdef DEBUG
|
||||
printf ("Got dirac fps %d/%d granule_shift %d\n",
|
||||
fps_numerator, fps_denominator, granule_shift);
|
||||
#endif
|
||||
|
||||
/* the granulerate is twice the frame rate (in order to handle interlace) */
|
||||
oggz_set_granulerate (oggz, serialno,
|
||||
2 * (ogg_int64_t)info->fps_numerator,
|
||||
OGGZ_AUTO_MULT * (ogg_int64_t)info->fps_denominator);
|
||||
oggz_set_granuleshift (oggz, serialno, granule_shift);
|
||||
|
||||
oggz_stream_set_numheaders (oggz, serialno, 0);
|
||||
|
||||
oggz_free(info);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
auto_fisbone (OGGZ * oggz, long serialno, unsigned char * data, long length, void * user_data)
|
||||
{
|
||||
unsigned char * header = data;
|
||||
long fisbone_serialno; /* The serialno referred to in this fisbone */
|
||||
ogg_int64_t granule_rate_numerator = 0, granule_rate_denominator = 0;
|
||||
int granuleshift, numheaders;
|
||||
|
||||
if (op->bytes < 48) return 0;
|
||||
if (length < 48) return 0;
|
||||
|
||||
fisbone_serialno = (long) INT32_LE_AT(&header[12]);
|
||||
|
||||
|
@ -380,7 +412,7 @@ auto_fisbone (OGGZ * oggz, ogg_packet * op, long serialno, void * user_data)
|
|||
granuleshift = (int)header[48];
|
||||
|
||||
#ifdef DEBUG
|
||||
printf ("Got fisbone granulerate %lld/%lld, granuleshift %d for serialno %010ld\n",
|
||||
printf ("Got fisbone granulerate %lld/%lld, granuleshift %d for serialno %010lu\n",
|
||||
granule_rate_numerator, granule_rate_denominator, granuleshift,
|
||||
fisbone_serialno);
|
||||
#endif
|
||||
|
@ -393,23 +425,18 @@ auto_fisbone (OGGZ * oggz, ogg_packet * op, long serialno, void * user_data)
|
|||
/* Increment the number of headers for this stream */
|
||||
numheaders = oggz_stream_get_numheaders (oggz, serialno);
|
||||
oggz_stream_set_numheaders (oggz, serialno, numheaders+1);
|
||||
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
auto_fishead (OGGZ * oggz, ogg_packet * op, long serialno, void * user_data)
|
||||
auto_fishead (OGGZ * oggz, long serialno, unsigned char * data, long length, void * user_data)
|
||||
{
|
||||
if (!op->b_o_s)
|
||||
{
|
||||
return auto_fisbone(oggz, op, serialno, user_data);
|
||||
}
|
||||
|
||||
oggz_set_granulerate (oggz, serialno, 0, 1);
|
||||
|
||||
/* For skeleton, numheaders will get incremented as each header is seen */
|
||||
oggz_stream_set_numheaders (oggz, serialno, 1);
|
||||
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -423,27 +450,28 @@ typedef struct {
|
|||
int encountered_first_data_packet;
|
||||
} auto_calc_speex_info_t;
|
||||
|
||||
static ogg_int64_t
|
||||
static ogg_int64_t
|
||||
auto_calc_speex(ogg_int64_t now, oggz_stream_t *stream, ogg_packet *op) {
|
||||
|
||||
|
||||
/*
|
||||
* on the first (b_o_s) packet, set calculate_data to be the number
|
||||
* of speex frames per packet
|
||||
*/
|
||||
|
||||
auto_calc_speex_info_t *info
|
||||
auto_calc_speex_info_t *info
|
||||
= (auto_calc_speex_info_t *)stream->calculate_data;
|
||||
|
||||
if (stream->calculate_data == NULL) {
|
||||
stream->calculate_data = malloc(sizeof(auto_calc_speex_info_t));
|
||||
stream->calculate_data = oggz_malloc(sizeof(auto_calc_speex_info_t));
|
||||
if (stream->calculate_data == NULL) return -1;
|
||||
info = stream->calculate_data;
|
||||
info->encountered_first_data_packet = 0;
|
||||
info->packet_size =
|
||||
info->packet_size =
|
||||
(*(int *)(op->packet + 64)) * (*(int *)(op->packet + 56));
|
||||
info->headers_encountered = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
if (info->headers_encountered < 2) {
|
||||
info->headers_encountered += 1;
|
||||
} else {
|
||||
|
@ -458,7 +486,7 @@ auto_calc_speex(ogg_int64_t now, oggz_stream_t *stream, ogg_packet *op) {
|
|||
if (stream->last_granulepos > 0) {
|
||||
return stream->last_granulepos + info->packet_size;
|
||||
}
|
||||
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -476,19 +504,21 @@ typedef struct {
|
|||
int encountered_first_data_packet;
|
||||
} auto_calc_celt_info_t;
|
||||
|
||||
static ogg_int64_t
|
||||
static ogg_int64_t
|
||||
auto_calc_celt (ogg_int64_t now, oggz_stream_t *stream, ogg_packet *op) {
|
||||
|
||||
|
||||
/*
|
||||
* on the first (b_o_s) packet, set calculate_data to be the number
|
||||
* of celt frames per packet
|
||||
*/
|
||||
|
||||
auto_calc_celt_info_t *info
|
||||
auto_calc_celt_info_t *info
|
||||
= (auto_calc_celt_info_t *)stream->calculate_data;
|
||||
|
||||
if (stream->calculate_data == NULL) {
|
||||
stream->calculate_data = malloc(sizeof(auto_calc_celt_info_t));
|
||||
stream->calculate_data = oggz_malloc(sizeof(auto_calc_celt_info_t));
|
||||
if (stream->calculate_data == NULL) return -1;
|
||||
|
||||
info = stream->calculate_data;
|
||||
info->encountered_first_data_packet = 0;
|
||||
|
||||
|
@ -501,7 +531,7 @@ auto_calc_celt (ogg_int64_t now, oggz_stream_t *stream, ogg_packet *op) {
|
|||
info->headers_encountered = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
if (info->headers_encountered < 2) {
|
||||
info->headers_encountered += 1;
|
||||
} else {
|
||||
|
@ -516,7 +546,7 @@ auto_calc_celt (ogg_int64_t now, oggz_stream_t *stream, ogg_packet *op) {
|
|||
if (stream->last_granulepos > 0) {
|
||||
return stream->last_granulepos + info->packet_size;
|
||||
}
|
||||
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -527,8 +557,8 @@ auto_calc_celt (ogg_int64_t now, oggz_stream_t *stream, ogg_packet *op) {
|
|||
* Header packets are marked by a set MSB in the first byte. Inter packets
|
||||
* are marked by a set 2MSB in the first byte. Intra packets (keyframes)
|
||||
* are any that are left over ;-)
|
||||
*
|
||||
* (see http://www.theora.org/doc/Theora_I_spec.pdf for the theora
|
||||
*
|
||||
* (see http://www.theora.org/doc/Theora_I_spec.pdf for the theora
|
||||
* specification)
|
||||
*/
|
||||
|
||||
|
@ -537,7 +567,7 @@ typedef struct {
|
|||
} auto_calc_theora_info_t;
|
||||
|
||||
|
||||
static ogg_int64_t
|
||||
static ogg_int64_t
|
||||
auto_calc_theora(ogg_int64_t now, oggz_stream_t *stream, ogg_packet *op) {
|
||||
|
||||
long keyframe_no;
|
||||
|
@ -553,13 +583,14 @@ auto_calc_theora(ogg_int64_t now, oggz_stream_t *stream, ogg_packet *op) {
|
|||
if (first_byte & 0x80)
|
||||
{
|
||||
if (info == NULL) {
|
||||
stream->calculate_data = malloc(sizeof(auto_calc_theora_info_t));
|
||||
stream->calculate_data = oggz_malloc(sizeof(auto_calc_theora_info_t));
|
||||
if (stream->calculate_data == NULL) return -1;
|
||||
info = stream->calculate_data;
|
||||
}
|
||||
info->encountered_first_data_packet = 0;
|
||||
return (ogg_int64_t)0;
|
||||
}
|
||||
|
||||
|
||||
/* known granulepos */
|
||||
if (now > (ogg_int64_t)(-1)) {
|
||||
info->encountered_first_data_packet = 1;
|
||||
|
@ -586,7 +617,7 @@ auto_calc_theora(ogg_int64_t now, oggz_stream_t *stream, ogg_packet *op) {
|
|||
return stream->last_granulepos + 1;
|
||||
}
|
||||
|
||||
keyframe_shift = stream->granuleshift;
|
||||
keyframe_shift = stream->granuleshift;
|
||||
/*
|
||||
* retrieve last keyframe number
|
||||
*/
|
||||
|
@ -596,12 +627,12 @@ auto_calc_theora(ogg_int64_t now, oggz_stream_t *stream, ogg_packet *op) {
|
|||
*/
|
||||
keyframe_no += (stream->last_granulepos & ((1 << keyframe_shift) - 1)) + 1;
|
||||
return ((ogg_int64_t)keyframe_no) << keyframe_shift;
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
static ogg_int64_t
|
||||
auto_rcalc_theora(ogg_int64_t next_packet_gp, oggz_stream_t *stream,
|
||||
auto_rcalc_theora(ogg_int64_t next_packet_gp, oggz_stream_t *stream,
|
||||
ogg_packet *this_packet, ogg_packet *next_packet) {
|
||||
|
||||
int keyframe = (int)(next_packet_gp >> stream->granuleshift);
|
||||
|
@ -642,9 +673,9 @@ auto_rcalc_theora(ogg_int64_t next_packet_gp, oggz_stream_t *stream,
|
|||
* (additional information is not required)
|
||||
*
|
||||
* The two blocksizes can be determined from the first header packet, by reading
|
||||
* byte 28. 1 << (packet[28] >> 4) == long_size.
|
||||
* byte 28. 1 << (packet[28] >> 4) == long_size.
|
||||
* 1 << (packet[28] & 0xF) == short_size.
|
||||
*
|
||||
*
|
||||
* (see http://xiph.org/vorbis/doc/Vorbis_I_spec.html for specification)
|
||||
*/
|
||||
|
||||
|
@ -658,13 +689,13 @@ typedef struct {
|
|||
int log2_num_modes;
|
||||
int mode_sizes[1];
|
||||
} auto_calc_vorbis_info_t;
|
||||
|
||||
|
||||
static ogg_int64_t
|
||||
|
||||
static ogg_int64_t
|
||||
auto_calc_vorbis(ogg_int64_t now, oggz_stream_t *stream, ogg_packet *op) {
|
||||
|
||||
auto_calc_vorbis_info_t *info;
|
||||
|
||||
|
||||
if (stream->calculate_data == NULL) {
|
||||
/*
|
||||
* on the first (b_o_s) packet, determine the long and short sizes,
|
||||
|
@ -672,11 +703,13 @@ auto_calc_vorbis(ogg_int64_t now, oggz_stream_t *stream, ogg_packet *op) {
|
|||
*/
|
||||
int short_size;
|
||||
int long_size;
|
||||
|
||||
|
||||
long_size = 1 << (op->packet[28] >> 4);
|
||||
short_size = 1 << (op->packet[28] & 0xF);
|
||||
|
||||
stream->calculate_data = malloc(sizeof(auto_calc_vorbis_info_t));
|
||||
stream->calculate_data = oggz_malloc(sizeof(auto_calc_vorbis_info_t));
|
||||
if (stream->calculate_data == NULL) return -1;
|
||||
|
||||
info = (auto_calc_vorbis_info_t *)stream->calculate_data;
|
||||
info->nln_increments[3] = long_size >> 1;
|
||||
info->nln_increments[2] = 3 * (long_size >> 2) - (short_size >> 2);
|
||||
|
@ -698,10 +731,10 @@ auto_calc_vorbis(ogg_int64_t now, oggz_stream_t *stream, ogg_packet *op) {
|
|||
/*
|
||||
* the code pages, a whole bunch of other fairly useless stuff, AND,
|
||||
* RIGHT AT THE END (of a bunch of variable-length compressed rubbish that
|
||||
* basically has only one actual set of values that everyone uses BUT YOU
|
||||
* basically has only one actual set of values that everyone uses BUT YOU
|
||||
* CAN'T BE SURE OF THAT, OH NO YOU CAN'T) is the only piece of data that's
|
||||
* actually useful to us - the packet modes (because it's inconceivable to
|
||||
* think people might want _just that_ and nothing else, you know, for
|
||||
* think people might want _just that_ and nothing else, you know, for
|
||||
* seeking and stuff).
|
||||
*
|
||||
* Fortunately, because of the mandate that non-used bits must be zero
|
||||
|
@ -716,11 +749,12 @@ auto_calc_vorbis(ogg_int64_t now, oggz_stream_t *stream, ogg_packet *op) {
|
|||
int size_check;
|
||||
int *mode_size_ptr;
|
||||
int i;
|
||||
|
||||
/*
|
||||
size_t size_realloc_bytes;
|
||||
|
||||
/*
|
||||
* This is the format of the mode data at the end of the packet for all
|
||||
* Vorbis Version 1 :
|
||||
*
|
||||
*
|
||||
* [ 6:number_of_modes ]
|
||||
* [ 1:size | 16:window_type(0) | 16:transform_type(0) | 8:mapping ]
|
||||
* [ 1:size | 16:window_type(0) | 16:transform_type(0) | 8:mapping ]
|
||||
|
@ -733,7 +767,7 @@ auto_calc_vorbis(ogg_int64_t now, oggz_stream_t *stream, ogg_packet *op) {
|
|||
* 0 0 0 0 0 1 0 0
|
||||
* 0 0 1 0 0 0 0 0
|
||||
* 0 0 1 0 0 0 0 0
|
||||
* 0 0 1|0 0 0 0 0
|
||||
* 0 0 1|0 0 0 0 0
|
||||
* 0 0 0 0|0|0 0 0
|
||||
* 0 0 0 0 0 0 0 0
|
||||
* 0 0 0 0|0 0 0 0
|
||||
|
@ -743,11 +777,11 @@ auto_calc_vorbis(ogg_int64_t now, oggz_stream_t *stream, ogg_packet *op) {
|
|||
* 0 0 0 0 0 0 0 0 V
|
||||
* 0 0 0|0 0 0 0 0
|
||||
* 0 0 0 0 0 0 0 0
|
||||
* 0 0 1|0 0 0 0 0
|
||||
* 0 0|1|0 0 0 0 0
|
||||
*
|
||||
*
|
||||
* i.e. each entry is an important bit, 32 bits of 0, 8 bits of blah, a
|
||||
* 0 0 1|0 0 0 0 0
|
||||
* 0 0|1|0 0 0 0 0
|
||||
*
|
||||
*
|
||||
* i.e. each entry is an important bit, 32 bits of 0, 8 bits of blah, a
|
||||
* bit of 1.
|
||||
* Let's find our last 1 bit first.
|
||||
*
|
||||
|
@ -765,7 +799,7 @@ auto_calc_vorbis(ogg_int64_t now, oggz_stream_t *stream, ogg_packet *op) {
|
|||
|
||||
while (1)
|
||||
{
|
||||
|
||||
|
||||
/*
|
||||
* from current_pos-5:(offset+1) to current_pos-1:(offset+1) should
|
||||
* be zero
|
||||
|
@ -773,15 +807,15 @@ auto_calc_vorbis(ogg_int64_t now, oggz_stream_t *stream, ogg_packet *op) {
|
|||
offset = (offset + 7) % 8;
|
||||
if (offset == 7)
|
||||
current_pos -= 1;
|
||||
|
||||
if
|
||||
|
||||
if
|
||||
(
|
||||
((current_pos[-5] & ~((1 << (offset + 1)) - 1)) != 0)
|
||||
||
|
||||
current_pos[-4] != 0
|
||||
||
|
||||
current_pos[-3] != 0
|
||||
||
|
||||
current_pos[-4] != 0
|
||||
||
|
||||
current_pos[-3] != 0
|
||||
||
|
||||
current_pos[-2] != 0
|
||||
||
|
||||
((current_pos[-1] & ((1 << (offset + 1)) - 1)) != 0)
|
||||
|
@ -789,12 +823,12 @@ auto_calc_vorbis(ogg_int64_t now, oggz_stream_t *stream, ogg_packet *op) {
|
|||
{
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
size += 1;
|
||||
|
||||
|
||||
current_pos -= 5;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (offset > 4) {
|
||||
size_check = (current_pos[0] >> (offset - 5)) & 0x3F;
|
||||
|
@ -804,10 +838,10 @@ auto_calc_vorbis(ogg_int64_t now, oggz_stream_t *stream, ogg_packet *op) {
|
|||
/* shift to appropriate position */
|
||||
size_check <<= (5 - offset);
|
||||
/* or in part of byte from current_pos - 1 */
|
||||
size_check |= (current_pos[-1] & ~((1 << (offset + 3)) - 1)) >>
|
||||
size_check |= (current_pos[-1] & ~((1 << (offset + 3)) - 1)) >>
|
||||
(offset + 3);
|
||||
}
|
||||
|
||||
|
||||
size_check += 1;
|
||||
#ifdef DEBUG
|
||||
if (size_check != size)
|
||||
|
@ -816,13 +850,16 @@ auto_calc_vorbis(ogg_int64_t now, oggz_stream_t *stream, ogg_packet *op) {
|
|||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* store mode size information in our info struct
|
||||
*/
|
||||
stream->calculate_data = realloc(stream->calculate_data,
|
||||
sizeof(auto_calc_vorbis_info_t) + (size - 1) * sizeof(int));
|
||||
info = (auto_calc_vorbis_info_t *)(stream->calculate_data);
|
||||
|
||||
/* Check that size to be realloc'd doesn't overflow */
|
||||
size_realloc_bytes = sizeof(auto_calc_vorbis_info_t) + (size - 1) * sizeof(int);
|
||||
if (size_realloc_bytes < sizeof (auto_calc_vorbis_info_t)) return -1;
|
||||
|
||||
/* Store mode size information in our info struct */
|
||||
info = realloc(stream->calculate_data, size_realloc_bytes);
|
||||
if (info == NULL) return -1;
|
||||
|
||||
stream->calculate_data = info;
|
||||
|
||||
i = -1;
|
||||
while ((1 << (++i)) < size);
|
||||
info->log2_num_modes = i;
|
||||
|
@ -837,9 +874,9 @@ auto_calc_vorbis(ogg_int64_t now, oggz_stream_t *stream, ogg_packet *op) {
|
|||
*mode_size_ptr++ = (current_pos[0] >> offset) & 0x1;
|
||||
current_pos += 5;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -847,7 +884,7 @@ auto_calc_vorbis(ogg_int64_t now, oggz_stream_t *stream, ogg_packet *op) {
|
|||
|
||||
return -1;
|
||||
|
||||
{
|
||||
{
|
||||
/*
|
||||
* we're in a data packet! First we need to get the mode of the packet,
|
||||
* and from the mode, the size
|
||||
|
@ -858,7 +895,7 @@ auto_calc_vorbis(ogg_int64_t now, oggz_stream_t *stream, ogg_packet *op) {
|
|||
|
||||
mode = (op->packet[0] >> 1) & ((1 << info->log2_num_modes) - 1);
|
||||
size = info->mode_sizes[mode];
|
||||
|
||||
|
||||
/*
|
||||
* if we have a working granulepos, we use it, but only if we can't
|
||||
* calculate a valid gp value.
|
||||
|
@ -884,28 +921,28 @@ auto_calc_vorbis(ogg_int64_t now, oggz_stream_t *stream, ogg_packet *op) {
|
|||
return -1;
|
||||
}
|
||||
|
||||
result = stream->last_granulepos +
|
||||
result = stream->last_granulepos +
|
||||
(
|
||||
(info->last_was_long ? info->long_size : info->short_size)
|
||||
+
|
||||
(info->last_was_long ? info->long_size : info->short_size)
|
||||
+
|
||||
(size ? info->long_size : info->short_size)
|
||||
) / 4;
|
||||
info->last_was_long = size;
|
||||
|
||||
return result;
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
ogg_int64_t
|
||||
auto_rcalc_vorbis(ogg_int64_t next_packet_gp, oggz_stream_t *stream,
|
||||
ogg_packet *this_packet, ogg_packet *next_packet) {
|
||||
|
||||
auto_calc_vorbis_info_t *info =
|
||||
auto_calc_vorbis_info_t *info =
|
||||
(auto_calc_vorbis_info_t *)stream->calculate_data;
|
||||
|
||||
int mode =
|
||||
int mode =
|
||||
(this_packet->packet[0] >> 1) & ((1 << info->log2_num_modes) - 1);
|
||||
int this_size = info->mode_sizes[mode] ? info->long_size : info->short_size;
|
||||
int next_size;
|
||||
|
@ -940,13 +977,15 @@ typedef struct {
|
|||
int encountered_first_data_packet;
|
||||
} auto_calc_flac_info_t;
|
||||
|
||||
static ogg_int64_t
|
||||
static ogg_int64_t
|
||||
auto_calc_flac (ogg_int64_t now, oggz_stream_t *stream, ogg_packet *op)
|
||||
{
|
||||
auto_calc_flac_info_t *info;
|
||||
|
||||
if (stream->calculate_data == NULL) {
|
||||
stream->calculate_data = malloc(sizeof(auto_calc_flac_info_t));
|
||||
stream->calculate_data = oggz_malloc(sizeof(auto_calc_flac_info_t));
|
||||
if (stream->calculate_data == NULL) return -1;
|
||||
|
||||
info = (auto_calc_flac_info_t *)stream->calculate_data;
|
||||
info->previous_gp = 0;
|
||||
info->encountered_first_data_packet = 0;
|
||||
|
@ -1045,31 +1084,32 @@ const oggz_auto_contenttype_t oggz_auto_codec_ident[] = {
|
|||
{"Annodex", 8, "Annodex", auto_annodex, NULL, NULL},
|
||||
{"fishead", 7, "Skeleton", auto_fishead, NULL, NULL},
|
||||
{"fLaC", 4, "Flac0", auto_flac0, auto_calc_flac, NULL},
|
||||
{"\177FLAC", 4, "Flac", auto_flac, auto_calc_flac, NULL},
|
||||
{"\177FLAC", 5, "Flac", auto_flac, auto_calc_flac, NULL},
|
||||
{"AnxData", 7, "AnxData", auto_anxdata, NULL, NULL},
|
||||
{"CELT ", 8, "CELT", auto_celt, auto_calc_celt, NULL},
|
||||
{"\200kate\0\0\0", 8, "Kate", auto_kate, NULL, NULL},
|
||||
{"BBCD\0", 5, "Dirac", auto_dirac, NULL, NULL},
|
||||
{"", 0, "Unknown", NULL, NULL, NULL}
|
||||
};
|
||||
};
|
||||
|
||||
static int
|
||||
oggz_auto_identify (OGGZ * oggz, long serialno, unsigned char * data, long len)
|
||||
{
|
||||
int i;
|
||||
|
||||
|
||||
for (i = 0; i < OGGZ_CONTENT_UNKNOWN; i++)
|
||||
{
|
||||
const oggz_auto_contenttype_t *codec = oggz_auto_codec_ident + i;
|
||||
|
||||
|
||||
if (len >= codec->bos_str_len &&
|
||||
memcmp (data, codec->bos_str, codec->bos_str_len) == 0) {
|
||||
|
||||
|
||||
oggz_stream_set_content (oggz, serialno, i);
|
||||
|
||||
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
oggz_stream_set_content (oggz, serialno, OGGZ_CONTENT_UNKNOWN);
|
||||
return 0;
|
||||
}
|
||||
|
@ -1087,27 +1127,44 @@ oggz_auto_identify_packet (OGGZ * oggz, ogg_packet * op, long serialno)
|
|||
}
|
||||
|
||||
int
|
||||
oggz_auto_get_granulerate (OGGZ * oggz, ogg_packet * op, long serialno,
|
||||
void * user_data)
|
||||
oggz_auto_read_bos_page (OGGZ * oggz, ogg_page * og, long serialno,
|
||||
void * user_data)
|
||||
{
|
||||
int content = 0;
|
||||
|
||||
content = oggz_stream_get_content(oggz, serialno);
|
||||
if (content < 0 || content >= OGGZ_CONTENT_UNKNOWN) {
|
||||
return 0;
|
||||
} else if (content == OGGZ_CONTENT_SKELETON && !ogg_page_bos(og)) {
|
||||
return auto_fisbone(oggz, serialno, og->body, og->body_len, user_data);
|
||||
} else {
|
||||
return oggz_auto_codec_ident[content].reader(oggz, serialno, og->body, og->body_len, user_data);
|
||||
}
|
||||
|
||||
oggz_auto_codec_ident[content].reader(oggz, op, serialno, user_data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ogg_int64_t
|
||||
oggz_auto_calculate_granulepos(int content, ogg_int64_t now,
|
||||
int
|
||||
oggz_auto_read_bos_packet (OGGZ * oggz, ogg_packet * op, long serialno,
|
||||
void * user_data)
|
||||
{
|
||||
int content = 0;
|
||||
|
||||
content = oggz_stream_get_content(oggz, serialno);
|
||||
if (content < 0 || content >= OGGZ_CONTENT_UNKNOWN) {
|
||||
return 0;
|
||||
} else if (content == OGGZ_CONTENT_SKELETON && !op->b_o_s) {
|
||||
return auto_fisbone(oggz, serialno, op->packet, op->bytes, user_data);
|
||||
} else {
|
||||
return oggz_auto_codec_ident[content].reader(oggz, serialno, op->packet, op->bytes, user_data);
|
||||
}
|
||||
}
|
||||
|
||||
ogg_int64_t
|
||||
oggz_auto_calculate_granulepos(int content, ogg_int64_t now,
|
||||
oggz_stream_t *stream, ogg_packet *op) {
|
||||
if (oggz_auto_codec_ident[content].calculator != NULL) {
|
||||
ogg_int64_t r = oggz_auto_codec_ident[content].calculator(now, stream, op);
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
return now;
|
||||
}
|
||||
|
|
|
@ -429,7 +429,7 @@ This was the Theora header for theora-alpha2:
|
|||
*/
|
||||
|
||||
/**
|
||||
* Kate bitstream version 0.1
|
||||
* Kate bitstream version 0.x
|
||||
*
|
||||
* Default field type: LITTLE ENDIAN unsigned integer
|
||||
|
||||
|
@ -445,7 +445,7 @@ This was the Theora header for theora-alpha2:
|
|||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| text encoding | directionality| reserved - 0 | granule shift | 12-15
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| reserved - 0 | 16-19
|
||||
| cw sh | canvas width | ch sh | canvcas height | 16-19
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| reserved - 0 | 20-23
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
|
@ -470,6 +470,8 @@ This was the Theora header for theora-alpha2:
|
|||
| category (continued) | 60-63
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
|
||||
since bitstream 0.3: cw sh, canvas width, ch sh, canvas height
|
||||
|
||||
*/
|
||||
|
||||
int oggz_auto_identify (OGGZ *oggz, ogg_page *og, long serialno);
|
||||
|
|
|
@ -39,10 +39,13 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <limits.h> /* ULONG_MAX */
|
||||
#ifndef WIN32
|
||||
#include <strings.h>
|
||||
#endif
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include "oggz_private.h"
|
||||
#include "oggz_vector.h"
|
||||
|
||||
|
@ -55,12 +58,26 @@
|
|||
#endif
|
||||
|
||||
|
||||
/* Ensure comment vector length can be expressed in 32 bits */
|
||||
static unsigned long
|
||||
oggz_comment_len (const char * s)
|
||||
{
|
||||
size_t len;
|
||||
|
||||
if (s == NULL) return 0;
|
||||
|
||||
len = strlen (s);
|
||||
return (unsigned long) MIN(len, 0xFFFFFFFF);
|
||||
}
|
||||
|
||||
static char *
|
||||
oggz_strdup (const char * s)
|
||||
{
|
||||
char * ret;
|
||||
if (s == NULL) return NULL;
|
||||
ret = oggz_malloc (strlen(s) + 1);
|
||||
ret = oggz_malloc (oggz_comment_len(s) + 1);
|
||||
if (ret == NULL) return NULL;
|
||||
|
||||
return strcpy (ret, s);
|
||||
}
|
||||
|
||||
|
@ -93,11 +110,6 @@ oggz_index_len (const char * s, char c, int len)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
#if 0
|
||||
static void comment_init(char **comments, int* length, char *vendor_string);
|
||||
static void comment_add(char **comments, int* length, char *tag, char *val);
|
||||
#endif
|
||||
|
||||
/*
|
||||
Comments will be stored in the Vorbis style.
|
||||
It is describled in the "Structure" section of
|
||||
|
@ -134,47 +146,6 @@ The comment header is decoded as follows:
|
|||
buf[base+1]=(char)(((val)>>8)&0xff); \
|
||||
buf[base+2]=(char)((val)&0xff);
|
||||
|
||||
#if 0
|
||||
static void
|
||||
comment_init(char **comments, int* length, char *vendor_string)
|
||||
{
|
||||
int vendor_length=strlen(vendor_string);
|
||||
int user_comment_list_length=0;
|
||||
int len=4+vendor_length+4;
|
||||
char *p=(char*)oggz_malloc(len);
|
||||
if(p==NULL){
|
||||
}
|
||||
writeint(p, 0, vendor_length);
|
||||
memcpy(p+4, vendor_string, vendor_length);
|
||||
writeint(p, 4+vendor_length, user_comment_list_length);
|
||||
*length=len;
|
||||
*comments=p;
|
||||
}
|
||||
|
||||
static void
|
||||
comment_add(char **comments, int* length, char *tag, char *val)
|
||||
{
|
||||
char* p=*comments;
|
||||
int vendor_length=readint(p, 0);
|
||||
int user_comment_list_length=readint(p, 4+vendor_length);
|
||||
int tag_len=(tag?strlen(tag):0);
|
||||
int val_len=strlen(val);
|
||||
int len=(*length)+4+tag_len+val_len;
|
||||
|
||||
p=(char*)oggz_realloc(p, len);
|
||||
if(p==NULL){
|
||||
}
|
||||
|
||||
writeint(p, *length, tag_len+val_len); /* length of comment */
|
||||
if(tag) memcpy(p+*length+4, tag, tag_len); /* comment */
|
||||
memcpy(p+*length+4+tag_len, val, val_len); /* comment */
|
||||
writeint(p, 4+vendor_length, user_comment_list_length+1);
|
||||
|
||||
*comments=p;
|
||||
*length=len;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int
|
||||
oggz_comment_validate_byname (const char * name, const char * value)
|
||||
{
|
||||
|
@ -204,6 +175,8 @@ oggz_comment_new (const char * name, const char * value)
|
|||
if (!oggz_comment_validate_byname (name, value)) return NULL;
|
||||
|
||||
comment = oggz_malloc (sizeof (OggzComment));
|
||||
if (comment == NULL) return NULL;
|
||||
|
||||
comment->name = oggz_strdup (name);
|
||||
comment->value = oggz_strdup (value);
|
||||
|
||||
|
@ -271,7 +244,10 @@ oggz_comment_set_vendor (OGGZ * oggz, long serialno, const char * vendor_string)
|
|||
if (oggz == NULL) return OGGZ_ERR_BAD_OGGZ;
|
||||
|
||||
stream = oggz_get_stream (oggz, serialno);
|
||||
if (stream == NULL) stream = oggz_add_stream (oggz, serialno);
|
||||
if (stream == NULL)
|
||||
stream = oggz_add_stream (oggz, serialno);
|
||||
if (stream == NULL)
|
||||
return OGGZ_ERR_OUT_OF_MEMORY;
|
||||
|
||||
if (oggz->flags & OGGZ_WRITE) {
|
||||
if (OGGZ_CONFIG_WRITE) {
|
||||
|
@ -377,7 +353,10 @@ oggz_comment_add (OGGZ * oggz, long serialno, const OggzComment * comment)
|
|||
if (oggz == NULL) return OGGZ_ERR_BAD_OGGZ;
|
||||
|
||||
stream = oggz_get_stream (oggz, serialno);
|
||||
if (stream == NULL) stream = oggz_add_stream (oggz, serialno);
|
||||
if (stream == NULL)
|
||||
stream = oggz_add_stream (oggz, serialno);
|
||||
if (stream == NULL)
|
||||
return OGGZ_ERR_OUT_OF_MEMORY;
|
||||
|
||||
if (oggz->flags & OGGZ_WRITE) {
|
||||
if (OGGZ_CONFIG_WRITE) {
|
||||
|
@ -408,7 +387,10 @@ oggz_comment_add_byname (OGGZ * oggz, long serialno,
|
|||
if (oggz == NULL) return OGGZ_ERR_BAD_OGGZ;
|
||||
|
||||
stream = oggz_get_stream (oggz, serialno);
|
||||
if (stream == NULL) stream = oggz_add_stream (oggz, serialno);
|
||||
if (stream == NULL)
|
||||
stream = oggz_add_stream (oggz, serialno);
|
||||
if (stream == NULL)
|
||||
return OGGZ_ERR_OUT_OF_MEMORY;
|
||||
|
||||
if (oggz->flags & OGGZ_WRITE) {
|
||||
if (OGGZ_CONFIG_WRITE) {
|
||||
|
@ -523,6 +505,8 @@ oggz_comments_init (oggz_stream_t * stream)
|
|||
{
|
||||
stream->vendor = NULL;
|
||||
stream->comments = oggz_vector_new ();
|
||||
if (stream->comments == NULL) return -1;
|
||||
|
||||
oggz_vector_set_cmp (stream->comments, (OggzCmpFunc) oggz_comment_cmp, NULL);
|
||||
|
||||
return 0;
|
||||
|
@ -618,6 +602,26 @@ oggz_comments_decode (OGGZ * oggz, long serialno,
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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) */
|
||||
assert (*accum != 0 || delta != 0);
|
||||
|
||||
/* Check for integer overflow */
|
||||
if (delta > ULONG_MAX - (*accum))
|
||||
return 0;
|
||||
|
||||
*accum += delta;
|
||||
|
||||
return *accum;
|
||||
}
|
||||
|
||||
long
|
||||
oggz_comments_encode (OGGZ * oggz, long serialno,
|
||||
unsigned char * buf, long length)
|
||||
|
@ -625,16 +629,20 @@ oggz_comments_encode (OGGZ * oggz, long serialno,
|
|||
oggz_stream_t * stream;
|
||||
char * c = (char *)buf;
|
||||
const OggzComment * comment;
|
||||
int nb_fields = 0, vendor_length = 0, field_length;
|
||||
long actual_length, remaining = length;
|
||||
int nb_fields = 0, vendor_length = 0;
|
||||
unsigned long actual_length = 0, remaining = length, field_length;
|
||||
|
||||
/* Deal with sign of length first */
|
||||
if (length < 0) return 0;
|
||||
|
||||
stream = oggz_get_stream (oggz, serialno);
|
||||
if (stream == NULL) return OGGZ_ERR_BAD_SERIALNO;
|
||||
|
||||
/* Vendor string */
|
||||
if (stream->vendor)
|
||||
vendor_length = strlen (stream->vendor);
|
||||
actual_length = 4 + vendor_length;
|
||||
vendor_length = oggz_comment_len (stream->vendor);
|
||||
if (accum_length (&actual_length, 4 + vendor_length) == 0)
|
||||
return 0;
|
||||
#ifdef DEBUG
|
||||
printf ("oggz_comments_encode: vendor = %s\n", stream->vendor);
|
||||
#endif
|
||||
|
@ -644,9 +652,14 @@ oggz_comments_encode (OGGZ * oggz, long serialno,
|
|||
|
||||
for (comment = oggz_comment_first (oggz, serialno); comment;
|
||||
comment = oggz_comment_next (oggz, serialno, comment)) {
|
||||
actual_length += 4 + strlen (comment->name); /* [size]"name" */
|
||||
if (comment->value)
|
||||
actual_length += 1 + strlen (comment->value); /* "=value" */
|
||||
/* [size]"name" */
|
||||
if (accum_length (&actual_length, 4 + oggz_comment_len (comment->name)) == 0)
|
||||
return 0;
|
||||
if (comment->value) {
|
||||
/* "=value" */
|
||||
if (accum_length (&actual_length, 1 + oggz_comment_len (comment->value)) == 0)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
printf ("oggz_comments_encode: %s = %s\n",
|
||||
|
@ -656,7 +669,11 @@ oggz_comments_encode (OGGZ * oggz, long serialno,
|
|||
nb_fields++;
|
||||
}
|
||||
|
||||
actual_length++; /* framing bit */
|
||||
/* 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;
|
||||
|
||||
|
@ -666,7 +683,7 @@ oggz_comments_encode (OGGZ * oggz, long serialno,
|
|||
c += 4;
|
||||
|
||||
if (stream->vendor) {
|
||||
field_length = strlen (stream->vendor);
|
||||
field_length = oggz_comment_len (stream->vendor);
|
||||
memcpy (c, stream->vendor, MIN (field_length, remaining));
|
||||
c += field_length; remaining -= field_length;
|
||||
if (remaining <= 0 ) return actual_length;
|
||||
|
@ -680,16 +697,16 @@ oggz_comments_encode (OGGZ * oggz, long serialno,
|
|||
for (comment = oggz_comment_first (oggz, serialno); comment;
|
||||
comment = oggz_comment_next (oggz, serialno, comment)) {
|
||||
|
||||
field_length = strlen (comment->name); /* [size]"name" */
|
||||
field_length = oggz_comment_len (comment->name); /* [size]"name" */
|
||||
if (comment->value)
|
||||
field_length += 1 + strlen (comment->value); /* "=value" */
|
||||
field_length += 1 + oggz_comment_len (comment->value); /* "=value" */
|
||||
|
||||
remaining -= 4;
|
||||
if (remaining <= 0) return actual_length;
|
||||
writeint (c, 0, field_length);
|
||||
c += 4;
|
||||
|
||||
field_length = strlen (comment->name);
|
||||
field_length = oggz_comment_len (comment->name);
|
||||
memcpy (c, comment->name, MIN (field_length, remaining));
|
||||
c += field_length; remaining -= field_length;
|
||||
if (remaining <= 0) return actual_length;
|
||||
|
@ -700,7 +717,7 @@ oggz_comments_encode (OGGZ * oggz, long serialno,
|
|||
*c = '=';
|
||||
c++;
|
||||
|
||||
field_length = strlen (comment->value);
|
||||
field_length = oggz_comment_len (comment->value);
|
||||
memcpy (c, comment->value, MIN (field_length, remaining));
|
||||
c += field_length; remaining -= field_length;
|
||||
if (remaining <= 0) return actual_length;
|
||||
|
@ -779,11 +796,11 @@ oggz_comment_generate(OGGZ * oggz, long serialno,
|
|||
return NULL;
|
||||
}
|
||||
|
||||
c_packet = malloc(sizeof *c_packet);
|
||||
c_packet = oggz_malloc(sizeof *c_packet);
|
||||
if(c_packet) {
|
||||
memset(c_packet, 0, sizeof *c_packet);
|
||||
c_packet->packetno = 1;
|
||||
c_packet->packet = malloc(buf_size);
|
||||
c_packet->packet = oggz_malloc(buf_size);
|
||||
}
|
||||
|
||||
if(c_packet && c_packet->packet) {
|
||||
|
@ -811,7 +828,7 @@ oggz_comment_generate(OGGZ * oggz, long serialno,
|
|||
c_packet->bytes -= 1;
|
||||
}
|
||||
} else {
|
||||
free(c_packet);
|
||||
oggz_free(c_packet);
|
||||
c_packet = 0;
|
||||
}
|
||||
|
||||
|
@ -836,9 +853,9 @@ void oggz_packet_destroy(ogg_packet *packet) {
|
|||
if(packet) {
|
||||
if(packet->packet)
|
||||
{
|
||||
free(packet->packet);
|
||||
oggz_free(packet->packet);
|
||||
}
|
||||
free(packet);
|
||||
oggz_free(packet);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -38,6 +38,7 @@
|
|||
#include <stdlib.h>
|
||||
|
||||
#include "oggz_dlist.h"
|
||||
#include "oggz_macros.h"
|
||||
|
||||
typedef struct OggzDListElem {
|
||||
struct OggzDListElem * next;
|
||||
|
@ -53,11 +54,25 @@ struct _OggzDList {
|
|||
OggzDList *
|
||||
oggz_dlist_new (void) {
|
||||
|
||||
OggzDList *dlist = malloc(sizeof(OggzDList));
|
||||
|
||||
OggzDListElem * dummy_front = malloc(sizeof(OggzDListElem));
|
||||
OggzDListElem * dummy_back = malloc(sizeof(OggzDListElem));
|
||||
OggzDList *dlist;
|
||||
OggzDListElem *dummy_front, *dummy_back;
|
||||
|
||||
dlist = oggz_malloc(sizeof(OggzDList));
|
||||
if (dlist == NULL) return NULL;
|
||||
|
||||
dummy_front = oggz_malloc(sizeof(OggzDListElem));
|
||||
if (dummy_front == NULL) {
|
||||
oggz_free (dlist);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
dummy_back = oggz_malloc(sizeof(OggzDListElem));
|
||||
if (dummy_back == NULL) {
|
||||
oggz_free (dummy_front);
|
||||
oggz_free (dlist);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
dummy_front->next = dummy_back;
|
||||
dummy_front->prev = NULL;
|
||||
|
||||
|
@ -68,7 +83,6 @@ oggz_dlist_new (void) {
|
|||
dlist->tail = dummy_back;
|
||||
|
||||
return dlist;
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -77,11 +91,11 @@ oggz_dlist_delete(OggzDList *dlist) {
|
|||
OggzDListElem *p;
|
||||
|
||||
for (p = dlist->head->next; p != NULL; p = p->next) {
|
||||
free(p->prev);
|
||||
oggz_free(p->prev);
|
||||
}
|
||||
|
||||
free(dlist->tail);
|
||||
free(dlist);
|
||||
oggz_free(dlist->tail);
|
||||
oggz_free(dlist);
|
||||
|
||||
}
|
||||
|
||||
|
@ -90,22 +104,34 @@ oggz_dlist_is_empty(OggzDList *dlist) {
|
|||
return (dlist->head->next == dlist->tail);
|
||||
}
|
||||
|
||||
void
|
||||
int
|
||||
oggz_dlist_append(OggzDList *dlist, void *elem) {
|
||||
|
||||
OggzDListElem *new_elem = malloc(sizeof(OggzDListElem));
|
||||
OggzDListElem *new_elem;
|
||||
|
||||
if (dlist == NULL) return -1;
|
||||
|
||||
new_elem = oggz_malloc(sizeof(OggzDListElem));
|
||||
if (new_elem == NULL) return -1;
|
||||
|
||||
new_elem->data = elem;
|
||||
new_elem->next = dlist->tail;
|
||||
new_elem->prev = dlist->tail->prev;
|
||||
new_elem->prev->next = new_elem;
|
||||
new_elem->next->prev = new_elem;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
int
|
||||
oggz_dlist_prepend(OggzDList *dlist, void *elem) {
|
||||
|
||||
OggzDListElem *new_elem = malloc(sizeof(OggzDListElem));
|
||||
OggzDListElem *new_elem;
|
||||
|
||||
if (dlist == NULL) return -1;
|
||||
|
||||
new_elem = oggz_malloc(sizeof(OggzDListElem));
|
||||
if (new_elem == NULL) return -1;
|
||||
|
||||
new_elem->data = elem;
|
||||
new_elem->prev = dlist->head;
|
||||
|
@ -113,6 +139,7 @@ oggz_dlist_prepend(OggzDList *dlist, void *elem) {
|
|||
new_elem->prev->next = new_elem;
|
||||
new_elem->next->prev = new_elem;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -154,7 +181,7 @@ oggz_dlist_deliter(OggzDList *dlist, OggzDListIterFunc func) {
|
|||
p->prev->next = p->next;
|
||||
p->next->prev = p->prev;
|
||||
|
||||
free(p);
|
||||
oggz_free(p);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -173,7 +200,7 @@ oggz_dlist_reverse_deliter(OggzDList *dlist, OggzDListIterFunc func) {
|
|||
p->prev->next = p->next;
|
||||
p->next->prev = p->prev;
|
||||
|
||||
free(p);
|
||||
oggz_free(p);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -49,10 +49,10 @@ oggz_dlist_delete(OggzDList *dlist);
|
|||
int
|
||||
oggz_dlist_is_empty(OggzDList *dlist);
|
||||
|
||||
void
|
||||
int
|
||||
oggz_dlist_append(OggzDList *dlist, void *elem);
|
||||
|
||||
void
|
||||
int
|
||||
oggz_dlist_prepend(OggzDList *dlist, void *elem);
|
||||
|
||||
void
|
||||
|
|
|
@ -180,11 +180,15 @@ oggz_io_flush (OGGZ * oggz)
|
|||
|
||||
/* get/set functions */
|
||||
|
||||
static void
|
||||
static int
|
||||
oggz_io_init (OGGZ * oggz)
|
||||
{
|
||||
oggz->io = (OggzIO *) oggz_malloc (sizeof (OggzIO));
|
||||
if (oggz->io == NULL) return -1;
|
||||
|
||||
memset (oggz->io, 0, sizeof (OggzIO));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
|
@ -193,7 +197,10 @@ oggz_io_set_read (OGGZ * oggz, OggzIORead read, void * user_handle)
|
|||
if (oggz == NULL) return OGGZ_ERR_BAD_OGGZ;
|
||||
if (oggz->file != NULL) return OGGZ_ERR_INVALID;
|
||||
|
||||
if (oggz->io == NULL) oggz_io_init (oggz);
|
||||
if (oggz->io == NULL) {
|
||||
if (oggz_io_init (oggz) == -1)
|
||||
return OGGZ_ERR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
oggz->io->read = read;
|
||||
oggz->io->read_user_handle = user_handle;
|
||||
|
@ -218,7 +225,10 @@ oggz_io_set_write (OGGZ * oggz, OggzIOWrite write, void * user_handle)
|
|||
if (oggz == NULL) return OGGZ_ERR_BAD_OGGZ;
|
||||
if (oggz->file != NULL) return OGGZ_ERR_INVALID;
|
||||
|
||||
if (oggz->io == NULL) oggz_io_init (oggz);
|
||||
if (oggz->io == NULL) {
|
||||
if (oggz_io_init (oggz) == -1)
|
||||
return OGGZ_ERR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
oggz->io->write = write;
|
||||
oggz->io->write_user_handle = user_handle;
|
||||
|
@ -243,7 +253,10 @@ oggz_io_set_seek (OGGZ * oggz, OggzIOSeek seek, void * user_handle)
|
|||
if (oggz == NULL) return OGGZ_ERR_BAD_OGGZ;
|
||||
if (oggz->file != NULL) return OGGZ_ERR_INVALID;
|
||||
|
||||
if (oggz->io == NULL) oggz_io_init (oggz);
|
||||
if (oggz->io == NULL) {
|
||||
if (oggz_io_init (oggz) == -1)
|
||||
return OGGZ_ERR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
oggz->io->seek = seek;
|
||||
oggz->io->seek_user_handle = user_handle;
|
||||
|
@ -268,7 +281,10 @@ oggz_io_set_tell (OGGZ * oggz, OggzIOTell tell, void * user_handle)
|
|||
if (oggz == NULL) return OGGZ_ERR_BAD_OGGZ;
|
||||
if (oggz->file != NULL) return OGGZ_ERR_INVALID;
|
||||
|
||||
if (oggz->io == NULL) oggz_io_init (oggz);
|
||||
if (oggz->io == NULL) {
|
||||
if (oggz_io_init (oggz) == -1)
|
||||
return OGGZ_ERR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
oggz->io->tell = tell;
|
||||
oggz->io->tell_user_handle = user_handle;
|
||||
|
@ -293,7 +309,10 @@ oggz_io_set_flush (OGGZ * oggz, OggzIOFlush flush, void * user_handle)
|
|||
if (oggz == NULL) return OGGZ_ERR_BAD_OGGZ;
|
||||
if (oggz->file != NULL) return OGGZ_ERR_INVALID;
|
||||
|
||||
if (oggz->io == NULL) oggz_io_init (oggz);
|
||||
if (oggz->io == NULL) {
|
||||
if (oggz_io_init (oggz) == -1)
|
||||
return OGGZ_ERR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
oggz->io->flush = flush;
|
||||
oggz->io->flush_user_handle = user_handle;
|
||||
|
|
|
@ -44,6 +44,8 @@
|
|||
#include "oggz_vector.h"
|
||||
#include "oggz_dlist.h"
|
||||
|
||||
#define OGGZ_AUTO_MULT 1000Ull
|
||||
|
||||
typedef struct _OGGZ OGGZ;
|
||||
typedef struct _OggzComment OggzComment;
|
||||
typedef struct _OggzIO OggzIO;
|
||||
|
@ -277,13 +279,18 @@ oggz_get_granulerate (OGGZ * oggz, long serialno,
|
|||
ogg_int64_t * granulerate_d);
|
||||
|
||||
int oggz_set_granuleshift (OGGZ * oggz, long serialno, int granuleshift);
|
||||
|
||||
int oggz_get_granuleshift (OGGZ * oggz, long serialno);
|
||||
|
||||
int oggz_set_preroll (OGGZ * oggz, long serialno, int preroll);
|
||||
int oggz_get_preroll (OGGZ * oggz, long serialno);
|
||||
|
||||
/* oggz_auto */
|
||||
|
||||
int
|
||||
oggz_auto_get_granulerate (OGGZ * oggz, ogg_packet * op, long serialno,
|
||||
oggz_auto_read_bos_page (OGGZ * oggz, ogg_page * og, long serialno,
|
||||
void * user_data);
|
||||
int
|
||||
oggz_auto_read_bos_packet (OGGZ * oggz, ogg_packet * op, long serialno,
|
||||
void * user_data);
|
||||
|
||||
int
|
||||
|
|
|
@ -124,12 +124,10 @@ oggz_set_read_callback (OGGZ * oggz, long serialno,
|
|||
reader->read_user_data = user_data;
|
||||
} else {
|
||||
stream = oggz_get_stream (oggz, serialno);
|
||||
#if 0
|
||||
if (stream == NULL) return OGGZ_ERR_BAD_SERIALNO;
|
||||
#else
|
||||
if (stream == NULL)
|
||||
stream = oggz_add_stream (oggz, serialno);
|
||||
#endif
|
||||
if (stream == NULL)
|
||||
return OGGZ_ERR_OUT_OF_MEMORY;
|
||||
|
||||
stream->read_packet = read_packet;
|
||||
stream->read_user_data = user_data;
|
||||
|
@ -158,12 +156,10 @@ oggz_set_read_page (OGGZ * oggz, long serialno, OggzReadPage read_page,
|
|||
reader->read_page_user_data = user_data;
|
||||
} else {
|
||||
stream = oggz_get_stream (oggz, serialno);
|
||||
#if 0
|
||||
if (stream == NULL) return OGGZ_ERR_BAD_SERIALNO;
|
||||
#else
|
||||
if (stream == NULL)
|
||||
stream = oggz_add_stream (oggz, serialno);
|
||||
#endif
|
||||
if (stream == NULL)
|
||||
return OGGZ_ERR_OUT_OF_MEMORY;
|
||||
|
||||
stream->read_page = read_page;
|
||||
stream->read_page_user_data = user_data;
|
||||
|
@ -173,9 +169,10 @@ oggz_set_read_page (OGGZ * oggz, long serialno, OggzReadPage read_page,
|
|||
}
|
||||
|
||||
/*
|
||||
* oggz_get_next_page_7 (oggz, og, do_read)
|
||||
* oggz_read_get_next_page (oggz, og, do_read)
|
||||
*
|
||||
* MODIFIED COPY OF CODE FROM BELOW SEEKING STUFF
|
||||
* This differs from oggz_get_next_page() in oggz_seek.c in that it
|
||||
* does not attempt to call oggz_io_read() if the sync buffer is empty.
|
||||
*
|
||||
* retrieves the next page.
|
||||
* returns >= 0 if found; return value is offset of page start
|
||||
|
@ -183,12 +180,9 @@ oggz_set_read_page (OGGZ * oggz, long serialno, OggzReadPage read_page,
|
|||
* returns -2 if EOF was encountered
|
||||
*/
|
||||
static oggz_off_t
|
||||
oggz_get_next_page_7 (OGGZ * oggz, ogg_page * og)
|
||||
oggz_read_get_next_page (OGGZ * oggz, ogg_page * og)
|
||||
{
|
||||
OggzReader * reader = &oggz->x.reader;
|
||||
#if _UNMODIFIED
|
||||
char * buffer;
|
||||
#endif
|
||||
long bytes = 0, more;
|
||||
oggz_off_t page_offset = 0, ret;
|
||||
int found = 0;
|
||||
|
@ -198,25 +192,7 @@ oggz_get_next_page_7 (OGGZ * oggz, ogg_page * og)
|
|||
|
||||
if (more == 0) {
|
||||
page_offset = 0;
|
||||
#if _UMMODIFIED_
|
||||
buffer = ogg_sync_buffer (&reader->ogg_sync, CHUNKSIZE);
|
||||
if ((bytes = oggz_io_read (oggz, buffer, CHUNKSIZE)) == 0) {
|
||||
#if 0
|
||||
if (ferror (oggz->file)) {
|
||||
oggz_set_error (oggz, OGGZ_ERR_SYSTEM);
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if (bytes == 0) {
|
||||
return -2;
|
||||
}
|
||||
|
||||
ogg_sync_wrote(&reader->ogg_sync, bytes);
|
||||
#else
|
||||
return -2;
|
||||
#endif
|
||||
} else if (more < 0) {
|
||||
#ifdef DEBUG_VERBOSE
|
||||
printf ("get_next_page: skipped %ld bytes\n", -more);
|
||||
|
@ -258,9 +234,11 @@ oggz_read_new_pbuffer_entry(OGGZ *oggz, ogg_packet *packet,
|
|||
ogg_int64_t granulepos, long serialno, oggz_stream_t * stream,
|
||||
OggzReader *reader) {
|
||||
|
||||
OggzBufferedPacket *p = malloc(sizeof(OggzBufferedPacket));
|
||||
OggzBufferedPacket *p = oggz_malloc(sizeof(OggzBufferedPacket));
|
||||
if (p == NULL) return NULL;
|
||||
|
||||
memcpy(&(p->packet), packet, sizeof(ogg_packet));
|
||||
p->packet.packet = malloc(packet->bytes);
|
||||
p->packet.packet = oggz_malloc(packet->bytes);
|
||||
memcpy(p->packet.packet, packet->packet, packet->bytes);
|
||||
|
||||
p->calced_granulepos = granulepos;
|
||||
|
@ -275,8 +253,8 @@ oggz_read_new_pbuffer_entry(OGGZ *oggz, ogg_packet *packet,
|
|||
void
|
||||
oggz_read_free_pbuffer_entry(OggzBufferedPacket *p) {
|
||||
|
||||
free(p->packet.packet);
|
||||
free(p);
|
||||
oggz_free(p->packet.packet);
|
||||
oggz_free(p);
|
||||
|
||||
}
|
||||
|
||||
|
@ -371,30 +349,36 @@ oggz_read_sync (OGGZ * oggz)
|
|||
/* new stream ... check bos etc. */
|
||||
if ((stream = oggz_add_stream (oggz, serialno)) == NULL) {
|
||||
/* error -- could not add stream */
|
||||
return -7;
|
||||
return OGGZ_ERR_OUT_OF_MEMORY;
|
||||
}
|
||||
}
|
||||
os = &stream->ogg_stream;
|
||||
|
||||
result = ogg_stream_packetout(os, op);
|
||||
|
||||
/*
|
||||
* libogg flags "holes in the data" (which are really inconsistencies
|
||||
* in the page sequence number) by returning -1.
|
||||
*/
|
||||
if(result == -1) {
|
||||
#ifdef DEBUG
|
||||
printf ("oggz_read_sync: hole in the data\n");
|
||||
#endif
|
||||
/* We can't tolerate holes in headers, so bail out. */
|
||||
if (stream->packetno < 3) return OGGZ_ERR_HOLE_IN_DATA;
|
||||
|
||||
/* Holes in content occur in some files and pretty much don't matter,
|
||||
* so we silently swallow the notification and reget the packet.
|
||||
*/
|
||||
result = ogg_stream_packetout(os, op);
|
||||
if (result == -1) {
|
||||
#ifdef DEBUG
|
||||
/*
|
||||
* libogg flags "holes in the data" (which are really
|
||||
* inconsistencies in the page sequence number) by returning
|
||||
* -1. This occurs in some files and pretty much doesn't matter,
|
||||
* so we silently swallow the notification and reget the packet.
|
||||
* If the result is *still* -1 then something strange is happening.
|
||||
/* If the result is *still* -1 then something strange is
|
||||
* happening.
|
||||
*/
|
||||
printf ("shouldn't get here");
|
||||
#ifdef DEBUG
|
||||
printf ("Multiple holes in data!");
|
||||
#endif
|
||||
return -7;
|
||||
return OGGZ_ERR_HOLE_IN_DATA;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -418,7 +402,7 @@ oggz_read_sync (OGGZ * oggz)
|
|||
(oggz->flags & OGGZ_AUTO)
|
||||
)
|
||||
{
|
||||
oggz_auto_get_granulerate (oggz, op, serialno, NULL);
|
||||
oggz_auto_read_bos_packet (oggz, op, serialno, NULL);
|
||||
}
|
||||
|
||||
/* attempt to determine granulepos for this packet */
|
||||
|
@ -511,7 +495,7 @@ oggz_read_sync (OGGZ * oggz)
|
|||
/* If we've got a stop already, don't read more data in */
|
||||
if (cb_ret == OGGZ_STOP_OK || cb_ret == OGGZ_STOP_ERR) return cb_ret;
|
||||
|
||||
if(oggz_get_next_page_7 (oggz, &og) < 0)
|
||||
if(oggz_read_get_next_page (oggz, &og) < 0)
|
||||
return OGGZ_READ_EMPTY; /* eof. leave uninitialized */
|
||||
|
||||
serialno = ogg_page_serialno (&og);
|
||||
|
@ -523,11 +507,15 @@ oggz_read_sync (OGGZ * oggz)
|
|||
/* new stream ... check bos etc. */
|
||||
if ((stream = oggz_add_stream (oggz, serialno)) == NULL) {
|
||||
/* error -- could not add stream */
|
||||
return -7;
|
||||
return OGGZ_ERR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
/* identify stream type */
|
||||
oggz_auto_identify_page (oggz, &og, serialno);
|
||||
|
||||
/* read bos data */
|
||||
if (oggz->flags & OGGZ_AUTO)
|
||||
oggz_auto_read_bos_page (oggz, &og, serialno, NULL);
|
||||
}
|
||||
else if (oggz_stream_get_content(oggz, serialno) == OGGZ_CONTENT_ANXDATA)
|
||||
{
|
||||
|
@ -560,12 +548,6 @@ oggz_read_sync (OGGZ * oggz)
|
|||
reader->read_page (oggz, &og, serialno, reader->read_page_user_data);
|
||||
}
|
||||
|
||||
#if 0
|
||||
/* bitrate tracking; add the header's bytes here, the body bytes
|
||||
are done by packet above */
|
||||
vf->bittrack+=og.header_len*8;
|
||||
#endif
|
||||
|
||||
ogg_stream_pagein(os, &og);
|
||||
}
|
||||
|
||||
|
@ -594,28 +576,14 @@ oggz_read (OGGZ * oggz, long n)
|
|||
reader = &oggz->x.reader;
|
||||
|
||||
cb_ret = oggz_read_sync (oggz);
|
||||
|
||||
#if 0
|
||||
if (cb_ret == OGGZ_READ_EMPTY) {
|
||||
/* If there's nothing to read yet, don't return 0 (eof) */
|
||||
if (reader->current_unit == 0) cb_ret = 0;
|
||||
else {
|
||||
#if 0
|
||||
printf ("oggz_read: EMPTY, current_unit %ld != 0\n",
|
||||
reader->current_unit);
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (cb_ret == OGGZ_ERR_OUT_OF_MEMORY)
|
||||
return cb_ret;
|
||||
|
||||
while (cb_ret != OGGZ_STOP_ERR && cb_ret != OGGZ_STOP_OK &&
|
||||
bytes_read > 0 && remaining > 0) {
|
||||
bytes = MIN (remaining, CHUNKSIZE);
|
||||
buffer = ogg_sync_buffer (&reader->ogg_sync, bytes);
|
||||
if ((bytes_read = (long) oggz_io_read (oggz, buffer, bytes)) == 0) {
|
||||
/* schyeah! */
|
||||
}
|
||||
bytes_read = (long) oggz_io_read (oggz, buffer, bytes);
|
||||
if (bytes_read == OGGZ_ERR_SYSTEM) {
|
||||
return OGGZ_ERR_SYSTEM;
|
||||
}
|
||||
|
@ -627,6 +595,8 @@ oggz_read (OGGZ * oggz, long n)
|
|||
nread += bytes_read;
|
||||
|
||||
cb_ret = oggz_read_sync (oggz);
|
||||
if (cb_ret == OGGZ_ERR_OUT_OF_MEMORY)
|
||||
return cb_ret;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -678,14 +648,8 @@ oggz_read_input (OGGZ * oggz, unsigned char * buf, long n)
|
|||
reader = &oggz->x.reader;
|
||||
|
||||
cb_ret = oggz_read_sync (oggz);
|
||||
|
||||
#if 0
|
||||
if (cb_ret == OGGZ_READ_EMPTY) {
|
||||
/* If there's nothing to read yet, don't return 0 (eof) */
|
||||
if (reader->current_unit == 0) cb_ret = 0;
|
||||
else return 0;
|
||||
}
|
||||
#endif
|
||||
if (cb_ret == OGGZ_ERR_OUT_OF_MEMORY)
|
||||
return cb_ret;
|
||||
|
||||
while (cb_ret != OGGZ_STOP_ERR && cb_ret != OGGZ_STOP_OK &&
|
||||
/* !oggz->eos && */ remaining > 0) {
|
||||
|
@ -699,6 +663,8 @@ oggz_read_input (OGGZ * oggz, unsigned char * buf, long n)
|
|||
nread += bytes;
|
||||
|
||||
cb_ret = oggz_read_sync (oggz);
|
||||
if (cb_ret == OGGZ_ERR_OUT_OF_MEMORY)
|
||||
return cb_ret;
|
||||
}
|
||||
|
||||
if (cb_ret == OGGZ_STOP_ERR) oggz_purge (oggz);
|
||||
|
|
|
@ -234,14 +234,6 @@ oggz_get_next_page (OGGZ * oggz, ogg_page * og)
|
|||
printf ("get_next_page: bytes == 0, returning -2\n");
|
||||
#endif
|
||||
return -2;
|
||||
#if 0
|
||||
} else if (oggz->file && feof (oggz->file)) {
|
||||
#ifdef DEBUG_VERBOSE
|
||||
printf ("get_next_page: feof (oggz->file), returning -2\n");
|
||||
#endif
|
||||
clearerr (oggz->file);
|
||||
return -2;
|
||||
#endif
|
||||
}
|
||||
|
||||
ogg_sync_wrote(&reader->ogg_sync, bytes);
|
||||
|
@ -632,7 +624,7 @@ oggz_offset_end (OGGZ * oggz)
|
|||
static ogg_int64_t
|
||||
oggz_seek_set (OGGZ * oggz, ogg_int64_t unit_target)
|
||||
{
|
||||
OggzReader * reader = &oggz->x.reader;
|
||||
OggzReader * reader;
|
||||
oggz_off_t offset_orig, offset_at, offset_guess;
|
||||
oggz_off_t offset_begin, offset_end = -1, offset_next;
|
||||
ogg_int64_t granule_at;
|
||||
|
@ -659,6 +651,8 @@ oggz_seek_set (OGGZ * oggz, ogg_int64_t unit_target)
|
|||
return -1;
|
||||
}
|
||||
|
||||
reader = &oggz->x.reader;
|
||||
|
||||
if (unit_target == reader->current_unit) {
|
||||
#ifdef DEBUG
|
||||
printf ("oggz_seek_set: unit_target == reader->current_unit, SKIP\n");
|
||||
|
@ -843,7 +837,7 @@ oggz_seek_end (OGGZ * oggz, ogg_int64_t unit_offset)
|
|||
off_t
|
||||
oggz_seek (OGGZ * oggz, oggz_off_t offset, int whence)
|
||||
{
|
||||
OggzReader * reader = &oggz->x.reader;
|
||||
OggzReader * reader;
|
||||
ogg_int64_t units = -1;
|
||||
|
||||
if (oggz == NULL) return -1;
|
||||
|
@ -853,7 +847,9 @@ oggz_seek (OGGZ * oggz, oggz_off_t offset, int whence)
|
|||
}
|
||||
|
||||
if (offset == 0 && whence == SEEK_SET) units = 0;
|
||||
|
||||
|
||||
reader = &oggz->x.reader;
|
||||
|
||||
if (!(offset == 0 && whence == SEEK_CUR)) {
|
||||
/* Invalidate current_unit */
|
||||
reader->current_unit = -1;
|
||||
|
@ -865,7 +861,7 @@ oggz_seek (OGGZ * oggz, oggz_off_t offset, int whence)
|
|||
ogg_int64_t
|
||||
oggz_seek_units (OGGZ * oggz, ogg_int64_t units, int whence)
|
||||
{
|
||||
OggzReader * reader = &oggz->x.reader;
|
||||
OggzReader * reader;
|
||||
|
||||
ogg_int64_t r;
|
||||
|
||||
|
@ -890,6 +886,8 @@ oggz_seek_units (OGGZ * oggz, ogg_int64_t units, int whence)
|
|||
return -1;
|
||||
}
|
||||
|
||||
reader = &oggz->x.reader;
|
||||
|
||||
switch (whence) {
|
||||
case SEEK_SET:
|
||||
r = oggz_seek_set (oggz, units);
|
||||
|
|
|
@ -90,3 +90,30 @@ oggz_stream_get_numheaders (OGGZ * oggz, long serialno)
|
|||
return stream->numheaders;
|
||||
}
|
||||
|
||||
int
|
||||
oggz_set_preroll (OGGZ * oggz, long serialno, int preroll)
|
||||
{
|
||||
oggz_stream_t * stream;
|
||||
|
||||
if (oggz == NULL) return OGGZ_ERR_BAD_OGGZ;
|
||||
|
||||
stream = oggz_get_stream (oggz, serialno);
|
||||
if (stream == NULL) return OGGZ_ERR_BAD_SERIALNO;
|
||||
|
||||
stream->preroll = preroll;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
oggz_get_preroll (OGGZ * oggz, long serialno)
|
||||
{
|
||||
oggz_stream_t * stream;
|
||||
|
||||
if (oggz == NULL) return OGGZ_ERR_BAD_OGGZ;
|
||||
|
||||
stream = oggz_get_stream (oggz, serialno);
|
||||
if (stream == NULL) return OGGZ_ERR_BAD_SERIALNO;
|
||||
|
||||
return stream->preroll;
|
||||
}
|
||||
|
|
|
@ -35,11 +35,15 @@
|
|||
|
||||
typedef struct _oggz_stream_t oggz_stream_t;
|
||||
|
||||
typedef int (*OggzReadBOS) (OGGZ * oggz, long serialno,
|
||||
unsigned char * data, long length,
|
||||
void * user_data);
|
||||
|
||||
typedef struct {
|
||||
const char *bos_str;
|
||||
int bos_str_len;
|
||||
const char *content_type;
|
||||
OggzReadPacket reader;
|
||||
OggzReadBOS reader;
|
||||
ogg_int64_t (*calculator)(ogg_int64_t now, oggz_stream_t *stream,
|
||||
ogg_packet *op);
|
||||
ogg_int64_t (*r_calculator)(ogg_int64_t next_packet_gp,
|
||||
|
|
|
@ -53,6 +53,8 @@ oggz_table_new (void)
|
|||
OggzTable * table;
|
||||
|
||||
table = oggz_malloc (sizeof (OggzTable));
|
||||
if (table == NULL) return NULL;
|
||||
|
||||
table->keys = oggz_vector_new ();
|
||||
table->data = oggz_vector_new ();
|
||||
|
||||
|
@ -74,6 +76,8 @@ oggz_table_lookup (OggzTable * table, long key)
|
|||
{
|
||||
int i, size;
|
||||
|
||||
if (table == NULL) return NULL;
|
||||
|
||||
size = oggz_vector_size (table->keys);
|
||||
for (i = 0; i < size; i++) {
|
||||
if (oggz_vector_nth_l (table->keys, i) == key) {
|
||||
|
|
|
@ -82,6 +82,7 @@ oggz_vector_new (void)
|
|||
OggzVector * vector;
|
||||
|
||||
vector = oggz_malloc (sizeof (OggzVector));
|
||||
if (vector == NULL) return NULL;
|
||||
|
||||
vector->max_elements = 0;
|
||||
vector->nr_elements = 0;
|
||||
|
@ -270,7 +271,6 @@ oggz_vector_grow (OggzVector * vector)
|
|||
|
||||
if (new_elements == NULL) {
|
||||
vector->nr_elements--;
|
||||
vector->data = NULL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -363,8 +363,7 @@ oggz_vector_remove_nth (OggzVector * vector, int n)
|
|||
oggz_realloc (vector->data,
|
||||
(size_t)new_max_elements * sizeof (oggz_data_t));
|
||||
|
||||
if (new_elements == NULL)
|
||||
{
|
||||
if (new_elements == NULL) {
|
||||
vector->data = NULL;
|
||||
return NULL;
|
||||
}
|
||||
|
@ -409,52 +408,13 @@ void *
|
|||
oggz_vector_pop (OggzVector * vector)
|
||||
{
|
||||
void * data;
|
||||
#if 0
|
||||
void * new_elements;
|
||||
int new_max_elements;
|
||||
#endif
|
||||
|
||||
if (!vector || vector->data == NULL) return NULL;
|
||||
if (vector == NULL || vector->data == NULL) return NULL;
|
||||
|
||||
data = vector->data[0].p;
|
||||
|
||||
#if 0
|
||||
vector->nr_elements--;
|
||||
|
||||
if (vector->nr_elements == 0) {
|
||||
oggz_vector_clear (vector);
|
||||
} else {
|
||||
#if 0
|
||||
memmove (vector->data, &vector->data[1],
|
||||
vector->nr_elements * sizeof (void *));
|
||||
#else
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < vector->nr_elements; i++) {
|
||||
vector->data[i].p = vector->data[i+1].p;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (vector->nr_elements < vector->max_elements/2) {
|
||||
new_max_elements = vector->max_elements/2;
|
||||
|
||||
new_elements =
|
||||
oggz_realloc (vector->data,
|
||||
(size_t)new_max_elements * sizeof (oggz_data_t));
|
||||
|
||||
if (new_elements != NULL) {
|
||||
vector->max_elements = new_max_elements;
|
||||
vector->data = new_elements;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
#else
|
||||
|
||||
oggz_vector_remove_nth (vector, 0);
|
||||
|
||||
#endif
|
||||
|
||||
return data;
|
||||
|
||||
}
|
||||
|
|
|
@ -40,9 +40,17 @@ typedef int (*OggzFunc1) (void * data, void *arg);
|
|||
typedef int (*OggzFindFunc) (void * data, long serialno);
|
||||
typedef int (*OggzCmpFunc) (const void * a, const void * b, void * user_data);
|
||||
|
||||
/**
|
||||
* Create a new vector object.
|
||||
* \retval a pointer to the new vector.
|
||||
* \retval NULL on failure.
|
||||
*/
|
||||
OggzVector *
|
||||
oggz_vector_new (void);
|
||||
|
||||
/**
|
||||
* Destroy a vector object.
|
||||
*/
|
||||
void
|
||||
oggz_vector_delete (OggzVector * vector);
|
||||
|
||||
|
@ -61,19 +69,41 @@ oggz_vector_nth_p (OggzVector * vector, int n);
|
|||
long
|
||||
oggz_vector_nth_l (OggzVector * vector, int n);
|
||||
|
||||
/**
|
||||
* Call a function on each element of a vector, in order.
|
||||
* \param vector The OggzVector to iterate over
|
||||
* \param func The OggzFunc to be called on each element
|
||||
* \retval 0 on success
|
||||
*/
|
||||
int
|
||||
oggz_vector_foreach (OggzVector * vector, OggzFunc func);
|
||||
|
||||
/**
|
||||
* Call a function with a userdata pointer on each element
|
||||
* of a vector, in order. This allows the function to access
|
||||
* shared data when operating on the element sequence.
|
||||
* \param vector The OggzVector to iterate over
|
||||
* \param func The OggzFunc1 to be called on each element
|
||||
* \param arg The userdata pointer to be passed to the function
|
||||
* along with the vector member
|
||||
* \retval 0 on success
|
||||
*/
|
||||
int
|
||||
oggz_vector_foreach1 (OggzVector * vector, OggzFunc1 func, void *arg);
|
||||
|
||||
/**
|
||||
* Return the number of elements in a vector.
|
||||
* \param vector The vector to query
|
||||
* \retval The number of elements
|
||||
*/
|
||||
int
|
||||
oggz_vector_size (OggzVector * vector);
|
||||
|
||||
/**
|
||||
* Add an element to a vector. If the vector has a comparison function,
|
||||
* the new element is inserted in sorted order, otherwise it is appended
|
||||
* to the tail.
|
||||
* to the tail. Use this function to add pointer elements to the vector.
|
||||
* Use ogg_vector_insert_l for long values.
|
||||
* \param vector An OggzVector
|
||||
* \param data The new element to add
|
||||
* \retval data If the element was successfully added
|
||||
|
@ -82,6 +112,16 @@ oggz_vector_size (OggzVector * vector);
|
|||
void *
|
||||
oggz_vector_insert_p (OggzVector * vector, void * data);
|
||||
|
||||
/**
|
||||
* Add an element to a vector. If the vector has a comparison function,
|
||||
* the new element is inserted in sorted order, otherwise it is appended
|
||||
* to the tail. Use this function to add long value elements to the
|
||||
* vector. Use ogg_vector_insert_p for pointer values.
|
||||
* \param vector An OggzVector
|
||||
* \param ldata The new element to add
|
||||
* \retval ldata If the element was successfully added
|
||||
* \retval -1L If adding the element failed
|
||||
*/
|
||||
long
|
||||
oggz_vector_insert_l (OggzVector * vector, long ldata);
|
||||
|
||||
|
@ -101,10 +141,29 @@ oggz_vector_remove_p (OggzVector * vector, void * data);
|
|||
OggzVector *
|
||||
oggz_vector_remove_l (OggzVector * vector, long ldata);
|
||||
|
||||
/**
|
||||
* Set a comparison function for a vector.
|
||||
* Vectors can be sorted, or stored in append order, depending on
|
||||
* whether they have a comparison function defined. When a comparison
|
||||
* function is first set, it will be used to sort the entire vector,
|
||||
* and subsequence insertions will maintain the sort. If no comparison
|
||||
* function is set, new elements are appended at the end of the vector.
|
||||
* Call oggz_vector_set_cmp(vector, NULL, NULL) to remove the current
|
||||
* comparison function. This does not affect the member order.
|
||||
* \param vector the vector to associate the comparison function with
|
||||
* \param compare the OggzCmpFunc to use for comparisons
|
||||
* \param user_data private data pointer for the compare function
|
||||
* \retval 0 on success
|
||||
*/
|
||||
int
|
||||
oggz_vector_set_cmp (OggzVector * vector, OggzCmpFunc compare,
|
||||
void * user_data);
|
||||
|
||||
/**
|
||||
* Pop a member off a vector.
|
||||
* \retval pointer to the popped member
|
||||
* \retval NULL if the vector is empty
|
||||
*/
|
||||
void *
|
||||
oggz_vector_pop (OggzVector * vector);
|
||||
|
||||
|
|
|
@ -95,6 +95,7 @@ oggz_write_init (OGGZ * oggz)
|
|||
writer->next_zpacket = NULL;
|
||||
|
||||
writer->packet_queue = oggz_vector_new ();
|
||||
if (writer->packet_queue == NULL) return NULL;
|
||||
|
||||
#ifdef ZPACKET_CMP
|
||||
/* XXX: comparison function should only kick in when a metric is set */
|
||||
|
@ -209,7 +210,7 @@ oggz_write_feed (OGGZ * oggz, ogg_packet * op, long serialno, int flush,
|
|||
oggz_stream_t * stream;
|
||||
oggz_writer_packet_t * packet;
|
||||
ogg_packet * new_op;
|
||||
unsigned char * new_buf;
|
||||
unsigned char * new_buf = NULL;
|
||||
int b_o_s, e_o_s, bos_auto;
|
||||
int strict, prefix, suffix;
|
||||
|
||||
|
@ -231,13 +232,13 @@ oggz_write_feed (OGGZ * oggz, ogg_packet * op, long serialno, int flush,
|
|||
* ie. that it fits within 32 bits and does not equal the special value -1 */
|
||||
if ((long)((ogg_int32_t)serialno) != serialno || serialno == -1) {
|
||||
#ifdef DEBUG
|
||||
printf ("oggz_write_feed: serialno %010ld\n", serialno);
|
||||
printf ("oggz_write_feed: serialno %010lu\n", serialno);
|
||||
#endif
|
||||
return OGGZ_ERR_BAD_SERIALNO;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
printf ("oggz_write_feed: (%010ld) FLUSH: %d\n", serialno, flush);
|
||||
printf ("oggz_write_feed: (%010lu) FLUSH: %d\n", serialno, flush);
|
||||
#endif
|
||||
|
||||
/* Cache strict, prefix, suffix */
|
||||
|
@ -260,6 +261,8 @@ oggz_write_feed (OGGZ * oggz, ogg_packet * op, long serialno, int flush,
|
|||
|
||||
if (b_o_s || !strict || suffix) {
|
||||
stream = oggz_add_stream (oggz, serialno);
|
||||
if (stream == NULL)
|
||||
return OGGZ_ERR_OUT_OF_MEMORY;
|
||||
oggz_auto_identify_packet (oggz, op, serialno);
|
||||
} else {
|
||||
return OGGZ_ERR_BAD_SERIALNO;
|
||||
|
@ -275,7 +278,9 @@ oggz_write_feed (OGGZ * oggz, ogg_packet * op, long serialno, int flush,
|
|||
if (strict) {
|
||||
if (op->bytes < 0) return OGGZ_ERR_BAD_BYTES;
|
||||
if (!suffix && b_o_s != stream->b_o_s) return OGGZ_ERR_BAD_B_O_S;
|
||||
if (op->granulepos != -1 && op->granulepos < stream->granulepos)
|
||||
if (op->granulepos != -1 && op->granulepos < stream->granulepos &&
|
||||
/* Allow negative granulepos immediately after headers, for Dirac: */
|
||||
!(stream->granulepos == 0 && op->granulepos < 0))
|
||||
return OGGZ_ERR_BAD_GRANULEPOS;
|
||||
|
||||
/* Allow packetno == -1 to indicate oggz should fill it in; otherwise:
|
||||
|
@ -294,7 +299,7 @@ oggz_write_feed (OGGZ * oggz, ogg_packet * op, long serialno, int flush,
|
|||
/* OK -- Update stream's memory of packet details */
|
||||
|
||||
if (!stream->metric && (oggz->flags & OGGZ_AUTO)) {
|
||||
oggz_auto_get_granulerate (oggz, op, serialno, NULL);
|
||||
oggz_auto_read_bos_packet (oggz, op, serialno, NULL);
|
||||
}
|
||||
|
||||
stream->b_o_s = 0; /* The stream is henceforth no longer at bos */
|
||||
|
@ -308,12 +313,18 @@ oggz_write_feed (OGGZ * oggz, ogg_packet * op, long serialno, int flush,
|
|||
/* Now set up the packet and add it to the queue */
|
||||
if (guard == NULL) {
|
||||
new_buf = oggz_malloc ((size_t)op->bytes);
|
||||
if (new_buf == NULL) return OGGZ_ERR_OUT_OF_MEMORY;
|
||||
|
||||
memcpy (new_buf, op->packet, (size_t)op->bytes);
|
||||
} else {
|
||||
new_buf = op->packet;
|
||||
}
|
||||
|
||||
packet = oggz_malloc (sizeof (oggz_writer_packet_t));
|
||||
if (packet == NULL) {
|
||||
if (guard == NULL && new_buf != NULL) oggz_free (new_buf);
|
||||
return OGGZ_ERR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
new_op = &packet->op;
|
||||
new_op->packet = new_buf;
|
||||
|
@ -375,13 +386,14 @@ oggz_write_feed (OGGZ * oggz, ogg_packet * op, long serialno, int flush,
|
|||
static long
|
||||
oggz_page_init (OGGZ * oggz)
|
||||
{
|
||||
OggzWriter * writer = &oggz->x.writer;
|
||||
OggzWriter * writer;
|
||||
ogg_stream_state * os;
|
||||
ogg_page * og;
|
||||
int ret;
|
||||
|
||||
if (oggz == NULL) return -1;
|
||||
|
||||
writer = &oggz->x.writer;
|
||||
os = writer->current_stream;
|
||||
og = &oggz->current_page;
|
||||
|
||||
|
@ -416,13 +428,14 @@ oggz_page_init (OGGZ * oggz)
|
|||
static long
|
||||
oggz_packet_init (OGGZ * oggz, oggz_writer_packet_t * next_zpacket)
|
||||
{
|
||||
OggzWriter * writer = &oggz->x.writer;
|
||||
OggzWriter * writer;
|
||||
oggz_stream_t * stream;
|
||||
ogg_stream_state * os;
|
||||
ogg_packet * op;
|
||||
|
||||
if (oggz == NULL) return -1L;
|
||||
|
||||
writer = &oggz->x.writer;
|
||||
writer->current_zpacket = next_zpacket;
|
||||
op = &next_zpacket->op;
|
||||
|
||||
|
@ -451,12 +464,13 @@ oggz_packet_init (OGGZ * oggz, oggz_writer_packet_t * next_zpacket)
|
|||
static long
|
||||
oggz_page_copyout (OGGZ * oggz, unsigned char * buf, long n)
|
||||
{
|
||||
OggzWriter * writer = &oggz->x.writer;
|
||||
OggzWriter * writer;
|
||||
long h, b;
|
||||
ogg_page * og;
|
||||
|
||||
if (oggz == NULL) return -1L;
|
||||
|
||||
writer = &oggz->x.writer;
|
||||
og = &oggz->current_page;
|
||||
|
||||
h = MIN (n, og->header_len - writer->page_offset);
|
||||
|
@ -493,7 +507,7 @@ oggz_page_copyout (OGGZ * oggz, unsigned char * buf, long n)
|
|||
static long
|
||||
oggz_page_writeout (OGGZ * oggz, long n)
|
||||
{
|
||||
OggzWriter * writer = &oggz->x.writer;
|
||||
OggzWriter * writer;
|
||||
long h, b, nwritten;
|
||||
ogg_page * og;
|
||||
|
||||
|
@ -503,6 +517,7 @@ oggz_page_writeout (OGGZ * oggz, long n)
|
|||
|
||||
if (oggz == NULL) return -1L;
|
||||
|
||||
writer = &oggz->x.writer;
|
||||
og = &oggz->current_page;
|
||||
|
||||
#ifdef OGGZ_WRITE_DIRECT
|
||||
|
@ -654,7 +669,7 @@ oggz_writer_make_packet (OGGZ * oggz)
|
|||
#ifdef DEBUG
|
||||
printf("oggz_writer_make_packet: cb_ret is %d\n", cb_ret);
|
||||
#endif
|
||||
|
||||
|
||||
if (cb_ret == 0 && next_zpacket == NULL) return OGGZ_WRITE_EMPTY;
|
||||
|
||||
return cb_ret;
|
||||
|
@ -668,7 +683,7 @@ oggz_write_output (OGGZ * oggz, unsigned char * buf, long n)
|
|||
int active = 1, cb_ret = 0;
|
||||
|
||||
if (oggz == NULL) return OGGZ_ERR_BAD_OGGZ;
|
||||
|
||||
|
||||
writer = &oggz->x.writer;
|
||||
|
||||
if (!(oggz->flags & OGGZ_WRITE)) {
|
||||
|
@ -820,7 +835,7 @@ oggz_write (OGGZ * oggz, long n)
|
|||
* if we're out of packets because we're at the end of the file,
|
||||
* we can't finish just yet. Instead we need to force a page flush,
|
||||
* and write the page out. So we set flushing and no_more_packets to
|
||||
* 1. This causes oggz_page_init to flush the page, then we
|
||||
* 1. This causes oggz_page_init to flush the page, then we
|
||||
* will switch the state to OGGZ_WRITING_PAGES, which will trigger
|
||||
* the writing code below.
|
||||
*/
|
||||
|
@ -903,11 +918,13 @@ oggz_write (OGGZ * oggz, long n)
|
|||
long
|
||||
oggz_write_get_next_page_size (OGGZ * oggz)
|
||||
{
|
||||
OggzWriter * writer = &oggz->x.writer;
|
||||
OggzWriter * writer;
|
||||
ogg_page * og;
|
||||
|
||||
if (oggz == NULL) return OGGZ_ERR_BAD_OGGZ;
|
||||
|
||||
writer = &oggz->x.writer;
|
||||
|
||||
if (!(oggz->flags & OGGZ_WRITE)) {
|
||||
return OGGZ_ERR_INVALID;
|
||||
}
|
||||
|
|
|
@ -40,9 +40,9 @@ sed s/\#include\ \"config.h\"/\#ifdef\ WIN32\\n\#include\ \"config_win32.h\"\\n\
|
|||
sed s/\#include\ \"config.h\"/\#ifdef\ WIN32\\n\#include\ \"config_win32.h\"\\n\#else\\n\#include\ \"config.h\"\\n\#endif/g $1/src/liboggz/oggz_seek.c >./src/liboggz/oggz_seek.c
|
||||
cp $1/src/liboggz/oggz_dlist.h ./src/liboggz/oggz_dlist.h
|
||||
sed s/\#include\ \"config.h\"/\#ifdef\ WIN32\\n\#include\ \"config_win32.h\"\\n\#else\\n\#include\ \"config.h\"\\n\#endif/g $1/src/liboggz/metric_internal.c >./src/liboggz/metric_internal.c
|
||||
cp $1/src/liboggz/dirac.h ./src/liboggz/dirac.h
|
||||
sed s/\#include\ \"config.h\"/\#ifdef\ WIN32\\n\#include\ \"config_win32.h\"\\n\#else\\n\#include\ \"config.h\"\\n\#endif/g $1/src/liboggz/dirac.c >./src/liboggz/dirac.c
|
||||
cp $1/AUTHORS ./AUTHORS
|
||||
patch -p4 <seek.patch
|
||||
patch -p4 <warning.patch
|
||||
patch -p3 <oggz_off_t.patch
|
||||
patch -p3 <wince.patch
|
||||
patch -p4 <endian.patch
|
||||
patch -p3 <endian.patch
|
||||
patch -p4 <seek.patch
|
||||
|
|
|
@ -1,17 +0,0 @@
|
|||
diff --git a/media/liboggz/src/liboggz/oggz_auto.c b/media/liboggz/src/liboggz/oggz_auto.c
|
||||
index 6d83fa9..95ffe6c 100644
|
||||
--- a/media/liboggz/src/liboggz/oggz_auto.c
|
||||
+++ b/media/liboggz/src/liboggz/oggz_auto.c
|
||||
@@ -809,10 +809,12 @@ auto_calc_vorbis(ogg_int64_t now, oggz_stream_t *stream, ogg_packet *op) {
|
||||
}
|
||||
|
||||
size_check += 1;
|
||||
+#ifdef DEBUG
|
||||
if (size_check != size)
|
||||
{
|
||||
printf("WARNING: size parsing failed for VORBIS mode packets\n");
|
||||
}
|
||||
+#endif
|
||||
|
||||
/*
|
||||
* store mode size information in our info struct
|
Загрузка…
Ссылка в новой задаче