[xiph-commits] r16390 - in trunk/xiph-qt: . OggImport/src build-macosx/XiphQT.xcodeproj

arek at svn.xiph.org arek at svn.xiph.org
Sat Aug 1 16:30:49 PDT 2009


Author: arek
Date: 2009-08-01 16:30:49 -0700 (Sat, 01 Aug 2009)
New Revision: 16390

Added:
   trunk/xiph-qt/OggImport/src/stream_private_vorbis.c
   trunk/xiph-qt/OggImport/src/stream_private_vorbis.h
Modified:
   trunk/xiph-qt/ChangeLog
   trunk/xiph-qt/OggImport/src/OggImport.c
   trunk/xiph-qt/OggImport/src/importer_types.h
   trunk/xiph-qt/OggImport/src/samplerefs.c
   trunk/xiph-qt/OggImport/src/samplerefs.h
   trunk/xiph-qt/OggImport/src/stream_flac.h
   trunk/xiph-qt/OggImport/src/stream_speex.h
   trunk/xiph-qt/OggImport/src/stream_theora.c
   trunk/xiph-qt/OggImport/src/stream_theora.h
   trunk/xiph-qt/OggImport/src/stream_types_vorbis.h
   trunk/xiph-qt/OggImport/src/stream_vorbis.c
   trunk/xiph-qt/OggImport/src/stream_vorbis.h
   trunk/xiph-qt/OggImport/src/utils.c
   trunk/xiph-qt/OggImport/src/utils.h
   trunk/xiph-qt/build-macosx/XiphQT.xcodeproj/project.pbxproj
Log:
	* OggImport/src/stream_private_vorbis.h (added):
	* OggImport/src/stream_private_vorbis.c (added):
	* OggImport/src/stream_types_vorbis.h:
	* build-macosx/XiphQT.xcodeproj/project.pbxproj:
	Add code to calculate duration of Vorbis ogg page.
	* OggImport/src/OggImport.c:
	* OggImport/src/importer_types.h:
	* OggImport/src/stream_theora.c:
	* OggImport/src/stream_theora.h:
	* OggImport/src/stream_vorbis.c:
	* OggImport/src/stream_vorbis.h:
	Add code to calculate base granulepos for each group of streams
	and use it to correctly synchronize the streams withing the
	groups.
	* OggImport/src/samplerefs.h:
	* OggImport/src/samplerefs.c:
	Add method for updating the duration of the first pending sample
	reference.
	* OggImport/src/utils.h:
	* OggImport/src/utils.c:
	Add granulepos -> time conversion utility.
	* OggImport/src/stream_flac.h:
	* OggImport/src/stream_speex.h:
	Adapt to changes.



Modified: trunk/xiph-qt/ChangeLog
===================================================================
--- trunk/xiph-qt/ChangeLog	2009-08-01 22:23:02 UTC (rev 16389)
+++ trunk/xiph-qt/ChangeLog	2009-08-01 23:30:49 UTC (rev 16390)
@@ -1,3 +1,34 @@
+2009-08-02  Arek Korbik  <arkadini at gmail.com>
+
+	* OggImport/src/stream_private_vorbis.h (added):
+	* OggImport/src/stream_private_vorbis.c (added):
+	* OggImport/src/stream_types_vorbis.h:
+	* build-macosx/XiphQT.xcodeproj/project.pbxproj:
+	Add code to calculate duration of Vorbis ogg page.
+
+	* OggImport/src/OggImport.c:
+	* OggImport/src/importer_types.h:
+	* OggImport/src/stream_theora.c:
+	* OggImport/src/stream_theora.h:
+	* OggImport/src/stream_vorbis.c:
+	* OggImport/src/stream_vorbis.h:
+	Add code to calculate base granulepos for each group of streams
+	and use it to correctly synchronize the streams withing the
+	groups.
+
+	* OggImport/src/samplerefs.h:
+	* OggImport/src/samplerefs.c:
+	Add method for updating the duration of the first pending sample
+	reference.
+
+	* OggImport/src/utils.h:
+	* OggImport/src/utils.c:
+	Add granulepos -> time conversion utility.
+
+	* OggImport/src/stream_flac.h:
+	* OggImport/src/stream_speex.h:
+	Adapt to changes.
+
 2009-07-18  Arek Korbik  <arkadini at gmail.com>
 
 	* OggImport/src/OggImport.r:

Modified: trunk/xiph-qt/OggImport/src/OggImport.c
===================================================================
--- trunk/xiph-qt/OggImport/src/OggImport.c	2009-08-01 22:23:02 UTC (rev 16389)
+++ trunk/xiph-qt/OggImport/src/OggImport.c	2009-08-01 23:30:49 UTC (rev 16390)
@@ -363,6 +363,12 @@
 
         // si->sampleOffset = 0;
 
+        si->baseGranulePosFound = false;
+        si->baseGranulePos = 0;
+        si->baseGranuleTime = -1;
+        si->baseGranuleTimeSubSecond = 0.0;
+        si->groupBaseOffsetApplied = false;
+
         globals->numTracksStarted++;
     }
 
@@ -775,6 +781,9 @@
                     SetTrackEnabled(si->theTrack, true);
 
                     si->lastGranulePos = 0;
