EVOLUTION-MANAGER
Edit File: vorbisEncoder.cpp
#include "vorbisEncoder.h" #ifdef HAVE_LIBVORBIS #include "vorbisExtractor.h" #include <cstdlib> #include <cstring> #include <iostream> VorbisEncoder::VorbisEncoder(uint32 _streamNo) : streamNo(_streamNo), pktCnt(0) { } VorbisEncoder::~VorbisEncoder() { // std::cerr << "Vorbis Encoder produced "<<pktCnt<<" packets\n"; if (isConfigured()) { vorbis_block_clear(&vorbisBlock); vorbis_dsp_clear(&vorbisState); vorbis_info_clear(&vorbisInfo); packet.packet = 0; // this has been deleted before } } void VorbisEncoder::configureEncoder(VorbisStreamParameter& config, StreamConfig& streamConfig, std::vector<OggComment>& oggComments) { if (isConfigured()) throw std::string("VorbisEncoder::setConfig: can't configure encoder twice\n"); vorbis_info_init(&vorbisInfo); /* int32 ret = vorbis_encode_init(&vorbisInfo, config.channels, config.samplerate, config.datarate, config.datarate, config.datarate); */ int32 ret = vorbis_encode_init(&vorbisInfo, config.channels, config.samplerate, -1, config.datarate, -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) throw std::string("VorbisEncoder::configureEncoder: can not configure encoder, wrong parameters"); /* add a comment */ vorbis_comment_init(&vorbisComment); vorbis_comment_add_tag(&vorbisComment, "ENCODER", "oggVideoTools 0.8"); /* add other comments */ for (uint32 i(0); i<oggComments.size(); ++i) vorbis_comment_add_tag(&vorbisComment, (char*) oggComments[i].tag.c_str(), (char*) oggComments[i].value.c_str()); /* set up the analysis state and auxiliary encoding storage */ vorbis_analysis_init(&vorbisState, &vorbisInfo); vorbis_block_init(&vorbisState, &vorbisBlock); OggPacketInternal header; OggPacketInternal header_comm; OggPacketInternal header_code; vorbis_analysis_headerout(&vorbisState, &vorbisComment, &header, &header_comm, &header_code); header.streamType = ogg_vorbis; header.streamNo = streamNo; header.streamHeader = true; #ifdef DEBUG std::cerr << "Vorbis Packet Number: "<< header.packetno << std::endl; #endif streamConfig.headerList.push_back(OggPacket(header.clone())); header_comm.streamType = ogg_vorbis; header_comm.streamNo = streamNo; header_comm.streamHeader = true; #ifdef DEBUG std::cerr << "Vorbis Packet Number: "<< header_comm.packetno << std::endl; #endif streamConfig.headerList.push_back(OggPacket(header_comm.clone())); header_code.streamType = ogg_vorbis; header_code.streamNo = streamNo; header_code.streamHeader = true; #ifdef DEBUG std::cerr << "Vorbis Packet Number: "<< header_code.packetno << std::endl; #endif streamConfig.headerList.push_back(OggPacket(header_code.clone())); VorbisExtractor extractor; extractor.extract(streamConfig.headerList[0], streamConfig); streamConfig.numOfHeaderPackets = streamConfig.headerList.size(); // streamConfig.parameter = new VorbisStreamParameter(config); // streamConfig.type = ogg_vorbis; streamConfig.streamNo = streamNo; streamConfig.serialNo = rand(); vorbis_comment_clear(&vorbisComment); setConfigured(); /* The vorbis decoder is not the owner of these packets, forget what we have seen */ header.packet = 0; header_comm.packet = 0; header_code.packet = 0; } MediaInputEncoder& VorbisEncoder::operator<<(AudioPacket& aPacket) { float **buffer=vorbis_analysis_buffer(&vorbisState, (*aPacket)->getLength()); /* there is no chance to give the data directly to the encoder * so we need to copy :-( */ for (uint8 i(0); i<vorbisInfo.channels; ++i) { memcpy(buffer[i], (*aPacket)->getDataOfChannel(i), (*aPacket)->getLength()*sizeof(float)); } /* tell the library how much we actually submitted */ if (vorbis_analysis_wrote(&vorbisState, (*aPacket)->getLength()) < 0) throw "VorbisEncoder::operator <<: Invalid value"; /* 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(&vorbisState, &vorbisBlock))==1) { /* analysis, assume we want to use bitrate management */ vorbis_analysis(&vorbisBlock,0); vorbis_bitrate_addblock(&vorbisBlock); while (vorbis_bitrate_flushpacket(&vorbisState, &packet)) { // std::cerr << "Position: "<<packet.granulepos<<std::endl; pktCnt++; packet.streamType = ogg_vorbis; packet.streamNo = streamNo; packet.streamHeader = false; #ifdef DEBUG std::cerr << "Vorbis Packet Number: "<< packet.packetno << std::endl; #endif packetList.push_back(OggPacket(packet.clone())); } } if (!packetList.empty()) setAvailable(); return(*this); } MediaInputEncoder& VorbisEncoder::operator >>(OggPacket& packet) { if (packetList.empty()) throw "VorbisEncoder::operator>> PacketList is empty"; packet = packetList.front(); packetList.pop_front(); if (packetList.empty()) setEmpty(); return(*this); } void VorbisEncoder::flush() { /* tell the library how much we actually submitted */ if (vorbis_analysis_wrote(&vorbisState, 0) < 0) throw std::string("VorbisEncoder::flush: can not flush"); /* 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(&vorbisState, &vorbisBlock))==1) { /* analysis, assume we want to use bitrate management */ vorbis_analysis(&vorbisBlock,0); vorbis_bitrate_addblock(&vorbisBlock); while (vorbis_bitrate_flushpacket(&vorbisState, &packet)) { // std::cerr << "Flush: "<<packet.granulepos<<std::endl; pktCnt++; packet.streamType = ogg_vorbis; packet.streamNo = streamNo; packet.streamHeader = false; packet.e_o_s = 255; packetList.push_back(OggPacket(packet.clone())); } } if (!packetList.empty()) setAvailable(); } #endif