int ogg_stream_pagein(ogg_stream_state *os, ogg_page *og){ unsigned char *header=og->header; unsigned char *body=og->body; long bodysize=og->body_len; int segptr=0; int version=ogg_page_version(og); int continued=ogg_page_continued(og); int bos=ogg_page_bos(og); int eos=ogg_page_eos(og); ogg_int64_t granulepos=ogg_page_granulepos(og); int serialno=ogg_page_serialno(og); long pageno=ogg_page_pageno(og); int segments=header[26]; /* clean up 'returned data' */ { long lr=os->lacing_returned; long br=os->body_returned; /* body data */ if(br){ os->body_fill-=br; if(os->body_fill) memmove(os->body_data,os->body_data+br,os->body_fill); os->body_returned=0; } if(lr){ /* segment table */ if(os->lacing_fill-lr){ memmove(os->lacing_vals,os->lacing_vals+lr, (os->lacing_fill-lr)*sizeof(*os->lacing_vals)); memmove(os->granule_vals,os->granule_vals+lr, (os->lacing_fill-lr)*sizeof(*os->granule_vals)); } os->lacing_fill-=lr; os->lacing_packet-=lr; os->lacing_returned=0; } } /* check the serial number */ if(serialno!=os->serialno)return(-1); if(version>0)return(-1); _os_lacing_expand(os,segments+1); /* are we in sequence? */ if(pageno!=os->pageno){ int i; /* unroll previous partial packet (if any) */ for(i=os->lacing_packet;i<os->lacing_fill;i++) os->body_fill-=os->lacing_vals[i]&0xff; os->lacing_fill=os->lacing_packet; /* make a note of dropped data in segment table */ if(os->pageno!=-1){ os->lacing_vals[os->lacing_fill++]=0x400; os->lacing_packet++; } } /* are we a 'continued packet' page? If so, we may need to skip some segments */ if(continued){ if(os->lacing_fill<1 || os->lacing_vals[os->lacing_fill-1]==0x400){ bos=0; for(;segptr<segments;segptr++){ int val=header[27+segptr]; body+=val; bodysize-=val; if(val<255){ segptr++; break; } } } } if(bodysize){ _os_body_expand(os,bodysize); memcpy(os->body_data+os->body_fill,body,bodysize); os->body_fill+=bodysize; } { int saved=-1; while(segptr<segments){ int val=header[27+segptr]; os->lacing_vals[os->lacing_fill]=val; os->granule_vals[os->lacing_fill]=-1; if(bos){ os->lacing_vals[os->lacing_fill]|=0x100; bos=0; } if(val<255)saved=os->lacing_fill; os->lacing_fill++; segptr++; if(val<255)os->lacing_packet=os->lacing_fill; } /* set the granulepos on the last granuleval of the last full packet */ if(saved!=-1){ os->granule_vals[saved]=granulepos; } } if(eos){ os->e_o_s=1; if(os->lacing_fill>0) os->lacing_vals[os->lacing_fill-1]|=0x200; } os->pageno=pageno+1; return(0); }
int main () { ogg_sync_state oy; /* sync and verify incoming physical bitstream */ ogg_stream_state os; /* take physical pages, weld into a logical stream of packets */ ogg_page og; /* one Ogg bitstream page. Vorbis packets are inside */ ogg_packet op; /* one raw packet of data for decode */ struct stream *st = NULL; int r; char *buffer; int bytes; int eos = 0; int i; int bufferSize = 4096; r = ogg_sync_init(&oy); /* Now we can read pages */ assert(r == 0); while (1) { /* we repeat if the bitstream is chained */ /* submit a 4k block to the libogg sync layer */ buffer = ogg_sync_buffer(&oy, bufferSize); bytes = fread(buffer, 1, bufferSize, stdin); if (bytes == 0) { fprintf(stderr, "Got stdin EOF.\n"); r = 0; break; } r = ogg_sync_wrote(&oy, bytes); assert(r == 0); /* Get the first page. */ r = ogg_sync_pageout(&oy, &og); if (r == 0) { fprintf(stderr, "Need more data.\n"); continue; } else if (r < 1) { /* have we simply run out of data? If so, we're done. */ if (bytes < bufferSize) break; /* error case. Must not be Vorbis data */ fprintf(stderr, "Input does not appear to be an Ogg bitstream.\n"); r = 1; break; } assert(r == 1); /* Get the serial number and set up the rest of decode. */ /* serialno first; use it to set up a logical stream */ int serialno = ogg_page_serialno(&og); int packets = ogg_page_packets(&og); fprintf(stderr, "version: %d\n", ogg_page_version(&og)); fprintf(stderr, "continued: %d\n", ogg_page_continued(&og)); fprintf(stderr, "pageno: %ld\n", ogg_page_pageno(&og)); fprintf(stderr, "serialno: %d\n", serialno); fprintf(stderr, "packets: %d\n", packets); fprintf(stderr, "granulepos: %lld\n", ogg_page_granulepos(&og)); fprintf(stderr, "eos: %d\n", ogg_page_eos(&og)); fprintf(stderr, "bos: %d\n", ogg_page_bos(&og)); /* we need to get the correct "ogg_stream_state" struct based on the serialno */ struct stream *s = st; while (1) { if (s == NULL) { fprintf(stderr, "creating struct stream for %d\n", serialno); s = malloc(sizeof(struct stream)); s->next = NULL; s->serialno = serialno; ogg_stream_init(&s->os, serialno); if (st == NULL) { st = s; } else { /* have to set "s" to the last element of the "st" linked list */ struct stream *t = st; while (1) { if (t->next == NULL) { t->next = s; break; } else { t = t->next; } } } break; } if (s->serialno == serialno) { break; } s = s->next; } assert(s->serialno == serialno); fprintf(stderr, "using struct stream %d\n", s->serialno); /* holy shit that sucked... */ if (ogg_stream_pagein(&s->os, &og) < 0) { /* error; stream version mismatch perhaps */ fprintf(stderr, "Error reading page of Ogg bitstream data.\n"); r = 1; break; } /* iterate though the "packets" in the page */ for (i=0; i<packets; i++) { fprintf(stderr, " Reading packet %d.\n", i); r = ogg_stream_packetout(&s->os, &op); fprintf(stderr, " Reading packet result %d.\n", r); if (r != 1) { /* no page? must not be vorbis */ fprintf(stderr, " Error reading packet.\n"); r = 1; break; } /** * At this point, you'd pass the raw packet data to the vorbis decoder or * whatever your destination is.... */ fprintf(stderr, " bytes: %ld\n", op.bytes); fprintf(stderr, " b_o_s: %ld\n", op.b_o_s); fprintf(stderr, " e_o_s: %ld\n", op.e_o_s); fprintf(stderr, " granulepos: %lld\n", op.granulepos); fprintf(stderr, " packetno: %lld\n", op.packetno); } fprintf(stderr, "\n"); } /* OK, clean up the framer */ ogg_sync_clear(&oy); fprintf(stderr,"\nDone.\n"); return r; }
// the main page reading hook (stream friendly) ssize_t OggReader::ReadPage(bool first_page) { // TRACE("OggReader::ReadPage\n"); int read_size = (first_page ? 4096 : 4*B_PAGE_SIZE); BAutolock autolock(fSyncLock); ogg_page page; retry: int result = ogg_sync_pageout(&fSync, &page); // first read leftovers while (result == 0) { char * buffer = ogg_sync_buffer(&fSync, read_size); ssize_t bytes = Source()->Read(buffer, read_size); if (bytes == 0) { TRACE("OggReader::GetPage: Read: no data\n"); return B_LAST_BUFFER_ERROR; } if (bytes < 0) { TRACE("OggReader::GetPage: Read: error\n"); return bytes; } if (ogg_sync_wrote(&fSync, bytes) != 0) { TRACE("OggReader::GetPage: ogg_sync_wrote failed?: error\n"); return B_ERROR; } result = ogg_sync_pageout(&fSync, &page); if (first_page && (result != 1)) { TRACE("OggReader::GetPage: short first page not found: error\n"); return B_ERROR; } } if (result == -1) { TRACE("OggReader::GetPage: ogg_sync_pageout: not synced: error\n"); return B_ERROR; } if (ogg_page_version(&page) != 0) { TRACE("OggReader::GetPage: ogg_page_version: error in page encoding: error\n"); return B_ERROR; } long serialno = ogg_page_serialno(&page); bool new_serialno = fTracks.find(serialno) == fTracks.end(); if (new_serialno) { // this is an unknown serialno if (ogg_page_bos(&page) == 0) { TRACE("OggReader::GetPage: non-bos page with unknown serialno\n"); #ifdef STRICT_OGG return B_ERROR; #else // silently discard non-bos packets with unknown serialno goto retry; #endif } #ifdef STRICT_OGG if (ogg_page_continued(&page) != 0) { TRACE("oggReader::GetPage: ogg_page_continued: continued page: not ogg\n"); return B_ERROR; } #endif //STRICT_OGG // this is a beginning of stream page ogg_stream_state stream; if (ogg_stream_init(&stream, serialno) != 0) { TRACE("oggReader::GetPage: ogg_stream_init failed?: error\n"); return B_ERROR; } if (ogg_stream_pagein(&stream, &page) != 0) { TRACE("oggReader::GetPage: ogg_stream_pagein: failed: error\n"); return B_ERROR; } ogg_packet packet; if (ogg_stream_packetout(&stream, &packet) != 1) { #ifdef STRICT_OGG return B_ERROR; #endif //STRICT_OGG } if (fSeekable) { fTracks[serialno] = OggSeekable::makeOggSeekable(fSeekable, &fSeekableLock, serialno, packet); } else { class Interface : public StreamInterface { private: OggReader * reader; public: Interface(OggReader * reader) { this->reader = reader; } virtual ssize_t ReadPage() { return reader->ReadPage(); } }; fTracks[serialno] = OggStream::makeOggStream(new Interface(this), serialno, packet); } fCookies.push_back(serialno); } // this check ensures that we only push the initial pages into OggSeekables. if (!fSeekable || new_serialno) { status_t status = fTracks[serialno]->AddPage(fPosition, page); if (status != B_OK) { return status; } fPosition += page.header_len + page.body_len; } return page.header_len + page.body_len; }
ComponentResult process_stream_page__speex(OggImportGlobals *globals, StreamInfo *si, ogg_page *opg) { ComponentResult ret = noErr; int ovret = 0; Boolean loop = true; Boolean movie_changed = false; TimeValue movieTS = GetMovieTimeScale(globals->theMovie); TimeValue mediaTS = 0; TimeValue mediaTS_fl = 0.0; ogg_packet op; switch(si->si_speex.state) { case kSStateReadingComments: case kSStateReadingAdditionalHeaders: ogg_stream_pagein(&si->os, opg); break; default: break; } do { switch(si->si_speex.state) { case kSStateReadingComments: ovret = ogg_stream_packetout(&si->os, &op); if (ovret < 0) { loop = false; ret = invalidMedia; } else if (ovret < 1) { loop = false; } else { unsigned long atomhead[2] = { EndianU32_NtoB(op.bytes + sizeof(atomhead)), EndianU32_NtoB(kCookieTypeSpeexComments) }; PtrAndHand(atomhead, si->soundDescExtension, sizeof(atomhead)); PtrAndHand(op.packet, si->soundDescExtension, op.bytes); ret = CreateTrackAndMedia(globals, si, opg); if (ret != noErr) { dbg_printf("??? -- CreateTrackAndMedia failed?: %ld\n", (long)ret); } unpack_vorbis_comments(&si->si_speex.vc, op.packet, op.bytes); /*err =*/ DecodeCommentsQT(globals, si, &si->si_speex.vc); //NotifyMovieChanged(globals); si->si_speex.state = kSStateReadingAdditionalHeaders; } break; case kSStateReadingAdditionalHeaders: if (si->si_speex.skipped_headers >= si->si_speex.header.extra_headers) { unsigned long endAtom[2] = { EndianU32_NtoB(sizeof(endAtom)), EndianU32_NtoB(kAudioTerminatorAtomType) }; ret = PtrAndHand(endAtom, si->soundDescExtension, sizeof(endAtom)); if (ret == noErr) { ret = AddSoundDescriptionExtension((SoundDescriptionHandle) si->sampleDesc, si->soundDescExtension, siDecompressionParams); //dbg_printf("??? -- Adding extension: %ld\n", ret); } else { //dbg_printf("??? -- Hmm, something went wrong: %ld\n", ret); } si->insertTime = 0; si->streamOffset = globals->currentGroupOffset; mediaTS = GetMediaTimeScale(si->theMedia); mediaTS_fl = (Float64) mediaTS; si->streamOffsetSamples = (TimeValue) (mediaTS_fl * globals->currentGroupOffsetSubSecond) - ((globals->currentGroupOffset % movieTS) * mediaTS / movieTS); dbg_printf("---/ / streamOffset: [%ld, %ld], %lg\n", si->streamOffset, si->streamOffsetSamples, globals->currentGroupOffsetSubSecond); si->incompleteCompensation = 0; si->si_speex.state = kSStateReadingFirstPacket; loop = false; // ??! break; } ovret = ogg_stream_packetout(&si->os, &op); if (ovret < 0) { loop = false; ret = invalidMedia; } else if (ovret < 1) { loop = false; } else { // not much here so far, basically just skip the extra header packet unsigned long atomhead[2] = { EndianU32_NtoB(op.bytes + sizeof(atomhead)), EndianU32_NtoB(kCookieTypeSpeexExtraHeader) }; PtrAndHand(atomhead, si->soundDescExtension, sizeof(atomhead)); PtrAndHand(op.packet, si->soundDescExtension, op.bytes); si->si_speex.skipped_headers += 1; } break; case kSStateReadingFirstPacket: if (ogg_page_pageno(opg) > 2) { si->lastGranulePos = ogg_page_granulepos(opg); dbg_printf("----==< skipping: %llx, %lx\n", si->lastGranulePos, ogg_page_pageno(opg)); loop = false; if (si->lastGranulePos < 0) si->lastGranulePos = 0; } si->si_speex.state = kSStateReadingPackets; break; case kVStateReadingPackets: { ogg_int64_t pos = ogg_page_granulepos(opg); int len = opg->header_len + opg->body_len; TimeValue duration = pos - si->lastGranulePos; short smp_flags = 0; if (ogg_page_continued(opg) || si->incompleteCompensation != 0) smp_flags |= mediaSampleNotSync; if (duration <= 0) { duration = INCOMPLETE_PAGE_DURATION; si->incompleteCompensation -= INCOMPLETE_PAGE_DURATION; } else if (si->incompleteCompensation != 0) { duration += si->incompleteCompensation; si->incompleteCompensation = 0; if (duration <= 0) { ret = badFileFormat; loop = false; break; } } if (si->insertTime == 0 && si->streamOffsetSamples > 0) { dbg_printf(" - :++: increasing duration (%ld) by sampleOffset: %ld\n", duration, si->streamOffsetSamples); duration += si->streamOffsetSamples; } ret = _store_sample_reference(si, &globals->dataOffset, len, duration, smp_flags); if (ret != noErr) { loop = false; break; } if (!globals->usingIdle) { if (si->sample_refs_count >= kSSRefsInitial) ret = _commit_srefs(globals, si, &movie_changed); } if (pos != -1) si->lastGranulePos = pos; } loop = false; break; default: loop = false; } } while(loop); if (movie_changed) NotifyMovieChanged(globals, false); return ret; };
ComponentResult process_stream_page__flac(OggImportGlobals *globals, StreamInfo *si, ogg_page *opg) { ComponentResult ret = noErr; int ovret = 0; Boolean loop = true; Boolean movie_changed = false; TimeValue movieTS = GetMovieTimeScale(globals->theMovie); TimeValue mediaTS = 0; TimeValue mediaTS_fl = 0.0; ogg_packet op; switch(si->si_flac.state) { case kFStateReadingComments: case kFStateReadingAdditionalMDBlocks: ogg_stream_pagein(&si->os, opg); break; default: break; } do { switch(si->si_flac.state) { case kFStateReadingComments: ovret = ogg_stream_packetout(&si->os, &op); if (ovret < 0) { loop = false; ret = invalidMedia; } else if (ovret < 1) { loop = false; } else { ret = CreateTrackAndMedia(globals, si, opg); if (ret != noErr) { dbg_printf("??? -- CreateTrackAndMedia failed?: %ld\n", (long)ret); loop = false; break; } if (si->si_flac.metablocks == 0 && (*((unsigned char*) op.packet) == 0xff)) { si->si_flac.metablocks = si->si_flac.skipped; si->si_flac.state = kFStateReadingAdditionalMDBlocks; break; } { unsigned long atomhead[2] = { EndianU32_NtoB(op.bytes + sizeof(atomhead)), EndianU32_NtoB(kCookieTypeFLACMetadata) }; PtrAndHand(atomhead, si->soundDescExtension, sizeof(atomhead)); PtrAndHand(op.packet, si->soundDescExtension, op.bytes); } if (((* (char *) op.packet) & 0x7f) == 4) { dbg_printf("! > - flac_stream_page - mb: %ld, skipped: %ld, h: %02x\n", si->si_flac.metablocks, si->si_flac.skipped, (*(char *) op.packet) & 0x7f); unpack_vorbis_comments(&si->si_flac.vc, ((char *) op.packet) + 4, op.bytes - 4); /*err =*/ DecodeCommentsQT(globals, si, &si->si_flac.vc); //NotifyMovieChanged(globals); } si->si_flac.skipped += 1; si->si_flac.state = kFStateReadingAdditionalMDBlocks; } break; case kFStateReadingAdditionalMDBlocks: dbg_printf("! -- - flac_stream_page - mb: %ld, skipped: %ld\n", si->si_flac.metablocks, si->si_flac.skipped); if (si->si_flac.metablocks > 0 && si->si_flac.skipped >= si->si_flac.metablocks) { unsigned long endAtom[2] = { EndianU32_NtoB(sizeof(endAtom)), EndianU32_NtoB(kAudioTerminatorAtomType) }; ret = PtrAndHand(endAtom, si->soundDescExtension, sizeof(endAtom)); if (ret == noErr) { ret = AddSoundDescriptionExtension((SoundDescriptionHandle) si->sampleDesc, si->soundDescExtension, siDecompressionParams); //dbg_printf("??? -- Adding extension: %ld\n", ret); } else { //dbg_printf("??? -- Hmm, something went wrong: %ld\n", ret); } si->insertTime = 0; si->streamOffset = globals->currentGroupOffset; mediaTS = GetMediaTimeScale(si->theMedia); mediaTS_fl = (Float64) mediaTS; si->streamOffsetSamples = (TimeValue) (mediaTS_fl * globals->currentGroupOffsetSubSecond) - ((globals->currentGroupOffset % movieTS) * mediaTS / movieTS); dbg_printf("---/ / streamOffset: [%ld, %ld], %lg\n", si->streamOffset, si->streamOffsetSamples, globals->currentGroupOffsetSubSecond); si->incompleteCompensation = 0; si->si_flac.state = kFStateReadingFirstPacket; loop = false; // the audio data is supposed to start on a fresh page break; } ovret = ogg_stream_packetout(&si->os, &op); dbg_printf("! -- - flac_stream_page - ovret: %d\n", ovret); if (ovret < 0) { loop = false; ret = invalidMedia; } else if (ovret < 1) { loop = false; } else { // not much here so far, basically just skip the extra header packet unsigned long atomhead[2] = { EndianU32_NtoB(op.bytes + sizeof(atomhead)), EndianU32_NtoB(kCookieTypeFLACMetadata) }; if (si->si_flac.metablocks == 0 && (* (unsigned char*) op.packet) == 0xff) { si->si_flac.metablocks = si->si_flac.skipped; break; } PtrAndHand(atomhead, si->soundDescExtension, sizeof(atomhead)); PtrAndHand(op.packet, si->soundDescExtension, op.bytes); if (((* (unsigned char *) op.packet) & 0x7f) == 4) { dbg_printf("! > - flac_stream_page - mb: %ld, skipped: %ld, h: %02x\n", si->si_flac.metablocks, si->si_flac.skipped, (*(char *) op.packet) & 0x7f); unpack_vorbis_comments(&si->si_flac.vc, ((char *) op.packet) + 4, op.bytes - 4); /*err =*/ DecodeCommentsQT(globals, si, &si->si_flac.vc); //NotifyMovieChanged(globals); } si->si_flac.skipped += 1; } break; case kFStateReadingFirstPacket: // what to do with this one? is it needed at all?? if (ogg_page_pageno(opg) > 2 && false) { si->lastGranulePos = ogg_page_granulepos(opg); dbg_printf("----==< skipping: %llx, %lx\n", si->lastGranulePos, ogg_page_pageno(opg)); loop = false; if (si->lastGranulePos < 0) si->lastGranulePos = 0; } si->si_flac.state = kFStateReadingPackets; break; case kFStateReadingPackets: { ogg_int64_t pos = ogg_page_granulepos(opg); int len = opg->header_len + opg->body_len; TimeValue duration = pos - si->lastGranulePos; short smp_flags = 0; if (ogg_page_continued(opg) || si->incompleteCompensation != 0) smp_flags |= mediaSampleNotSync; if (duration <= 0) { duration = INCOMPLETE_PAGE_DURATION; si->incompleteCompensation -= INCOMPLETE_PAGE_DURATION; } else if (si->incompleteCompensation != 0) { duration += si->incompleteCompensation; si->incompleteCompensation = 0; if (duration <= 0) { ret = badFileFormat; loop = false; break; } } if (si->insertTime == 0 && si->streamOffsetSamples > 0) { dbg_printf(" - :++: increasing duration (%ld) by sampleOffset: %ld\n", duration, si->streamOffsetSamples); duration += si->streamOffsetSamples; } ret = _store_sample_reference(si, &globals->dataOffset, len, duration, smp_flags); if (ret != noErr) { loop = false; break; } if (!globals->usingIdle) { #if !defined(XIPHQT_FORCE_SINGLE_SAMPLE_REF) if (si->sample_refs_count >= si->sample_refs_size) //if (si->sample_refs_count >= kFSRefsInitial) #endif { ret = _commit_srefs(globals, si, &movie_changed); } } if (pos != -1) si->lastGranulePos = pos; } loop = false; break; default: loop = false; } } while(loop); if (movie_changed) NotifyMovieChanged(globals, false); return ret; };