+                    si->baseGranulePos = 0;
+                    si->baseGranulePosFound = false;
+                    si->groupBaseOffsetApplied = false;
                 }
                 else
                 {
@@ -1059,6 +1068,67 @@
 
 /* =============================================================== */
 
+static Boolean found_all_base_gps(OggImportGlobalsPtr globals) {
+    int i;
+    Boolean found_all = true;
+
+    for (i = 0; i < globals->streamCount; i++) {
+        StreamInfoPtr si = &(*globals->streamInfoHandle)[i];
+        if (!si->baseGranulePosFound) {
+            found_all = false;
+            break;
+        }
+    }
+
+    return found_all;
+}
+
+#define TIME_SUBSEC_EARLIER(t1, t1ss, t2, t2ss) (((t1) < (t2)) || (((t1) == (t2)) && ((t1ss) < (t2ss))))
+
+static void set_group_base(OggImportGlobalsPtr globals) {
+    int i;
+    ComponentResult err = noErr;
+    TimeValue64 min = -1;
+    Float64 min_subsec = 0.0;
+
+    dbg_printf("[OI  ]  >> [%08lx] :: set_group_base()\n", (UInt32) globals);
+
+    for (i = 0; i < globals->streamCount; i++) {
+        StreamInfoPtr si = &(*globals->streamInfoHandle)[i];
+
+        dbg_printf("[OI  ]     [%08lx] :: set_group_base(): comparing %lld %lf < %lld %lf\n", (UInt32) globals, si->baseGranuleTime, si->baseGranuleTimeSubSecond,
+                   min, min_subsec);
+
+        if (min == -1 || TIME_SUBSEC_EARLIER(si->baseGranuleTime, si->baseGranuleTimeSubSecond, min, min_subsec)) {
+            min = si->baseGranuleTime;
+            min_subsec = si->baseGranuleTimeSubSecond;
+        }
+    }
+
+    globals->currentGroupBase = min;
+    globals->currentGroupBaseSubSecond = min_subsec;
+
+    dbg_printf("[OI  ] <   [%08lx] :: set_group_base() = %lld %lf\n", (UInt32) globals, globals->currentGroupBase, globals->currentGroupBaseSubSecond);
+}
+
+static ComponentResult update_stream_base_offsets(OggImportGlobalsPtr globals) {
+    int i;
+    ComponentResult ret = noErr;
+
+    for (i = 0; i < globals->streamCount; i++) {
+        StreamInfoPtr si = &(*globals->streamInfoHandle)[i];
+
+        if (si->sfhf->update_group_gp != NULL) {
+            ret = (*si->sfhf->update_group_gp)(globals, si);
+
+            if (ret != noErr)
+                break;
+        }
+    }
+
+    return ret;
+}
+
 static ComponentResult ProcessPage(OggImportGlobalsPtr globals, ogg_page *op) {
     ComponentResult ret = noErr;
     long serialno;
@@ -1113,6 +1183,10 @@
     if (si != NULL) {
         if (process_page) {
             ret = ProcessStreamPage(globals, si, op);
+            if (globals->currentGroupBase < 0 && found_all_base_gps(globals)) {
+                set_group_base(globals);
+                update_stream_base_offsets(globals);
+            }
         }
 
         if (ogg_page_eos(op)) {
@@ -1122,6 +1196,8 @@
                 globals->groupStreamsFound = false;
                 globals->currentGroupOffset = -1;
                 globals->currentGroupOffsetSubSecond = 0.0;
+                globals->currentGroupBase = -1;
+                globals->currentGroupBaseSubSecond = 0.0;
             }
         }
     }
@@ -1185,6 +1261,9 @@
             globals->currentGroupOffsetSubSecond = (Float64) (globals->startTime % GetMovieTimeScale(globals->theMovie)) / (Float64) GetMovieTimeScale(globals->theMovie);
             globals->groupStreamsFound = false;
 
+            globals->currentGroupBase = -1;
+            globals->currentGroupBaseSubSecond = 0.0;
+
             if (!globals->sizeInitialised) {
                 result = XQTGetFileSize(globals);
             }

Modified: trunk/xiph-qt/OggImport/src/importer_types.h
===================================================================
--- trunk/xiph-qt/OggImport/src/importer_types.h	2009-08-01 22:23:02 UTC (rev 16389)
+++ trunk/xiph-qt/OggImport/src/importer_types.h	2009-08-01 23:30:49 UTC (rev 16390)
@@ -101,6 +101,11 @@
     SampleDescriptionHandle sampleDesc;
 
     ogg_int64_t         lastGranulePos;
+    ogg_int64_t         baseGranulePos;
+    Boolean             baseGranulePosFound;
+    TimeValue64         baseGranuleTime;
+    Float64             baseGranuleTimeSubSecond;
+    Boolean             groupBaseOffsetApplied;
 
     TimeValue           incompleteCompensation;
 
@@ -167,6 +172,9 @@
     TimeValue               currentGroupOffset;
     Float64                 currentGroupOffsetSubSecond;   // same as with timeLoaded
 
+    TimeValue64             currentGroupBase;
+    Float64                 currentGroupBaseSubSecond;     // same as with timeLoaded
+
     long                    newMovieFlags;
 
     ComponentInstance	    dataReader;
@@ -247,7 +255,9 @@
 
 typedef ComponentResult (*granulepos_to_time) (StreamInfo *si, ogg_int64_t *gp, TimeRecord *time);
 
+typedef ComponentResult (*update_group_granulepos) (OggImportGlobals *globals, StreamInfo *si);
 
+
 typedef struct stream_format_handle_funcs {
     process_stream_page                 process_page;
 
@@ -264,8 +274,10 @@
     clear_stream                        clear;
 
     granulepos_to_time                  gp_to_time;
+
+    update_group_granulepos             update_group_gp;
 } stream_format_handle_funcs;
 
-#define HANDLE_FUNCTIONS__NULL { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }
+#define HANDLE_FUNCTIONS__NULL { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }
 
 #endif /* __importer_types_h__ */

Modified: trunk/xiph-qt/OggImport/src/samplerefs.c
===================================================================
--- trunk/xiph-qt/OggImport/src/samplerefs.c	2009-08-01 22:23:02 UTC (rev 16389)
+++ trunk/xiph-qt/OggImport/src/samplerefs.c	2009-08-01 23:30:49 UTC (rev 16390)
@@ -124,3 +124,23 @@
 
     return err;
 }
