diff --git a/include/FFmpegWriter.h b/include/FFmpegWriter.h
index 9a765697..2996eac3 100644
--- a/include/FFmpegWriter.h
+++ b/include/FFmpegWriter.h
@@ -69,9 +69,12 @@ namespace openshot
int audio_input_frame_size;
int initial_audio_input_frame_size;
int audio_input_position;
-
AudioResampler *resampler;
+ deque queued_frames;
+ deque processed_frames;
+ map av_frames;
+
/// Add an audio output stream
AVStream* add_audio_stream();
@@ -99,11 +102,16 @@ namespace openshot
/// open video codec
void open_video(AVFormatContext *oc, AVStream *st);
+ /// process video frame
+ void process_video_packet(Frame* frame);
+
/// write audio frame
void write_audio_packet(Frame* frame);
/// write video frame
- void write_video_packet(Frame* frame);
+ void write_video_packet(Frame* frame, AVFrame* frame_final);
+
+
public:
@@ -132,11 +140,14 @@ namespace openshot
/// Write the file header (after the options are set)
void WriteHeader();
- /// Write a single frame
- void WriteFrame(Frame* frame);
+ /// Add a frame to the stack waiting to be encoded.
+ void AddFrame(Frame* frame);
+
+ /// Write all frames on the stack to the video file.
+ void WriteFrames();
/// Write a block of frames from a reader
- void WriteFrame(FileReaderBase* reader, int start, int length);
+ //void WriteFrame(FileReaderBase* reader, int start, int length);
/// Write the file trailer (after all frames are written)
void WriteTrailer();
diff --git a/include/FileWriterBase.h b/include/FileWriterBase.h
index ba8fb5a2..a3b583e4 100644
--- a/include/FileWriterBase.h
+++ b/include/FileWriterBase.h
@@ -62,8 +62,13 @@ namespace openshot
/// Information about the current media file
WriterInfo info;
- /// This method is required for all derived classes of FileWriterBase
- virtual void WriteFrame(Frame* frame) = 0;
+ /// This method is required for all derived classes of FileWriterBase. Add a frame to the stack
+ /// waiting to be encoded.
+ virtual void AddFrame(Frame* frame) = 0;
+
+ /// This method is required for all derived classes of FileWriterBase. Write all frames on the
+ /// stack.
+ virtual void WriteFrames() = 0;
/// Initialize the values of the WriterInfo struct. It is important for derived classes to call
/// this method, or the WriterInfo struct values will not be initialized.
diff --git a/src/FFmpegReader.cpp b/src/FFmpegReader.cpp
index 59f539b4..6de23dc4 100644
--- a/src/FFmpegReader.cpp
+++ b/src/FFmpegReader.cpp
@@ -4,7 +4,7 @@ using namespace openshot;
FFmpegReader::FFmpegReader(string path) throw(InvalidFile, NoStreamsFound, InvalidCodec)
: last_frame(0), is_seeking(0), seeking_pts(0), seeking_frame(0),
- audio_pts_offset(99999), video_pts_offset(99999), working_cache(10), final_cache(10), path(path),
+ audio_pts_offset(99999), video_pts_offset(99999), working_cache(12), final_cache(12), path(path),
is_video_seek(true), check_interlace(false), check_fps(false), enable_seek(true),
rescaler_position(0), num_of_rescalers(32) {
diff --git a/src/FFmpegWriter.cpp b/src/FFmpegWriter.cpp
index 6d2b2a4c..8da14a5a 100644
--- a/src/FFmpegWriter.cpp
+++ b/src/FFmpegWriter.cpp
@@ -281,30 +281,89 @@ void FFmpegWriter::WriteHeader()
avformat_write_header(oc, NULL);
}
-// Write a single frame
-void FFmpegWriter::WriteFrame(Frame* frame)
+// Add a frame to the queue waiting to be encoded.
+void FFmpegWriter::AddFrame(Frame* frame)
{
- // Encode and add the frame to the output file
- if (info.has_video && video_st)
- write_video_packet(frame);
+ // Add frame pointer to "queue", waiting to be processed the next
+ // time the WriteFrames() method is called.
+ queued_frames.push_back(frame);
+}
+
+// Write all frames in the queue to the video file.
+void FFmpegWriter::WriteFrames()
+{
+ //omp_set_num_threads(1);
+ #pragma omp parallel
+ {
+ #pragma omp master
+ {
+ // Loop through each queued frame
+ while (!queued_frames.empty())
+ {
+ // Get front frame (from the queue)
+ Frame *frame = queued_frames.front();
+
+ // Add to processed queue
+ processed_frames.push_back(frame);
+
+ // Encode and add the frame to the output file
+ if (info.has_video && video_st)
+ process_video_packet(frame);
+
+ if (info.has_audio && audio_st)
+ write_audio_packet(frame);
+
+
+ // Remove front item
+ queued_frames.pop_front();
+
+ } // end while
+
+ } // 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)
+ {
+ // Get AVFrame
+ AVFrame *frame_final = av_frames[frame];
+
+ // Write frame to video file
+ write_video_packet(frame, frame_final);
+
+ // Remove AVFrame
+ av_frames.erase(frame);
+ }
+
+ // Remove front item
+ processed_frames.pop_front();
+ }
- if (info.has_audio && audio_st)
- write_audio_packet(frame);
}
// Write a block of frames from a reader
-void FFmpegWriter::WriteFrame(FileReaderBase* reader, int start, int length)
-{
- // Loop through each frame (and encoded it)
- for (int number = start; number <= length; number++)
- {
- // Get the frame
- Frame *f = reader->GetFrame(number);
-
- // Encode frame
- WriteFrame(f);
- }
-}
+//void FFmpegWriter::WriteFrame(FileReaderBase* reader, int start, int length)
+//{
+// // Loop through each frame (and encoded it)
+// for (int number = start; number <= length; number++)
+// {
+// // Get the frame
+// Frame *f = reader->GetFrame(number);
+//
+// // Encode frame
+// WriteFrame(f);
+// }
+//}
// Write the file trailer (after all frames are written)
void FFmpegWriter::WriteTrailer()
@@ -723,42 +782,73 @@ AVFrame* FFmpegWriter::allocate_avframe(PixelFormat pix_fmt, int width, int heig
return new_av_frame;
}
-// write video frame
-void FFmpegWriter::write_video_packet(Frame* frame)
+// process video frame
+void FFmpegWriter::process_video_packet(Frame* frame)
{
// Get the codec
AVCodecContext *c;
c = video_st->codec;
- // Allocate an RGB frame & final output frame
- int bytes_source = 0;
- int bytes_final = 0;
- AVFrame *frame_source = allocate_avframe(PIX_FMT_RGB24, frame->GetWidth(), frame->GetHeight(), &bytes_source);
- AVFrame *frame_final = allocate_avframe(c->pix_fmt, info.width, info.height, &bytes_final);
-
- // Get a list of pixels from the frame.
- const Magick::PixelPacket *pixel_packets = frame->GetPixels();
-
- // Fill the AVFrame with RGB image data
- for (int packet = 0, row = 0; row < bytes_source; packet++, row+=3)
+ // Initialize the software scaler (if needed)
+ SwsContext *scaler = img_convert_ctx;
+ #pragma omp critical (image_scaler)
{
- // Update buffer (which is already linked to the AVFrame: pFrameRGB)
- frame_source->data[0][row] = pixel_packets[packet].red;
- frame_source->data[0][row+1] = pixel_packets[packet].green;
- frame_source->data[0][row+2] = pixel_packets[packet].blue;
+ if (!scaler)
+ // Init the software scaler from FFMpeg
+ scaler = sws_getContext(frame->GetWidth(), frame->GetHeight(), PIX_FMT_RGB24, info.width, info.height, c->pix_fmt, SWS_FAST_BILINEAR, NULL, NULL, NULL);
+ if (scaler == NULL)
+ throw OutOfMemory("Could not allocate SwsContext.", path);
}
+ #pragma omp task firstprivate(frame, c, scaler)
+ {
- // Resize image and convet pixel format to correct output format (for example: RGB to YUV420P)
- if (!img_convert_ctx)
- // Init the software scaler from FFMpeg
- img_convert_ctx = sws_getContext(frame->GetWidth(), frame->GetHeight(), PIX_FMT_RGB24, info.width, info.height, c->pix_fmt, SWS_FAST_BILINEAR, NULL, NULL, NULL);
- if (img_convert_ctx == NULL)
- throw OutOfMemory("Could not allocate SwsContext.", path);
+ // Allocate an RGB frame & final output frame
+ int bytes_source = 0;
+ int bytes_final = 0;
+ AVFrame *frame_source = allocate_avframe(PIX_FMT_RGB24, frame->GetWidth(), frame->GetHeight(), &bytes_source);
+ AVFrame *frame_final = allocate_avframe(c->pix_fmt, info.width, info.height, &bytes_final);
- // Resize & convert pixel format
- sws_scale(img_convert_ctx, frame_source->data, frame_source->linesize, 0,
- frame->GetHeight(), frame_final->data, frame_final->linesize);
+ // Get a list of pixels from the frame.
+ const Magick::PixelPacket *pixel_packets = frame->GetPixels();
+
+ // Fill the AVFrame with RGB image data
+ for (int packet = 0, row = 0; row < bytes_source; packet++, row+=3)
+ {
+ // Update buffer (which is already linked to the AVFrame: pFrameRGB)
+ frame_source->data[0][row] = pixel_packets[packet].red;
+ frame_source->data[0][row+1] = pixel_packets[packet].green;
+ frame_source->data[0][row+2] = pixel_packets[packet].blue;
+ }
+
+// SwsContext *scaler = sws_getContext(frame->GetWidth(), frame->GetHeight(), PIX_FMT_RGB24, info.width, info.height, c->pix_fmt, SWS_FAST_BILINEAR, NULL, NULL, NULL);
+// if (scaler == NULL)
+// throw OutOfMemory("Could not allocate SwsContext.", path);
+
+ // Resize & convert pixel format
+ #pragma omp critical (image_scaler)
+ sws_scale(scaler, frame_source->data, frame_source->linesize, 0,
+ frame->GetHeight(), frame_final->data, frame_final->linesize);
+
+ // Add resized AVFrame to av_frames map
+ #pragma omp critical (av_frames)
+ av_frames[frame] = frame_final;
+
+ // Deallocate memory
+ av_free(frame_source->data[0]);
+ av_free(frame_source);
+
+ } // end task
+
+
+}
+
+// write video frame
+void FFmpegWriter::write_video_packet(Frame* frame, AVFrame* frame_final)
+{
+ // Get the codec
+ AVCodecContext *c;
+ c = video_st->codec;
// Encode Picture and Write Frame
@@ -819,11 +909,10 @@ void FFmpegWriter::write_video_packet(Frame* frame)
}
// Deallocate memory
- av_free(frame_source->data[0]);
- av_free(frame_source);
av_free(frame_final->data[0]);
av_free(frame_final);
delete[] video_outbuf;
+
}
// Output the ffmpeg info about this format, streams, and codecs (i.e. dump format)
diff --git a/src/Main.cpp b/src/Main.cpp
index 646217f3..7b1ea125 100644
--- a/src/Main.cpp
+++ b/src/Main.cpp
@@ -14,25 +14,6 @@ void FrameReady(int number)
int main()
{
-// Cache c;
-// // Loop 30 times
-// for (int i = 0; i < 30; i++)
-// {
-// // Add blank frame to the cache
-// Frame *f = new Frame();
-// c.Add(i, f);
-//
-//
-// if (i == 27 || i == 28)
-// c.Remove(i);
-// else
-// c.SetCurrentFrame(i);
-//
-// }
-// cout << c.Count() << endl;
-// c.Clear();
-// cout << c.Count() << endl;
-
// openshot::FFmpegReader r("../../src/examples/test.mp4");
// openshot::FFmpegReader r("../../src/examples/test1.mp4");
@@ -84,20 +65,30 @@ int main()
// Output stream info
w.OutputStreamInfo();
- Frame *f = r.GetFrame(300);
+ //Frame *f = r.GetFrame(300);
- for (int frame = 1; frame <= 1000; frame++)
+ for (int frame = 1; frame <= 500; frame++)
{
- //Frame *f = r.GetFrame(frame);
+ Frame *f = r.GetFrame(frame);
// Apply effect
//f->AddEffect("flip");
// Write frame
- cout << "Write frame " << f->number << endl;
- w.WriteFrame(f);
+ cout << "queue frame " << f->number << endl;
+ w.AddFrame(f);
+
+ if (frame % 12 == 0)
+ {
+ cout << "-- Writing frames --" << endl;
+ w.WriteFrames();
+ }
}
+ // Write remaining frames
+ w.WriteFrames();
+ w.WriteFrames();
+
// Write Footer
w.WriteTrailer();