From dc583513aa7f0a8934a56dbf4c9cb3c9a05b9d20 Mon Sep 17 00:00:00 2001 From: "(no author)" <(no author)@d8a302eb-03bc-478d-80e4-98257eca68ef> Date: Fri, 29 Aug 2014 05:37:23 +0000 Subject: [PATCH] x git-svn-id: svn://elaine/murooma/trunk@220 d8a302eb-03bc-478d-80e4-98257eca68ef --- server/Makefile | 2 +- server/encoder.h | 2 +- server/oggEncoder.cpp | 170 ++++++++++++++++++++++++++++++++++++++++-- server/oggEncoder.h | 28 ++++++- server/pcmEncoder.cpp | 3 +- server/pcmEncoder.h | 2 +- server/snapServer.cpp | 11 ++- 7 files changed, 204 insertions(+), 14 deletions(-) diff --git a/server/Makefile b/server/Makefile index 6f06bac7..b1f65d28 100644 --- a/server/Makefile +++ b/server/Makefile @@ -1,7 +1,7 @@ VERSION = 0.01 CC = /usr/bin/g++ CFLAGS = -std=gnu++0x -Wall -Wno-unused-function -D_REENTRANT -DVERSION=\"$(VERSION)\" -I.. -LDFLAGS = -lrt -lpthread -lboost_system -lboost_program_options +LDFLAGS = -lrt -lpthread -lboost_system -lboost_program_options -lvorbis -lvorbisenc -logg OBJ = snapServer.o pcmEncoder.o oggEncoder.o ../common/chunk.o ../common/sampleFormat.o BIN = snapserver diff --git a/server/encoder.h b/server/encoder.h index d394e801..13205baa 100644 --- a/server/encoder.h +++ b/server/encoder.h @@ -7,7 +7,7 @@ class Encoder { public: Encoder(); - virtual void encode(Chunk* chunk) = 0; + virtual bool encode(Chunk* chunk) = 0; }; diff --git a/server/oggEncoder.cpp b/server/oggEncoder.cpp index 2d2cc8e3..07904523 100644 --- a/server/oggEncoder.cpp +++ b/server/oggEncoder.cpp @@ -1,18 +1,178 @@ #include "oggEncoder.h" +#include +#include + +using namespace std; + OggEncoder::OggEncoder() { + init(); } -void OggEncoder::encode(Chunk* chunk) +bool OggEncoder::encode(Chunk* chunk) { + bool res = false; WireChunk* wireChunk = chunk->wireChunk; - for (size_t n=0; nlength; ++n) - wireChunk->payload[n] *= 1.5; -// return chunk; + if (tv_sec == 0) + { + tv_sec = wireChunk->tv_sec; + tv_usec = wireChunk->tv_usec; + } +//cout << "pcm: " << wireChunk->length << endl; + + int bytes = wireChunk->length / 4; + float **buffer=vorbis_analysis_buffer(&vd, bytes); + + int i; + /* uninterleave samples */ + for(i=0;ipayload[i*4+1]<<8)| + (0x00ff&(int)wireChunk->payload[i*4]))/32768.f; + buffer[1][i]=((wireChunk->payload[i*4+3]<<8)| + (0x00ff&(int)wireChunk->payload[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 */ + size_t pos = 0; + while(vorbis_analysis_blockout(&vd,&vb)==1) + { + + /* analysis, assume we want to use bitrate management */ + vorbis_analysis(&vb,NULL); + vorbis_bitrate_addblock(&vb); + + while(vorbis_bitrate_flushpacket(&vd,&op)) + { + /* weld the packet into the bitstream */ + ogg_stream_packetin(&os,&op); + + /* write out pages (if any) */ + while(true) + { +// int result = ogg_stream_pageout(&os,&og); + int result = ogg_stream_flush(&os,&og); +//cout << "result: " << result << "\n"; + if (result == 0) + { + break; + } + else + { + res = true; + cout << "pcm: " << wireChunk->length << ", header len: " << og.header_len << ", body len: " << og.body_len << endl; +// fwrite(og.header,1,og.header_len,stdout); +// fwrite(og.body,1,og.body_len,stdout); + memcpy(wireChunk->payload + pos, og.header, og.header_len); + pos += og.header_len; + memcpy(wireChunk->payload + pos, og.body, og.body_len); + pos += og.body_len; + } + } + } + } + if (res) + { + wireChunk->payload = (char*)realloc(wireChunk->payload, pos); + wireChunk->length = pos; + wireChunk->tv_sec = tv_sec; + wireChunk->tv_usec = tv_usec; + tv_sec = 0; + tv_usec = 0; + } + return res; +} + + +void OggEncoder::init() +{ + /********** Encode setup ************/ + tv_sec = 0; + tv_usec = 0; + + 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,48000,0.4); + + /* 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 */ + + 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(!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); + } + */ } - diff --git a/server/oggEncoder.h b/server/oggEncoder.h index 72712349..ae3bc76e 100644 --- a/server/oggEncoder.h +++ b/server/oggEncoder.h @@ -1,13 +1,39 @@ #ifndef OGG_ENCODER_H #define OGG_ENCODER_H #include "encoder.h" +#include class OggEncoder { public: OggEncoder(); - virtual void encode(Chunk* chunk); + virtual bool encode(Chunk* chunk); + +private: + void init(); + + 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 */ + + ogg_packet header; + ogg_packet header_comm; + ogg_packet header_code; + + int eos=0,ret; + int i, founddata; + + int32_t tv_sec; + int32_t tv_usec; }; diff --git a/server/pcmEncoder.cpp b/server/pcmEncoder.cpp index 955f7328..a418dcc8 100644 --- a/server/pcmEncoder.cpp +++ b/server/pcmEncoder.cpp @@ -5,12 +5,13 @@ PcmEncoder::PcmEncoder() } -void PcmEncoder::encode(Chunk* chunk) +bool PcmEncoder::encode(Chunk* chunk) { /* WireChunk* wireChunk = chunk->wireChunk; for (size_t n=0; nlength; ++n) wireChunk->payload[n] *= 1; */ + return true; } diff --git a/server/pcmEncoder.h b/server/pcmEncoder.h index b054df91..ddd4b532 100644 --- a/server/pcmEncoder.h +++ b/server/pcmEncoder.h @@ -7,7 +7,7 @@ class PcmEncoder { public: PcmEncoder(); - virtual void encode(Chunk* chunk); + virtual bool encode(Chunk* chunk); }; diff --git a/server/snapServer.cpp b/server/snapServer.cpp index ecd28cd4..0b70038f 100644 --- a/server/snapServer.cpp +++ b/server/snapServer.cpp @@ -27,6 +27,7 @@ #include "common/utils.h" #include "common/sampleFormat.h" #include "pcmEncoder.h" +#include "oggEncoder.h" #include @@ -136,7 +137,7 @@ public: { socket_ptr sock(new tcp::socket(io_service_)); a.accept(*sock); - cout << "New connection: " << sock->remote_endpoint().address().to_string() << "\n"; +// cout << "New connection: " << sock->remote_endpoint().address().to_string() << "\n"; Session* session = new Session(sock); session->start(); sessions.insert(shared_ptr(session)); @@ -145,6 +146,8 @@ public: void send(shared_ptr chunk) { +// fwrite(chunk->wireChunk->payload, 1, chunk->wireChunk->length, stdout); + for (std::set>::iterator it = sessions.begin(); it != sessions.end(); ) { if (!(*it)->isActive()) @@ -262,7 +265,7 @@ int main(int argc, char* argv[]) mkfifo(fifoName.c_str(), 0777); size_t duration = 50; - PcmEncoder pcmEncoder; + OggEncoder pcmEncoder; SampleFormat format(sampleFormat); while (!g_terminated) { @@ -290,8 +293,8 @@ size_t duration = 50; wireChunk->tv_sec = tvChunk.tv_sec; wireChunk->tv_usec = tvChunk.tv_usec; - pcmEncoder.encode(chunk.get()); - server->send(chunk); + if (pcmEncoder.encode(chunk.get())) + server->send(chunk); addMs(tvChunk, duration); nextTick += duration;