+
+ComponentResult _add_first_duration(StreamInfo *si, TimeValue duration)
+{
+    ComponentResult err = noErr;
+    SampleReference64Record *srptr = NULL;
+
+    if (si->sample_refs_count < 1)
+        return -1;
+
+    srptr = &si->sample_refs[0];
+
+    dbg_printf("[OIsr]  =! _add_first_duration(): dur: %d += %d [%08lx, %08lx]\n", srptr->durationPerSample, duration,
+               (UInt32) si->sample_refs, (UInt32) srptr);
+    srptr->durationPerSample += duration;
+    si->sample_refs_duration += duration;
+
+
+    return err;
+}
+

Modified: trunk/xiph-qt/OggImport/src/samplerefs.h
===================================================================
--- trunk/xiph-qt/OggImport/src/samplerefs.h	2009-08-01 22:23:02 UTC (rev 16389)
+++ trunk/xiph-qt/OggImport/src/samplerefs.h	2009-08-01 23:30:49 UTC (rev 16390)
@@ -37,6 +37,7 @@
 
 extern ComponentResult _store_sample_reference(StreamInfo *si, SInt64 *dataOffset, int size, TimeValue duration, short smp_flags);
 extern ComponentResult _commit_srefs(OggImportGlobals *globals, StreamInfo *si, Boolean *movie_changed);
+extern ComponentResult _add_first_duration(StreamInfo *si, TimeValue duration);
 
 
 #endif /* __samplerefs_h__ */

Modified: trunk/xiph-qt/OggImport/src/stream_flac.h
===================================================================
--- trunk/xiph-qt/OggImport/src/stream_flac.h	2009-08-01 22:23:02 UTC (rev 16389)
+++ trunk/xiph-qt/OggImport/src/stream_flac.h	2009-08-01 23:30:49 UTC (rev 16390)
@@ -51,7 +51,7 @@
 
 #define HANDLE_FUNCTIONS__FLAC { &process_stream_page__flac, &recognize_header__flac, \
             &verify_header__flac, &process_first_packet__flac, &create_sample_description__flac, \
-            NULL, NULL, &initialize_stream__flac, &flush_stream__flac, &clear_stream__flac, NULL }
+            NULL, NULL, &initialize_stream__flac, &flush_stream__flac, &clear_stream__flac, NULL, NULL }
 
 
 #endif /* __stream_flac_h__ */

Added: trunk/xiph-qt/OggImport/src/stream_private_vorbis.c
===================================================================
--- trunk/xiph-qt/OggImport/src/stream_private_vorbis.c	                        (rev 0)
+++ trunk/xiph-qt/OggImport/src/stream_private_vorbis.c	2009-08-01 23:30:49 UTC (rev 16390)
@@ -0,0 +1,105 @@
+/*
+ *  stream_types_vorbis.h
+ *
+ *    Definition of private Vorbis specific data structures.
+ *
+ *
+ *  Copyright (c) 2009  Arek Korbik
+ *
+ *  This file is part of XiphQT, the Xiph QuickTime Components.
+ *
+ *  XiphQT is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2.1 of the License, or (at your option) any later version.
+ *
+ *  XiphQT is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with XiphQT; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ *
+ *  Last modified: $Id$
+ *
+ */
+
+
+#include "stream_vorbis.h"
+#include "debug.h"
+
+
+int
+vorbis_private_extract_info(StreamInfo *si)
+{
+    StreamPrivate__vorbis *info = &(si->si_vorbis.private);
+    _codec_setup_info *ci = (_codec_setup_info *) si->si_vorbis.vi.codec_setup;
+    int i, size;
+
+    long short_size = ci->blocksizes[0];
+    long long_size = ci->blocksizes[1];
+
+    size = info->num_modes = ci->modes;
+
+    i = -1;
+    while ((1 << (++i)) < size);
+    info->mask_modes = (1 << i) - 1;
+
+    for (i = 0; i < size; i++) {
+	info->mode_sizes[i] = (ci->mode_param[i]->blockflag ?
+			       long_size : short_size);
+    }
+
+    return 0;
+}
+
+static long
+_vorbis_private_packet_duration(StreamInfo *si, ogg_packet *current,
+                               ogg_packet *previous)
+{
+    StreamPrivate__vorbis *info = &(si->si_vorbis.private);
+    int mode = (current->packet[0] >> 1) & info->mask_modes;
+    int current_size = info->mode_sizes[mode];
+
+    mode = (previous->packet[0] >> 1) & info->mask_modes;
+
+    return (info->mode_sizes[mode] + current_size) / 4;
+}
+
+long
+vorbis_private_page_duration(StreamInfo *si /*, ogg_page *og */)
+{
+    long duration = 0;
+    int ovret = -1;
+    ogg_packet p1, p2;
+    ogg_packet *previous = NULL;
+    ogg_packet *current = &p1;
+    ogg_packet *other = &p2;
+
+    while (ovret < 0) {
+        ovret = ogg_stream_packetout(&si->os, previous);
+    }
+
+    if (ovret == 0)
+        return -1;
+
+    while (1) {
+        ovret = ogg_stream_packetout(&si->os, current);
+        if (ovret < 0)
+            continue;
+        else if (ovret < 1)
+            break;
+        if (previous != NULL) {
+            duration += _vorbis_private_packet_duration(si, current, previous);
+        }
+
+        previous = current;
+        current = other;
+        other = (other == &p1 ? &p2 : &p1);
+    };
+
+    return duration;
+}


Property changes on: trunk/xiph-qt/OggImport/src/stream_private_vorbis.c
___________________________________________________________________
Added: svn:keywords
   + Id

