/* Opens the Ogg stream, searching for and initializing Theora and Vorbis media */ int alogg_open(APEG_LAYER *layer) { ALOGG_INFO *info; int vok = 0, aok = 0; int flag, cs, size; info = calloc(1, sizeof(ALOGG_INFO)); if(!info) return APEG_ERROR; LOCK_DATA(info, sizeof(ALOGG_INFO)); ogg_sync_init(&info->osync); theora_comment_init(&info->tcomment); theora_info_init(&info->tinfo); vorbis_info_init(&info->vinfo); vorbis_comment_init(&info->vcomment); flag = FALSE; while(!flag) { int ret = buffer_data(layer, info); if(ret == 0) break; while(ogg_sync_pageout(&info->osync, &info->opage) > 0) { ogg_stream_state test; /* is this a mandated initial header? If not, stop parsing */ if(!ogg_page_bos(&info->opage)) { if(vok > 0) ogg_stream_pagein(&info->ostream[0], &info->opage); if(aok > 0) ogg_stream_pagein(&info->ostream[1], &info->opage); flag = TRUE; break; } ogg_stream_init(&test, ogg_page_serialno(&info->opage)); ogg_stream_pagein(&test, &info->opage); ogg_stream_packetout(&test, &info->opkt); /* identify the codec: try theora */ if(!vok && theora_decode_header(&info->tinfo, &info->tcomment, &info->opkt) >= 0) { /* it is theora */ if(!_apeg_ignore_video) { memcpy(&info->ostream[0], &test, sizeof(test)); vok = 1; } else ogg_stream_clear(&test); } else if(!aok && vorbis_synthesis_headerin(&info->vinfo, &info->vcomment, &info->opkt) >= 0) { /* it is vorbis */ if(!_apeg_ignore_audio) { memcpy(&info->ostream[1], &test, sizeof(test)); aok = 1; } else ogg_stream_clear(&test); } /* whatever it is, we don't care about it */ else ogg_stream_clear(&test); } /* fall through to non-bos page parsing */ } /* look for further theora headers */ while((vok > 0 && vok < 3) || (aok > 0 && aok < 3)) { int ret; // Get the last two of three Theora headers while(vok > 0 && vok < 3 && (ret = ogg_stream_packetout(&info->ostream[0], &info->opkt))) { if(ret < 0) goto error; if(theora_decode_header(&info->tinfo, &info->tcomment, &info->opkt)) goto error; ++vok; } // Get the last two of three Vorbis headers while(aok > 0 && aok < 3 && (ret = ogg_stream_packetout(&info->ostream[1], &info->opkt))) { if(ret < 0) goto error; if(vorbis_synthesis_headerin(&info->vinfo, &info->vcomment, &info->opkt)) goto error; ++aok; } if(ogg_sync_pageout(&info->osync, &info->opage) <= 0) { /* need more data */ if(buffer_data(layer, info) == 0) break; } else { if(vok > 0) ogg_stream_pagein(&info->ostream[0], &info->opage); if(aok > 0) ogg_stream_pagein(&info->ostream[1], &info->opage); } } // Neither Vorbis or Theora fully initialized. Error. if(vok != 3 && aok != 3) goto error; layer->ogg_info = info; if(aok == 3) { vorbis_synthesis_init(&info->vdsp, &info->vinfo); vorbis_block_init(&info->vdsp, &info->vblock); if(info->vinfo.channels == 1) layer->stream.audio.down_channel = FALSE; layer->stream.audio.channels = info->vinfo.channels; layer->stream.audio.freq = info->vinfo.rate >> layer->stream.audio.down_sample; if(_apeg_audio_reset_parameters(layer) != APEG_OK) { vorbis_block_clear(&info->vblock); vorbis_dsp_clear(&info->vdsp); goto error; } // layer->audio.inited = TRUE; layer->stream.flags |= APEG_VORBIS_AUDIO; }
int main(int argc, char *argv[]) { daala_packet dp; ogg_packet op; int long_option_index; int c; ogg_sync_state oy; ogg_page og; ogg_stream_state to; daala_info di; daala_comment dc; daala_setup_info *ds; daala_dec_ctx *dd; daala_image img; const char *optstring = "o:r"; struct option options [] = { { "output", required_argument, NULL, 'o' }, { "raw", no_argument, NULL, 'r' }, /*Disable YUV4MPEG2 headers:*/ { "version", no_argument, NULL, 0}, { NULL, 0, NULL, 0 } }; int frames = 0; int pix_fmt = 1; int daala_p = 0; int daala_processing_headers = 0; int stateflag = 0; /* single frame video buffering */ int videobuf_ready = 0; int raw = 0; FILE *outfile = NULL; ogg_int32_t pic_width = 0; ogg_int32_t pic_height = 0; ogg_int32_t fps_num = 0; ogg_int32_t fps_denom = 0; FILE *infile = stdin; outfile = stdout; dd = NULL; ds = NULL; daala_log_init(); #ifdef _WIN32 /* We need to set stdin/stdout to binary mode on windows. */ /* Beware the evil ifdef. We avoid these where we can, but this one we cannot. Don't add any more, you'll probably go to hell if you do. */ _setmode(_fileno(stdin), _O_BINARY); _setmode(_fileno(stdout), _O_BINARY); #endif /* Process option arguments. */ while ((c = getopt_long(argc, argv, optstring, options, &long_option_index)) != EOF) { switch (c) { case 'o': { if (strcmp(optarg, "-") != 0) { outfile = fopen(optarg, "wb"); if (outfile == NULL) { fprintf(stderr, "Unable to open output file '%s'\n", optarg); exit(1); } } else { outfile = stdout; } break; } case 'r': { raw = 1; break; } case 0: { if (strcmp(options[long_option_index].name, "version") == 0) { version(); } break; } default: usage(); break; } } if (optind < argc) { infile = fopen(argv[optind], "rb"); if (infile == NULL) { fprintf(stderr, "Unable to open '%s' for extraction.\n", argv[optind]); exit(1); } if (++optind < argc) { usage(); exit(1); } } /*Ok, Ogg parsing. The idea here is we have a bitstream that is made up of Ogg pages. The libogg sync layer will find them for us. There may be pages from several logical streams interleaved; we find the first daala stream and ignore any others. Then we pass the pages for our stream to the libogg stream layer which assembles our original set of packets out of them. start up Ogg stream synchronization layer */ ogg_sync_init(&oy); /* init supporting Theora structures needed in header parsing */ daala_comment_init(&dc); daala_info_init(&di); /*Ogg file open; parse the headers. Theora (like Vorbis) depends on some initial header packets for decoder setup and initialization. We retrieve these first before entering the main decode loop.*/ /* Only interested in Daala streams */ while (!stateflag) { int ret = buffer_data(infile, &oy); if (ret == 0) break; while (ogg_sync_pageout(&oy, &og) > 0) { int got_packet; ogg_stream_state test; /* is this a mandated initial header? If not, stop parsing */ if (!ogg_page_bos(&og)) { /* don't leak the page; get it into the appropriate stream */ queue_page(&og, &to, daala_p); stateflag = 1; break; } ogg_stream_init(&test, ogg_page_serialno(&og)); ogg_stream_pagein(&test, &og); got_packet = ogg_stream_packetpeek(&test, &op); ogg_to_daala_packet(&dp, &op); /* identify the codec: try daala */ if ((got_packet == 1) && !daala_p && (daala_processing_headers = daala_decode_header_in(&di, &dc, &ds, &dp)) >= 0) { /* it is daala -- save this stream state */ memcpy(&to, &test, sizeof(test)); daala_p = 1; /*Advance past the successfully processed header.*/ if (daala_processing_headers) ogg_stream_packetout(&to, NULL); } else { /* whatever it is, we don't care about it */ ogg_stream_clear(&test); } } /* fall through to non-bos page parsing */ } /* we're expecting more header packets. */ while (daala_p && daala_processing_headers) { int ret; /* look for further daala headers */ while (daala_processing_headers && (ret = ogg_stream_packetpeek(&to, &op))) { if (ret < 0) continue; ogg_to_daala_packet(&dp, &op); daala_processing_headers = daala_decode_header_in(&di, &dc, &ds, &dp); if (daala_processing_headers < 0) { fprintf(stderr, "Error parsing Daala stream headers; " "corrupt stream?\n"); exit(1); } else if (daala_processing_headers >= 0) { /*Advance past the successfully processed header.*/ ogg_stream_packetout(&to, NULL); } daala_p++; } /*Stop now so we don't fail if there aren't enough pages in a short stream.*/ if (!(daala_p && daala_processing_headers)) break; /* The header pages/packets will arrive before anything else we care about, or the stream is not obeying spec */ if (ogg_sync_pageout(&oy, &og) > 0) { queue_page(&og, &to, daala_p); /* demux into the appropriate stream */ } else { if (buffer_data(infile, &oy) == 0) { /* someone needs more data */ fprintf(stderr, "End of file while searching for codec headers.\n"); exit(1); } } } /* and now we have it all. initialize decoders */ if (daala_p) { dump_comments(&dc); dd = daala_decode_create(&di, ds); fprintf(stderr, "Ogg logical stream %lx is Daala %dx%d %.02f fps video\n", to.serialno, di.pic_width, di.pic_height, di.timebase_numerator/(double)di.timebase_denominator*di.frame_duration); } else { /* tear down the partial daala setup */ daala_info_clear(&di); daala_comment_clear(&dc); } /*Either way, we're done with the codec setup data.*/ daala_setup_free(ds); if (!raw && outfile) { static const char *CHROMA_TYPES[5] = { "420jpeg", NULL, "422jpeg", "444", "mono" }; pic_width = di.pic_width; pic_height = di.pic_height; fps_num = di.timebase_numerator; fps_denom = di.timebase_denominator*di.frame_duration; if (di.nplanes > 1) { /*calculate pixel_fmt based on the xdec & ydec values from one of the chroma planes.*/ if (di.plane_info[1].xdec == 1 && di.plane_info[1].ydec == 1) { pix_fmt = 0; } else if (di.plane_info[1].xdec == 1 && di.plane_info[1].ydec == 0) { pix_fmt = 2; } else if (di.plane_info[1].xdec == 0 && di.plane_info[1].ydec == 0) { pix_fmt = 3; } } else { pix_fmt = 4; } if (pix_fmt >= 5 || pix_fmt == 1) { fprintf(stderr, "Unknown pixel format: %i\n", pix_fmt); exit(1); } /*Store header information*/ fprintf(outfile, "YUV4MPEG2 W%d H%d F%d:%d Ip A%d:%d C%s\n", pic_width, pic_height, fps_num, fps_denom, di.pixel_aspect_numerator, di.pixel_aspect_denominator, CHROMA_TYPES[pix_fmt]); } /* install signal handler */ signal(SIGINT, sigint_handler); /*Finally the main decode loop. It's one Daala packet per frame, so this is pretty straightforward if we're not trying to maintain sync with other multiplexed streams. The videobuf_ready flag is used to maintain the input buffer in the libogg stream state. If there's no output frame available at the end of the decode step, we must need more input data. We could simplify this by just using the return code on ogg_page_packetout(), but the flag system extends easily to the case where you care about more than one multiplexed stream (like with audio playback). In that case, just maintain a flag for each decoder you care about, and pull data when any one of them stalls.*/ stateflag = 0; /* playback has not begun */ /* queue any remaining pages from data we buffered but that did not contain headers */ while (ogg_sync_pageout(&oy, &og) > 0) { queue_page(&og, &to, daala_p); } while (!got_sigint) { while (daala_p && !videobuf_ready) { if (ogg_stream_packetout(&to, &op) > 0) { ogg_to_daala_packet(&dp, &op); if (daala_decode_packet_in(dd, &dp) >= 0) { videobuf_ready = 1; frames++; } } else break; } if (!videobuf_ready && feof(infile)) break; if (!videobuf_ready) { /* no data yet for somebody. Grab another page */ buffer_data(infile, &oy); while (ogg_sync_pageout(&oy, &og) > 0) { queue_page(&og, &to, daala_p); } } /* dumpvideo frame, and get new one */ else if (outfile && daala_decode_img_out(dd, &img)) { video_write(outfile, &img, raw); } videobuf_ready = 0; } /*Flush the output frame buffer of decoder.*/ while (!got_sigint && daala_decode_img_out(dd, &img)) { video_write(outfile, &img, raw); } /* end of decoder loop -- close everything */ if (daala_p) { ogg_stream_clear(&to); daala_decode_free(dd); daala_comment_clear(&dc); daala_info_clear(&di); } ogg_sync_clear(&oy); if (infile && infile != stdin) fclose(infile); if (outfile && outfile != stdout) fclose(outfile); fprintf(stderr, "\n\n%d frames\n", frames); fprintf(stderr, "\nDone.\n"); return 0; }
static int play_vorbis(lua_State *lstate) { char buf[BLOCKSIZE]; char *pt, *oggbuf, **comm, *mark; int n, sock, sr_err, port; const char *host, *mount; VORBIS_FEED *feed; lua_pushstring(lstate, "host"); lua_gettable(lstate, -2); lua_pushstring(lstate, "port"); lua_gettable(lstate, -3); lua_pushstring(lstate, "mount"); lua_gettable(lstate, -4); mount = lua_tostring(lstate, -1); port = lua_tointeger(lstate, -2); host = lua_tostring(lstate, -3); sock = stream_connect(host, port, mount, buf, &mark); lua_pop(lstate, 3); if (sock == 0) { lua_pop(lstate, 1); return 0; } lua_pushstring(lstate, "intern"); lua_gettable(lstate, -2); feed = (VORBIS_FEED *)lua_touserdata(lstate, -1); lua_pop(lstate, 1); feed->base.sock = sock; pthread_mutex_init(&(feed->base.thread_lock), NULL); pthread_cond_init(&(feed->base.data_ready), NULL); ogg_sync_init(&(feed->oy)); oggbuf = ogg_sync_buffer(&(feed->oy), BLOCKSIZE); n = BLOCKSIZE - (mark - buf); memcpy(oggbuf, mark, n); read_sock(feed->base.sock, oggbuf + n, BLOCKSIZE - n); ogg_sync_wrote(&(feed->oy), BLOCKSIZE); if ((n = ogg_sync_pageout(&(feed->oy), &(feed->og))) != 1) { logmsg("out of data: %d\n", n); free_vorbis((FEED *)feed); lua_pop(lstate, 1); return 0; } ogg_stream_init(&(feed->os), ogg_page_serialno(&(feed->og))); vorbis_info_init(&(feed->vi)); vorbis_comment_init(&(feed->vc)); if (ogg_stream_pagein(&(feed->os), &(feed->og)) < 1) { logmsg("error reading first ogg page\n"); //free_feed(feed); //return 0; } if (ogg_stream_packetout(&(feed->os), &(feed->op)) != 1) { logmsg("error reading first header packet\n"); free_vorbis((FEED *)feed); lua_pop(lstate, 1); return 0; } if (vorbis_synthesis_headerin(&(feed->vi), &(feed->vc), &(feed->op)) < 0) { logmsg("stream is not vorbis\n"); free_vorbis((FEED *)feed); lua_pop(lstate, 1); return 0; } vorbis_headers(feed); add_table(lstate, "info"); add_table(lstate, "comments"); comm = feed->vc.user_comments; while (*comm) { if ((pt = index(*comm, '=')) != NULL) { *pt++ = '\0'; set_string(lstate, *comm, pt); } ++comm; } lua_pop(lstate, 1); // comments feed->base.channels = feed->vi.channels; set_integer(lstate, "channels", feed->base.channels); set_integer(lstate, "srate", feed->vi.rate); lua_pop(lstate, 1); // info feed->base.cbuf = new_ringbuf(feed->vi.rate, feed->base.channels, BUFSECS, 0.333, 0.667); if (jack_sr != feed->vi.rate) { feed->base.converter = src_new(SRC_SINC_MEDIUM_QUALITY, feed->base.channels, &sr_err); feed->base.src_data_in = (float *)malloc(SRC_DATA_FRAMES * feed->base.channels * sizeof(float)); feed->base.src_data.data_in = feed->base.src_data_in; feed->base.src_data_remain = 0; feed->base.src_data.src_ratio = jack_sr / (double)feed->vi.rate; feed->base.src_data_out = (float *)malloc( (int)ceil(SRC_DATA_FRAMES * feed->base.channels * sizeof(float) * feed->base.src_data.src_ratio)); } feed->base.init = 1; lua_pop(lstate, 1); pthread_create(&(feed->base.thread_id), NULL, vorbis_thread, feed); return 0; }
/* handle incoming page. as the stream is being rebuilt, we need to * add all pages from the stream before processing packets */ static refbuf_t *process_vorbis_page (ogg_state_t *ogg_info, ogg_codec_t *codec, ogg_page *page) { ogg_packet header; vorbis_codec_t *source_vorbis = codec->specific; char *comment; if (ogg_stream_pagein (&codec->os, page) < 0) { ogg_info->error = 1; return NULL; } if (codec->headers == 3) { if (source_vorbis->initial_audio_page) { source_vorbis->initial_page_granulepos = ogg_page_granulepos (page); source_vorbis->initial_audio_page = 0; } return NULL; } while (codec->headers < 3) { /* now, lets extract the packets */ DEBUG1 ("processing incoming header packet (%d)", codec->headers); if (ogg_stream_packetout (&codec->os, &header) <= 0) { if (ogg_info->codecs->next) format_ogg_attach_header (codec, page); return NULL; } /* change comments here if need be */ if (vorbis_synthesis_headerin (&source_vorbis->vi, &source_vorbis->vc, &header) < 0) { ogg_info->error = 1; WARN0 ("Problem parsing ogg vorbis header"); return NULL; } header.granulepos = 0; source_vorbis->header [codec->headers] = copy_ogg_packet (&header); codec->headers++; } DEBUG0 ("we have the header packets now"); /* if vorbis is the only codec then allow rebuilding of the streams */ if (ogg_info->codecs->next == NULL && ogg_info->passthrough == 0) { /* set queued vorbis pages to contain about 1/2 second worth of samples */ source_vorbis->page_samples_trigger = (ogg_int64_t)(source_vorbis->vi.rate/2); if (ogg_info->admin_comments_only) source_vorbis->rebuild_comment = 1; source_vorbis->process_packet = process_vorbis_headers; source_vorbis->initial_audio_page = 1; } else { format_ogg_attach_header (codec, &source_vorbis->bos_page); format_ogg_attach_header (codec, page); codec->process_page = process_vorbis_passthru_page; } if (ogg_info->admin_comments_only == 0) { free (ogg_info->title); comment = vorbis_comment_query (&source_vorbis->vc, "TITLE", 0); if (comment) ogg_info->title = strdup (comment); else ogg_info->title = NULL; free (ogg_info->artist); comment = vorbis_comment_query (&source_vorbis->vc, "ARTIST", 0); if (comment) ogg_info->artist = strdup (comment); else ogg_info->artist = NULL; } ogg_info->log_metadata = 1; stats_event_args (ogg_info->mount, "audio_samplerate", "%ld", (long)source_vorbis->vi.rate); stats_event_args (ogg_info->mount, "audio_channels", "%ld", (long)source_vorbis->vi.channels); stats_event_args (ogg_info->mount, "audio_bitrate", "%ld", (long)source_vorbis->vi.bitrate_nominal); stats_event_args (ogg_info->mount, "ice-bitrate", "%ld", (long)source_vorbis->vi.bitrate_nominal/1000); return NULL; }
static int ReadHeader(OGG_context *ctx, SYS_FILEHANDLE file) { const size_t size = 4096; int theError; void *buffer; int i, serialNo; size_t bytes = 0; ogg_sync_init(&ctx->oy); /* Now we can read pages */ /* submit a 4k block to libvorbis' Ogg layer */ if (!ctx->eos) { buffer = ogg_sync_buffer(&ctx->oy, (int32_t)size); bytes = FIO_cur->fread(buffer, 1 , size, file); ogg_sync_wrote(&ctx->oy, (int32_t)size); } /* Get the first page. */ theError = ogg_sync_pageout(&ctx->oy, &ctx->og); SYS_ASSERT(theError == 1); if (theError!=1) { /* error case. Must not be Vorbis data */ SYS_ASSERT(bytes<size); return 0; } /* Get the serial number and set up the rest of decode. */ /* serialno first; use it to set up a logical stream */ serialNo = ogg_page_serialno(&ctx->og); theError = ogg_stream_init(&ctx->os, serialNo); SYS_ASSERT(theError==0); /* extract the initial header from the first page and verify that the Ogg bitstream is in fact Vorbis data */ /* I handle the initial header first instead of just having the code read all three Vorbis headers at once because reading the initial header is an easy way to identify a Vorbis bitstream and it's useful to see that functionality seperated out. */ theError = ogg_stream_pagein(&ctx->os, &ctx->og); SYS_ASSERT(theError>=0); if (theError < 0) { /* error; stream version mismatch perhaps */ return 0; } theError = ogg_stream_packetout(&ctx->os, &ctx->op); SYS_ASSERT(theError == 1); if (theError!=1) { /* no page? must not be vorbis */ return 0; } theError = vorbis_synthesis_headerin(&ctx->vi, &ctx->vc, &ctx->op); SYS_ASSERT(theError >=0); if (theError < 0) { return 0; } /* At this point, we're sure we're Vorbis. We've set up the logical (Ogg) bitstream decoder. Get the comment and codebook headers and set up the Vorbis decoder */ /* The next two packets in order are the comment and codebook headers. They're likely large and may span multiple pages. Thus we reead and submit data until we get our two pacakets, watching that no pages are missing. If a page is missing, error out; losing a header page is the only place where missing data is fatal. */ i=0; while(i<2) { while(i<2) { int result = ogg_sync_pageout(&ctx->oy, &ctx->og); if (result==0) break; /* Need more data */ /* Don't complain about missing or corrupt data yet. We'll catch it at the packet output phase */ if(result==1) { ogg_stream_pagein(&ctx->os, &ctx->og); /* we can ignore any errors here as they'll also become apparent at packetout */ while(i<2) { result = ogg_stream_packetout(&ctx->os, &ctx->op); if (result==0) break; if (result<0) { /* Uh oh; data at some point was corrupted or missing! We can't tolerate that in a header. Die. */ SYS_ASSERT(0); return 0; } vorbis_synthesis_headerin(&ctx->vi, &ctx->vc, &ctx->op); i++; } } } buffer = ogg_sync_buffer(&ctx->oy, (int32_t)size); bytes = FIO_cur->fread(buffer, 1 , size, file); SYS_ASSERT(!(bytes==0 && i<2)); ogg_sync_wrote(&ctx->oy,(int32_t) size); } /* OK, got and parsed all three headers. Initialize the Vorbis packet->PCM decoder. */ vorbis_synthesis_init(&ctx->vd, &ctx->vi); /* central decode state */ vorbis_block_init(&ctx->vd, &ctx->vb); /* local state for most of the decode so multiple block decodes can proceed in parallel. We could init multiple vorbis_block structures for vd here */ ctx->input_size = size; ctx->state = 0; return 1; }
bool SFB::Audio::OggSpeexDecoder::_Open(CFErrorRef *error) { // Initialize Ogg data struct ogg_sync_init(&mOggSyncState); // Get the ogg buffer for writing char *data = ogg_sync_buffer(&mOggSyncState, READ_SIZE_BYTES); // Read bitstream from input file ssize_t bytesRead = (ssize_t)GetInputSource().Read(data, READ_SIZE_BYTES); if(-1 == bytesRead) { if(error) { SFB::CFString description(CFCopyLocalizedString(CFSTR("The file “%@” could not be read."), "")); SFB::CFString failureReason(CFCopyLocalizedString(CFSTR("Read error"), "")); SFB::CFString recoverySuggestion(CFCopyLocalizedString(CFSTR("Unable to read from the input file."), "")); *error = CreateErrorForURL(Decoder::ErrorDomain, Decoder::InputOutputError, description, mInputSource->GetURL(), failureReason, recoverySuggestion); } ogg_sync_destroy(&mOggSyncState); return false; } // Tell the sync layer how many bytes were written to its internal buffer int result = ogg_sync_wrote(&mOggSyncState, bytesRead); if(-1 == result) { if(error) { SFB::CFString description(CFCopyLocalizedString(CFSTR("The file “%@” is not a valid Ogg file."), "")); SFB::CFString failureReason(CFCopyLocalizedString(CFSTR("Not an Ogg file"), "")); SFB::CFString recoverySuggestion(CFCopyLocalizedString(CFSTR("The file's extension may not match the file's type."), "")); *error = CreateErrorForURL(Decoder::ErrorDomain, Decoder::InputOutputError, description, mInputSource->GetURL(), failureReason, recoverySuggestion); } ogg_sync_destroy(&mOggSyncState); return false; } // Turn the data we wrote into an ogg page result = ogg_sync_pageout(&mOggSyncState, &mOggPage); if(1 != result) { if(error) { SFB::CFString description(CFCopyLocalizedString(CFSTR("The file “%@” is not a valid Ogg file."), "")); SFB::CFString failureReason(CFCopyLocalizedString(CFSTR("Not an Ogg file"), "")); SFB::CFString recoverySuggestion(CFCopyLocalizedString(CFSTR("The file's extension may not match the file's type."), "")); *error = CreateErrorForURL(Decoder::ErrorDomain, Decoder::InputOutputError, description, mInputSource->GetURL(), failureReason, recoverySuggestion); } ogg_sync_destroy(&mOggSyncState); return false; } // Initialize the stream and grab the serial number ogg_stream_init(&mOggStreamState, ogg_page_serialno(&mOggPage)); // Get the first Ogg page result = ogg_stream_pagein(&mOggStreamState, &mOggPage); if(0 != result) { if(error) { SFB::CFString description(CFCopyLocalizedString(CFSTR("The file “%@” is not a valid Ogg file."), "")); SFB::CFString failureReason(CFCopyLocalizedString(CFSTR("Not an Ogg file"), "")); SFB::CFString recoverySuggestion(CFCopyLocalizedString(CFSTR("The file's extension may not match the file's type."), "")); *error = CreateErrorForURL(Decoder::ErrorDomain, Decoder::InputOutputError, description, mInputSource->GetURL(), failureReason, recoverySuggestion); } ogg_sync_destroy(&mOggSyncState); return false; } // Get the first packet (should be the header) from the page ogg_packet op; result = ogg_stream_packetout(&mOggStreamState, &op); if(1 != result) { if(error) { SFB::CFString description(CFCopyLocalizedString(CFSTR("The file “%@” is not a valid Ogg file."), "")); SFB::CFString failureReason(CFCopyLocalizedString(CFSTR("Not an Ogg file"), "")); SFB::CFString recoverySuggestion(CFCopyLocalizedString(CFSTR("The file's extension may not match the file's type."), "")); *error = CreateErrorForURL(Decoder::ErrorDomain, Decoder::InputOutputError, description, mInputSource->GetURL(), failureReason, recoverySuggestion); } ogg_sync_destroy(&mOggSyncState); return false; } if(op.bytes >= 5 && !memcmp(op.packet, "Speex", 5)) mSpeexSerialNumber = mOggStreamState.serialno; ++mOggPacketCount; // Convert the packet to the Speex header SpeexHeader *header = speex_packet_to_header((char *)op.packet, (int)op.bytes); if(nullptr == header) { if(error) { SFB::CFString description(CFCopyLocalizedString(CFSTR("The file “%@” is not a valid Ogg Speex file."), "")); SFB::CFString failureReason(CFCopyLocalizedString(CFSTR("Not an Ogg Speex file"), "")); SFB::CFString recoverySuggestion(CFCopyLocalizedString(CFSTR("The file's extension may not match the file's type."), "")); *error = CreateErrorForURL(Decoder::ErrorDomain, Decoder::FileFormatNotRecognizedError, description, mInputSource->GetURL(), failureReason, recoverySuggestion); } ogg_sync_destroy(&mOggSyncState); return false; } else if(SPEEX_NB_MODES <= header->mode) { if(error) { SFB::CFString description(CFCopyLocalizedString(CFSTR("The Speex mode in the file “%@” is not supported."), "")); SFB::CFString failureReason(CFCopyLocalizedString(CFSTR("Unsupported Ogg Speex file mode"), "")); SFB::CFString recoverySuggestion(CFCopyLocalizedString(CFSTR("This file may have been encoded with a newer version of Speex."), "")); *error = CreateErrorForURL(Decoder::ErrorDomain, Decoder::FileFormatNotSupportedError, description, mInputSource->GetURL(), failureReason, recoverySuggestion); } speex_header_free(header), header = nullptr; ogg_sync_destroy(&mOggSyncState); return false; } const SpeexMode *mode = speex_lib_get_mode(header->mode); if(mode->bitstream_version != header->mode_bitstream_version) { if(error) { SFB::CFString description(CFCopyLocalizedString(CFSTR("The Speex version in the file “%@” is not supported."), "")); SFB::CFString failureReason(CFCopyLocalizedString(CFSTR("Unsupported Ogg Speex file version"), "")); SFB::CFString recoverySuggestion(CFCopyLocalizedString(CFSTR("This file was encoded with a different version of Speex."), "")); *error = CreateErrorForURL(Decoder::ErrorDomain, Decoder::FileFormatNotSupportedError, description, mInputSource->GetURL(), failureReason, recoverySuggestion); } speex_header_free(header), header = nullptr; ogg_sync_destroy(&mOggSyncState); return false; } // Initialize the decoder mSpeexDecoder = speex_decoder_init(mode); if(nullptr== mSpeexDecoder) { if(error) { SFB::CFString description(CFCopyLocalizedString(CFSTR("Unable to initialize the Speex decoder."), "")); SFB::CFString failureReason(CFCopyLocalizedString(CFSTR("Error initializing Speex decoder"), "")); SFB::CFString recoverySuggestion(CFCopyLocalizedString(CFSTR("An unknown error occurred."), "")); *error = CreateErrorForURL(Decoder::ErrorDomain, Decoder::InputOutputError, description, mInputSource->GetURL(), failureReason, recoverySuggestion); } speex_header_free(header), header = nullptr; ogg_sync_destroy(&mOggSyncState); return false; } speex_decoder_ctl(mSpeexDecoder, SPEEX_SET_SAMPLING_RATE, &header->rate); mSpeexFramesPerOggPacket = (0 == header->frames_per_packet ? 1 : header->frames_per_packet); mExtraSpeexHeaderCount = (UInt32)header->extra_headers; // Initialize the speex bit-packing data structure speex_bits_init(&mSpeexBits); // Initialize the stereo mode mSpeexStereoState = speex_stereo_state_init(); if(2 == header->nb_channels) { SpeexCallback callback; callback.callback_id = SPEEX_INBAND_STEREO; callback.func = speex_std_stereo_request_handler; callback.data = mSpeexStereoState; speex_decoder_ctl(mSpeexDecoder, SPEEX_SET_HANDLER, &callback); } // Canonical Core Audio format mFormat.mFormatID = kAudioFormatLinearPCM; mFormat.mFormatFlags = kAudioFormatFlagsNativeFloatPacked | kAudioFormatFlagIsNonInterleaved; mFormat.mBitsPerChannel = 8 * sizeof(float); mFormat.mSampleRate = header->rate; mFormat.mChannelsPerFrame = (UInt32)header->nb_channels; mFormat.mBytesPerPacket = (mFormat.mBitsPerChannel / 8); mFormat.mFramesPerPacket = 1; mFormat.mBytesPerFrame = mFormat.mBytesPerPacket * mFormat.mFramesPerPacket; mFormat.mReserved = 0; // Set up the source format mSourceFormat.mFormatID = 'SPEE'; mSourceFormat.mSampleRate = header->rate; mSourceFormat.mChannelsPerFrame = (UInt32)header->nb_channels; switch(header->nb_channels) { case 1: mChannelLayout = ChannelLayout::ChannelLayoutWithTag(kAudioChannelLayoutTag_Mono); break; case 2: mChannelLayout = ChannelLayout::ChannelLayoutWithTag(kAudioChannelLayoutTag_Stereo); break; } speex_header_free(header), header = nullptr; // Allocate the buffer list spx_int32_t speexFrameSize = 0; speex_decoder_ctl(mSpeexDecoder, SPEEX_GET_FRAME_SIZE, &speexFrameSize); if(!mBufferList.Allocate(mFormat, (UInt32)speexFrameSize)) { if(error) *error = CFErrorCreate(kCFAllocatorDefault, kCFErrorDomainPOSIX, ENOMEM, nullptr); speex_header_free(header), header = nullptr; speex_stereo_state_destroy(mSpeexStereoState), mSpeexStereoState = nullptr; speex_decoder_destroy(mSpeexDecoder), mSpeexDecoder = nullptr; speex_bits_destroy(&mSpeexBits); ogg_sync_destroy(&mOggSyncState); return false; } for(UInt32 i = 0; i < mBufferList->mNumberBuffers; ++i) mBufferList->mBuffers[i].mDataByteSize = 0; return true; }
static gboolean xmms_speex_init (xmms_xform_t *xform) { gint pe; xmms_config_property_t *val; xmms_speex_data_t *data; xmms_error_t error; g_return_val_if_fail (xform, FALSE); data = g_new0 (xmms_speex_data_t, 1); g_return_val_if_fail (data, FALSE); xmms_xform_private_data_set (xform, data); ogg_sync_init (&data->sync_state); speex_bits_init (&data->speex_bits); /* Find the speex header */ while (42) { gint ret; data->ogg_data = ogg_sync_buffer (&data->sync_state, 1024); ret = xmms_xform_read (xform, data->ogg_data, 1024, &error); ogg_sync_wrote (&data->sync_state, ret); if (ret <= 0) { return FALSE; } if (ogg_sync_pageout (&data->sync_state, &data->ogg_page) == 1) { break; } } ogg_stream_init (&data->stream_state, ogg_page_serialno (&data->ogg_page)); if (ogg_stream_pagein (&data->stream_state, &data->ogg_page) < 0) { return FALSE; } if (ogg_stream_packetout (&data->stream_state, &data->ogg_packet) != 1) { return FALSE; } data->speexheader = speex_packet_to_header ((char *)data->ogg_packet.packet, data->ogg_packet.bytes); data->speex_state = speex_decoder_init (speex_mode_list[data->speexheader->mode]); val = xmms_xform_config_lookup (xform, "perceptual_enhancer"); pe = xmms_config_property_get_int (val); speex_decoder_ctl (data->speex_state, SPEEX_SET_ENH, &pe); ogg_sync_pageout (&data->sync_state, &data->ogg_page); ogg_stream_pagein (&data->stream_state, &data->ogg_page); ogg_stream_packetout (&data->stream_state, &data->ogg_packet); data->samples_buf = g_new (gint16, data->speexheader->frames_per_packet * data->speexheader->frame_size * data->speexheader->nb_channels); data->samples_start = data->samples_buf; data->samples_count = 0; xmms_speex_read_metadata (xform, data); xmms_xform_outdata_type_add (xform, XMMS_STREAM_TYPE_MIMETYPE, "audio/pcm", XMMS_STREAM_TYPE_FMT_FORMAT, XMMS_SAMPLE_FORMAT_S16, XMMS_STREAM_TYPE_FMT_CHANNELS, data->speexheader->nb_channels, XMMS_STREAM_TYPE_FMT_SAMPLERATE, data->speexheader->rate, XMMS_STREAM_TYPE_END); return TRUE; }
/*! * \brief Create a new OGG/Vorbis filestream and set it up for reading. * \param fd Descriptor that points to on disk storage of the OGG/Vorbis data. * \return The new filestream. */ static struct cw_filestream *ogg_vorbis_open(FILE *fp) { int i; int bytes; int result; char **ptr; char *buffer; struct cw_filestream *tmp; if ((tmp = malloc(sizeof(struct cw_filestream)))) { memset(tmp, 0, sizeof(struct cw_filestream)); tmp->writing = 0; tmp->fp = fp; ogg_sync_init(&tmp->oy); buffer = ogg_sync_buffer(&tmp->oy, BLOCK_SIZE); bytes = fread(buffer, 1, BLOCK_SIZE, tmp->fp); ogg_sync_wrote(&tmp->oy, bytes); result = ogg_sync_pageout(&tmp->oy, &tmp->og); if (result != 1) { if (bytes < BLOCK_SIZE) cw_log(LOG_ERROR, "Run out of data... %d %s\n", errno, strerror(errno)); else cw_log(LOG_ERROR, "Input does not appear to be an Ogg bitstream.\n"); fclose(fp); ogg_sync_clear(&tmp->oy); free(tmp); return NULL; } ogg_stream_init(&tmp->os, ogg_page_serialno(&tmp->og)); vorbis_info_init(&tmp->vi); vorbis_comment_init(&tmp->vc); if (ogg_stream_pagein(&tmp->os, &tmp->og) < 0) { cw_log(LOG_ERROR, "Error reading first page of Ogg bitstream data.\n"); fclose(fp); ogg_stream_clear(&tmp->os); vorbis_comment_clear(&tmp->vc); vorbis_info_clear(&tmp->vi); ogg_sync_clear(&tmp->oy); free(tmp); return NULL; } if (ogg_stream_packetout(&tmp->os, &tmp->op) != 1) { cw_log(LOG_ERROR, "Error reading initial header packet.\n"); fclose(fp); ogg_stream_clear(&tmp->os); vorbis_comment_clear(&tmp->vc); vorbis_info_clear(&tmp->vi); ogg_sync_clear(&tmp->oy); free(tmp); return NULL; } if (vorbis_synthesis_headerin(&tmp->vi, &tmp->vc, &tmp->op) < 0) { cw_log(LOG_ERROR, "This Ogg bitstream does not contain Vorbis audio data.\n"); fclose(fp); ogg_stream_clear(&tmp->os); vorbis_comment_clear(&tmp->vc); vorbis_info_clear(&tmp->vi); ogg_sync_clear(&tmp->oy); free(tmp); return NULL; } i = 0; while (i < 2) { while (i < 2) { result = ogg_sync_pageout(&tmp->oy, &tmp->og); if (result == 0) break; if (result == 1) { ogg_stream_pagein(&tmp->os, &tmp->og); while (i < 2) { result = ogg_stream_packetout(&tmp->os,&tmp->op); if (result == 0) break; if (result < 0) { cw_log(LOG_ERROR, "Corrupt secondary header. Exiting.\n"); fclose(fp); ogg_stream_clear(&tmp->os); vorbis_comment_clear(&tmp->vc); vorbis_info_clear(&tmp->vi); ogg_sync_clear(&tmp->oy); free(tmp); return NULL; } vorbis_synthesis_headerin(&tmp->vi, &tmp->vc, &tmp->op); i++; } } } buffer = ogg_sync_buffer(&tmp->oy, BLOCK_SIZE); bytes = fread(buffer, 1, BLOCK_SIZE, tmp->fp); if (bytes == 0 && i < 2) { cw_log(LOG_ERROR, "End of file before finding all Vorbis headers!\n"); fclose(fp); ogg_stream_clear(&tmp->os); vorbis_comment_clear(&tmp->vc); vorbis_info_clear(&tmp->vi); ogg_sync_clear(&tmp->oy); free(tmp); return NULL; } ogg_sync_wrote(&tmp->oy, bytes); } ptr = tmp->vc.user_comments; while (*ptr) { cw_log(LOG_DEBUG, "OGG/Vorbis comment: %s\n", *ptr); ++ptr; } cw_log(LOG_DEBUG, "OGG/Vorbis bitstream is %d channel, %ldHz\n", tmp->vi.channels, tmp->vi.rate); cw_log(LOG_DEBUG, "OGG/Vorbis file encoded by: %s\n", tmp->vc.vendor); if (tmp->vi.channels != 1) { cw_log(LOG_ERROR, "Only monophonic OGG/Vorbis files are currently supported!\n"); ogg_stream_clear(&tmp->os); vorbis_comment_clear(&tmp->vc); vorbis_info_clear(&tmp->vi); ogg_sync_clear(&tmp->oy); free(tmp); return NULL; } if (tmp->vi.rate != 8000) { cw_log(LOG_ERROR, "Only 8000Hz OGG/Vorbis files are currently supported!\n"); fclose(fp); ogg_stream_clear(&tmp->os); vorbis_block_clear(&tmp->vb); vorbis_dsp_clear(&tmp->vd); vorbis_comment_clear(&tmp->vc); vorbis_info_clear(&tmp->vi); ogg_sync_clear(&tmp->oy); free(tmp); return NULL; } vorbis_synthesis_init(&tmp->vd, &tmp->vi); vorbis_block_init(&tmp->vd, &tmp->vb); if (cw_mutex_lock(&ogg_vorbis_lock)) { cw_log(LOG_WARNING, "Unable to lock ogg_vorbis list\n"); fclose(fp); ogg_stream_clear(&tmp->os); vorbis_block_clear(&tmp->vb); vorbis_dsp_clear(&tmp->vd); vorbis_comment_clear(&tmp->vc); vorbis_info_clear(&tmp->vi); ogg_sync_clear(&tmp->oy); free(tmp); return NULL; } glistcnt++; cw_mutex_unlock(&ogg_vorbis_lock); cw_update_use_count(); } return tmp; }
static int64_t find_first_page( demux_t *p_demux, int64_t i_pos1, int64_t i_pos2, logical_stream_t *p_stream, int64_t *pi_kframe, int64_t *pi_frame ) { int64_t i_result; int64_t i_granulepos; int64_t i_bytes_to_read = i_pos2 - i_pos1 + 1; int64_t i_bytes_read; int64_t i_pages_checked = 0; int64_t i_packets_checked; demux_sys_t *p_sys = p_demux->p_sys; ogg_packet op; seek_byte( p_demux, i_pos1 ); if ( i_pos1 == p_stream->i_data_start ) { /* set a dummy granulepos at data_start */ *pi_kframe = p_stream->i_keyframe_offset; *pi_frame = p_stream->i_keyframe_offset; p_sys->b_page_waiting = true; return p_sys->i_input_position; } if ( i_bytes_to_read > OGGSEEK_BYTES_TO_READ ) i_bytes_to_read = OGGSEEK_BYTES_TO_READ; while ( 1 ) { if ( p_sys->i_input_position >= i_pos2 ) { /* we reached the end and found no pages */ *pi_frame=-1; return -1; } /* read next chunk */ if ( ! ( i_bytes_read = get_data( p_demux, i_bytes_to_read ) ) ) { /* EOF */ *pi_frame = -1; return -1; } i_bytes_to_read = OGGSEEK_BYTES_TO_READ; i_result = ogg_sync_pageseek( &p_sys->oy, &p_sys->current_page ); if ( i_result < 0 ) { /* found a page, sync to page start */ p_sys->i_input_position -= i_result; i_pos1 = p_sys->i_input_position; continue; } if ( i_result > 0 || ( i_result == 0 && p_sys->oy.fill > 3 && ! strncmp( (char *)p_sys->oy.data, "OggS" , 4 ) ) ) { i_pos1 = p_sys->i_input_position; break; } p_sys->i_input_position += i_bytes_read; }; seek_byte( p_demux, p_sys->i_input_position ); ogg_stream_reset( &p_stream->os ); while( 1 ) { if ( p_sys->i_input_position >= i_pos2 ) { /* reached the end of the search region and nothing was found */ *pi_frame = -1; return p_sys->i_input_position; } p_sys->b_page_waiting = false; if ( ! ( i_result = oggseek_read_page( p_demux ) ) ) { /* EOF */ *pi_frame = -1; return p_sys->i_input_position; } // found a page if ( p_stream->os.serialno != ogg_page_serialno( &p_sys->current_page ) ) { /* page is not for this stream */ p_sys->i_input_position += i_result; if ( ! i_pages_checked ) i_pos1 = p_sys->i_input_position; continue; } ogg_stream_pagein( &p_stream->os, &p_sys->current_page ); i_pages_checked++; i_packets_checked = 0; if ( ogg_stream_packetout( &p_stream->os, &op ) > 0 ) { i_packets_checked++; } if ( i_packets_checked ) { i_granulepos = ogg_page_granulepos( &p_sys->current_page ); oggseek_theora_index_entry_add( p_stream, i_granulepos, i_pos1 ); *pi_kframe = i_granulepos >> p_stream->i_granule_shift; *pi_frame = *pi_kframe + i_granulepos - ( *pi_kframe << p_stream->i_granule_shift ); p_sys->b_page_waiting = true; return i_pos1; } /* -> start of next page */ p_sys->i_input_position += i_result; } }
int AudioStreamPlaybackSpeex::mix(int16_t* p_buffer,int p_frames) { //printf("update, loops %i, read ofs %i\n", (int)loops, read_ofs); //printf("playing %i, paused %i\n", (int)playing, (int)paused); if (!active || !playing || paused || !data.size()) return 0; /* if (read_ofs >= data.size()) { if (loops) { reload(); ++loop_count; } else { return; }; }; */ int todo = p_frames; if (todo < page_size) { return 0; }; int eos = 0; bool reloaded=false; while (todo > page_size) { int ret=0; while ((todo>page_size && packets_available && !eos) || (ret = ogg_sync_pageout(&oy, &og))==1) { if (!packets_available) { /*Add page to the bitstream*/ ogg_stream_pagein(&os, &og); page_granule = ogg_page_granulepos(&og); page_nb_packets = ogg_page_packets(&og); packet_no=0; if (page_granule>0 && frame_size) { skip_samples = page_nb_packets*frame_size*nframes - (page_granule-last_granule); if (ogg_page_eos(&og)) skip_samples = -skip_samples; /*else if (!ogg_page_bos(&og)) skip_samples = 0;*/ } else { skip_samples = 0; } last_granule = page_granule; packets_available=true; } /*Extract all available packets*/ //int packet_no=0; while (todo > page_size && !eos) { if (ogg_stream_packetout(&os, &op)!=1) { packets_available=false; break; } packet_no++; /*End of stream condition*/ if (op.e_o_s) eos=1; /*Copy Ogg packet to Speex bitstream*/ speex_bits_read_from(&bits, (char*)op.packet, op.bytes); for (int j=0;j!=nframes;j++) { int16_t* out = p_buffer; int ret; /*Decode frame*/ ret = speex_decode_int(st, &bits, out); /*for (i=0;i<frame_size*channels;i++) printf ("%d\n", (int)output[i]);*/ if (ret==-1) { printf("decode returned -1\n"); break; }; if (ret==-2) { OS::get_singleton()->printerr( "Decoding error: corrupted stream?\n"); break; } if (speex_bits_remaining(&bits)<0) { OS::get_singleton()->printerr( "Decoding overflow: corrupted stream?\n"); break; } //if (channels==2) // speex_decode_stereo_int(output, frame_size, &stereo); /*Convert to short and save to output file*/ for (int i=0;i<frame_size*stream_channels;i++) { out[i]=le_short(out[i]); } { int frame_offset = 0; int new_frame_size = frame_size; /*printf ("packet %d %d\n", packet_no, skip_samples);*/ if (packet_no == 1 && j==0 && skip_samples > 0) { /*printf ("chopping first packet\n");*/ new_frame_size -= skip_samples; frame_offset = skip_samples; } if (packet_no == page_nb_packets && skip_samples < 0) { int packet_length = nframes*frame_size+skip_samples; new_frame_size = packet_length - j*frame_size; if (new_frame_size<0) new_frame_size = 0; if (new_frame_size>frame_size) new_frame_size = frame_size; /*printf ("chopping end: %d %d %d\n", new_frame_size, packet_length, packet_no);*/ } p_buffer+=new_frame_size*stream_channels; todo-=new_frame_size; } } }; }; //todo = get_todo(); //todo is still greater than page size, can write more if (todo > page_size || eos) { if (read_ofs < data.size()) { //char *buf; int nb_read = MIN(data.size() - read_ofs, READ_CHUNK); /*Get the ogg buffer for writing*/ char* ogg_dst = ogg_sync_buffer(&oy, nb_read); /*Read bitstream from input file*/ copymem(ogg_dst, &data[read_ofs], nb_read); read_ofs += nb_read; ogg_sync_wrote(&oy, nb_read); } else { if (loops) { reload(); ++loop_count; //break; } else { playing=false; unload(); break; }; } }; }; return p_frames-todo; };
void AudioStreamPlaybackSpeex::reload() { if (active) unload(); if (!data.size()) return; ogg_sync_init(&oy); speex_bits_init(&bits); read_ofs = 0; // char *buf; int packet_count = 0; int extra_headers = 0; int stream_init = 0; page_granule=0; last_granule=0; skip_samples=0; page_nb_packets=0; packets_available=false; packet_no=0; int eos = 0; do { /*Get the ogg buffer for writing*/ int nb_read = MIN(data.size() - read_ofs, READ_CHUNK); char* ogg_dst = ogg_sync_buffer(&oy, nb_read); /*Read bitstream from input file*/ copymem(ogg_dst, &data[read_ofs], nb_read); read_ofs += nb_read; ogg_sync_wrote(&oy, nb_read); /*Loop for all complete pages we got (most likely only one)*/ while (ogg_sync_pageout(&oy, &og)==1) { int packet_no; if (stream_init == 0) { ogg_stream_init(&os, ogg_page_serialno(&og)); stream_init = 1; } /*Add page to the bitstream*/ ogg_stream_pagein(&os, &og); page_granule = ogg_page_granulepos(&og); page_nb_packets = ogg_page_packets(&og); if (page_granule>0 && frame_size) { skip_samples = page_nb_packets*frame_size*nframes - (page_granule-last_granule); if (ogg_page_eos(&og)) skip_samples = -skip_samples; /*else if (!ogg_page_bos(&og)) skip_samples = 0;*/ } else { skip_samples = 0; } last_granule = page_granule; /*Extract all available packets*/ packet_no=0; while (!eos && ogg_stream_packetout(&os, &op)==1) { /*If first packet, process as Speex header*/ if (packet_count==0) { int rate = 0; int channels; st = process_header(&op, &frame_size, &rate, &nframes, &channels, &extra_headers); if (!nframes) nframes=1; if (!st) { unload(); return; }; page_size = nframes * frame_size; stream_srate=rate; stream_channels=channels; stream_minbuff_size=page_size; } else if (packet_count==1) { } else if (packet_count<=1+extra_headers) { /* Ignore extra headers */ }; }; ++packet_count; }; } while (packet_count <= extra_headers); active=true; }
int OggDec::DecodeOGG(char *inmemory,int inmemsize, char *outmemory,int outmemsize,int *done) { char *buffer; int i; *done = 0; if(leakSize){ if(outmemsize >= leakSize){ memcpy(outmemory,leak_mem,leakSize); *done = leakSize; free(leak_mem); leak_mem = NULL; leakSize = 0; allocMemSize = 0; }else{ memcpy(outmemory,leak_mem,outmemsize); *done = outmemsize; memmove(leak_mem,leak_mem+outmemsize,leakSize-outmemsize); leakSize -= outmemsize; } if(inmemsize==0) return (OGG_DEC_CONTINUE); } if(0==decStep){ eos = 0; buffer=ogg_sync_buffer(&oy,4096); memcpy(buffer,inmemory,inmemsize); ogg_sync_wrote(&oy,inmemsize); if(ogg_sync_pageout(&oy,&og)!=1){ if(inmemsize<4096){ Clear_ogg(); return(OGG_DEC_END); } return(OGG_DEC_ERR); } ogg_stream_init(&os,ogg_page_serialno(&og)); vorbis_info_init(&vi); vorbis_comment_init(&vc); if(ogg_stream_pagein(&os,&og)<0){ return(OGG_DEC_ERR); } if(ogg_stream_packetout(&os,&op)!=1){ return(OGG_DEC_ERR); } if(vorbis_synthesis_headerin(&vi,&vc,&op)<0){ return(OGG_DEC_ERR); } wfmt.wFormatTag = WAVE_FORMAT_PCM; wfmt.nChannels = vi.channels; wfmt.wBitsPerSample = 16; wfmt.nSamplesPerSec = vi.rate; wfmt.nBlockAlign = wfmt.nChannels * (wfmt.wBitsPerSample/8); wfmt.nAvgBytesPerSec = wfmt.nSamplesPerSec * wfmt.nBlockAlign; wfmt.cbSize = 0; bWaveGet = TRUE; decStep = 1; d1loop=0; return (OGG_DEC_CONTINUE); } if(1==decStep){ while(d1loop<2){ while(d1loop<2){ int result=ogg_sync_pageout(&oy,&og); if(result==0)break; if(result==1){ ogg_stream_pagein(&os,&og); while(d1loop<2){ result=ogg_stream_packetout(&os,&op); if(result==0)break; if(result<0){ return(OGG_DEC_ERR); } vorbis_synthesis_headerin(&vi,&vc,&op); d1loop++; } } } buffer=ogg_sync_buffer(&oy,4096); memcpy(buffer,inmemory,inmemsize); if(inmemsize==0 && d1loop<2){ return(OGG_DEC_ERR); } ogg_sync_wrote(&oy,inmemsize); if(d1loop<2) return (OGG_DEC_CONTINUE); } decStep = 2; convsize=4096/vi.channels; vorbis_synthesis_init(&vd,&vi); vorbis_block_init(&vd,&vb); return (OGG_DEC_CONTINUE); } while(!eos){ while(!eos){ int result=ogg_sync_pageout(&oy,&og); if(result==0)break; if(result<0){ }else{ ogg_stream_pagein(&os,&og); while(1){ result=ogg_stream_packetout(&os,&op); if(result==0)break; if(result<0){ }else{ float **pcm; int samples; if(vorbis_synthesis(&vb,&op)==0) vorbis_synthesis_blockin(&vd,&vb); while((samples=vorbis_synthesis_pcmout(&vd,&pcm))>0){ int j; int clipflag=0; int bout=(samples<convsize?samples:convsize); for(i=0;i<vi.channels;i++){ ogg_int16_t *ptr=convbuffer+i; float *mono=pcm[i]; for(j=0;j<bout;j++){ #if 1 int val=int(mono[j]*32767.f); #else int val=mono[j]*32767.f+drand48()-0.5f; #endif if(val>32767){ val=32767; clipflag=1; } if(val<-32768){ val=-32768; clipflag=1; } *ptr=val; ptr+=(vi.channels); } } if(NULL==leak_mem){ if(outmemsize >= (*done +2*vi.channels*bout)){ memcpy(outmemory+(*done),convbuffer,2*vi.channels*bout); *done += 2*vi.channels*bout; }else{ allocMemSize = 0x100000; leak_mem = (char *)malloc(allocMemSize); } } if(leak_mem){ if(allocMemSize < (leakSize + 2*vi.channels*bout)){ allocMemSize += 0x100000; realloc(leak_mem,allocMemSize); } memcpy(leak_mem+leakSize,convbuffer,2*vi.channels*bout); leakSize += 2*vi.channels*bout; } vorbis_synthesis_read(&vd,bout); } } } if(ogg_page_eos(&og))eos=1; } } if(!eos){ buffer=ogg_sync_buffer(&oy,4096); memcpy(buffer,inmemory,inmemsize); ogg_sync_wrote(&oy,inmemsize); if(inmemsize==0) eos=1; return (OGG_DEC_CONTINUE); } } if(bLoop){ eos = 0; return OGG_DEC_REPLAY; } ogg_stream_clear(&os); vorbis_block_clear(&vb); vorbis_dsp_clear(&vd); vorbis_comment_clear(&vc); vorbis_info_clear(&vi); decStep = 0; return (OGG_DEC_CONTINUE); }
static int read_packet(struct ast_filestream *fs) { struct speex_desc *s = (struct speex_desc *)fs->_private; char *buffer; int result; size_t bytes; while (1) { /* Get one packet */ result = ogg_stream_packetout(&s->os, &s->op); if (result > 0) { if (s->op.bytes >= 5 && !memcmp(s->op.packet, "Speex", 5)) { s->serialno = s->os.serialno; } if (s->serialno == -1 || s->os.serialno != s->serialno) { continue; } return 0; } if (result < 0) { ast_log(LOG_WARNING, "Corrupt or missing data at this page position; continuing...\n"); } /* No more packets left in the current page... */ if (s->eos) { /* No more pages left in the stream */ return -1; } while (!s->eos) { /* See if OGG has any pages in it's internal buffers */ result = ogg_sync_pageout(&s->oy, &s->og); if (result > 0) { /* Read all streams. */ if (ogg_page_serialno(&s->og) != s->os.serialno) { ogg_stream_reset_serialno(&s->os, ogg_page_serialno(&s->og)); } /* Yes, OGG has more pages in it's internal buffers, add the page to the stream state */ result = ogg_stream_pagein(&s->os, &s->og); if (result == 0) { /* Yes, got a new, valid page */ if (ogg_page_eos(&s->og) && ogg_page_serialno(&s->og) == s->serialno) s->eos = 1; break; } ast_log(LOG_WARNING, "Invalid page in the bitstream; continuing...\n"); } if (result < 0) { ast_log(LOG_WARNING, "Corrupt or missing data in bitstream; continuing...\n"); } /* No, we need to read more data from the file descrptor */ /* get a buffer from OGG to read the data into */ buffer = ogg_sync_buffer(&s->oy, BLOCK_SIZE); bytes = fread(buffer, 1, BLOCK_SIZE, fs->f); ogg_sync_wrote(&s->oy, bytes); if (bytes == 0) { s->eos = 1; } } } }
int main(void){ ogg_stream_init(&os_en,0x04030201); ogg_stream_init(&os_de,0x04030201); ogg_sync_init(&oy); /* Exercise each code path in the framing code. Also verify that the checksums are working. */ { /* 17 only */ const int packets[]={17, -1}; const int *headret[]={head1_0,NULL}; fprintf(stderr,"testing single page encoding... "); test_pack(packets,headret,0,0,0); } { /* 17, 254, 255, 256, 500, 510, 600 byte, pad */ const int packets[]={17, 254, 255, 256, 500, 510, 600, -1}; const int *headret[]={head1_1,head2_1,NULL}; fprintf(stderr,"testing basic page encoding... "); test_pack(packets,headret,0,0,0); } { /* nil packets; beginning,middle,end */ const int packets[]={0,17, 254, 255, 0, 256, 0, 500, 510, 600, 0, -1}; const int *headret[]={head1_2,head2_2,NULL}; fprintf(stderr,"testing basic nil packets... "); test_pack(packets,headret,0,0,0); } { /* large initial packet */ const int packets[]={4345,259,255,-1}; const int *headret[]={head1_3,head2_3,NULL}; fprintf(stderr,"testing initial-packet lacing > 4k... "); test_pack(packets,headret,0,0,0); } { /* continuing packet test */ const int packets[]={0,4345,259,255,-1}; const int *headret[]={head1_4,head2_4,head3_4,NULL}; fprintf(stderr,"testing single packet page span... "); test_pack(packets,headret,0,0,0); } /* page with the 255 segment limit */ { const int packets[]={0,10,10,10,10,10,10,10,10, 10,10,10,10,10,10,10,10, 10,10,10,10,10,10,10,10, 10,10,10,10,10,10,10,10, 10,10,10,10,10,10,10,10, 10,10,10,10,10,10,10,10, 10,10,10,10,10,10,10,10, 10,10,10,10,10,10,10,10, 10,10,10,10,10,10,10,10, 10,10,10,10,10,10,10,10, 10,10,10,10,10,10,10,10, 10,10,10,10,10,10,10,10, 10,10,10,10,10,10,10,10, 10,10,10,10,10,10,10,10, 10,10,10,10,10,10,10,10, 10,10,10,10,10,10,10,10, 10,10,10,10,10,10,10,10, 10,10,10,10,10,10,10,10, 10,10,10,10,10,10,10,10, 10,10,10,10,10,10,10,10, 10,10,10,10,10,10,10,10, 10,10,10,10,10,10,10,10, 10,10,10,10,10,10,10,10, 10,10,10,10,10,10,10,10, 10,10,10,10,10,10,10,10, 10,10,10,10,10,10,10,10, 10,10,10,10,10,10,10,10, 10,10,10,10,10,10,10,10, 10,10,10,10,10,10,10,10, 10,10,10,10,10,10,10,10, 10,10,10,10,10,10,10,10, 10,10,10,10,10,10,10,50,-1}; const int *headret[]={head1_5,head2_5,head3_5,NULL}; fprintf(stderr,"testing max packet segments... "); test_pack(packets,headret,0,0,0); } { /* packet that overspans over an entire page */ const int packets[]={0,100,9000,259,255,-1}; const int *headret[]={head1_6,head2_6,head3_6,head4_6,NULL}; fprintf(stderr,"testing very large packets... "); test_pack(packets,headret,0,0,0); } { /* test for the libogg 1.1.1 resync in large continuation bug found by Josh Coalson) */ const int packets[]={0,100,9000,259,255,-1}; const int *headret[]={head1_6,head2_6,head3_6,head4_6,NULL}; fprintf(stderr,"testing continuation resync in very large packets... "); test_pack(packets,headret,100,2,3); } { /* term only page. why not? */ const int packets[]={0,100,4080,-1}; const int *headret[]={head1_7,head2_7,head3_7,NULL}; fprintf(stderr,"testing zero data page (1 nil packet)... "); test_pack(packets,headret,0,0,0); } { /* build a bunch of pages for testing */ unsigned char *data=_ogg_malloc(1024*1024); int pl[]={0,100,4079,2956,2057,76,34,912,0,234,1000,1000,1000,300,-1}; int inptr=0,i,j; ogg_page og[5]; ogg_stream_reset(&os_en); for(i=0;pl[i]!=-1;i++){ ogg_packet op; int len=pl[i]; op.packet=data+inptr; op.bytes=len; op.e_o_s=(pl[i+1]<0?1:0); op.granulepos=(i+1)*1000; for(j=0;j<len;j++)data[inptr++]=i+j; ogg_stream_packetin(&os_en,&op); } _ogg_free(data); /* retrieve finished pages */ for(i=0;i<5;i++){ if(ogg_stream_pageout(&os_en,&og[i])==0){ fprintf(stderr,"Too few pages output building sync tests!\n"); exit(1); } copy_page(&og[i]); } /* Test lost pages on pagein/packetout: no rollback */ { ogg_page temp; ogg_packet test; fprintf(stderr,"Testing loss of pages... "); ogg_sync_reset(&oy); ogg_stream_reset(&os_de); for(i=0;i<5;i++){ memcpy(ogg_sync_buffer(&oy,og[i].header_len),og[i].header, og[i].header_len); ogg_sync_wrote(&oy,og[i].header_len); memcpy(ogg_sync_buffer(&oy,og[i].body_len),og[i].body,og[i].body_len); ogg_sync_wrote(&oy,og[i].body_len); } ogg_sync_pageout(&oy,&temp); ogg_stream_pagein(&os_de,&temp); ogg_sync_pageout(&oy,&temp); ogg_stream_pagein(&os_de,&temp); ogg_sync_pageout(&oy,&temp); /* skip */ ogg_sync_pageout(&oy,&temp); ogg_stream_pagein(&os_de,&temp); /* do we get the expected results/packets? */ if(ogg_stream_packetout(&os_de,&test)!=1)error(); checkpacket(&test,0,0,0); if(ogg_stream_packetout(&os_de,&test)!=1)error(); checkpacket(&test,100,1,-1); if(ogg_stream_packetout(&os_de,&test)!=1)error(); checkpacket(&test,4079,2,3000); if(ogg_stream_packetout(&os_de,&test)!=-1){ fprintf(stderr,"Error: loss of page did not return error\n"); exit(1); } if(ogg_stream_packetout(&os_de,&test)!=1)error(); checkpacket(&test,76,5,-1); if(ogg_stream_packetout(&os_de,&test)!=1)error(); checkpacket(&test,34,6,-1); fprintf(stderr,"ok.\n"); } /* Test lost pages on pagein/packetout: rollback with continuation */ { ogg_page temp; ogg_packet test; fprintf(stderr,"Testing loss of pages (rollback required)... "); ogg_sync_reset(&oy); ogg_stream_reset(&os_de); for(i=0;i<5;i++){ memcpy(ogg_sync_buffer(&oy,og[i].header_len),og[i].header, og[i].header_len); ogg_sync_wrote(&oy,og[i].header_len); memcpy(ogg_sync_buffer(&oy,og[i].body_len),og[i].body,og[i].body_len); ogg_sync_wrote(&oy,og[i].body_len); } ogg_sync_pageout(&oy,&temp); ogg_stream_pagein(&os_de,&temp); ogg_sync_pageout(&oy,&temp); ogg_stream_pagein(&os_de,&temp); ogg_sync_pageout(&oy,&temp); ogg_stream_pagein(&os_de,&temp); ogg_sync_pageout(&oy,&temp); /* skip */ ogg_sync_pageout(&oy,&temp); ogg_stream_pagein(&os_de,&temp); /* do we get the expected results/packets? */ if(ogg_stream_packetout(&os_de,&test)!=1)error(); checkpacket(&test,0,0,0); if(ogg_stream_packetout(&os_de,&test)!=1)error(); checkpacket(&test,100,1,-1); if(ogg_stream_packetout(&os_de,&test)!=1)error(); checkpacket(&test,4079,2,3000); if(ogg_stream_packetout(&os_de,&test)!=1)error(); checkpacket(&test,2956,3,4000); if(ogg_stream_packetout(&os_de,&test)!=-1){ fprintf(stderr,"Error: loss of page did not return error\n"); exit(1); } if(ogg_stream_packetout(&os_de,&test)!=1)error(); checkpacket(&test,300,13,14000); fprintf(stderr,"ok.\n"); } /* the rest only test sync */ { ogg_page og_de; /* Test fractional page inputs: incomplete capture */ fprintf(stderr,"Testing sync on partial inputs... "); ogg_sync_reset(&oy); memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header, 3); ogg_sync_wrote(&oy,3); if(ogg_sync_pageout(&oy,&og_de)>0)error(); /* Test fractional page inputs: incomplete fixed header */ memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header+3, 20); ogg_sync_wrote(&oy,20); if(ogg_sync_pageout(&oy,&og_de)>0)error(); /* Test fractional page inputs: incomplete header */ memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header+23, 5); ogg_sync_wrote(&oy,5); if(ogg_sync_pageout(&oy,&og_de)>0)error(); /* Test fractional page inputs: incomplete body */ memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header+28, og[1].header_len-28); ogg_sync_wrote(&oy,og[1].header_len-28); if(ogg_sync_pageout(&oy,&og_de)>0)error(); memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body,1000); ogg_sync_wrote(&oy,1000); if(ogg_sync_pageout(&oy,&og_de)>0)error(); memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body+1000, og[1].body_len-1000); ogg_sync_wrote(&oy,og[1].body_len-1000); if(ogg_sync_pageout(&oy,&og_de)<=0)error(); fprintf(stderr,"ok.\n"); } /* Test fractional page inputs: page + incomplete capture */ { ogg_page og_de; fprintf(stderr,"Testing sync on 1+partial inputs... "); ogg_sync_reset(&oy); memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header, og[1].header_len); ogg_sync_wrote(&oy,og[1].header_len); memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body, og[1].body_len); ogg_sync_wrote(&oy,og[1].body_len); memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header, 20); ogg_sync_wrote(&oy,20); if(ogg_sync_pageout(&oy,&og_de)<=0)error(); if(ogg_sync_pageout(&oy,&og_de)>0)error(); memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header+20, og[1].header_len-20); ogg_sync_wrote(&oy,og[1].header_len-20); memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body, og[1].body_len); ogg_sync_wrote(&oy,og[1].body_len); if(ogg_sync_pageout(&oy,&og_de)<=0)error(); fprintf(stderr,"ok.\n"); } /* Test recapture: garbage + page */ { ogg_page og_de; fprintf(stderr,"Testing search for capture... "); ogg_sync_reset(&oy); /* 'garbage' */ memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body, og[1].body_len); ogg_sync_wrote(&oy,og[1].body_len); memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header, og[1].header_len); ogg_sync_wrote(&oy,og[1].header_len); memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body, og[1].body_len); ogg_sync_wrote(&oy,og[1].body_len); memcpy(ogg_sync_buffer(&oy,og[2].header_len),og[2].header, 20); ogg_sync_wrote(&oy,20); if(ogg_sync_pageout(&oy,&og_de)>0)error(); if(ogg_sync_pageout(&oy,&og_de)<=0)error(); if(ogg_sync_pageout(&oy,&og_de)>0)error(); memcpy(ogg_sync_buffer(&oy,og[2].header_len),og[2].header+20, og[2].header_len-20); ogg_sync_wrote(&oy,og[2].header_len-20); memcpy(ogg_sync_buffer(&oy,og[2].body_len),og[2].body, og[2].body_len); ogg_sync_wrote(&oy,og[2].body_len); if(ogg_sync_pageout(&oy,&og_de)<=0)error(); fprintf(stderr,"ok.\n"); } /* Test recapture: page + garbage + page */ { ogg_page og_de; fprintf(stderr,"Testing recapture... "); ogg_sync_reset(&oy); memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header, og[1].header_len); ogg_sync_wrote(&oy,og[1].header_len); memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body, og[1].body_len); ogg_sync_wrote(&oy,og[1].body_len); memcpy(ogg_sync_buffer(&oy,og[2].header_len),og[2].header, og[2].header_len); ogg_sync_wrote(&oy,og[2].header_len); memcpy(ogg_sync_buffer(&oy,og[2].header_len),og[2].header, og[2].header_len); ogg_sync_wrote(&oy,og[2].header_len); if(ogg_sync_pageout(&oy,&og_de)<=0)error(); memcpy(ogg_sync_buffer(&oy,og[2].body_len),og[2].body, og[2].body_len-5); ogg_sync_wrote(&oy,og[2].body_len-5); memcpy(ogg_sync_buffer(&oy,og[3].header_len),og[3].header, og[3].header_len); ogg_sync_wrote(&oy,og[3].header_len); memcpy(ogg_sync_buffer(&oy,og[3].body_len),og[3].body, og[3].body_len); ogg_sync_wrote(&oy,og[3].body_len); if(ogg_sync_pageout(&oy,&og_de)>0)error(); if(ogg_sync_pageout(&oy,&og_de)<=0)error(); fprintf(stderr,"ok.\n"); } /* Free page data that was previously copied */ { for(i=0;i<5;i++){ free_page(&og[i]); } } } return(0); }
/** central buffer management function * @param openmaxStandComp the component handle * @param inputbuffer contains the input ogg file content * @param outputbuffer is returned along with its output pcm file content that is produced as a result of this function execution */ void omx_vorbisdec_component_BufferMgmtCallbackVorbis(OMX_COMPONENTTYPE *openmaxStandComp, OMX_BUFFERHEADERTYPE* inputbuffer, OMX_BUFFERHEADERTYPE* outputbuffer) { omx_vorbisdec_component_PrivateType* omx_vorbisdec_component_Private = openmaxStandComp->pComponentPrivate; OMX_U8* outputCurrBuffer; OMX_U32 outputLength; OMX_S32 result; float **pcm; OMX_S32 samples; OMX_S32 i, j; OMX_S32 bout; OMX_S32 clipflag=0; int val; float *mono; int eos=0; char *vorbis_buffer; ogg_int16_t convbuffer[4096]; DEBUG(DEB_LEV_FULL_SEQ, "input buf %x filled len : %d \n", (int)inputbuffer->pBuffer, (int)inputbuffer->nFilledLen); /** Fill up the current input buffer when a new buffer has arrived */ if(omx_vorbisdec_component_Private->isNewBuffer) { omx_vorbisdec_component_Private->inputCurrBuffer = inputbuffer->pBuffer; omx_vorbisdec_component_Private->inputCurrLength = inputbuffer->nFilledLen; omx_vorbisdec_component_Private->positionInOutBuf = 0; DEBUG(DEB_LEV_SIMPLE_SEQ, "new -- input buf %x filled len : %d \n", (int)inputbuffer->pBuffer, (int)inputbuffer->nFilledLen); /** for each new input buffer --- copy buffer content into into ogg sync state structure data */ vorbis_buffer = ogg_sync_buffer(&omx_vorbisdec_component_Private->oy, inputbuffer->nAllocLen); memcpy(vorbis_buffer, inputbuffer->pBuffer, inputbuffer->nFilledLen); ogg_sync_wrote(&omx_vorbisdec_component_Private->oy, inputbuffer->nFilledLen); DEBUG(DEB_LEV_FULL_SEQ,"***** bytes read to buffer (of first header): %d \n",(int)inputbuffer->nFilledLen); } outputCurrBuffer = outputbuffer->pBuffer; outputLength = outputbuffer->nAllocLen; outputbuffer->nFilledLen = 0; outputbuffer->nOffset = 0; if(omx_vorbisdec_component_Private->packetNumber < 3) { omx_vorbisdec_component_Private->isNewBuffer = 0; if(omx_vorbisdec_component_Private->packetNumber == 0) { DEBUG(DEB_LEV_SIMPLE_SEQ, "in processing the first header buffer\n"); if(ogg_sync_pageout(&omx_vorbisdec_component_Private->oy, &omx_vorbisdec_component_Private->og) != 1) { DEBUG(DEB_LEV_ERR, "this input stream is not an Ogg stream\n"); return; } ogg_stream_init(&omx_vorbisdec_component_Private->os, ogg_page_serialno(&omx_vorbisdec_component_Private->og)); vorbis_info_init(&omx_vorbisdec_component_Private->vi); vorbis_comment_init(&omx_vorbisdec_component_Private->vc); if(ogg_stream_pagein(&omx_vorbisdec_component_Private->os, &omx_vorbisdec_component_Private->og) < 0) { DEBUG(DEB_LEV_ERR, "Error reading first page of Ogg bitstream data.\n"); return; } if(ogg_stream_packetout(&omx_vorbisdec_component_Private->os, &omx_vorbisdec_component_Private->op) != 1) { DEBUG(DEB_LEV_ERR, "Error reading initial header packet.\n"); return; } omx_vorbisdec_component_Private->packetNumber++; if(vorbis_synthesis_headerin(&omx_vorbisdec_component_Private->vi, &omx_vorbisdec_component_Private->vc, &omx_vorbisdec_component_Private->op) < 0) { DEBUG(DEB_LEV_ERR, "This Ogg bitstream does not contain Vorbis audio data\n"); return; } } while(omx_vorbisdec_component_Private->packetNumber < 3) { int result=ogg_sync_pageout(&omx_vorbisdec_component_Private->oy,&omx_vorbisdec_component_Private->og); if(result==0) { //break; /* Need more data */ omx_vorbisdec_component_Private->isNewBuffer = 1; inputbuffer->nFilledLen = 0; return; } /* Don't complain about missing or corrupt data yet. We'll catch it at the packet output phase */ if(result==1) { ogg_stream_pagein(&omx_vorbisdec_component_Private->os,&omx_vorbisdec_component_Private->og); /* we can ignore any errors here as they'll also become apparent at packetout */ while(omx_vorbisdec_component_Private->packetNumber < 3) { result=ogg_stream_packetout(&omx_vorbisdec_component_Private->os,&omx_vorbisdec_component_Private->op); if(result==0)break; if(result<0) { /* Uh oh; data at some point was corrupted or missing! We can't tolerate that in a header. Die. */ DEBUG(DEB_LEV_ERR,"Corrupt secondary header. Exiting.\n"); break; }//end if omx_vorbisdec_component_Private->packetNumber++; vorbis_synthesis_headerin(&omx_vorbisdec_component_Private->vi,&omx_vorbisdec_component_Private->vc,&omx_vorbisdec_component_Private->op); }//end while }//end if }//end while omx_vorbisdec_component_Private->isNewBuffer = 1; inputbuffer->nFilledLen = 0; return; } /* A Vorbis logical bitstream begins with 3 headers. Once the last of these has been processed, * we can report the metadata and set up the output audio port appropriately. */ if(omx_vorbisdec_component_Private->packetNumber == 3) { /* Throw the comments plus a few lines about the bitstream we're decoding */ { // ptr should be declared earlier// char **ptr=omx_vorbisdec_component_Private->vc.user_comments; while(*ptr){ DEBUG(DEB_LEV_ERR,"%s\n",*ptr); ++ptr; } DEBUG(DEB_LEV_ERR,"Bitstream is %d channel, %ldHz\n",omx_vorbisdec_component_Private->vi.channels,omx_vorbisdec_component_Private->vi.rate); DEBUG(DEB_LEV_ERR,"Encoded by: %s\n\n",omx_vorbisdec_component_Private->vc.vendor); } /* Update pAudioVorbis settings */ omx_vorbisdec_component_Private->pAudioVorbis.nSampleRate = omx_vorbisdec_component_Private->vi.rate; omx_vorbisdec_component_Private->pAudioVorbis.nChannels = omx_vorbisdec_component_Private->vi.channels; /* Update audio port settings for this Vorbis bitstream */ if ((omx_vorbisdec_component_Private->pAudioPcmMode.nSamplingRate != omx_vorbisdec_component_Private->pAudioVorbis.nSampleRate) || (omx_vorbisdec_component_Private->pAudioPcmMode.nChannels != omx_vorbisdec_component_Private->pAudioVorbis.nChannels)) { omx_vorbisdec_component_Private->pAudioPcmMode.nSamplingRate = omx_vorbisdec_component_Private->pAudioVorbis.nSampleRate; omx_vorbisdec_component_Private->pAudioPcmMode.nChannels = omx_vorbisdec_component_Private->pAudioVorbis.nChannels; /*Send Port Settings changed call back*/ (*(omx_vorbisdec_component_Private->callbacks->EventHandler)) (openmaxStandComp, omx_vorbisdec_component_Private->callbackData, OMX_EventPortSettingsChanged, /* The command was completed */ 0, 1, /* This is the output port index */ NULL); } omx_vorbisdec_component_Private->convsize=inputbuffer->nFilledLen/omx_vorbisdec_component_Private->vi.channels; /* OK, got and parsed all three headers. Initialize the Vorbis packet->PCM decoder. */ vorbis_synthesis_init(&omx_vorbisdec_component_Private->vd,&omx_vorbisdec_component_Private->vi); /* central decode state */ vorbis_block_init(&omx_vorbisdec_component_Private->vd,&omx_vorbisdec_component_Private->vb);/* local state for most of the decode so multiple block decodes can proceed in parallel. We could init multiple vorbis_block structures for vd here */ } DEBUG(DEB_LEV_FULL_SEQ,"***** now the decoding will start *****\n"); if(omx_vorbisdec_component_Private->isNewBuffer) { omx_vorbisdec_component_Private->isNewBuffer=0; int result=ogg_sync_pageout(&omx_vorbisdec_component_Private->oy,&omx_vorbisdec_component_Private->og); DEBUG(DEB_LEV_FULL_SEQ," ---> page (read in decoding) - header len : %ld body len : %ld \n",omx_vorbisdec_component_Private->og.header_len,omx_vorbisdec_component_Private->og.body_len); if(result == 0) { omx_vorbisdec_component_Private->isNewBuffer = 1; inputbuffer->nFilledLen = 0; return; } if(result<0) { /* missing or corrupt data at this page position */ DEBUG(DEB_LEV_ERR,"Corrupt or missing data in bitstream; continuing...\n"); } else { ogg_stream_pagein(&omx_vorbisdec_component_Private->os,&omx_vorbisdec_component_Private->og); /* can safely ignore errors at */ } } result=ogg_stream_packetout(&omx_vorbisdec_component_Private->os,&omx_vorbisdec_component_Private->op); DEBUG(DEB_LEV_FULL_SEQ," packet length (read in decoding a particular page): %ld \n",omx_vorbisdec_component_Private->op.bytes); if(result == 0) { omx_vorbisdec_component_Private->isNewBuffer = 1; inputbuffer->nFilledLen = 0; return; } if(result<0) { /* missing or corrupt data at this page position */ /* no reason to complain; already complained above */ DEBUG(DEB_LEV_ERR,"Corrupt or missing data in bitstream; continuing...\n"); } else { /* we have a packet. Decode it */ omx_vorbisdec_component_Private->packetNumber++; if(vorbis_synthesis(&omx_vorbisdec_component_Private->vb,&omx_vorbisdec_component_Private->op)==0) /* test for success! */ vorbis_synthesis_blockin(&omx_vorbisdec_component_Private->vd,&omx_vorbisdec_component_Private->vb); /**pcm is a multichannel float vector. In stereo, for example, pcm[0] is left, and pcm[1] is right. samples is the size of each channel. Convert the float values (-1.<=range<=1.) to whatever PCM format and write it out */ while((samples=vorbis_synthesis_pcmout(&omx_vorbisdec_component_Private->vd,&pcm))>0) { bout=(samples<omx_vorbisdec_component_Private->convsize?samples:omx_vorbisdec_component_Private->convsize); /* convert floats to 16 bit signed ints (host order) and interleave */ for(i=0;i<omx_vorbisdec_component_Private->vi.channels;i++) { ogg_int16_t *ptr=convbuffer+i; mono=pcm[i]; for(j=0;j<bout;j++) { #if 1 val=mono[j]*32767.f; #else /* optional dither */ val=mono[j]*32767.f+drand48()-0.5f; #endif /* might as well guard against clipping */ if(val>32767) { val=32767; clipflag=1; } if(val<-32768) { val=-32768; clipflag=1; } *ptr=val; ptr+=omx_vorbisdec_component_Private->vi.channels; } } outputbuffer->nFilledLen=2*omx_vorbisdec_component_Private->vi.channels*bout; memcpy(outputCurrBuffer,(char *)convbuffer,outputbuffer->nFilledLen); if(clipflag) { DEBUG(DEB_LEV_FULL_SEQ,"Clipping in frame %ld\n",(long)(omx_vorbisdec_component_Private->vd.sequence)); } vorbis_synthesis_read(&omx_vorbisdec_component_Private->vd,bout); /* tell libvorbis how many samples we actually consumed */ } } if(ogg_page_eos(&omx_vorbisdec_component_Private->og)) { DEBUG(DEB_LEV_FULL_SEQ, "In %s EOS Detected\n",__func__); eos=1; } DEBUG(DEB_LEV_FULL_SEQ, "One output buffer %x len=%d is full returning\n", (int)outputbuffer->pBuffer, (int)outputbuffer->nFilledLen); }
/* The page is the beginning of a new stream. Check the contents for known stream headers. If it is a known stream and the user has requested that it should be extracted then allocate a new packetizer based on the stream type and store the needed data in a new ogm_demuxer_c. */ void ogm_reader_c::handle_new_stream(ogg_page *og) { ogg_stream_state os; ogg_packet op; if (ogg_stream_init(&os, ogg_page_serialno(og))) { mxwarn_fn(m_ti.m_fname, boost::format(Y("ogg_stream_init for stream number %1% failed. Will try to continue and ignore this stream.\n")) % sdemuxers.size()); return; } // Read the first page and get its first packet. ogg_stream_pagein(&os, og); ogg_stream_packetout(&os, &op); ogm_demuxer_c *dmx = nullptr; /* * Check the contents for known stream headers. This one is the * standard Vorbis header. */ if ((7 <= op.bytes) && !strncmp((char *)&op.packet[1], "vorbis", 6)) dmx = new ogm_a_vorbis_demuxer_c(this); else if ((8 <= op.bytes) && !memcmp(&op.packet[0], "OpusHead", 8)) dmx = new ogm_a_opus_demuxer_c(this); else if ((7 <= op.bytes) && !strncmp((char *)&op.packet[1], "theora", 6)) dmx = new ogm_v_theora_demuxer_c(this); else if ((8 <= op.bytes) && !memcmp(&op.packet[1], "kate\0\0\0", 7)) dmx = new ogm_s_kate_demuxer_c(this); // FLAC else if ( ((4 <= op.bytes) && !strncmp(reinterpret_cast<char *>(&op.packet[0]), "fLaC", 4)) || ((5 <= op.bytes) && !strncmp(reinterpret_cast<char *>(&op.packet[1]), "FLAC", 4) && (0x7f == op.packet[0]))) { #if !defined(HAVE_FLAC_FORMAT_H) if (demuxing_requested('a', sdemuxers.size())) mxerror_fn(m_ti.m_fname, Y("mkvmerge has not been compiled with FLAC support but handling of this stream has been requested.\n")); else { dmx = new ogm_demuxer_c(this); dmx->stype = OGM_STREAM_TYPE_A_FLAC; dmx->in_use = true; } #else dmx = new ogm_a_flac_demuxer_c(this, 0x7f == op.packet[0] ? ofm_post_1_1_1 : ofm_pre_1_1_1); #endif } else if ((static_cast<size_t>(op.bytes) >= sizeof(vp8_ogg_header_t)) && (0x4f == op.packet[0]) && (get_uint32_be(&op.packet[1]) == 0x56503830)) dmx = new ogm_v_vp8_demuxer_c(this, op); else if (((*op.packet & PACKET_TYPE_BITS ) == PACKET_TYPE_HEADER) && (op.bytes >= ((int)sizeof(stream_header) + 1))) { // The new stream headers introduced by OggDS (see ogmstreams.h). stream_header *sth = (stream_header *)(op.packet + 1); char buf[5]; buf[4] = 0; if (!strncmp(sth->streamtype, "video", 5)) { memcpy(buf, (char *)sth->subtype, 4); if (mpeg4::p10::is_avc_fourcc(buf) && !hack_engaged(ENGAGE_ALLOW_AVC_IN_VFW_MODE)) dmx = new ogm_v_avc_demuxer_c(this); else dmx = new ogm_v_mscomp_demuxer_c(this); } else if (!strncmp(sth->streamtype, "audio", 5)) { memcpy(buf, (char *)sth->subtype, 4); uint32_t codec_id = strtol(buf, (char **)nullptr, 16); if (0x0001 == codec_id) dmx = new ogm_a_pcm_demuxer_c(this); else if ((0x0050 == codec_id) || (0x0055 == codec_id)) dmx = new ogm_a_mp3_demuxer_c(this); else if (0x2000 == codec_id) dmx = new ogm_a_ac3_demuxer_c(this); else if (0x00ff == codec_id) dmx = new ogm_a_aac_demuxer_c(this); else mxwarn_fn(m_ti.m_fname, boost::format(Y("Unknown audio stream type 0x%|1$04x|. Stream ID %2% will be ignored.\n")) % codec_id % sdemuxers.size()); } else if (!strncmp(sth->streamtype, "text", 4)) dmx = new ogm_s_text_demuxer_c(this); } /* * The old OggDS headers (see MPlayer's source, libmpdemux/demux_ogg.c) * are not supported. */ if (!dmx) dmx = new ogm_demuxer_c(this); std::string type = dmx->get_type(); dmx->serialno = ogg_page_serialno(og); dmx->track_id = sdemuxers.size(); dmx->in_use = (type != "unknown") && demuxing_requested(type[0], dmx->track_id); dmx->packet_data.push_back(memory_c::clone(op.packet, op.bytes)); memcpy(&dmx->os, &os, sizeof(ogg_stream_state)); sdemuxers.push_back(ogm_demuxer_cptr(dmx)); dmx->initialize(); }
UInt32 SFB::Audio::OggSpeexDecoder::_ReadAudio(AudioBufferList *bufferList, UInt32 frameCount) { if(bufferList->mNumberBuffers != mFormat.mChannelsPerFrame) { LOGGER_WARNING("org.sbooth.AudioEngine.Decoder.OggSpeex", "_ReadAudio() called with invalid parameters"); return 0; } UInt32 framesRead = 0; // Reset output buffer data size for(UInt32 i = 0; i < bufferList->mNumberBuffers; ++i) bufferList->mBuffers[i].mDataByteSize = 0; for(;;) { UInt32 framesRemaining = frameCount - framesRead; UInt32 framesToSkip = (UInt32)(bufferList->mBuffers[0].mDataByteSize / sizeof(float)); UInt32 framesInBuffer = (UInt32)(mBufferList->mBuffers[0].mDataByteSize / sizeof(float)); UInt32 framesToCopy = std::min(framesInBuffer, framesRemaining); // Copy data from the buffer to output for(UInt32 i = 0; i < mBufferList->mNumberBuffers; ++i) { float *floatBuffer = (float *)bufferList->mBuffers[i].mData; memcpy(floatBuffer + framesToSkip, mBufferList->mBuffers[i].mData, framesToCopy * sizeof(float)); bufferList->mBuffers[i].mDataByteSize += framesToCopy * sizeof(float); // Move remaining data in buffer to beginning if(framesToCopy != framesInBuffer) { floatBuffer = (float *)mBufferList->mBuffers[i].mData; memmove(floatBuffer, floatBuffer + framesToCopy, (framesInBuffer - framesToCopy) * sizeof(float)); } mBufferList->mBuffers[i].mDataByteSize -= framesToCopy * sizeof(float); } framesRead += framesToCopy; // All requested frames were read if(framesRead == frameCount) break; // EOS reached if(mSpeexEOSReached) break; // Attempt to process the desired number of packets unsigned packetsDesired = 1; while(0 < packetsDesired && !mSpeexEOSReached) { // Process any packets in the current page while(0 < packetsDesired && !mSpeexEOSReached) { // Grab a packet from the streaming layer ogg_packet oggPacket; int result = ogg_stream_packetout(&mOggStreamState, &oggPacket); if(-1 == result) { LOGGER_ERR("org.sbooth.AudioEngine.Decoder.OggSpeex", "Ogg Speex decoding error: Ogg loss of streaming"); break; } // If result is 0, there is insufficient data to assemble a packet if(0 == result) break; // Otherwise, we got a valid packet for processing if(1 == result) { if(5 <= oggPacket.bytes && !memcmp(oggPacket.packet, "Speex", 5)) mSpeexSerialNumber = mOggStreamState.serialno; if(-1 == mSpeexSerialNumber || mOggStreamState.serialno != mSpeexSerialNumber) break; // Ignore the following: // - Speex comments in packet #2 // - Extra headers (optionally) in packets 3+ if(1 != mOggPacketCount && 1 + mExtraSpeexHeaderCount <= mOggPacketCount) { // Detect Speex EOS if(oggPacket.e_o_s && mOggStreamState.serialno == mSpeexSerialNumber) mSpeexEOSReached = true; // SPEEX_GET_FRAME_SIZE is in samples spx_int32_t speexFrameSize; speex_decoder_ctl(mSpeexDecoder, SPEEX_GET_FRAME_SIZE, &speexFrameSize); float buffer [(2 == mFormat.mChannelsPerFrame) ? 2 * speexFrameSize : speexFrameSize]; // Copy the Ogg packet to the Speex bitstream speex_bits_read_from(&mSpeexBits, (char *)oggPacket.packet, (int)oggPacket.bytes); // Decode each frame in the Speex packet for(spx_int32_t i = 0; i < mSpeexFramesPerOggPacket; ++i) { result = speex_decode(mSpeexDecoder, &mSpeexBits, buffer); // -1 indicates EOS if(-1 == result) break; else if(-2 == result) { LOGGER_ERR("org.sbooth.AudioEngine.Decoder.OggSpeex", "Ogg Speex decoding error: possible corrupted stream"); break; } if(0 > speex_bits_remaining(&mSpeexBits)) { LOGGER_ERR("org.sbooth.AudioEngine.Decoder.OggSpeex", "Ogg Speex decoding overflow: possible corrupted stream"); break; } // Normalize the values float maxSampleValue = 1u << 15; vDSP_vsdiv(buffer, 1, &maxSampleValue, buffer, 1, (vDSP_Length)speexFrameSize); // Copy the frames from the decoding buffer to the output buffer, skipping over any frames already decoded framesInBuffer = mBufferList->mBuffers[0].mDataByteSize / sizeof(float); memcpy((float *)mBufferList->mBuffers[0].mData + framesInBuffer, buffer, (size_t)speexFrameSize * sizeof(float)); mBufferList->mBuffers[0].mDataByteSize += (size_t)speexFrameSize * sizeof(float); // Process stereo channel, if present if(2 == mFormat.mChannelsPerFrame) { speex_decode_stereo(buffer, speexFrameSize, mSpeexStereoState); vDSP_vsdiv(buffer + speexFrameSize, 1, &maxSampleValue, buffer + speexFrameSize, 1, (vDSP_Length)speexFrameSize); memcpy((float *)mBufferList->mBuffers[1].mData + framesInBuffer, buffer + speexFrameSize, (size_t)speexFrameSize * sizeof(float)); mBufferList->mBuffers[1].mDataByteSize += (size_t)speexFrameSize * sizeof(float); } // Packet processing finished --packetsDesired; } } ++mOggPacketCount; } } // Grab a new Ogg page for processing, if necessary if(!mSpeexEOSReached && 0 < packetsDesired) { while(1 != ogg_sync_pageout(&mOggSyncState, &mOggPage)) { // Get the ogg buffer for writing char *data = ogg_sync_buffer(&mOggSyncState, READ_SIZE_BYTES); // Read bitstream from input file ssize_t bytesRead = (ssize_t)GetInputSource().Read(data, READ_SIZE_BYTES); if(-1 == bytesRead) { LOGGER_ERR("org.sbooth.AudioEngine.Decoder.OggSpeex", "Unable to read from the input file"); break; } ogg_sync_wrote(&mOggSyncState, bytesRead); // No more data available from input file if(0 == bytesRead) break; } // Ensure all Ogg streams are read if(ogg_page_serialno(&mOggPage) != mOggStreamState.serialno) ogg_stream_reset_serialno(&mOggStreamState, ogg_page_serialno(&mOggPage)); // Get the resultant Ogg page int result = ogg_stream_pagein(&mOggStreamState, &mOggPage); if(0 != result) { LOGGER_ERR("org.sbooth.AudioEngine.Decoder.OggSpeex", "Error reading Ogg page"); break; } } } } mCurrentFrame += framesRead; if(0 == framesRead && mSpeexEOSReached) mTotalFrames = mCurrentFrame; return framesRead; }
static int read_samples(struct ast_filestream *fs, float ***pcm) { int samples_in; int result; char *buffer; int bytes; struct vorbis_desc *s = (struct vorbis_desc *)fs->_private; while (1) { samples_in = vorbis_synthesis_pcmout(&s->vd, pcm); if (samples_in > 0) { return samples_in; } /* The Vorbis decoder needs more data... */ /* See ifOGG has any packets in the current page for the Vorbis decoder. */ result = ogg_stream_packetout(&s->os, &s->op); if (result > 0) { /* Yes OGG had some more packets for the Vorbis decoder. */ if (vorbis_synthesis(&s->vb, &s->op) == 0) { vorbis_synthesis_blockin(&s->vd, &s->vb); } continue; } if (result < 0) ast_log(LOG_WARNING, "Corrupt or missing data at this page position; continuing...\n"); /* No more packets left in the current page... */ if (s->eos) { /* No more pages left in the stream */ return -1; } while (!s->eos) { /* See ifOGG has any pages in it's internal buffers */ result = ogg_sync_pageout(&s->oy, &s->og); if (result > 0) { /* Yes, OGG has more pages in it's internal buffers, add the page to the stream state */ result = ogg_stream_pagein(&s->os, &s->og); if (result == 0) { /* Yes, got a new,valid page */ if (ogg_page_eos(&s->og)) { s->eos = 1; } break; } ast_log(LOG_WARNING, "Invalid page in the bitstream; continuing...\n"); } if (result < 0) ast_log(LOG_WARNING, "Corrupt or missing data in bitstream; continuing...\n"); /* No, we need to read more data from the file descrptor */ /* get a buffer from OGG to read the data into */ buffer = ogg_sync_buffer(&s->oy, BLOCK_SIZE); /* read more data from the file descriptor */ bytes = fread(buffer, 1, BLOCK_SIZE, fs->f); /* Tell OGG how many bytes we actually read into the buffer */ ogg_sync_wrote(&s->oy, bytes); if (bytes == 0) { s->eos = 1; } } } }
static gint xmms_speex_read (xmms_xform_t *xform, gpointer buf, gint len, xmms_error_t *err) { gint ret = 0, n; gfloat outfloat [2000]; gint16 *outbuf = (gint16 *) buf; xmms_speex_data_t *data; xmms_error_t error; SpeexStereoState stereo = SPEEX_STEREO_STATE_INIT; g_return_val_if_fail (xform, -1); data = xmms_xform_private_data_get (xform); g_return_val_if_fail (data, -1); /* convert from bytes to samples */ len /= 2; /* first, copy already decoded samples over if we have any. */ if (data->samples_count) { n = MIN (data->samples_count, len); memcpy (outbuf, data->samples_start, n * 2); data->samples_count -= n; if (!data->samples_count) { data->samples_start = data->samples_buf; } else { data->samples_start += n; } /* convert from samples to bytes */ return n * 2; } while (42) { gint samples_per_frame; samples_per_frame = data->speexheader->frame_size * data->speexheader->nb_channels; while (ogg_stream_packetout (&data->stream_state, &data->ogg_packet) == 1) { gint frame; speex_bits_read_from (&data->speex_bits, (char *)data->ogg_packet.packet, data->ogg_packet.bytes); for (frame = 0; frame < data->speexheader->frames_per_packet; frame++) { gint cnt; speex_decode (data->speex_state, &data->speex_bits, outfloat); if (data->speexheader->nb_channels == 2) { speex_decode_stereo (outfloat, data->speexheader->frame_size,&stereo); } n = MIN (samples_per_frame, len); /* copy as many samples to the output buffer as * possible. */ for (cnt = 0; cnt < n; cnt++) { *outbuf++ = outfloat[cnt]; len--; ret += 2; } /* store the remaining samples for later use */ for (; cnt < samples_per_frame; cnt++) { data->samples_buf[data->samples_count++] = outfloat[cnt]; } } return ret; } /* Need more data */ do { gint ret; data->ogg_data = ogg_sync_buffer (&data->sync_state, 200); ret = xmms_xform_read (xform, data->ogg_data, 200, &error); ogg_sync_wrote (&data->sync_state, ret); if (ret <= 0) { return ret; } } while (ogg_sync_pageout (&data->sync_state, &data->ogg_page) != 1); ogg_stream_pagein (&data->stream_state, &data->ogg_page); } }
/*! * \brief Create a new OGG/Vorbis filestream and set it up for reading. * \param s File that points to on disk storage of the OGG/Vorbis data. * \return The new filestream. */ static int ogg_vorbis_open(struct ast_filestream *s) { int i; int bytes; int result; char **ptr; char *buffer; struct vorbis_desc *tmp = (struct vorbis_desc *)s->_private; tmp->writing = 0; ogg_sync_init(&tmp->oy); buffer = ogg_sync_buffer(&tmp->oy, BLOCK_SIZE); bytes = fread(buffer, 1, BLOCK_SIZE, s->f); ogg_sync_wrote(&tmp->oy, bytes); result = ogg_sync_pageout(&tmp->oy, &tmp->og); if (result != 1) { if(bytes < BLOCK_SIZE) { ast_log(LOG_ERROR, "Run out of data...\n"); } else { ast_log(LOG_ERROR, "Input does not appear to be an Ogg bitstream.\n"); } ogg_sync_clear(&tmp->oy); return -1; } ogg_stream_init(&tmp->os, ogg_page_serialno(&tmp->og)); vorbis_info_init(&tmp->vi); vorbis_comment_init(&tmp->vc); if (ogg_stream_pagein(&tmp->os, &tmp->og) < 0) { ast_log(LOG_ERROR, "Error reading first page of Ogg bitstream data.\n"); error: ogg_stream_clear(&tmp->os); vorbis_comment_clear(&tmp->vc); vorbis_info_clear(&tmp->vi); ogg_sync_clear(&tmp->oy); return -1; } if (ogg_stream_packetout(&tmp->os, &tmp->op) != 1) { ast_log(LOG_ERROR, "Error reading initial header packet.\n"); goto error; } if (vorbis_synthesis_headerin(&tmp->vi, &tmp->vc, &tmp->op) < 0) { ast_log(LOG_ERROR, "This Ogg bitstream does not contain Vorbis audio data.\n"); goto error; } for (i = 0; i < 2 ; ) { while (i < 2) { result = ogg_sync_pageout(&tmp->oy, &tmp->og); if (result == 0) break; if (result == 1) { ogg_stream_pagein(&tmp->os, &tmp->og); while(i < 2) { result = ogg_stream_packetout(&tmp->os,&tmp->op); if(result == 0) break; if(result < 0) { ast_log(LOG_ERROR, "Corrupt secondary header. Exiting.\n"); goto error; } vorbis_synthesis_headerin(&tmp->vi, &tmp->vc, &tmp->op); i++; } } } buffer = ogg_sync_buffer(&tmp->oy, BLOCK_SIZE); bytes = fread(buffer, 1, BLOCK_SIZE, s->f); if (bytes == 0 && i < 2) { ast_log(LOG_ERROR, "End of file before finding all Vorbis headers!\n"); goto error; } ogg_sync_wrote(&tmp->oy, bytes); } for (ptr = tmp->vc.user_comments; *ptr; ptr++) ast_debug(1, "OGG/Vorbis comment: %s\n", *ptr); ast_debug(1, "OGG/Vorbis bitstream is %d channel, %ldHz\n", tmp->vi.channels, tmp->vi.rate); ast_debug(1, "OGG/Vorbis file encoded by: %s\n", tmp->vc.vendor); if (tmp->vi.channels != 1) { ast_log(LOG_ERROR, "Only monophonic OGG/Vorbis files are currently supported!\n"); goto error; } if (tmp->vi.rate != DEFAULT_SAMPLE_RATE) { ast_log(LOG_ERROR, "Only 8000Hz OGG/Vorbis files are currently supported!\n"); vorbis_block_clear(&tmp->vb); vorbis_dsp_clear(&tmp->vd); goto error; } vorbis_synthesis_init(&tmp->vd, &tmp->vi); vorbis_block_init(&tmp->vd, &tmp->vb); return 0; }
/* process the vorbis audio packets. Here we just take each packet out * and add them into the new stream, flushing after so many samples. We * also check if an new headers are requested after each processed page */ static int process_vorbis_audio (ogg_state_t *ogg_info, ogg_codec_t *codec) { vorbis_codec_t *source_vorbis = codec->specific; while (1) { int window; ogg_packet packet; /* now, lets extract what packets we can */ if (ogg_stream_packetout (&codec->os, &packet) <= 0) break; /* calculate granulepos for the packet */ window = vorbis_packet_blocksize (&source_vorbis->vi, &packet) / 4; source_vorbis->granulepos += window; if (source_vorbis->prev_packet) { ogg_packet *prev_packet = source_vorbis->prev_packet; add_audio_packet (source_vorbis, prev_packet); free_ogg_packet (prev_packet); /* check for short values on first initial page */ if (packet . packetno == 4) { source_vorbis->initial_page_granulepos = codec->os.granulepos; if (source_vorbis->initial_page_granulepos < source_vorbis->granulepos) source_vorbis->granulepos -= source_vorbis->initial_page_granulepos; } /* check for long values on first page */ if (packet.granulepos == source_vorbis->initial_page_granulepos) { if (source_vorbis->initial_page_granulepos > source_vorbis->granulepos) source_vorbis->granulepos = source_vorbis->initial_page_granulepos; } if (packet.e_o_s == 0) packet . granulepos = source_vorbis->granulepos; } else { packet . granulepos = 0; } /* store the current packet details */ source_vorbis->prev_window = window; source_vorbis->prev_packet = copy_ogg_packet (&packet); if (packet.e_o_s) { initiate_flush (source_vorbis); free_ogg_packet (source_vorbis->prev_packet); source_vorbis->prev_packet = NULL; return 1; } /* allow for pages to be flushed if there's over a certain number of samples */ if (source_vorbis->samples_in_page > source_vorbis->page_samples_trigger) return 1; } if (source_vorbis->stream_notify) { initiate_flush (source_vorbis); source_vorbis->stream_notify = 0; return 1; } return -1; }
/* Read the speex header. Return 0 on error. */ static int read_speex_header (struct spx_data *data) { int packet_count = 0; int stream_init = 0; char *buf; int nb_read; while (packet_count < 2) { /* Get the ogg buffer for writing */ buf = ogg_sync_buffer (&data->oy, 200); /* Read bitstream from input file */ nb_read = io_read (data->stream, buf, 200); if (nb_read < 0) { decoder_error (&data->error, ERROR_FATAL, 0, "Can't open speex file: IO error: %s", io_strerror(data->stream)); return 0; } if (nb_read == 0) { decoder_error (&data->error, ERROR_FATAL, 0, "Can't open speex header"); return 0; } ogg_sync_wrote (&data->oy, nb_read); /* Loop for all complete pages we got (most likely only one) */ while (ogg_sync_pageout(&data->oy, &data->og) == 1) { if (stream_init == 0) { ogg_stream_init(&data->os, ogg_page_serialno(&data->og)); stream_init = 1; } /* Add page to the bitstream */ ogg_stream_pagein (&data->os, &data->og); /* Extract all available packets FIXME: EOS! */ while (ogg_stream_packetout(&data->os, &data->op) == 1) { /* If first packet, process as Speex header */ if (packet_count == 0) { data->st = process_header (data); if (!data->st) { ogg_stream_clear (&data->os); return 0; } data->rate = data->header->rate; data->nchannels = data->header->nb_channels; data->frames_per_packet = data->header->frames_per_packet; /*data->vbr = data->header->vbr; */ if (!data->frames_per_packet) data->frames_per_packet=1; data->output = xmalloc (data->frame_size * data->nchannels * data->frames_per_packet * sizeof(int16_t)); data->output_start = 0; data->output_left = 0; } else if (packet_count == 1) { data->comment_packet_len = data->op.bytes; data->comment_packet = xmalloc ( sizeof(char) * data->comment_packet_len); memcpy (data->comment_packet, data->op.packet, data->comment_packet_len); } /* FIXME: ignore extra headers */ packet_count++; } } } return 1; }
// Decode static int Decode(void *context, const void *dataRAW, size_t sizeRAW, void **ppdataPCM, size_t *sizePCM) { OGG_context *ctx = (OGG_context*)context; *sizePCM = 0; *ppdataPCM = 0; if (!dataRAW) return 0; switch(ctx->state) { // Sync buffer case 0xff: { sysMemCpy(ogg_sync_buffer(&ctx->oy, (int32_t)sizeRAW), dataRAW, sizeRAW); ctx->input_size = sizeRAW; ogg_sync_wrote(&ctx->oy, (int32_t)ctx->input_size); ctx->state = 0; } break; // Sync page out case 0: { int result = ogg_sync_pageout(&ctx->oy, &ctx->og); if (result == 0) { ctx->state = 0xff; } else if (result < 0) { ctx->state = -1; } else { ogg_stream_pagein(&ctx->os, &ctx->og); /* can safely ignore errors at this point */ ctx->state = 1; } } break; // Stream packet out case 1: { int result = ogg_stream_packetout(&ctx->os, &ctx->op); if (result == 0) { ctx->state = 0; } else if (result < 0) { ctx->state = -2; } else { /* we have a packet. Decode it */ if (vorbis_synthesis(&ctx->vb, &ctx->op)==0) /* test for success! */ vorbis_synthesis_blockin(&ctx->vd, &ctx->vb); ctx->state = 3; } } break; // synthetis pcm out case 3: { size_t samples; float **pcm; samples = vorbis_synthesis_pcmout(&ctx->vd, &pcm); if (samples<=0) { ctx->state = 1; } else { size_t convsize = ctx->input_size / ctx->vi.channels; size_t bytesCount = samples < convsize ? samples : convsize; SYS_ASSERT(bytesCount < OGG_BUFFER_SIZE); #ifdef SUPPORT_IEEE_AUDIO DeinterleaveAudio(ctx->uncompressed, pcm, ctx->vi.channels, bytesCount); *sizePCM = 4 * ctx->vi.channels * bytesCount; #else ConvertFloatToInteger(ctx->uncompressed, pcm, ctx->vi.channels, bytesCount); *sizePCM = 2 * ctx->vi.channels * bytesCount; #endif /* tell libvorbis how many samples we actually consumed */ vorbis_synthesis_read(&ctx->vd, (int32_t)bytesCount); *ppdataPCM = ctx->uncompressed; } } break; // Invalid state default: SYS_ASSERT(0); return -1; break; } return ctx->state != 0xff ? 1 : 0; }
int main(int argc,char *argv[]){ ogg_packet op; int long_option_index; int c; struct timeb start; struct timeb after; struct timeb last; int fps_only=0; int frames = 0; FILE *infile = stdin; outfile = stdout; #ifdef _WIN32 /* We need to set stdin/stdout to binary mode on windows. */ /* Beware the evil ifdef. We avoid these where we can, but this one we cannot. Don't add any more, you'll probably go to hell if you do. */ _setmode( _fileno( stdin ), _O_BINARY ); _setmode( _fileno( stdout ), _O_BINARY ); #endif /* Process option arguments. */ while((c=getopt_long(argc,argv,optstring,options,&long_option_index))!=EOF){ switch(c){ case 'o': if(strcmp(optarg,"-")!=0){ outfile=fopen(optarg,"wb"); if(outfile==NULL){ fprintf(stderr,"Unable to open output file '%s'\n", optarg); exit(1); } }else{ outfile=stdout; } break; case 'c': crop=1; break; case 'r': raw=1; break; case 'f': fps_only = 1; outfile = NULL; break; default: usage(); } } if(optind<argc){ infile=fopen(argv[optind],"rb"); if(infile==NULL){ fprintf(stderr,"Unable to open '%s' for extraction.\n", argv[optind]); exit(1); } if(++optind<argc){ usage(); exit(1); } } /*Ok, Ogg parsing. The idea here is we have a bitstream that is made up of Ogg pages. The libogg sync layer will find them for us. There may be pages from several logical streams interleaved; we find the first theora stream and ignore any others. Then we pass the pages for our stream to the libogg stream layer which assembles our original set of packets out of them. It's the packets that libtheora actually knows how to handle.*/ /* start up Ogg stream synchronization layer */ ogg_sync_init(&oy); /* init supporting Theora structures needed in header parsing */ th_comment_init(&tc); th_info_init(&ti); /*Ogg file open; parse the headers. Theora (like Vorbis) depends on some initial header packets for decoder setup and initialization. We retrieve these first before entering the main decode loop.*/ /* Only interested in Theora streams */ while(!stateflag){ int ret=buffer_data(infile,&oy); if(ret==0)break; while(ogg_sync_pageout(&oy,&og)>0){ int got_packet; ogg_stream_state test; /* is this a mandated initial header? If not, stop parsing */ if(!ogg_page_bos(&og)){ /* don't leak the page; get it into the appropriate stream */ queue_page(&og); stateflag=1; break; } ogg_stream_init(&test,ogg_page_serialno(&og)); ogg_stream_pagein(&test,&og); got_packet = ogg_stream_packetpeek(&test,&op); /* identify the codec: try theora */ if((got_packet==1) && !theora_p && (theora_processing_headers= th_decode_headerin(&ti,&tc,&ts,&op))>=0){ /* it is theora -- save this stream state */ memcpy(&to,&test,sizeof(test)); theora_p=1; /*Advance past the successfully processed header.*/ if(theora_processing_headers)ogg_stream_packetout(&to,NULL); }else{ /* whatever it is, we don't care about it */ ogg_stream_clear(&test); } } /* fall through to non-bos page parsing */ } /* we're expecting more header packets. */ while(theora_p && theora_processing_headers){ int ret; /* look for further theora headers */ while(theora_processing_headers&&(ret=ogg_stream_packetpeek(&to,&op))){ if(ret<0)continue; theora_processing_headers=th_decode_headerin(&ti,&tc,&ts,&op); if(theora_processing_headers<0){ fprintf(stderr,"Error parsing Theora stream headers; " "corrupt stream?\n"); exit(1); } else if(theora_processing_headers>0){ /*Advance past the successfully processed header.*/ ogg_stream_packetout(&to,NULL); } theora_p++; } /*Stop now so we don't fail if there aren't enough pages in a short stream.*/ if(!(theora_p && theora_processing_headers))break; /* The header pages/packets will arrive before anything else we care about, or the stream is not obeying spec */ if(ogg_sync_pageout(&oy,&og)>0){ queue_page(&og); /* demux into the appropriate stream */ }else{ int ret=buffer_data(infile,&oy); /* someone needs more data */ if(ret==0){ fprintf(stderr,"End of file while searching for codec headers.\n"); exit(1); } } } /* and now we have it all. initialize decoders */ if(theora_p){ dump_comments(&tc); td=th_decode_alloc(&ti,ts); fprintf(stderr,"Ogg logical stream %lx is Theora %dx%d %.02f fps video\n" "Encoded frame content is %dx%d with %dx%d offset\n", to.serialno,ti.frame_width,ti.frame_height, (double)ti.fps_numerator/ti.fps_denominator, ti.pic_width,ti.pic_height,ti.pic_x,ti.pic_y); }else{ /* tear down the partial theora setup */ th_info_clear(&ti); th_comment_clear(&tc); } /*Either way, we're done with the codec setup data.*/ th_setup_free(ts); /* open video */ if(theora_p)open_video(); if(!raw && outfile){ static const char *CHROMA_TYPES[4]={"420jpeg",NULL,"422jpeg","444"}; int width; int height; if(ti.pixel_fmt>=4||ti.pixel_fmt==TH_PF_RSVD){ fprintf(stderr,"Unknown pixel format: %i\n",ti.pixel_fmt); exit(1); } if(crop){ int hdec; int vdec; hdec=!(ti.pixel_fmt&1); vdec=!(ti.pixel_fmt&2); if((ti.pic_x&hdec)||(ti.pic_width&hdec) ||(ti.pic_y&vdec)||(ti.pic_height&vdec)){ fprintf(stderr, "Error: Cropped images with odd offsets/sizes and chroma subsampling\n" "cannot be output to YUV4MPEG2. Remove the --crop flag or add the\n" "--raw flag.\n"); exit(1); } width=ti.pic_width; height=ti.pic_height; } else{ width=ti.frame_width; height=ti.frame_height; } fprintf(outfile,"YUV4MPEG2 C%s W%d H%d F%d:%d I%c A%d:%d\n", CHROMA_TYPES[ti.pixel_fmt],width,height, ti.fps_numerator,ti.fps_denominator,'p', ti.aspect_numerator,ti.aspect_denominator); } /* install signal handler */ signal (SIGINT, sigint_handler); /*Finally the main decode loop. It's one Theora packet per frame, so this is pretty straightforward if we're not trying to maintain sync with other multiplexed streams. The videobuf_ready flag is used to maintain the input buffer in the libogg stream state. If there's no output frame available at the end of the decode step, we must need more input data. We could simplify this by just using the return code on ogg_page_packetout(), but the flag system extends easily to the case where you care about more than one multiplexed stream (like with audio playback). In that case, just maintain a flag for each decoder you care about, and pull data when any one of them stalls. videobuf_time holds the presentation time of the currently buffered video frame. We ignore this value.*/ stateflag=0; /* playback has not begun */ /* queue any remaining pages from data we buffered but that did not contain headers */ while(ogg_sync_pageout(&oy,&og)>0){ queue_page(&og); } if(fps_only){ ftime(&start); ftime(&last); } while(!got_sigint){ while(theora_p && !videobuf_ready){ /* theora is one in, one out... */ if(ogg_stream_packetout(&to,&op)>0){ if(th_decode_packetin(td,&op,&videobuf_granulepos)>=0){ videobuf_time=th_granule_time(td,videobuf_granulepos); videobuf_ready=1; frames++; if(fps_only) ftime(&after); } }else break; } if(fps_only && (videobuf_ready || fps_only==2)){ long ms = after.time*1000.+after.millitm- (last.time*1000.+last.millitm); if(ms>500 || fps_only==1 || (feof(infile) && !videobuf_ready)){ float file_fps = (float)ti.fps_numerator/ti.fps_denominator; fps_only=2; ms = after.time*1000.+after.millitm- (start.time*1000.+start.millitm); fprintf(stderr,"\rframe:%d rate:%.2fx ", frames, frames*1000./(ms*file_fps)); memcpy(&last,&after,sizeof(last)); } } if(!videobuf_ready && feof(infile))break; if(!videobuf_ready){ /* no data yet for somebody. Grab another page */ buffer_data(infile,&oy); while(ogg_sync_pageout(&oy,&og)>0){ queue_page(&og); } } /* dumpvideo frame, and get new one */ else if(outfile)video_write(); videobuf_ready=0; } /* end of decoder loop -- close everything */ if(theora_p){ ogg_stream_clear(&to); th_decode_free(td); th_comment_clear(&tc); th_info_clear(&ti); } ogg_sync_clear(&oy); if(infile && infile!=stdin)fclose(infile); if(outfile && outfile!=stdout)fclose(outfile); fprintf(stderr, "\n\n%d frames\n", frames); fprintf(stderr, "\nDone.\n"); return(0); }
/* this is called for each file to process */ enum codec_status codec_run(void) { int error = CODEC_ERROR; long action; intptr_t param; ogg_sync_state oy; ogg_page og; ogg_packet op; ogg_stream_state os; int64_t page_granule = 0; int stream_init = -1; int sample_rate = 48000; OpusDecoder *st = NULL; OpusHeader header; int ret; unsigned long strtoffset; int skip = 0; int64_t seek_target; uint64_t granule_pos; ogg_malloc_init(); action = CODEC_ACTION_NULL; param = ci->id3->elapsed; strtoffset = ci->id3->offset; #if defined(CPU_COLDFIRE) /* EMAC rounding is disabled because of MULT16_32_Q15, which will be inaccurate with rounding in its current incarnation */ coldfire_set_macsr(EMAC_FRACTIONAL | EMAC_SATURATE); #endif /* pre-init the ogg_sync_state buffer, so it won't need many reallocs */ ogg_sync_init(&oy); oy.storage = 64*1024; oy.data = _ogg_malloc(oy.storage); /* allocate output buffer */ uint16_t *output = (uint16_t*) _ogg_malloc(MAX_FRAME_SIZE*sizeof(uint16_t)); ci->seek_buffer(0); ci->set_elapsed(0); goto next_page; /* need to decode header before we do anything else */ while (1) { action = ci->get_command(¶m); process_action: if (action == CODEC_ACTION_SEEK_TIME) { if (st != NULL) { /* calculate granule to seek to (including seek rewind) */ seek_target = (48LL * param) + header.preskip; skip = MIN(seek_target, SEEK_REWIND); seek_target -= skip; LOGF("Opus seek page:%lld,%lld,%ld\n", seek_target, page_granule, (long)param); opus_seek_page_granule(seek_target, page_granule, &oy, &os); } ci->set_elapsed(param); ci->seek_complete(); param = 0; } else if (action == CODEC_ACTION_HALT) break; next_page: /*Get the ogg buffer for writing*/ if (get_more_data(&oy) < 1) { goto done; } /* Loop for all complete pages we got (most likely only one) */ while (ogg_sync_pageout(&oy, &og) == 1) { if (stream_init != 0) { stream_init = ogg_stream_init(&os, ogg_page_serialno(&og)); if (stream_init != 0) { LOGF("Stream init failed"); goto done; } } /* Add page to the bitstream */ ogg_stream_pagein(&os, &og); page_granule = ogg_page_granulepos(&og); granule_pos = page_granule; while ((ogg_stream_packetout(&os, &op) == 1) && !op.e_o_s) { if (op.packetno == 0){ /* identification header */ if (opus_header_parse(op.packet, op.bytes, &header) == 0) { LOGF("Could not parse header"); goto done; } skip = header.preskip; st = opus_decoder_create(sample_rate, header.channels, &ret); if (ret != OPUS_OK) { LOGF("opus_decoder_create failed %d", ret); goto done; } LOGF("Decoder inited"); codec_set_replaygain(ci->id3); opus_decoder_ctl(st, OPUS_SET_GAIN(header.gain)); ci->configure(DSP_SET_FREQUENCY, sample_rate); ci->configure(DSP_SET_SAMPLE_DEPTH, 16); ci->configure(DSP_SET_STEREO_MODE, (header.channels == 2) ? STEREO_INTERLEAVED : STEREO_MONO); if (strtoffset) seek_ogg_page(strtoffset); else if (param) { action = CODEC_ACTION_SEEK_TIME; goto process_action; } else { /* seek buffer directly to the first audio packet to avoid allocating space for huge comment packets (embedded Album Art) */ if (seek_opus_tags()) seek_ogg_page(ci->curpos); else { LOGF("Could not find comment header"); goto done; } } LOGF("sync reset"); ogg_sync_reset(&oy); /* next page */ break; } else { /* report progress */ ci->set_offset((size_t) ci->curpos); ci->set_elapsed((granule_pos - header.preskip) / 48); /* Decode audio packets */ ret = opus_decode(st, op.packet, op.bytes, output, MAX_FRAME_SIZE, 0); if (ret > skip) { /* part of or entire output buffer is played */ ret -= skip; ci->pcmbuf_insert(&output[skip * header.channels], NULL, ret); skip = 0; } else { if (ret < 0) { LOGF("opus_decode failed %d", ret); goto done; } else if (ret == 0) break; else { /* entire output buffer is skipped */ skip -= ret; ret = 0; } } } } } } LOGF("Returned OK"); error = CODEC_OK; done: ogg_malloc_destroy(); return error; }
/* this is void and does not propogate errors up because we want to be able to open and use damaged bitstreams as well as we can. Just watch out for missing information for links in the OggVorbis_File struct */ static void _prefetch_all_headers(OggVorbis_File *vf, ogg_int64_t dataoffset){ ogg_page og; int i; ogg_int64_t ret; vf->vi=_ogg_realloc(vf->vi,vf->links*sizeof(*vf->vi)); vf->vc=_ogg_realloc(vf->vc,vf->links*sizeof(*vf->vc)); vf->dataoffsets=_ogg_malloc(vf->links*sizeof(*vf->dataoffsets)); vf->pcmlengths=_ogg_malloc(vf->links*2*sizeof(*vf->pcmlengths)); for(i=0;i<vf->links;i++){ if(i==0){ /* we already grabbed the initial header earlier. Just set the offset */ vf->dataoffsets[i]=dataoffset; _seek_helper(vf,dataoffset); }else{ /* seek to the location of the initial header */ _seek_helper(vf,vf->offsets[i]); if(_fetch_headers(vf,vf->vi+i,vf->vc+i,NULL,NULL)<0){ vf->dataoffsets[i]=-1; }else{ vf->dataoffsets[i]=vf->offset; } } /* fetch beginning PCM offset */ if(vf->dataoffsets[i]!=-1){ ogg_int64_t accumulated=0; long lastblock=-1; int result; ogg_stream_reset_serialno(&vf->os,vf->serialnos[i]); while(1){ ogg_packet op; ret=_get_next_page(vf,&og,-1); if(ret<0) /* this should not be possible unless the file is truncated/mangled */ break; if(ogg_page_serialno(&og)!=vf->serialnos[i]) break; /* count blocksizes of all frames in the page */ ogg_stream_pagein(&vf->os,&og); while((result=ogg_stream_packetout(&vf->os,&op))){ if(result>0){ /* ignore holes */ long thisblock=vorbis_packet_blocksize(vf->vi+i,&op); if(lastblock!=-1) accumulated+=(lastblock+thisblock)>>2; lastblock=thisblock; } } if(ogg_page_granulepos(&og)!=-1){ /* pcm offset of last packet on the first audio page */ accumulated= ogg_page_granulepos(&og)-accumulated; break; } } /* less than zero? This is a stream with samples trimmed off the beginning, a normal occurrence; set the offset to zero */ if(accumulated<0)accumulated=0; vf->pcmlengths[i*2]=accumulated; }
static int decode(quicktime_t *file, int16_t *output_i, float *output_f, long samples, int track, int channel) { int result = 0; int i, j; quicktime_audio_map_t *track_map = &(file->atracks[track]); quicktime_trak_t *trak = track_map->track; quicktime_vorbis_codec_t *codec = ((quicktime_codec_t*)track_map->codec)->priv; long current_position = track_map->current_position; long end_position = current_position + samples; char *buffer; // End of data in ogg buffer int eos = 0; float *pcm; int have_chunk = 0; if(samples > OUTPUT_ALLOCATION) printf("vorbis.c decode: can't read more than %d samples at a time.\n", OUTPUT_ALLOCATION); if(output_i) bzero(output_i, sizeof(int16_t) * samples); if(output_f) bzero(output_f, sizeof(float) * samples); // Seeked outside output buffer's range or not initialized: restart if(current_position < codec->output_position - codec->output_size || current_position > codec->output_position || !codec->decode_initialized) { quicktime_chunk_of_sample(&codec->output_position, &codec->chunk, trak, current_position); // We know the first ogg packet in the chunk has a pcm_offset from the encoding. codec->output_size = 0; codec->output_end = 0; codec->chunk_samples = 0; // Initialize and load initial buffer for decoding if(!codec->decode_initialized) { int init_chunk = 1; codec->decode_initialized = 1; codec->output = malloc(sizeof(float*) * track_map->channels); for(i = 0; i < track_map->channels; i++) { codec->output[i] = malloc(sizeof(float) * OUTPUT_ALLOCATION); } codec->output_allocated = OUTPUT_ALLOCATION; ogg_sync_init(&codec->dec_oy); /* Now we can read pages */ READ_CHUNK(init_chunk); init_chunk++; if(ogg_sync_pageout(&codec->dec_oy, &codec->dec_og)!=1) { fprintf(stderr, "decode: ogg_sync_pageout: Must not be Vorbis data\n"); return 1; } ogg_stream_init(&codec->dec_os, ogg_page_serialno(&codec->dec_og)); vorbis_info_init(&codec->dec_vi); vorbis_comment_init(&codec->dec_vc); if(ogg_stream_pagein(&codec->dec_os, &codec->dec_og) < 0) { fprintf(stderr,"decode: ogg_stream_pagein: stream version mismatch perhaps.\n"); return 1; } if(ogg_stream_packetout(&codec->dec_os, &codec->dec_op) != 1) { fprintf(stderr, "decode: ogg_stream_packetout: Must not be Vorbis data\n"); return 1; } if(vorbis_synthesis_headerin(&codec->dec_vi, &codec->dec_vc, &codec->dec_op) < 0) { fprintf(stderr, "decode: vorbis_synthesis_headerin: not a vorbis header\n"); return 1; } i = 0; while(i < 2) { while(i < 2) { result = ogg_sync_pageout(&codec->dec_oy, &codec->dec_og); if(result == 0) break; if(result == 1) { ogg_stream_pagein(&codec->dec_os, &codec->dec_og); while(i < 2) { result = ogg_stream_packetout(&codec->dec_os, &codec->dec_op); if(result == 0) break; if(result < 0) { fprintf(stderr, "decode: ogg_stream_packetout: corrupt secondary header\n"); return 1; } vorbis_synthesis_headerin(&codec->dec_vi, &codec->dec_vc, &codec->dec_op); i++; } } } if(i < 2) { READ_CHUNK(init_chunk); init_chunk++; } // Header should never span more than one chunk so assume it's done here } vorbis_synthesis_init(&codec->dec_vd, &codec->dec_vi); vorbis_block_init(&codec->dec_vd, &codec->dec_vb); // Also the first chunk needed in decoding so don't reread after this. if(codec->chunk == init_chunk - 1) { have_chunk = 1; codec->chunk++; } } // Don't already have initial chunk from header if(!have_chunk) { // Get initial chunk for decoding at new location // From vorbisfile.c /* clear out decoding machine state */ ogg_stream_clear(&codec->dec_os); vorbis_dsp_clear(&codec->dec_vd); vorbis_block_clear(&codec->dec_vb); ogg_sync_reset(&codec->dec_oy); ogg_stream_init(&codec->dec_os, ogg_page_serialno(&codec->dec_og)); ogg_sync_init(&codec->dec_oy); vorbis_synthesis_init(&codec->dec_vd, &codec->dec_vi); vorbis_block_init(&codec->dec_vd, &codec->dec_vb); READ_CHUNK(codec->chunk); codec->chunk++; have_chunk = 1; } } // Assume the chunk exists by now and rely on libogg to say if it's out of // data. have_chunk = 1; // Read chunks until output buffer is on or after end_position result = 0; while(codec->output_position < end_position) { // Read chunk to decode if it hasn't been read yet. if(!have_chunk) { codec->chunk_samples = 0; READ_CHUNK(codec->chunk); if(result) break; codec->chunk++; } eos = 0; while(!eos) { result = ogg_sync_pageout(&codec->dec_oy, &codec->dec_og); // Need more data from chunk if(result == 0) { // End of chunk eos = 1; } else // This stage checks for OggS and a checksum error. // It doesn't tell if it's the end of a chunk. Need to manually parse OggS // pages to figure out how big the chunk is. if(result < 0) { //printf("ogg_sync_pageout=-1\n"); ; } else { ogg_stream_pagein(&codec->dec_os, &codec->dec_og); while(!eos) { //printf("decode 7\n"); result = ogg_stream_packetout(&codec->dec_os, &codec->dec_op); //printf("decode 8 %d\n", result); if(result == 0) { //printf("ogg_stream_packetout=0\n"); // End of page eos = 1; } else // This stage doesn't check for OggS. if(result < 0) { //printf("ogg_stream_packetout=-1\n"); } else { float **pcm; if(vorbis_synthesis(&codec->dec_vb, &codec->dec_op) == 0) { vorbis_synthesis_blockin(&codec->dec_vd, &codec->dec_vb); } while((result = vorbis_synthesis_pcmout(&codec->dec_vd, &pcm)) > 0) { //printf("vorbis_synthesis_pcmout=%x\n", result); for(i = 0; i < track_map->channels; i++) { float *output_channel = codec->output[i]; float *input_channel = pcm[i]; int k = codec->output_end; for(j = 0; j < result; j++) { output_channel[k++] = input_channel[j]; if(k >= codec->output_allocated) k = 0; } if(i == track_map->channels - 1) codec->output_end = k; } //printf("codec->output_end = %d\n", codec->output_end); codec->output_position += result; codec->output_size += result; codec->chunk_samples += result; if(codec->output_size > codec->output_allocated) codec->output_size = codec->output_allocated; vorbis_synthesis_read(&codec->dec_vd, result); } } //printf("decode 11\n"); } // Reset end of page so it isn't interpreted as an end of chunk eos = 0; } } // Next chunk if(eos) { //printf("decode 12 got=%x\n", codec->chunk_samples); have_chunk = 0; } } // Fill silence while(codec->output_position < end_position) { for(i = 0; i < track_map->channels; i++) codec->output[i][codec->output_end] = 0; codec->output_end++; if(codec->output_end >= codec->output_allocated) codec->output_end = 0; codec->output_position++; } //printf("decode 15\n"); //printf("decode 2 codec->output_position=%lld codec->output_end=%d codec->output_size=%d\n", // codec->output_position, codec->output_end, codec->output_size); current_position = track_map->current_position; i = codec->output_end - (codec->output_position - current_position); j = 0; while(i < 0) i += codec->output_allocated; pcm = codec->output[channel]; if(output_i) { for( ; j < samples; j++) { int sample = pcm[i] * 32767; CLAMP(sample, -32768, 32767); output_i[j] = sample; i++; if(i >= codec->output_allocated) i = 0; } } else if(output_f) { for( ; j < samples; j++) { output_f[j] = pcm[i]; i++; if(i >= codec->output_allocated) i = 0; } } //printf("decode 16\n"); return 0; }
int main (int argc, char **argv) { int indexing, ch; FILE *in; ogg_sync_state oy; ogg_page og; ogg_stream_state os; indexing = 0; while ((ch = getopt(argc, argv, "io:")) != -1) { switch (ch) { case 'i': indexing = 1; break; case 'o': break; case '?': default: usage(); } } argc -= optind; argv += optind; if (argc == 0) { usage (); return 1; } in = fopen (argv[0], "rb"); if (in == NULL) { perror ("error opening input"); return -1; } /* initialise ogg_sync_state */ ogg_sync_init (&oy); /* process all the headers of the Ogg container */ while (1) { int ret = buffer_data (in, &oy); if (ret == 0) break; while (ogg_sync_pageout (&oy, &og) > 0) { ogg_packet op; int got_packet; ogg_stream_init (&os, ogg_page_serialno (&og)); ogg_stream_pagein (&os, &og); if ((got_packet = ogg_stream_packetout (&os, &op))) { } } } fclose (in); return 0; }
void test_pack(const int *pl, const int **headers){ unsigned char *data=_ogg_malloc(1024*1024); /* for scripted test cases only */ long inptr=0; long outptr=0; long deptr=0; long depacket=0; long granule_pos=7,pageno=0; int i,j,packets,pageout=0; int eosflag=0; int bosflag=0; ogg_stream_reset(&os_en); ogg_stream_reset(&os_de); ogg_sync_reset(&oy); for(packets=0;;packets++)if(pl[packets]==-1)break; for(i=0;i<packets;i++){ /* construct a test packet */ ogg_packet op; int len=pl[i]; op.packet=data+inptr; op.bytes=len; op.e_o_s=(pl[i+1]<0?1:0); op.granulepos=granule_pos; granule_pos+=1024; for(j=0;j<len;j++)data[inptr++]=i+j; /* submit the test packet */ ogg_stream_packetin(&os_en,&op); /* retrieve any finished pages */ { ogg_page og; while(ogg_stream_pageout(&os_en,&og)){ /* We have a page. Check it carefully */ fprintf(stderr,"%ld, ",pageno); if(headers[pageno]==NULL){ fprintf(stderr,"coded too many pages!\n"); exit(1); } check_page(data+outptr,headers[pageno],&og); outptr+=og.body_len; pageno++; /* have a complete page; submit it to sync/decode */ { ogg_page og_de; ogg_packet op_de,op_de2; char *buf=ogg_sync_buffer(&oy,og.header_len+og.body_len); memcpy(buf,og.header,og.header_len); memcpy(buf+og.header_len,og.body,og.body_len); ogg_sync_wrote(&oy,og.header_len+og.body_len); while(ogg_sync_pageout(&oy,&og_de)>0){ /* got a page. Happy happy. Verify that it's good. */ check_page(data+deptr,headers[pageout],&og_de); deptr+=og_de.body_len; pageout++; /* submit it to deconstitution */ ogg_stream_pagein(&os_de,&og_de); /* packets out? */ while(ogg_stream_packetpeek(&os_de,&op_de2)>0){ ogg_stream_packetpeek(&os_de,NULL); ogg_stream_packetout(&os_de,&op_de); /* just catching them all */ /* verify peek and out match */ if(memcmp(&op_de,&op_de2,sizeof(op_de))){ fprintf(stderr,"packetout != packetpeek! pos=%ld\n", depacket); exit(1); } /* verify the packet! */ /* check data */ if(memcmp(data+depacket,op_de.packet,op_de.bytes)){ fprintf(stderr,"packet data mismatch in decode! pos=%ld\n", depacket); exit(1); } /* check bos flag */ if(bosflag==0 && op_de.b_o_s==0){ fprintf(stderr,"b_o_s flag not set on packet!\n"); exit(1); } if(bosflag && op_de.b_o_s){ fprintf(stderr,"b_o_s flag incorrectly set on packet!\n"); exit(1); } bosflag=1; depacket+=op_de.bytes; /* check eos flag */ if(eosflag){ fprintf(stderr,"Multiple decoded packets with eos flag!\n"); exit(1); } if(op_de.e_o_s)eosflag=1; /* check granulepos flag */ if(op_de.granulepos!=-1){ fprintf(stderr," granule:%ld ",(long)op_de.granulepos); } } } } } } } _ogg_free(data); if(headers[pageno]!=NULL){ fprintf(stderr,"did not write last page!\n"); exit(1); } if(headers[pageout]!=NULL){ fprintf(stderr,"did not decode last page!\n"); exit(1); } if(inptr!=outptr){ fprintf(stderr,"encoded page data incomplete!\n"); exit(1); } if(inptr!=deptr){ fprintf(stderr,"decoded page data incomplete!\n"); exit(1); } if(inptr!=depacket){ fprintf(stderr,"decoded packet data incomplete!\n"); exit(1); } if(!eosflag){ fprintf(stderr,"Never got a packet with EOS set!\n"); exit(1); } fprintf(stderr,"ok.\n"); }
static int spx_decode (void *prv_data, char *sound_buf, int nbytes, struct sound_params *sound_params) { struct spx_data *data = (struct spx_data *)prv_data; int bytes_requested = nbytes; int16_t *out = (int16_t *)sound_buf; sound_params->channels = data->nchannels; sound_params->rate = data->rate; sound_params->fmt = SFMT_S16 | SFMT_NE; while (nbytes) { int j; /* First see if there is anything left in the output buffer and * empty it out */ if (data->output_left > 0) { int to_copy = nbytes / sizeof(int16_t); to_copy = MIN(data->output_left, to_copy); memcpy (out, data->output + data->output_start, to_copy * sizeof(int16_t)); out += to_copy; data->output_start += to_copy; data->output_left -= to_copy; nbytes -= to_copy * sizeof(int16_t); } else if (ogg_stream_packetout (&data->os, &data->op) == 1) { int16_t *temp_output = data->output; /* Decode some more samples */ /* Copy Ogg packet to Speex bitstream */ speex_bits_read_from (&data->bits, (char*)data->op.packet, data->op.bytes); for (j = 0; j < data->frames_per_packet; j++) { /* Decode frame */ speex_decode_int (data->st, &data->bits, temp_output); if (data->nchannels == 2) speex_decode_stereo_int (temp_output, data->frame_size, &data->stereo); speex_decoder_ctl (data->st, SPEEX_GET_BITRATE, &data->bitrate); /*data->samples_decoded += data->frame_size;*/ temp_output += data->frame_size * data->nchannels; } /*logit ("Read %d bytes from page", data->frame_size * data->nchannels * data->frames_per_packet);*/ data->output_start = 0; data->output_left = data->frame_size * data->nchannels * data->frames_per_packet; } else if (ogg_sync_pageout(&data->oy, &data->og) == 1) { /* Read in another ogg page */ ogg_stream_pagein (&data->os, &data->og); debug ("Granulepos: %"PRId64, ogg_page_granulepos(&data->og)); } else if (!io_eof(data->stream)) { /* Finally, pull in some more data and try again on the next pass */ get_more_data (data); } else break; } return bytes_requested - nbytes; }