void encode_silent_samples(int n_samples) { float **buffer; int i; /* generate a silent buffer */ buffer = vorbis_analysis_buffer(&vd, n_samples); for (i = 0; i < vi.channels; i++) memset(buffer[i], 0, n_samples * sizeof (float)); vorbis_analysis_wrote(&vd, n_samples); /* encode it */ while (vorbis_analysis_blockout(&vd, &vb) == 1) { vorbis_analysis(&vb, NULL); vorbis_bitrate_addblock(&vb); while (vorbis_bitrate_flushpacket(&vd, &op)) { ogg_stream_packetin(&os, &op); while (ogg_stream_pageout(&os, &og)) { write_out(&og); if (ogg_page_eos(&og)) break; } } } }
static int ogg_close (SF_PRIVATE *psf) { OGG_PRIVATE *odata = (OGG_PRIVATE *) psf->container_data ; VORBIS_PRIVATE *vdata = (VORBIS_PRIVATE *) psf->codec_data ; if (odata == NULL || vdata == NULL) return 0 ; /* Clean up this logical bitstream ; before exit we shuld see if we're ** followed by another [chained]. */ if (psf->file.mode == SFM_WRITE) { if (psf->write_current <= 0) ogg_write_header (psf, 0) ; vorbis_analysis_wrote (&vdata->vd, 0) ; while (vorbis_analysis_blockout (&vdata->vd, &vdata->vb) == 1) { /* analysis, assume we want to use bitrate management */ vorbis_analysis (&vdata->vb, NULL) ; vorbis_bitrate_addblock (&vdata->vb) ; while (vorbis_bitrate_flushpacket (&vdata->vd, &odata->op)) { /* weld the packet into the bitstream */ ogg_stream_packetin (&odata->os, &odata->op) ; /* write out pages (if any) */ while (!odata->eos) { int result = ogg_stream_pageout (&odata->os, &odata->og) ; if (result == 0) break ; psf_fwrite (odata->og.header, 1, odata->og.header_len, psf) ; psf_fwrite (odata->og.body, 1, odata->og.body_len, psf) ; /* this could be set above, but for illustrative purposes, I do it here (to show that vorbis does know where the stream ends) */ if (ogg_page_eos (&odata->og)) odata->eos = 1 ; } } } } /* ogg_page and ogg_packet structs always point to storage in libvorbis. They are never freed or manipulated directly */ vorbis_block_clear (&vdata->vb) ; vorbis_dsp_clear (&vdata->vd) ; vorbis_comment_clear (&vdata->vc) ; vorbis_info_clear (&vdata->vi) ; /* must be called last */ /* should look here to reopen if chained */ /* OK, clean up the framer */ ogg_sync_clear (&odata->oy) ; ogg_stream_clear (&odata->os) ; return 0 ; } /* ogg_close */
/*! * \brief Write out any pending encoded data. * \param s An OGG/Vorbis filestream. * \param f The file to write to. */ static void write_stream(struct vorbis_desc *s, FILE *f) { while (vorbis_analysis_blockout(&s->vd, &s->vb) == 1) { vorbis_analysis(&s->vb, NULL); vorbis_bitrate_addblock(&s->vb); while (vorbis_bitrate_flushpacket(&s->vd, &s->op)) { ogg_stream_packetin(&s->os, &s->op); while (!s->eos) { if (ogg_stream_pageout(&s->os, &s->og) == 0) { break; } if (!fwrite(s->og.header, 1, s->og.header_len, f)) { ast_log(LOG_WARNING, "fwrite() failed: %s\n", strerror(errno)); } if (!fwrite(s->og.body, 1, s->og.body_len, f)) { ast_log(LOG_WARNING, "fwrite() failed: %s\n", strerror(errno)); } if (ogg_page_eos(&s->og)) { s->eos = 1; } } } } }
bool VorbisWriter::write(QByteArray &left, QByteArray &right, long samples, bool flush) { const long maxChunkSize = 4096; const qint16 *leftData = (const qint16 *)left.constData(); const qint16 *rightData = stereo ? (const qint16 *)right.constData() : NULL; long todoSamples = samples; int eos = 0; while (!eos) { long chunkSize = todoSamples > maxChunkSize ? maxChunkSize : todoSamples; todoSamples -= chunkSize; if (chunkSize == 0) { if (!flush) break; hasFlushed = true; vorbis_analysis_wrote(&pd->vd, 0); } else { float **buffer = vorbis_analysis_buffer(&pd->vd, chunkSize); for (long i = 0; i < chunkSize; i++) buffer[0][i] = (float)leftData[i] / 32768.0f; leftData += chunkSize; if (stereo) { for (long i = 0; i < chunkSize; i++) buffer[1][i] = (float)rightData[i] / 32768.0f; rightData += chunkSize; } vorbis_analysis_wrote(&pd->vd, chunkSize); } while (vorbis_analysis_blockout(&pd->vd, &pd->vb) == 1) { vorbis_analysis(&pd->vb, NULL); vorbis_bitrate_addblock(&pd->vb); while (vorbis_bitrate_flushpacket(&pd->vd, &pd->op)) { ogg_stream_packetin(&pd->os, &pd->op); while (!eos && ogg_stream_pageout(&pd->os, &pd->og) != 0) { file.write((const char *)pd->og.header, pd->og.header_len); file.write((const char *)pd->og.body, pd->og.body_len); if (ogg_page_eos(&pd->og)) eos = 1; } } } } samplesWritten += samples; left.remove(0, samples * 2); if (stereo) right.remove(0, samples * 2); return true; }
void MediaRecorder::WriteAudio() { int ret; nsresult rv; PRUint32 wr; while (vorbis_analysis_blockout(&aState->vd, &aState->vb) == 1) { vorbis_analysis(&aState->vb, NULL); vorbis_bitrate_addblock(&aState->vb); while (vorbis_bitrate_flushpacket( &aState->vd, &aState->op)) { ogg_stream_packetin(&aState->os, &aState->op); for (;;) { ret = ogg_stream_pageout(&aState->os, &aState->og); if (ret == 0) break; rv = WriteData(aState->og.header, aState->og.header_len, &wr); rv = WriteData(aState->og.body, aState->og.body_len, &wr); if (ogg_page_eos(&aState->og)) break; } } } }
int lame_encode_ogg_frame ( lame_global_flags* gfp, const sample_t* inbuf_l, const sample_t* inbuf_r, unsigned char* mp3buf, size_t mp3buf_size ) { lame_internal_flags *gfc = gfp->internal_flags; int i; int eos = 0; int bytes = 0; /* expose the buffer to submit data */ double **buffer = vorbis_analysis_buffer(&vd2,gfp->framesize); /* change level of input by -90 dB (no de-interleaving!) */ for ( i = 0; i < gfp->framesize; i++ ) buffer [0] [i] = (1/32768.) * inbuf_l [i]; if ( gfc->channels_out == 2 ) for ( i = 0; i < gfp->framesize; i++ ) buffer [1] [i] = (1/32768.) * inbuf_r [i]; /* tell the library how much we actually submitted */ vorbis_analysis_wrote(&vd2,i); /* vorbis does some data preanalysis, then divvies up blocks for more involved (potentially parallel) processing. Get a single block for encoding now */ while(vorbis_analysis_blockout(&vd2,&vb2)==1){ int result; /* analysis */ vorbis_analysis(&vb2,&op2); /* weld the packet into the bitstream */ ogg_stream_packetin(&os2,&op2); /* write out pages (if any) */ do { result=ogg_stream_pageout(&os2,&og2); if (result==0) break; /* check if mp3buffer is big enough for the output */ bytes += og2.header_len + og2.body_len; /* DEBUGF("\n\n*********\ndecoded bytes=%i %i \n",bytes,mp3buf_size); */ if (bytes > mp3buf_size && mp3buf_size>0) return -6; memcpy(mp3buf,og2.header,og2.header_len); memcpy(mp3buf+og2.header_len,og2.body,og2.body_len); mp3buf += og2.header_len + og2.body_len; if(ogg_page_eos(&og2))eos=1; } while (1); } (gfp -> frameNum)++; return bytes; }
static PyObject * py_ogg_ogg_page_eos(PyObject *self, PyObject *args) { int size; int c_out; ogg_page * og; PyArg_ParseTuple(args, "s#", &og, &size); c_out = ogg_page_eos(og); return Py_BuildValue("i", c_out); };
static ChainState * validate_ogg_page (ogg_page * page) { gulong serialno; gint64 granule; ChainState *state; serialno = ogg_page_serialno (page); granule = ogg_page_granulepos (page); state = g_hash_table_lookup (eos_chain_states, GINT_TO_POINTER (serialno)); fail_if (ogg_page_packets (page) == 0 && granule != -1, "Must have granulepos -1 when page has no packets, has %" G_GINT64_FORMAT, granule); if (ogg_page_bos (page)) { fail_unless (state == NULL, "Extraneous BOS flag on chain %u", serialno); state = g_new0 (ChainState, 1); g_hash_table_insert (eos_chain_states, GINT_TO_POINTER (serialno), state); state->serialno = serialno; state->last_granule = granule; state->codec = get_page_codec (page); /* check for things like BOS ordering, etc */ switch (state->codec) { case CODEC_THEORA: /* check we have no vorbis/speex chains yet */ g_hash_table_foreach (eos_chain_states, (GHFunc) fail_if_audio, NULL); break; case CODEC_VORBIS: case CODEC_SPEEX: /* no checks (yet) */ break; case CODEC_UNKNOWN: default: break; } } else if (ogg_page_eos (page)) { fail_unless (state != NULL, "Missing BOS flag on chain %u", serialno); state->eos = TRUE; } else { fail_unless (state != NULL, "Missing BOS flag on chain %u", serialno); fail_unless (!state->eos, "Data after EOS flag on chain %u", serialno); } if (granule != -1) { fail_unless (granule >= state->last_granule, "Granulepos out-of-order for chain %u: old=%" G_GINT64_FORMAT ", new=" G_GINT64_FORMAT, serialno, state->last_granule, granule); state->last_granule = granule; } return state; }
tbool CVorbisEncoder::Finalize_Descendant() { if (miOutputSamplesTotal > 0) { // Actually done any processing? // Tell the library we're at end of stream so that it can handle // the last frame and mark end of stream in the output properly vorbis_analysis_wrote(&vd,0); while(vorbis_analysis_blockout(&vd,&vb)==1){ /* analysis, assume we want to use bitrate management */ vorbis_analysis(&vb,NULL); vorbis_bitrate_addblock(&vb); while(vorbis_bitrate_flushpacket(&vd,&op)){ /* weld the packet into the bitstream */ ogg_stream_packetin(&os,&op); /* write out pages (if any) */ tbool bEOS = false; while(!bEOS){ int result=ogg_stream_pageout(&os,&og); if(result==0)break; //fwrite(og.header,1,og.header_len,stdout); //fwrite(og.body,1,og.body_len,stdout); WriteOutput((char*)og.header, og.header_len); WriteOutput((char*)og.body, og.body_len); /* this could be set above, but for illustrative purposes, I do it here (to show that vorbis does know where the stream ends) */ if(ogg_page_eos(&og))bEOS=1; } } } /* clean up and exit. vorbis_info_clear() must be called last */ ogg_stream_clear(&os); vorbis_block_clear(&vb); vorbis_dsp_clear(&vd); vorbis_comment_clear(&vc); vorbis_info_clear(&vi); /* ogg_page and ogg_packet structs always point to storage in libvorbis. They're never freed or manipulated directly */ } tfloat fSecs = ((tfloat)miOutputSamplesTotal) / miOutputSampleFreq; tfloat fKbps = muiBytesTotalOutput * 8.0f / (fSecs * 1000); std::cout << "Done (wrote " << muiBytesTotalOutput << " bytes, " << fSecs << " secs, avg rate " << fKbps << " kbps)\n\n"; return true; }
static void close_output(void) { int eos = 0; ogg_page og; /* one Ogg bitstream page. Vorbis packets are inside */ ogg_packet op; /* one raw packet of data for decode */ if(dpm.fd < 0) return; /* end of file. this can be done implicitly in the mainline, but it's easier to see here in non-clever fashion. Tell the library we're at end of stream so that it can handle the last frame and mark end of stream in the output properly */ vorbis_analysis_wrote(&vd, 0); /* vorbis does some data preanalysis, then divvies up blocks for more involved (potentially parallel) processing. Get a single block for encoding now */ while(vorbis_analysis_blockout(&vd, &vb) == 1) { /* analysis */ vorbis_analysis(&vb, &op); /* weld the packet into the bitstream */ ogg_stream_packetin(&os, &op); /* write out pages (if any) */ while(!eos){ int result = ogg_stream_pageout(&os,&og); if(result == 0) break; write(dpm.fd, og.header, og.header_len); write(dpm.fd, og.body, og.body_len); /* this could be set above, but for illustrative purposes, I do it here (to show that vorbis does know where the stream ends) */ if(ogg_page_eos(&og)) eos = 1; } } /* clean up and exit. vorbis_info_clear() must be called last */ ogg_stream_clear(&os); vorbis_block_clear(&vb); vorbis_dsp_clear(&vd); close(dpm.fd); dpm.fd = -1; }
/*! * \brief Create a new OGG/Vorbis filestream and set it up for writing. * \param s File pointer that points to on-disk storage. * \param comment Comment that should be embedded in the OGG/Vorbis file. * \return A new filestream. */ static int ogg_vorbis_rewrite(struct ast_filestream *s, const char *comment) { ogg_packet header; ogg_packet header_comm; ogg_packet header_code; struct ogg_vorbis_desc *tmp = (struct ogg_vorbis_desc *) s->_private; tmp->writing = 1; tmp->writing_pcm_pos = 0; vorbis_info_init(&tmp->vi); if (vorbis_encode_init_vbr(&tmp->vi, 1, DEFAULT_SAMPLE_RATE, 0.4)) { ast_log(LOG_ERROR, "Unable to initialize Vorbis encoder!\n"); return -1; } vorbis_comment_init(&tmp->vc); vorbis_comment_add_tag(&tmp->vc, "ENCODER", "Asterisk PBX"); if (comment) vorbis_comment_add_tag(&tmp->vc, "COMMENT", (char *) comment); vorbis_analysis_init(&tmp->vd, &tmp->vi); vorbis_block_init(&tmp->vd, &tmp->vb); ogg_stream_init(&tmp->os, ast_random()); vorbis_analysis_headerout(&tmp->vd, &tmp->vc, &header, &header_comm, &header_code); ogg_stream_packetin(&tmp->os, &header); ogg_stream_packetin(&tmp->os, &header_comm); ogg_stream_packetin(&tmp->os, &header_code); while (!tmp->eos) { if (ogg_stream_flush(&tmp->os, &tmp->og) == 0) break; if (!fwrite(tmp->og.header, 1, tmp->og.header_len, s->f)) { ast_log(LOG_WARNING, "fwrite() failed: %s\n", strerror(errno)); } if (!fwrite(tmp->og.body, 1, tmp->og.body_len, s->f)) { ast_log(LOG_WARNING, "fwrite() failed: %s\n", strerror(errno)); } if (ogg_page_eos(&tmp->og)) tmp->eos = 1; } return 0; }
int lame_encode_ogg_finish(lame_global_flags *gfp, char *mp3buf, int mp3buf_size) { int eos=0,bytes=0; vorbis_analysis_wrote(&vd2,0); while(vorbis_analysis_blockout(&vd2,&vb2)==1){ /* analysis */ vorbis_analysis(&vb2,&op2); /* weld the packet into the bitstream */ ogg_stream_packetin(&os2,&op2); /* write out pages (if any) */ while(!eos){ int result=ogg_stream_pageout(&os2,&og2); if(result==0)break; /* check if mp3buffer is big enough for the output */ bytes += og2.header_len + og2.body_len; if (bytes > mp3buf_size && mp3buf_size>0) return -5; memcpy(mp3buf,og2.header,og2.header_len); memcpy(mp3buf+og2.header_len,og2.body,og2.body_len); /* this could be set above, but for illustrative purposes, I do it here (to show that vorbis does know where the stream ends) */ if(ogg_page_eos(&og2))eos=1; } } /* clean up and exit. vorbis_info_clear() must be called last */ ogg_stream_clear(&os2); vorbis_block_clear(&vb2); vorbis_dsp_clear(&vd2); /* ogg_page and ogg_packet structs always point to storage in libvorbis. They're never freed or manipulated directly */ return bytes; }
bool ShoutVSTEncoderOGG::Process( float **inputs, long sampleFrames ) { if (!bInitialized) return false; float **buffer=vorbis_analysis_buffer(&vd,sampleFrames); /* uninterleave samples */ for(int i=0;i<sampleFrames;i++){ buffer[0][i] = inputs[0][i]; buffer[1][i] = inputs[1][i]; } /* tell the library how much we actually submitted */ vorbis_analysis_wrote(&vd,sampleFrames); /* vorbis does some data preanalysis, then divvies up blocks for more involved (potentially parallel) processing. Get a single block for encoding now */ int eos = 0; while(vorbis_analysis_blockout(&vd,&vb)==1){ /* analysis, assume we want to use bitrate management */ vorbis_analysis(&vb,NULL); vorbis_bitrate_addblock(&vb); while(vorbis_bitrate_flushpacket(&vd,&op)){ /* weld the packet into the bitstream */ ogg_stream_packetin(&os,&op); /* write out pages (if any) */ while(!eos){ int result=ogg_stream_pageout(&os,&og); if(result==0)break; if (!SendOGGPageToICE(&og)) return false; /* this could be set above, but for illustrative purposes, I do it here (to show that vorbis does know where the stream ends) */ if(ogg_page_eos(&og))eos=1; } } } return true; }
bool VideoClip_Theora::_readData() { int audioEos = 0; int serno = 0; float audioTime = 0; float time = this->timer->getTime(); if (this->restarted) { time = 0.0f; } char* buffer = NULL; int bytesRead = 0; ogg_int64_t granule = 0; do { buffer = ogg_sync_buffer(&this->info.OggSyncState, BUFFER_SIZE); bytesRead = this->stream->read(buffer, BUFFER_SIZE); ogg_sync_wrote(&this->info.OggSyncState, bytesRead); if (bytesRead == 0) { if (!this->autoRestart) { this->endOfFile = true; log(this->name + " finished playing"); } return false; } // when we fill the stream with enough pages, it'll start spitting out packets // which contain key frames, delta frames or audio data while (ogg_sync_pageout(&this->info.OggSyncState, &this->info.OggPage) > 0) { serno = ogg_page_serialno(&this->info.OggPage); if (serno == this->info.TheoraStreamState.serialno) { ogg_stream_pagein(&this->info.TheoraStreamState, &this->info.OggPage); } if (this->audioInterface != NULL && serno == this->info.VorbisStreamState.serialno) { granule = ogg_page_granulepos(&this->info.OggPage); audioTime = (float)vorbis_granule_time(&this->info.VorbisDSPState, granule); audioEos = ogg_page_eos(&this->info.OggPage); ogg_stream_pagein(&this->info.VorbisStreamState, &this->info.OggPage); } } } while (this->audioInterface != NULL && audioEos == 0 && audioTime < time + 1.0f); return true; }
void EncoderVorbis::writePage() { /* * Vorbis streams begin with three headers; the initial header (with * most of the codec setup parameters) which is mandated by the Ogg * bitstream spec. The second header holds any comment fields. The * third header holds the bitstream codebook. We merely need to * make the headers, then pass them to libvorbis one at a time; * libvorbis handles the additional Ogg bitstream constraints */ //Write header only once after stream has been initalized int result; if (m_header_write) { while (true) { result = ogg_stream_flush(&m_oggs, &m_oggpage); if (result == 0) break; m_pCallback->write(m_oggpage.header, m_oggpage.body, m_oggpage.header_len, m_oggpage.body_len); } m_header_write = false; } while (vorbis_analysis_blockout(&m_vdsp, &m_vblock) == 1) { vorbis_analysis(&m_vblock, 0); vorbis_bitrate_addblock(&m_vblock); while (vorbis_bitrate_flushpacket(&m_vdsp, &m_oggpacket)) { // weld packet into bitstream ogg_stream_packetin(&m_oggs, &m_oggpacket); // write out pages bool eos = false; while (!eos) { int result = ogg_stream_pageout(&m_oggs, &m_oggpage); if (result == 0) break; m_pCallback->write(m_oggpage.header, m_oggpage.body, m_oggpage.header_len, m_oggpage.body_len); if (ogg_page_eos(&m_oggpage)) eos = true; } } } }
void ogg_encoder_write_blocks(guac_audio_stream* audio) { /* Get state */ ogg_encoder_state* state = (ogg_encoder_state*) audio->data; while (vorbis_analysis_blockout(&(state->vorbis_state), &(state->vorbis_block)) == 1) { /* Analyze */ vorbis_analysis(&(state->vorbis_block), NULL); vorbis_bitrate_addblock(&(state->vorbis_block)); /* Flush Ogg pages */ while (vorbis_bitrate_flushpacket(&(state->vorbis_state), &(state->ogg_packet))) { /* Weld packet into bitstream */ ogg_stream_packetin(&(state->ogg_state), &(state->ogg_packet)); /* Write out pages */ while (ogg_stream_pageout(&(state->ogg_state), &(state->ogg_page)) != 0) { /* Write packet header */ guac_audio_stream_write_encoded(audio, state->ogg_page.header, state->ogg_page.header_len); /* Write packet body */ guac_audio_stream_write_encoded(audio, state->ogg_page.body, state->ogg_page.body_len); if (ogg_page_eos(&(state->ogg_page))) break; } } } }
/*! * \brief Write out any pending encoded data. * \param s An OGG/Vorbis filestream. * \param f The file to write to. */ static void write_stream(struct vorbis_desc *s, FILE *f) { while (vorbis_analysis_blockout(&s->vd, &s->vb) == 1) { vorbis_analysis(&s->vb, NULL); vorbis_bitrate_addblock(&s->vb); while (vorbis_bitrate_flushpacket(&s->vd, &s->op)) { ogg_stream_packetin(&s->os, &s->op); while (!s->eos) { if (ogg_stream_pageout(&s->os, &s->og) == 0) { break; } fwrite(s->og.header, 1, s->og.header_len, f); fwrite(s->og.body, 1, s->og.body_len, f); if (ogg_page_eos(&s->og)) { s->eos = 1; } } } } }
int oggWrite(EncInfo* encInfo,int close) { int total = 0; #ifdef DEBUG fprintf(file,"oggwrite\n"); #endif /* vorbis does some data preanalysis, then divvies up blocks for more involved (potentially parallel) processing. Get a single block for encoding now */ while(vorbis_analysis_blockout(&encInfo->vd,&encInfo->vb)==1){ /* analysis */ vorbis_analysis(&encInfo->vb,NULL); vorbis_bitrate_addblock(&encInfo->vb); while(vorbis_bitrate_flushpacket(&encInfo->vd,&encInfo->op)){ /* weld the packet into the bitstream */ ogg_stream_packetin(&encInfo->os,&encInfo->op); /* write out pages (if any) */ while(!ogg_page_eos(&encInfo->og)){ int result; #ifdef DEBUG fprintf(file,"Write a page\n"); #endif result=ogg_stream_pageout(&encInfo->os,&encInfo->og); if(result==0)break; result = mmioWrite(encInfo->hmmioSS, encInfo->og.header,encInfo->og.header_len); total += result; if (result!=encInfo->og.header_len) return -1; result = mmioWrite(encInfo->hmmioSS, encInfo->og.body,encInfo->og.body_len); total += result; if (result!=encInfo->og.body_len) return -1; } } } #ifdef DEBUG fprintf(file,"Wrote %d\n",total); #endif return total; }
static int vorbis_write(SWORD *pbuf, size_t nr) { float **buffer; size_t i; size_t amount = (stereo) ? nr / 2 : nr; int result; int eos = 0; buffer = vorbis_analysis_buffer(&vd, (int)amount); for (i = 0; i < amount; i++) { if (stereo == 1) { buffer[0][i]= pbuf[i * 2] / 32768.f; buffer[1][i]= pbuf[(i * 2) + 1] / 32768.f; } else { buffer[0][i]= pbuf[i] / 32768.f; } } vorbis_analysis_wrote(&vd, (int)i); while (vorbis_analysis_blockout(&vd, &vb) == 1) { vorbis_analysis(&vb, NULL); vorbis_bitrate_addblock(&vb); while (vorbis_bitrate_flushpacket(&vd, &op)) { ogg_stream_packetin(&os, &op); while(!eos) { result = ogg_stream_pageout(&os, &og); if (!result) { break; } fwrite(og.header, 1, (size_t)(og.header_len), vorbis_fd); fwrite(og.body, 1, (size_t)(og.body_len), vorbis_fd); if (ogg_page_eos(&og)) { eos = 1; } } } } return 0; }
static void ogg_write_samples (SF_PRIVATE *psf, OGG_PRIVATE *odata, VORBIS_PRIVATE *vdata, int in_frames) { vorbis_analysis_wrote (&vdata->vd, in_frames) ; /* ** Vorbis does some data preanalysis, then divvies up blocks for ** more involved (potentially parallel) processing. Get a single ** block for encoding now. */ while (vorbis_analysis_blockout (&vdata->vd, &vdata->vb) == 1) { /* analysis, assume we want to use bitrate management */ vorbis_analysis (&vdata->vb, NULL) ; vorbis_bitrate_addblock (&vdata->vb) ; while (vorbis_bitrate_flushpacket (&vdata->vd, &odata->op)) { /* weld the packet into the bitstream */ ogg_stream_packetin (&odata->os, &odata->op) ; /* write out pages (if any) */ while (!odata->eos) { int result = ogg_stream_pageout (&odata->os, &odata->og) ; if (result == 0) break ; psf_fwrite (odata->og.header, 1, odata->og.header_len, psf) ; psf_fwrite (odata->og.body, 1, odata->og.body_len, psf) ; /* This could be set above, but for illustrative purposes, I do ** it here (to show that vorbis does know where the stream ends) */ if (ogg_page_eos (&odata->og)) odata->eos = 1 ; } ; } ; } ; vdata->loc += in_frames ; } /* ogg_write_data */
bool Finish(void *ctx) { ogg_context *context = (ogg_context *)ctx; if (!context || !context->callbacks.write) return false; int eos = 0; // tell vorbis we are encoding the end of the stream vorbis_analysis_wrote(&context->vorbisDspState, 0); while (vorbis_analysis_blockout(&context->vorbisDspState, &context->vorbisBlock) == 1) { /* analysis, assume we want to use bitrate management */ vorbis_analysis(&context->vorbisBlock, NULL); vorbis_bitrate_addblock(&context->vorbisBlock); ogg_packet packet; ogg_page page; while (vorbis_bitrate_flushpacket(&context->vorbisDspState, &packet)) { /* weld the packet into the bitstream */ ogg_stream_packetin(&context->oggStreamState, &packet); /* write out pages (if any) */ while (!eos) { int result = ogg_stream_pageout(&context->oggStreamState, &page); if (result == 0) break; context->callbacks.write(context->callbacks.opaque, page.header, page.header_len); context->callbacks.write(context->callbacks.opaque, page.body, page.body_len); /* this could be set above, but for illustrative purposes, I do it here (to show that vorbis does know where the stream ends) */ if (ogg_page_eos(&page)) eos = 1; } } } return true; }
int main(){ ogg_stream_state os; /* take physical pages, weld into a logical stream of packets */ ogg_page og; /* one Ogg bitstream page. Vorbis packets are inside */ ogg_packet op; /* one raw packet of data for decode */ vorbis_info vi; /* struct that stores all the static vorbis bitstream settings */ vorbis_comment vc; /* struct that stores all the user comments */ vorbis_dsp_state vd; /* central working state for the packet->PCM decoder */ vorbis_block vb; /* local working space for packet->PCM decode */ int eos=0,ret; int i, founddata; #if defined(macintosh) && defined(__MWERKS__) int argc = 0; char **argv = NULL; argc = ccommand(&argv); /* get a "command line" from the Mac user */ /* this also lets the user set stdin and stdout */ #endif /* we cheat on the WAV header; we just bypass 44 bytes and never verify that it matches 16bit/stereo/44.1kHz. This is just an example, after all. */ #ifdef _WIN32 /* We need to set stdin/stdout to binary mode. Damn windows. */ /* if we were reading/writing a file, it would also need to in binary mode, eg, fopen("file.wav","wb"); */ /* 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 /* we cheat on the WAV header; we just bypass the header and never verify that it matches 16bit/stereo/44.1kHz. This is just an example, after all. */ readbuffer[0] = '\0'; for (i=0, founddata=0; i<30 && ! feof(stdin) && ! ferror(stdin); i++) { fread(readbuffer,1,2,stdin); if ( ! strncmp((char*)readbuffer, "da", 2) ) { founddata = 1; fread(readbuffer,1,6,stdin); break; } } /********** Encode setup ************/ vorbis_info_init(&vi); /* choose an encoding mode. A few possibilities commented out, one actually used: */ /********************************************************************* Encoding using a VBR quality mode. The usable range is -.1 (lowest quality, smallest file) to 1. (highest quality, largest file). Example quality mode .4: 44kHz stereo coupled, roughly 128kbps VBR ret = vorbis_encode_init_vbr(&vi,2,44100,.4); --------------------------------------------------------------------- Encoding using an average bitrate mode (ABR). example: 44kHz stereo coupled, average 128kbps VBR ret = vorbis_encode_init(&vi,2,44100,-1,128000,-1); --------------------------------------------------------------------- Encode using a quality mode, but select that quality mode by asking for an approximate bitrate. This is not ABR, it is true VBR, but selected using the bitrate interface, and then turning bitrate management off: ret = ( vorbis_encode_setup_managed(&vi,2,44100,-1,128000,-1) || vorbis_encode_ctl(&vi,OV_ECTL_RATEMANAGE2_SET,NULL) || vorbis_encode_setup_init(&vi)); *********************************************************************/ ret=vorbis_encode_init_vbr(&vi,2,44100,0.1); /* do not continue if setup failed; this can happen if we ask for a mode that libVorbis does not support (eg, too low a bitrate, etc, will return 'OV_EIMPL') */ if(ret)exit(1); /* add a comment */ vorbis_comment_init(&vc); vorbis_comment_add_tag(&vc,"ENCODER","encoder_example.c"); /* set up the analysis state and auxiliary encoding storage */ vorbis_analysis_init(&vd,&vi); vorbis_block_init(&vd,&vb); /* set up our packet->stream encoder */ /* pick a random serial number; that way we can more likely build chained streams just by concatenation */ srand(time(NULL)); ogg_stream_init(&os,rand()); /* Vorbis streams begin with three headers; the initial header (with most of the codec setup parameters) which is mandated by the Ogg bitstream spec. The second header holds any comment fields. The third header holds the bitstream codebook. We merely need to make the headers, then pass them to libvorbis one at a time; libvorbis handles the additional Ogg bitstream constraints */ { ogg_packet header; ogg_packet header_comm; ogg_packet header_code; vorbis_analysis_headerout(&vd,&vc,&header,&header_comm,&header_code); ogg_stream_packetin(&os,&header); /* automatically placed in its own page */ ogg_stream_packetin(&os,&header_comm); ogg_stream_packetin(&os,&header_code); /* This ensures the actual * audio data will start on a new page, as per spec */ while(!eos){ int result=ogg_stream_flush(&os,&og); if(result==0)break; fwrite(og.header,1,og.header_len,stdout); fwrite(og.body,1,og.body_len,stdout); } } while(!eos){ long i; long bytes=fread(readbuffer,1,READ*4,stdin); /* stereo hardwired here */ if(bytes==0){ /* end of file. this can be done implicitly in the mainline, but it's easier to see here in non-clever fashion. Tell the library we're at end of stream so that it can handle the last frame and mark end of stream in the output properly */ vorbis_analysis_wrote(&vd,0); }else{ /* data to encode */ /* expose the buffer to submit data */ float **buffer=vorbis_analysis_buffer(&vd,READ); /* uninterleave samples */ for(i=0;i<bytes/4;i++){ buffer[0][i]=((readbuffer[i*4+1]<<8)| (0x00ff&(int)readbuffer[i*4]))/32768.f; buffer[1][i]=((readbuffer[i*4+3]<<8)| (0x00ff&(int)readbuffer[i*4+2]))/32768.f; } /* tell the library how much we actually submitted */ vorbis_analysis_wrote(&vd,i); } /* vorbis does some data preanalysis, then divvies up blocks for more involved (potentially parallel) processing. Get a single block for encoding now */ while(vorbis_analysis_blockout(&vd,&vb)==1){ /* analysis, assume we want to use bitrate management */ vorbis_analysis(&vb,NULL); vorbis_bitrate_addblock(&vb); while(vorbis_bitrate_flushpacket(&vd,&op)){ /* weld the packet into the bitstream */ ogg_stream_packetin(&os,&op); /* write out pages (if any) */ while(!eos){ int result=ogg_stream_pageout(&os,&og); if(result==0)break; fwrite(og.header,1,og.header_len,stdout); fwrite(og.body,1,og.body_len,stdout); /* this could be set above, but for illustrative purposes, I do it here (to show that vorbis does know where the stream ends) */ if(ogg_page_eos(&og))eos=1; } } } } /* clean up and exit. vorbis_info_clear() must be called last */ ogg_stream_clear(&os); vorbis_block_clear(&vb); vorbis_dsp_clear(&vd); vorbis_comment_clear(&vc); vorbis_info_clear(&vi); /* ogg_page and ogg_packet structs always point to storage in libvorbis. They're never freed or manipulated directly */ fprintf(stderr,"Done.\n"); return(0); }
int main(){ ogg_sync_state oy; /* sync and verify incoming physical bitstream */ ogg_stream_state os; /* take physical pages, weld into a logical stream of packets */ ogg_page og; /* one Ogg bitstream page. Vorbis packets are inside */ ogg_packet op; /* one raw packet of data for decode */ vorbis_info vi; /* struct that stores all the static vorbis bitstream settings */ vorbis_comment vc; /* struct that stores all the bitstream user comments */ vorbis_dsp_state vd; /* central working state for the packet->PCM decoder */ vorbis_block vb; /* local working space for packet->PCM decode */ char *buffer; int bytes; FILE *instream; FILE *outstream; char *inname = "01.ogg"; char *outname = "esmith2000-09-28d1t15.raw"; //#ifdef _WIN32 /* We need to set stdin/stdout to binary mode. Damn 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 #if defined(macintosh) && defined(__MWERKS__) { int argc; char **argv; argc=ccommand(&argv); /* get a "command line" from the Mac user */ /* this also lets the user set stdin and stdout */ } #endif /********** Decode setup ************/ //opening the file if( fopen_s( &instream, inname, "rb" ) != 0 ) { fprintf(stderr,"Can not open file %s\n", inname); exit(1); }; if( fopen_s( &outstream, outname, "wb" ) != 0 ) { fprintf(stderr,"Can not open file %s\n", outname); exit(1); } ogg_sync_init(&oy); /* Now we can read pages */ while(1){ /* we repeat if the bitstream is chained */ int eos=0; int i; /* grab some data at the head of the stream. We want the first page (which is guaranteed to be small and only contain the Vorbis stream initial header) We need the first page to get the stream serialno. */ /* submit a 4k block to libvorbis' Ogg layer */ buffer=ogg_sync_buffer(&oy,4096); //bytes=fread(buffer,1,4096,stdin); bytes=fread(buffer,1,4096,instream); ogg_sync_wrote(&oy,bytes); /* Get the first page. */ if(ogg_sync_pageout(&oy,&og)!=1){ /* have we simply run out of data? If so, we're done. */ if(bytes<4096)break; /* error case. Must not be Vorbis data */ fprintf(stderr,"Input does not appear to be an Ogg bitstream.\n"); exit(1); } /* Get the serial number and set up the rest of decode. */ /* serialno first; use it to set up a logical stream */ ogg_stream_init(&os,ogg_page_serialno(&og)); /* 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. */ vorbis_info_init(&vi); vorbis_comment_init(&vc); if(ogg_stream_pagein(&os,&og)<0){ /* error; stream version mismatch perhaps */ fprintf(stderr,"Error reading first page of Ogg bitstream data.\n"); exit(1); } if(ogg_stream_packetout(&os,&op)!=1){ /* no page? must not be vorbis */ fprintf(stderr,"Error reading initial header packet.\n"); exit(1); } if(vorbis_synthesis_headerin(&vi,&vc,&op)<0){ /* error case; not a vorbis header */ fprintf(stderr,"This Ogg bitstream does not contain Vorbis " "audio data.\n"); exit(1); } /* 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 read and submit data until we get our two packets, 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(&oy,&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(&os,&og); /* we can ignore any errors here as they'll also become apparent at packetout */ while(i<2){ result=ogg_stream_packetout(&os,&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. */ fprintf(stderr,"Corrupt secondary header. Exiting.\n"); exit(1); } result=vorbis_synthesis_headerin(&vi,&vc,&op); if(result<0){ fprintf(stderr,"Corrupt secondary header. Exiting.\n"); exit(1); } i++; } } } /* no harm in not checking before adding more */ buffer=ogg_sync_buffer(&oy,4096); //bytes=fread(buffer,1,4096,stdin); bytes=fread(buffer,1,4096,instream); if(bytes==0 && i<2){ fprintf(stderr,"End of file before finding all Vorbis headers!\n"); exit(1); } ogg_sync_wrote(&oy,bytes); } /* Throw the comments plus a few lines about the bitstream we're decoding */ { char **ptr=vc.user_comments; while(*ptr){ fprintf(stderr,"%s\n",*ptr); ++ptr; } fprintf(stderr,"\nBitstream is %d channel, %ldHz\n",vi.channels,vi.rate); fprintf(stderr,"Encoded by: %s\n\n",vc.vendor); } convsize=4096/vi.channels; /* OK, got and parsed all three headers. Initialize the Vorbis packet->PCM decoder. */ if(vorbis_synthesis_init(&vd,&vi)==0){ /* central decode state */ vorbis_block_init(&vd,&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 */ /* The rest is just a straight decode loop until end of stream */ while(!eos){ while(!eos){ int result=ogg_sync_pageout(&oy,&og); if(result==0)break; /* need more data */ if(result<0){ /* missing or corrupt data at this page position */ fprintf(stderr,"Corrupt or missing data in bitstream; " "continuing...\n"); }else{ ogg_stream_pagein(&os,&og); /* can safely ignore errors at this point */ while(1){ result=ogg_stream_packetout(&os,&op); if(result==0)break; /* need more data */ if(result<0){ /* missing or corrupt data at this page position */ /* no reason to complain; already complained above */ }else{ /* we have a packet. Decode it */ float **pcm; int samples; if(vorbis_synthesis(&vb,&op)==0) /* test for success! */ vorbis_synthesis_blockin(&vd,&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(&vd,&pcm))>0){ int j; int clipflag=0; int bout=(samples<convsize?samples:convsize); /* convert floats to 16 bit signed ints (host order) and interleave */ 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=floor(mono[j]*32767.f+.5f); #else /* optional dither */ int 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+=vi.channels; } } if(clipflag) fprintf(stderr,"Clipping in frame %ld\n",(long)(vd.sequence)); //fwrite(convbuffer,2*vi.channels,bout,stdout); fwrite(convbuffer,2*vi.channels,bout,outstream); vorbis_synthesis_read(&vd,bout); /* tell libvorbis how many samples we actually consumed */ } } } if(ogg_page_eos(&og))eos=1; } } if(!eos){ buffer=ogg_sync_buffer(&oy,4096); //bytes=fread(buffer,1,4096,stdin); bytes=fread(buffer,1,4096,instream); ogg_sync_wrote(&oy,bytes); if(bytes==0)eos=1; } } /* ogg_page and ogg_packet structs always point to storage in libvorbis. They're never freed or manipulated directly */ vorbis_block_clear(&vb); vorbis_dsp_clear(&vd); }else{ fprintf(stderr,"Error: Corrupt header during playback initialization.\n"); } /* clean up this logical bitstream; before exit we see if we're followed by another [chained] */ ogg_stream_clear(&os); vorbis_comment_clear(&vc); vorbis_info_clear(&vi); /* must be called last */ } /* OK, clean up the framer */ ogg_sync_clear(&oy); fprintf(stderr,"Done.\n"); return(0); }
static stream_processor * find_stream_processor (stream_set *set, ogg_page *page) { uint32_t serial = ogg_page_serialno (page) ; int i, invalid = 0 ; stream_processor *stream ; for (i = 0 ; i < set->used ; i++) { if (serial == set->streams [i].serial) { /* We have a match! */ stream = & (set->streams [i]) ; set->in_headers = 0 ; /* if we have detected EOS, then this can't occur here. */ if (stream->end) { stream->isillegal = 1 ; return stream ; } stream->isnew = 0 ; stream->end = ogg_page_eos (page) ; stream->serial = serial ; return stream ; } ; } ; /* If there are streams open, and we've reached the end of the ** headers, then we can't be starting a new stream. ** XXX: might this sometimes catch ok streams if EOS flag is missing, ** but the stream is otherwise ok? */ if (streams_open (set) && !set->in_headers) invalid = 1 ; set->in_headers = 1 ; if (set->allocated < set->used) stream = &set->streams [set->used] ; else { set->allocated += 5 ; set->streams = realloc (set->streams, sizeof (stream_processor) * set->allocated) ; stream = &set->streams [set->used] ; } ; set->used++ ; stream->isnew = 1 ; stream->isillegal = invalid ; { int res ; ogg_packet packet ; /* We end up processing the header page twice, but that's ok. */ ogg_stream_init (&stream->ostream, serial) ; ogg_stream_pagein (&stream->ostream, page) ; res = ogg_stream_packetout (&stream->ostream, &packet) ; if (res <= 0) return NULL ; else if (packet.bytes >= 7 && memcmp (packet.packet, "\x01vorbis", 7) == 0) { stream->lastgranulepos = 0 ; vorbis_comment_init (&stream->vcomment) ; vorbis_info_init (&stream->vinfo) ; } ; res = ogg_stream_packetout (&stream->ostream, &packet) ; /* re-init, ready for processing */ ogg_stream_clear (&stream->ostream) ; ogg_stream_init (&stream->ostream, serial) ; } stream->end = ogg_page_eos (page) ; stream->serial = serial ; return stream ; } /* find_stream_processor */
static sf_count_t vorbis_read_sample (SF_PRIVATE *psf, void *ptr, sf_count_t lens, convert_func *transfn) { VORBIS_PRIVATE *vdata = psf->codec_data ; OGG_PRIVATE *odata = psf->container_data ; int len, samples, i = 0 ; float **pcm ; len = lens / psf->sf.channels ; while ((samples = vorbis_synthesis_pcmout (&vdata->vdsp, &pcm)) > 0) { if (samples > len) samples = len ; i += transfn (psf, samples, ptr, i, psf->sf.channels, pcm) ; len -= samples ; /* tell libvorbis how many samples we actually consumed */ vorbis_synthesis_read (&vdata->vdsp, samples) ; vdata->loc += samples ; if (len == 0) return i ; /* Is this necessary */ } goto start0 ; /* Jump into the nasty nest */ while (len > 0 && !odata->eos) { while (len > 0 && !odata->eos) { int result = ogg_sync_pageout (&odata->osync, &odata->opage) ; if (result == 0) break ; /* need more data */ if (result < 0) { /* missing or corrupt data at this page position */ psf_log_printf (psf, "Corrupt or missing data in bitstream ; continuing...\n") ; } else { /* can safely ignore errors at this point */ ogg_stream_pagein (&odata->ostream, &odata->opage) ; start0: while (1) { result = ogg_stream_packetout (&odata->ostream, &odata->opacket) ; if (result == 0) break ; /* need more data */ if (result < 0) { /* missing or corrupt data at this page position */ /* no reason to complain ; already complained above */ } else { /* we have a packet. Decode it */ if (vorbis_synthesis (&vdata->vblock, &odata->opacket) == 0) /* test for success! */ vorbis_synthesis_blockin (&vdata->vdsp, &vdata->vblock) ; /* ** 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 (&vdata->vdsp, &pcm)) > 0) { if (samples > len) samples = len ; i += transfn (psf, samples, ptr, i, psf->sf.channels, pcm) ; len -= samples ; /* tell libvorbis how many samples we actually consumed */ vorbis_synthesis_read (&vdata->vdsp, samples) ; vdata->loc += samples ; if (len == 0) return i ; /* Is this necessary */ } ; } } if (ogg_page_eos (&odata->opage)) odata->eos = 1 ; } } if (!odata->eos) { char *buffer ; int bytes ; buffer = ogg_sync_buffer (&odata->osync, 4096) ; bytes = psf_fread (buffer, 1, 4096, psf) ; ogg_sync_wrote (&odata->osync, bytes) ; if (bytes == 0) odata->eos = 1 ; } } return i ; } /* vorbis_read_sample */
int ogg_stream_pagein(ogg_stream_state *os, ogg_page *og){ unsigned char *header=og->header; unsigned char *body=og->body; long bodysize=og->body_len; int segptr=0; int version=ogg_page_version(og); int continued=ogg_page_continued(og); int bos=ogg_page_bos(og); int eos=ogg_page_eos(og); ogg_int64_t granulepos=ogg_page_granulepos(og); int serialno=ogg_page_serialno(og); long pageno=ogg_page_pageno(og); int segments=header[26]; /* clean up 'returned data' */ { long lr=os->lacing_returned; long br=os->body_returned; /* body data */ if(br){ os->body_fill-=br; if(os->body_fill) memmove(os->body_data,os->body_data+br,os->body_fill); os->body_returned=0; } if(lr){ /* segment table */ if(os->lacing_fill-lr){ memmove(os->lacing_vals,os->lacing_vals+lr, (os->lacing_fill-lr)*sizeof(*os->lacing_vals)); memmove(os->granule_vals,os->granule_vals+lr, (os->lacing_fill-lr)*sizeof(*os->granule_vals)); } os->lacing_fill-=lr; os->lacing_packet-=lr; os->lacing_returned=0; } } /* check the serial number */ if(serialno!=os->serialno)return(-1); if(version>0)return(-1); _os_lacing_expand(os,segments+1); /* are we in sequence? */ if(pageno!=os->pageno){ int i; /* unroll previous partial packet (if any) */ for(i=os->lacing_packet;i<os->lacing_fill;i++) os->body_fill-=os->lacing_vals[i]&0xff; os->lacing_fill=os->lacing_packet; /* make a note of dropped data in segment table */ if(os->pageno!=-1){ os->lacing_vals[os->lacing_fill++]=0x400; os->lacing_packet++; } /* are we a 'continued packet' page? If so, we'll need to skip some segments */ if(continued){ bos=0; for(;segptr<segments;segptr++){ int val=header[27+segptr]; body+=val; bodysize-=val; if(val<255){ segptr++; break; } } } } if(bodysize){ _os_body_expand(os,bodysize); memcpy(os->body_data+os->body_fill,body,bodysize); os->body_fill+=bodysize; } { int saved=-1; while(segptr<segments){ int val=header[27+segptr]; os->lacing_vals[os->lacing_fill]=val; os->granule_vals[os->lacing_fill]=-1; if(bos){ os->lacing_vals[os->lacing_fill]|=0x100; bos=0; } if(val<255)saved=os->lacing_fill; os->lacing_fill++; segptr++; if(val<255)os->lacing_packet=os->lacing_fill; } /* set the granulepos on the last granuleval of the last full packet */ if(saved!=-1){ os->granule_vals[saved]=granulepos; } } if(eos){ os->e_o_s=1; if(os->lacing_fill>0) os->lacing_vals[os->lacing_fill-1]|=0x200; } os->pageno=pageno+1; return(0); }
int oe_encode ( oe_enc_opt* opt ) { ogg_stream_state os; ogg_page og; ogg_packet op; vorbis_dsp_state vd; vorbis_block vb; vorbis_info vi; long samplesdone = 0; int eos; long bytes_written = 0; long packetsdone = 0; int ret = 0; vorbis_info_init ( &vi ); if ( opt->quality >= 0.0f ) { if ( vorbis_encode_init_vbr ( &vi, opt->channels, opt->rate, opt->quality ) ) { vorbis_info_clear ( &vi ); return 1; } } else { if ( vorbis_encode_init ( &vi, opt->channels, opt->rate, opt->max_bitrate > 0 ? opt->max_bitrate * 1000 : -1, opt->bitrate * 1000, opt->min_bitrate > 0 ? opt->min_bitrate * 1000 : -1 ) ) { vorbis_info_clear ( &vi ); return 1; } } vorbis_analysis_init ( &vd, &vi ); vorbis_block_init ( &vd, &vb ); ogg_stream_init ( &os, opt->serialno ); ogg_packet header_main; ogg_packet header_comments; ogg_packet header_codebooks; int result; vorbis_analysis_headerout ( &vd,opt->comments, &header_main, &header_comments, &header_codebooks ); ogg_stream_packetin ( &os, &header_main ); ogg_stream_packetin ( &os, &header_comments ); ogg_stream_packetin ( &os, &header_codebooks ); while ( ( result = ogg_stream_flush ( &os, &og ) ) ) { if ( !result ) break; ret = oe_write_page ( &og, opt->out ); if ( ret != og.header_len + og.body_len ) { ret = 1; goto cleanup; } else bytes_written += ret; } eos = 0; while ( !eos ) { float** buffer = vorbis_analysis_buffer ( &vd, READSIZE ); long samples_read = opt->read_samples ( opt->readdata, buffer, READSIZE ); if ( samples_read == 0 ) vorbis_analysis_wrote ( &vd, 0 ); else { samplesdone += samples_read; vorbis_analysis_wrote ( &vd, samples_read ); } while ( vorbis_analysis_blockout ( &vd, &vb ) == 1 ) { vorbis_analysis ( &vb, NULL ); vorbis_bitrate_addblock ( &vb ); while ( vorbis_bitrate_flushpacket ( &vd, &op ) ) { ogg_stream_packetin ( &os,&op ); packetsdone++; while ( !eos ) { int result = ogg_stream_pageout ( &os, &og ); if ( !result ) break; ret = oe_write_page ( &og, opt->out ); if ( ret != og.header_len + og.body_len ) { ret = 1; goto cleanup; } else bytes_written += ret; if ( ogg_page_eos ( &og ) ) eos = 1; } } } } ret = 0; cleanup: ogg_stream_clear ( &os ); vorbis_block_clear ( &vb ); vorbis_dsp_clear ( &vd ); vorbis_info_clear ( &vi ); return ret; }
/* For lame_decode_fromfile: return code -1 error, or eof 0 ok, but need more data before outputing any samples n number of samples output. */ int lame_decode_ogg_fromfile( lame_global_flags* gfp, FILE* fd, short int pcm_l[], short int pcm_r[], mp3data_struct* mp3data ) { lame_internal_flags *gfc = gfp->internal_flags; int samples,result,i,j,eof=0,eos=0,bout=0; double **pcm; while(1){ /* **pcm is a multichannel double 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 */ /* unpack the buffer, if it has at least 1024 samples */ convsize=1024; samples=vorbis_synthesis_pcmout(&vd,&pcm); if (samples >= convsize || eos || eof) { /* read 1024 samples, or if eos, read what ever is in buffer */ int clipflag=0; bout=(samples<convsize?samples:convsize); /* convert doubles to 16 bit signed ints (host order) and interleave */ for(i=0;i<vi.channels;i++){ double *mono=pcm[i]; for(j=0;j<bout;j++){ int val=mono[j]*32767.; /* might as well guard against clipping */ if(val>32767){ val=32767; clipflag=1; } if(val<-32768){ val=-32768; clipflag=1; } if (i==0) pcm_l[j]=val; if (i==1) pcm_r[j]=val; } } /* if(clipflag) MSGF( gfc, "Clipping in frame %ld\n", vd.sequence ); */ /* tell libvorbis how many samples we actually consumed */ vorbis_synthesis_read(&vd,bout); break; } result=ogg_sync_pageout(&oy,&og); if(result==0) { /* need more data */ }else if (result==-1){ /* missing or corrupt data at this page position */ ERRORF( gfc, "Corrupt or missing data in bitstream; " "continuing...\n"); }else{ /* decode this page */ ogg_stream_pagein(&os,&og); /* can safely ignore errors at this point */ do { result=ogg_stream_packetout(&os,&op); if(result==0) { /* need more data */ } else if(result==-1){ /* missing or corrupt data at this page position */ /* no reason to complain; already complained above */ }else{ /* we have a packet. Decode it */ vorbis_synthesis(&vb,&op); vorbis_synthesis_blockin(&vd,&vb); } } while (result!=0); } /* is this the last page? */ if(ogg_page_eos(&og))eos=1; if(!eos){ char *buffer; int bytes; buffer=ogg_sync_buffer(&oy,4096); bytes=fread(buffer,1,4096,fd); ogg_sync_wrote(&oy,bytes); if(bytes==0)eof=1; } } mp3data->stereo = vi.channels; mp3data->samplerate = vi.rate; mp3data->bitrate = 0; //ov_bitrate_instant(&vf); /* mp3data->nsamp=MAX_U_32_NUM;*/ if (bout==0) { /* clean up this logical bitstream; before exit we see if we're followed by another [chained] */ ogg_stream_clear(&os); /* ogg_page and ogg_packet structs always point to storage in libvorbis. They're never freed or manipulated directly */ vorbis_block_clear(&vb); vorbis_dsp_clear(&vd); vorbis_info_clear(&vi); /* must be called last */ /* OK, clean up the framer */ ogg_sync_clear(&oy); return -1; } return bout; }
/** ** Load vorbis. ** ** @param name File name. ** @param flags Load flags. ** ** @return Returns the loaded sample. */ CSample *LoadVorbis(const std::string &name, int flags) { CSample *sample; OggData *data; CFile *f; vorbis_info *info; f = new CFile; if (f->open(name.c_str(), CL_OPEN_READ) == -1) { fprintf(stderr, "Can't open file `%s'\n", name.c_str()); delete f; return NULL; } if (flags & PlayAudioStream) { sample = new CSampleVorbisStream; data = &((CSampleVorbisStream *)sample)->Data; } else { sample = new CSampleVorbis; data = &((CSampleVorbis *)sample)->Data; } memset(data, 0, sizeof(*data)); if (OggInit(f, data) || !data->audio) { delete sample; f->close(); delete f; return NULL; } info = &data->vinfo; sample->Channels = info->channels; sample->SampleSize = 16; sample->Frequency = info->rate; sample->Len = 0; sample->Pos = 0; data->File = f; if (flags & PlayAudioStream) { sample->Buffer = new unsigned char[SOUND_BUFFER_SIZE]; } else { unsigned char *buf; int pos; int ret; int total; ogg_page pg; ogg_sync_state sync; int i; // find total size pos = f->tell(); ogg_sync_init(&sync); for (i = 0; ; ++i) { f->seek(-1 * i * 4096, SEEK_END); buf = (unsigned char *)ogg_sync_buffer(&sync, 4096); f->read(buf, 8192); ogg_sync_wrote(&sync, 8192); if (ogg_sync_pageout(&sync, &pg) == 1 && ogg_page_eos(&pg)) { total = (int)(ogg_page_granulepos(&pg) * 2 * sample->Channels); break; } } f->seek(pos, SEEK_SET); sample->Buffer = new unsigned char[total]; pos = 0; while ((ret = VorbisStreamRead(sample, &((CSampleVorbis *)sample)->Data, sample->Buffer + pos, 8192))) { pos += ret; } sample->Len = total; sample->Pos = 0; f->close(); delete f; OggFree(data); } return sample; }
S32 encode_vorbis_file(const std::string& in_fname, const std::string& out_fname) { #define READ_BUFFER 1024 unsigned char readbuffer[READ_BUFFER*4+44]; /* out of the data segment, not the stack */ /*Flawfinder: ignore*/ ogg_stream_state os; /* take physical pages, weld into a logical stream of packets */ ogg_page og; /* one Ogg bitstream page. Vorbis packets are inside */ ogg_packet op; /* one raw packet of data for decode */ vorbis_info vi; /* struct that stores all the static vorbis bitstream settings */ vorbis_comment vc; /* struct that stores all the user comments */ vorbis_dsp_state vd; /* central working state for the packet->PCM decoder */ vorbis_block vb; /* local working space for packet->PCM decode */ int eos=0; int result; U16 num_channels = 0; U32 sample_rate = 0; U32 bits_per_sample = 0; S32 format_error = 0; std::string error_msg; if ((format_error = check_for_invalid_wav_formats(in_fname, error_msg))) { llwarns << error_msg << ": " << in_fname << llendl; return(format_error); } #if 1 unsigned char wav_header[44]; /*Flawfinder: ignore*/ S32 data_left = 0; LLAPRFile infile ; infile.open(in_fname,LL_APR_RB); if (!infile.getFileHandle()) { llwarns << "Couldn't open temporary ogg file for writing: " << in_fname << llendl; return(LLVORBISENC_SOURCE_OPEN_ERR); } LLAPRFile outfile ; outfile.open(out_fname,LL_APR_WPB); if (!outfile.getFileHandle()) { llwarns << "Couldn't open upload sound file for reading: " << in_fname << llendl; return(LLVORBISENC_DEST_OPEN_ERR); } // parse the chunks U32 chunk_length = 0; U32 file_pos = 12; // start at the first chunk (usually fmt but not always) while (infile.eof() != APR_EOF) { infile.seek(APR_SET,file_pos); infile.read(wav_header, 44); chunk_length = ((U32) wav_header[7] << 24) + ((U32) wav_header[6] << 16) + ((U32) wav_header[5] << 8) + wav_header[4]; // llinfos << "chunk found: '" << wav_header[0] << wav_header[1] << wav_header[2] << wav_header[3] << "'" << llendl; if (!(strncmp((char *)&(wav_header[0]),"fmt ",4))) { num_channels = ((U16) wav_header[11] << 8) + wav_header[10]; sample_rate = ((U32) wav_header[15] << 24) + ((U32) wav_header[14] << 16) + ((U32) wav_header[13] << 8) + wav_header[12]; bits_per_sample = ((U16) wav_header[23] << 8) + wav_header[22]; } else if (!(strncmp((char *)&(wav_header[0]),"data",4))) { infile.seek(APR_SET,file_pos+8); // leave the file pointer at the beginning of the data chunk data data_left = chunk_length; break; } file_pos += (chunk_length + 8); chunk_length = 0; } /********** Encode setup ************/ /* choose an encoding mode */ /* (mode 0: 44kHz stereo uncoupled, roughly 128kbps VBR) */ vorbis_info_init(&vi); // always encode to mono // SL-52913 & SL-53779 determined this quality level to be our 'good // enough' general-purpose quality level with a nice low bitrate. // Equivalent to oggenc -q0.5 F32 quality = 0.05f; // quality = (bitrate==128000 ? 0.4f : 0.1); // if (vorbis_encode_init(&vi, /* num_channels */ 1 ,sample_rate, -1, bitrate, -1)) if (vorbis_encode_init_vbr(&vi, /* num_channels */ 1 ,sample_rate, quality)) // if (vorbis_encode_setup_managed(&vi,1,sample_rate,-1,bitrate,-1) || // vorbis_encode_ctl(&vi,OV_ECTL_RATEMANAGE_AVG,NULL) || // vorbis_encode_setup_init(&vi)) { llwarns << "unable to initialize vorbis codec at quality " << quality << llendl; // llwarns << "unable to initialize vorbis codec at bitrate " << bitrate << llendl; return(LLVORBISENC_DEST_OPEN_ERR); } /* add a comment */ vorbis_comment_init(&vc); // vorbis_comment_add(&vc,"Linden"); /* set up the analysis state and auxiliary encoding storage */ vorbis_analysis_init(&vd,&vi); vorbis_block_init(&vd,&vb); /* set up our packet->stream encoder */ /* pick a random serial number; that way we can more likely build chained streams just by concatenation */ ogg_stream_init(&os, ll_rand()); /* Vorbis streams begin with three headers; the initial header (with most of the codec setup parameters) which is mandated by the Ogg bitstream spec. The second header holds any comment fields. The third header holds the bitstream codebook. We merely need to make the headers, then pass them to libvorbis one at a time; libvorbis handles the additional Ogg bitstream constraints */ { ogg_packet header; ogg_packet header_comm; ogg_packet header_code; vorbis_analysis_headerout(&vd,&vc,&header,&header_comm,&header_code); ogg_stream_packetin(&os,&header); /* automatically placed in its own page */ ogg_stream_packetin(&os,&header_comm); ogg_stream_packetin(&os,&header_code); /* We don't have to write out here, but doing so makes streaming * much easier, so we do, flushing ALL pages. This ensures the actual * audio data will start on a new page */ while(!eos){ int result=ogg_stream_flush(&os,&og); if(result==0)break; outfile.write(og.header, og.header_len); outfile.write(og.body, og.body_len); } } while(!eos) { long bytes_per_sample = bits_per_sample/8; long bytes=(long)infile.read(readbuffer,llclamp((S32)(READ_BUFFER*num_channels*bytes_per_sample),0,data_left)); /* stereo hardwired here */ if (bytes==0) { /* end of file. this can be done implicitly in the mainline, but it's easier to see here in non-clever fashion. Tell the library we're at end of stream so that it can handle the last frame and mark end of stream in the output properly */ vorbis_analysis_wrote(&vd,0); // eos = 1; } else { long i; long samples; int temp; data_left -= bytes; /* data to encode */ /* expose the buffer to submit data */ float **buffer=vorbis_analysis_buffer(&vd,READ_BUFFER); i = 0; samples = bytes / (num_channels * bytes_per_sample); if (num_channels == 2) { if (bytes_per_sample == 2) { /* uninterleave samples */ for(i=0; i<samples ;i++) { temp = ((signed char *)readbuffer)[i*4+1]; /*Flawfinder: ignore*/ temp += ((signed char *)readbuffer)[i*4+3]; /*Flawfinder: ignore*/ temp <<= 8; temp += readbuffer[i*4]; temp += readbuffer[i*4+2]; buffer[0][i] = ((float)temp) / 65536.f; } } else // presume it's 1 byte per which is unsigned (F#@%ing wav "standard") { /* uninterleave samples */ for(i=0; i<samples ;i++) { temp = readbuffer[i*2+0]; temp += readbuffer[i*2+1]; temp -= 256; buffer[0][i] = ((float)temp) / 256.f; } } } else if (num_channels == 1) { if (bytes_per_sample == 2) { for(i=0; i < samples ;i++) { temp = ((signed char*)readbuffer)[i*2+1]; temp <<= 8; temp += readbuffer[i*2]; buffer[0][i] = ((float)temp) / 32768.f; } } else // presume it's 1 byte per which is unsigned (F#@%ing wav "standard") { for(i=0; i < samples ;i++) { temp = readbuffer[i]; temp -= 128; buffer[0][i] = ((float)temp) / 128.f; } } } /* tell the library how much we actually submitted */ vorbis_analysis_wrote(&vd,i); } /* vorbis does some data preanalysis, then divvies up blocks for more involved (potentially parallel) processing. Get a single block for encoding now */ while(vorbis_analysis_blockout(&vd,&vb)==1) { /* analysis */ /* Do the main analysis, creating a packet */ vorbis_analysis(&vb, NULL); vorbis_bitrate_addblock(&vb); while(vorbis_bitrate_flushpacket(&vd, &op)) { /* weld the packet into the bitstream */ ogg_stream_packetin(&os,&op); /* write out pages (if any) */ while(!eos) { result = ogg_stream_pageout(&os,&og); if(result==0) break; outfile.write(og.header, og.header_len); outfile.write(og.body, og.body_len); /* this could be set above, but for illustrative purposes, I do it here (to show that vorbis does know where the stream ends) */ if(ogg_page_eos(&og)) eos=1; } } } } /* clean up and exit. vorbis_info_clear() must be called last */ ogg_stream_clear(&os); vorbis_block_clear(&vb); vorbis_dsp_clear(&vd); vorbis_comment_clear(&vc); vorbis_info_clear(&vi); /* ogg_page and ogg_packet structs always point to storage in libvorbis. They're never freed or manipulated directly */ // fprintf(stderr,"Vorbis encoding: Done.\n"); llinfos << "Vorbis encoding: Done." << llendl; #endif return(LLVORBISENC_NOERR); }