Added: trunk/xiph-qt/OggImport/src/stream_private_vorbis.h
===================================================================
--- trunk/xiph-qt/OggImport/src/stream_private_vorbis.h	                        (rev 0)
+++ trunk/xiph-qt/OggImport/src/stream_private_vorbis.h	2009-08-01 23:30:49 UTC (rev 16390)
@@ -0,0 +1,100 @@
+/*
+ *  stream_types_vorbis.h
+ *
+ *    Definition of private Vorbis specific data structures.
+ *
+ *
+ *  Copyright (c) 2009  Arek Korbik
+ *
+ *  This file is part of XiphQT, the Xiph QuickTime Components.
+ *
+ *  XiphQT is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2.1 of the License, or (at your option) any later version.
+ *
+ *  XiphQT is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with XiphQT; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ *
+ *  Last modified: $Id$
+ *
+ */
+
+
+#if !defined(__stream_private_vorbis_h__)
+#define __stream_private_vorbis_h__
+
+
+/* The following two structures were almost literally copied from
+   codec_internal.h in libvorbis, at version 1.2.3, and need to be in
+   sync with the libvorbis linked against - otherwise things will
+   break horribly.
+
+   (Yes, I wish there was a cleaner way of getting the needed info...)
+*/
+
+typedef struct {
+    int blockflag;
+    int windowtype;
+    int transformtype;
+    int mapping;
+} _vorbis_info_mode;
+
+typedef struct _codec_setup_info {
+
+    /* Vorbis supports only short and long blocks, but allows the
+       encoder to choose the sizes */
+
+    long blocksizes[2];
+
+    /* modes are the primary means of supporting on-the-fly different
+       blocksizes, different channel mappings (LR or M/A),
+       different residue backends, etc.  Each mode consists of a
+       blocksize flag and a mapping (along with the mapping setup */
+
+    int        modes;
+    int        maps;
+    int        floors;
+    int        residues;
+    int        books;
+    int        psys;     /* encode only */
+
+    _vorbis_info_mode       *mode_param[64];
+    int                     map_type[64];
+
+#if 0  /* we don't need the rest, so... */
+    vorbis_info_mapping    *map_param[64];
+    int                     floor_type[64];
+    vorbis_info_floor      *floor_param[64];
+    int                     residue_type[64];
+    vorbis_info_residue    *residue_param[64];
+    static_codebook        *book_param[256];
+    codebook               *fullbooks;
+
+    vorbis_info_psy        *psy_param[4]; /* encode only */
+    vorbis_info_psy_global psy_g_param;
+
+    bitrate_manager_info   bi;
+    highlevel_encode_setup hi; /* used only by vorbisenc.c.  It's a
+                                  highly redundant structure, but
+                                  improves clarity of program flow. */
+    int         halfrate_flag; /* painless downsample for decode */
+#endif /* 0 */
+} _codec_setup_info;
+
+
+typedef struct {
+    int num_modes;
+    int mask_modes;
+    long mode_sizes[64];
+} StreamPrivate__vorbis;
+
+
+#endif /* __stream_private_vorbis_h__ */


Property changes on: trunk/xiph-qt/OggImport/src/stream_private_vorbis.h
___________________________________________________________________
Added: svn:keywords
   + Id

Modified: trunk/xiph-qt/OggImport/src/stream_speex.h
===================================================================
--- trunk/xiph-qt/OggImport/src/stream_speex.h	2009-08-01 22:23:02 UTC (rev 16389)
+++ trunk/xiph-qt/OggImport/src/stream_speex.h	2009-08-01 23:30:49 UTC (rev 16390)
@@ -49,7 +49,7 @@
 
 #define HANDLE_FUNCTIONS__SPEEX { &process_stream_page__speex, &recognize_header__speex, \
             &verify_header__speex, &process_first_packet__speex, &create_sample_description__speex, \
-            NULL, NULL, &initialize_stream__speex, &flush_stream__speex, &clear_stream__speex, NULL }
+            NULL, NULL, &initialize_stream__speex, &flush_stream__speex, &clear_stream__speex, NULL, NULL }
 
 
 #endif /* __stream_vorbis_h__ */

Modified: trunk/xiph-qt/OggImport/src/stream_theora.c
===================================================================
--- trunk/xiph-qt/OggImport/src/stream_theora.c	2009-08-01 22:23:02 UTC (rev 16389)
+++ trunk/xiph-qt/OggImport/src/stream_theora.c	2009-08-01 23:30:49 UTC (rev 16390)
@@ -83,6 +83,56 @@
     return a;
 }
 
