/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /*************************************************************************** * mov_encoder_thread.cc * * Tue May 17 16:00:01 CEST 2005 * Copyright 2005 Bent Bisballe * deva@aasimon.org ****************************************************************************/ /* * This file is part of MIaV. * * MIaV is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * MIaV is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with MIaV; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ #include #include "mov_encoder_thread.h" #include #include "miav_config.h" MovEncoderThread::MovEncoderThread(const char *cpr, Info *i) { info = i; info->info("MovEncoderThread"); // 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(); num_frames_in_block = config->readString("frame_sequence")->length(); info->info("Frame sequence length %d", num_frames_in_block); threads = config->readInt("encoding_threads"); // 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(); frame_number = 0; } #include MovEncoderThread::~MovEncoderThread() { info->info("~MovEncoderThread"); // 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. writer->running = false; 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); // Tell the encoding threads to stop. for(int cnt = 0; cnt < threads; cnt++) { encs[cnt]->running = false; } // Kick them to initiate the exit. for(int cnt = 0; cnt < threads; cnt++) { sem_post(&in_sem); } // They should be exited now, so we can delete them. for(int cnt = 0; cnt < threads; cnt++) { // Wait for it to stop encs[cnt]->wait_stop(); // Delete it 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; // Kick it to make it stop. sem_post(&video_out_sem); sem_post(&audio_out_sem); // Wait for it to stop. writer->wait_stop(); // 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) { if(frame == NULL) { info->info("MovEncoderThread::encode - NULL frame detected."); // Terminate return; } frame->number = frame_number; block->push_back(frame); // Switch frame if(block->size() == num_frames_in_block || frame->endOfFrameStream == true) { // Wait until a free encoder. sem_wait(&read_sem); // Lock input mutex pthread_mutex_lock(&input_mutex); inputqueue->push(block); pthread_mutex_unlock(&input_mutex); // Unlock input mutex // Kick encoders sem_post(&in_sem); // Start new block block = new FrameVector; } frame_number ++; }