diff --git a/include/FFmpegWriter.h b/include/FFmpegWriter.h index b6095dae..62ab0c91 100644 --- a/include/FFmpegWriter.h +++ b/include/FFmpegWriter.h @@ -56,6 +56,7 @@ namespace openshot private: string path; int cache_size; + bool is_writing; AVOutputFormat *fmt; AVFormatContext *oc; @@ -77,10 +78,15 @@ namespace openshot int audio_input_position; AudioResampler *resampler; - deque audio_frames; - deque queued_frames; + deque spooled_audio_frames; + deque spooled_video_frames; + + deque queued_audio_frames; + deque queued_video_frames; + deque processed_frames; deque deallocate_frames; + map av_frames; /// Add an AVFrame to the cache diff --git a/src/FFmpegReader.cpp b/src/FFmpegReader.cpp index 1711fc29..80e547c3 100644 --- a/src/FFmpegReader.cpp +++ b/src/FFmpegReader.cpp @@ -319,7 +319,7 @@ Frame* FFmpegReader::ReadStream(int requested_frame) //omp_set_num_threads(1); #pragma omp parallel { - #pragma omp master + #pragma omp single { // Loop through the stream until the correct frame is found while (true) @@ -407,11 +407,7 @@ Frame* FFmpegReader::ReadStream(int requested_frame) } // end while - } // end omp master - - // Be sure all threads are finished - #pragma omp barrier - + } // end omp single } // end omp parallel diff --git a/src/FFmpegWriter.cpp b/src/FFmpegWriter.cpp index d0a2f177..e5860bb7 100644 --- a/src/FFmpegWriter.cpp +++ b/src/FFmpegWriter.cpp @@ -31,7 +31,7 @@ FFmpegWriter::FFmpegWriter(string path) throw (InvalidFile, InvalidFormat, Inval path(path), fmt(NULL), oc(NULL), audio_st(NULL), video_st(NULL), audio_pts(0), video_pts(0), samples(NULL), audio_outbuf(NULL), audio_outbuf_size(0), audio_input_frame_size(0), audio_input_position(0), initial_audio_input_frame_size(0), resampler(NULL), img_convert_ctx(NULL), cache_size(12), - num_of_rescalers(32), rescaler_position(0), video_codec(NULL), audio_codec(NULL) + num_of_rescalers(32), rescaler_position(0), video_codec(NULL), audio_codec(NULL), is_writing(false) { // Init FileInfo struct (clear all values) @@ -289,34 +289,61 @@ void FFmpegWriter::WriteFrame(Frame* frame) // Add frame pointer to "queue", waiting to be processed the next // time the WriteFrames() method is called. if (info.has_video && video_st) - queued_frames.push_back(frame); + spooled_video_frames.push_back(frame); if (info.has_audio && audio_st) - audio_frames.push_back(frame); + spooled_audio_frames.push_back(frame); // Write the frames once it reaches the correct cache size - if (queued_frames.size() == cache_size || audio_frames.size() == cache_size) - // Write frames to video file - write_queued_frames(); + if (spooled_video_frames.size() == cache_size || spooled_audio_frames.size() == cache_size) + { + // Is writer currently writing? + if (!is_writing) + // Write frames to video file + write_queued_frames(); + + else + { + // YES, WRITING... so wait until it finishes, before writing again + while (is_writing) + usleep(250 * 1000); // sleep for 250 milliseconds + + // Write frames to video file + write_queued_frames(); + } + + } + } // Write all frames in the queue to the video file. void FFmpegWriter::write_queued_frames() { + // Flip writing flag + is_writing = true; + + // Transfer spool to queue + queued_video_frames = spooled_video_frames; + queued_audio_frames = spooled_audio_frames; + + // Empty spool + spooled_video_frames.clear(); + spooled_audio_frames.clear(); + //omp_set_num_threads(1); #pragma omp parallel { - #pragma omp master + #pragma omp single { // Process all audio frames (in a separate thread) - if (info.has_audio && audio_st && !audio_frames.empty()) + if (info.has_audio && audio_st && !queued_audio_frames.empty()) write_audio_packets(); // Loop through each queued image frame - while (!queued_frames.empty()) + while (!queued_video_frames.empty()) { // Get front frame (from the queue) - Frame *frame = queued_frames.front(); + Frame *frame = queued_video_frames.front(); // Add to processed queue processed_frames.push_back(frame); @@ -326,66 +353,67 @@ void FFmpegWriter::write_queued_frames() process_video_packet(frame); // Remove front item - queued_frames.pop_front(); + queued_video_frames.pop_front(); } // end while + } // end omp single - } // end omp master - - // Be sure all threads are finished - #pragma omp barrier - - } // end omp parallel - - - // Loop back through the frames (in order), and write them to the video file - while (!processed_frames.empty()) - { - // Get front frame (from the queue) - Frame *frame = processed_frames.front(); - - if (info.has_video && video_st) + #pragma omp single { - // Add to deallocate queue (so we can remove the AVFrames when we are done) - deallocate_frames.push_back(frame); - - // Does this frame's AVFrame still exist - if (av_frames.count(frame)) + // Loop back through the frames (in order), and write them to the video file + while (!processed_frames.empty()) { - // Get AVFrame - AVFrame *frame_final = av_frames[frame]; + // Get front frame (from the queue) + Frame *frame = processed_frames.front(); - // Write frame to video file - write_video_packet(frame, frame_final); + if (info.has_video && video_st) + { + // Add to deallocate queue (so we can remove the AVFrames when we are done) + deallocate_frames.push_back(frame); + + // Does this frame's AVFrame still exist + if (av_frames.count(frame)) + { + // Get AVFrame + AVFrame *frame_final = av_frames[frame]; + + // Write frame to video file + write_video_packet(frame, frame_final); + } + } + + // Remove front item + processed_frames.pop_front(); } - } - // Remove front item - processed_frames.pop_front(); - } + // Loop through, and deallocate AVFrames + while (!deallocate_frames.empty()) + { + // Get front frame (from the queue) + Frame *frame = deallocate_frames.front(); - // Loop through, and deallocate AVFrames - while (!deallocate_frames.empty()) - { - // Get front frame (from the queue) - Frame *frame = deallocate_frames.front(); + // Does this frame's AVFrame still exist + if (av_frames.count(frame)) + { + // Get AVFrame + AVFrame *av_frame = av_frames[frame]; - // Does this frame's AVFrame still exist - if (av_frames.count(frame)) - { - // Get AVFrame - AVFrame *av_frame = av_frames[frame]; + // deallocate AVFrame + av_free(av_frame->data[0]); + av_free(av_frame); - // deallocate AVFrame - av_free(av_frame->data[0]); - av_free(av_frame); + av_frames.erase(frame); + } - av_frames.erase(frame); - } + // Remove front item + deallocate_frames.pop_front(); + } - // Remove front item - deallocate_frames.pop_front(); - } + // Done writing + is_writing = false; + + } // end omp single + } // end omp parallel } @@ -406,6 +434,10 @@ void FFmpegWriter::WriteFrame(FileReaderBase* reader, int start, int length) // Write the file trailer (after all frames are written) void FFmpegWriter::WriteTrailer() { + // YES, WRITING... so wait until it finishes, before writing again + while (is_writing) + usleep(250 * 1000); // sleep for 250 milliseconds + // Write any remaining queued frames to video file write_queued_frames(); @@ -700,16 +732,16 @@ void FFmpegWriter::write_audio_packets() int samples_in_frame = 0; // Create a new array (to hold all S16 audio samples, for the current queued frames - int16_t* frame_samples = new int16_t[(audio_frames.size() * AVCODEC_MAX_AUDIO_FRAME_SIZE) + FF_INPUT_BUFFER_PADDING_SIZE]; + int16_t* frame_samples = new int16_t[(queued_audio_frames.size() * AVCODEC_MAX_AUDIO_FRAME_SIZE) + FF_INPUT_BUFFER_PADDING_SIZE]; // create a new array (to hold all the re-sampled audio, for the current queued frames) - int16_t* converted_audio = new int16_t[(audio_frames.size() * AVCODEC_MAX_AUDIO_FRAME_SIZE) + FF_INPUT_BUFFER_PADDING_SIZE]; + int16_t* converted_audio = new int16_t[(queued_audio_frames.size() * AVCODEC_MAX_AUDIO_FRAME_SIZE) + FF_INPUT_BUFFER_PADDING_SIZE]; // Loop through each queued audio frame - while (!audio_frames.empty()) + while (!queued_audio_frames.empty()) { // Get front frame (from the queue) - Frame *frame = audio_frames.front(); + Frame *frame = queued_audio_frames.front(); // Get the audio details from this frame sample_rate_in_frame = info.sample_rate; // resampling happens when getting the interleaved audio samples below @@ -732,7 +764,7 @@ void FFmpegWriter::write_audio_packets() delete[] frame_samples_float; // Remove front item - audio_frames.pop_front(); + queued_audio_frames.pop_front(); } // end while @@ -817,7 +849,6 @@ void FFmpegWriter::write_audio_packets() /* write the compressed frame in the media file */ int averror = 0; - #pragma omp critical (output_context) averror = av_interleaved_write_frame(oc, &pkt); if (averror != 0) { @@ -885,7 +916,7 @@ void FFmpegWriter::process_video_packet(Frame* frame) if (rescaler_position == num_of_rescalers) rescaler_position = 0; - #pragma task firstprivate(frame, scaler, source_image_width, source_image_height) + #pragma omp task firstprivate(frame, scaler, source_image_width, source_image_height) { // Allocate an RGB frame & final output frame int bytes_source = 0; @@ -955,7 +986,6 @@ void FFmpegWriter::write_video_packet(Frame* frame, AVFrame* frame_final) /* write the compressed frame in the media file */ int averror = 0; - #pragma omp critical (output_context) averror = av_interleaved_write_frame(oc, &pkt); if (averror != 0) { @@ -987,7 +1017,6 @@ void FFmpegWriter::write_video_packet(Frame* frame, AVFrame* frame_final) /* write the compressed frame in the media file */ int averror = 0; - #pragma omp critical (output_context) averror = av_interleaved_write_frame(oc, &pkt); if (averror != 0) { diff --git a/src/Main.cpp b/src/Main.cpp index ed84601d..95cbe2d5 100644 --- a/src/Main.cpp +++ b/src/Main.cpp @@ -20,9 +20,9 @@ int main() // openshot::FFmpegReader r("../../src/examples/piano.wav"); // openshot::FFmpegReader r("/home/jonathan/Videos/big-buck-bunny_trailer.webm"); - openshot::FFmpegReader r("/home/jonathan/Videos/sintel-1024-stereo.mp4"); + // openshot::FFmpegReader r("/home/jonathan/Videos/sintel-1024-stereo.mp4"); // openshot::FFmpegReader r("/home/jonathan/Videos/OpenShot_Now_In_3d.mp4"); - // openshot::FFmpegReader r("/home/jonathan/Videos/sintel_trailer-720p.mp4"); + openshot::FFmpegReader r("/home/jonathan/Videos/sintel_trailer-720p.mp4"); // openshot::FFmpegReader r("/home/jonathan/Aptana Studio Workspace/OpenShotLibrary/src/examples/piano.wav"); // openshot::FFmpegReader r("/home/jonathan/Music/Army of Lovers/Crucified/Army of Lovers - Crucified [Single Version].mp3"); // openshot::FFmpegReader r("/home/jonathan/Documents/OpenShot Art/test.jpeg"); @@ -67,7 +67,7 @@ int main() //Frame *f = r.GetFrame(1); - for (int frame = 1; frame <= 2000; frame++) + for (int frame = 1; frame <= 1000; frame++) { Frame *f = r.GetFrame(frame);