diff --git a/include/FFmpegWriter.h b/include/FFmpegWriter.h index 77215c72..929f8a86 100644 --- a/include/FFmpegWriter.h +++ b/include/FFmpegWriter.h @@ -55,6 +55,7 @@ namespace openshot { private: string path; + int cache_size; AVOutputFormat *fmt; AVFormatContext *oc; @@ -115,7 +116,8 @@ namespace openshot /// write video frame void write_video_packet(Frame* frame, AVFrame* frame_final); - + /// write all queued frames + void write_queued_frames(); public: @@ -125,12 +127,18 @@ namespace openshot /// Close the writer void Close(); + /// Get the cache size (number of frames to queue before writing) + int GetCacheSize() { return cache_size; }; + /// Output the ffmpeg info about this format, streams, and codecs (i.e. dump format) void OutputStreamInfo(); /// Set audio export options void SetAudioOptions(bool has_audio, string codec, int sample_rate, int channels, int bit_rate); + /// Set the cache size (number of frames to queue before writing) + int SetCacheSize(int new_size) { cache_size = new_size; }; + /// Set video export options void SetVideoOptions(bool has_video, string codec, Fraction fps, int width, int height, Fraction pixel_ratio, bool interlaced, bool top_field_first, int bit_rate); @@ -145,13 +153,10 @@ namespace openshot void WriteHeader(); /// 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(); + void WriteFrame(Frame* frame); /// 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 a3b583e4..f5bc92df 100644 --- a/include/FileWriterBase.h +++ b/include/FileWriterBase.h @@ -11,6 +11,7 @@ #include #include "Fraction.h" #include "Frame.h" +#include "FileReaderBase.h" using namespace std; @@ -62,13 +63,11 @@ namespace openshot /// Information about the current media file WriterInfo info; - /// 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 a Frame to the video file. + virtual void WriteFrame(Frame* frame) = 0; - /// This method is required for all derived classes of FileWriterBase. Write all frames on the - /// stack. - virtual void WriteFrames() = 0; + /// This method is required for all derived classes of FileWriterBase. Write a block of frames from a reader. + virtual void WriteFrame(FileReaderBase* reader, int start, int length) = 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/CMakeLists.txt b/src/CMakeLists.txt index 17625552..ba35a10b 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -34,7 +34,8 @@ FIND_PACKAGE(OpenMP) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}") ############### PROFILING ################# -#set(PROFILER "/usr/lib/libprofiler.so") +set(PROFILER "/usr/lib/libprofiler.so") +#set(PROFILER "/usr/lib/libtcmalloc.so") ############### CREATE LIBRARY ################# # Create shared openshot library diff --git a/src/FFmpegWriter.cpp b/src/FFmpegWriter.cpp index 45d5defe..0dcf4874 100644 --- a/src/FFmpegWriter.cpp +++ b/src/FFmpegWriter.cpp @@ -30,7 +30,7 @@ using namespace openshot; FFmpegWriter::FFmpegWriter(string path) throw (InvalidFile, InvalidFormat, InvalidCodec, InvalidOptions, OutOfMemory) : 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) + initial_audio_input_frame_size(0), resampler(NULL), img_convert_ctx(NULL), cache_size(12) { // Init FileInfo struct (clear all values) @@ -282,7 +282,7 @@ void FFmpegWriter::WriteHeader() } // Add a frame to the queue waiting to be encoded. -void FFmpegWriter::AddFrame(Frame* frame) +void FFmpegWriter::WriteFrame(Frame* frame) { // Add frame pointer to "queue", waiting to be processed the next // time the WriteFrames() method is called. @@ -291,10 +291,15 @@ void FFmpegWriter::AddFrame(Frame* frame) if (info.has_audio && audio_st) audio_frames.push_back(frame); + + // Write the frames once it reaches the correct cache size + if (queued_frames.size() == cache_size) + // Write frames to video file + write_queued_frames(); } // Write all frames in the queue to the video file. -void FFmpegWriter::WriteFrames() +void FFmpegWriter::write_queued_frames() { //omp_set_num_threads(1); #pragma omp parallel @@ -342,11 +347,15 @@ void FFmpegWriter::WriteFrames() // Add to deallocate queue (so we can remove the AVFrames when we are done) deallocate_frames.push_back(frame); - // Get AVFrame - AVFrame *frame_final = av_frames[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); + // Write frame to video file + write_video_packet(frame, frame_final); + } } // Remove front item @@ -379,22 +388,25 @@ void FFmpegWriter::WriteFrames() } // 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() { + // Write any remaining queued frames to video file + write_queued_frames(); + /* write the trailer, if any. the trailer must be written * before you close the CodecContexts open when you wrote the * header; otherwise write_trailer may try to use memory that @@ -459,8 +471,10 @@ void FFmpegWriter::add_avframe(Frame* frame, AVFrame* av_frame) { // Add AVFrame to map (if it does not already exist) if (!av_frames.count(frame)) - // Add + { + // Add av_frame av_frames[frame] = av_frame; + } else { // Do not add, and deallocate this AVFrame @@ -683,9 +697,9 @@ void FFmpegWriter::write_audio_packets() c = audio_st->codec; // Create a resampler (only once) + if (!resampler) + resampler = new AudioResampler(); AudioResampler *new_sampler = resampler; - if (!new_sampler) - new_sampler = new AudioResampler(); #pragma omp task firstprivate(c, new_sampler) { @@ -715,6 +729,7 @@ void FFmpegWriter::write_audio_packets() channels_in_frame = frame->GetAudioChannelsCount(); // Get audio sample array + //float* frame_samples_float = new float(total_frame_samples); float* frame_samples_float = frame->GetInterleavedAudioSamples(info.sample_rate, new_sampler, &samples_in_frame); // Calculate total samples @@ -867,12 +882,12 @@ void FFmpegWriter::process_video_packet(Frame* frame) c = video_st->codec; // Initialize the software scaler (if needed) - SwsContext *scaler = img_convert_ctx; - if (!scaler) + if (!img_convert_ctx) // 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) + 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); + SwsContext *scaler = img_convert_ctx; #pragma omp task firstprivate(frame, c, scaler) { diff --git a/src/Frame.cpp b/src/Frame.cpp index 242f5aa8..e048895c 100644 --- a/src/Frame.cpp +++ b/src/Frame.cpp @@ -294,6 +294,13 @@ float* Frame::GetInterleavedAudioSamples(int new_sample_rate, AudioResampler* re } } + // Clear resampled buffer (if any) + if (resampled_buffer) + { + resampled_buffer->clear(); + delete resampled_buffer; + } + // Update sample count (since it might have changed due to resampling) *sample_count = num_of_samples; @@ -322,14 +329,14 @@ int Frame::GetAudioSamplesRate() // Get pixel data (as packets) const Magick::PixelPacket* Frame::GetPixels() { - // Return arry of pixel packets + // Return array of pixel packets return image->getConstPixels(0,0, image->columns(), image->rows()); } // Get pixel data (for only a single scan-line) const Magick::PixelPacket* Frame::GetPixels(int row) { - // Return arry of pixel packets + // Return array of pixel packets return image->getConstPixels(0,row, image->columns(), 1); } @@ -343,9 +350,9 @@ const Magick::PixelPacket* Frame::GetPixels(unsigned int width, unsigned int hei small_image->colorize(255, 0, 0, Magick::Color(0,0,255)); small_image->blur(5.0, 5.0); - stringstream file; - file << "frame" << frame << ".png"; - small_image->write(file.str()); +// stringstream file; +// file << "frame" << frame << ".png"; +// small_image->write(file.str()); // Return arry of pixel packets return small_image->getConstPixels(0,0, small_image->columns(), small_image->rows()); diff --git a/src/Main.cpp b/src/Main.cpp index 4d170ad9..e5ae3c66 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/00001.mts"); - // 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"); @@ -38,7 +38,7 @@ int main() // Set options w.SetAudioOptions(true, "libvorbis", 44100, 2, 128000); - w.SetVideoOptions(true, "libvpx", Fraction(25, 1), 640, 360, Fraction(1,1), false, false, 2000000); + w.SetVideoOptions(true, "libvpx", Fraction(24, 1), 640, 360, Fraction(1,1), false, false, 2000000); // Prepare Streams w.PrepareStreams(); @@ -67,7 +67,7 @@ int main() //Frame *f = r.GetFrame(1); - for (int frame = 1; frame <= 500; frame++) + for (int frame = 1; frame <= 1000; frame++) { Frame *f = r.GetFrame(frame); @@ -76,19 +76,10 @@ int main() // Write frame cout << "queue frame " << frame << endl; - w.AddFrame(f); + w.WriteFrame(f); - if (frame % 12 == 0) - { - cout << "-- Writing frames --" << endl; - w.WriteFrames(); - } } - // Write remaining frames - w.WriteFrames(); - w.WriteFrames(); - // Write Footer w.WriteTrailer();