diff --git a/include/Cache.h b/include/Cache.h index 6a850cec..a9e0c11e 100644 --- a/include/Cache.h +++ b/include/Cache.h @@ -28,7 +28,7 @@ namespace openshot { class Cache { private: int max_frames; ///< This is the max number of "previous" frames to cache - map frames; ///< This map holds the frame number and Frame objects + map frames; ///< This map holds the frame number and Frame objects deque frame_numbers; ///< This queue holds a sequential list of cached Frame numbers int current_frame; ///< This is the last requested frame (used to dynamically adjust the max_frames) @@ -43,20 +43,23 @@ namespace openshot { Cache(int max_frames); /// Add a Frame to the cache - void Add(int frame_number, Frame frame); + void Add(int frame_number, Frame* frame); /// Check for the existence of a frame in the cache bool Exists(int frame_number); /// Get a frame from the cache - Frame GetFrame(int frame_number); + Frame* GetFrame(int frame_number); /// Get the smallest frame number - Frame GetSmallestFrame(); + Frame* GetSmallestFrame(); /// Remove a specific frame void Remove(int frame_number); + /// Remove a specific frame + void Remove(int frame_number, bool delete_data); + /// Clear the cache of all frames void Clear(); diff --git a/include/FFmpegReader.h b/include/FFmpegReader.h index c349ab89..7ab1ea33 100644 --- a/include/FFmpegReader.h +++ b/include/FFmpegReader.h @@ -67,6 +67,10 @@ namespace openshot bool check_interlace; bool check_fps; + int num_of_rescalers; + int rescaler_position; + vector image_rescalers; + Cache final_cache; Cache working_cache; map packets; @@ -105,7 +109,7 @@ namespace openshot int ConvertVideoPTStoFrame(int pts); /// Create a new Frame (or return an existing one) and add it to the working queue. - Frame CreateFrame(int requested_frame); + Frame* CreateFrame(int requested_frame); /// Calculate Starting video frame and sample # for an audio PTS audio_packet_location GetAudioPTSLocation(int pts); @@ -128,6 +132,9 @@ namespace openshot /// Get the PTS for the current video packet int GetVideoPTS(); + /// Init a collection of software rescalers (thread safe) + void InitScalers(); + /// Open File - which is called by the constructor automatically void Open(); @@ -138,7 +145,7 @@ namespace openshot void ProcessAudioPacket(int requested_frame, int target_frame, int starting_sample); /// Read the stream until we find the requested Frame - Frame ReadStream(int requested_frame); + Frame* ReadStream(int requested_frame); /// Remove AVFrame from cache (and deallocate it's memory) void RemoveAVFrame(AVFrame*); @@ -146,6 +153,9 @@ namespace openshot /// Remove AVPacket from cache (and deallocate it's memory) void RemoveAVPacket(AVPacket*); + /// Remove & deallocate all software scalers + void RemoveScalers(); + /// Seek to a specific Frame. This is not always frame accurate, it's more of an estimation on many codecs. void Seek(int requested_frame); @@ -175,7 +185,7 @@ namespace openshot /// /// @returns The requested frame of video /// @param[requested_frame] number The frame number that is requested. - Frame GetFrame(int requested_frame); + Frame* GetFrame(int requested_frame); }; } diff --git a/include/FFmpegWriter.h b/include/FFmpegWriter.h index ad57474d..9a765697 100644 --- a/include/FFmpegWriter.h +++ b/include/FFmpegWriter.h @@ -59,6 +59,7 @@ namespace openshot AVOutputFormat *fmt; AVFormatContext *oc; AVStream *audio_st, *video_st; + SwsContext *img_convert_ctx; double audio_pts, video_pts; int16_t *samples; uint8_t *audio_outbuf; diff --git a/include/FileReaderBase.h b/include/FileReaderBase.h index 0b54e0f2..9adf6cc1 100644 --- a/include/FileReaderBase.h +++ b/include/FileReaderBase.h @@ -69,7 +69,7 @@ namespace openshot /// /// @returns The requested frame of video /// @param[in] number The frame number that is requested. - virtual Frame GetFrame(int number) = 0; + virtual Frame* GetFrame(int number) = 0; /// Initialize the values of the ReaderInfo struct. It is important for derived classes to call /// this method, or the ReaderInfo struct values will not be initialized. diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 54df9cd2..17625552 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -33,6 +33,9 @@ FIND_PACKAGE(OpenMP) # Add the OpenMP compiler flag set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}") +############### PROFILING ################# +#set(PROFILER "/usr/lib/libprofiler.so") + ############### CREATE LIBRARY ################# # Create shared openshot library add_library(openshot SHARED @@ -59,7 +62,7 @@ set_target_properties(openshot SOVERSION ${SO_VERSION}) # Link all referenced libraries -target_link_libraries(openshot ${ImageMagick_LIBRARIES} ${FFMPEG_LIBRARIES} ${LIBJUCE_LIBRARIES} ${SDL_LIBRARY}) #${GTK2_LIBRARIES} +target_link_libraries(openshot ${ImageMagick_LIBRARIES} ${FFMPEG_LIBRARIES} ${LIBJUCE_LIBRARIES} ${SDL_LIBRARY} ${PROFILER}) ############### TEST EXECUTABLE ################ @@ -67,7 +70,7 @@ target_link_libraries(openshot ${ImageMagick_LIBRARIES} ${FFMPEG_LIBRARIES} ${LI add_executable(example Main.cpp) # Link test executable to the new library -target_link_libraries(example openshot) +target_link_libraries(example openshot ${PROFILER} ) ############### SWIG PYTHON BINDINGS ################ FIND_PACKAGE(SWIG REQUIRED) diff --git a/src/Cache.cpp b/src/Cache.cpp index 6b3569b0..ab05049b 100644 --- a/src/Cache.cpp +++ b/src/Cache.cpp @@ -16,7 +16,7 @@ Cache::Cache() : max_frames(20), current_frame(0) { }; Cache::Cache(int max_frames) : max_frames(max_frames), current_frame(0) { }; // Add a Frame to the cache -void Cache::Add(int frame_number, Frame frame) +void Cache::Add(int frame_number, Frame *frame) { // Only add frame if it does not exist in the cache if (!frames.count(frame_number)) @@ -24,9 +24,6 @@ void Cache::Add(int frame_number, Frame frame) // Add frame to queue and map frames[frame_number] = frame; frame_numbers.push_front(frame_number); - - // Clean up older frames (that exceed the max frames) - CleanUp(); } else { @@ -47,7 +44,7 @@ bool Cache::Exists(int frame_number) } // Get a frame from the cache -Frame Cache::GetFrame(int frame_number) +Frame* Cache::GetFrame(int frame_number) { // Does frame exists in cache? if (Exists(frame_number)) @@ -61,7 +58,7 @@ Frame Cache::GetFrame(int frame_number) } // Get the smallest frame number -Frame Cache::GetSmallestFrame() +Frame* Cache::GetSmallestFrame() { // Loop through frame numbers deque::iterator itr; @@ -77,10 +74,10 @@ Frame Cache::GetSmallestFrame() } // Remove a specific frame -void Cache::Remove(int frame_number) +void Cache::Remove(int frame_number, bool delete_data) { // Get the frame (or throw exception) - Frame f = GetFrame(frame_number); + Frame *f = GetFrame(frame_number); // Loop through frame numbers deque::iterator itr; @@ -94,17 +91,35 @@ void Cache::Remove(int frame_number) } } + // Deallocate frame (if requested) + if (delete_data) + delete frames[frame_number]; + // Remove frame from map frames.erase(frame_number); } +// Remove a specific frame +void Cache::Remove(int frame_number) +{ + // Remove and delete frame data + Remove(frame_number, true); +} + // Clear the cache of all frames void Cache::Clear() { - // clear map - frames.clear(); + deque::iterator itr; + for(itr = frame_numbers.begin(); itr != frame_numbers.end(); ++itr) + { + // Deallocate frame + delete frames[*itr]; - // pop each of the frames from the queue... which emptys the queue + // Remove frame from map + frames.erase(*itr); + } + + // pop each of the frames from the queue... which empties the queue while(!frame_numbers.empty()) frame_numbers.pop_back(); } diff --git a/src/FFmpegReader.cpp b/src/FFmpegReader.cpp index c607a5b0..59f539b4 100644 --- a/src/FFmpegReader.cpp +++ b/src/FFmpegReader.cpp @@ -5,7 +5,8 @@ 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), - is_video_seek(true), check_interlace(false), check_fps(false), enable_seek(true) { + is_video_seek(true), check_interlace(false), check_fps(false), enable_seek(true), + rescaler_position(0), num_of_rescalers(32) { // Init FileInfo struct (clear all values) InitFileInfo(); @@ -16,14 +17,39 @@ FFmpegReader::FFmpegReader(string path) throw(InvalidFile, NoStreamsFound, Inval // Open the file (if possible) Open(); - // Check for the correct frames per second (only once) - //if (info.has_video) - // CheckFPS(); + // Init rescalers (if video stream detected) + if (info.has_video) + InitScalers(); // Get 1st frame GetFrame(1); } +// Init a collection of software rescalers (thread safe) +void FFmpegReader::InitScalers() +{ + // Init software rescalers vector (many of them, one for each thread) + for (int x = 0; x < num_of_rescalers; x++) + { + SwsContext *img_convert_ctx = sws_getContext(info.width, info.height, pCodecCtx->pix_fmt, info.width, + info.height, PIX_FMT_RGB24, SWS_FAST_BILINEAR, NULL, NULL, NULL); + + // Add rescaler to vector + image_rescalers.push_back(img_convert_ctx); + } +} + +// Remove & deallocate all software scalers +void FFmpegReader::RemoveScalers() +{ + // Close all rescalers + for (int x = 0; x < num_of_rescalers; x++) + sws_freeContext(image_rescalers[x]); + + // Clear vector + image_rescalers.clear(); +} + void FFmpegReader::Open() { // Initialize format context @@ -116,6 +142,10 @@ void FFmpegReader::Close() avcodec_close(aCodecCtx); } + // Clear image scalers + if (info.has_video) + RemoveScalers(); + // Clear cache working_cache.Clear(); final_cache.Clear(); @@ -232,12 +262,11 @@ void FFmpegReader::UpdateVideoInfo() } -Frame FFmpegReader::GetFrame(int requested_frame) +Frame* FFmpegReader::GetFrame(int requested_frame) { // Check the cache for this frame if (final_cache.Exists(requested_frame)) { - cout << "Cached Frame!" << endl; // Return the cached frame return final_cache.GetFrame(requested_frame); } @@ -258,7 +287,6 @@ Frame FFmpegReader::GetFrame(int requested_frame) if (abs(diff) >= 0 && abs(diff) <= 19) { // Continue walking the stream - cout << " >> CLOSE, SO WALK THE STREAM" << endl; return ReadStream(requested_frame); } else @@ -277,7 +305,7 @@ Frame FFmpegReader::GetFrame(int requested_frame) } // Read the stream until we find the requested Frame -Frame FFmpegReader::ReadStream(int requested_frame) +Frame* FFmpegReader::ReadStream(int requested_frame) { // Allocate video frame bool end_of_stream = false; @@ -308,8 +336,11 @@ Frame FFmpegReader::ReadStream(int requested_frame) if (packet->stream_index == videoStream) { // Check the status of a seek (if any) - #pragma omp critical (openshot_cache) - check_seek = CheckSeek(true); + if (is_seeking) + #pragma omp critical (openshot_cache) + check_seek = CheckSeek(true); + else + check_seek = false; if (check_seek) // Jump to the next iteration of this loop @@ -321,8 +352,6 @@ Frame FFmpegReader::ReadStream(int requested_frame) // Check if the AVFrame is finished and set it if (frame_finished) { - cout << endl << "VIDEO PACKET (PTS: " << GetVideoPTS() << ")" << endl; - // Update PTS / Frame Offset (if any) UpdatePTSOffset(true); @@ -334,11 +363,12 @@ Frame FFmpegReader::ReadStream(int requested_frame) // Audio packet else if (packet->stream_index == audioStream) { - cout << "AUDIO PACKET (PTS: " << packet->pts << ")" << endl; - // Check the status of a seek (if any) - #pragma omp critical (openshot_cache) - check_seek = CheckSeek(false); + if (is_seeking) + #pragma omp critical (openshot_cache) + check_seek = CheckSeek(false); + else + check_seek = false; if (check_seek) // Jump to the next iteration of this loop @@ -528,11 +558,17 @@ void FFmpegReader::ProcessVideoPacket(int requested_frame) AVPacket *my_packet = packets[packet]; AVFrame *my_frame = frames[pFrame]; + // Get a unique rescaler (for this thread) + SwsContext *img_convert_ctx = image_rescalers[rescaler_position]; + rescaler_position++; + if (rescaler_position == num_of_rescalers) + rescaler_position = 0; + // Add video frame to list of processing video frames #pragma omp critical (processing_list) processing_video_frames[current_frame] = current_frame; - #pragma omp task firstprivate(current_frame, my_cache, my_packet, my_frame, height, width, video_length, pix_fmt) + #pragma omp task firstprivate(current_frame, my_cache, my_packet, my_frame, height, width, video_length, pix_fmt, img_convert_ctx) { // Create variables for a RGB Frame (since most videos are not in RGB, we must convert it) AVFrame *pFrameRGB = NULL; @@ -553,37 +589,21 @@ void FFmpegReader::ProcessVideoPacket(int requested_frame) // of AVPicture avpicture_fill((AVPicture *) pFrameRGB, buffer, PIX_FMT_RGB24, width, height); - struct SwsContext *img_convert_ctx = NULL; - - // Convert the image into RGB (for ImageMagick++) - if (img_convert_ctx == NULL) { - img_convert_ctx = sws_getContext(width, height, pix_fmt, width, - height, PIX_FMT_RGB24, SWS_FAST_BILINEAR, NULL, NULL, NULL); - if (img_convert_ctx == NULL) { - fprintf(stderr, "Cannot initialize the conversion context!\n"); - exit(1); - } - } - // Resize / Convert to RGB sws_scale(img_convert_ctx, my_frame->data, my_frame->linesize, 0, height, pFrameRGB->data, pFrameRGB->linesize); - // Deallocate swscontext - sws_freeContext(img_convert_ctx); + Frame *f = NULL; + #pragma omp critical (openshot_cache) + // Create or get frame object + f = CreateFrame(current_frame); + // Add Image data to frame + f->AddImage(width, height, "RGB", Magick::CharPixel, buffer); #pragma omp critical (openshot_cache) - { - // Create or get frame object - Frame f = CreateFrame(current_frame); - - // Add Image data to frame - f.AddImage(width, height, "RGB", Magick::CharPixel, buffer); - // Update working cache - my_cache->Add(f.number, f); - } + my_cache->Add(f->number, f); // Free the RGB image av_free(buffer); @@ -754,28 +774,17 @@ void FFmpegReader::ProcessAudioPacket(int requested_frame, int target_frame, int #pragma omp critical (processing_list) processing_audio_frames[starting_frame_number] = starting_frame_number; + Frame *f = NULL; #pragma omp critical (openshot_cache) - { // Create or get frame object - Frame f = CreateFrame(starting_frame_number); + f = CreateFrame(starting_frame_number); - // Add samples for current channel to the frame - f.AddAudio(channel_filter, start, iterate_channel_buffer, samples, 1.0f); + // Add samples for current channel to the frame + f->AddAudio(channel_filter, start, iterate_channel_buffer, samples, 1.0f); + #pragma omp critical (openshot_cache) // Add or update cache - my_cache->Add(f.number, f); - - // DEBUG -// for (int s = start; s 500) -// { -// cout << iterate_channel_buffer[s] << endl; -// } -// else if (f.number == 2 && s < 34) -// { -// cout << iterate_channel_buffer[s] << endl; -// } - } + my_cache->Add(f->number, f); // Decrement remaining samples remaining_samples -= samples; @@ -1028,13 +1037,13 @@ int FFmpegReader::GetSamplesPerFrame(int frame_number) } // Create a new Frame (or return an existing one) and add it to the working queue. -Frame FFmpegReader::CreateFrame(int requested_frame) +Frame* FFmpegReader::CreateFrame(int requested_frame) { // Check working cache if (working_cache.Exists(requested_frame)) { // Return existing frame - Frame output = working_cache.GetFrame(requested_frame); + Frame* output = working_cache.GetFrame(requested_frame); return output; } @@ -1044,9 +1053,9 @@ Frame FFmpegReader::CreateFrame(int requested_frame) int samples_per_frame = GetSamplesPerFrame(requested_frame); // Create a new frame on the working cache - Frame f(requested_frame, info.width, info.height, "#000000", samples_per_frame, info.channels); - f.SetPixelRatio(info.pixel_ratio.num, info.pixel_ratio.den); - f.SetSampleRate(info.sample_rate); + Frame *f = new Frame(requested_frame, info.width, info.height, "#000000", samples_per_frame, info.channels); + f->SetPixelRatio(info.pixel_ratio.num, info.pixel_ratio.den); + f->SetSampleRate(info.sample_rate); working_cache.Add(requested_frame, f); @@ -1081,22 +1090,22 @@ void FFmpegReader::CheckWorkingFrames(bool end_of_stream) break; // Get the front frame of working cache - Frame f = working_cache.GetSmallestFrame(); + Frame *f = working_cache.GetSmallestFrame(); - bool is_video_ready = (f.number < smallest_video_frame); - bool is_audio_ready = (f.number < smallest_audio_frame); + bool is_video_ready = (f->number < smallest_video_frame); + bool is_audio_ready = (f->number < smallest_audio_frame); // Check if working frame is final if ((!end_of_stream && is_video_ready && is_audio_ready) || end_of_stream || working_cache.Count() >= 200) { // Move frame to final cache - final_cache.Add(f.number, f); + final_cache.Add(f->number, f); // Remove frame from working cache - working_cache.Remove(f.number); + working_cache.Remove(f->number, false); // Update last frame processed - last_frame = f.number; + last_frame = f->number; } else // Stop looping diff --git a/src/FFmpegWriter.cpp b/src/FFmpegWriter.cpp index 0448119b..6d2b2a4c 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), - converted_audio(NULL), initial_audio_input_frame_size(0), resampler(NULL) + converted_audio(NULL), initial_audio_input_frame_size(0), resampler(NULL), img_convert_ctx(NULL) { // Init FileInfo struct (clear all values) @@ -299,10 +299,10 @@ void FFmpegWriter::WriteFrame(FileReaderBase* reader, int start, int length) for (int number = start; number <= length; number++) { // Get the frame - Frame f = reader->GetFrame(number); + Frame *f = reader->GetFrame(number); // Encode frame - WriteFrame(&f); + WriteFrame(f); } } @@ -321,6 +321,9 @@ void FFmpegWriter::close_video(AVFormatContext *oc, AVStream *st) { avcodec_close(st->codec); + // Deallocate swscontext + sws_freeContext(img_convert_ctx); + //av_free(picture->data[0]); //av_free(picture); //if (tmp_picture) { @@ -747,10 +750,9 @@ void FFmpegWriter::write_video_packet(Frame* frame) // Resize image and convet pixel format to correct output format (for example: RGB to YUV420P) - SwsContext *img_convert_ctx = NULL; - - // 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) + // 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); @@ -758,9 +760,6 @@ void FFmpegWriter::write_video_packet(Frame* frame) sws_scale(img_convert_ctx, frame_source->data, frame_source->linesize, 0, frame->GetHeight(), frame_final->data, frame_final->linesize); - // Deallocate swscontext - sws_freeContext(img_convert_ctx); - // Encode Picture and Write Frame int video_outbuf_size = 200000; diff --git a/src/Frame.cpp b/src/Frame.cpp index 6026292a..242f5aa8 100644 --- a/src/Frame.cpp +++ b/src/Frame.cpp @@ -13,7 +13,7 @@ using namespace openshot; Frame::Frame() : number(1), image(0), audio(0), pixel_ratio(1,1), sample_rate(48000), channels(2) { // Init the image magic and audio buffer - image = new Magick::Image(Magick::Geometry(300,200), Magick::Color("red")); + image = new Magick::Image(Magick::Geometry(1,1), Magick::Color("red")); audio = new juce::AudioSampleBuffer(channels, 1600); // initialize the audio samples to zero (silence) @@ -25,7 +25,7 @@ Frame::Frame(int number, int width, int height, string color) : number(number), image(0), audio(0), pixel_ratio(1,1), sample_rate(48000), channels(2) { // Init the image magic and audio buffer - image = new Magick::Image(Magick::Geometry(width, height), Magick::Color(color)); + image = new Magick::Image(Magick::Geometry(1, 1), Magick::Color(color)); audio = new juce::AudioSampleBuffer(channels, 1600); // initialize the audio samples to zero (silence) @@ -49,7 +49,7 @@ Frame::Frame(int number, int samples, int channels) : number(number), image(0), audio(0), pixel_ratio(1,1), sample_rate(48000), channels(channels) { // Init the image magic and audio buffer - image = new Magick::Image(Magick::Geometry(300, 200), Magick::Color("white")); + image = new Magick::Image(Magick::Geometry(1, 1), Magick::Color("white")); audio = new juce::AudioSampleBuffer(channels, samples); // initialize the audio samples to zero (silence) @@ -61,7 +61,7 @@ Frame::Frame(int number, int width, int height, string color, int samples, int c : number(number), image(0), audio(0), pixel_ratio(1,1), sample_rate(48000), channels(channels) { // Init the image magic and audio buffer - image = new Magick::Image(Magick::Geometry(width, height), Magick::Color(color)); + image = new Magick::Image(Magick::Geometry(1, 1), Magick::Color(color)); audio = new juce::AudioSampleBuffer(channels, samples); // initialize the audio samples to zero (silence) @@ -100,7 +100,6 @@ Frame& Frame::operator= (const Frame& other) // Copy data and pointers from another Frame instance void Frame::DeepCopy(const Frame& other) { - // ignore copy if objects are the same number = other.number; image = new Magick::Image(*(other.image)); audio = new juce::AudioSampleBuffer(*(other.audio)); @@ -115,7 +114,6 @@ void Frame::DeletePointers() // deallocate image memory delete image; image = NULL; - // deallocate audio memory delete audio; audio = NULL; } diff --git a/src/Main.cpp b/src/Main.cpp index a1365212..81962a42 100644 --- a/src/Main.cpp +++ b/src/Main.cpp @@ -14,12 +14,32 @@ 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"); - openshot::FFmpegReader r("../../src/examples/piano.wav"); + // 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/Aptana Studio Workspace/OpenShotLibrary/src/examples/piano.wav"); @@ -32,15 +52,15 @@ int main() r.DisplayInfo(); // Create a writer - FFmpegWriter w("/home/jonathan/output.webm"); - w.DisplayInfo(); + //FFmpegWriter w("/home/jonathan/output.webm"); + //w.DisplayInfo(); // Set options - w.SetAudioOptions(true, "libvorbis", 44100, 2, 128000); + //w.SetAudioOptions(true, "libvorbis", 44100, 2, 128000); //w.SetVideoOptions(true, "libvpx", Fraction(25, 1), 640, 360, Fraction(1,1), false, false, 2000000); // Prepare Streams - w.PrepareStreams(); + //w.PrepareStreams(); // Set Options // w.SetOption(VIDEO_STREAM, "quality", "good"); @@ -59,28 +79,28 @@ int main() // w.SetOption(VIDEO_STREAM, "arnr_type", "3"); // Write header - w.WriteHeader(); + //w.WriteHeader(); // Output stream info - w.OutputStreamInfo(); + //w.OutputStreamInfo(); - for (int frame = 1; frame <= 120; frame++) + for (int frame = 1; frame <= 1000; frame++) { - Frame f = r.GetFrame(frame); + Frame *f = r.GetFrame(frame); // Apply effect - //f.AddEffect("oilPaint"); + //f->AddEffect("flip"); // Write frame - cout << "Write frame " << f.number << endl; - w.WriteFrame(&f); + cout << "Write frame " << f->number << endl; + //w.WriteFrame(f); } // Write Footer - w.WriteTrailer(); + //w.WriteTrailer(); // Close writer & reader - w.Close(); + //w.Close(); r.Close(); diff --git a/src/Player.cpp b/src/Player.cpp index ad7b1139..4b2865d3 100644 --- a/src/Player.cpp +++ b/src/Player.cpp @@ -25,11 +25,11 @@ void Player::SetFrameCallback(CallbackPtr p_callback, void *p_pythonmethod) // double *Pixels = new double[100]; // for (int i = 0; i < 100; i++) // Pixels[i] = i + 100; - Frame f = reader->GetFrame(300); + Frame *f = reader->GetFrame(300); // invoke method pointer 10 times for (int i = 0; i < 30; i++) - callback(i, f.GetWidth(), f.GetHeight(), f.GetPixels(), pythonmethod); + callback(i, f->GetWidth(), f->GetHeight(), f->GetPixels(), pythonmethod); }; // Manually invoke function (if any) @@ -41,11 +41,11 @@ void Player::Push() // double *Pixels = new double[100]; // for (int i = 0; i < 100; i++) // Pixels[i] = i + 200; - Frame f = reader->GetFrame(500); + Frame *f = reader->GetFrame(500); // manually invoke method for (int i = 30; i < 20; i++) - callback(i, f.GetWidth(), f.GetHeight(), f.GetPixels(), pythonmethod); + callback(i, f->GetWidth(), f->GetHeight(), f->GetPixels(), pythonmethod); } // Play the video @@ -79,7 +79,7 @@ cout << "START PREPARING SURFACES..." << endl; for (int stuff = 0; stuff < number_of_cycles; stuff++) { // Get pointer to pixels of image. - Frame f = reader->GetFrame(300 + stuff); + Frame *f = reader->GetFrame(300 + stuff); // Create YUV Overlay SDL_Overlay *bmp; @@ -88,7 +88,7 @@ for (int stuff = 0; stuff < number_of_cycles; stuff++) // Get pixels for resized frame (for reduced color needed by YUV420p) int divider = 2; - const Magick::PixelPacket *reduced_color = f.GetPixels(reader->info.width / divider, reader->info.height / divider, f.number); + const Magick::PixelPacket *reduced_color = f->GetPixels(reader->info.width / divider, reader->info.height / divider, f->number); int number_of_colors = (reader->info.width / divider) * (reader->info.height / divider); int pixel_index = 0; @@ -97,7 +97,7 @@ for (int stuff = 0; stuff < number_of_cycles; stuff++) for (int row = 0; row < screen->h; row++) { // Get array of pixels for this row //cout << "row: " << row << endl; - const Magick::PixelPacket *imagepixels = f.GetPixels(row); + const Magick::PixelPacket *imagepixels = f->GetPixels(row); // Loop through pixels on this row for (int column = 0; column < screen->w; column++) { diff --git a/tests/Cache_Tests.cpp b/tests/Cache_Tests.cpp index 93765114..a0de4a79 100644 --- a/tests/Cache_Tests.cpp +++ b/tests/Cache_Tests.cpp @@ -13,7 +13,8 @@ TEST(Cache_Default_Constructor) for (int i = 0; i < 30; i++) { // Add blank frame to the cache - c.Add(i, Frame()); + Frame *f = new Frame(); + c.Add(i, f); } CHECK_EQUAL(30, c.Count()); // Cache should still have all 30 items, because the current frame is 0 @@ -29,7 +30,8 @@ TEST(Cache_Max_Frames_Constructor) for (int i = 20; i > 0; i--) { // Add blank frame to the cache - c.Add(i, Frame()); + Frame *f = new Frame(); + c.Add(i, f); } // Cache should have all 20 (since current frame is 0) @@ -45,10 +47,17 @@ TEST(Cache_Max_Frames_Constructor) for (int i = 9; i > 0; i--) { // Add blank frame to the cache - c.Add(i, Frame()); + Frame *f = new Frame(); + c.Add(i, f); } - // Count should still be 11, since all these frames were previous to 15 + // Count should be 20, since adding frames does not clean up old ones + CHECK_EQUAL(20, c.Count()); + + // Set current frame to 15, which should clean up many older frames + c.SetCurrentFrame(15); + + // Count should be 11, since we've cleaned up again CHECK_EQUAL(11, c.Count()); // Check which 10 items the cache kept @@ -73,23 +82,17 @@ TEST(Cache_Max_Frames_Constructor) c.SetCurrentFrame(18); CHECK_EQUAL(8, c.Count()); - // Add first 18 frames again - for (int i = 18; i > 0; i--) - { - // Add blank frame to the cache - c.Add(i, Frame()); - } - - // Count should be 8 - CHECK_EQUAL(8, c.Count()); - // Increase frames to 50 for (int i = 1; i <= 50; i++) { // Add blank frame to the cache - c.Add(i, Frame()); + Frame *f = new Frame(); + c.Add(i, f); } + // Set current frame, which cleans up old frames + c.SetCurrentFrame(18); + // Count should be 38 (5 previous to 18 + all frames after 18) CHECK_EQUAL(38, c.Count()); @@ -104,7 +107,8 @@ TEST(Cache_Clear) for (int i = 0; i < 10; i++) { // Add blank frame to the cache - c.Add(i, Frame()); + Frame *f = new Frame(); + c.Add(i, f); } // Cache should only have 10 items @@ -126,7 +130,8 @@ TEST(Cache_Add_Duplicate_Frames) for (int i = 0; i < 10; i++) { // Add blank frame to the cache (each frame is #1) - c.Add(1, Frame()); + Frame *f = new Frame(); + c.Add(1, f); } // Cache should only have 1 items (since all frames were frame #1) @@ -142,7 +147,8 @@ TEST(Cache_Check_If_Frame_Exists) for (int i = 1; i < 6; i++) { // Add blank frame to the cache - c.Add(i, Frame()); + Frame *f = new Frame(); + c.Add(i, f); } // Check if certain frames exists (only 1-5 exist) @@ -166,18 +172,18 @@ TEST(Cache_GetFrame) Frame green(3, 500, 500, "green"); // Add frames to cache - c.Add(red.number, red); - c.Add(blue.number, blue); - c.Add(green.number, green); + c.Add(red.number, &red); + c.Add(blue.number, &blue); + c.Add(green.number, &green); // Get frames CHECK_THROW(c.GetFrame(0), OutOfBoundsFrame); CHECK_THROW(c.GetFrame(4), OutOfBoundsFrame); // Check if certain frames exists (only 1-5 exist) - CHECK_EQUAL(1, c.GetFrame(1).number); - CHECK_EQUAL(2, c.GetFrame(2).number); - CHECK_EQUAL(3, c.GetFrame(3).number); + CHECK_EQUAL(1, c.GetFrame(1)->number); + CHECK_EQUAL(2, c.GetFrame(2)->number); + CHECK_EQUAL(3, c.GetFrame(3)->number); } TEST(Cache_GetSmallest) @@ -191,21 +197,21 @@ TEST(Cache_GetSmallest) Frame green(3, 500, 500, "green"); // Add frames to cache - c.Add(red.number, red); - c.Add(blue.number, blue); - c.Add(green.number, green); + c.Add(red.number, &red); + c.Add(blue.number, &blue); + c.Add(green.number, &green); // Check if frame 1 is the front - CHECK_EQUAL(1, c.GetSmallestFrame().number); + CHECK_EQUAL(1, c.GetSmallestFrame()->number); // Check if frame 1 is STILL the front - CHECK_EQUAL(1, c.GetSmallestFrame().number); + CHECK_EQUAL(1, c.GetSmallestFrame()->number); // Erase frame 1 - c.Remove(1); + c.Remove(1, false); // Check if frame 2 is the front - CHECK_EQUAL(2, c.GetSmallestFrame().number); + CHECK_EQUAL(2, c.GetSmallestFrame()->number); } TEST(Cache_Remove) @@ -219,9 +225,9 @@ TEST(Cache_Remove) Frame green(3, 500, 500, "green"); // Add frames to cache - c.Add(red.number, red); - c.Add(blue.number, blue); - c.Add(green.number, green); + c.Add(red.number, &red); + c.Add(blue.number, &blue); + c.Add(green.number, &green); // Check if count is 3 CHECK_EQUAL(3, c.Count()); @@ -230,7 +236,7 @@ TEST(Cache_Remove) CHECK_EQUAL(true, c.Exists(2)); // Remove frame 2 - c.Remove(2); + c.Remove(2, false); // Check if frame 2 exists CHECK_EQUAL(false, c.Exists(2)); @@ -239,7 +245,7 @@ TEST(Cache_Remove) CHECK_EQUAL(2, c.Count()); // Remove frame 1 - c.Remove(1); + c.Remove(1, false); // Check if frame 1 exists CHECK_EQUAL(false, c.Exists(1)); @@ -257,7 +263,8 @@ TEST(Cache_Current_Frame) for (int i = 0; i < 20; i++) { // Add blank frame to the cache - c.Add(i, Frame()); + Frame *f = new Frame(); + c.Add(i, f); } CHECK_EQUAL(0, c.GetCurrentFrame()); // Cache defaults current frame is 0 @@ -282,7 +289,8 @@ TEST(Cache_Set_Max_Frames) for (int i = 0; i < 20; i++) { // Add blank frame to the cache - c.Add(i, Frame()); + Frame *f = new Frame(); + c.Add(i, f); } CHECK_EQUAL(20, c.GetMaxFrames()); // Cache defaults max frames to 20 diff --git a/tests/FFmpegReader_Tests.cpp b/tests/FFmpegReader_Tests.cpp index 67a38d4b..acebeab3 100644 --- a/tests/FFmpegReader_Tests.cpp +++ b/tests/FFmpegReader_Tests.cpp @@ -16,14 +16,14 @@ TEST(FFmpegReader_Check_Audio_File) FFmpegReader r("../../src/examples/piano.wav"); // Get frame 1 - Frame f = r.GetFrame(1); + Frame *f = r.GetFrame(1); // Get the number of channels and samples - float *samples = f.GetAudioSamples(0); + float *samples = f->GetAudioSamples(0); // Check audio properties - CHECK_EQUAL(2, f.GetAudioChannelsCount()); - CHECK_EQUAL(267, f.GetAudioSamplesCount()); + CHECK_EQUAL(2, f->GetAudioChannelsCount()); + CHECK_EQUAL(267, f->GetAudioSamplesCount()); // Check actual sample values (to be sure the waveform is correct) CHECK_CLOSE(0.0f, samples[0], 0.00001); @@ -43,10 +43,10 @@ TEST(FFmpegReader_Check_Video_File) FFmpegReader r("../../src/examples/test.mp4"); // Get frame 1 - Frame f = r.GetFrame(1); + Frame *f = r.GetFrame(1); // Get the image data - const Magick::PixelPacket* pixels = f.GetPixels(10); + const Magick::PixelPacket* pixels = f->GetPixels(10); // Check image properties on scanline 10, pixel 112 CHECK_EQUAL(5397, pixels[112].red); @@ -58,7 +58,7 @@ TEST(FFmpegReader_Check_Video_File) f = r.GetFrame(2); // Get the next frame - pixels = f.GetPixels(10); + pixels = f->GetPixels(10); // Check image properties on scanline 10, pixel 112 CHECK_EQUAL(0, pixels[112].red); diff --git a/tests/FileReaderBase_Tests.cpp b/tests/FileReaderBase_Tests.cpp index a1ff0426..a92c16c6 100644 --- a/tests/FileReaderBase_Tests.cpp +++ b/tests/FileReaderBase_Tests.cpp @@ -13,7 +13,7 @@ TEST(FileReaderBase_Derived_Class) { public: TestReader() { InitFileInfo(); }; - Frame GetFrame(int number) { return Frame(); } + Frame* GetFrame(int number) { Frame *f = new Frame(); return f; } }; // Create an instance of the derived class