+/* TEMPORARILY here */
+long
+theora_private_page_duration(StreamInfo *si /*, ogg_page *og */)
+{
+    long count = 0;
+    int oret = 0;
+    ogg_packet op;
+
+    while (1) {
+        oret = ogg_stream_packetout(&si->os, &op);
+        if (oret < 0)
+            continue;
+        else if (oret < 1)
+            break;
+        count += 1;
+    };
+
+    return count;
+}
+
+
+static void _gp_to_time_subsec(StreamInfo *si, ogg_int64_t gp, TimeValue64 *ts, Float64 *subsec)
+{
+    ogg_int64_t frames = gp >> si->si_theora.granulepos_shift;
+    frames += gp - (frames << si->si_theora.granulepos_shift);
+
+    *ts = frames * si->si_theora.fps_framelen / si->rate;
+    *subsec = (Float64) (frames - *ts * si->rate / si->si_theora.fps_framelen) * (Float64) si->si_theora.fps_framelen / (Float64) si->rate;
+}
+
+static void _find_base_gp(StreamInfo *si, ogg_page *opg)
+{
+    ogg_int64_t grpos = ogg_page_granulepos(opg);
+    if (grpos >= 0) {
+        ogg_int64_t duration = theora_private_page_duration(si); // will use page that's been recently pagein-ed, assumes
+                                                                 // we've been consistently packeting-out so far...
+        dbg_printf("---/t / page duration: %lld, %lld (%lld)\n", duration, ogg_page_granulepos(opg), si->lastGranulePos);
+        if (duration >= 0) {
+            si->baseGranulePos = grpos - (duration << si->si_theora.granulepos_shift); // subtracting from the "frames at last keyframe" part directly
+            if (si->baseGranulePos < 0)
+                si->baseGranulePos = 0;
+            _gp_to_time_subsec(si, si->baseGranulePos, &si->baseGranuleTime, &si->baseGranuleTimeSubSecond);
+            si->baseGranulePosFound = true;
+            dbg_printf("---/t / found base grpos: %lld, %lf\n", si->baseGranuleTime, si->baseGranuleTimeSubSecond);
+        }
+    } else {
+        dbg_printf("---/t / page no duration: %lld (nr: %ld) (%lld)\n", ogg_page_granulepos(opg), ogg_page_pageno(opg), si->lastGranulePos);
+    }
+}
+
 int recognize_header__theora(ogg_page *op)
 {
     dbg_printf("! -- - theora_recognise_header: '%4.4s'\n", ((char *)op->body) + 1);
@@ -285,6 +335,13 @@
     case kTStateReadingCodebooks:
         ogg_stream_pagein(&si->os, opg);
         break;
+
+    case kTStateReadingFirstPacket:
+    case kTStateReadingPackets:
+        if (!si->baseGranulePosFound)
+            ogg_stream_pagein(&si->os, opg);
+        break;
+
     default:
         break;
     }
@@ -357,14 +414,13 @@
             break;
 
         case kTStateReadingFirstPacket:
-            if (ogg_page_pageno(opg) > 3) {
-                si->lastGranulePos = ogg_page_granulepos(opg);
-                dbg_printf("----==< skipping: %llx, %lx\n", si->lastGranulePos, ogg_page_pageno(opg));
-                loop = false;
+            si->lastGranulePos = 0;
 
-                if (si->lastGranulePos < 0)
-                    si->lastGranulePos = 0;
-            }
+            _find_base_gp(si, opg);
+
+            if (si->baseGranulePosFound)
+                si->lastGranulePos = si->baseGranulePos;
+
             si->si_theora.state = kTStateReadingPackets;
             break;
 
@@ -377,13 +433,13 @@
                 int i, segments;
                 Boolean continued = ogg_page_continued(opg);
                 TimeValue durationPerSample = 0;
-                ogg_int64_t last_packet_pos = si->lastGranulePos >> si->si_theora.granulepos_shift;
-                last_packet_pos += si->lastGranulePos - (last_packet_pos << si->si_theora.granulepos_shift);
 
-                loop = false;
-                if (ovret < 0) {
-                    ret = invalidMedia;
-                    break;
+                if (!si->baseGranulePosFound) {
+                    _find_base_gp(si, opg);
+
+                    if (si->baseGranulePosFound) {
+                        si->lastGranulePos = si->baseGranulePos;
+                    }
                 }
 
                 if (continued)
@@ -467,7 +523,7 @@
                 }
 
                 if (!globals->usingIdle) {
-                    if (si->sample_refs_count >= kTSRefsInitial)
+                    if (si->sample_refs_count >= kTSRefsInitial && si->baseGranulePosFound)
                         ret = _commit_srefs(globals, si, &movie_changed);
                 }
 
@@ -493,6 +549,11 @@
     ComponentResult err = noErr;
     Boolean movie_changed = false;
 
+    if (!si->baseGranulePosFound) {
+        dbg_printf("[OIv ]  =  [%08lx] :: flush_stream() - asked to flush but still no base grpos!!\n", (UInt32) globals);
+        return err;
+    }
+
     err = _commit_srefs(globals, si, &movie_changed);
 
     if (movie_changed && notify)
@@ -516,3 +577,44 @@
 
     return err;
 };
+
+ComponentResult update_group_gp__theora(OggImportGlobals *globals, StreamInfo *si)
+{
+    ComponentResult ret = noErr;
+    TimeValue offset;
+    Float64 offset_subsec;
+
+    if (si->groupBaseOffsetApplied)
+        return ret;
+
+    if (globals->currentGroupBase == si->baseGranuleTime && globals->currentGroupBaseSubSecond == si->baseGranuleTimeSubSecond)
+        return ret;
+
+    offset = si->baseGranuleTime - globals->currentGroupBase;
+    offset_subsec =  si->baseGranuleTimeSubSecond - globals->currentGroupBaseSubSecond;
+    if (offset_subsec < 0.0) {
+        offset -= 1;
+        offset_subsec += 1.0;
+    }
+
+    dbg_printf("---/t / offset diff: %ld %lf\n", offset, offset_subsec);
+
+    if (offset > 0) {
+        si->streamOffset += offset * GetMovieTimeScale(globals->theMovie);
+        dbg_printf("---/t / adjusting streamOffset: %ld (dt: %ld)\n", si->streamOffset, offset * GetMovieTimeScale(globals->theMovie));
+    }
+
+    if (offset_subsec > 0.0) {
+        dbg_printf("---/t / adjusting streamOffsetSamples: %ld (dt: %ld)\n", si->streamOffsetSamples, (UInt32) (offset_subsec * si->rate));
+        if (_add_first_duration(si, offset_subsec * si->rate) != noErr)
+            si->streamOffsetSamples += offset_subsec * si->rate;
+    }
+
+    si->groupBaseOffsetApplied = true;
+
+    dbg_printf("[OIt ]  =  [%08lx] :: update_group_gp(): group base: (%lld, %lf) stream base: (%lld, %lf)\n", (UInt32) globals,
+               globals->currentGroupBase, globals->currentGroupBaseSubSecond, si->baseGranuleTime, si->baseGranuleTimeSubSecond);
+
+
+    return ret;
+};

