diff options
-rw-r--r-- | src/Makefile.am | 2 | ||||
-rw-r--r-- | src/frame.cc | 2 | ||||
-rw-r--r-- | src/frame.h | 2 | ||||
-rw-r--r-- | src/libfame_wrapper.cc | 4 | ||||
-rw-r--r-- | src/liblame_wrapper.cc | 7 | ||||
-rw-r--r-- | src/mov_encoder.cc | 67 | ||||
-rw-r--r-- | src/mov_encoder.h | 6 | ||||
-rw-r--r-- | src/mov_encoder_thread.cc | 98 | ||||
-rw-r--r-- | src/mov_encoder_thread.h | 8 | ||||
-rw-r--r-- | src/mov_encoder_writer.cc | 3 | ||||
-rw-r--r-- | src/multiplexer.cc | 11 | ||||
-rw-r--r-- | src/server.cc | 3 |
12 files changed, 146 insertions, 67 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index 8494cf1..38bc2d5 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -7,6 +7,7 @@ bin_PROGRAMS = miav miav_SOURCES = $(shell if [ $QT_CXXFLAGS ] ; then ../tools/MocList cc; fi ) \ aboutwindow.cc \ + audio_encoder.cc \ camera.cc \ cprquerydialog.cc \ daemon.cc \ @@ -44,6 +45,7 @@ miav_SOURCES = $(shell if [ $QT_CXXFLAGS ] ; then ../tools/MocList cc; fi ) \ EXTRA_DIST = \ aboutwindow.h \ + audio_encoder.h \ camera.h \ cprquerydialog.h \ daemon.h \ diff --git a/src/frame.cc b/src/frame.cc index cc53d62..b216164 100644 --- a/src/frame.cc +++ b/src/frame.cc @@ -32,6 +32,8 @@ #include <memory.h> #include <stdlib.h> +Frame *endOfFrameStream = NULL;// = (Frame*)0xffffffff; + Frame::Frame(unsigned char *d, int sz) { if(sz) data = new unsigned char[sz]; diff --git a/src/frame.h b/src/frame.h index 18425ab..17de4fa 100644 --- a/src/frame.h +++ b/src/frame.h @@ -69,4 +69,6 @@ typedef std::priority_queue< Frame*, std::vector<Frame*>, frame_priority<Frame*> > FramePriorityQueue; +extern Frame *endOfFrameStream; + #endif/*__FRAME_H__*/ diff --git a/src/libfame_wrapper.cc b/src/libfame_wrapper.cc index 5c71154..a663df6 100644 --- a/src/libfame_wrapper.cc +++ b/src/libfame_wrapper.cc @@ -97,10 +97,10 @@ LibFAMEWrapper::LibFAMEWrapper(Info *i) fame_par.coding = config->readString("frame_sequence")->c_str(); // quality is a percentage, which controls compression versus quality. - fame_par.quality = config->readInt("frame_quality"); + fame_par.quality = config->readInt("video_quality"); // Bitrate - fame_par.bitrate = 150000; // video bitrate in bytes pr second (0=VBR) + fame_par.bitrate = config->readInt("video_bitrate") * 1000; // video bitrate in bytes pr second (0=VBR) // slices_per_frame is the number of frame slices per frame. More slices provide // better error recovery. There must be at least one slice per frame, and at most diff --git a/src/liblame_wrapper.cc b/src/liblame_wrapper.cc index 87b2f11..c72c2dc 100644 --- a/src/liblame_wrapper.cc +++ b/src/liblame_wrapper.cc @@ -222,7 +222,7 @@ Frame *LibLAMEWrapper::encode(Frame *dvframe) mp3buf_size - val); // number of valid octets in this stream */ - info->info("VAL: %d - FLUSH_SZ: %d - TOTAL: %d", val, flush_sz, (val + flush_sz)); + // info->info("VAL: %d - FLUSH_SZ: %d - TOTAL: %d", val, flush_sz, (val + flush_sz)); audio_frame->size = val + flush_sz; @@ -265,5 +265,10 @@ Frame *LibLAMEWrapper::encode(Frame *dvframe) (float)(config->readInt("mp3_bitrate") * 1000)/(float)(audio_frame->bitrate)); */ + /* + FILE* fp = fopen("/tmp/audiotest.mp3", "a"); + fwrite(audio_frame->data, audio_frame->size, 1, fp); + fclose(fp); + */ return audio_frame; } diff --git a/src/mov_encoder.cc b/src/mov_encoder.cc index 118a338..9212e5a 100644 --- a/src/mov_encoder.cc +++ b/src/mov_encoder.cc @@ -43,7 +43,7 @@ #include "debug.h" -MovEncoder::MovEncoder(sem_t *r_sem, +MovEncoder::MovEncoder(volatile bool *r, sem_t *r_sem, FrameVectorQueue *in, sem_t *in_sem, pthread_mutex_t *in_mutex, FramePriorityQueue *v_out, pthread_mutex_t *v_out_mutex, sem_t *v_out_sem, FramePriorityQueue *a_out, pthread_mutex_t *a_out_mutex, sem_t *a_out_sem, @@ -52,7 +52,7 @@ MovEncoder::MovEncoder(sem_t *r_sem, info = i; info->info("MovEncoder"); - running = true; + running = r; // Queues inputqueue = in; @@ -86,8 +86,8 @@ void MovEncoder::thread_main() int a_outsize = 0; int insize = 0; - // Run with slightly lower priority than MovEncoderWriter - nice(1); + // Run with slightly lower priority than MovEncoderWriter AND AudioEncoder + nice(2); FrameVector *item; Frame *in_frame; @@ -95,23 +95,16 @@ void MovEncoder::thread_main() Frame *out_a_frame; LibFAMEWrapper fame(info); - // LibLAMEWrapper lame(info); - // Make a new instance for every frame sequence (usually 5) to ensure no - // frame dependencies are broken when running multithreaded. - LibLAMEWrapper lame(info); - - while(running) { + // Process until running == false and the queue is empty + while(*running || ((*running == false) && (insize > 0))) { sem_wait(input_sem); - // Lock inout mutex pthread_mutex_lock(input_mutex); item = inputqueue->front(); inputqueue->pop(); - insize = inputqueue->size(); - pthread_mutex_unlock(input_mutex); // Unlock input mutex @@ -119,45 +112,45 @@ void MovEncoder::thread_main() for(unsigned int cnt = 0; cnt < item->size(); cnt++) { in_frame = item->at(cnt); - // Encode video - //out_v_frame = new Frame(in_frame->data, in_frame->size); - //out_v_frame->number = in_frame->number; - out_v_frame = fame.encode(in_frame); - out_v_frame->number = in_frame->number; - - // Encode audio - //out_a_frame = new Frame(in_frame->data, in_frame->size); - //out_a_frame->number = in_frame->number; - out_a_frame = lame.encode(in_frame); - out_a_frame->number = in_frame->number; - - // Last frame - we need to close LAME - // if(cnt == item->size() - 1) out_a_frame = lame.close(out_a_frame); - - delete in_frame; - + // Check for end of stream + if(in_frame == endOfFrameStream) { + info->info("endOfFrameStream in MovEncoder"); + + out_v_frame = in_frame; + + // Stop running + *running = false; + } else { + // Encode video + out_v_frame = fame.encode(in_frame); + out_v_frame->number = in_frame->number; + } + // Create audio frame + out_a_frame = in_frame; + // Lock output mutex pthread_mutex_lock(video_output_mutex); video_outputqueue->push(out_v_frame); v_outsize = video_outputqueue->size(); pthread_mutex_unlock(video_output_mutex); // Unlock output mutex - + // Kick multiplexer (video) sem_post(video_output_sem); - + // Lock output mutex pthread_mutex_lock(audio_output_mutex); audio_outputqueue->push(out_a_frame); a_outsize = audio_outputqueue->size(); pthread_mutex_unlock(audio_output_mutex); // Unlock output mutex - - // Kick multiplexer (audio) + + // Kick audio encoder sem_post(audio_output_sem); } delete item; + item = NULL; test++; if(test % (25 * 24) == 0) @@ -169,7 +162,11 @@ void MovEncoder::thread_main() } } - // Kick multiplexer (audio) + info->info("Input pool size: %d, video output pool size: %d, audio output pool size: %d", + insize, v_outsize, a_outsize); + + + // Kick audio encoder sem_post(audio_output_sem); // Kick multiplexer (video) diff --git a/src/mov_encoder.h b/src/mov_encoder.h index 6862c84..8488008 100644 --- a/src/mov_encoder.h +++ b/src/mov_encoder.h @@ -49,11 +49,11 @@ using namespace std; #include "info.h" #include "libfame_wrapper.h" -#include "liblame_wrapper.h" +//#include "liblame_wrapper.h" class MovEncoder : public Thread { public: - MovEncoder(sem_t *r_sem, + MovEncoder(volatile bool *r, sem_t *r_sem, FrameVectorQueue *in, sem_t *in_sem, pthread_mutex_t *in_mutex, FramePriorityQueue *v_out, pthread_mutex_t *v_out_mutex, sem_t *v_out_sem, FramePriorityQueue *a_out, pthread_mutex_t *a_out_mutex, sem_t *a_out_sem, @@ -62,7 +62,7 @@ public: void thread_main(); - volatile bool running; + volatile bool *running; private: // LibFAMEWrapper *fame; diff --git a/src/mov_encoder_thread.cc b/src/mov_encoder_thread.cc index dc3581d..4562ec9 100644 --- a/src/mov_encoder_thread.cc +++ b/src/mov_encoder_thread.cc @@ -37,11 +37,13 @@ MovEncoderThread::MovEncoderThread(const char *cpr, Info *i) // Queues inputqueue = new FrameVectorQueue(); video_outputqueue = new FramePriorityQueue(); + audio_inputqueue = new FramePriorityQueue(); audio_outputqueue = new FramePriorityQueue(); // Queue mutexes pthread_mutex_init (&input_mutex, NULL); pthread_mutex_init (&video_output_mutex, NULL); + pthread_mutex_init (&audio_input_mutex, NULL); pthread_mutex_init (&audio_output_mutex, NULL); block = new FrameVector(); @@ -55,39 +57,83 @@ MovEncoderThread::MovEncoderThread(const char *cpr, Info *i) // Thread stuff sem_init(&in_sem, 0, 0); sem_init(&video_out_sem, 0, 0); + sem_init(&audio_in_sem, 0, 0); sem_init(&audio_out_sem, 0, 0); sem_init(&read_sem, 0, 0); + movencodersrunning = true; + for(int cnt = 0; cnt < threads; cnt++) sem_post(&read_sem); + // Create the video encoders + for(int cnt = 0; cnt < threads; cnt++) { + MovEncoder *movenc = + new MovEncoder(&movencodersrunning, &read_sem, + inputqueue, &in_sem, &input_mutex, + video_outputqueue, &video_output_mutex, &video_out_sem, + audio_inputqueue, &audio_input_mutex, &audio_in_sem, + info); + movenc->run(); + encs.push_back(movenc); + } + + // Create the audio encoder + audioenc = new AudioEncoder(audio_inputqueue, &audio_input_mutex, &audio_in_sem, + audio_outputqueue, &audio_output_mutex, &audio_out_sem, + info); + audioenc->run(); + + // Create the multiplexer writer = new MovEncoderWriter(cpr, video_outputqueue, &video_output_mutex, &video_out_sem, audio_outputqueue, &audio_output_mutex, &audio_out_sem, info); writer->run(); - for(int cnt = 0; cnt < threads; cnt++) { - MovEncoder *movenc = new MovEncoder(&read_sem, - inputqueue, &in_sem, &input_mutex, - video_outputqueue, &video_output_mutex, &video_out_sem, - audio_outputqueue, &audio_output_mutex, &audio_out_sem, - info); - movenc->run(); - encs.push_back(movenc); - } - frame_number = 0; } +#include <unistd.h> MovEncoderThread::~MovEncoderThread() { info->info("~MovEncoderThread"); + // Push end of stream frame to the queue. + num_frames_in_block = block->size() + 1; // Make the next frame fill out the block. + encode(endOfFrameStream); + + info->info("Posted endOfFrameStream"); + + // First we destroy the movie encoders + for(int cnt = 0; cnt < threads; cnt++) sem_post(&in_sem); // Kick them + for(int cnt = 0; cnt < threads; cnt++) { + encs[cnt]->wait_stop(); // Wait for it to stop + delete encs[cnt]; // Delete it + } + + info->info("Deleted the movie encoders"); + + // Then we destroy the audio encoder + sem_post(&audio_in_sem); // Kick it + audioenc->wait_stop(); // Wait for it to stop. + delete audioenc; // delete the audio encoder + + info->info("Deleted the audio encoder"); + + // Finally we destroy the writer. + sem_post(&video_out_sem); // Kick it to make it stop. + sem_post(&audio_out_sem); // Kick it to make it stop. + writer->wait_stop(); // Wait for it to stop. + delete writer; // delete the writer (end thereby close the file) + + info->info("Deleted the writer"); + + /* // These should not be deleted here... its done elsewhere. // inputqueue = NULL; - sem_post(&video_out_sem); - sem_post(&audio_out_sem); + // sem_post(&video_out_sem); + // sem_post(&audio_out_sem); // Tell the encoding threads to stop. for(int cnt = 0; cnt < threads; cnt++) { @@ -107,6 +153,18 @@ MovEncoderThread::~MovEncoderThread() delete encs[cnt]; } + // Tell the audio encoder to stop + audioenc->running = false; + + // Kick it to make it stop. + sem_post(&audio_in_sem); + + // Wait for it to stop. + audioenc->wait_stop(); + + // delete the audio encoder + delete audioenc; + // Tell the writer to stop writer->running = false; @@ -119,12 +177,16 @@ MovEncoderThread::~MovEncoderThread() // delete the writer (end thereby close the file) delete writer; - + */ // Destroy the semaphores. sem_destroy(&in_sem); sem_destroy(&video_out_sem); + sem_destroy(&audio_in_sem); sem_destroy(&audio_out_sem); sem_destroy(&read_sem); + + + info->info("MovEncoderThread done deinitializing."); } void MovEncoderThread::encode(Frame* frame) @@ -141,11 +203,6 @@ void MovEncoderThread::encode(Frame* frame) // Switch frame if(block->size() == num_frames_in_block) { // Wait until a free encoder. - /* - int val; - sem_getvalue(&read_sem, &val); - fprintf(stderr, "Sem Value: %d\n", val); fflush(stderr); - */ sem_wait(&read_sem); // Lock input mutex @@ -154,11 +211,6 @@ void MovEncoderThread::encode(Frame* frame) pthread_mutex_unlock(&input_mutex); // Unlock input mutex - // fprintf(stderr, "Frame vector [%d-%d] pushed\n", - // block->at(0)->number, - // block->at(block->size() - 1)->number); - fflush(stderr); - // Kick encoders sem_post(&in_sem); diff --git a/src/mov_encoder_thread.h b/src/mov_encoder_thread.h index 5684edf..e3fba27 100644 --- a/src/mov_encoder_thread.h +++ b/src/mov_encoder_thread.h @@ -37,6 +37,7 @@ using namespace std; #include "mov_encoder.h" +#include "audio_encoder.h" #include "mov_encoder_writer.h" #include "info.h" @@ -53,20 +54,25 @@ private: FrameVectorQueue *inputqueue; FramePriorityQueue *video_outputqueue; + FramePriorityQueue *audio_inputqueue; FramePriorityQueue *audio_outputqueue; FrameVector *block; //thread stuff sem_t in_sem; sem_t video_out_sem; + sem_t audio_in_sem; sem_t audio_out_sem; sem_t read_sem; pthread_mutex_t input_mutex; pthread_mutex_t video_output_mutex; + pthread_mutex_t audio_input_mutex; pthread_mutex_t audio_output_mutex; + volatile bool movencodersrunning; + // Used for encoder switching unsigned int frame_number; @@ -75,6 +81,8 @@ private: MovEncoderWriter *writer; // pthread_t* writer_tid; + AudioEncoder* audioenc; + int threads; vector<MovEncoder*> encs; // vector<pthread_t*> tids; diff --git a/src/mov_encoder_writer.cc b/src/mov_encoder_writer.cc index bc9302a..83530ac 100644 --- a/src/mov_encoder_writer.cc +++ b/src/mov_encoder_writer.cc @@ -93,9 +93,6 @@ MovEncoderWriter::MovEncoderWriter(const char* cpr, audio_frame_number = 0; running = true; - - // empty_timecode_struc(&SCR); - // timestamp = 0.0; } MovEncoderWriter::~MovEncoderWriter() diff --git a/src/multiplexer.cc b/src/multiplexer.cc index a94c150..323b33c 100644 --- a/src/multiplexer.cc +++ b/src/multiplexer.cc @@ -125,21 +125,31 @@ int Multiplexer::read_stream(char *buf, unsigned int size, StreamType type) // Lock output mutex pthread_mutex_lock( mutex[type] ); tmpframe = queue[type]->top(); + if(tmpframe && tmpframe->number == frame_number[type] ) { queue[type]->pop(); frame[type] = tmpframe; frame_number[type]++; read[type] = 0; } + /* if(*running == false && frame[type] == NULL) { pthread_mutex_unlock( mutex[type] ); //info->info("Bailed out early %d!", copied); return copied; } + */ + pthread_mutex_unlock( mutex[type] ); // Unlock output mutex } + // check for end of stream + if( frame[type] == endOfFrameStream ) { + info->info("endOfFrameStream in Multiplexer %s-stream.", type==TYPE_VIDEO?"video\0":"audio\0"); + return copied; + } + // If a frame exists in the buffer copy it to the output buffer // (No frame ocurres when *running is set to false) if( frame[type] ) { @@ -455,6 +465,7 @@ void Multiplexer::multiplex() char buf[1024]; do { frmsz = read_stream(buf, sizeof(buf), BYPASS); + info->info("Wrote %d bytes", frmsz); file->Write(buf, frmsz); } while(frmsz == sizeof(buf)); return; diff --git a/src/server.cc b/src/server.cc index bdca907..892b2e9 100644 --- a/src/server.cc +++ b/src/server.cc @@ -56,6 +56,9 @@ void newConnection(Socket *socket, Info *info) { + // We need to create the end of stream frame. + if(endOfFrameStream == NULL) endOfFrameStream = new Frame(NULL, 1); + char cpr[256]; bool hasCpr = false; ServerStatus status(info); |