OSDN Git Service

add seek function.
authorNoumi Akira <noumiakira@users.sourceforge.jp>
Thu, 23 Jul 2009 08:33:33 +0000 (17:33 +0900)
committerNoumi Akira <noumiakira@users.sourceforge.jp>
Thu, 23 Jul 2009 08:33:33 +0000 (17:33 +0900)
Lib/QOgg/OggReader.c
Lib/QOgg/OggReader.h
Lib/QOgg/OggVorbisReader.c
Lib/QOgg/OggVorbisReader.h
Lib/QOgg/StdAfx.h
Lib/QOgg/StreamReader.h
Lib/QOgg/Utils.c

index bdf4f24..48c9ca1 100644 (file)
@@ -143,6 +143,26 @@ static BOOL ReadBuffer(
        return TRUE;
 }
 
+static BOOL SkipBuffer(
+       QO_OggReader_t* t,
+       SIZE_T          cb)
+{
+       if (t->Filled < cb) {
+               if (!ReadNext(t)) {
+                       return FALSE;
+               }
+
+               if (t->Filled < cb) {
+                       return FALSE;
+               }
+       }
+
+       t->Pointer = (t->Pointer + cb) & (t->Size - 1);
+       t->Filled -= cb;
+
+       return TRUE;
+}
+
 /* */
 
 /* Ogg Header
@@ -293,3 +313,57 @@ BOOL QO_OggReader_ReadPayload(
 
 /* */
 
+BOOL QO_OggReader_SkipPayload(
+       QO_OggReader_t* t)
+{
+       INT32 i;
+
+       t->Discontinue = TRUE;
+
+       for (i = 0; i < t->Packets; i++) {
+               if (!SkipBuffer(t, t->PacketsSize[i])) {
+                       return FALSE;
+               }
+       }
+
+       if (t->PacketsSize[i] > 0) {
+               if (!SkipBuffer(t, t->PacketsSize[i])) {
+                       return FALSE;
+               }
+       }
+
+       return TRUE;
+}
+
+/* */
+
+BOOL QO_OggReader_Seek(
+       QO_OggReader_t* t,
+       INT64           pos)
+{
+       INT32 s;
+
+       if (!t->Reader->Seek(t->Reader->Context, pos)) {
+               return FALSE;
+       }
+
+       t->Pointer = 0;
+       t->Filled  = 0;
+
+       if (!ReadNext(t)) {
+               return FALSE;
+       }
+
+       s = QO_ScanCapturePattern(t->Buffer, t->Filled);
+       if (s < 0) {
+               return FALSE;
+       }
+
+       t->Pointer  = s;
+       t->Filled  -= s;
+
+       return TRUE;
+}
+
+/* */
+
index 8f15b83..78e18ad 100644 (file)
@@ -65,6 +65,8 @@ BOOL QO_OggReader_Init(
        QO_Allocator_t*    allocator,
        QO_StreamReader_t* reader);
 
+/* */
+
 BOOL QO_OggReader_ReadHeader(
        QO_OggReader_t* t,
        QO_OggHeader_t* header);