Modified: trunk/xiph-qt/OggImport/src/stream_theora.h
===================================================================
--- trunk/xiph-qt/OggImport/src/stream_theora.h	2009-08-01 22:23:02 UTC (rev 16389)
+++ trunk/xiph-qt/OggImport/src/stream_theora.h	2009-08-01 23:30:49 UTC (rev 16390)
@@ -51,11 +51,12 @@
 extern ComponentResult flush_stream__theora(OggImportGlobals *globals, StreamInfo *si, Boolean notify);
 
 extern ComponentResult granulepos_to_time__theora(StreamInfo *si, ogg_int64_t *gp, TimeRecord *time);
+extern ComponentResult update_group_gp__theora(OggImportGlobals *globals, StreamInfo *si);
 
 #define HANDLE_FUNCTIONS__THEORA { &process_stream_page__theora, &recognize_header__theora, \
             &verify_header__theora, &process_first_packet__theora, &create_sample_description__theora, \
             &create_track__theora, &create_track_media__theora, &initialize_stream__theora, flush_stream__theora, \
-            &clear_stream__theora, &granulepos_to_time__theora }
+            &clear_stream__theora, &granulepos_to_time__theora, &update_group_gp__theora }
 
 
 #endif /* __stream_theora_h__ */

Modified: trunk/xiph-qt/OggImport/src/stream_types_vorbis.h
===================================================================
--- trunk/xiph-qt/OggImport/src/stream_types_vorbis.h	2009-08-01 22:23:02 UTC (rev 16389)
+++ trunk/xiph-qt/OggImport/src/stream_types_vorbis.h	2009-08-01 23:30:49 UTC (rev 16390)
@@ -34,6 +34,7 @@
 
 #if !defined(_NO_VORBIS_SUPPORT)
 #include <Vorbis/codec.h>
+#include "stream_private_vorbis.h"
 
 typedef enum VorbisImportStates {
     kVStateInitial,
@@ -54,6 +55,8 @@
 
     vorbis_info vi;
     vorbis_comment vc;
+
+    StreamPrivate__vorbis private;
 } StreamInfo__vorbis;
 
 

Modified: trunk/xiph-qt/OggImport/src/stream_vorbis.c
===================================================================
--- trunk/xiph-qt/OggImport/src/stream_vorbis.c	2009-08-01 22:23:02 UTC (rev 16389)
+++ trunk/xiph-qt/OggImport/src/stream_vorbis.c	2009-08-01 23:30:49 UTC (rev 16390)
@@ -39,8 +39,32 @@
 #include "data_types.h"
 
 #include "samplerefs.h"
+#include "utils.h"
 
+extern int vorbis_private_extract_info(StreamInfo *si);
+extern long vorbis_private_page_duration(StreamInfo *si);
 
+
+static void _find_base_gp(StreamInfo *si, ogg_page *opg)
+{
+    ogg_int64_t grpos = ogg_page_granulepos(opg);
+    if (grpos >= 0) {
+        ogg_int64_t duration = vorbis_private_page_duration(si); // will use page that's been recently pagein-ed, assumes
+                                                                 // we've been consistently packeting-out so far...
+        dbg_printf("---/v / page duration: %lld, %lld (%lld)\n", duration, ogg_page_granulepos(opg), si->lastGranulePos);
+        if (duration >= 0) {
+            si->baseGranulePos = grpos - duration;
+            if (si->baseGranulePos < 0)
+                si->baseGranulePos = 0;
+            gp_to_time_subsec(si->rate, si->baseGranulePos, &si->baseGranuleTime, &si->baseGranuleTimeSubSecond);
+            si->baseGranulePosFound = true;
+            dbg_printf("---/v / found base grpos: %lld, %lf\n", si->baseGranuleTime, si->baseGranuleTimeSubSecond);
+        }
+    } else {
+        dbg_printf("---/v / page no duration: %lld (nr: %ld) (%lld)\n", ogg_page_granulepos(opg), ogg_page_pageno(opg), si->lastGranulePos);
+    }
+}
+
 int recognize_header__vorbis(ogg_page *op)
 {
     if (!strncmp("\1vorbis", (char *)op->body, 7))
@@ -205,6 +229,13 @@
     case kVStateReadingCodebooks:
         ogg_stream_pagein(&si->os, opg);
         break;
+
+    case kVStateReadingFirstPacket:
+    case kVStateReadingPackets:
+        if (!si->baseGranulePosFound)
+            ogg_stream_pagein(&si->os, opg);
+        break;
+
     default:
         break;
     }
@@ -261,18 +292,20 @@
                 dbg_printf("---/  / streamOffset: [%ld, %ld], %lg\n", si->streamOffset, si->streamOffsetSamples, globals->currentGroupOffsetSubSecond);
                 si->incompleteCompensation = 0;
                 loop = false; //there should be an end of page here according to specs...
+
+                vorbis_private_extract_info(si);
             }
             break;
 
         case kVStateReadingFirstPacket:
