[xiph-commits] r3751 - libannodex/trunk/src/importers
conrad at svn.annodex.net
conrad at svn.annodex.net
Wed Oct 29 04:06:27 PDT 2008
Author: conrad
Date: 2008-10-29 04:06:26 -0700 (Wed, 29 Oct 2008)
New Revision: 3751
Modified:
libannodex/trunk/src/importers/anx_import_ogg.c
Log:
anx_import_ogg: replace scan/seek algorithm with one-pass accumulation,
like oggz-chop but on a packet basis
Modified: libannodex/trunk/src/importers/anx_import_ogg.c
===================================================================
--- libannodex/trunk/src/importers/anx_import_ogg.c 2008-10-29 11:06:21 UTC (rev 3750)
+++ libannodex/trunk/src/importers/anx_import_ogg.c 2008-10-29 11:06:26 UTC (rev 3751)
@@ -85,8 +85,11 @@
typedef enum {
STATE_HEADERS,
+ STATE_GLUE,
+#if 0
STATE_GRANULEINFO,
STATE_FILTER,
+#endif
STATE_DATA
} state_t;
@@ -111,11 +114,16 @@
struct _AnxOggTrack {
AnxSourceTrack source_track;
+ int nr_headers_remaining;
+
+ /* Queue of packets corresponding to the last GOP of the
+ * glue section for this track. */
+ AnxList * glue_packets;
+
int need_keygranule;
ogg_int64_t keygranule;
double keygranule_time;
int filter_got_keygranule;
- int nr_headers_remaining;
};
struct _AnxOggData {
@@ -136,8 +144,8 @@
long skeleton_serialno;
int got_skeleton_eos;
- long nr_headers_remaining;
- long headers_unread;
+ int nr_headers_remaining;
+ int headers_unread;
int use_granule_seek;
double min_granule_seek;
@@ -146,9 +154,12 @@
int got_end;
/* Maintain a list of AnxOggTracks */
- OggzTable * logicals;
+ OggzTable * tracks;
+ /* Packet queues */
+ AnxList * header_queue;
AnxList * delivery_queue;
+
long current_offset; /* offset into current packet */
AnxImportCMML import_cmml;
@@ -287,6 +298,8 @@
aop->source_track = source_track;
aop->eos = op->e_o_s;
+ memcpy (aop->data, op->packet, op->bytes);
+
return aop;
}
@@ -311,22 +324,23 @@
read_packet_headers (OGGZ * oggz, ogg_packet * op, long serialno,
void * user_data)
{
- unsigned char * header = op->packet;
AnxOggData * aod = (AnxOggData *)user_data;
AnxOggTrack * aot = NULL;
+ AnxOggPacket * aop = NULL;
AnxSource * m = aod->anx_source;
AnxSourceTrack * track = NULL;
OggzStreamContent content;
int need_insert = 1;
int got_headers = 0;
- aot = (AnxOggTrack *) oggz_table_lookup (aod->logicals, serialno);
+ aot = (AnxOggTrack *) oggz_table_lookup (aod->tracks, serialno);
if (aot != NULL) {
need_insert = 0;
}
+ content = oggz_stream_get_content (oggz, serialno);
+
if (op->b_o_s) {
- content = oggz_stream_get_content (oggz, serialno);
if (content == OGGZ_CONTENT_CMML) {
/* Don't insert this into the media */
@@ -397,7 +411,7 @@
}
if (need_insert) {
- oggz_table_insert (aod->logicals, serialno, aot);
+ oggz_table_insert (aod->tracks, serialno, aot);
}
/* XXX: fix this for theora */
@@ -431,6 +445,11 @@
aod->got_skeleton_eos = 1;
}
+ if (content != OGGZ_CONTENT_CMML) {
+ aot = (AnxOggTrack *) oggz_table_lookup (aod->tracks, serialno);
+ track = &(aot->source_track);
+ }
+
aod->got_non_bos = 1;
}
@@ -444,43 +463,202 @@
if (aod->got_skeleton_eos) got_headers = 1;
}
+ /* Add this packet to the headers_queue */
+ if (track) {
+ aop = anxogg_packet_new (op, track, 0.0);
+ aod->header_queue = anx_list_append (aod->header_queue, aop);
+ }
+
if (got_headers) {
+#if 0
if (m->start_time != 0.0) {
if (oggz_seek_units (oggz, 0, SEEK_CUR) >= 0) {
oggz_set_data_start (oggz, oggz_tell (oggz));
- if (aod->use_granule_seek) aod->state = STATE_GRANULEINFO;
+ if (aod->use_granule_seek)
+ aod->state = STATE_GRANULEINFO;
}
} else {
aod->state = STATE_DATA;
}
+#else
+ aod->state = STATE_GLUE;
+ aod->headers_unread = anx_list_length (aod->header_queue);
+#endif
return OGGZ_STOP_OK;
}
return OGGZ_CONTINUE;
}
+/*
+ * OggzReadPacket read_packet_glue
+ *
+ * Parse Ogg packets up to the start point.
+ */
static int
+read_packet_glue (OGGZ * oggz, ogg_packet * op, long serialno,
+ void * user_data)
+{
+ AnxOggData * aod = (AnxOggData *)user_data;
+ AnxOggTrack * aot = NULL;
+ AnxSourceTrack * track = NULL;
+ AnxOggPacket * aop;
+ int granuleshift, iframe;
+ double start_time, at_time;
+
+ aot = (AnxOggTrack *) oggz_table_lookup (aod->tracks, serialno);
+
+ /* If this track is not in the table, ignore it. */
+ if (aot == NULL) return OGGZ_CONTINUE;
+
+ track = &(aot->source_track);
+
+ /* If we are past the start time, then queue this packet for delivery
+ * and set state to STATE_DATA */
+ start_time = aod->anx_source->start_time;
+ at_time = gp_to_time (aod->oggz, serialno, op->granulepos);
+ if (at_time >= start_time) {
+ aop = anxogg_packet_new (op, track, at_time);
+ aod->delivery_queue = anx_list_append (aod->delivery_queue, aop);
+ aod->state = STATE_DATA;
+ return OGGZ_STOP_OK;
+ }
+
+ granuleshift = oggz_get_granuleshift(oggz, serialno);
+ /* No need to cache packets of tracks without granuleshift */
+ if (granuleshift == 0) return OGGZ_CONTINUE;
+
+ /* If this is a keyframe, clear the glue_packets queue for this track */
+ iframe = op->granulepos >> granuleshift;
+ if (op->granulepos != -1 && (iframe << granuleshift) == op->granulepos) {
+ anx_list_free_with (aot->glue_packets, anxogg_packet_free);
+ aot->glue_packets = NULL;
+ }
+
+ /* Append this packet to this track's list of glue_packets */
+ aop = anxogg_packet_new (op, track, at_time);
+ aot->glue_packets = anx_list_append (aot->glue_packets, aop);
+
+ return OGGZ_CONTINUE;
+}
+
+/*
+ * Create a single list containing all the glue packets from all
+ * tracks, in time order.
+ */
+static AnxList *
+merge_glue (AnxOggData * aod)
+{
+ AnxList * glued = NULL, * candidates = NULL, * c, * min_aot_l, * min_aop_l;
+ AnxOggTrack * aot = NULL, * min_aot;
+ AnxOggPacket * aop = NULL;
+ int i, ntracks, ncandidates=0;
+ long serialno;
+ double at_time, min_time;
+
+ /* Prime candidates */
+ ntracks = oggz_table_size (aod->tracks);
+ for (i=0; i < ntracks; i++) {
+ aot = oggz_table_nth (aod->tracks, i, &serialno);
+ if (aot != NULL && aot->glue_packets != NULL) {
+ candidates = anx_list_append (candidates, aot);
+ }
+ }
+
+ /* Merge candidates */
+ while (candidates != NULL) {
+ /* Find minimum time packet in all glue buffers */
+ min_time = 10e100;
+ min_aot_l = NULL;
+ for (c = candidates; c; c = c->next) {
+ aot = (AnxOggTrack *)c->data;
+ aop = (AnxOggPacket *)aot->glue_packets->data;
+ if (aop->current_time < min_time) {
+ /* This is the min so far ... */
+ min_time = aop->current_time;
+ min_aot_l = c;
+ }
+ }
+
+ /* Got min_aot */
+ min_aot = min_aot_l->data;
+
+ /* Stash the AnxList* containing the minimum glue packet */
+ min_aop_l = min_aot->glue_packets;
+
+ /* Set that track's glue_packets to it's own tail */
+ min_aot->glue_packets = min_aop_l->next;
+ if (min_aot->glue_packets) {
+ /* If packets are remaining, clear the head's prev pointer */
+ min_aot->glue_packets->prev = NULL;
+ } else {
+ /* Otherwise, we can remove this track from future candidates */
+ candidates = anx_list_remove (candidates, min_aot_l);
+ /* Free the min_aot_l container (but not its AnxOggTrack data) */
+ anx_free (min_aot_l);
+ }
+
+ /* Append the min_aop to the list of glued packets we are building */
+ glued = anx_list_append (glued, min_aop_l->data);
+
+ /* Free the min_aop_l container (but not it's AnxOggPacket data) */
+ anx_free (min_aop_l);
+ }
+
+ return glued;
+}
+
+static int
+init_delivery_queue (AnxOggData * aod, AnxList * glued)
+{
+ AnxList * queue = NULL, * tail;
+
+ queue = aod->header_queue;
+ tail = anx_list_tail (queue);
+
+ /* If there packets glued, join them to the header queue */
+ if (glued != NULL) {
+ tail->next = glued;
+ glued->prev = tail;
+
+ /* Advance tail to the tail of (glued)queue */
+ tail = anx_list_tail (glued);
+ }
+
+ /* If there's any packets already queued for delivery during gluing,
+ * join them too. */
+ if (aod->delivery_queue != NULL) {
+ tail->next = aod->delivery_queue;
+ aod->delivery_queue->prev = tail;
+ }
+
+ /* Now queue points to the original headers++glued++delivery, so
+ * mark that for delivery */
+ aod->delivery_queue = queue;
+
+ /* And clear the header_queue pointer as it is no longer needed */
+ aod->header_queue = NULL;
+
+ return 0;
+}
+
+#if 0
+static int
granuleinfo_update_state (AnxOggData * aod)
{
AnxOggTrack * aot;
int i, n;
-#ifdef DEBUG
- //fprintf (aod->df, "anxogg::granuleinfo_update_state cmml %010ld %s\n",
- // aod->cmml_serialno,
- // aod->cmml_need_keygranule ? "needs keygranule" : "no keygranule");
-#endif
-
if (aod->cmml_serialno != -1 && aod->cmml_need_keygranule) return 0;
- n = oggz_table_size (aod->logicals);
+ n = oggz_table_size (aod->tracks);
#ifdef DEBUG
- fprintf (aod->df, "anxogg::granuleinfo_update_state %d logicals\n", n);
+ fprintf (aod->df, "anxogg::granuleinfo_update_state %d tracks\n", n);
#endif
for (i = 0; i < n; i++) {
- aot = (AnxOggTrack *)oggz_table_nth (aod->logicals, i, NULL);
+ aot = (AnxOggTrack *)oggz_table_nth (aod->tracks, i, NULL);
if (aot->need_keygranule) {
#ifdef DEBUG
fprintf (aod->df, "anxogg::granuleinfo_update_state logical %d needs keygranule\n", i);
@@ -559,7 +737,7 @@
aod->min_granule_seek = offset;
} else {
- aot = (AnxOggTrack *) oggz_table_lookup (aod->logicals, serialno);
+ aot = (AnxOggTrack *) oggz_table_lookup (aod->tracks, serialno);
if (aot == NULL) {
/* If this track is not in the table, ignore it. */
return OGGZ_STOP_OK;
@@ -617,10 +795,12 @@
return OGGZ_STOP_OK;
}
+#endif
static int
anxogg_setup (AnxOggData * aod)
{
+ AnxList * glued;
long n;
double start_time = 0.0, end_time = -1.0;
off_t start_offset = 0, end_offset = -1;
@@ -642,6 +822,16 @@
aod->nr_headers_remaining);
#endif
+ /* Slurp glue section */
+ oggz_set_read_callback (aod->oggz, -1, read_packet_glue, aod);
+ while (aod->state == STATE_GLUE &&
+ (n = oggz_read (aod->oggz, 1024)) != 0);
+
+ /* Now merge the glue section, and build the initial delivery queue */
+ glued = merge_glue (aod);
+ init_delivery_queue (aod, glued);
+
+#if 0
/* Find bitrate info */
start_time = aod->anx_source->start_time;
end_time = aod->anx_source->end_time;
@@ -723,6 +913,7 @@
/* Reset to beginning */
oggz_seek (aod->oggz, 0, SEEK_SET);
aod->nr_headers_remaining = aod->headers_unread;
+#endif
return 0;
}
@@ -731,6 +922,7 @@
* Read: Pass data packets to the writer
*/
+#if 0
static double
anxogg_seek_update (AnxSource * source)
{
@@ -784,24 +976,28 @@
return offset;
}
+#endif
static long
anxogg_read_update (AnxSource * media)
{
AnxOggData * aod = (AnxOggData *)media->custom_data;
- do_read:
+ //do_read:
while ((aod->delivery_queue == NULL) && (oggz_read (aod->oggz, 1024)) != 0);
+#if 0
if (aod->need_seek == NEED_SEEK && aod->nr_headers_remaining == 0) {
anxogg_seek_update (media);
goto do_read;
}
+#endif
return 0;
}
+#if 0
/***********************************************************
* A filter predicate, used between the min seek granule
* and the start time (ie. the bit between the prior keyframe
@@ -889,6 +1085,7 @@
return 1;
#endif
}
+#endif
/*
* OggzReadPacket read_packet_data
@@ -914,7 +1111,7 @@
#endif
if (!(aod->cmml_serialno != -1 && serialno == aod->cmml_serialno)) {
- aot = (AnxOggTrack *) oggz_table_lookup (aod->logicals, serialno);
+ aot = (AnxOggTrack *) oggz_table_lookup (aod->tracks, serialno);
if (aot == NULL) {
#ifdef DEBUG
fprintf (aod->df,
@@ -990,22 +1187,22 @@
}
#ifdef DEBUG
- fprintf (aod->df, "anxogg::read_packet: Filter? (%s)\n",
- aod->state == STATE_FILTER ? "USE_FN" : "NO_FN");
+ //fprintf (aod->df, "anxogg::read_packet: Filter? (%s)\n",
+ // aod->state == STATE_FILTER ? "USE_FN" : "NO_FN");
#endif
- if (!aod->ignore_media && !aod->got_end &&
- (aod->state != STATE_FILTER || filter (aod, aot, serialno, op))) {
+ if (!aod->ignore_media && !aod->got_end) {
+ // &&
+ //(aod->state != STATE_FILTER || filter (aod, aot, serialno, op))) {
#ifdef DEBUG
fprintf (aod->df, "anxogg::read_packet_data: no, copy out\n");
#endif
aop = anxogg_packet_new (op, track,
((double)oggz_tell_units(oggz)) / SUBSECONDS);
- memcpy (aop->data, op->packet, op->bytes);
-
aod->delivery_queue = anx_list_append (aod->delivery_queue, aop);
+#if 0
if (aot->nr_headers_remaining > 0) {
aod->nr_headers_remaining--;
aot->nr_headers_remaining--;
@@ -1027,6 +1224,7 @@
return OGGZ_CONTINUE;
}
}
+#endif
}
return OGGZ_STOP_OK;
@@ -1072,6 +1270,7 @@
/* If that's finished this media packet, advance to the next one */
if (aod->current_offset >= aop->length) {
+
aod->delivery_queue = anx_list_remove (aod->delivery_queue, head);
aop = anxogg_packet_free (aop);
@@ -1153,8 +1352,10 @@
aod->need_seek = NEED_SEEK_PENDING;
aod->got_end = 0;
- aod->logicals = oggz_table_new ();
+ aod->tracks = oggz_table_new ();
+ aod->header_queue = NULL;
+
aod->delivery_queue = NULL;
aod->current_offset = 0;
@@ -1242,9 +1443,9 @@
anx_list_free_with (aod->delivery_queue, (AnxFreeFunc)anxogg_packet_free);
- n = oggz_table_size (aod->logicals);
+ n = oggz_table_size (aod->tracks);
for (i = 0; i < n; i++) {
- aot = (AnxOggTrack *)oggz_table_nth (aod->logicals, i, NULL);
+ aot = (AnxOggTrack *)oggz_table_nth (aod->tracks, i, NULL);
if (aot) {
track = &(aot->source_track);
anx_free (track->id);
@@ -1253,7 +1454,7 @@
}
}
- oggz_table_delete (aod->logicals);
+ oggz_table_delete (aod->tracks);
#ifdef DEBUG
#ifdef DEBUG_FILE
More information about the commits
mailing list