@@ -72,5 +74,14 @@ BOOL QO_OggReader_ReadHeader(
 BOOL QO_OggReader_ReadPayload(
        QO_OggReader_t* t);
 
+BOOL QO_OggReader_SkipPayload(
+       QO_OggReader_t* t);
+
+/* */
+
+BOOL QO_OggReader_Seek(
+       QO_OggReader_t* t,
+       INT64           pos);
+
 /* */
 
index 52c45bb..27244d4 100644 (file)
@@ -19,6 +19,10 @@ BOOL QO_OggVorbisReader_Init(
                return FALSE;
        }
 
+       t->StreamSize = reader->Size(reader->Context);
+
+       t->Position = 0;
+
        t->Setup = QV_CreateDecoderSetup();
        if (t->Setup == NULL) {
                return FALSE;
@@ -98,6 +102,10 @@ BOOL QO_OggVorbisReader_Setup(
                }
 
                if (header.StreamSerialNumber != t->StreamSerialNumber) {
+                       if (!QO_OggReader_SkipPayload(reader)) {
+                               return FALSE;
+                       }
+
                        continue;
                }
 
@@ -151,3 +159,193 @@ BOOL QO_OggVorbisReader_Setup(
 
 /* */
 
+BOOL QO_OggVorbisReader_DetectSamples(
+       QO_OggVorbisReader_t* t,
+       INT64*                samples)
+{
+       QO_OggReader_t* reader = &(t->Reader);
+
+       INT64 psz = reader->Size / 2;
+
+       INT64 pos = t->StreamSize;
+       if (pos >= psz) {
+               pos -= psz;
+       }
+       pos &= ~(psz - 1);
+
+       *samples = 0;
+
+       if (!QO_OggReader_Seek(reader, pos)) {
+               return FALSE;
+       }
+
+       for (; ; ) {
+               QO_OggHeader_t header;
+
+               if (!QO_OggReader_ReadHeader(reader, &header)) {
+                       return FALSE;
+               }
+
+               if (!QO_OggReader_SkipPayload(reader)) {
+                       return FALSE;
+               }
+
+               if (header.StreamSerialNumber == t->StreamSerialNumber &&
+                       (header.HeaderType & HT_EOS) != 0) {
+                       *samples = header.GranulePosition;
+                       break;
+               }
+       }
+
+       return TRUE;
+}
+
+/* */
+
+BOOL QO_OggVorbisReader_QuerySampleRange(
+       QO_OggVorbisReader_t* t,
+       INT64                 pos,
+       QO_OggVorbisRange_t*  range)
+{
+       QO_OggHeader_t header;
+
+       QO_OggReader_t* reader = &(t->Reader);
+
+       SIZE_T sz = reader->Size / 2;
+
+       INT64 start = -1;
+       INT64 end   = -1;
+
+       range->Start = 0;
+       range->End   = 0;
+
+       QV_ResetDecoderChecker(t->Decoder);
+
+       if (!QO_OggReader_Seek(reader, pos)) {
+               return FALSE;
+       }
+
+       /* printf("S: %04X\n", reader->Pointer); */
+
+       for (; ; ) {
+               if (reader->Pointer >= sz) {
+                       /* printf("E: %04X\n", reader->Pointer); */
+                       break;
+               }
+
+               for (; ; ) {
+                       if (!QO_OggReader_ReadHeader(reader, &header)) {
+                               return FALSE;
+                       }
+
+                       if (header.StreamSerialNumber == t->StreamSerialNumber) {
+                               if (!QO_OggReader_ReadPayload(reader)) {
+                                       return FALSE;
+                               }
+                               break;
+                       }
+
+                       if (!QO_OggReader_SkipPayload(reader)) {
+                               return FALSE;
+                       }
+               }
+
+               if (reader->Packets > 0) {
+                       INT32 i, samples = 0;
+
+                       UINT8* pb = reader->PacketsBuffer;
+
+                       if ((pb[0] & 1) != 0) { /* Skip Header Packet */
+                               continue;
+                       }
+
+                       for (i = 0; i < reader->Packets; i++) {
+                               INT32 s = 0;
+                               if (!QV_CheckDecoderChecker(t->Decoder, pb, reader->PacketsSize[i], &s)) {
+                                       return FALSE;
+                               }
+
+                               pb += reader->PacketsSize[i];
+
+                               samples += s;
+                       }
+
+                       if (start < 0) {
+                               start = header.GranulePosition - samples;
+                       }
+
+                       end = header.GranulePosition;
+               }
+       }
+
+       range->Start = start;
+       range->End   = end;
+
+       return TRUE;
+}
+
+/* */
+
+BOOL QO_OggVorbisReader_SeekPage(
+       QO_OggVorbisReader_t* t,
+       INT64                 pos)
+{
+       QO_OggHeader_t header;
+
+       QO_OggReader_t* reader = &(t->Reader);
+
+       QV_ResetDecoderChecker(t->Decoder);
+       QV_ResetDecoder(t->Decoder);
+
+       if (!QO_OggReader_Seek(reader, pos)) {
+               return FALSE;
+       }
+
+       for (; ; ) {
+               for (; ; ) {
+                       if (!QO_OggReader_ReadHeader(reader, &header)) {
+                               return FALSE;
+                       }
+
+                       if (header.StreamSerialNumber == t->StreamSerialNumber) {
+                               if (!QO_OggReader_ReadPayload(reader)) {
+                                       return FALSE;
+                               }
+                               break;
+                       }
+
+                       if (!QO_OggReader_SkipPayload(reader)) {
+                               return FALSE;
+                       }
+               }
+
+               if (reader->Packets > 0) {
+                       INT32 i, samples = 0;
+
+                       UINT8* pb = reader->PacketsBuffer;
+
+                       if ((pb[0] & 1) != 0) { /* Skip Header Packet */
+                               continue;
+                       }
+
+                       for (i = 0; i < reader->Packets; i++) {
+                               INT32 s = 0;
+                               if (!QV_CheckDecoderChecker(t->Decoder, pb, reader->PacketsSize[i], &s)) {
+                                       return FALSE;
+                               }
+
+                               pb += reader->PacketsSize[i];
+
+                               samples += s;
+                       }
+
+                       t->Position = header.GranulePosition - samples;
+                       break;
+               }
+       }
+
+       return TRUE;
+}
+
+/* */
+
index ec2aeb6..23c80e6 100644 (file)
@@ -15,6 +15,10 @@ struct QO_OggVorbisReader {
 
        QO_OggReader_t Reader;
 
+       INT64 StreamSize;
+
+       INT64 Position;
+
        UINT32 StreamSerialNumber;
        UINT32 PageSequenceNumber;
 
@@ -41,5 +45,31 @@ void QO_OggVorbisReader_Release(
 BOOL QO_OggVorbisReader_Setup(
        QO_OggVorbisReader_t* t);
 
+BOOL QO_OggVorbisReader_DetectSamples(
+       QO_OggVorbisReader_t* t,
+       INT64*                samples);
+
+/* */
+
+struct QO_OggVorbisRange {
+
+       INT64 Start;
+       INT64 End;
+
+}; /* QO_OggVorbisRange */
+
+typedef struct QO_OggVorbisRange QO_OggVorbisRange_t;
+
+BOOL QO_OggVorbisReader_QuerySampleRange(
+       QO_OggVorbisReader_t* t,
+       INT64                 pos,
+       QO_OggVorbisRange_t*  range);
+
+/* */
+
+BOOL QO_OggVorbisReader_SeekPage(
+       QO_OggVorbisReader_t* t,
+       INT64                 pos);
+
 /* */
 
index 627ec38..4adb8ea 100644 (file)
@@ -9,3 +9,5 @@
 #include <stdlib.h>
 #include <string.h>
 
+#include <io.h>
+
index 2ce28ad..de4df6f 100644 (file)
@@ -5,6 +5,7 @@
 
 typedef INT32 (*QO_Read_t)(VOID*, VOID*, INT32);
 typedef BOOL  (*QO_Seek_t)(VOID*, INT64);
+typedef INT64 (*QO_Size_t)(VOID*);
 
 struct QO_StreamReader {
 
@@ -12,6 +13,7 @@ struct QO_StreamReader {
 
        QO_Read_t Read;
        QO_Seek_t Seek;
+       QO_Size_t Size;
 
 };
 
index a3f0095..f748cd9 100644 (file)
@@ -49,6 +49,12 @@ static BOOL  s_seek(VOID* ctx, INT64 pos)
        return TRUE;
 }
 
+static INT64 s_size(VOID* ctx)
+{
+       int fd = _fileno((FILE*)ctx);
+       return _filelengthi64(fd);
+}
+
 void QO_StreamReader_Init(
        QO_StreamReader_t* t,
        FILE*              fp)
@@ -57,6 +63,7 @@ void QO_StreamReader_Init(
 
        t->Read = s_read;
        t->Seek = s_seek;
+       t->Size = s_size;
 }
 
 /* */