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; int numReads=0; FILE *outFile = fopen("../test.ogg","wb"); /* we cheat on the WAV header; we just bypass 44 bytes (simplest WAV header is 44 bytes) and assume that the data is 44.1khz, stereo, 16 bit little endian pcm samples. This is just an example, after all. */ /********** 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,1.0); /* 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,outFile); fwrite(og.body,1,og.body_len,outFile); } } while(!eos){ long i; long bytes=READ*4; /* stereo hardwired here */ numReads++; if(numReads>10000) bytes=0; 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++){ static float curamp = 0; curamp += 0.15f; buffer[0][i] = sinf(curamp); buffer[1][i] = sinf(curamp); } /* 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,outFile); fwrite(og.body,1,og.body_len,outFile); /* 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); }
void CompressionTool::encodeRaw(const char *rawData, int length, int samplerate, const char *outname, AudioFormat compmode) { print(" - len=%ld, ch=%d, rate=%d, %dbits", length, (rawAudioType.isStereo ? 2 : 1), samplerate, rawAudioType.bitsPerSample); #ifdef USE_VORBIS if (compmode == AUDIO_VORBIS) { char outputString[256] = ""; int numChannels = (rawAudioType.isStereo ? 2 : 1); int totalSamples = length / ((rawAudioType.bitsPerSample / 8) * numChannels); int samplesLeft = totalSamples; int eos = 0; int totalBytes = 0; vorbis_info vi; vorbis_comment vc; vorbis_dsp_state vd; vorbis_block vb; ogg_stream_state os; ogg_page og; ogg_packet op; ogg_packet header; ogg_packet header_comm; ogg_packet header_code; Common::File outputOgg(outname, "wb"); vorbis_info_init(&vi); if (oggparms.nominalBitr > 0) { int result = 0; /* Input is in kbps, function takes bps */ result = vorbis_encode_setup_managed(&vi, numChannels, samplerate, (oggparms.maxBitr > 0 ? 1000 * oggparms.maxBitr : -1), (1000 * oggparms.nominalBitr), (oggparms.minBitr > 0 ? 1000 * oggparms.minBitr : -1)); if (result == OV_EFAULT) { vorbis_info_clear(&vi); error("Error: Internal Logic Fault"); } else if ((result == OV_EINVAL) || (result == OV_EIMPL)) { vorbis_info_clear(&vi); error("Error: Invalid bitrate parameters"); } if (!oggparms.silent) { sprintf(outputString, "Encoding to\n \"%s\"\nat average bitrate %i kbps (", outname, oggparms.nominalBitr); if (oggparms.minBitr > 0) { sprintf(outputString + strlen(outputString), "min %i kbps, ", oggparms.minBitr); } else { sprintf(outputString + strlen(outputString), "no min, "); } if (oggparms.maxBitr > 0) { sprintf(outputString + strlen(outputString), "max %i kbps),\nusing full bitrate management engine\nSet optional hard quality restrictions\n", oggparms.maxBitr); } else { sprintf(outputString + strlen(outputString), "no max),\nusing full bitrate management engine\nSet optional hard quality restrictions\n"); } } } else { int result = 0; /* Quality input is -1 - 10, function takes -0.1 through 1.0 */ result = vorbis_encode_setup_vbr(&vi, numChannels, samplerate, oggparms.quality * 0.1f); if (result == OV_EFAULT) { vorbis_info_clear(&vi); error("Internal Logic Fault"); } else if ((result == OV_EINVAL) || (result == OV_EIMPL)) { vorbis_info_clear(&vi); error("Invalid bitrate parameters"); } if (!oggparms.silent) { sprintf(outputString, "Encoding to\n \"%s\"\nat quality %2.2f", outname, oggparms.quality); } if ((oggparms.minBitr > 0) || (oggparms.maxBitr > 0)) { struct ovectl_ratemanage_arg extraParam; vorbis_encode_ctl(&vi, OV_ECTL_RATEMANAGE_GET, &extraParam); extraParam.bitrate_hard_min = (oggparms.minBitr > 0 ? (1000 * oggparms.minBitr) : -1); extraParam.bitrate_hard_max = (oggparms.maxBitr > 0 ? (1000 * oggparms.maxBitr) : -1); extraParam.management_active = 1; vorbis_encode_ctl(&vi, OV_ECTL_RATEMANAGE_SET, &extraParam); if (!oggparms.silent) { sprintf(outputString + strlen(outputString), " using constrained VBR ("); if (oggparms.minBitr != -1) { sprintf(outputString + strlen(outputString), "min %i kbps, ", oggparms.minBitr); } else { sprintf(outputString + strlen(outputString), "no min, "); } if (oggparms.maxBitr != -1) { sprintf(outputString + strlen(outputString), "max %i kbps)\nSet optional hard quality restrictions\n", oggparms.maxBitr); } else { sprintf(outputString + strlen(outputString), "no max)\nSet optional hard quality restrictions\n"); } } } else { sprintf(outputString + strlen(outputString), "\n"); } } puts(outputString); vorbis_encode_setup_init(&vi); vorbis_comment_init(&vc); vorbis_analysis_init(&vd, &vi); vorbis_block_init(&vd, &vb); ogg_stream_init(&os, 0); vorbis_analysis_headerout(&vd, &vc, &header, &header_comm, &header_code); ogg_stream_packetin(&os, &header); ogg_stream_packetin(&os, &header_comm); ogg_stream_packetin(&os, &header_code); while (!eos) { int result = ogg_stream_flush(&os,&og); if (result == 0) { break; } outputOgg.write(og.header, og.header_len); outputOgg.write(og.body, og.body_len); } while (!eos) { int numSamples = ((samplesLeft < 2048) ? samplesLeft : 2048); float **buffer = vorbis_analysis_buffer(&vd, numSamples); /* We must tell the encoder that we have reached the end of the stream */ if (numSamples == 0) { vorbis_analysis_wrote(&vd, 0); } else { /* Adapted from oggenc 1.1.1 */ if (rawAudioType.bitsPerSample == 8) { const byte *rawDataUnsigned = (const byte *)rawData; for (int i = 0; i < numSamples; i++) { for (int j = 0; j < numChannels; j++) { buffer[j][i] = ((int)(rawDataUnsigned[i * numChannels + j]) - 128) / 128.0f; } } } else if (rawAudioType.bitsPerSample == 16) { if (rawAudioType.isLittleEndian) { for (int i = 0; i < numSamples; i++) { for (int j = 0; j < numChannels; j++) { buffer[j][i] = ((rawData[(i * 2 * numChannels) + (2 * j) + 1] << 8) | (rawData[(i * 2 * numChannels) + (2 * j)] & 0xff)) / 32768.0f; } } } else { for (int i = 0; i < numSamples; i++) { for (int j = 0; j < numChannels; j++) { buffer[j][i] = ((rawData[(i * 2 * numChannels) + (2 * j)] << 8) | (rawData[(i * 2 * numChannels) + (2 * j) + 1] & 0xff)) / 32768.0f; } } } } vorbis_analysis_wrote(&vd, numSamples); } 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) { int result = ogg_stream_pageout(&os, &og); if (result == 0) { break; } totalBytes += outputOgg.write(og.header, og.header_len); totalBytes += outputOgg.write(og.body, og.body_len); if (ogg_page_eos(&og)) { eos = 1; } } } } rawData += 2048 * (rawAudioType.bitsPerSample / 8) * numChannels; samplesLeft -= 2048; } ogg_stream_clear(&os); vorbis_block_clear(&vb); vorbis_dsp_clear(&vd); vorbis_info_clear(&vi); if (!oggparms.silent) { print("\nDone encoding file \"%s\"", outname); print("\n\tFile length: %dm %ds", (int)(totalSamples / samplerate / 60), (totalSamples / samplerate % 60)); print("\tAverage bitrate: %.1f kb/s\n", (8.0 * (double)totalBytes / 1000.0) / ((double)totalSamples / (double)samplerate)); } } #endif #ifdef USE_FLAC if (compmode == AUDIO_FLAC) { int i; int numChannels = (rawAudioType.isStereo ? 2 : 1); int samplesPerChannel = length / ((rawAudioType.bitsPerSample / 8) * numChannels); FLAC__StreamEncoder *encoder; FLAC__StreamEncoderInitStatus initStatus; FLAC__int32 *flacData; flacData = (FLAC__int32 *)malloc(samplesPerChannel * numChannels * sizeof(FLAC__int32)); if (rawAudioType.bitsPerSample == 8) { for (i = 0; i < samplesPerChannel * numChannels; i++) { flacData[i] = (FLAC__int32)(FLAC__uint8)rawData[i] - 0x80; } } else if (rawAudioType.bitsPerSample == 16) { if (rawAudioType.isLittleEndian) { for (i = 0; i < samplesPerChannel * numChannels; i++) { flacData[i] = (FLAC__int32)((FLAC__int16)(FLAC__int8)(FLAC__byte)rawData[2 * i + 1] << 8 | (FLAC__int16)(FLAC__byte)rawData[2 * i ]); } } else { for (i = 0; i < samplesPerChannel * numChannels; i++) { flacData[i] = (FLAC__int32)((FLAC__int16)(FLAC__int8)(FLAC__byte)rawData[2 * i ] << 8 | (FLAC__int16)(FLAC__byte)rawData[2 * i + 1]); } } } if (!flacparms.silent) { print("Encoding to\n \"%s\"\nat compression level %d using blocksize %d\n", outname, flacparms.compressionLevel, flacparms.blocksize); } encoder = FLAC__stream_encoder_new(); FLAC__stream_encoder_set_bits_per_sample(encoder, rawAudioType.bitsPerSample); FLAC__stream_encoder_set_blocksize(encoder, flacparms.blocksize); FLAC__stream_encoder_set_channels(encoder, numChannels); FLAC__stream_encoder_set_compression_level(encoder, flacparms.compressionLevel); FLAC__stream_encoder_set_sample_rate(encoder, samplerate); FLAC__stream_encoder_set_streamable_subset(encoder, false); FLAC__stream_encoder_set_total_samples_estimate(encoder, samplesPerChannel); FLAC__stream_encoder_set_verify(encoder, flacparms.verify); initStatus = FLAC__stream_encoder_init_file(encoder, outname, NULL, NULL); if (initStatus != FLAC__STREAM_ENCODER_INIT_STATUS_OK) { char buf[2048]; sprintf(buf, "Error in FLAC encoder. (check the parameters)\nExact error was:%s", FLAC__StreamEncoderInitStatusString[initStatus]); free(flacData); throw ToolException(buf); } else { FLAC__stream_encoder_process_interleaved(encoder, flacData, samplesPerChannel); } FLAC__stream_encoder_finish(encoder); FLAC__stream_encoder_delete(encoder); free(flacData); if (!flacparms.silent) { print("\nDone encoding file \"%s\"", outname); print("\n\tFile length: %dm %ds\n", (int)(samplesPerChannel / samplerate / 60), (samplesPerChannel / samplerate % 60)); } } #endif }
/* all of the real encoding details are here. The modes, books, everything */ static int _vorbis_unpack_books(vorbis_info *vi,oggpack_buffer *opb){ codec_setup_info *ci=vi->codec_setup; int i; if(!ci)return(OV_EFAULT); /* codebooks */ ci->books=oggpack_read(opb,8)+1; if(ci->books<=0)goto err_out; for(i=0;i<ci->books;i++){ ci->book_param[i]=vorbis_staticbook_unpack(opb); if(!ci->book_param[i])goto err_out; } /* time backend settings; hooks are unused */ { int times=oggpack_read(opb,6)+1; if(times<=0)goto err_out; for(i=0;i<times;i++){ int test=oggpack_read(opb,16); if(test<0 || test>=VI_TIMEB)goto err_out; } } /* floor backend settings */ ci->floors=oggpack_read(opb,6)+1; if(ci->floors<=0)goto err_out; for(i=0;i<ci->floors;i++){ ci->floor_type[i]=oggpack_read(opb,16); if(ci->floor_type[i]<0 || ci->floor_type[i]>=VI_FLOORB)goto err_out; ci->floor_param[i]=_floor_P[ci->floor_type[i]]->unpack(vi,opb); if(!ci->floor_param[i])goto err_out; } /* residue backend settings */ ci->residues=oggpack_read(opb,6)+1; if(ci->residues<=0)goto err_out; for(i=0;i<ci->residues;i++){ ci->residue_type[i]=oggpack_read(opb,16); if(ci->residue_type[i]<0 || ci->residue_type[i]>=VI_RESB)goto err_out; ci->residue_param[i]=_residue_P[ci->residue_type[i]]->unpack(vi,opb); if(!ci->residue_param[i])goto err_out; } /* map backend settings */ ci->maps=oggpack_read(opb,6)+1; if(ci->maps<=0)goto err_out; for(i=0;i<ci->maps;i++){ ci->map_type[i]=oggpack_read(opb,16); if(ci->map_type[i]<0 || ci->map_type[i]>=VI_MAPB)goto err_out; ci->map_param[i]=_mapping_P[ci->map_type[i]]->unpack(vi,opb); if(!ci->map_param[i])goto err_out; } /* mode settings */ ci->modes=oggpack_read(opb,6)+1; if(ci->modes<=0)goto err_out; for(i=0;i<ci->modes;i++){ ci->mode_param[i]=_ogg_calloc(1,sizeof(*ci->mode_param[i])); ci->mode_param[i]->blockflag=oggpack_read(opb,1); ci->mode_param[i]->windowtype=oggpack_read(opb,16); ci->mode_param[i]->transformtype=oggpack_read(opb,16); ci->mode_param[i]->mapping=oggpack_read(opb,8); if(ci->mode_param[i]->windowtype>=VI_WINDOWB)goto err_out; if(ci->mode_param[i]->transformtype>=VI_WINDOWB)goto err_out; if(ci->mode_param[i]->mapping>=ci->maps)goto err_out; if(ci->mode_param[i]->mapping<0)goto err_out; } if(oggpack_read(opb,1)!=1)goto err_out; /* top level EOP check */ return(0); err_out: vorbis_info_clear(vi); return(OV_EBADHEADER); }
/*! * \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_log(LOG_DEBUG, "OGG/Vorbis comment: %s\n", *ptr); ast_log(LOG_DEBUG, "OGG/Vorbis bitstream is %d channel, %ldHz\n", tmp->vi.channels, tmp->vi.rate); ast_log(LOG_DEBUG, "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; }
int main(int argc,char *argv[]){ int i,j; ogg_packet op; FILE *infile = stdin; #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 ); #endif /* open the input file if any */ if(argc==2){ infile=fopen(argv[1],"rb"); if(infile==NULL){ fprintf(stderr,"Unable to open '%s' for playback.\n", argv[1]); exit(1); } } if(argc>2){ usage(); exit(1); } /* start up Ogg stream synchronization layer */ ogg_sync_init(&oy); /* init supporting Vorbis structures needed in header parsing */ vorbis_info_init(&vi); vorbis_comment_init(&vc); /* init supporting Theora structures needed in header parsing */ theora_comment_init(&tc); theora_info_init(&ti); /* Ogg file open; parse the headers */ /* Only interested in Vorbis/Theora streams */ while(!stateflag){ int ret=buffer_data(infile,&oy); if(ret==0)break; while(ogg_sync_pageout(&oy,&og)>0){ 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); ogg_stream_packetout(&test,&op); /* identify the codec: try theora */ if(!theora_p && theora_decode_header(&ti,&tc,&op)>=0){ /* it is theora */ memcpy(&to,&test,sizeof(test)); theora_p=1; }else if(!vorbis_p && vorbis_synthesis_headerin(&vi,&vc,&op)>=0){ /* it is vorbis */ memcpy(&vo,&test,sizeof(test)); vorbis_p=1; }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_p<3) || (vorbis_p && vorbis_p<3)){ int ret; /* look for further theora headers */ while(theora_p && (theora_p<3) && (ret=ogg_stream_packetout(&to,&op))){ if(ret<0){ fprintf(stderr,"Error parsing Theora stream headers; corrupt stream?\n"); exit(1); } if(theora_decode_header(&ti,&tc,&op)){ printf("Error parsing Theora stream headers; corrupt stream?\n"); exit(1); } theora_p++; if(theora_p==3)break; } /* look for more vorbis header packets */ while(vorbis_p && (vorbis_p<3) && (ret=ogg_stream_packetout(&vo,&op))){ if(ret<0){ fprintf(stderr,"Error parsing Vorbis stream headers; corrupt stream?\n"); exit(1); } if(vorbis_synthesis_headerin(&vi,&vc,&op)){ fprintf(stderr,"Error parsing Vorbis stream headers; corrupt stream?\n"); exit(1); } vorbis_p++; if(vorbis_p==3)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){ theora_decode_init(&td,&ti); printf("Ogg logical stream %x is Theora %dx%d %.02f fps", (unsigned int)to.serialno,ti.width,ti.height, (double)ti.fps_numerator/ti.fps_denominator); switch(ti.pixelformat){ case OC_PF_420: printf(" 4:2:0 video\n"); break; case OC_PF_422: printf(" 4:2:2 video\n"); break; case OC_PF_444: printf(" 4:4:4 video\n"); break; case OC_PF_RSVD: default: printf(" video\n (UNKNOWN Chroma sampling!)\n"); break; } if(ti.width!=ti.frame_width || ti.height!=ti.frame_height) printf(" Frame content is %dx%d with offset (%d,%d).\n", ti.frame_width, ti.frame_height, ti.offset_x, ti.offset_y); report_colorspace(&ti); dump_comments(&tc); }else{ /* tear down the partial theora setup */ theora_info_clear(&ti); theora_comment_clear(&tc); } if(vorbis_p){ vorbis_synthesis_init(&vd,&vi); vorbis_block_init(&vd,&vb); fprintf(stderr,"Ogg logical stream %x is Vorbis %d channel %d Hz audio.\n", (unsigned int)vo.serialno,vi.channels,(int)vi.rate); }else{ /* tear down the partial vorbis setup */ vorbis_info_clear(&vi); vorbis_comment_clear(&vc); } /* open audio */ if(vorbis_p)open_audio(); /* open video */ if(theora_p)open_video(); /* install signal handler as SDL clobbered the default */ signal (SIGINT, sigint_handler); /* on to the main decode loop. We assume in this example that audio and video start roughly together, and don't begin playback until we have a start frame for both. This is not necessarily a valid assumption in Ogg A/V streams! It will always be true of the example_encoder (and most streams) though. */ stateflag=0; /* playback has not begun */ while(!got_sigint){ /* we want a video and audio frame ready to go at all times. If we have to buffer incoming, buffer the compressed data (ie, let ogg do the buffering) */ while(vorbis_p && !audiobuf_ready){ int ret; float **pcm; /* if there's pending, decoded audio, grab it */ if((ret=vorbis_synthesis_pcmout(&vd,&pcm))>0){ int count=audiobuf_fill/2; int maxsamples=(audiofd_fragsize-audiobuf_fill)/2/vi.channels; for(i=0;i<ret && i<maxsamples;i++) for(j=0;j<vi.channels;j++){ int val=rint(pcm[j][i]*32767.f); if(val>32767)val=32767; if(val<-32768)val=-32768; audiobuf[count++]=val; } vorbis_synthesis_read(&vd,i); audiobuf_fill+=i*vi.channels*2; if(audiobuf_fill==audiofd_fragsize)audiobuf_ready=1; if(vd.granulepos>=0) audiobuf_granulepos=vd.granulepos-ret+i; else audiobuf_granulepos+=i; }else{ /* no pending audio; is there a pending packet to decode? */ if(ogg_stream_packetout(&vo,&op)>0){ if(vorbis_synthesis(&vb,&op)==0) /* test for success! */ vorbis_synthesis_blockin(&vd,&vb); }else /* we need more data; break out to suck in another page */ break; } } while(theora_p && !videobuf_ready){ /* theora is one in, one out... */ if(ogg_stream_packetout(&to,&op)>0){ theora_decode_packetin(&td,&op); videobuf_granulepos=td.granulepos; videobuf_time=theora_granule_time(&td,videobuf_granulepos); /* is it already too old to be useful? This is only actually useful cosmetically after a SIGSTOP. Note that we have to decode the frame even if we don't show it (for now) due to keyframing. Soon enough libtheora will be able to deal with non-keyframe seeks. */ if(videobuf_time>=get_time()) videobuf_ready=1; }else break; } if(!videobuf_ready && !audiobuf_ready && feof(infile))break; if(!videobuf_ready || !audiobuf_ready){ /* no data yet for somebody. Grab another page */ int bytes=buffer_data(infile,&oy); while(ogg_sync_pageout(&oy,&og)>0){ queue_page(&og); } } /* If playback has begun, top audio buffer off immediately. */ if(stateflag) audio_write_nonblocking(); /* are we at or past time for this video frame? */ if(stateflag && videobuf_ready && videobuf_time<=get_time()){ video_write(); videobuf_ready=0; } if(stateflag && (audiobuf_ready || !vorbis_p) && (videobuf_ready || !theora_p) && !got_sigint){ /* we have an audio frame ready (which means the audio buffer is full), it's not time to play video, so wait until one of the audio buffer is ready or it's near time to play video */ /* set up select wait on the audiobuffer and a timeout for video */ struct timeval timeout; fd_set writefs; fd_set empty; int n=0; FD_ZERO(&writefs); FD_ZERO(&empty); if(audiofd>=0){ FD_SET(audiofd,&writefs); n=audiofd+1; } if(theora_p){ long milliseconds=(videobuf_time-get_time())*1000-5; if(milliseconds>500)milliseconds=500; if(milliseconds>0){ timeout.tv_sec=milliseconds/1000; timeout.tv_usec=(milliseconds%1000)*1000; n=select(n,&empty,&writefs,&empty,&timeout); if(n)audio_calibrate_timer(0); } }else{ select(n,&empty,&writefs,&empty,NULL); } } /* if our buffers either don't exist or are ready to go, we can begin playback */ if((!theora_p || videobuf_ready) && (!vorbis_p || audiobuf_ready))stateflag=1; /* same if we've run out of input */ if(feof(infile))stateflag=1; } /* tear it all down */ audio_close(); SDL_Quit(); if(vorbis_p){ ogg_stream_clear(&vo); vorbis_block_clear(&vb); vorbis_dsp_clear(&vd); vorbis_comment_clear(&vc); vorbis_info_clear(&vi); } if(theora_p){ ogg_stream_clear(&to); theora_clear(&td); theora_comment_clear(&tc); theora_info_clear(&ti); } ogg_sync_clear(&oy); if(infile && infile!=stdin)fclose(infile); fprintf(stderr, "\r " "\nDone.\n"); return(0); }
int OggEncode( wsul nSize, wsfb *bData, wsul nCh, int nBit, wsf_file *wOut, wsul nFreq ) { 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 */ wsul nRLen; int eos=0,ret; nRLen = READ; if (nCh == 1) nRLen /= 2; if (nBit) nRLen /= 2; if (nFreq < 22050) nFreq = 44100; if (nFreq > 44800) nFreq = 44100; wsf_file *wIn; wIn = wsfopenmem(bData,nSize); /********** 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 qulity 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_RATEMANAGE_AVG,NULL) || vorbis_encode_setup_init(&vi)); *********************************************************************/ if (nFreq == 0) ret = vorbis_encode_init(&vi,2,44100,-1,g_nRate*1000,-1); else { ret = vorbis_encode_init(&vi,2,nFreq,-1,g_nRate*1000,-1); if (ret) { vorbis_info_clear(&vi); vorbis_info_init(&vi); ret = vorbis_encode_init(&vi,2,44100,-1,g_nRate*1000,-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)printf("Errorly, improper bitrate?\n\n"); if(ret)return 1; /* add a comment */ vorbis_comment_init(&vc); vorbis_comment_add_tag(&vc,"ENCODER","WSF Encoder"); /* 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; wsfwrite(og.header,og.header_len,wOut); wsfwrite(og.body,og.body_len,wOut); } } while(!eos) { int i; int bytes=wsfread(readbuffer,nRLen*4,wIn); /* 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,nRLen); /* uninterleave samples */ if (nBit == 16) { for(i=0; i<bytes/4; i++) { buffer[0][i]=((readbuffer[i*4+1]<<8)| (0x00ff&(int)readbuffer[i*4]))/32768.f; if (buffer[1]) buffer[1][i]=((readbuffer[i*4+3]<<8)| (0x00ff&(int)readbuffer[i*4+2]))/32768.f; } } else { for(i=0; i<bytes/2; i++) { buffer[0][i]=((readbuffer[i*2+1]<<8)| (0x00ff&(int)readbuffer[i*2]))/32768.f; if (buffer[1]) buffer[1][i]=((readbuffer[i*2+3]<<8)| (0x00ff&(int)readbuffer[i*2+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; wsfwrite(og.header,og.header_len,wOut); wsfwrite(og.body,og.body_len,wOut); /* 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); wsfclose(wIn); /* ogg_page and ogg_packet structs always point to storage in libvorbis. They're never freed or manipulated directly */ return(0); }
static void vorbis_end (stream_processor *stream, sf_count_t * len) { *len += stream->lastgranulepos ; vorbis_comment_clear (&stream->vc) ; vorbis_info_clear (&stream->vi) ; } /* vorbis_end */
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, LLAPRFile::global); 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, LLAPRFile::global); 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); }
const char * _edje_multisense_encode_to_ogg_vorbis(char *snd_path, double quality, SF_INFO sfinfo) { 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; char *tmp; SNDFILE *sfile; FILE *fout; sfile = sf_open(snd_path, SFM_READ, &sfinfo); if (!sfile) return NULL; if (!sf_format_check(&sfinfo)) { sf_close(sfile); return NULL; } tmp = malloc(strlen(snd_path) + 1 + 4); if (!tmp) { sf_close(sfile); return NULL; } strcpy(tmp, snd_path); snd_path = tmp; strcat(snd_path, ".ogg"); fout = fopen(snd_path, "wb"); if (!fout) { free(snd_path); sf_close(sfile); return NULL; } /********** Encode setup ************/ vorbis_info_init(&vi); ret = vorbis_encode_init(&vi, sfinfo.channels, sfinfo.samplerate, -1, (long)(quality * 1000), -1); if (ret == OV_EFAULT) printf("OV_EFAULT\n"); if (ret == OV_EINVAL) printf("OV_EINVAL\n"); if (ret == OV_EIMPL) printf("OV_EIMPL\n"); if (ret) { fclose(fout); free(snd_path); sf_close(sfile); return NULL; } /* add a comment */ vorbis_comment_init(&vc); vorbis_comment_add_tag(&vc, "", ""); /* set up the analysis state and auxiliary encoding storage */ vorbis_analysis_init(&vd, &vi); vorbis_block_init(&vd, &vb); srand(time(NULL)); ogg_stream_init(&os, rand()); 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); while (!eos) { int result = ogg_stream_flush(&os, &og); if (!result) break; fwrite(og.header, 1, og.header_len, fout); fwrite(og.body, 1, og.body_len, fout); } while (!eos) { int i, ch; float readbuffer[READBUF * 2]; sf_count_t count; count = sf_readf_float(sfile, readbuffer, READBUF); if (!count) vorbis_analysis_wrote(&vd, 0); else { float **buffer = vorbis_analysis_buffer(&vd, count); /* uninterleave samples */ for (i = 0; i < count; i++) { for (ch = 0; ch < sfinfo.channels; ch++) buffer[ch][i]= readbuffer[(i * sfinfo.channels) + ch]; } vorbis_analysis_wrote(&vd, 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) { int result = ogg_stream_pageout(&os, &og); if (!result) break; fwrite(og.header, 1, og.header_len, fout); fwrite(og.body, 1, og.body_len, fout); if (ogg_page_eos(&og)) eos = 1; } } } } ogg_stream_clear(&os); vorbis_block_clear(&vb); vorbis_dsp_clear(&vd); vorbis_comment_clear(&vc); vorbis_info_clear(&vi); sf_close(sfile); fclose (fout); return snd_path; }
xtr_oggvorbis_c::~xtr_oggvorbis_c() { vorbis_info_clear(&m_vorbis_info); vorbis_comment_clear(&m_vorbis_comment); }
HOTSPOT PUBLIC SW32 vorbis_encode( const char *filename, void *data, W32 size, W32 in_channels, W32 in_samplesize, W32 rate, W32 quality, W32 max_bitrate, W32 min_bitrate ) { FILE *fp; ogg_stream_state os; ogg_page og; ogg_packet op; vorbis_dsp_state vd; vorbis_block vb; vorbis_info vi; ogg_packet header_main; ogg_packet header_comments; ogg_packet header_codebooks; SW32 result; W32 serialno = 0; vorbis_comment comments; SW32 ret = 0; SW32 eos; W32 samplesdone = 0; W32 packetsdone = 0; W32 bytes_written = 0; fp = fopen( filename, "wb" ); if( fp == NULL ) { return 0; } memset( &comments, 0, sizeof( comments ) ); channels = in_channels; samplesize = in_samplesize; ptrCurrent = (PW8)data; ptrEnd = (PW8)data + size; vorbis_info_init( &vi ); if( vorbis_encode_setup_vbr( &vi, channels, rate, quality ) ) { fprintf( stderr, "Mode initialisation failed: invalid parameters for quality\n" ); vorbis_info_clear( &vi ); // Añadido como consejo de cppcheck. fclose(fp); return 1; } /* do we have optional hard quality restrictions? */ if( max_bitrate > 0 || min_bitrate > 0 ) { struct ovectl_ratemanage_arg ai; vorbis_encode_ctl( &vi, OV_ECTL_RATEMANAGE_GET, &ai ); ai.bitrate_hard_min = min_bitrate; ai.bitrate_hard_max = max_bitrate; ai.management_active = 1; vorbis_encode_ctl( &vi, OV_ECTL_RATEMANAGE_SET, &ai ); } /* Turn off management entirely (if it was turned on). */ vorbis_encode_ctl( &vi, OV_ECTL_RATEMANAGE_SET, NULL ); vorbis_encode_setup_init( &vi ); vorbis_analysis_init( &vd, &vi ); vorbis_block_init( &vd, &vb ); ogg_stream_init( &os, serialno ); /* Now, build the three header packets and send through to the stream output stage (but defer actual file output until the main encode loop) */ /* Build the packets */ ret = vorbis_analysis_headerout( &vd, &comments, &header_main, &header_comments, &header_codebooks ); /* And stream them out */ 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 )) ) { ret = fwrite( og.header, 1, og.header_len, fp ); ret += fwrite( og.body, 1, og.body_len, fp ); if(ret != og.header_len + og.body_len) { fprintf( stderr, "[vorbis_encode]: Failed writing header to output stream\n") ; ret = 1; goto cleanup; /* Bail and try to clean up stuff */ } } eos = 0; /* Main encode loop - continue until end of file */ while( ! eos ) { float **buffer = vorbis_analysis_buffer( &vd, READSIZE ); SW32 samples_read = read_samples( buffer, READSIZE ); if( samples_read == 0 ) { /* Tell the library that we wrote 0 bytes - signalling the end */ vorbis_analysis_wrote( &vd, 0 ); } else { samplesdone += samples_read; /* Call progress update every 40 pages */ if( packetsdone >= 40 ) { packetsdone = 0; // progress bar here } /* Tell the library how many samples (per channel) we wrote into the supplied buffer */ vorbis_analysis_wrote( &vd, samples_read ); } /* While we can get enough data from the library to analyse, one block at a time... */ while( vorbis_analysis_blockout( &vd, &vb ) == 1 ) { /* Do the main analysis, creating a packet */ vorbis_analysis( &vb, NULL ); vorbis_bitrate_addblock( &vb ); while( vorbis_bitrate_flushpacket( &vd, &op ) ) { /* Add packet to bitstream */ ogg_stream_packetin( &os, &op ); packetsdone++; /* If we've gone over a page boundary, we can do actual output, so do so (for however many pages are available) */ while( ! eos ) { SW32 result = ogg_stream_pageout( &os, &og ); if( ! result ) { break; } ret = fwrite( og.header, 1, og.header_len, fp ); ret += fwrite( og.body, 1, og.body_len, fp ); if(ret != og.header_len + og.body_len) { fprintf( stderr, "[vorbis_encode]: Failed writing data to output stream\n" ); ret = 1; goto cleanup; /* Bail */ } else { bytes_written += ret; } if( ogg_page_eos( &og ) ) { eos = 1; } } } } } cleanup: fclose( fp ); ogg_stream_clear( &os ); vorbis_block_clear( &vb ); vorbis_dsp_clear( &vd ); vorbis_info_clear( &vi ); return 0; }
static LONG APIENTRY IOProc_Entry2(PVOID pmmioStr, USHORT usMsg, LONG lParam1, LONG lParam2) { PMMIOINFO pmmioinfo = (PMMIOINFO)pmmioStr; switch (usMsg) { case MMIOM_OPEN: { HMMIO hmmioSS; MMIOINFO mmioinfoSS; PSZ pszFileName = (char *)lParam1; if (!pmmioinfo) return MMIO_ERROR; if ((pmmioinfo->ulFlags & MMIO_READWRITE)) { #ifdef DEBUG fprintf(file,"ReadWrite - requested.\n"); #endif return MMIO_ERROR; } if (!(pmmioinfo->ulTranslate & MMIO_TRANSLATEHEADER) && !(pmmioinfo->ulTranslate & MMIO_TRANSLATEDATA)) return MMIO_ERROR; if (!pmmioinfo->fccChildIOProc) { FOURCC fccFileStorageSystem; if (pmmioinfo->ulFlags & MMIO_CREATE) { if (mmioDetermineSSIOProc(pszFileName, pmmioinfo, &fccFileStorageSystem, NULL)) { fccFileStorageSystem = FOURCC_DOS; } } else { if (mmioIdentifyStorageSystem(pszFileName, pmmioinfo, &fccFileStorageSystem)) { return MMIO_ERROR; } } if (!fccFileStorageSystem) { return MMIO_ERROR; } else { pmmioinfo->fccChildIOProc = fccFileStorageSystem; } /* endif */ } memmove(&mmioinfoSS, pmmioinfo, sizeof(MMIOINFO)); mmioinfoSS.pIOProc = NULL; mmioinfoSS.fccIOProc = pmmioinfo->fccChildIOProc; mmioinfoSS.ulFlags |= MMIO_NOIDENTIFY; hmmioSS = mmioOpen (pszFileName, &mmioinfoSS, mmioinfoSS.ulFlags); if (pmmioinfo->ulFlags & MMIO_DELETE) { if (!hmmioSS) { pmmioinfo->ulErrorRet = MMIOERR_DELETE_FAILED; return MMIO_ERROR; } else return MMIO_SUCCESS; } if (!hmmioSS) return MMIO_ERROR; if (pmmioinfo->ulFlags & MMIO_READ) { DecInfo *decInfo = (DecInfo *)malloc(sizeof(DecInfo)); #ifdef DEBUG fprintf(file,"File Read: %s\n",pszFileName); #endif if (!decInfo) { mmioClose(hmmioSS, 0); return MMIO_ERROR; } decInfo->t = READNUM; decInfo->vorbisOptions = pmmioinfo->pExtraInfoStruct; pmmioinfo->pExtraInfoStruct = (PVOID)decInfo; { ov_callbacks cb; cb.read_func = mread; cb.seek_func = mseek; cb.close_func = mclose; cb.tell_func = mtell; if(0 != ov_open_callbacks((void *)hmmioSS, &decInfo->oggfile, 0, 0, cb)) { free(decInfo); mmioClose(hmmioSS, 0); return MMIO_ERROR; } } #ifdef DEBUG fprintf(file,"Open successfull\n"); #endif return MMIO_SUCCESS; } else if (pmmioinfo->ulFlags & MMIO_WRITE) { EncInfo *encInfo = (EncInfo *)malloc(sizeof(EncInfo)); #ifdef DEBUG fprintf(file,"File Write: %s\n",pszFileName); #endif if (!encInfo) { mmioClose(hmmioSS, 0); return MMIO_ERROR; } memset(encInfo, 0, sizeof(EncInfo)); encInfo->t = WRITENUM; encInfo->hmmioSS = hmmioSS; encInfo->vorbisOptions = (PVORBISOPTIONS)pmmioinfo->pExtraInfoStruct; pmmioinfo->pExtraInfoStruct = (PVOID)encInfo; return MMIO_SUCCESS; } #ifdef DEBUG fprintf(file,"File not read nor write: %s\n",pszFileName); #endif return MMIO_ERROR; } break; case MMIOM_READ: { if (!pmmioinfo || !pmmioinfo->pExtraInfoStruct || !lParam1) return MMIO_ERROR; if (!pmmioinfo->ulTranslate & MMIO_TRANSLATEDATA) { return MMIO_ERROR; // return mmioRead (ogginfo->hmmioSS, (PVOID) lParam1, (ULONG) lParam2); } else { OggVorbis_File *oggfile; long rc = 0; int current_section; long total = 0; oggfile = &((DecInfo *)pmmioinfo->pExtraInfoStruct)->oggfile; if (READNUM != ((DecInfo *)pmmioinfo->pExtraInfoStruct)->t) return MMIO_ERROR; while (lParam2 > 0) { rc = ov_read(oggfile, (char *)lParam1, (int)lParam2, 0, 2, 1, ¤t_section); if (rc < 0) { #ifdef DEBUG fprintf(file, "Read failed once\n"); #endif continue; } if (rc <= 0) break; lParam2 -= rc; lParam1 += rc; total += rc; } #ifdef DEBUG fprintf(file,"Read rc:%ld total:%ld\n",rc,total); #endif if (rc < 0) return MMIO_ERROR; return total; } } break; case MMIOM_SEEK: { LONG lPosDesired; OggVorbis_File *oggfile; vorbis_info *vi; if (!pmmioinfo || !pmmioinfo->pExtraInfoStruct) return MMIO_ERROR; if (!pmmioinfo->ulTranslate & MMIO_TRANSLATEDATA) return MMIO_ERROR; oggfile = &((DecInfo *)pmmioinfo->pExtraInfoStruct)->oggfile; if (READNUM != ((DecInfo *)pmmioinfo->pExtraInfoStruct)->t) return MMIO_ERROR; vi = ov_info(oggfile, -1); if (!vi) return MMIO_ERROR; if (SEEK_SET == lParam2) { lPosDesired = lParam1/(2*vi->channels); } else if (SEEK_CUR == lParam2) { if (0 == lParam1) { return ov_pcm_tell(oggfile)*2*vi->channels; } /* endif */ lPosDesired = ov_pcm_tell(oggfile) + lParam1/(2*vi->channels); } else if (SEEK_END == lParam2) { lPosDesired = ov_pcm_total(oggfile,-1) + lParam1/(2*vi->channels); } else { return MMIO_ERROR; } #ifdef DEBUG fprintf(file,"Seek to %ld by %d\n",lPosDesired, lParam2); #endif if (ov_pcm_seek(oggfile, lPosDesired) < 0) return MMIO_ERROR; return lPosDesired*2*vi->channels; } break; case MMIOM_CLOSE: { int rc; #ifdef DEBUG fprintf(file,"start CLOSE\n"); #endif if (!pmmioinfo) return MMIO_ERROR; if (pmmioinfo->pExtraInfoStruct) { DecInfo *decInfo = (DecInfo *)pmmioinfo->pExtraInfoStruct; #ifdef DEBUG fprintf(file,"ready CLOSE\n"); #endif if (READNUM == decInfo->t) { #ifdef DEBUG fprintf(file,"read CLOSE\n"); #endif ov_clear(&decInfo->oggfile); free(decInfo); decInfo = 0; rc=MMIO_SUCCESS; } else if (WRITENUM == decInfo->t) { EncInfo *encInfo = (EncInfo*)pmmioinfo->pExtraInfoStruct; #ifdef DEBUG fprintf(file,"write CLOSE\n"); #endif if (encInfo->headerSet) { vorbis_analysis_wrote(&encInfo->vd,0); rc = oggWrite(encInfo,1); ogg_stream_clear(&encInfo->os); vorbis_block_clear(&encInfo->vb); vorbis_dsp_clear(&encInfo->vd); vorbis_comment_clear(&encInfo->vc); vorbis_info_clear(&encInfo->vi); } mmioClose(encInfo->hmmioSS, 0); free(encInfo); encInfo = 0; rc = MMIO_SUCCESS; } else rc = MMIO_ERROR; pmmioinfo->pExtraInfoStruct = 0; #ifdef DEBUG fprintf(file,"CLOSE\n"); #endif return rc; } return MMIO_ERROR; } break; case MMIOM_IDENTIFYFILE: { unsigned char buf[4]; HMMIO hmmioTemp; ULONG ulTempFlags = MMIO_READ | MMIO_DENYWRITE | MMIO_NOIDENTIFY; LONG rc = MMIO_ERROR; if (!lParam1 && !lParam2) return MMIO_ERROR; hmmioTemp = (HMMIO)lParam2; if (!hmmioTemp) { hmmioTemp = mmioOpen((PSZ)lParam1, NULL, ulTempFlags); } if (hmmioTemp) { rc = mmioRead(hmmioTemp, buf, 4); if (rc == 4 && buf[0] == 'O' && buf[1] == 'g' && buf[2] == 'g' && buf[3] == 'S') { rc = MMIO_SUCCESS; } if (!lParam2) mmioClose(hmmioTemp, 0); } return rc; } break; case MMIOM_GETFORMATINFO: { PMMFORMATINFO pmmformatinfo; pmmformatinfo = (PMMFORMATINFO)lParam1; pmmformatinfo->ulStructLen = sizeof(MMFORMATINFO); pmmformatinfo->fccIOProc = FOURCC_Vorbis; pmmformatinfo->ulIOProcType = MMIO_IOPROC_FILEFORMAT; pmmformatinfo->ulMediaType = MMIO_MEDIATYPE_AUDIO; pmmformatinfo->ulFlags = MMIO_CANREADTRANSLATED | MMIO_CANWRITETRANSLATED | MMIO_CANSEEKTRANSLATED; strcpy(pmmformatinfo->szDefaultFormatExt, "OGG"); pmmformatinfo->ulCodePage = 0; pmmformatinfo->ulLanguage = 0; pmmformatinfo->lNameLength = 21; return MMIO_SUCCESS; } break; case MMIOM_GETFORMATNAME: if (lParam2 > 21) { strcpy((PSZ)lParam1, "Ogg Vorbis"); return MMIO_SUCCESS; } else return MMIO_ERROR; break; case MMIOM_QUERYHEADERLENGTH: return (sizeof (MMAUDIOHEADER)); break; case MMIOM_GETHEADER: { OggVorbis_File *oggfile; DecInfo *decInfo; PMMAUDIOHEADER mmaudioheader; vorbis_info *vi; if (!pmmioinfo || !pmmioinfo->pExtraInfoStruct) return 0; if (!(pmmioinfo->ulFlags & MMIO_READ)) return 0; decInfo = (DecInfo *)pmmioinfo->pExtraInfoStruct; oggfile = &decInfo->oggfile; if (READNUM != decInfo->t){ pmmioinfo->ulErrorRet = MMIOERR_INVALID_STRUCTURE; return 0; } #ifdef DEBUG fprintf(file,"HERE\n"); #endif if (!(pmmioinfo->ulTranslate & MMIO_TRANSLATEHEADER) && !(pmmioinfo->ulTranslate & MMIO_TRANSLATEDATA)) return 0; mmaudioheader = (MMAUDIOHEADER *)lParam1; if (sizeof(MMAUDIOHEADER) > lParam2) { pmmioinfo->ulErrorRet = MMIOERR_INVALID_BUFFER_LENGTH; return 0; } #ifdef DEBUG fprintf(file,"THERE\n"); #endif vi = ov_info(oggfile, -1); if (!vi) { pmmioinfo->ulErrorRet = MMIOERR_INVALID_STRUCTURE; return 0; } mmaudioheader->ulContentType = MMIO_MIDI_UNKNOWN; mmaudioheader->ulMediaType = MMIO_MEDIATYPE_AUDIO; mmaudioheader->mmXWAVHeader.WAVEHeader.usFormatTag=DATATYPE_WAVEFORM; mmaudioheader->mmXWAVHeader.WAVEHeader.usChannels = vi->channels; mmaudioheader->mmXWAVHeader.WAVEHeader.ulSamplesPerSec = vi->rate; mmaudioheader->mmXWAVHeader.WAVEHeader.usBitsPerSample = 16; mmaudioheader->mmXWAVHeader.WAVEHeader.ulAvgBytesPerSec= mmaudioheader->mmXWAVHeader.WAVEHeader.usChannels * mmaudioheader->mmXWAVHeader.WAVEHeader.ulSamplesPerSec * mmaudioheader->mmXWAVHeader.WAVEHeader.usBitsPerSample / 8; mmaudioheader->mmXWAVHeader.WAVEHeader.usBlockAlign= mmaudioheader->mmXWAVHeader.WAVEHeader.usChannels * mmaudioheader->mmXWAVHeader.WAVEHeader.usBitsPerSample / 8; mmaudioheader->mmXWAVHeader.XWAVHeaderInfo.ulAudioLengthInMS= (unsigned long)(ov_time_total(oggfile, -1)*1000.0); mmaudioheader->mmXWAVHeader.XWAVHeaderInfo.ulAudioLengthInBytes= (unsigned long)ov_pcm_total(oggfile, -1)* mmaudioheader->mmXWAVHeader.WAVEHeader.usBlockAlign; #ifdef DEBUG fprintf(file,"time: %ld size: %ld rate: %ld\n", mmaudioheader->mmXWAVHeader.XWAVHeaderInfo.ulAudioLengthInMS, mmaudioheader->mmXWAVHeader.XWAVHeaderInfo.ulAudioLengthInBytes, mmaudioheader->mmXWAVHeader.WAVEHeader.ulSamplesPerSec); #endif if (0 != decInfo->vorbisOptions && VORBIS_COOKIE == decInfo->vorbisOptions->cookie) { decInfo->vorbisOptions->nominal_bitrate = ov_bitrate(oggfile, -1); mmaudioheader->mmXWAVHeader.XWAVHeaderInfo.pAdditionalInformation = decInfo->vorbisOptions; } return (sizeof (MMAUDIOHEADER)); } break; case MMIOM_SETHEADER: { EncInfo *encInfo; PMMAUDIOHEADER mmaudioheader; int totalout = 0; int rc; if (!pmmioinfo || !pmmioinfo->pExtraInfoStruct) return 0; encInfo = (EncInfo*)pmmioinfo->pExtraInfoStruct; if (WRITENUM != encInfo->t) return 0; #ifdef DEBUG fprintf(file,"write header: %x, %x, %x\n",!(pmmioinfo->ulFlags & MMIO_WRITE), encInfo->headerSet, (!(pmmioinfo->ulTranslate & MMIO_TRANSLATEHEADER) && !(pmmioinfo->ulTranslate & MMIO_TRANSLATEDATA))); fprintf(file,"flag: %x, trans: %x\n",pmmioinfo->ulFlags,pmmioinfo->ulTranslate); #endif if (/*!(pmmioinfo->ulFlags & MMIO_WRITE) ||*/ encInfo->headerSet || (!(pmmioinfo->ulTranslate & MMIO_TRANSLATEHEADER) && !(pmmioinfo->ulTranslate & MMIO_TRANSLATEDATA))) return 0; if (!lParam1) { pmmioinfo->ulErrorRet = MMIOERR_INVALID_STRUCTURE; return 0; } mmaudioheader = (PMMAUDIOHEADER)lParam1; if (lParam2 != sizeof(MMAUDIOHEADER)) { pmmioinfo->ulErrorRet = MMIOERR_INVALID_BUFFER_LENGTH; return 0; } /********** Encode setup ************/ if (0 != mmaudioheader->mmXWAVHeader.WAVEHeader.usBitsPerSample%8) { /* Bit-rate must be multiple of 8 */ return 0; } encInfo->bitsPerSample=mmaudioheader->mmXWAVHeader.WAVEHeader.usBitsPerSample; #ifdef DEBUG fprintf(file,"ready to write header: "); #endif vorbis_info_init(&encInfo->vi); if (0 == encInfo->vorbisOptions || VORBIS_COOKIE != encInfo->vorbisOptions->cookie) { #ifdef DEBUG fprintf(file,"default quality 0.3\n"); #endif rc = vorbis_encode_init_vbr(&encInfo->vi, mmaudioheader->mmXWAVHeader.WAVEHeader.usChannels, mmaudioheader->mmXWAVHeader.WAVEHeader.ulSamplesPerSec, 0.3); } else { #ifdef DEBUG fprintf(file,"bitsPerSample: %d channels: %d samplesPerSec: %ld min: %ld nominal: %ld max: %ld\n", encInfo->bitsPerSample, mmaudioheader->mmXWAVHeader.WAVEHeader.usChannels, mmaudioheader->mmXWAVHeader.WAVEHeader.ulSamplesPerSec, encInfo->vorbisOptions->max_bitrate, encInfo->vorbisOptions->nominal_bitrate, encInfo->vorbisOptions->min_bitrate); #endif rc = vorbis_encode_init(&encInfo->vi, mmaudioheader->mmXWAVHeader.WAVEHeader.usChannels, mmaudioheader->mmXWAVHeader.WAVEHeader.ulSamplesPerSec, encInfo->vorbisOptions->max_bitrate, encInfo->vorbisOptions->nominal_bitrate, encInfo->vorbisOptions->min_bitrate); } if (rc) { #ifdef DEBUG fprintf(file,"encodeInit failed: %d\n",rc); #endif return 0; } /* endif */ /* add a comment */ vorbis_comment_init(&encInfo->vc); vorbis_comment_add_tag(&encInfo->vc,"ENCODER","mmioVorbis"); /* set up the analysis state and auxiliary encoding storage */ vorbis_analysis_init(&encInfo->vd,&encInfo->vi); vorbis_block_init(&encInfo->vd,&encInfo->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(&encInfo->os,rand()); { ogg_packet header; ogg_packet header_comm; ogg_packet header_code; vorbis_analysis_headerout(&encInfo->vd,&encInfo->vc,&header,&header_comm,&header_code); ogg_stream_packetin(&encInfo->os,&header); /* automatically placed in its own page */ ogg_stream_packetin(&encInfo->os,&header_comm); ogg_stream_packetin(&encInfo->os,&header_code); while(1){ int result=ogg_stream_flush(&encInfo->os,&encInfo->og); if(result==0)break; result = mmioWrite(encInfo->hmmioSS, encInfo->og.header,encInfo->og.header_len); totalout += result; if (result!=encInfo->og.header_len) { ogg_stream_clear(&encInfo->os); vorbis_block_clear(&encInfo->vb); vorbis_dsp_clear(&encInfo->vd); vorbis_comment_clear(&encInfo->vc); vorbis_info_clear(&encInfo->vi); return 0; } result = mmioWrite(encInfo->hmmioSS, encInfo->og.body,encInfo->og.body_len); totalout += result; if (result!=encInfo->og.body_len) { ogg_stream_clear(&encInfo->os); vorbis_block_clear(&encInfo->vb); vorbis_dsp_clear(&encInfo->vd); vorbis_comment_clear(&encInfo->vc); vorbis_info_clear(&encInfo->vi); return 0; } } } encInfo->headerSet = 1; return totalout; } break; case MMIOM_WRITE: { EncInfo *encInfo; if (!pmmioinfo || !pmmioinfo->pExtraInfoStruct) return MMIO_ERROR; encInfo = (EncInfo*)pmmioinfo->pExtraInfoStruct; if (WRITENUM != encInfo->t) return MMIO_ERROR; if (!encInfo->headerSet) return MMIO_ERROR; if (!(pmmioinfo->ulTranslate & MMIO_TRANSLATEDATA)) { if (!lParam1) return MMIO_ERROR; return mmioWrite(encInfo->hmmioSS, (PVOID)lParam1, lParam2); } else { if (lParam2 == 0) { vorbis_analysis_wrote(&encInfo->vd,0); } else { long i; int j, k; int num; float denom = 1; signed char *readbuffer = (char *)lParam1; /* data to encode */ /* expose the buffer to submit data */ int sampleSize = encInfo->vi.channels*encInfo->bitsPerSample/8; int samples = lParam2/sampleSize; float **buffer=vorbis_analysis_buffer(&encInfo->vd, samples); #ifdef DEBUG fprintf(file,"write: %ld\n",lParam2); #endif /* :TODO: Work with buffers not a multiple of sampleSize*/ if (lParam2 % sampleSize != 0) { #ifdef DEBUG fprintf(file,"Bad Write Buffer Size\n"); #endif return MMIO_ERROR; } for(i=0;i<samples;i++){ for (j=0;j<encInfo->vi.channels;j++) { num=0; denom=0.5; if (encInfo->bitsPerSample<=8) { buffer[j][i]=(float)((unsigned char)(readbuffer[i*sampleSize])- (1<<(encInfo->bitsPerSample-1)))/ (float)(1<<(encInfo->bitsPerSample-1)); } else { for (k=encInfo->bitsPerSample/8;k>0;k--) { if (k==encInfo->bitsPerSample/8) { num=(readbuffer[i*sampleSize+k-1]); } else { num=(num<<8)|((0xff)&(int)(readbuffer[i*sampleSize+k-1])); } denom *= 256.0; } buffer[j][i]=((float)num)/denom; } } /* endfor */ } vorbis_analysis_wrote(&encInfo->vd,i); } /* endif */ if (oggWrite(encInfo,0)>=0) { return lParam2; } else { return MMIO_ERROR; } /* endif */ } } break; #ifdef DEBUG case MMIOM_TEMPCHANGE: { return MMIO_SUCCESS; } break; #endif } #ifdef DEBUG fprintf(file,"unexpected command: %x\n",usMsg); #endif return MMIOERR_UNSUPPORTED_MESSAGE; }
/* all of the real encoding details are here. The modes, books, everything */ static int _vorbis_unpack_books(vorbis_info *vi,oggpack_buffer *opb) { codec_setup_info *ci=(codec_setup_info *)vi->codec_setup; int i; if(!ci)return(OV_EFAULT); /* codebooks */ ci->books=oggpack_read(opb,8)+1; /*ci->book_param=_ogg_calloc(ci->books,sizeof(*ci->book_param));*/ for(i=0; i<ci->books; i++) { ci->book_param[i]=(static_codebook *)_ogg_calloc(1,sizeof(*ci->book_param[i])); if(vorbis_staticbook_unpack(opb,ci->book_param[i]))goto err_out; } /* time backend settings */ ci->times=oggpack_read(opb,6)+1; /*ci->time_type=_ogg_malloc(ci->times*sizeof(*ci->time_type));*/ /*ci->time_param=_ogg_calloc(ci->times,sizeof(void *));*/ for(i=0; i<ci->times; i++) { ci->time_type[i]=oggpack_read(opb,16); if(ci->time_type[i]<0 || ci->time_type[i]>=VI_TIMEB)goto err_out; /* ci->time_param[i]=_time_P[ci->time_type[i]]->unpack(vi,opb); Vorbis I has no time backend */ /*if(!ci->time_param[i])goto err_out;*/ } /* floor backend settings */ ci->floors=oggpack_read(opb,6)+1; /*ci->floor_type=_ogg_malloc(ci->floors*sizeof(*ci->floor_type));*/ /*ci->floor_param=_ogg_calloc(ci->floors,sizeof(void *));*/ for(i=0; i<ci->floors; i++) { ci->floor_type[i]=oggpack_read(opb,16); if(ci->floor_type[i]<0 || ci->floor_type[i]>=VI_FLOORB)goto err_out; ci->floor_param[i]=_floor_P[ci->floor_type[i]]->unpack(vi,opb); if(!ci->floor_param[i])goto err_out; } /* residue backend settings */ ci->residues=oggpack_read(opb,6)+1; /*ci->residue_type=_ogg_malloc(ci->residues*sizeof(*ci->residue_type));*/ /*ci->residue_param=_ogg_calloc(ci->residues,sizeof(void *));*/ for(i=0; i<ci->residues; i++) { ci->residue_type[i]=oggpack_read(opb,16); if(ci->residue_type[i]<0 || ci->residue_type[i]>=VI_RESB)goto err_out; ci->residue_param[i]=_residue_P[ci->residue_type[i]]->unpack(vi,opb); if(!ci->residue_param[i])goto err_out; } /* map backend settings */ ci->maps=oggpack_read(opb,6)+1; /*ci->map_type=_ogg_malloc(ci->maps*sizeof(*ci->map_type));*/ /*ci->map_param=_ogg_calloc(ci->maps,sizeof(void *));*/ for(i=0; i<ci->maps; i++) { ci->map_type[i]=oggpack_read(opb,16); if(ci->map_type[i]<0 || ci->map_type[i]>=VI_MAPB)goto err_out; ci->map_param[i]=_mapping_P[ci->map_type[i]]->unpack(vi,opb); if(!ci->map_param[i])goto err_out; } /* mode settings */ ci->modes=oggpack_read(opb,6)+1; /*vi->mode_param=_ogg_calloc(vi->modes,sizeof(void *));*/ for(i=0; i<ci->modes; i++) { ci->mode_param[i]=(vorbis_info_mode *)_ogg_calloc(1,sizeof(*ci->mode_param[i])); ci->mode_param[i]->blockflag=oggpack_read(opb,1); ci->mode_param[i]->windowtype=oggpack_read(opb,16); ci->mode_param[i]->transformtype=oggpack_read(opb,16); ci->mode_param[i]->mapping=oggpack_read(opb,8); if(ci->mode_param[i]->windowtype>=VI_WINDOWB)goto err_out; if(ci->mode_param[i]->transformtype>=VI_WINDOWB)goto err_out; if(ci->mode_param[i]->mapping>=ci->maps)goto err_out; } if(oggpack_read(opb,1)!=1)goto err_out; /* top level EOP check */ return(0); err_out: vorbis_info_clear(vi); return(OV_EBADHEADER); }
//Method to start encoding int startEncoding(JNIEnv *env, jclass *cls_ptr, jlong *sampleRate_ptr, jlong *channels_ptr, jfloat *quality_ptr, jlong *bitrate_ptr, jobject *encoderDataFeed_ptr, int type) { //Dereference our variables jclass cls = (*cls_ptr); jlong sampleRate = (*sampleRate_ptr); jlong channels = (*channels_ptr); jfloat quality = (*quality_ptr); jlong bitrate = (*bitrate_ptr); jobject encoderDataFeed = (*encoderDataFeed_ptr); //Create our PCM data buffer signed char readbuffer[READ*4+44]; //Create a new java byte array to pass to the data feed method jbyteArray jByteArrayBuffer = (*env)->NewByteArray(env, READ*4); //Create a new java byte buffer to write to jbyteArray jByteArrayWriteBuffer = (*env)->NewByteArray(env, READ*8); //Find our java classes we'll be calling jclass encoderDataFeedClass = (*env)->FindClass(env, "org/xiph/vorbis/encoder/EncodeFeed"); //Find our java method id's we'll be calling jmethodID writeVorbisDataMethodId = (*env)->GetMethodID(env, encoderDataFeedClass, "writeVorbisData", "([BI)I"); jmethodID readPCMDataMethodId = (*env)->GetMethodID(env, encoderDataFeedClass, "readPCMData", "([BI)J"); jmethodID startMethodId = (*env)->GetMethodID(env, encoderDataFeedClass, "start", "()V"); jmethodID stopMethodId = (*env)->GetMethodID(env, encoderDataFeedClass, "stop", "()V"); 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; /********** Encode setup ************/ __android_log_print(ANDROID_LOG_INFO, "VorbisEncoder", "Setting up encoding"); 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)); *********************************************************************/ switch(type) { case WITH_BITRATE: __android_log_print(ANDROID_LOG_INFO, "VorbisEncoder", "Initializing with %lld channels %lldHz sample rate and %lld bitrate", channels, sampleRate, bitrate); ret=vorbis_encode_init(&vi, (long)channels, (long)sampleRate, (long)-1, (long)bitrate, (long)-1); break; case WITH_QUALITY: __android_log_print(ANDROID_LOG_INFO, "VorbisEncoder", "Initializing with %lld channels %lldHz sample rate and %f quality", channels, sampleRate, quality); ret=vorbis_encode_init_vbr(&vi, (long)channels, (long)sampleRate, (float)quality); break; default: __android_log_print(ANDROID_LOG_ERROR, "VorbisEncoder", "Failed to initialize"); stopEncodeFeed(env, &encoderDataFeed, &stopMethodId); return ERROR_INITIALIZING; } /* 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) { __android_log_print(ANDROID_LOG_ERROR, "VorbisEncoder", "Failed to initialize"); stopEncodeFeed(env, &encoderDataFeed, &stopMethodId); return ERROR_INITIALIZING; } startEncodeFeed(env, &encoderDataFeed, &startMethodId); /* add a comment */ __android_log_print(ANDROID_LOG_DEBUG, "VorbisEncoder", "Adding comments"); vorbis_comment_init(&vc); vorbis_comment_add_tag(&vc,"ENCODER","JNIVorbisEncoder"); /* 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 */ __android_log_print(ANDROID_LOG_INFO, "VorbisEncoder", "Writting header"); while(!eos){ int result=ogg_stream_flush(&os,&og); if(result==0)break; writeVorbisDataToEncoderDataFeed(env, &encoderDataFeed, &writeVorbisDataMethodId, og.header, og.header_len, &jByteArrayWriteBuffer); writeVorbisDataToEncoderDataFeed(env, &encoderDataFeed, &writeVorbisDataMethodId, og.body, og.body_len, &jByteArrayWriteBuffer); } } __android_log_print(ANDROID_LOG_INFO, "VorbisEncoder", "Starting to read from pcm callback"); while(!eos){ long i; long bytes = readPCMDataFromEncoderDataFeed(env, &encoderDataFeed, &readPCMDataMethodId, readbuffer, READ*4, &jByteArrayBuffer); 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 */ __android_log_print(ANDROID_LOG_INFO, "VorbisEncoder", "End of file"); vorbis_analysis_wrote(&vd,0); }else{ /* data to encode */ /* expose the buffer to submit data */ float **buffer=vorbis_analysis_buffer(&vd,bytes/(2*channels)); /* uninterleave samples */ int channel; for(i=0;i<bytes/(2*channels);i++) { for(channel = 0; channel < channels; channel++) { buffer[channel][i]=((readbuffer[i*(2*channels)+(channel*2+1)]<<8)| (0x00ff&(int)readbuffer[i*(2*channels)+(channel*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; writeVorbisDataToEncoderDataFeed(env, &encoderDataFeed, &writeVorbisDataMethodId, og.header, og.header_len, &jByteArrayWriteBuffer); writeVorbisDataToEncoderDataFeed(env, &encoderDataFeed, &writeVorbisDataMethodId, og.body, og.body_len, &jByteArrayWriteBuffer); /* 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 */ __android_log_print(ANDROID_LOG_INFO, "VorbisEncoder", "Cleaning up encoder"); 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 */ __android_log_print(ANDROID_LOG_INFO, "VorbisEncoder", "Completed encoding."); stopEncodeFeed(env, &encoderDataFeed, &stopMethodId); //Clean up encode buffers (*env)->DeleteLocalRef(env, jByteArrayBuffer); (*env)->DeleteLocalRef(env, jByteArrayWriteBuffer); return SUCCESS; }
virtual bool Cook(FName Format, const TArray<uint8>& SrcBuffer, FSoundQualityInfo& QualityInfo, TArray<uint8>& CompressedDataStore) const { check(Format == NAME_OGG); #if WITH_OGGVORBIS { short ReadBuffer[SAMPLES_TO_READ * SAMPLE_SIZE * 2]; 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 uint32 i; bool eos; // Create a buffer to store compressed data CompressedDataStore.Empty(); FMemoryWriter CompressedData( CompressedDataStore ); uint32 BufferOffset = 0; float CompressionQuality = ( float )( QualityInfo.Quality + VORBIS_QUALITY_MODIFIER ) / 100.0f; CompressionQuality = FMath::Clamp( CompressionQuality, -0.1f, 1.0f ); vorbis_info_init( &vi ); if( vorbis_encode_init_vbr( &vi, QualityInfo.NumChannels, QualityInfo.SampleRate, CompressionQuality ) ) { return false; } // add a comment vorbis_comment_init( &vc ); vorbis_comment_add_tag( &vc, "ENCODER", "UnrealEngine4" ); // 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 ogg_stream_init( &os, 0 ); 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 ); 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( true ) { int result = ogg_stream_flush( &os, &og ); if( result == 0 ) { break; } CompressedData.Serialize( og.header, og.header_len ); CompressedData.Serialize( og.body, og.body_len ); } eos = false; while( !eos ) { // Read samples uint32 BytesToRead = FMath::Min( SAMPLES_TO_READ * QualityInfo.NumChannels * SAMPLE_SIZE, QualityInfo.SampleDataSize - BufferOffset ); FMemory::Memcpy( ReadBuffer, SrcBuffer.GetTypedData() + BufferOffset, BytesToRead ); BufferOffset += BytesToRead; if( BytesToRead == 0) { // end of file vorbis_analysis_wrote( &vd, 0 ); } else { // expose the buffer to submit data float **buffer = vorbis_analysis_buffer( &vd, SAMPLES_TO_READ ); if( QualityInfo.NumChannels == 1 ) { for( i = 0; i < BytesToRead / SAMPLE_SIZE; i++ ) { buffer[0][i] = ( ReadBuffer[i] ) / 32768.0f; } } else { for( i = 0; i < BytesToRead / ( SAMPLE_SIZE * 2 ); i++ ) { buffer[0][i] = ( ReadBuffer[i * 2] ) / 32768.0f; buffer[1][i] = ( ReadBuffer[i * 2 + 1] ) / 32768.0f; } } // tell the library how many samples we actually submitted vorbis_analysis_wrote( &vd, i ); } // vorbis does some data preanalysis, then divvies up blocks for more involved (potentially parallel) processing. 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; } CompressedData.Serialize( og.header, og.header_len ); CompressedData.Serialize( 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 = true; } } } } } // 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 } return CompressedDataStore.Num() > 0; #else return false; #endif // WITH_OGGVOBVIS }
int ExportOGG::Export(AudacityProject *project, int numChannels, wxString fName, bool selectionOnly, double t0, double t1, MixerSpec *mixerSpec, Tags *metadata, int WXUNUSED(subformat)) { double rate = project->GetRate(); TrackList *tracks = project->GetTracks(); double quality = (gPrefs->Read(wxT("/FileFormats/OggExportQuality"), 50)/(float)100.0); wxLogNull logNo; // temporarily disable wxWidgets error messages int updateResult = eProgressSuccess; int eos = 0; FileIO outFile(fName, FileIO::Output); if (!outFile.IsOpened()) { wxMessageBox(_("Unable to open target file for writing")); return false; } // All the Ogg and Vorbis encoding data ogg_stream_state stream; ogg_page page; ogg_packet packet; vorbis_info info; vorbis_comment comment; vorbis_dsp_state dsp; vorbis_block block; // Encoding setup vorbis_info_init(&info); vorbis_encode_init_vbr(&info, numChannels, int(rate + 0.5), quality); // Retrieve tags if (!FillComment(project, &comment, metadata)) { return false; } // Set up analysis state and auxiliary encoding storage vorbis_analysis_init(&dsp, &info); vorbis_block_init(&dsp, &block); // Set up packet->stream encoder. According to encoder example, // a random serial number makes it more likely that you can make // chained streams with concatenation. srand(time(NULL)); ogg_stream_init(&stream, rand()); // First we need to write the required headers: // 1. The Ogg bitstream header, which contains codec setup params // 2. The Vorbis comment header // 3. The bitstream codebook. // // After we create those our responsibility is complete, libvorbis will // take care of any other ogg bistream constraints (again, according // to the example encoder source) ogg_packet bitstream_header; ogg_packet comment_header; ogg_packet codebook_header; vorbis_analysis_headerout(&dsp, &comment, &bitstream_header, &comment_header, &codebook_header); // Place these headers into the stream ogg_stream_packetin(&stream, &bitstream_header); ogg_stream_packetin(&stream, &comment_header); ogg_stream_packetin(&stream, &codebook_header); // Flushing these headers now guarentees that audio data will // start on a NEW page, which apparently makes streaming easier while (ogg_stream_flush(&stream, &page)) { outFile.Write(page.header, page.header_len); outFile.Write(page.body, page.body_len); } int numWaveTracks; WaveTrack **waveTracks; tracks->GetWaveTracks(selectionOnly, &numWaveTracks, &waveTracks); Mixer *mixer = CreateMixer(numWaveTracks, waveTracks, tracks->GetTimeTrack(), t0, t1, numChannels, SAMPLES_PER_RUN, false, rate, floatSample, true, mixerSpec); delete [] waveTracks; ProgressDialog *progress = new ProgressDialog(wxFileName(fName).GetName(), selectionOnly ? _("Exporting the selected audio as Ogg Vorbis") : _("Exporting the entire project as Ogg Vorbis")); while (updateResult == eProgressSuccess && !eos) { float **vorbis_buffer = vorbis_analysis_buffer(&dsp, SAMPLES_PER_RUN); sampleCount samplesThisRun = mixer->Process(SAMPLES_PER_RUN); if (samplesThisRun == 0) { // Tell the library that we wrote 0 bytes - signalling the end. vorbis_analysis_wrote(&dsp, 0); } else { for (int i = 0; i < numChannels; i++) { float *temp = (float *)mixer->GetBuffer(i); memcpy(vorbis_buffer[i], temp, sizeof(float)*SAMPLES_PER_RUN); } // tell the encoder how many samples we have vorbis_analysis_wrote(&dsp, samplesThisRun); } // I don't understand what this call does, so here is the comment // from the example, verbatim: // // 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(&dsp, &block) == 1) { // analysis, assume we want to use bitrate management vorbis_analysis(&block, NULL); vorbis_bitrate_addblock(&block); while (vorbis_bitrate_flushpacket(&dsp, &packet)) { // add the packet to the bitstream ogg_stream_packetin(&stream, &packet); // From vorbis-tools-1.0/oggenc/encode.c: // If we've gone over a page boundary, we can do actual output, // so do so (for however many pages are available). while (!eos) { int result = ogg_stream_pageout(&stream, &page); if (!result) { break; } outFile.Write(page.header, page.header_len); outFile.Write(page.body, page.body_len); if (ogg_page_eos(&page)) { eos = 1; } } } } updateResult = progress->Update(mixer->MixGetCurrentTime()-t0, t1-t0); } delete progress;; delete mixer; ogg_stream_clear(&stream); vorbis_block_clear(&block); vorbis_dsp_clear(&dsp); vorbis_info_clear(&info); vorbis_comment_clear(&comment); outFile.Close(); return updateResult; }
int OggDecode( wsul nSize, wsfb *bData, int nBit, wsf_file *wOut ) { 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; wsf_file *wIn; wIn = wsfopenmem(bData,nSize); /********** Decode setup ************/ 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=wsfread(buffer,4096,wIn); 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 */ return 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 */ return 1; } if(ogg_stream_packetout(&os,&op)!=1) { /* no page? must not be vorbis */ return 1; } if(vorbis_synthesis_headerin(&vi,&vc,&op)<0) { /* error case; not a vorbis header */ return 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 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(&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. */ return 1; } vorbis_synthesis_headerin(&vi,&vc,&op); i++; } } } /* no harm in not checking before adding more */ buffer=ogg_sync_buffer(&oy,4096); bytes=wsfread(buffer,4096,wIn); if(bytes==0 && i<2) { return 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) { ++ptr; } } convsize=4096/vi.channels; /* OK, got and parsed all three headers. Initialize the Vorbis packet->PCM decoder. */ vorbis_synthesis_init(&vd,&vi); /* 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,""); } 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); if (nBit == 16) { /* 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=(int)(mono[j]*32767.f); #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; } } } else { /* convert floats to 8 bit signed ints (host order) and interleave */ for(i=0; i<vi.channels; i++) { char *ptr=(char*)convbuffer+i; float *mono=pcm[i]; for(j=0; j<bout; j++) { int val=(int)(mono[j]*127.f); /* might as well guard against clipping */ if(val>127) { val=127; clipflag=1; } if(val<-128) { val=-128; clipflag=1; } *ptr=val; ptr+=vi.channels; } } } wsfwrite(convbuffer,(nBit/8)*vi.channels*bout,wOut); 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=wsfread(buffer,4096,wIn); ogg_sync_wrote(&oy,bytes); if(bytes==0)eos=1; } } /* 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_comment_clear(&vc); vorbis_info_clear(&vi); /* must be called last */ } /* OK, clean up the framer */ ogg_sync_clear(&oy); wsfclose(wIn); return(0); }
/***************************************************************************** * OpenEncoder: probe the encoder and return score *****************************************************************************/ static int OpenEncoder( vlc_object_t *p_this ) { encoder_t *p_enc = (encoder_t *)p_this; encoder_sys_t *p_sys; int i_quality, i_min_bitrate, i_max_bitrate; ogg_packet header[3]; if( p_enc->fmt_out.i_codec != VLC_CODEC_VORBIS && !p_enc->b_force ) { return VLC_EGENERIC; } /* Allocate the memory needed to store the decoder's structure */ if( ( p_sys = (encoder_sys_t *)malloc(sizeof(encoder_sys_t)) ) == NULL ) return VLC_ENOMEM; p_enc->p_sys = p_sys; p_enc->pf_encode_audio = Encode; p_enc->fmt_in.i_codec = VLC_CODEC_FL32; p_enc->fmt_out.i_codec = VLC_CODEC_VORBIS; config_ChainParse( p_enc, ENC_CFG_PREFIX, ppsz_enc_options, p_enc->p_cfg ); i_quality = var_GetInteger( p_enc, ENC_CFG_PREFIX "quality" ); if( i_quality > 10 ) i_quality = 10; if( i_quality < 0 ) i_quality = 0; if( var_GetBool( p_enc, ENC_CFG_PREFIX "cbr" ) ) i_quality = 0; i_max_bitrate = var_GetInteger( p_enc, ENC_CFG_PREFIX "max-bitrate" ); i_min_bitrate = var_GetInteger( p_enc, ENC_CFG_PREFIX "min-bitrate" ); /* Initialize vorbis encoder */ vorbis_info_init( &p_sys->vi ); if( i_quality > 0 ) { /* VBR mode */ if( vorbis_encode_setup_vbr( &p_sys->vi, p_enc->fmt_in.audio.i_channels, p_enc->fmt_in.audio.i_rate, i_quality * 0.1 ) ) { vorbis_info_clear( &p_sys->vi ); free( p_enc->p_sys ); msg_Err( p_enc, "VBR mode initialisation failed" ); return VLC_EGENERIC; } /* Do we have optional hard quality restrictions? */ if( i_max_bitrate > 0 || i_min_bitrate > 0 ) { struct ovectl_ratemanage_arg ai; vorbis_encode_ctl( &p_sys->vi, OV_ECTL_RATEMANAGE_GET, &ai ); ai.bitrate_hard_min = i_min_bitrate; ai.bitrate_hard_max = i_max_bitrate; ai.management_active = 1; vorbis_encode_ctl( &p_sys->vi, OV_ECTL_RATEMANAGE_SET, &ai ); } else { /* Turn off management entirely */ vorbis_encode_ctl( &p_sys->vi, OV_ECTL_RATEMANAGE_SET, NULL ); } } else { if( vorbis_encode_setup_managed( &p_sys->vi, p_enc->fmt_in.audio.i_channels, p_enc->fmt_in.audio.i_rate, i_min_bitrate > 0 ? i_min_bitrate * 1000: -1, p_enc->fmt_out.i_bitrate, i_max_bitrate > 0 ? i_max_bitrate * 1000: -1 ) ) { vorbis_info_clear( &p_sys->vi ); msg_Err( p_enc, "CBR mode initialisation failed" ); free( p_enc->p_sys ); return VLC_EGENERIC; } } vorbis_encode_setup_init( &p_sys->vi ); /* Add a comment */ vorbis_comment_init( &p_sys->vc); vorbis_comment_add_tag( &p_sys->vc, "ENCODER", "VLC media player"); /* Set up the analysis state and auxiliary encoding storage */ vorbis_analysis_init( &p_sys->vd, &p_sys->vi ); vorbis_block_init( &p_sys->vd, &p_sys->vb ); /* Create and store headers */ vorbis_analysis_headerout( &p_sys->vd, &p_sys->vc, &header[0], &header[1], &header[2]); for( int i = 0; i < 3; i++ ) { if( xiph_AppendHeaders( &p_enc->fmt_out.i_extra, &p_enc->fmt_out.p_extra, header[i].bytes, header[i].packet ) ) { p_enc->fmt_out.i_extra = 0; p_enc->fmt_out.p_extra = NULL; } } p_sys->i_channels = p_enc->fmt_in.audio.i_channels; p_sys->i_last_block_size = 0; p_sys->i_samples_delay = 0; ConfigureChannelOrder(p_sys->pi_chan_table, p_sys->vi.channels, p_enc->fmt_in.audio.i_physical_channels, true); return VLC_SUCCESS; }
static int ogg_read_header (SF_PRIVATE *psf, int log_data) { OGG_PRIVATE *odata = (OGG_PRIVATE *) psf->container_data ; VORBIS_PRIVATE *vdata = (VORBIS_PRIVATE *) psf->codec_data ; char *buffer ; int bytes ; int i, nn ; odata->eos = 0 ; /* Weird stuff happens if these aren't called. */ ogg_stream_reset (&odata->os) ; ogg_sync_reset (&odata->oy) ; /* ** 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. */ /* Expose the buffer */ buffer = ogg_sync_buffer (&odata->oy, 4096L) ; /* Grab the part of the header that has already been read. */ memcpy (buffer, psf->header, psf->headindex) ; bytes = psf->headindex ; /* Submit a 4k block to libvorbis' Ogg layer */ bytes += (int)psf_fread (buffer + psf->headindex, 1, 4096 - psf->headindex, psf) ; ogg_sync_wrote (&odata->oy, bytes) ; /* Get the first page. */ if ((nn = ogg_sync_pageout (&odata->oy, &odata->og)) != 1) { /* Have we simply run out of data? If so, we're done. */ if (bytes < 4096) return 0 ; /* Error case. Must not be Vorbis data */ psf_log_printf (psf, "Input does not appear to be an Ogg bitstream.\n") ; return SFE_MALFORMED_FILE ; } ; /* ** Get the serial number and set up the rest of decode. ** Serialno first ; use it to set up a logical stream. */ ogg_stream_clear (&odata->os) ; ogg_stream_init (&odata->os, ogg_page_serialno (&odata->og)) ; /* ** This function (ogg_read_header) gets called multiple times, so the OGG ** and vorbis structs have to be cleared every time we pass through to ** prevent memory leaks. */ vorbis_block_clear (&vdata->vb) ; vorbis_dsp_clear (&vdata->vd) ; vorbis_comment_clear (&vdata->vc) ; vorbis_info_clear (&vdata->vi) ; /* ** 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 (&vdata->vi) ; vorbis_comment_init (&vdata->vc) ; if (ogg_stream_pagein (&odata->os, &odata->og) < 0) { /* Error ; stream version mismatch perhaps. */ psf_log_printf (psf, "Error reading first page of Ogg bitstream data\n") ; return SFE_MALFORMED_FILE ; } ; if (ogg_stream_packetout (&odata->os, &odata->op) != 1) { /* No page? must not be vorbis. */ psf_log_printf (psf, "Error reading initial header packet.\n") ; return SFE_MALFORMED_FILE ; } ; if (vorbis_synthesis_headerin (&vdata->vi, &vdata->vc, &odata->op) < 0) { /* Error case ; not a vorbis header. */ psf_log_printf (psf, "This Ogg bitstream does not contain Vorbis audio data.\n") ; return SFE_MALFORMED_FILE ; } ; /* ** Common Ogg metadata fields? ** TITLE, VERSION, ALBUM, TRACKNUMBER, ARTIST, PERFORMER, COPYRIGHT, LICENSE, ** ORGANIZATION, DESCRIPTION, GENRE, DATE, LOCATION, CONTACT, ISRC, */ if (log_data) { int k ; for (k = 0 ; k < ARRAY_LEN (vorbis_metatypes) ; k++) { char *dd ; dd = vorbis_comment_query (&vdata->vc, vorbis_metatypes [k].name, 0) ; if (dd == NULL) continue ; psf_store_string (psf, vorbis_metatypes [k].id, dd) ; } ; } ; /* ** 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 ; /* Count of number of packets read */ while (i < 2) { int result = ogg_sync_pageout (&odata->oy, &odata->og) ; if (result == 0) { /* Need more data */ buffer = ogg_sync_buffer (&odata->oy, 4096) ; bytes = (int)psf_fread (buffer, 1, 4096, psf) ; if (bytes == 0 && i < 2) { psf_log_printf (psf, "End of file before finding all Vorbis headers!\n") ; return SFE_MALFORMED_FILE ; } ; nn = ogg_sync_wrote (&odata->oy, bytes) ; } else if (result == 1) { /* ** Don't complain about missing or corrupt data yet. We'll ** catch it at the packet output phase. ** ** We can ignore any errors here as they'll also become apparent ** at packetout. */ nn = ogg_stream_pagein (&odata->os, &odata->og) ; while (i < 2) { result = ogg_stream_packetout (&odata->os, &odata->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. */ psf_log_printf (psf, "Corrupt secondary header. Exiting.\n") ; return SFE_MALFORMED_FILE ; } ; vorbis_synthesis_headerin (&vdata->vi, &vdata->vc, &odata->op) ; i++ ; } ; } ; } ; if (log_data) { int printed_metadata_msg = 0 ; int k ; psf_log_printf (psf, "\nBitstream is %d channel, %D Hz\n", vdata->vi.channels, vdata->vi.rate) ; psf_log_printf (psf, "Encoded by: %s\n", vdata->vc.vendor) ; /* Throw the comments plus a few lines about the bitstream we're decoding. */ for (k = 0 ; k < ARRAY_LEN (vorbis_metatypes) ; k++) { char *dd ; dd = vorbis_comment_query (&vdata->vc, vorbis_metatypes [k].name, 0) ; if (dd == NULL) continue ; if (printed_metadata_msg == 0) { psf_log_printf (psf, "Metadata :\n") ; printed_metadata_msg = 1 ; } ; psf_store_string (psf, vorbis_metatypes [k].id, dd) ; psf_log_printf (psf, " %-10s : %s\n", vorbis_metatypes [k].name, dd) ; } ; psf_log_printf (psf, "End\n") ; } ; psf->sf.samplerate = vdata->vi.rate ; psf->sf.channels = vdata->vi.channels ; psf->sf.format = SF_FORMAT_OGG | SF_FORMAT_VORBIS ; /* OK, got and parsed all three headers. Initialize the Vorbis ** packet->PCM decoder. ** Central decode state. */ vorbis_synthesis_init (&vdata->vd, &vdata->vi) ; /* 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. */ vorbis_block_init (&vdata->vd, &vdata->vb) ; vdata->loc = 0 ; return 0 ; } /* ogg_read_header */
static gboolean gst_vorbis_enc_setup (GstVorbisEnc * vorbisenc) { GST_LOG_OBJECT (vorbisenc, "setup"); if (vorbisenc->bitrate < 0 && vorbisenc->min_bitrate < 0 && vorbisenc->max_bitrate < 0) { vorbisenc->quality_set = TRUE; } update_start_message (vorbisenc); /* choose an encoding mode */ /* (mode 0: 44kHz stereo uncoupled, roughly 128kbps VBR) */ vorbis_info_init (&vorbisenc->vi); if (vorbisenc->quality_set) { if (vorbis_encode_setup_vbr (&vorbisenc->vi, vorbisenc->channels, vorbisenc->frequency, vorbisenc->quality) != 0) { GST_ERROR_OBJECT (vorbisenc, "vorbisenc: initialisation failed: invalid parameters for quality"); vorbis_info_clear (&vorbisenc->vi); return FALSE; } /* do we have optional hard quality restrictions? */ if (vorbisenc->max_bitrate > 0 || vorbisenc->min_bitrate > 0) { struct ovectl_ratemanage_arg ai; vorbis_encode_ctl (&vorbisenc->vi, OV_ECTL_RATEMANAGE_GET, &ai); ai.bitrate_hard_min = vorbisenc->min_bitrate; ai.bitrate_hard_max = vorbisenc->max_bitrate; ai.management_active = 1; vorbis_encode_ctl (&vorbisenc->vi, OV_ECTL_RATEMANAGE_SET, &ai); } } else { long min_bitrate, max_bitrate; min_bitrate = vorbisenc->min_bitrate > 0 ? vorbisenc->min_bitrate : -1; max_bitrate = vorbisenc->max_bitrate > 0 ? vorbisenc->max_bitrate : -1; if (vorbis_encode_setup_managed (&vorbisenc->vi, vorbisenc->channels, vorbisenc->frequency, max_bitrate, vorbisenc->bitrate, min_bitrate) != 0) { GST_ERROR_OBJECT (vorbisenc, "vorbis_encode_setup_managed " "(c %d, rate %d, max br %ld, br %d, min br %ld) failed", vorbisenc->channels, vorbisenc->frequency, max_bitrate, vorbisenc->bitrate, min_bitrate); vorbis_info_clear (&vorbisenc->vi); return FALSE; } } if (vorbisenc->managed && vorbisenc->bitrate < 0) { vorbis_encode_ctl (&vorbisenc->vi, OV_ECTL_RATEMANAGE_AVG, NULL); } else if (!vorbisenc->managed) { /* Turn off management entirely (if it was turned on). */ vorbis_encode_ctl (&vorbisenc->vi, OV_ECTL_RATEMANAGE_SET, NULL); } vorbis_encode_setup_init (&vorbisenc->vi); /* set up the analysis state and auxiliary encoding storage */ vorbis_analysis_init (&vorbisenc->vd, &vorbisenc->vi); vorbis_block_init (&vorbisenc->vd, &vorbisenc->vb); /* samples == granulepos start at 0 again */ vorbisenc->samples_out = 0; /* fresh encoder available */ vorbisenc->setup = TRUE; return TRUE; }
bool TheoraDecoder::loadStream(Common::SeekableReadStream *stream) { close(); _endOfAudio = false; _endOfVideo = false; _fileStream = stream; // start up Ogg stream synchronization layer ogg_sync_init(&_oggSync); // init supporting Vorbis structures needed in header parsing vorbis_info_init(&_vorbisInfo); vorbis_comment_init(&_vorbisComment); // init supporting Theora structures needed in header parsing th_comment_init(&_theoraComment); th_info_init(&_theoraInfo); // Ogg file open; parse the headers // Only interested in Vorbis/Theora streams bool foundHeader = false; while (!foundHeader) { int ret = bufferData(); if (ret == 0) break; while (ogg_sync_pageout(&_oggSync, &_oggPage) > 0) { ogg_stream_state test; // is this a mandated initial header? If not, stop parsing if (!ogg_page_bos(&_oggPage)) { // don't leak the page; get it into the appropriate stream queuePage(&_oggPage); foundHeader = true; break; } ogg_stream_init(&test, ogg_page_serialno(&_oggPage)); ogg_stream_pagein(&test, &_oggPage); ogg_stream_packetout(&test, &_oggPacket); // identify the codec: try theora if (!_theoraPacket && th_decode_headerin(&_theoraInfo, &_theoraComment, &_theoraSetup, &_oggPacket) >= 0) { // it is theora memcpy(&_theoraOut, &test, sizeof(test)); _theoraPacket = 1; } else if (!_vorbisPacket && vorbis_synthesis_headerin(&_vorbisInfo, &_vorbisComment, &_oggPacket) >= 0) { // it is vorbis memcpy(&_vorbisOut, &test, sizeof(test)); _vorbisPacket = 1; } 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 ((_theoraPacket && _theoraPacket < 3) || (_vorbisPacket && _vorbisPacket < 3)) { int ret; // look for further theora headers while (_theoraPacket && (_theoraPacket < 3) && (ret = ogg_stream_packetout(&_theoraOut, &_oggPacket))) { if (ret < 0) error("Error parsing Theora stream headers; corrupt stream?"); if (!th_decode_headerin(&_theoraInfo, &_theoraComment, &_theoraSetup, &_oggPacket)) error("Error parsing Theora stream headers; corrupt stream?"); _theoraPacket++; } // look for more vorbis header packets while (_vorbisPacket && (_vorbisPacket < 3) && (ret = ogg_stream_packetout(&_vorbisOut, &_oggPacket))) { if (ret < 0) error("Error parsing Vorbis stream headers; corrupt stream?"); if (vorbis_synthesis_headerin(&_vorbisInfo, &_vorbisComment, &_oggPacket)) error("Error parsing Vorbis stream headers; corrupt stream?"); _vorbisPacket++; if (_vorbisPacket == 3) break; } // The header pages/packets will arrive before anything else we // care about, or the stream is not obeying spec if (ogg_sync_pageout(&_oggSync, &_oggPage) > 0) { queuePage(&_oggPage); // demux into the appropriate stream } else { ret = bufferData(); // someone needs more data if (ret == 0) error("End of file while searching for codec headers."); } } // and now we have it all. initialize decoders if (_theoraPacket) { _theoraDecode = th_decode_alloc(&_theoraInfo, _theoraSetup); debugN(1, "Ogg logical stream %lx is Theora %dx%d %.02f fps", _theoraOut.serialno, _theoraInfo.pic_width, _theoraInfo.pic_height, (double)_theoraInfo.fps_numerator / _theoraInfo.fps_denominator); switch (_theoraInfo.pixel_fmt) { case TH_PF_420: debug(1, " 4:2:0 video"); break; case TH_PF_422: debug(1, " 4:2:2 video"); break; case TH_PF_444: debug(1, " 4:4:4 video"); break; case TH_PF_RSVD: default: debug(1, " video\n (UNKNOWN Chroma sampling!)"); break; } if (_theoraInfo.pic_width != _theoraInfo.frame_width || _theoraInfo.pic_height != _theoraInfo.frame_height) debug(1, " Frame content is %dx%d with offset (%d,%d).", _theoraInfo.frame_width, _theoraInfo.frame_height, _theoraInfo.pic_x, _theoraInfo.pic_y); switch (_theoraInfo.colorspace){ case TH_CS_UNSPECIFIED: /* nothing to report */ break; case TH_CS_ITU_REC_470M: debug(1, " encoder specified ITU Rec 470M (NTSC) color."); break; case TH_CS_ITU_REC_470BG: debug(1, " encoder specified ITU Rec 470BG (PAL) color."); break; default: debug(1, "warning: encoder specified unknown colorspace (%d).", _theoraInfo.colorspace); break; } debug(1, "Encoded by %s", _theoraComment.vendor); if (_theoraComment.comments) { debug(1, "theora comment header:"); for (int i = 0; i < _theoraComment.comments; i++) { if (_theoraComment.user_comments[i]) { int len = _theoraComment.comment_lengths[i]; char *value = (char *)malloc(len + 1); if (value) { memcpy(value, _theoraComment.user_comments[i], len); value[len] = '\0'; debug(1, "\t%s", value); free(value); } } } } th_decode_ctl(_theoraDecode, TH_DECCTL_GET_PPLEVEL_MAX, &_ppLevelMax, sizeof(_ppLevelMax)); _ppLevel = _ppLevelMax; th_decode_ctl(_theoraDecode, TH_DECCTL_SET_PPLEVEL, &_ppLevel, sizeof(_ppLevel)); _ppInc = 0; } else { // tear down the partial theora setup th_info_clear(&_theoraInfo); th_comment_clear(&_theoraComment); } th_setup_free(_theoraSetup); _theoraSetup = 0; if (_vorbisPacket) { vorbis_synthesis_init(&_vorbisDSP, &_vorbisInfo); vorbis_block_init(&_vorbisDSP, &_vorbisBlock); debug(3, "Ogg logical stream %lx is Vorbis %d channel %ld Hz audio.", _vorbisOut.serialno, _vorbisInfo.channels, _vorbisInfo.rate); _audStream = Audio::makeQueuingAudioStream(_vorbisInfo.rate, _vorbisInfo.channels); // Get enough audio data to start us off while (_audStream->numQueuedStreams() == 0) { // Queue more data bufferData(); while (ogg_sync_pageout(&_oggSync, &_oggPage) > 0) queuePage(&_oggPage); queueAudio(); } if (_audStream) g_system->getMixer()->playStream(Audio::Mixer::kPlainSoundType, _audHandle, _audStream, -1, getVolume(), getBalance()); } else { // tear down the partial vorbis setup vorbis_info_clear(&_vorbisInfo); vorbis_comment_clear(&_vorbisComment); _endOfAudio = true; } _surface.create(_theoraInfo.frame_width, _theoraInfo.frame_height, g_system->getScreenFormat()); // Set up a display surface _displaySurface.pixels = _surface.getBasePtr(_theoraInfo.pic_x, _theoraInfo.pic_y); _displaySurface.w = _theoraInfo.pic_width; _displaySurface.h = _theoraInfo.pic_height; _displaySurface.format = _surface.format; _displaySurface.pitch = _surface.pitch; // Set the frame rate _frameRate = Common::Rational(_theoraInfo.fps_numerator, _theoraInfo.fps_denominator); return true; }
encoder_state *encode_initialise(int channels, int rate, int managed, int min_br, int nom_br, int max_br, float quality, vorbis_comment *vc) { encoder_state *s = calloc(1, sizeof(encoder_state)); ogg_packet h1,h2,h3; /* Have vorbisenc choose a mode for us */ vorbis_info_init(&s->vi); if (max_br < 0 && nom_br < 0 && min_br < 0) managed = 0; if (managed == 0 && nom_br >= 0) if (min_br >= 0 || max_br >= 0) managed = 1; do { if (managed) { LOG_INFO5("Encoder initialising with bitrate management: %d " "channels, %d Hz, minimum bitrate %d, nominal %d, " "maximum %d", channels, rate, min_br, nom_br, max_br); if (vorbis_encode_setup_managed (&s->vi, channels, rate, max_br, nom_br, min_br)) break; } else { if (nom_br < 0) { LOG_INFO3("Encoder initialising in VBR mode: %d channel(s), " "%d Hz, quality %f", channels, rate, quality); if (min_br > 0 || max_br > 0) LOG_INFO0("ignoring min/max bitrate, not supported in VBR " "mode, use nominal-bitrate instead"); if (vorbis_encode_setup_vbr(&s->vi, channels, rate, quality*0.1)) break; #if 0 if (max_br > 0 || min_br > 0) { struct ovectl_ratemanage_arg ai; if (vorbis_encode_ctl(&s->vi, OV_ECTL_RATEMANAGE_GET, &ai)) break; ai.bitrate_hard_min = min_br; ai.bitrate_hard_max = max_br; ai.management_active = 1; if (vorbis_encode_ctl(&s->vi, OV_ECTL_RATEMANAGE_SET, &ai)) break; } #endif } else { LOG_INFO3("Encoder initialising in VBR mode: %d " "channels, %d Hz, nominal %d", channels, rate, nom_br); if (vorbis_encode_setup_managed (&s->vi, channels, rate, max_br, nom_br, max_br)) break; if (vorbis_encode_ctl (&s->vi, OV_ECTL_RATEMANAGE_SET, NULL)) break; } } if (vorbis_encode_setup_init(&s->vi)) break; vorbis_analysis_init(&s->vd, &s->vi); vorbis_block_init(&s->vd, &s->vb); ogg_stream_init(&s->os, _get_serial()); vorbis_analysis_headerout(&s->vd, vc, &h1,&h2,&h3); ogg_stream_packetin(&s->os, &h1); ogg_stream_packetin(&s->os, &h2); ogg_stream_packetin(&s->os, &h3); s->in_header = 1; s->samplerate = rate; s->samples_in_current_page = 0; s->prevgranulepos = 0; return s; } while (0); LOG_INFO0("Failed to configure encoder, verify settings"); vorbis_info_clear(&s->vi); free (s); return NULL; }
static int icecast_internal_connect(t_channel *c, t_channel_outputstream *os, t_icecast *icecast, char *error, int errsize) { ogg_packet header; ogg_packet header_comm; ogg_packet header_code; (void)c; (void)os; if (icecast->connected) return MSERV_SUCCESS; if (shout_open(icecast->shout) != SHOUTERR_SUCCESS) { snprintf(error, errsize, "icecast: failed opening connection: %s", shout_get_error(icecast->shout)); goto failed; } mserv_log("Successfully connected to Icecast server '%s:%d'" " for mount '%s'", shout_get_host(icecast->shout), shout_get_port(icecast->shout), shout_get_mount(icecast->shout)); icecast->connected = 1; vorbis_info_init(&icecast->vi); if (vorbis_encode_init(&icecast->vi, os->channels, os->samplerate, -1, icecast->bitrate, -1) != 0) { snprintf(error, errsize, "icecast: failed to initialise vorbis engine"); goto failed; } vorbis_comment_init(&icecast->vc); vorbis_comment_add_tag(&icecast->vc, "ENCODER", "mserv " VERSION); vorbis_analysis_init(&icecast->vd, &icecast->vi); vorbis_block_init(&icecast->vd, &icecast->vb); ogg_stream_init(&icecast->os, rand()); vorbis_analysis_headerout(&icecast->vd, &icecast->vc, &header, &header_comm, &header_code); ogg_stream_packetin(&icecast->os, &header); ogg_stream_packetin(&icecast->os, &header_comm); ogg_stream_packetin(&icecast->os, &header_code); for (;;) { if (ogg_stream_flush(&icecast->os, &icecast->og) == 0) break; if (shout_send(icecast->shout, icecast->og.header, icecast->og.header_len) != SHOUTERR_SUCCESS || shout_send(icecast->shout, icecast->og.body, icecast->og.body_len) != SHOUTERR_SUCCESS) { snprintf(error, errsize, "icecast: failed to send starter to " "shout: %s", shout_get_error(icecast->shout)); vorbis_block_clear(&icecast->vb); vorbis_dsp_clear(&icecast->vd); vorbis_info_clear(&icecast->vi); goto failed; } } return MSERV_SUCCESS; failed: if (icecast->connected) shout_close(icecast->shout); icecast->connected = 0; return MSERV_FAILURE; }
static int _fetch_headers(OggVorbis_File *vf, vorbis_info *vi, vorbis_comment *vc, ogg_uint32_t *serialno, ogg_page *og_ptr){ ogg_page og={0,0,0,0}; ogg_packet op={0,0,0,0,0,0}; int i,ret; if(vf->ready_state>OPENED)_decode_clear(vf); if(!og_ptr){ ogg_int64_t llret=_get_next_page(vf,&og,CHUNKSIZE); if(llret==OV_EREAD)return OV_EREAD; if(llret<0)return OV_ENOTVORBIS; og_ptr=&og; } ogg_stream_reset_serialno(vf->os,ogg_page_serialno(og_ptr)); if(serialno)*serialno=vf->os->serialno; /* extract the initial header from the first page and verify that the Ogg bitstream is in fact Vorbis data */ vorbis_info_init(vi); vorbis_comment_init(vc); i=0; while(i<3){ ogg_stream_pagein(vf->os,og_ptr); while(i<3){ int result=ogg_stream_packetout(vf->os,&op); if(result==0)break; if(result==-1){ ret=OV_EBADHEADER; goto bail_header; } if((ret=vorbis_dsp_headerin(vi,vc,&op))){ goto bail_header; } i++; } if(i<3) if(_get_next_page(vf,og_ptr,CHUNKSIZE)<0){ ret=OV_EBADHEADER; goto bail_header; } } ogg_packet_release(&op); ogg_page_release(&og); vf->ready_state=LINKSET; return 0; bail_header: ogg_packet_release(&op); ogg_page_release(&og); vorbis_info_clear(vi); vorbis_comment_clear(vc); vf->ready_state=OPENED; return ret; }
void VideoStreamPlaybackTheora::set_file(const String &p_file) { ERR_FAIL_COND(playing); ogg_packet op; th_setup_info *ts = NULL; file_name = p_file; if (file) { memdelete(file); } file = FileAccess::open(p_file, FileAccess::READ); ERR_FAIL_COND(!file); #ifdef THEORA_USE_THREAD_STREAMING thread_exit = false; thread_eof = false; //pre-fill buffer int to_read = ring_buffer.space_left(); int read = file->get_buffer(read_buffer.ptr(), to_read); ring_buffer.write(read_buffer.ptr(), read); thread = Thread::create(_streaming_thread, this); #endif ogg_sync_init(&oy); /* init supporting Vorbis structures needed in header parsing */ vorbis_info_init(&vi); vorbis_comment_init(&vc); /* init supporting Theora structures needed in header parsing */ th_comment_init(&tc); th_info_init(&ti); theora_eos = false; vorbis_eos = false; /* Ogg file open; parse the headers */ /* Only interested in Vorbis/Theora streams */ int stateflag = 0; int audio_track_skip = audio_track; while (!stateflag) { int ret = buffer_data(); if (ret == 0) break; while (ogg_sync_pageout(&oy, &og) > 0) { 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); ogg_stream_packetout(&test, &op); /* identify the codec: try theora */ if (!theora_p && th_decode_headerin(&ti, &tc, &ts, &op) >= 0) { /* it is theora */ copymem(&to, &test, sizeof(test)); theora_p = 1; } else if (!vorbis_p && vorbis_synthesis_headerin(&vi, &vc, &op) >= 0) { /* it is vorbis */ if (audio_track_skip) { vorbis_info_clear(&vi); vorbis_comment_clear(&vc); ogg_stream_clear(&test); vorbis_info_init(&vi); vorbis_comment_init(&vc); audio_track_skip--; } else { copymem(&vo, &test, sizeof(test)); vorbis_p = 1; } } 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_p < 3) || (vorbis_p && vorbis_p < 3)) { int ret; /* look for further theora headers */ while (theora_p && (theora_p < 3) && (ret = ogg_stream_packetout(&to, &op))) { if (ret < 0) { fprintf(stderr, "Error parsing Theora stream headers; " "corrupt stream?\n"); clear(); return; } if (!th_decode_headerin(&ti, &tc, &ts, &op)) { fprintf(stderr, "Error parsing Theora stream headers; " "corrupt stream?\n"); clear(); return; } theora_p++; } /* look for more vorbis header packets */ while (vorbis_p && (vorbis_p < 3) && (ret = ogg_stream_packetout(&vo, &op))) { if (ret < 0) { fprintf(stderr, "Error parsing Vorbis stream headers; corrupt stream?\n"); clear(); return; } ret = vorbis_synthesis_headerin(&vi, &vc, &op); if (ret) { fprintf(stderr, "Error parsing Vorbis stream headers; corrupt stream?\n"); clear(); return; } vorbis_p++; if (vorbis_p == 3) 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(); /* someone needs more data */ if (ret == 0) { fprintf(stderr, "End of file while searching for codec headers.\n"); clear(); return; } } } /* and now we have it all. initialize decoders */ if (theora_p) { td = th_decode_alloc(&ti, ts); printf("Ogg logical stream %lx is Theora %dx%d %.02f fps", to.serialno, ti.pic_width, ti.pic_height, (double)ti.fps_numerator / ti.fps_denominator); px_fmt = ti.pixel_fmt; switch (ti.pixel_fmt) { case TH_PF_420: printf(" 4:2:0 video\n"); break; case TH_PF_422: printf(" 4:2:2 video\n"); break; case TH_PF_444: printf(" 4:4:4 video\n"); break; case TH_PF_RSVD: default: printf(" video\n (UNKNOWN Chroma sampling!)\n"); break; } if (ti.pic_width != ti.frame_width || ti.pic_height != ti.frame_height) printf(" Frame content is %dx%d with offset (%d,%d).\n", ti.frame_width, ti.frame_height, ti.pic_x, ti.pic_y); th_decode_ctl(td, TH_DECCTL_GET_PPLEVEL_MAX, &pp_level_max, sizeof(pp_level_max)); pp_level = pp_level_max; pp_level = 0; th_decode_ctl(td, TH_DECCTL_SET_PPLEVEL, &pp_level, sizeof(pp_level)); pp_inc = 0; /*{ int arg = 0xffff; th_decode_ctl(td,TH_DECCTL_SET_TELEMETRY_MBMODE,&arg,sizeof(arg)); th_decode_ctl(td,TH_DECCTL_SET_TELEMETRY_MV,&arg,sizeof(arg)); th_decode_ctl(td,TH_DECCTL_SET_TELEMETRY_QI,&arg,sizeof(arg)); arg=10; th_decode_ctl(td,TH_DECCTL_SET_TELEMETRY_BITS,&arg,sizeof(arg)); }*/ int w; int h; w = (ti.pic_x + ti.frame_width + 1 & ~1) - (ti.pic_x & ~1); h = (ti.pic_y + ti.frame_height + 1 & ~1) - (ti.pic_y & ~1); size.x = w; size.y = h; texture->create(w, h, Image::FORMAT_RGBA, Texture::FLAG_FILTER | Texture::FLAG_VIDEO_SURFACE); } else { /* tear down the partial theora setup */ th_info_clear(&ti); th_comment_clear(&tc); } th_setup_free(ts); if (vorbis_p) { vorbis_synthesis_init(&vd, &vi); vorbis_block_init(&vd, &vb); fprintf(stderr, "Ogg logical stream %lx is Vorbis %d channel %ld Hz audio.\n", vo.serialno, vi.channels, vi.rate); //_setup(vi.channels, vi.rate); } else { /* tear down the partial vorbis setup */ vorbis_info_clear(&vi); vorbis_comment_clear(&vc); } playing = false; buffering = true; time = 0; audio_frames_wrote = 0; };
int main_encoder(){ 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 (simplest WAV header is 44 bytes) and assume that the data is 44.1khz, stereo, 16 bit little endian pcm samples. 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); }
/* all of the real encoding details are here. The modes, books, everything */ static int _vorbis_unpack_books(vorbis_info *vi,oggpack_buffer *opb){ codec_setup_info *ci=(codec_setup_info *)vi->codec_setup; int i; if(!ci)return(OV_EFAULT); /* codebooks */ ci->books=tremoroggpack_read(opb,8)+1; ci->book_param=(codebook *)_ogg_calloc(ci->books,sizeof(*ci->book_param)); for(i=0;i<ci->books;i++) if(vorbis_book_unpack(opb,ci->book_param+i))goto err_out; /* time backend settings, not actually used */ i=tremoroggpack_read(opb,6); for(;i>=0;i--) if(tremoroggpack_read(opb,16)!=0)goto err_out; /* floor backend settings */ ci->floors=tremoroggpack_read(opb,6)+1; ci->floor_param=_ogg_malloc(sizeof(*ci->floor_param)*ci->floors); ci->floor_type=_ogg_malloc(sizeof(*ci->floor_type)*ci->floors); for(i=0;i<ci->floors;i++){ ci->floor_type[i]=tremoroggpack_read(opb,16); if(ci->floor_type[i]<0 || ci->floor_type[i]>=VI_FLOORB)goto err_out; if(ci->floor_type[i]) ci->floor_param[i]=floor1_info_unpack(vi,opb); else ci->floor_param[i]=floor0_info_unpack(vi,opb); if(!ci->floor_param[i])goto err_out; } /* residue backend settings */ ci->residues=tremoroggpack_read(opb,6)+1; ci->residue_param=_ogg_malloc(sizeof(*ci->residue_param)*ci->residues); for(i=0;i<ci->residues;i++) if(res_unpack(ci->residue_param+i,vi,opb))goto err_out; /* map backend settings */ ci->maps=tremoroggpack_read(opb,6)+1; ci->map_param=_ogg_malloc(sizeof(*ci->map_param)*ci->maps); for(i=0;i<ci->maps;i++){ if(tremoroggpack_read(opb,16)!=0)goto err_out; if(mapping_info_unpack(ci->map_param+i,vi,opb))goto err_out; } /* mode settings */ ci->modes=tremoroggpack_read(opb,6)+1; ci->mode_param= (vorbis_info_mode *)_ogg_malloc(ci->modes*sizeof(*ci->mode_param)); for(i=0;i<ci->modes;i++){ ci->mode_param[i].blockflag=tremoroggpack_read(opb,1); if(tremoroggpack_read(opb,16))goto err_out; if(tremoroggpack_read(opb,16))goto err_out; ci->mode_param[i].mapping=tremoroggpack_read(opb,8); if(ci->mode_param[i].mapping>=ci->maps)goto err_out; } if(tremoroggpack_read(opb,1)!=1)goto err_out; /* top level EOP check */ return(0); err_out: vorbis_info_clear(vi); return(OV_EBADHEADER); }
int OggInit(CFile *f, OggData *data) { ogg_packet packet; int num_vorbis; #ifdef USE_THEORA int num_theora; #endif int stream_start; int ret; unsigned magic; f->read(&magic, sizeof(magic)); if (SDL_SwapLE32(magic) != 0x5367674F) { // "OggS" in ASCII return -1; } f->seek(0, SEEK_SET); ogg_sync_init(&data->sync); vorbis_info_init(&data->vinfo); vorbis_comment_init(&data->vcomment); #ifdef USE_THEORA theora_info_init(&data->tinfo); theora_comment_init(&data->tcomment); #endif #ifdef USE_THEORA num_theora = 0; #endif num_vorbis = 0; stream_start = 0; while (!stream_start) { ogg_stream_state test; if (OggGetNextPage(&data->page, &data->sync, f)) { return -1; } if (!ogg_page_bos(&data->page)) { if (num_vorbis) { ogg_stream_pagein(&data->astream, &data->page); } #ifdef USE_THEORA if (num_theora) { ogg_stream_pagein(&data->vstream, &data->page); } #endif stream_start = 1; break; } ogg_stream_init(&test, ogg_page_serialno(&data->page)); ogg_stream_pagein(&test, &data->page); // initial codec headers while (ogg_stream_packetout(&test, &packet) == 1) { #ifdef USE_THEORA if (theora_decode_header(&data->tinfo, &data->tcomment, &packet) >= 0) { memcpy(&data->vstream, &test, sizeof(test)); ++num_theora; } else #endif if (!vorbis_synthesis_headerin(&data->vinfo, &data->vcomment, &packet)) { memcpy(&data->astream, &test, sizeof(test)); ++num_vorbis; } else { ogg_stream_clear(&test); } } } data->audio = num_vorbis; #ifdef USE_THEORA data->video = num_theora; #endif // remainint codec headers while ((num_vorbis && num_vorbis < 3) #ifdef USE_THEORA || (num_theora && num_theora < 3)) { // are we in the theora page ? while (num_theora && num_theora < 3 && (ret = ogg_stream_packetout(&data->vstream, &packet))) { if (ret < 0) { return -1; } if (theora_decode_header(&data->tinfo, &data->tcomment, &packet)) { return -1; } ++num_theora; } #else ) { #endif // are we in the vorbis page ? while (num_vorbis && num_vorbis < 3 && (ret = ogg_stream_packetout(&data->astream, &packet))) { if (ret < 0) { return -1; } if (vorbis_synthesis_headerin(&data->vinfo, &data->vcomment, &packet)) { return -1; } ++num_vorbis; } if (OggGetNextPage(&data->page, &data->sync, f)) { break; } if (num_vorbis) { ogg_stream_pagein(&data->astream, &data->page); } #ifdef USE_THEORA if (num_theora) { ogg_stream_pagein(&data->vstream, &data->page); } #endif } if (num_vorbis) { vorbis_synthesis_init(&data->vdsp, &data->vinfo); vorbis_block_init(&data->vdsp, &data->vblock); } else { vorbis_info_clear(&data->vinfo); vorbis_comment_clear(&data->vcomment); } #ifdef USE_THEORA if (num_theora) { theora_decode_init(&data->tstate, &data->tinfo); data->tstate.internal_encode = NULL; // needed for a bug in libtheora (fixed in next release) } else { theora_info_clear(&data->tinfo); theora_comment_clear(&data->tcomment); } return !(num_vorbis || num_theora); #else return !num_vorbis; #endif }
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; #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 ************/ 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); 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); 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); 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); 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); }
//---------------------------Start Destructor--------------------------------------// VorbisPropertyHandler::~VorbisPropertyHandler(void) { // Delete Vorbis structures vorbis_info_clear (&m_oInfo); vorbis_comment_clear (&m_oComment); }