void OutputManager::StartFragment() { // get fragment number unsigned int fragment_number = 0; if(m_fragmented) { SharedLock lock(&m_shared_data); fragment_number = lock->m_fragment_number; } // create new muxer and encoders // we can't hold the lock while doing this because this could take some time QString filename; if(m_fragmented) { filename = GetNewFragmentFile(m_output_settings.file, fragment_number); } else { filename = m_output_settings.file; } std::unique_ptr<Muxer> muxer(new Muxer(m_output_settings.container_avname, filename)); VideoEncoder *video_encoder = NULL; AudioEncoder *audio_encoder = NULL; if(!m_output_settings.video_codec_avname.isEmpty()) video_encoder = muxer->AddVideoEncoder(m_output_settings.video_codec_avname, m_output_settings.video_options, m_output_settings.video_kbit_rate * 1024, m_output_settings.video_width, m_output_settings.video_height, m_output_settings.video_frame_rate); if(!m_output_settings.audio_codec_avname.isEmpty()) audio_encoder = muxer->AddAudioEncoder(m_output_settings.audio_codec_avname, m_output_settings.audio_options, m_output_settings.audio_kbit_rate * 1024, m_output_settings.audio_channels, m_output_settings.audio_sample_rate); muxer->Start(); // acquire lock and share the muxer and encoders SharedLock lock(&m_shared_data); lock->m_muxer = std::move(muxer); lock->m_video_encoder = video_encoder; lock->m_audio_encoder = audio_encoder; // increment fragment number // It's important that this is done here (i.e. after the encoders have been set up), because the fragment number // acts as a signal to AddVideoFrame/AddAudioFrame that they can pass frames to the encoders. ++lock->m_fragment_number; // push queued frames to the new encoders if(m_fragmented) { while(!lock->m_video_frame_queue.empty()) { int64_t fragment_begin = m_fragment_length * m_output_format.m_video_frame_rate * (lock->m_fragment_number - 1); int64_t fragment_end = m_fragment_length * m_output_format.m_video_frame_rate * lock->m_fragment_number; if(lock->m_video_frame_queue.front()->GetFrame()->pts >= fragment_end) break; std::unique_ptr<AVFrameWrapper> frame = std::move(lock->m_video_frame_queue.front()); lock->m_video_frame_queue.pop_front(); frame->GetFrame()->pts -= fragment_begin; video_encoder->AddFrame(std::move(frame)); } while(!lock->m_audio_frame_queue.empty()) { int64_t fragment_begin = m_fragment_length * m_output_format.m_audio_sample_rate * (lock->m_fragment_number - 1); int64_t fragment_end = m_fragment_length * m_output_format.m_audio_sample_rate * lock->m_fragment_number; if(lock->m_audio_frame_queue.front()->GetFrame()->pts >= fragment_end) break; std::unique_ptr<AVFrameWrapper> frame = std::move(lock->m_audio_frame_queue.front()); lock->m_audio_frame_queue.pop_front(); frame->GetFrame()->pts -= fragment_begin; audio_encoder->AddFrame(std::move(frame)); } } }
void compressFile(string & file_name, string const & ref_file_name, const int num_workers, bool seq_only, bool discard_secondary_alignments) { int dictionary_size = 1<<23; int match_len_limit = 36; // equivalent to -6 option // const int num_workers = num_threads - 1;//max(2, num_threads - 1); // one for parsing const int slots_per_worker = 20; const int num_slots = ( ( num_workers > 1 ) ? num_workers * slots_per_worker : 1 ); Packet_courier courier(num_workers, num_slots); // open output streams Output_args output_args = initializeOutputStreams(file_name, seq_only, discard_secondary_alignments, &courier); // cerr << "Initialized output streams" << endl; // from plzip library implementation // initialize parsing thread -- pass courier, FDs for output Parser_args parser_args; parser_args.output = output_args; parser_args.file_name = file_name; parser_args.ref_file_name = ref_file_name; parser_args.courier = &courier; parser_args.seq_only = seq_only; parser_args.discard_secondary_alignments = discard_secondary_alignments; pthread_t * parser_thread = new pthread_t(); int errcode = pthread_create( parser_thread, 0, parseSAM, &parser_args ); if ( errcode ) { show_error( "Can't create parser thread", errcode ); cleanup_and_fail(); } // initialize worker threads Worker_arg worker_arg; worker_arg.courier = &courier; worker_arg.dictionary_size = dictionary_size; worker_arg.match_len_limit = match_len_limit; pthread_t * worker_threads = new( std::nothrow ) pthread_t[num_workers]; if( !worker_threads ) { cleanup_and_fail(); } for( int i = 0; i < num_workers; ++i ) { errcode = pthread_create( worker_threads + i, 0, cworker, &worker_arg ); if( errcode ) { show_error( "Can't create worker threads", errcode ); cleanup_and_fail(); } } // cerr << "launched threads" << endl; // concurrently wait for threads to return compressed packets; write them to disk muxer(courier); // join worker threads for( int i = num_workers - 1; i >= 0; --i ) { errcode = pthread_join( worker_threads[i], 0 ); if( errcode ) { show_error( "Can't join worker threads", errcode ); cleanup_and_fail(); } else { // cerr << "thread " << i << " joined" << endl; } } delete[] worker_threads; // join the parser thread errcode = pthread_join( *parser_thread, 0 ); if( errcode ) { show_error( "Can't join parser thread", errcode ); cleanup_and_fail(); } // destructor in OutputBuffer will close file output streams };