-            if (ogg_page_pageno(opg) > 3) {
-                si->lastGranulePos = ogg_page_granulepos(opg);
-                dbg_printf("----==< skipping: %llx, %lx\n", si->lastGranulePos, ogg_page_pageno(opg));
-                loop = false;
+            si->lastGranulePos = 0;
 
-                if (si->lastGranulePos < 0)
-                    si->lastGranulePos = 0;
-            }
+            _find_base_gp(si, opg);
+
+            if (si->baseGranulePosFound)
+                si->lastGranulePos = si->baseGranulePos;
+
+            // now update the sound desc
             {
                 unsigned long pagenoatom[3] = { EndianU32_NtoB(sizeof(pagenoatom)), EndianU32_NtoB(kCookieTypeVorbisFirstPageNo),
                                                 EndianU32_NtoB(ogg_page_pageno(opg)) };
@@ -298,6 +331,16 @@
                 TimeValue   duration  = pos - si->lastGranulePos;
                 short       smp_flags = 0;
 
+                if (!si->baseGranulePosFound) {
+                    _find_base_gp(si, opg);
+
+                    if (si->baseGranulePosFound) {
+                        si->lastGranulePos = si->baseGranulePos;
+                        // update current page duration as we now know it
+                        duration = pos - si->lastGranulePos;
+                    }
+                }
+
                 if (ogg_page_continued(opg) || si->incompleteCompensation != 0)
                     smp_flags |= mediaSampleNotSync;
 
@@ -317,6 +360,9 @@
                 if (si->insertTime == 0 && si->streamOffsetSamples > 0) {
                     dbg_printf("   -   :++: increasing duration (%ld) by sampleOffset: %ld\n", duration, si->streamOffsetSamples);
                     duration += si->streamOffsetSamples;
+                    
+                    si->streamOffsetSamples = 0;
+                    
                 }
 
                 ret = _store_sample_reference(si, &globals->dataOffset, len, duration, smp_flags);
@@ -327,7 +373,7 @@
 
                 if (!globals->usingIdle) {
                     //if (si->sample_refs_count >= si->sample_refs_size)
-                    if (si->sample_refs_count >= kVSRefsInitial)
+                    if (si->sample_refs_count >= kVSRefsInitial && si->baseGranulePosFound)
                         ret = _commit_srefs(globals, si, &movie_changed);
                 }
 
@@ -353,6 +399,11 @@
     ComponentResult ret = noErr;
     Boolean movie_changed = false;
 
+    if (!si->baseGranulePosFound) {
+        dbg_printf("[OIv ]  =  [%08lx] :: flush_stream() - asked to flush but still no base grpos!!\n", (UInt32) globals);
+        return ret;
+    }
+
     ret = _commit_srefs(globals, si, &movie_changed);
 
     if (movie_changed && notify)
@@ -360,3 +411,43 @@
 
     return ret;
 };
+
+ComponentResult update_group_gp__vorbis(OggImportGlobals *globals, StreamInfo *si)
+{
+    ComponentResult ret = noErr;
+    TimeValue offset;
+    Float64 offset_subsec;
+
+    if (si->groupBaseOffsetApplied)
+        return ret;
+
+    if (globals->currentGroupBase == si->baseGranuleTime && globals->currentGroupBaseSubSecond == si->baseGranuleTimeSubSecond)
+        return ret;
+
+    offset = si->baseGranuleTime - globals->currentGroupBase;
+    offset_subsec =  si->baseGranuleTimeSubSecond - globals->currentGroupBaseSubSecond;
+    if (offset_subsec < 0.0) {
+        offset -= 1;
+        offset_subsec += 1.0;
+    }
+
+    dbg_printf("---/v / offset diff: %ld %lf\n", offset, offset_subsec);
+
+    if (offset > 0) {
+        si->streamOffset += offset * GetMovieTimeScale(globals->theMovie);
+        dbg_printf("---/v / adjusting streamOffset: %ld (dt: %ld)\n", si->streamOffset, offset * GetMovieTimeScale(globals->theMovie));
+    }
+
+    if (offset_subsec > 0.0) {
+        dbg_printf("---/v / adjusting streamOffsetSamples: %ld (dt: %ld)\n", si->streamOffsetSamples, (UInt32) (offset_subsec * si->rate));
+        if (_add_first_duration(si, offset_subsec * si->rate) != noErr)
+            si->streamOffsetSamples += offset_subsec * si->rate;
+    }
+
+    si->groupBaseOffsetApplied = true;
+
+    dbg_printf("[OIv ]  =  [%08lx] :: update_group_gp(): group base: (%lld, %lf) stream base: (%lld, %lf)\n", (UInt32) globals,
+               globals->currentGroupBase, globals->currentGroupBaseSubSecond, si->baseGranuleTime, si->baseGranuleTimeSubSecond);
+
+    return ret;
+};

Modified: trunk/xiph-qt/OggImport/src/stream_vorbis.h
===================================================================
--- trunk/xiph-qt/OggImport/src/stream_vorbis.h	2009-08-01 22:23:02 UTC (rev 16389)
+++ trunk/xiph-qt/OggImport/src/stream_vorbis.h	2009-08-01 23:30:49 UTC (rev 16390)
@@ -46,10 +46,12 @@
 extern int process_first_packet__vorbis(StreamInfo *si, ogg_page *op, ogg_packet *opckt);
 extern ComponentResult process_stream_page__vorbis(OggImportGlobals *globals, StreamInfo *si, ogg_page *opg);
 extern ComponentResult flush_stream__vorbis(OggImportGlobals *globals, StreamInfo *si, Boolean notify);
+extern ComponentResult update_group_gp__vorbis(OggImportGlobals *globals, StreamInfo *si);
 
 #define HANDLE_FUNCTIONS__VORBIS { &process_stream_page__vorbis, &recognize_header__vorbis, \
             &verify_header__vorbis, &process_first_packet__vorbis, &create_sample_description__vorbis, \
-            NULL, NULL, &initialize_stream__vorbis, &flush_stream__vorbis, &clear_stream__vorbis, NULL }
+            NULL, NULL, &initialize_stream__vorbis, &flush_stream__vorbis, &clear_stream__vorbis, NULL, \
+            &update_group_gp__vorbis }
 
 
 #endif /* __stream_vorbis_h__ */

Modified: trunk/xiph-qt/OggImport/src/utils.c
===================================================================
--- trunk/xiph-qt/OggImport/src/utils.c	2009-08-01 22:23:02 UTC (rev 16389)
+++ trunk/xiph-qt/OggImport/src/utils.c	2009-08-01 23:30:49 UTC (rev 16390)
@@ -84,3 +84,9 @@
         }
     }
 }
