Commit 6633fe87 authored by shans's avatar shans

Code to generate initial granulepos values for packets before the end of the first page.



git-svn-id: http://svn.annodex.net/liboggz/trunk@3216 8158c8cd-e7e1-0310-9fa4-c5954c97daef
parent 6496ff67
......@@ -101,6 +101,8 @@ oggz_new (int flags)
oggz->order = NULL;
oggz->order_user_data = NULL;
oggz->packet_buffer = oggz_dlist_new ();
if (OGGZ_CONFIG_WRITE && (oggz->flags & OGGZ_WRITE)) {
oggz_write_init (oggz);
} else if (OGGZ_CONFIG_READ) {
......
......@@ -444,6 +444,26 @@ auto_calc_theora(ogg_int64_t now, oggz_stream_t *stream, ogg_packet *op) {
}
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);
int offset = (int)(next_packet_gp - (keyframe << stream->granuleshift));
/* assume kf is 60 frames ago. NOTE: This is going to cause problems,
* but I can't think of what else to do. The position of the last kf
* is fundamentally unknowable.
*/
if (offset == 0) {
return ((keyframe - 60L) << stream->granuleshift) + 59;
}
else {
return (((ogg_int64_t)keyframe) << stream->granuleshift) + (offset - 1);
}
}
/*
* Vorbis packets can be short or long, and each packet overlaps the previous
* and next packets. The granulepos of a packet is always the last sample
......@@ -721,6 +741,25 @@ auto_calc_vorbis(ogg_int64_t now, oggz_stream_t *stream, ogg_packet *op) {
}
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 *)stream->calculate_data;
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;
mode = (next_packet->packet[0] >> 1) & ((1 << info->log2_num_modes) - 1);
next_size = info->mode_sizes[mode] ? info->long_size : info->short_size;
return next_packet_gp - ((this_size + next_size) / 4);
}
/**
* FLAC
* Defined at: http://flac.sourceforge.net/ogg_mapping.html
......@@ -838,17 +877,17 @@ out:
}
const oggz_auto_contenttype_t oggz_auto_codec_ident[] = {
{"\200theora", 7, "Theora", auto_theora, auto_calc_theora},
{"\001vorbis", 7, "Vorbis", auto_vorbis, auto_calc_vorbis},
{"Speex", 5, "Speex", auto_speex, auto_calc_speex},
{"PCM ", 8, "PCM", auto_oggpcm2, NULL},
{"CMML\0\0\0\0", 8, "CMML", auto_cmml, NULL},
{"Annodex", 8, "Annodex", auto_annodex, NULL},
{"fishead", 7, "Skeleton", auto_fishead, NULL},
{"fLaC", 4, "Flac0", auto_flac0, auto_calc_flac},
{"\177FLAC", 4, "Flac", auto_flac, auto_calc_flac},
{"AnxData", 7, "AnxData", auto_anxdata, NULL},
{"", 0, "Unknown", NULL, NULL}
{"\200theora", 7, "Theora", auto_theora, auto_calc_theora, auto_rcalc_theora},
{"\001vorbis", 7, "Vorbis", auto_vorbis, auto_calc_vorbis, auto_rcalc_vorbis},
{"Speex", 5, "Speex", auto_speex, auto_calc_speex, NULL},
{"PCM ", 8, "PCM", auto_oggpcm2, NULL, NULL},
{"CMML\0\0\0\0", 8, "CMML", auto_cmml, NULL, NULL},
{"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},
{"AnxData", 7, "AnxData", auto_anxdata, NULL, NULL},
{"", 0, "Unknown", NULL, NULL, NULL}
};
int oggz_auto_identify (OGGZ *oggz, ogg_page *og, long serialno) {
......@@ -892,28 +931,23 @@ 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);
/*
* this will cause a hiccough at the end of the first data page if there are
* more than one packets on that page. In the absence of pervasive access
* to the packets on a page, though, it might have to do.
*
* Why a hiccough? Because there's no granulepos attached to any packets
* except for the last on a page. If the stream doesn't start at gp 0 (a
* very common occurrence) then we don't realise until we get to the end of
* the page. By that time we've already junked the first packets on the
* page.
*/
/*
if (now != -1LL) {
return op->granulepos;
}
*/
return r;
}
return now;
}
ogg_int64_t
oggz_auto_calculate_gp_backwards(int content, ogg_int64_t next_packet_gp,
oggz_stream_t *stream, ogg_packet *this_packet, ogg_packet *next_packet) {
if (oggz_auto_codec_ident[content].r_calculator != NULL) {
return oggz_auto_codec_ident[content].r_calculator(next_packet_gp,
stream, this_packet, next_packet);
}
return 0;
}
int
......
......@@ -63,6 +63,8 @@ oggz_dlist_new (void) {
dlist->head = dummy_front;
dlist->tail = dummy_back;
return dlist;
}
void
......@@ -77,6 +79,8 @@ oggz_dlist_delete(OggzDList *dlist) {
free(dlist->tail);
free(dlist);
printf("dlist:DELETE complete\n");
}
int
......@@ -137,13 +141,14 @@ oggz_dlist_reverse_iter(OggzDList *dlist, OggzDListIterFunc func) {
void
oggz_dlist_deliter(OggzDList *dlist, OggzDListIterFunc func) {
OggzDListElem *p;
OggzDListElem *p, *q;
for (p = dlist->head->next; p != dlist->tail; p = p->next) {
for (p = dlist->head->next; p != dlist->tail; p = q) {
if (func(p->data) == DLIST_ITER_CANCEL) {
break;
}
q = p->next;
p->prev->next = p->next;
p->next->prev = p->prev;
......@@ -155,13 +160,14 @@ oggz_dlist_deliter(OggzDList *dlist, OggzDListIterFunc func) {
void
oggz_dlist_reverse_deliter(OggzDList *dlist, OggzDListIterFunc func) {
OggzDListElem *p;
OggzDListElem *p, *q;
for (p = dlist->tail->prev; p != dlist->head; p = p->prev) {
for (p = dlist->tail->prev; p != dlist->head; p = q) {
if (func(p->data) == DLIST_ITER_CANCEL) {
break;
}
q = p->prev;
p->prev->next = p->next;
p->next->prev = p->prev;
......
......@@ -42,7 +42,7 @@
#include "oggz_macros.h"
#include "oggz_vector.h"
#include "oggz_dlist.h"
typedef struct _OGGZ OGGZ;
typedef struct _OggzComment OggzComment;
......@@ -118,6 +118,7 @@ struct _oggz_stream_t {
ogg_int64_t last_granulepos;
ogg_int64_t page_granulepos;
void * calculate_data;
ogg_packet * last_packet;
};
struct _OggzReader {
......@@ -237,6 +238,8 @@ struct _OGGZ {
OggzReader reader;
OggzWriter writer;
} x;
OggzDList * packet_buffer;
};
OGGZ * oggz_read_init (OGGZ * oggz);
......
......@@ -238,6 +238,96 @@ oggz_get_next_page_7 (OGGZ * oggz, ogg_page * og)
return ret;
}
typedef struct {
ogg_packet packet;
ogg_int64_t calced_granulepos;
oggz_stream_t * stream;
OggzReader * reader;
OGGZ * oggz;
long serialno;
} OggzBufferedPacket;
OggzBufferedPacket *
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));
memcpy(&(p->packet), packet, sizeof(ogg_packet));
p->packet.packet = malloc(packet->bytes);
memcpy(p->packet.packet, packet->packet, packet->bytes);
p->calced_granulepos = granulepos;
p->stream = stream;
p->serialno = serialno;
p->reader = reader;
p->oggz = oggz;
return p;
}
void
oggz_read_free_pbuffer_entry(OggzBufferedPacket *p) {
free(p->packet.packet);
free(p);
}
OggzDListIterResponse
oggz_read_update_gp(void *elem) {
OggzBufferedPacket *p = (OggzBufferedPacket *)elem;
if (p->calced_granulepos == -1 && p->stream->last_granulepos != -1) {
int content = oggz_stream_get_content(p->oggz, p->serialno);
p->calced_granulepos =
oggz_auto_calculate_gp_backwards(content, p->stream->last_granulepos,
p->stream, &(p->packet), p->stream->last_packet);
p->stream->last_granulepos = p->calced_granulepos;
p->stream->last_packet = &(p->packet);
}
return DLIST_ITER_CONTINUE;
}
OggzDListIterResponse
oggz_read_deliver_packet(void *elem) {
OggzBufferedPacket *p = (OggzBufferedPacket *)elem;
ogg_int64_t gp_stored;
long unit_stored;
if (p->calced_granulepos == -1) {
return DLIST_ITER_CANCEL;
}
gp_stored = p->reader->current_granulepos;
unit_stored = p->reader->current_unit;
p->reader->current_granulepos = p->calced_granulepos;
p->reader->current_unit =
oggz_get_unit (p->oggz, p->serialno, p->calced_granulepos);
if (p->stream->read_packet) {
p->stream->read_packet(p->oggz, &(p->packet), p->serialno,
p->stream->read_user_data);
} else if (p->reader->read_packet) {
p->reader->read_packet(p->oggz, &(p->packet), p->serialno,
p->reader->read_user_data);
}
p->reader->current_granulepos = gp_stored;
p->reader->current_unit = unit_stored;
oggz_read_free_pbuffer_entry(p);
return DLIST_ITER_CONTINUE;
}
static int
oggz_read_sync (OGGZ * oggz)
{
......@@ -348,6 +438,44 @@ oggz_read_sync (OGGZ * oggz)
oggz_auto_read_comments (oggz, stream, serialno, op);
}
/*
* while we are getting invalid granulepos values, store the incoming
* packets in a dlist */
if (reader->current_granulepos == -1) {
OggzBufferedPacket *p = oggz_read_new_pbuffer_entry(
oggz, &packet, reader->current_granulepos,
serialno, stream, reader);
oggz_dlist_append(oggz->packet_buffer, p);
continue;
} else if (!oggz_dlist_is_empty(oggz->packet_buffer)) {
/*
* move backward through the list assigning gp values based upon
* the granulepos we just recieved. Then move forward through
* the list delivering any packets at the beginning with valid
* gp values
*/
ogg_int64_t gp_stored = stream->last_granulepos;
stream->last_packet = &packet;
oggz_dlist_reverse_iter(oggz->packet_buffer, oggz_read_update_gp);
oggz_dlist_deliter(oggz->packet_buffer, oggz_read_deliver_packet);
/*
* fix up the stream granulepos
*/
stream->last_granulepos = gp_stored;
if (!oggz_dlist_is_empty(oggz->packet_buffer)) {
OggzBufferedPacket *p = oggz_read_new_pbuffer_entry(
oggz, &packet, reader->current_granulepos,
serialno, stream, reader);
oggz_dlist_append(oggz->packet_buffer, p);
continue;
}
}
if (stream->read_packet) {
cb_ret =
stream->read_packet (oggz, op, serialno, stream->read_user_data);
......
......@@ -42,6 +42,9 @@ typedef struct {
OggzReadPacket 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,
oggz_stream_t *stream, ogg_packet *this_packet,
ogg_packet *next_packet);
} oggz_auto_contenttype_t;
extern const oggz_auto_contenttype_t oggz_auto_codec_ident[];
......@@ -57,4 +60,9 @@ const char * oggz_stream_get_content_type (OGGZ *oggz, long serialno);
ogg_int64_t
oggz_auto_calculate_granulepos(int content, ogg_int64_t now,
oggz_stream_t *stream, ogg_packet *op);
ogg_int64_t
oggz_auto_calculate_gp_backwards(int content, ogg_int64_t next_packet_gp,
oggz_stream_t *stream, ogg_packet *this_packet, ogg_packet *next_packet);
#endif /* __OGGZ_STREAM_H__ */
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment