static PyObject * py_ogg_ogg_page_pageno(PyObject *self, PyObject *args) { int size; long c_out; ogg_page * og; PyArg_ParseTuple(args, "s#", &og, &size); c_out = ogg_page_pageno(og); return Py_BuildValue("l", c_out); };
void CAOggFLACDecoder::InPacket(const void* inInputData, const AudioStreamPacketDescription* inPacketDescription) { if (!mCompressionInitialized) CODEC_THROW(kAudioCodecUnspecifiedError); ogg_page op; if (!WrapOggPage(&op, inInputData, inPacketDescription->mDataByteSize + inPacketDescription->mStartOffset, inPacketDescription->mStartOffset)) CODEC_THROW(kAudioCodecUnspecifiedError); dbg_printf("[ oFD] : [%08lx] InPacket() [%4.4s] %ld\n", (UInt32) this, (char *) (static_cast<const Byte*> (inInputData) + inPacketDescription->mStartOffset), ogg_page_pageno(&op)); ogg_packet opk; SInt32 packet_count = 0; int oret; AudioStreamPacketDescription flac_packet_desc = {0, 0, 0}; UInt32 page_packets = ogg_page_packets(&op); ogg_stream_pagein(&mO_st, &op); while ((oret = ogg_stream_packetout(&mO_st, &opk)) != 0) { if (oret < 0) { page_packets--; continue; } packet_count++; flac_packet_desc.mDataByteSize = opk.bytes; CAFLACDecoder::InPacket(opk.packet, &flac_packet_desc); } if (packet_count > 0) complete_pages += 1; mFramesBufferedList.push_back(OggPagePacket(packet_count, inPacketDescription->mVariableFramesInPacket)); }
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'll need to skip some segments */ if(continued){ 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); }
/* Reads in buffers, parses them, reframes into one-buffer-per-ogg-page, submits * pages to output pad. */ static GstFlowReturn gst_ogg_parse_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer) { GstOggParse *ogg; GstFlowReturn result = GST_FLOW_OK; gint ret = -1; guint32 serialno; GstBuffer *pagebuffer; GstClockTime buffertimestamp = GST_BUFFER_TIMESTAMP (buffer); ogg = GST_OGG_PARSE (parent); GST_LOG_OBJECT (ogg, "Chain function received buffer of size %" G_GSIZE_FORMAT, gst_buffer_get_size (buffer)); gst_ogg_parse_submit_buffer (ogg, buffer); while (ret != 0 && result == GST_FLOW_OK) { ogg_page page; /* We use ogg_sync_pageseek() rather than ogg_sync_pageout() so that we can * track how many bytes the ogg layer discarded (in the case of sync errors, * etc.); this allows us to accurately track the current stream offset */ ret = ogg_sync_pageseek (&ogg->sync, &page); if (ret == 0) { /* need more data, that's fine... */ break; } else if (ret < 0) { /* discontinuity; track how many bytes we skipped (-ret) */ ogg->offset -= ret; } else { gint64 granule = ogg_page_granulepos (&page); #ifndef GST_DISABLE_GST_DEBUG int bos = ogg_page_bos (&page); #endif guint64 startoffset = ogg->offset; GstOggStream *stream; gboolean keyframe; serialno = ogg_page_serialno (&page); stream = gst_ogg_parse_find_stream (ogg, serialno); GST_LOG_OBJECT (ogg, "Timestamping outgoing buffer as %" GST_TIME_FORMAT, GST_TIME_ARGS (buffertimestamp)); if (stream) { buffertimestamp = gst_ogg_stream_get_end_time_for_granulepos (stream, granule); if (ogg->video_stream) { if (stream == ogg->video_stream) { keyframe = gst_ogg_stream_granulepos_is_key_frame (stream, granule); } else { keyframe = FALSE; } } else { keyframe = TRUE; } } else { buffertimestamp = GST_CLOCK_TIME_NONE; keyframe = TRUE; } pagebuffer = gst_ogg_parse_buffer_from_page (&page, startoffset, buffertimestamp); /* We read out 'ret' bytes, so we set the next offset appropriately */ ogg->offset += ret; GST_LOG_OBJECT (ogg, "processing ogg page (serial %08x, pageno %ld, " "granule pos %" G_GUINT64_FORMAT ", bos %d, offset %" G_GUINT64_FORMAT "-%" G_GUINT64_FORMAT ") keyframe=%d", serialno, ogg_page_pageno (&page), granule, bos, startoffset, ogg->offset, keyframe); if (ogg_page_bos (&page)) { /* If we've seen this serialno before, this is technically an error, * we log this case but accept it - this one replaces the previous * stream with this serialno. We can do this since we're streaming, and * not supporting seeking... */ GstOggStream *stream = gst_ogg_parse_find_stream (ogg, serialno); if (stream != NULL) { GST_LOG_OBJECT (ogg, "Incorrect stream; repeats serial number %08x " "at offset %" G_GINT64_FORMAT, serialno, ogg->offset); } if (ogg->last_page_not_bos) { GST_LOG_OBJECT (ogg, "Deleting all referenced streams, found a new " "chain starting with serial %u", serialno); gst_ogg_parse_delete_all_streams (ogg); } stream = gst_ogg_parse_new_stream (ogg, &page); ogg->last_page_not_bos = FALSE; gst_buffer_ref (pagebuffer); stream->headers = g_list_append (stream->headers, pagebuffer); if (!ogg->in_headers) { GST_LOG_OBJECT (ogg, "Found start of new chain at offset %" G_GUINT64_FORMAT, startoffset); ogg->in_headers = 1; } /* For now, we just keep the header buffer in the stream->headers list; * it actually gets output once we've collected the entire set */ } else { /* Non-BOS page. Either: we're outside headers, and this isn't a * header (normal data), outside headers and this is (error!), inside * headers, this is (append header), or inside headers and this isn't * (we've found the end of headers; flush the lot!) * * Before that, we flag that the last page seen (this one) was not a * BOS page; that way we know that when we next see a BOS page it's a * new chain, and we can flush all existing streams. */ page_type type; GstOggStream *stream = gst_ogg_parse_find_stream (ogg, serialno); if (!stream) { GST_LOG_OBJECT (ogg, "Non-BOS page unexpectedly found at %" G_GINT64_FORMAT, ogg->offset); goto failure; } ogg->last_page_not_bos = TRUE; type = gst_ogg_parse_is_header (ogg, stream, &page); if (type == PAGE_PENDING && ogg->in_headers) { gst_buffer_ref (pagebuffer); stream->unknown_pages = g_list_append (stream->unknown_pages, pagebuffer); } else if (type == PAGE_HEADER) { if (!ogg->in_headers) { GST_LOG_OBJECT (ogg, "Header page unexpectedly found outside " "headers at offset %" G_GINT64_FORMAT, ogg->offset); goto failure; } else { /* Append the header to the buffer list, after any unknown previous * pages */ stream->headers = g_list_concat (stream->headers, stream->unknown_pages); g_list_free (stream->unknown_pages); gst_buffer_ref (pagebuffer); stream->headers = g_list_append (stream->headers, pagebuffer); } } else { /* PAGE_DATA, or PAGE_PENDING but outside headers */ if (ogg->in_headers) { /* First non-header page... set caps, flush headers. * * First up, we build a single GValue list of all the pagebuffers * we're using for the headers, in order. * Then we set this on the caps structure. Then we can start pushing * buffers for the headers, and finally we send this non-header * page. */ GstCaps *caps; GstStructure *structure; GValue array = { 0 }; gint count = 0; gboolean found_pending_headers = FALSE; GSList *l; g_value_init (&array, GST_TYPE_ARRAY); for (l = ogg->oggstreams; l != NULL; l = l->next) { GstOggStream *stream = (GstOggStream *) l->data; if (g_list_length (stream->headers) == 0) { GST_LOG_OBJECT (ogg, "No primary header found for stream %08x", stream->serialno); goto failure; } gst_ogg_parse_append_header (&array, GST_BUFFER (stream->headers->data)); count++; } for (l = ogg->oggstreams; l != NULL; l = l->next) { GstOggStream *stream = (GstOggStream *) l->data; GList *j; /* already appended the first header, now do headers 2-N */ for (j = stream->headers->next; j != NULL; j = j->next) { gst_ogg_parse_append_header (&array, GST_BUFFER (j->data)); count++; } } caps = gst_pad_query_caps (ogg->srcpad, NULL); caps = gst_caps_make_writable (caps); structure = gst_caps_get_structure (caps, 0); gst_structure_take_value (structure, "streamheader", &array); gst_pad_set_caps (ogg->srcpad, caps); if (ogg->caps) gst_caps_unref (ogg->caps); ogg->caps = caps; GST_LOG_OBJECT (ogg, "Set \"streamheader\" caps with %d buffers " "(one per page)", count); /* Now, we do the same thing, but push buffers... */ for (l = ogg->oggstreams; l != NULL; l = l->next) { GstOggStream *stream = (GstOggStream *) l->data; GstBuffer *buf = GST_BUFFER (stream->headers->data); result = gst_pad_push (ogg->srcpad, buf); if (result != GST_FLOW_OK) return result; } for (l = ogg->oggstreams; l != NULL; l = l->next) { GstOggStream *stream = (GstOggStream *) l->data; GList *j; /* pushed the first one for each stream already, now do 2-N */ for (j = stream->headers->next; j != NULL; j = j->next) { GstBuffer *buf = GST_BUFFER (j->data); result = gst_pad_push (ogg->srcpad, buf); if (result != GST_FLOW_OK) return result; } } ogg->in_headers = 0; /* And finally the pending data pages */ for (l = ogg->oggstreams; l != NULL; l = l->next) { GstOggStream *stream = (GstOggStream *) l->data; GList *k; if (stream->unknown_pages == NULL) continue; if (found_pending_headers) { GST_WARNING_OBJECT (ogg, "Incorrectly muxed headers found at " "approximate offset %" G_GINT64_FORMAT, ogg->offset); } found_pending_headers = TRUE; GST_LOG_OBJECT (ogg, "Pushing %d pending pages after headers", g_list_length (stream->unknown_pages) + 1); for (k = stream->unknown_pages; k != NULL; k = k->next) { GstBuffer *buf = GST_BUFFER (k->data); result = gst_pad_push (ogg->srcpad, buf); if (result != GST_FLOW_OK) return result; } g_list_foreach (stream->unknown_pages, (GFunc) gst_mini_object_unref, NULL); g_list_free (stream->unknown_pages); stream->unknown_pages = NULL; } } if (granule == -1) { stream->stored_buffers = g_list_append (stream->stored_buffers, pagebuffer); } else { while (stream->stored_buffers) { GstBuffer *buf = stream->stored_buffers->data; buf = gst_buffer_make_writable (buf); GST_BUFFER_TIMESTAMP (buf) = buffertimestamp; if (!keyframe) { GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT); } else { keyframe = FALSE; } result = gst_pad_push (ogg->srcpad, buf); if (result != GST_FLOW_OK) return result; stream->stored_buffers = g_list_delete_link (stream->stored_buffers, stream->stored_buffers); } pagebuffer = gst_buffer_make_writable (pagebuffer); if (!keyframe) { GST_BUFFER_FLAG_SET (pagebuffer, GST_BUFFER_FLAG_DELTA_UNIT); } else { keyframe = FALSE; } result = gst_pad_push (ogg->srcpad, pagebuffer); if (result != GST_FLOW_OK) return result; } } } } } return result; failure: gst_pad_push_event (GST_PAD (ogg->srcpad), gst_event_new_eos ()); return GST_FLOW_ERROR; }
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; }
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; };
int scan_get_oggfileinfo(char *filename, MP3FILE *pmp3) { FILE *file = fopen(filename, "rb"); ogg_sync_state sync; ogg_page page; stream_set *processors = create_stream_set(); int gotpage = 0; ogg_int64_t written = 0; struct stat psb; if(!file) { DPRINTF(E_FATAL, L_SCAN, "Error opening input file \"%s\": %s\n", filename, strerror(errno)); return -1; } DPRINTF(E_INF, L_SCAN, "Processing file \"%s\"...\n\n", filename); if (!stat(filename, &psb)) { pmp3->time_added = psb.st_mtime; if (psb.st_ctime < pmp3->time_added) { pmp3->time_added = psb.st_ctime; } pmp3->time_modified = psb.st_mtime; } else { DPRINTF(E_WARN, L_SCAN, "Error statting: %s\n", strerror(errno)); } ogg_sync_init(&sync); while(get_next_page(file, &sync, &page, &written)) { stream_processor *p = find_stream_processor(processors, &page); gotpage = 1; if(!p) { DPRINTF(E_FATAL, L_SCAN, "Could not find a processor for stream, bailing\n"); return -1; } if(p->isillegal && !p->shownillegal) { char *constraint; switch(p->constraint_violated) { case CONSTRAINT_PAGE_AFTER_EOS: constraint = "Page found for stream after EOS flag"; break; case CONSTRAINT_MUXING_VIOLATED: constraint = "Ogg muxing constraints violated, new " "stream before EOS of all previous streams"; break; default: constraint = "Error unknown."; } DPRINTF(E_WARN, L_SCAN, "Warning: illegally placed page(s) for logical stream %d\n" "This indicates a corrupt ogg file: %s.\n", p->num, constraint); p->shownillegal = 1; /* If it's a new stream, we want to continue processing this page * anyway to suppress additional spurious errors */ if(!p->isnew) continue; } if(p->isnew) { DPRINTF(E_DBG, L_SCAN, "New logical stream (#%d, serial: %08x): type %s\n", p->num, p->serial, p->type); if(!p->start) DPRINTF(E_WARN, L_SCAN, "stream start flag not set on stream %d\n", p->num); } else if(p->start) DPRINTF(E_WARN, L_SCAN, "stream start flag found in mid-stream " "on stream %d\n", p->num); if(p->seqno++ != ogg_page_pageno(&page)) { if(!p->lostseq) DPRINTF(E_WARN, L_SCAN, "sequence number gap in stream %d. Got page %ld " "when expecting page %ld. Indicates missing data.\n", p->num, ogg_page_pageno(&page), p->seqno - 1); p->seqno = ogg_page_pageno(&page); p->lostseq = 1; } else p->lostseq = 0; if(!p->isillegal) { p->process_page(p, &page, pmp3); if(p->end) { if(p->process_end) p->process_end(p, pmp3); DPRINTF(E_DBG, L_SCAN, "Logical stream %d ended\n", p->num); p->isillegal = 1; p->constraint_violated = CONSTRAINT_PAGE_AFTER_EOS; } } } free_stream_set(processors); ogg_sync_clear(&sync); fclose(file); if(!gotpage) { DPRINTF(E_FATAL, L_SCAN, "No ogg data found in file \"%s\".\n" "Input probably not ogg.\n", filename); return -1; } return 0; }
static void process_file(char *filename) { FILE *file = fopen(filename, "rb"); ogg_sync_state sync; ogg_page page; stream_set *processors = create_stream_set(); int gotpage = 0; ogg_int64_t written = 0; if(!file) { error(_("Error opening input file \"%s\": %s\n"), filename, strerror(errno)); return; } printf(_("Processing file \"%s\"...\n\n"), filename); ogg_sync_init(&sync); while(get_next_page(file, &sync, &page, &written)) { stream_processor *p = find_stream_processor(processors, &page); gotpage = 1; if(!p) { error(_("Could not find a processor for stream, bailing\n")); return; } if(p->isillegal && !p->shownillegal) { char *constraint; switch(p->constraint_violated) { case CONSTRAINT_PAGE_AFTER_EOS: constraint = _("Page found for stream after EOS flag"); break; case CONSTRAINT_MUXING_VIOLATED: constraint = _("Ogg muxing constraints violated, new " "stream before EOS of all previous streams"); break; default: constraint = _("Error unknown."); } warn(_("Warning: illegally placed page(s) for logical stream %d\n" "This indicates a corrupt ogg file: %s.\n"), p->num, constraint); p->shownillegal = 1; /* If it's a new stream, we want to continue processing this page * anyway to suppress additional spurious errors */ if(!p->isnew) continue; } if(p->isnew) { info(_("New logical stream (#%d, serial: %08x): type %s\n"), p->num, p->serial, p->type); if(!p->start) warn(_("Warning: stream start flag not set on stream %d\n"), p->num); } else if(p->start) warn(_("Warning: stream start flag found in mid-stream " "on stream %d\n"), p->num); if(p->seqno++ != ogg_page_pageno(&page)) { if(!p->lostseq) warn(_("Warning: sequence number gap in stream %d. Got page " "%ld when expecting page %ld. Indicates missing data.\n" ), p->num, ogg_page_pageno(&page), p->seqno - 1); p->seqno = ogg_page_pageno(&page); p->lostseq = 1; } else p->lostseq = 0; if(!p->isillegal) { p->process_page(p, &page); if(p->end) { if(p->process_end) p->process_end(p); info(_("Logical stream %d ended\n"), p->num); p->isillegal = 1; p->constraint_violated = CONSTRAINT_PAGE_AFTER_EOS; } } } if(!gotpage) error(_("Error: No ogg data found in file \"%s\".\n" "Input probably not ogg.\n"), filename); free_stream_set(processors); ogg_sync_clear(&sync); fclose(file); }
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; };
void rip_ogg_process_chunk(RIP_MANAGER_INFO * rmi, LIST * page_list, const char *buf, u_long size, TRACK_INFO * ti) { OGG_PAGE_LIST *ol; int header; int ret; char *buffer; // static ogg_int64_t written = 0; // static unsigned int written = 0; // static int ogg_page2 = 0; INIT_LIST_HEAD(page_list); debug_printf("-- rip_ogg_process_chunk (%d)\n", size); buffer = ogg_sync_buffer(&rmi->ogg_sync, size); memcpy(buffer, buf, size); ogg_sync_wrote(&rmi->ogg_sync, size); do { switch (ret = ogg_sync_pageout(&rmi->ogg_sync, &rmi->ogg_pg)) { case -1: /* -1 if we were not properly synced and had to skip some bytes */ debug_printf("Hole in ogg, skipping bytes\n"); break; case 0: /* 0 if we need more data to verify a page */ debug_printf("Ogg needs more data\n"); break; case 1: /* 1 if we have a page */ debug_printf("Found an ogg page!\n"); /* Do stuff needed for decoding vorbis */ if (ogg_page_bos(&rmi->ogg_pg)) { int rc; ogg_packet packet; ogg_stream_init(&rmi->stream.os, ogg_page_serialno(&rmi->ogg_pg)); ogg_stream_pagein(&rmi->stream.os, &rmi->ogg_pg); rc = ogg_stream_packetout(&rmi->stream.os, &packet); if (rc <= 0) { printf("Warning: Invalid header page, no packet found\n"); // null_start (&rmi->stream); exit(1); } else if (packet.bytes >= 7 && memcmp(packet.packet, "\001vorbis", 7) == 0) { vorbis_start(&rmi->stream); } } header = vorbis_process(rmi, &rmi->stream, &rmi->ogg_pg, ti); if (ogg_page_eos(&rmi->ogg_pg)) { vorbis_end(&rmi->stream); } /* Create ogg page boundary struct */ ol = (OGG_PAGE_LIST *) malloc(sizeof(OGG_PAGE_LIST)); if (!ol) { printf("Malloc error\n"); exit(1); } ol->m_page_len = rmi->ogg_pg.header_len + rmi->ogg_pg.body_len; ol->m_page_flags = 0; /* ***************************************************** Create header buffer for relay stream. A pointer to the header buffer will attached to all pages after page 2. If a relay connects in the middle of a song, we send the header to the relay. Finally, the memory for the header is freed when the last page of the song is ejected from the cbuf. ** ***************************************************** */ if (ogg_page_bos(&rmi->ogg_pg)) { /* First page in song */ ol->m_page_flags |= OGG_PAGE_BOS; ol->m_header_buf_ptr = 0; ol->m_header_buf_len = 0; rmi->ogg_curr_header = (char *)malloc(ol->m_page_len); rmi->ogg_curr_header_len = ol->m_page_len; memcpy(rmi->ogg_curr_header, rmi->ogg_pg.header, rmi->ogg_pg.header_len); memcpy(rmi->ogg_curr_header + rmi->ogg_pg.header_len, rmi->ogg_pg.body, rmi->ogg_pg.body_len); } else if (header) { /* Second or third page in song */ ol->m_page_flags |= OGG_PAGE_2; ol->m_header_buf_ptr = 0; ol->m_header_buf_len = 0; rmi->ogg_curr_header = (char *) realloc(rmi->ogg_curr_header, rmi->ogg_curr_header_len + ol->m_page_len); memcpy(rmi->ogg_curr_header + rmi->ogg_curr_header_len, rmi->ogg_pg.header, rmi->ogg_pg.header_len); memcpy(rmi->ogg_curr_header + rmi->ogg_curr_header_len + rmi->ogg_pg.header_len, rmi->ogg_pg.body, rmi->ogg_pg.body_len); rmi->ogg_curr_header_len += ol->m_page_len; } else if (!ogg_page_eos(&rmi->ogg_pg)) { /* Middle pages in song */ ol->m_header_buf_ptr = rmi->ogg_curr_header; ol->m_header_buf_len = rmi->ogg_curr_header_len; } else { /* Last page in song */ ol->m_page_flags |= OGG_PAGE_EOS; ol->m_header_buf_ptr = rmi->ogg_curr_header; ol->m_header_buf_len = rmi->ogg_curr_header_len; rmi->ogg_curr_header = 0; rmi->ogg_curr_header_len = 0; } debug_printf("OGG_PAGE\n" " header_len = %d\n" " body_len = %d\n" " serial no = %d\n" " page no = %d\n" " bos? = %d\n" " eos? = %d\n", rmi->ogg_pg.header_len, rmi->ogg_pg.body_len, ogg_page_serialno(&rmi->ogg_pg), ogg_page_pageno(&rmi->ogg_pg), ogg_page_bos(&rmi->ogg_pg), ogg_page_eos(&rmi->ogg_pg)); list_add_tail(&(ol->m_list), page_list); break; } } while (ret != 0); debug_printf("OGG_SYNC state:\n" " storage = %d\n" " fill = %d\n" " returned = %d\n" " unsynced = %d\n" " headerbytes = %d\n" " bodybytes = %d\n", rmi->ogg_sync.storage, rmi->ogg_sync.fill, rmi->ogg_sync.returned, rmi->ogg_sync.unsynced, rmi->ogg_sync.headerbytes, rmi->ogg_sync.bodybytes); // return 1; }