+
+void gp_to_time_subsec(int rate, ogg_int64_t gp, TimeValue64 *ts, Float64 *subsec)
+{
+    *ts = gp / rate;
+    *subsec = (Float64) (gp - *ts * rate) / (Float64) rate;
+}

Modified: trunk/xiph-qt/OggImport/src/utils.h
===================================================================
--- trunk/xiph-qt/OggImport/src/utils.h	2009-08-01 22:23:02 UTC (rev 16389)
+++ trunk/xiph-qt/OggImport/src/utils.h	2009-08-01 23:30:49 UTC (rev 16390)
@@ -38,6 +38,7 @@
 extern int unpack_vorbis_comments(vorbis_comment *vc, const void *data, UInt32 data_size);
 extern void find_last_page_GP(const unsigned char *data, UInt32 data_size,
                               ogg_int64_t *gp, long *serialno);
+extern void gp_to_time_subsec(int rate, ogg_int64_t gp, TimeValue64 *ts, Float64 *subsec);
 
 
 #endif /* __ogg_utils_h__ */

Modified: trunk/xiph-qt/build-macosx/XiphQT.xcodeproj/project.pbxproj
===================================================================
--- trunk/xiph-qt/build-macosx/XiphQT.xcodeproj/project.pbxproj	2009-08-01 22:23:02 UTC (rev 16389)
+++ trunk/xiph-qt/build-macosx/XiphQT.xcodeproj/project.pbxproj	2009-08-01 23:30:49 UTC (rev 16390)
@@ -8,6 +8,8 @@
 
 /* Begin PBXBuildFile section */
 		09C8F66C0C82FC7D00F72188 /* libtheoradec.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 09C8F6460C82FBE500F72188 /* libtheoradec.a */; };
+		37B42EC70FF5453E00FC88AE /* stream_private_vorbis.c in Sources */ = {isa = PBXBuildFile; fileRef = 37B42EC50FF5453E00FC88AE /* stream_private_vorbis.c */; };
+		37B42EC80FF5453E00FC88AE /* stream_private_vorbis.c in Sources */ = {isa = PBXBuildFile; fileRef = 37B42EC50FF5453E00FC88AE /* stream_private_vorbis.c */; };
 		37CA8E6D0DD74A65005C8CB6 /* libtheoradec.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 09C8F6460C82FBE500F72188 /* libtheoradec.a */; };
 		7326B5130B5AC44B004CE9D3 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 089C167DFE841241C02AAC07 /* InfoPlist.strings */; };
 		7326B5160B5AC44B004CE9D3 /* common.c in Sources */ = {isa = PBXBuildFile; fileRef = 7374489F0B19EC05002B059E /* common.c */; };
@@ -391,6 +393,8 @@
 		089C167EFE841241C02AAC07 /* English */ = {isa = PBXFileReference; fileEncoding = 10; lastKnownFileType = text.plist.strings; name = English; path = English.lproj/InfoPlist.strings; sourceTree = "<group>"; };
 		08EA7FFBFE8413EDC02AAC07 /* Carbon.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Carbon.framework; path = /System/Library/Frameworks/Carbon.framework; sourceTree = "<absolute>"; };
 		32BAE0B30371A71500C91783 /* XiphQT_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = XiphQT_Prefix.pch; sourceTree = "<group>"; };
+		37B42EC50FF5453E00FC88AE /* stream_private_vorbis.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = stream_private_vorbis.c; path = ../OggImport/src/stream_private_vorbis.c; sourceTree = SOURCE_ROOT; };
+		37B42EC60FF5453E00FC88AE /* stream_private_vorbis.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = stream_private_vorbis.h; path = ../OggImport/src/stream_private_vorbis.h; sourceTree = SOURCE_ROOT; };
 		7326B5510B5AC44B004CE9D3 /* XiphQT (decoders).component */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "XiphQT (decoders).component"; sourceTree = BUILT_PRODUCTS_DIR; };
 		7326B5520B5AC44B004CE9D3 /* Info (decoders).plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "Info (decoders).plist"; sourceTree = "<group>"; };
 		73271C820B610B2400175874 /* RingBufferTests.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RingBufferTests.h; path = ../tests/common/RingBufferTests.h; sourceTree = SOURCE_ROOT; };
@@ -750,6 +754,8 @@
 		737448C10B19EC3E002B059E /* vorbis */ = {
 			isa = PBXGroup;
 			children = (
+				37B42EC50FF5453E00FC88AE /* stream_private_vorbis.c */,
+				37B42EC60FF5453E00FC88AE /* stream_private_vorbis.h */,
 				737448B00B19EC05002B059E /* stream_types_vorbis.h */,
 				737448B10B19EC05002B059E /* stream_vorbis.c */,
 				737448B20B19EC05002B059E /* stream_vorbis.h */,
@@ -1351,6 +1357,7 @@
 				7326B5320B5AC44B004CE9D3 /* CAOggFLACDecoder.cpp in Sources */,
 				7326B5330B5AC44B004CE9D3 /* flac_entrypoints.cpp in Sources */,
 				7373EDD20B7BDCAA00591836 /* samplerefs.c in Sources */,
+				37B42EC80FF5453E00FC88AE /* stream_private_vorbis.c in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -1415,6 +1422,7 @@
 				73744CAE0B1A3D07002B059E /* stream_audio.c in Sources */,
 				73744CB20B1A3D07002B059E /* stream_video.c in Sources */,
 				7373EDD00B7BDCAA00591836 /* samplerefs.c in Sources */,
+				37B42EC70FF5453E00FC88AE /* stream_private_vorbis.c in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};



More information about the commits mailing list