From bfa050409c22bd7e5cbc1d7e23c72b11751ded07 Mon Sep 17 00:00:00 2001 From: Jonathan Thomas Date: Mon, 24 Aug 2015 01:05:48 -0500 Subject: [PATCH] Improved support for missing frames and invalid PTS (which result in gaps and duplicate frames). Also changed frame number to larger data type, and did some code clean-up and refactoring. Less crashes, and more video support! --- include/Cache.h | 16 +- include/ChunkReader.h | 4 +- include/Clip.h | 8 +- include/ClipBase.h | 2 +- include/Color.h | 2 +- include/DecklinkInput.h | 2 +- include/DecklinkReader.h | 2 +- include/DummyReader.h | 2 +- include/EffectBase.h | 2 +- include/FFmpegReader.h | 70 ++++---- include/FFmpegWriter.h | 2 +- include/Frame.h | 12 +- include/FrameMapper.h | 12 +- include/ImageReader.h | 2 +- include/ImageWriter.h | 2 +- include/KeyFrame.h | 29 ++-- include/QtImageReader.h | 2 +- include/ReaderBase.h | 2 +- include/TextReader.h | 2 +- include/Timeline.h | 10 +- include/WriterBase.h | 2 +- include/effects/Brightness.h | 4 +- include/effects/ChromaKey.h | 4 +- include/effects/Deinterlace.h | 4 +- include/effects/Mask.h | 4 +- include/effects/Negate.h | 4 +- include/effects/Saturation.h | 4 +- src/Cache.cpp | 34 ++-- src/ChunkReader.cpp | 4 +- src/Clip.cpp | 12 +- src/Color.cpp | 2 +- src/DecklinkInput.cpp | 2 +- src/DecklinkReader.cpp | 2 +- src/DummyReader.cpp | 2 +- src/FFmpegReader.cpp | 303 +++++++++++++++++++++++++--------- src/FFmpegWriter.cpp | 4 +- src/Frame.cpp | 11 +- src/FrameMapper.cpp | 38 +++-- src/ImageReader.cpp | 2 +- src/ImageWriter.cpp | 4 +- src/KeyFrame.cpp | 122 ++++++++------ src/QtImageReader.cpp | 2 +- src/TextReader.cpp | 2 +- src/Timeline.cpp | 16 +- src/effects/Brightness.cpp | 4 +- src/effects/ChromaKey.cpp | 4 +- src/effects/Deinterlace.cpp | 4 +- src/effects/Mask.cpp | 4 +- src/effects/Negate.cpp | 4 +- src/effects/Saturation.cpp | 4 +- src/examples/Example.cpp | 78 ++++++++- tests/Color_Tests.cpp | 6 +- tests/KeyFrame_Tests.cpp | 4 +- tests/ReaderBase_Tests.cpp | 2 +- 54 files changed, 566 insertions(+), 321 deletions(-) diff --git a/include/Cache.h b/include/Cache.h index b2f16370..c6df705a 100644 --- a/include/Cache.h +++ b/include/Cache.h @@ -56,8 +56,8 @@ namespace openshot { { private: int64 max_bytes; ///< This is the max number of bytes to cache (0 = no limit) - map > frames; ///< This map holds the frame number and Frame objects - deque frame_numbers; ///< This queue holds a sequential list of cached Frame numbers + map > frames; ///< This map holds the frame number and Frame objects + deque frame_numbers; ///< This queue holds a sequential list of cached Frame numbers /// Clean up cached frames that exceed the max number of bytes void CleanUp(); @@ -80,20 +80,20 @@ namespace openshot { /// @brief Add a Frame to the cache /// @param frame_number The frame number of the cached frame /// @param frame The openshot::Frame object needing to be cached. - void Add(int frame_number, tr1::shared_ptr frame); + void Add(long int frame_number, tr1::shared_ptr frame); /// Clear the cache of all frames void Clear(); /// Count the frames in the queue - int Count(); + long int Count(); /// Display a list of cached frame numbers void Display(); /// @brief Get a frame from the cache /// @param frame_number The frame number of the cached frame - tr1::shared_ptr GetFrame(int frame_number); + tr1::shared_ptr GetFrame(long int frame_number); /// Gets the maximum bytes value int64 GetBytes(); @@ -106,11 +106,11 @@ namespace openshot { /// @brief Move frame to front of queue (so it lasts longer) /// @param frame_number The frame number of the cached frame - void MoveToFront(int frame_number); + void MoveToFront(long int frame_number); /// @brief Remove a specific frame /// @param frame_number The frame number of the cached frame - void Remove(int frame_number); + void Remove(long int frame_number); /// @brief Set maximum bytes to a different amount /// @param number_of_bytes The maximum bytes to allow in the cache. Once exceeded, the cache will purge the oldest frames. @@ -122,7 +122,7 @@ namespace openshot { /// @param height The height of the frame's image /// @param sample_rate The sample rate of the frame's audio data /// @param channels The number of audio channels in the frame - void SetMaxBytesFromInfo(int number_of_frames, int width, int height, int sample_rate, int channels); + void SetMaxBytesFromInfo(long int number_of_frames, int width, int height, int sample_rate, int channels); }; diff --git a/include/ChunkReader.h b/include/ChunkReader.h index ab4a0c6a..b43323a2 100644 --- a/include/ChunkReader.h +++ b/include/ChunkReader.h @@ -117,7 +117,7 @@ namespace openshot bool does_folder_exist(string path); /// Find the location of a frame in a chunk - ChunkLocation find_chunk_frame(int requested_frame); + ChunkLocation find_chunk_frame(long int requested_frame); /// get a formatted path of a specific chunk string get_chunk_path(int chunk_number, string folder, string extension); @@ -150,7 +150,7 @@ namespace openshot /// @brief Get an openshot::Frame object for a specific frame number of this reader. /// @returns The requested frame (containing the image and audio) /// @param requested_frame The frame number you want to retrieve - tr1::shared_ptr GetFrame(int requested_frame) throw(ReaderClosed, ChunkNotFound); + tr1::shared_ptr GetFrame(long int requested_frame) throw(ReaderClosed, ChunkNotFound); /// Determine if reader is open or closed bool IsOpen() { return is_open; }; diff --git a/include/Clip.h b/include/Clip.h index db93bd1f..6b8edb50 100644 --- a/include/Clip.h +++ b/include/Clip.h @@ -121,7 +121,7 @@ namespace openshot { bool manage_reader; /// Adjust frame number minimum value - int adjust_frame_number_minimum(int frame_number); + int adjust_frame_number_minimum(long int frame_number); /// Apply effects to the source frame (if any) tr1::shared_ptr apply_effects(tr1::shared_ptr frame); @@ -130,7 +130,7 @@ namespace openshot { string get_file_extension(string path); /// Adjust the audio and image of a time mapped frame - tr1::shared_ptr get_time_mapped_frame(tr1::shared_ptr frame, int frame_number) throw(ReaderClosed); + tr1::shared_ptr get_time_mapped_frame(tr1::shared_ptr frame, long int frame_number) throw(ReaderClosed); /// Init default settings for a clip void init_settings(); @@ -174,7 +174,7 @@ namespace openshot { /// /// @returns The requested frame (containing the image) /// @param requested_frame The frame number that is requested - tr1::shared_ptr GetFrame(int requested_frame) throw(ReaderClosed); + tr1::shared_ptr GetFrame(long int requested_frame) throw(ReaderClosed); /// Open the internal reader void Open() throw(InvalidFile, ReaderClosed); @@ -198,7 +198,7 @@ namespace openshot { /// Get all properties for a specific frame (perfect for a UI to display the current state /// of all properties at any time) - string PropertiesJSON(int requested_frame); + string PropertiesJSON(long int requested_frame); /// @brief Remove an effect from the clip /// @param effect Remove an effect from the clip. diff --git a/include/ClipBase.h b/include/ClipBase.h index c4a684ee..38994308 100644 --- a/include/ClipBase.h +++ b/include/ClipBase.h @@ -92,7 +92,7 @@ namespace openshot { /// Get all properties for a specific frame (perfect for a UI to display the current state /// of all properties at any time) - virtual string PropertiesJSON(int requested_frame) = 0; + virtual string PropertiesJSON(long int requested_frame) = 0; }; diff --git a/include/Color.h b/include/Color.h index d8104a04..b3e5b7c2 100644 --- a/include/Color.h +++ b/include/Color.h @@ -60,7 +60,7 @@ namespace openshot { Color(Keyframe Red, Keyframe Green, Keyframe Blue, Keyframe Alpha); /// Get the HEX value of a color at a specific frame - string GetColorHex(int frame_number); + string GetColorHex(long int frame_number); /// Get the distance between 2 RGB pairs. (0=identical colors, 10=very close colors, 760=very different colors) static long GetDistance(long R1, long G1, long B1, long R2, long G2, long B2); diff --git a/include/DecklinkInput.h b/include/DecklinkInput.h index 7d705cbf..94221752 100644 --- a/include/DecklinkInput.h +++ b/include/DecklinkInput.h @@ -93,7 +93,7 @@ public: virtual HRESULT STDMETHODCALLTYPE VideoInputFrameArrived(IDeckLinkVideoInputFrame*, IDeckLinkAudioInputPacket*); // Extra methods - tr1::shared_ptr GetFrame(int requested_frame); + tr1::shared_ptr GetFrame(long int requested_frame); unsigned long GetCurrentFrameNumber(); private: diff --git a/include/DecklinkReader.h b/include/DecklinkReader.h index e22b5033..e46e0023 100644 --- a/include/DecklinkReader.h +++ b/include/DecklinkReader.h @@ -108,7 +108,7 @@ namespace openshot /// /// @returns The requested frame (containing the image) /// @param requested_frame The frame number that is requested. - tr1::shared_ptr GetFrame(int requested_frame) throw(ReaderClosed); + tr1::shared_ptr GetFrame(long int requested_frame) throw(ReaderClosed); unsigned long GetCurrentFrameNumber(); /// Determine if reader is open or closed diff --git a/include/DummyReader.h b/include/DummyReader.h index 7f51155c..36b8e752 100644 --- a/include/DummyReader.h +++ b/include/DummyReader.h @@ -76,7 +76,7 @@ namespace openshot /// /// @returns The requested frame (containing the image) /// @param requested_frame The frame number that is requested. - tr1::shared_ptr GetFrame(int requested_frame) throw(ReaderClosed); + tr1::shared_ptr GetFrame(long int requested_frame) throw(ReaderClosed); /// Determine if reader is open or closed bool IsOpen() { return is_open; }; diff --git a/include/EffectBase.h b/include/EffectBase.h index 2fd84e69..eef29287 100644 --- a/include/EffectBase.h +++ b/include/EffectBase.h @@ -84,7 +84,7 @@ namespace openshot /// @returns The modified openshot::Frame object /// @param frame The frame object that needs the effect applied to it /// @param frame_number The frame number (starting at 1) of the effect on the timeline. - virtual tr1::shared_ptr GetFrame(tr1::shared_ptr frame, int frame_number) = 0; + virtual tr1::shared_ptr GetFrame(tr1::shared_ptr frame, long int frame_number) = 0; /// Initialize the values of the EffectInfo struct. It is important for derived classes to call /// this method, or the EffectInfo struct values will not be initialized. diff --git a/include/FFmpegReader.h b/include/FFmpegReader.h index d38fa359..73fdc452 100644 --- a/include/FFmpegReader.h +++ b/include/FFmpegReader.h @@ -106,38 +106,43 @@ namespace openshot bool is_duration_known; bool check_interlace; bool check_fps; + bool has_missing_frames; int num_of_rescalers; int rescaler_position; vector image_rescalers; Cache working_cache; + Cache missing_frames; map packets; map frames; - map processing_video_frames; - multimap processing_audio_frames; - map processed_video_frames; - map processed_audio_frames; + map processing_video_frames; + multimap processing_audio_frames; + map processed_video_frames; + map processed_audio_frames; + multimap missing_video_frames; + multimap duplicate_video_frames; AudioLocation previous_packet_location; // DEBUG VARIABLES (FOR AUDIO ISSUES) int prev_samples; - int prev_pts; - int pts_total; - int pts_counter; + long int prev_pts; + long int pts_total; + long int pts_counter; bool is_seeking; - int seeking_pts; - int seeking_frame; + long int seeking_pts; + long int seeking_frame; bool is_video_seek; int seek_count; - int seek_audio_frame_found; - int seek_video_frame_found; + long int seek_audio_frame_found; + long int seek_video_frame_found; - int audio_pts_offset; - int video_pts_offset; - int last_frame; - int largest_frame_processed; + long int audio_pts_offset; + long int video_pts_offset; + long int last_frame; + long int largest_frame_processed; + long int current_video_frame; // can't reliably use PTS of video to determine this /// Check for the correct frames per second value by scanning the 1st few seconds of video packets. void CheckFPS(); @@ -145,26 +150,29 @@ namespace openshot /// Check the current seek position and determine if we need to seek again bool CheckSeek(bool is_video); + /// Check if a frame is missing and attempt to replace it's frame image (and + bool CheckMissingFrame(long int requested_frame); + /// Check the working queue, and move finished frames to the finished queue - void CheckWorkingFrames(bool end_of_stream); + void CheckWorkingFrames(bool end_of_stream, long int requested_frame); /// Convert image to RGB format - void convert_image(int current_frame, AVPicture *copyFrame, int width, int height, PixelFormat pix_fmt); + void convert_image(long int current_frame, AVPicture *copyFrame, int width, int height, PixelFormat pix_fmt); /// Convert Frame Number into Audio PTS - int ConvertFrameToAudioPTS(int frame_number); + long int ConvertFrameToAudioPTS(long int frame_number); /// Convert Frame Number into Video PTS - int ConvertFrameToVideoPTS(int frame_number); + long int ConvertFrameToVideoPTS(long int frame_number); /// Convert Video PTS into Frame Number - int ConvertVideoPTStoFrame(int pts); + long int ConvertVideoPTStoFrame(long int pts); /// Create a new Frame (or return an existing one) and add it to the working queue. - tr1::shared_ptr CreateFrame(int requested_frame); + tr1::shared_ptr CreateFrame(long int requested_frame); /// Calculate Starting video frame and sample # for an audio PTS - AudioLocation GetAudioPTSLocation(int pts); + AudioLocation GetAudioPTSLocation(long int pts); /// Get an AVFrame (if any) bool GetAVFrame(); @@ -173,28 +181,28 @@ namespace openshot int GetNextPacket(); /// Get the smallest video frame that is still being processed - int GetSmallestVideoFrame(); + long int GetSmallestVideoFrame(); /// Get the smallest audio frame that is still being processed - int GetSmallestAudioFrame(); + long int GetSmallestAudioFrame(); /// Get the PTS for the current video packet - int GetVideoPTS(); + long int GetVideoPTS(); /// Init a collection of software rescalers (thread safe) void InitScalers(); /// Remove partial frames due to seek - bool IsPartialFrame(int requested_frame); + bool IsPartialFrame(long int requested_frame); /// Process a video packet - void ProcessVideoPacket(int requested_frame); + void ProcessVideoPacket(long int requested_frame); /// Process an audio packet - void ProcessAudioPacket(int requested_frame, int target_frame, int starting_sample); + void ProcessAudioPacket(long int requested_frame, long int target_frame, int starting_sample); /// Read the stream until we find the requested Frame - tr1::shared_ptr ReadStream(int requested_frame); + tr1::shared_ptr ReadStream(long int requested_frame); /// Remove AVFrame from cache (and deallocate it's memory) void RemoveAVFrame(AVPicture*); @@ -206,7 +214,7 @@ namespace openshot 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) throw(TooManySeeks); + void Seek(long int requested_frame) throw(TooManySeeks); /// Update PTS Offset (if any) void UpdatePTSOffset(bool is_video); @@ -239,7 +247,7 @@ namespace openshot /// /// @returns The requested frame of video /// @param requested_frame The frame number that is requested. - tr1::shared_ptr GetFrame(int requested_frame) throw(OutOfBoundsFrame, ReaderClosed, TooManySeeks); + tr1::shared_ptr GetFrame(long int requested_frame) throw(OutOfBoundsFrame, ReaderClosed, TooManySeeks); /// Determine if reader is open or closed bool IsOpen() { return is_open; }; diff --git a/include/FFmpegWriter.h b/include/FFmpegWriter.h index b749f3cf..0b9b33f9 100644 --- a/include/FFmpegWriter.h +++ b/include/FFmpegWriter.h @@ -322,7 +322,7 @@ namespace openshot /// @param reader A openshot::ReaderBase object which will provide frames to be written /// @param start The starting frame number of the reader /// @param length The number of frames to write - void WriteFrame(ReaderBase* reader, int start, int length) throw(WriterClosed); + void WriteFrame(ReaderBase* reader, long int start, long int length) throw(WriterClosed); /// @brief Write the file trailer (after all frames are written). This is called automatically /// by the Close() method if this method has not yet been called. diff --git a/include/Frame.h b/include/Frame.h index 25ac561d..8dc813e8 100644 --- a/include/Frame.h +++ b/include/Frame.h @@ -129,22 +129,22 @@ namespace openshot int sample_rate; public: - int number; ///< This is the frame number (starting at 1) + long int number; ///< This is the frame number (starting at 1) /// Constructor - blank frame (300x200 blank image, 48kHz audio silence) Frame(); /// Constructor - image only (48kHz audio silence) - Frame(int number, int width, int height, string color); + Frame(long int number, int width, int height, string color); /// Constructor - image only from pixel array (48kHz audio silence) - Frame(int number, int width, int height, const string map, const Magick::StorageType type, const void *pixels_); + Frame(long int number, int width, int height, const string map, const Magick::StorageType type, const void *pixels_); /// Constructor - audio only (300x200 blank image) - Frame(int number, int samples, int channels); + Frame(long int number, int samples, int channels); /// Constructor - image & audio - Frame(int number, int width, int height, string color, int samples, int channels); + Frame(long int number, int width, int height, string color, int samples, int channels); /// Copy constructor Frame ( const Frame &other ); @@ -243,7 +243,7 @@ namespace openshot int GetSamplesPerFrame(Fraction fps, int sample_rate, int channels); /// Calculate the # of samples per video frame (for a specific frame number and frame rate) - static int GetSamplesPerFrame(int frame_number, Fraction fps, int sample_rate, int channels); + static int GetSamplesPerFrame(long int frame_number, Fraction fps, int sample_rate, int channels); /// Get an audio waveform image tr1::shared_ptr GetWaveform(int width, int height, int Red, int Green, int Blue, int Alpha); diff --git a/include/FrameMapper.h b/include/FrameMapper.h index f3e47ded..37a735da 100644 --- a/include/FrameMapper.h +++ b/include/FrameMapper.h @@ -72,12 +72,12 @@ namespace openshot */ struct Field { - int Frame; + long int Frame; bool isOdd; Field() : Frame(0), isOdd(true) { }; - Field(int frame, bool isodd) + Field(long int frame, bool isodd) { Frame = frame; isOdd = isodd; @@ -149,7 +149,7 @@ namespace openshot AVAudioResampleContext *avr; // Audio resampling context object // Internal methods used by init - void AddField(int frame); + void AddField(long int frame); void AddField(Field field); // Use the original and target frame rates and a pull-down technique to create @@ -173,7 +173,7 @@ namespace openshot void Close(); /// Get a frame based on the target frame rate and the new frame number of a frame - MappedFrame GetMappedFrame(int TargetFrameNumber) throw(OutOfBoundsFrame); + MappedFrame GetMappedFrame(long int TargetFrameNumber) throw(OutOfBoundsFrame); /// Get the cache object used by this reader Cache* GetCache() { return &final_cache; }; @@ -184,7 +184,7 @@ namespace openshot /// /// @returns The requested frame of video /// @param requested_frame The frame number that is requested. - tr1::shared_ptr GetFrame(int requested_frame) throw(ReaderClosed); + tr1::shared_ptr GetFrame(long int requested_frame) throw(ReaderClosed); /// Determine if reader is open or closed bool IsOpen(); @@ -202,7 +202,7 @@ namespace openshot void PrintMapping(); /// Resample audio and map channels (if needed) - void ResampleMappedAudio(tr1::shared_ptr frame, int original_frame_number); + void ResampleMappedAudio(tr1::shared_ptr frame, long int original_frame_number); }; } diff --git a/include/ImageReader.h b/include/ImageReader.h index 50d86d96..4a3e3c94 100644 --- a/include/ImageReader.h +++ b/include/ImageReader.h @@ -88,7 +88,7 @@ namespace openshot /// /// @returns The requested frame (containing the image) /// @param requested_frame The frame number that is requested. - tr1::shared_ptr GetFrame(int requested_frame) throw(ReaderClosed); + tr1::shared_ptr GetFrame(long int requested_frame) throw(ReaderClosed); /// Determine if reader is open or closed bool IsOpen() { return is_open; }; diff --git a/include/ImageWriter.h b/include/ImageWriter.h index 83ad9e25..60e3523a 100644 --- a/include/ImageWriter.h +++ b/include/ImageWriter.h @@ -140,7 +140,7 @@ namespace openshot /// @param reader A openshot::ReaderBase object which will provide frames to be written /// @param start The starting frame number of the reader /// @param length The number of frames to write - void WriteFrame(ReaderBase* reader, int start, int length) throw(WriterClosed); + void WriteFrame(ReaderBase* reader, long int start, long int length) throw(WriterClosed); }; diff --git a/include/KeyFrame.h b/include/KeyFrame.h index 25486870..5a5565a0 100644 --- a/include/KeyFrame.h +++ b/include/KeyFrame.h @@ -80,13 +80,13 @@ namespace openshot { void CreateFactorialTable(); // Get a factorial for a coordinate - double Factorial(int n); + double Factorial(long int n); // Calculate the factorial function for Bernstein basis - double Ni(int n, int i); + double Ni(long int n, long int i); // Calculate Bernstein Basis - double Bernstein(int n, int i, double t); + double Bernstein(long int n, long int i, double t); public: vector Points; ///< Vector of all Points @@ -118,31 +118,34 @@ namespace openshot { void FlipPoints(); /// Get the index of a point by matching a coordinate - int FindIndex(Point p) throw(OutOfBoundsPoint); + long int FindIndex(Point p) throw(OutOfBoundsPoint); /// Get the value at a specific index - float GetValue(int index); + float GetValue(long int index); /// Get the rounded INT value at a specific index - int GetInt(int index); + int GetInt(long int index); + + /// Get the rounded LONG value at a specific index + long int GetLong(long int index); /// Get the fraction that represents how many times this value is repeated in the curve - Fraction GetRepeatFraction(int index); + Fraction GetRepeatFraction(long int index); /// Get the change in Y value (from the previous Y value) - float GetDelta(int index); + float GetDelta(long int index); /// Get a point at a specific index - Point& GetPoint(int index) throw(OutOfBoundsPoint); + Point& GetPoint(long int index) throw(OutOfBoundsPoint); /// Get current point (or closest point) from the X coordinate (i.e. the frame number) Point GetClosestPoint(Point p); // Get the number of values (i.e. coordinates on the X axis) - int GetLength(); + long int GetLength(); /// Get the number of points (i.e. # of points) - int GetCount(); + long int GetCount(); /// Get the direction of the curve at a specific index (increasing or decreasing) bool IsIncreasing(int index); @@ -165,14 +168,14 @@ namespace openshot { void RemovePoint(Point p) throw(OutOfBoundsPoint); /// Remove a point by index - void RemovePoint(int index) throw(OutOfBoundsPoint); + void RemovePoint(long int index) throw(OutOfBoundsPoint); /// Scale all points by a percentage (good for evenly lengthening or shortening an openshot::Keyframe) /// 1.0 = same size, 1.05 = 5% increase, etc... void ScalePoints(float scale); /// Replace an existing point with a new point - void UpdatePoint(int index, Point p); + void UpdatePoint(long int index, Point p); /// Print a list of points void PrintPoints(); diff --git a/include/QtImageReader.h b/include/QtImageReader.h index e53dc088..0bb7d2a2 100644 --- a/include/QtImageReader.h +++ b/include/QtImageReader.h @@ -90,7 +90,7 @@ namespace openshot /// /// @returns The requested frame (containing the image) /// @param requested_frame The frame number that is requested. - tr1::shared_ptr GetFrame(int requested_frame) throw(ReaderClosed); + tr1::shared_ptr GetFrame(long int requested_frame) throw(ReaderClosed); /// Determine if reader is open or closed bool IsOpen() { return is_open; }; diff --git a/include/ReaderBase.h b/include/ReaderBase.h index dc6ef932..b949c3f3 100644 --- a/include/ReaderBase.h +++ b/include/ReaderBase.h @@ -140,7 +140,7 @@ namespace openshot /// /// @returns The requested frame of video /// @param[in] number The frame number that is requested. - virtual tr1::shared_ptr GetFrame(int number) = 0; + virtual tr1::shared_ptr GetFrame(long int number) = 0; /// A thread safe version of GetFrame. //tr1::shared_ptr GetFrameSafe(int number); diff --git a/include/TextReader.h b/include/TextReader.h index b5bc28ca..db830cc9 100644 --- a/include/TextReader.h +++ b/include/TextReader.h @@ -124,7 +124,7 @@ namespace openshot /// /// @returns The requested frame (containing the image) /// @param requested_frame The frame number that is requested. - tr1::shared_ptr GetFrame(int requested_frame) throw(ReaderClosed); + tr1::shared_ptr GetFrame(long int requested_frame) throw(ReaderClosed); /// Determine if reader is open or closed bool IsOpen() { return is_open; }; diff --git a/include/Timeline.h b/include/Timeline.h index 36eef258..f05bc3b8 100644 --- a/include/Timeline.h +++ b/include/Timeline.h @@ -150,7 +150,7 @@ namespace openshot { Cache final_cache; /// new_frame, Clip* source_clip, int clip_frame_number, int timeline_frame_number, bool is_top_clip); + void add_layer(tr1::shared_ptr new_frame, Clip* source_clip, long int clip_frame_number, long int timeline_frame_number, bool is_top_clip); /// Apply a FrameMapper to a clip which matches the settings of this timeline void apply_mapper_to_clip(Clip* clip); @@ -162,7 +162,7 @@ namespace openshot { void apply_json_to_timeline(Json::Value change) throw(InvalidJSONKey); /// find_intersecting_clips(int requested_frame, int number_of_frames, bool include); + vector find_intersecting_clips(long int requested_frame, int number_of_frames, bool include); /// Apply effects to the source frame (if any) - tr1::shared_ptr apply_effects(tr1::shared_ptr frame, int timeline_frame_number, int layer); + tr1::shared_ptr apply_effects(tr1::shared_ptr frame, long int timeline_frame_number, int layer); /// Compare 2 floating point numbers for equality bool isEqual(double a, double b); @@ -231,7 +231,7 @@ namespace openshot { /// /// @returns The requested frame (containing the image) /// @param requested_frame The frame number that is requested. - tr1::shared_ptr GetFrame(int requested_frame) throw(ReaderClosed, OutOfBoundsFrame); + tr1::shared_ptr GetFrame(long int requested_frame) throw(ReaderClosed, OutOfBoundsFrame); // Curves for the viewport Keyframe viewport_scale; /// frame) throw(WriterClosed) = 0; /// This method is required for all derived classes of WriterBase. Write a block of frames from a reader. - virtual void WriteFrame(ReaderBase* reader, int start, int length) throw(WriterClosed) = 0; + virtual void WriteFrame(ReaderBase* reader, long int start, long int length) throw(WriterClosed) = 0; /// Get and Set JSON methods string Json(); ///< Generate JSON string of this object diff --git a/include/effects/Brightness.h b/include/effects/Brightness.h index 15a0d01e..83efd8e5 100644 --- a/include/effects/Brightness.h +++ b/include/effects/Brightness.h @@ -90,7 +90,7 @@ namespace openshot /// @returns The modified openshot::Frame object /// @param frame The frame object that needs the effect applied to it /// @param frame_number The frame number (starting at 1) of the effect on the timeline. - tr1::shared_ptr GetFrame(tr1::shared_ptr frame, int frame_number); + tr1::shared_ptr GetFrame(tr1::shared_ptr frame, long int frame_number); /// Get and Set JSON methods string Json(); ///< Generate JSON string of this object @@ -100,7 +100,7 @@ namespace openshot /// Get all properties for a specific frame (perfect for a UI to display the current state /// of all properties at any time) - string PropertiesJSON(int requested_frame); + string PropertiesJSON(long int requested_frame); }; } diff --git a/include/effects/ChromaKey.h b/include/effects/ChromaKey.h index 7404c410..a666339c 100644 --- a/include/effects/ChromaKey.h +++ b/include/effects/ChromaKey.h @@ -83,7 +83,7 @@ namespace openshot /// @returns The modified openshot::Frame object /// @param frame The frame object that needs the effect applied to it /// @param frame_number The frame number (starting at 1) of the effect on the timeline. - tr1::shared_ptr GetFrame(tr1::shared_ptr frame, int frame_number); + tr1::shared_ptr GetFrame(tr1::shared_ptr frame, long int frame_number); /// Get and Set JSON methods string Json(); ///< Generate JSON string of this object @@ -92,7 +92,7 @@ namespace openshot void SetJsonValue(Json::Value root); ///< Load Json::JsonValue into this object // Get all properties for a specific frame - string PropertiesJSON(int requested_frame); + string PropertiesJSON(long int requested_frame); }; } diff --git a/include/effects/Deinterlace.h b/include/effects/Deinterlace.h index fe0f3062..6c6b9f8b 100644 --- a/include/effects/Deinterlace.h +++ b/include/effects/Deinterlace.h @@ -79,7 +79,7 @@ namespace openshot /// @returns The modified openshot::Frame object /// @param frame The frame object that needs the effect applied to it /// @param frame_number The frame number (starting at 1) of the effect on the timeline. - tr1::shared_ptr GetFrame(tr1::shared_ptr frame, int frame_number); + tr1::shared_ptr GetFrame(tr1::shared_ptr frame, long int frame_number); /// Get and Set JSON methods string Json(); ///< Generate JSON string of this object @@ -88,7 +88,7 @@ namespace openshot void SetJsonValue(Json::Value root); ///< Load Json::JsonValue into this object // Get all properties for a specific frame - string PropertiesJSON(int requested_frame); + string PropertiesJSON(long int requested_frame); }; } diff --git a/include/effects/Mask.h b/include/effects/Mask.h index c5e580eb..bc602cfd 100644 --- a/include/effects/Mask.h +++ b/include/effects/Mask.h @@ -99,7 +99,7 @@ namespace openshot /// @returns The modified openshot::Frame object /// @param frame The frame object that needs the effect applied to it /// @param frame_number The frame number (starting at 1) of the effect on the timeline. - tr1::shared_ptr GetFrame(tr1::shared_ptr frame, int frame_number); + tr1::shared_ptr GetFrame(tr1::shared_ptr frame, long int frame_number); /// Get and Set JSON methods string Json(); ///< Generate JSON string of this object @@ -109,7 +109,7 @@ namespace openshot /// Get all properties for a specific frame (perfect for a UI to display the current state /// of all properties at any time) - string PropertiesJSON(int requested_frame); + string PropertiesJSON(long int requested_frame); /// Get the reader object of the mask grayscale image ReaderBase* Reader() { return reader; }; diff --git a/include/effects/Negate.h b/include/effects/Negate.h index d64f8f6a..c29b6783 100644 --- a/include/effects/Negate.h +++ b/include/effects/Negate.h @@ -67,7 +67,7 @@ namespace openshot /// @returns The modified openshot::Frame object /// @param frame The frame object that needs the effect applied to it /// @param frame_number The frame number (starting at 1) of the effect on the timeline. - tr1::shared_ptr GetFrame(tr1::shared_ptr frame, int frame_number); + tr1::shared_ptr GetFrame(tr1::shared_ptr frame, long int frame_number); /// Get and Set JSON methods string Json(); ///< Generate JSON string of this object @@ -76,7 +76,7 @@ namespace openshot void SetJsonValue(Json::Value root); ///< Load Json::JsonValue into this object // Get all properties for a specific frame - string PropertiesJSON(int requested_frame); + string PropertiesJSON(long int requested_frame); }; } diff --git a/include/effects/Saturation.h b/include/effects/Saturation.h index e47a5650..7ade6135 100644 --- a/include/effects/Saturation.h +++ b/include/effects/Saturation.h @@ -87,7 +87,7 @@ namespace openshot /// @returns The modified openshot::Frame object /// @param frame The frame object that needs the effect applied to it /// @param frame_number The frame number (starting at 1) of the effect on the timeline. - tr1::shared_ptr GetFrame(tr1::shared_ptr frame, int frame_number); + tr1::shared_ptr GetFrame(tr1::shared_ptr frame, long int frame_number); /// Get and Set JSON methods string Json(); ///< Generate JSON string of this object @@ -97,7 +97,7 @@ namespace openshot /// Get all properties for a specific frame (perfect for a UI to display the current state /// of all properties at any time) - string PropertiesJSON(int requested_frame); + string PropertiesJSON(long int requested_frame); }; } diff --git a/src/Cache.cpp b/src/Cache.cpp index b0f211be..6ddd5afb 100644 --- a/src/Cache.cpp +++ b/src/Cache.cpp @@ -54,7 +54,7 @@ Cache::~Cache() } // Add a Frame to the cache -void Cache::Add(int frame_number, tr1::shared_ptr frame) +void Cache::Add(long int frame_number, tr1::shared_ptr frame) { // Create a scoped lock, to protect the cache from multiple threads const GenericScopedLock lock(*cacheCriticalSection); @@ -76,7 +76,7 @@ void Cache::Add(int frame_number, tr1::shared_ptr frame) } // Get a frame from the cache (or NULL shared_ptr if no frame is found) -tr1::shared_ptr Cache::GetFrame(int frame_number) +tr1::shared_ptr Cache::GetFrame(long int frame_number) { // Create a scoped lock, to protect the cache from multiple threads const GenericScopedLock lock(*cacheCriticalSection); @@ -96,21 +96,19 @@ tr1::shared_ptr Cache::GetSmallestFrame() { // Create a scoped lock, to protect the cache from multiple threads const GenericScopedLock lock(*cacheCriticalSection); - tr1::shared_ptr f; - // Loop through frame numbers - deque::iterator itr; - int smallest_frame = -1; + // Loop through frame numbers + deque::iterator itr; + long int smallest_frame = -1; for(itr = frame_numbers.begin(); itr != frame_numbers.end(); ++itr) { if (*itr < smallest_frame || smallest_frame == -1) smallest_frame = *itr; } - // Return frame (or error if no frame found) - if (smallest_frame > 0) - f = GetFrame(smallest_frame); + // Return frame + f = GetFrame(smallest_frame); return f; } @@ -124,7 +122,7 @@ int64 Cache::GetBytes() int64 total_bytes = 0; // Loop through frames, and calculate total bytes - deque::reverse_iterator itr; + deque::reverse_iterator itr; for(itr = frame_numbers.rbegin(); itr != frame_numbers.rend(); ++itr) { //cout << "get bytes from frame " << *itr << ", frames.count(" << *itr << "): " << frames.count(*itr) << endl; @@ -136,13 +134,13 @@ int64 Cache::GetBytes() } // Remove a specific frame -void Cache::Remove(int frame_number) +void Cache::Remove(long int frame_number) { // Create a scoped lock, to protect the cache from multiple threads const GenericScopedLock lock(*cacheCriticalSection); // Loop through frame numbers - deque::iterator itr; + deque::iterator itr; for(itr = frame_numbers.begin(); itr != frame_numbers.end(); ++itr) { if (*itr == frame_number) @@ -158,7 +156,7 @@ void Cache::Remove(int frame_number) } // Move frame to front of queue (so it lasts longer) -void Cache::MoveToFront(int frame_number) +void Cache::MoveToFront(long int frame_number) { // Create a scoped lock, to protect the cache from multiple threads const GenericScopedLock lock(*cacheCriticalSection); @@ -167,7 +165,7 @@ void Cache::MoveToFront(int frame_number) if (frames.count(frame_number)) { // Loop through frame numbers - deque::iterator itr; + deque::iterator itr; for(itr = frame_numbers.begin(); itr != frame_numbers.end(); ++itr) { if (*itr == frame_number) @@ -194,7 +192,7 @@ void Cache::Clear() } // Count the frames in the queue -int Cache::Count() +long int Cache::Count() { // Create a scoped lock, to protect the cache from multiple threads const GenericScopedLock lock(*cacheCriticalSection); @@ -215,7 +213,7 @@ void Cache::CleanUp() while (GetBytes() > max_bytes && frame_numbers.size() > 20) { // Remove the oldest frame - int frame_to_remove = frame_numbers.back(); + long int frame_to_remove = frame_numbers.back(); // Remove frame_number and frame Remove(frame_to_remove); @@ -227,7 +225,7 @@ void Cache::CleanUp() void Cache::Display() { cout << "----- Cache List (" << frames.size() << ") ------" << endl; - deque::iterator itr; + deque::iterator itr; int i = 1; for(itr = frame_numbers.begin(); itr != frame_numbers.end(); ++itr) @@ -238,7 +236,7 @@ void Cache::Display() } // Set maximum bytes to a different amount based on a ReaderInfo struct -void Cache::SetMaxBytesFromInfo(int number_of_frames, int width, int height, int sample_rate, int channels) +void Cache::SetMaxBytesFromInfo(long int number_of_frames, int width, int height, int sample_rate, int channels) { // n frames X height X width X 4 colors of chars X audio channels X 4 byte floats int64 bytes = number_of_frames * (height * width * 4 + (sample_rate * channels * 4)); diff --git a/src/ChunkReader.cpp b/src/ChunkReader.cpp index d7863ae9..6c241add 100644 --- a/src/ChunkReader.cpp +++ b/src/ChunkReader.cpp @@ -123,7 +123,7 @@ void ChunkReader::load_json() } // Find the location of a frame in a chunk -ChunkLocation ChunkReader::find_chunk_frame(int requested_frame) +ChunkLocation ChunkReader::find_chunk_frame(long int requested_frame) { // Determine which chunk contains this frame. int chunk_number = (requested_frame / chunk_size) + 1; @@ -187,7 +187,7 @@ string ChunkReader::get_chunk_path(int chunk_number, string folder, string exten } // Get an openshot::Frame object for a specific frame number of this reader. -tr1::shared_ptr ChunkReader::GetFrame(int requested_frame) throw(ReaderClosed, ChunkNotFound) +tr1::shared_ptr ChunkReader::GetFrame(long int requested_frame) throw(ReaderClosed, ChunkNotFound) { // Determine what chunk contains this frame ChunkLocation location = find_chunk_frame(requested_frame); diff --git a/src/Clip.cpp b/src/Clip.cpp index 59f9a05e..585c1d24 100644 --- a/src/Clip.cpp +++ b/src/Clip.cpp @@ -244,7 +244,7 @@ float Clip::End() throw(ReaderClosed) } // Get an openshot::Frame object for a specific frame number of this reader. -tr1::shared_ptr Clip::GetFrame(int requested_frame) throw(ReaderClosed) +tr1::shared_ptr Clip::GetFrame(long int requested_frame) throw(ReaderClosed) { if (reader) { @@ -252,9 +252,9 @@ tr1::shared_ptr Clip::GetFrame(int requested_frame) throw(ReaderClosed) requested_frame = adjust_frame_number_minimum(requested_frame); // Is a time map detected - int new_frame_number = requested_frame; + long int new_frame_number = requested_frame; if (time.Values.size() > 1) - new_frame_number = time.GetInt(requested_frame); + new_frame_number = time.GetLong(requested_frame); // Now that we have re-mapped what frame number is needed, go and get the frame pointer @@ -322,7 +322,7 @@ void Clip::reverse_buffer(juce::AudioSampleBuffer* buffer) } // Adjust the audio and image of a time mapped frame -tr1::shared_ptr Clip::get_time_mapped_frame(tr1::shared_ptr frame, int frame_number) throw(ReaderClosed) +tr1::shared_ptr Clip::get_time_mapped_frame(tr1::shared_ptr frame, long int frame_number) throw(ReaderClosed) { // Check for valid reader if (!reader) @@ -517,7 +517,7 @@ tr1::shared_ptr Clip::get_time_mapped_frame(tr1::shared_ptr frame, } // Adjust frame number minimum value -int Clip::adjust_frame_number_minimum(int frame_number) +int Clip::adjust_frame_number_minimum(long int frame_number) { // Never return a frame number 0 or below if (frame_number < 1) @@ -535,7 +535,7 @@ string Clip::Json() { } // Get all properties for a specific frame -string Clip::PropertiesJSON(int requested_frame) { +string Clip::PropertiesJSON(long int requested_frame) { // Requested Point Point requested_point(requested_frame, requested_frame); diff --git a/src/Color.cpp b/src/Color.cpp index f351970c..925b5c99 100644 --- a/src/Color.cpp +++ b/src/Color.cpp @@ -61,7 +61,7 @@ Color::Color(string color_hex) } // Get the HEX value of a color at a specific frame -string Color::GetColorHex(int frame_number) { +string Color::GetColorHex(long int frame_number) { int r = red.GetInt(frame_number); int g = green.GetInt(frame_number); diff --git a/src/DecklinkInput.cpp b/src/DecklinkInput.cpp index 3647c05e..1d5aa8d0 100644 --- a/src/DecklinkInput.cpp +++ b/src/DecklinkInput.cpp @@ -104,7 +104,7 @@ unsigned long DeckLinkInputDelegate::GetCurrentFrameNumber() return 0; } -tr1::shared_ptr DeckLinkInputDelegate::GetFrame(int requested_frame) +tr1::shared_ptr DeckLinkInputDelegate::GetFrame(long int requested_frame) { tr1::shared_ptr f; diff --git a/src/DecklinkReader.cpp b/src/DecklinkReader.cpp index 9c5bf94a..76a846d3 100644 --- a/src/DecklinkReader.cpp +++ b/src/DecklinkReader.cpp @@ -231,7 +231,7 @@ unsigned long DecklinkReader::GetCurrentFrameNumber() } // Get an openshot::Frame object for the next available LIVE frame -tr1::shared_ptr DecklinkReader::GetFrame(int requested_frame) throw(ReaderClosed) +tr1::shared_ptr DecklinkReader::GetFrame(long int requested_frame) throw(ReaderClosed) { // Get a frame from the delegate decklink class (which is collecting them on another thread) tr1::shared_ptr f = delegate->GetFrame(requested_frame); diff --git a/src/DummyReader.cpp b/src/DummyReader.cpp index 015899cd..cfdb12b3 100644 --- a/src/DummyReader.cpp +++ b/src/DummyReader.cpp @@ -97,7 +97,7 @@ void DummyReader::Close() } // Get an openshot::Frame object for a specific frame number of this reader. -tr1::shared_ptr DummyReader::GetFrame(int requested_frame) throw(ReaderClosed) +tr1::shared_ptr DummyReader::GetFrame(long int requested_frame) throw(ReaderClosed) { // Check for open reader (or throw exception) if (!is_open) diff --git a/src/FFmpegReader.cpp b/src/FFmpegReader.cpp index 2ffdc13a..27b217c7 100644 --- a/src/FFmpegReader.cpp +++ b/src/FFmpegReader.cpp @@ -37,14 +37,16 @@ FFmpegReader::FFmpegReader(string path) throw(InvalidFile, NoStreamsFound, Inval audio_pts_offset(99999), video_pts_offset(99999), path(path), is_video_seek(true), check_interlace(false), check_fps(false), enable_seek(true), rescaler_position(0), num_of_rescalers(OPEN_MP_NUM_PROCESSORS), is_open(false), seek_audio_frame_found(0), seek_video_frame_found(0), prev_samples(0), prev_pts(0), - pts_total(0), pts_counter(0), is_duration_known(false), largest_frame_processed(0) { + pts_total(0), pts_counter(0), is_duration_known(false), largest_frame_processed(0), + current_video_frame(0), has_missing_frames(false) { // Initialize FFMpeg, and register all formats and codecs av_register_all(); avcodec_register_all(); // Init cache - working_cache.SetMaxBytes(0); + working_cache.SetMaxBytesFromInfo(OPEN_MP_NUM_PROCESSORS * 60, info.width, info.height, info.sample_rate, info.channels); + missing_frames.SetMaxBytesFromInfo(OPEN_MP_NUM_PROCESSORS * 4, info.width, info.height, info.sample_rate, info.channels); final_cache.SetMaxBytesFromInfo(OPEN_MP_NUM_PROCESSORS * 4, info.width, info.height, info.sample_rate, info.channels); // Open and Close the reader, to populate it's attributes (such as height, width, etc...) @@ -83,7 +85,7 @@ int AudioLocation::is_near(AudioLocation location, int samples_per_frame, int am if (location.frame > frame) { // remaining samples + new samples - int sample_diff = (samples_per_frame - sample_start) + location.sample_start; + sample_diff = (samples_per_frame - sample_start) + location.sample_start; if (sample_diff >= 0 && sample_diff <= amount) return true; } @@ -92,7 +94,7 @@ int AudioLocation::is_near(AudioLocation location, int samples_per_frame, int am if (location.frame < frame) { // remaining new samples + old samples - int sample_diff = (samples_per_frame - location.sample_start) + sample_start; + sample_diff = (samples_per_frame - location.sample_start) + sample_start; if (sample_diff >= 0 && sample_diff <= amount) return true; } @@ -205,6 +207,8 @@ void FFmpegReader::Open() throw(InvalidFile, NoStreamsFound, InvalidCodec) previous_packet_location.sample_start = 0; // Adjust cache size based on size of frame and audio + working_cache.SetMaxBytesFromInfo(OPEN_MP_NUM_PROCESSORS * 60, info.width, info.height, info.sample_rate, info.channels); + missing_frames.SetMaxBytesFromInfo(OPEN_MP_NUM_PROCESSORS * 4, info.width, info.height, info.sample_rate, info.channels); final_cache.SetMaxBytesFromInfo(OPEN_MP_NUM_PROCESSORS * 4, info.width, info.height, info.sample_rate, info.channels); // Mark as "open" @@ -235,12 +239,17 @@ void FFmpegReader::Close() // Clear final cache final_cache.Clear(); working_cache.Clear(); + missing_frames.Clear(); // Clear processed lists - processed_video_frames.clear(); - processed_audio_frames.clear(); - processing_video_frames.clear(); - processing_audio_frames.clear(); + { + const GenericScopedLock lock(processingCriticalSection); + processed_video_frames.clear(); + processed_audio_frames.clear(); + processing_video_frames.clear(); + processing_audio_frames.clear(); + missing_video_frames.clear(); + } // Clear debug json debug_root.clear(); @@ -257,6 +266,8 @@ void FFmpegReader::Close() largest_frame_processed = 0; seek_audio_frame_found = 0; seek_video_frame_found = 0; + current_video_frame = 0; + has_missing_frames = false; } } @@ -396,7 +407,7 @@ void FFmpegReader::UpdateVideoInfo() } -tr1::shared_ptr FFmpegReader::GetFrame(int requested_frame) throw(OutOfBoundsFrame, ReaderClosed, TooManySeeks) +tr1::shared_ptr FFmpegReader::GetFrame(long int requested_frame) throw(OutOfBoundsFrame, ReaderClosed, TooManySeeks) { // Check for open reader (or throw exception) if (!is_open) @@ -429,6 +440,8 @@ tr1::shared_ptr FFmpegReader::GetFrame(int requested_frame) throw(OutOfBo const GenericScopedLock lock(getFrameCriticalSection); // Check the cache a 2nd time (due to a potential previous lock) + if (has_missing_frames) + CheckMissingFrame(requested_frame); frame = final_cache.GetFrame(requested_frame); if (frame) { // Debug output @@ -448,7 +461,7 @@ tr1::shared_ptr FFmpegReader::GetFrame(int requested_frame) throw(OutOfBo ReadStream(1); // Are we within X frames of the requested frame? - int diff = requested_frame - last_frame; + long int diff = requested_frame - last_frame; if (diff >= 1 && diff <= 20) { // Continue walking the stream @@ -476,7 +489,7 @@ tr1::shared_ptr FFmpegReader::GetFrame(int requested_frame) throw(OutOfBo } // Read the stream until we find the requested Frame -tr1::shared_ptr FFmpegReader::ReadStream(int requested_frame) +tr1::shared_ptr FFmpegReader::ReadStream(long int requested_frame) { // Allocate video frame bool end_of_stream = false; @@ -503,6 +516,11 @@ tr1::shared_ptr FFmpegReader::ReadStream(int requested_frame) // Loop through the stream until the correct frame is found while (true) { + // Missing frames (sometimes frame #'s are skipped due to invalid or missing timestamps) + if (has_missing_frames && CheckMissingFrame(requested_frame)) + // Break this loop (found the requested missing frame) + break; + // Get the next packet into a local variable called packet packet_error = GetNextPacket(); @@ -584,7 +602,7 @@ tr1::shared_ptr FFmpegReader::ReadStream(int requested_frame) // Check if working frames are 'finished' bool is_cache_found = false; if (!is_seeking) - CheckWorkingFrames(false); + CheckWorkingFrames(false, requested_frame); // Check if requested 'final' frame is available is_cache_found = (final_cache.GetFrame(requested_frame) != NULL); @@ -592,8 +610,8 @@ tr1::shared_ptr FFmpegReader::ReadStream(int requested_frame) // Increment frames processed packets_processed++; - // Break once the frame is found - if (is_cache_found && packets_processed >= minimum_packets) + // Break once the frame is found, or after way too many packets have been checked + if ((is_cache_found && packets_processed >= minimum_packets) or packets_processed > 4096) break; } // end while @@ -607,7 +625,7 @@ tr1::shared_ptr FFmpegReader::ReadStream(int requested_frame) // End of stream? if (end_of_stream) // Mark the any other working frames as 'finished' - CheckWorkingFrames(end_of_stream); + CheckWorkingFrames(end_of_stream, requested_frame); // Return requested frame (if found) tr1::shared_ptr frame = final_cache.GetFrame(requested_frame); @@ -722,7 +740,7 @@ bool FFmpegReader::CheckSeek(bool is_video) return false; // Determine max seeked frame - int max_seeked_frame = seek_audio_frame_found; // determine max seeked frame + long int max_seeked_frame = seek_audio_frame_found; // determine max seeked frame if (seek_video_frame_found > max_seeked_frame) max_seeked_frame = seek_video_frame_found; @@ -733,7 +751,7 @@ bool FFmpegReader::CheckSeek(bool is_video) AppendDebugMethod("FFmpegReader::CheckSeek (Too far, seek again)", "is_video_seek", is_video_seek, "max_seeked_frame", max_seeked_frame, "seeking_frame", seeking_frame, "seeking_pts", seeking_pts, "seek_video_frame_found", seek_video_frame_found, "seek_audio_frame_found", seek_audio_frame_found); // Seek again... to the nearest Keyframe - Seek(seeking_frame - 10); + Seek(seeking_frame - (20 * seek_count * seek_count)); } else { @@ -752,13 +770,13 @@ bool FFmpegReader::CheckSeek(bool is_video) } // Process a video packet -void FFmpegReader::ProcessVideoPacket(int requested_frame) +void FFmpegReader::ProcessVideoPacket(long int requested_frame) { // Calculate current frame # - int current_frame = ConvertVideoPTStoFrame(GetVideoPTS()); + long int current_frame = ConvertVideoPTStoFrame(GetVideoPTS()); - // Are we close enough to decode the frame? - if ((current_frame) < (requested_frame - 20)) + // Are we close enough to decode the frame? and is this frame # valid? + if ((!has_missing_frames and current_frame < (requested_frame - 20)) or (current_frame == -1)) { // Remove frame and packet RemoveAVFrame(pFrame); @@ -789,7 +807,7 @@ void FFmpegReader::ProcessVideoPacket(int requested_frame) rescaler_position = 0; // Add video frame to list of processing video frames - #pragma omp critical (processing_list) + const GenericScopedLock lock(processingCriticalSection); processing_video_frames[current_frame] = current_frame; // Track 1st video packet after a successful seek @@ -853,10 +871,10 @@ void FFmpegReader::ProcessVideoPacket(int requested_frame) } // Process an audio packet -void FFmpegReader::ProcessAudioPacket(int requested_frame, int target_frame, int starting_sample) +void FFmpegReader::ProcessAudioPacket(long int requested_frame, long int target_frame, int starting_sample) { // Are we close enough to decode the frame's audio? - if (target_frame < (requested_frame - 20)) + if (!has_missing_frames and target_frame < (requested_frame - 20)) { // Remove packet RemoveAVPacket(packet); @@ -923,8 +941,10 @@ void FFmpegReader::ProcessAudioPacket(int requested_frame, int target_frame, int prev_samples = pts_remaining_samples; // Add audio frame to list of processing audio frames - #pragma omp critical (processing_list) - processing_audio_frames.insert(pair(previous_packet_location.frame, previous_packet_location.frame)); + { + const GenericScopedLock lock(processingCriticalSection); + processing_audio_frames.insert(pair(previous_packet_location.frame, previous_packet_location.frame)); + } while (pts_remaining_samples) { @@ -945,8 +965,10 @@ void FFmpegReader::ProcessAudioPacket(int requested_frame, int target_frame, int previous_packet_location.sample_start = 0; // Add audio frame to list of processing audio frames - #pragma omp critical (processing_list) - processing_audio_frames.insert(pair(previous_packet_location.frame, previous_packet_location.frame)); + { + const GenericScopedLock lock(processingCriticalSection); + processing_audio_frames.insert(pair(previous_packet_location.frame, previous_packet_location.frame)); + } } else { // Increment sample start @@ -1107,10 +1129,10 @@ void FFmpegReader::ProcessAudioPacket(int requested_frame, int target_frame, int audio_buf = NULL; // Remove audio frame from list of processing audio frames - #pragma omp critical (processing_list) { + const GenericScopedLock lock(processingCriticalSection); // Update all frames as completed - for (int f = target_frame; f < starting_frame_number; f++) { + for (long int f = target_frame; f < starting_frame_number; f++) { // Remove the frame # from the processing list. NOTE: If more than one thread is // processing this frame, the frame # will be in this list multiple times. We are only // removing a single instance of it here. @@ -1140,7 +1162,7 @@ void FFmpegReader::ProcessAudioPacket(int requested_frame, int target_frame, int // Seek to a specific frame. This is not always frame accurate, it's more of an estimation on many codecs. -void FFmpegReader::Seek(int requested_frame) throw(TooManySeeks) +void FFmpegReader::Seek(long int requested_frame) throw(TooManySeeks) { // Adjust for a requested frame that is too small or too large if (requested_frame < 1) @@ -1161,21 +1183,22 @@ void FFmpegReader::Seek(int requested_frame) throw(TooManySeeks) processing_video_frames.clear(); processed_video_frames.clear(); processed_audio_frames.clear(); + duplicate_video_frames.clear(); + missing_video_frames.clear(); } // Reset the last frame variable last_frame = 0; + current_video_frame = 0; + largest_frame_processed = 0; + has_missing_frames = false; // Increment seek count seek_count++; - // too many seeks - if (seek_count > 10) - throw TooManySeeks("Too many seek attempts... something seems wrong.", path); - - // If seeking to frame 1, we need to close and re-open the file (this is more reliable than seeking) + // If seeking near frame 1, we need to close and re-open the file (this is more reliable than seeking) int buffer_amount = 6; - if (requested_frame - buffer_amount <= 1) + if (requested_frame - buffer_amount < 20) { // Close and re-open file (basically seeking to frame 1) Close(); @@ -1183,8 +1206,11 @@ void FFmpegReader::Seek(int requested_frame) throw(TooManySeeks) // Not actually seeking, so clear these flags is_seeking = false; - seeking_frame = 1; - seeking_pts = ConvertFrameToVideoPTS(1); + if (seek_count == 1) { + // Don't redefine this on multiple seek attempts for a specific frame + seeking_frame = 1; + seeking_pts = ConvertFrameToVideoPTS(1); + } seek_audio_frame_found = 0; // used to detect which frames to throw away after a seek seek_video_frame_found = 0; // used to detect which frames to throw away after a seek } @@ -1193,20 +1219,8 @@ void FFmpegReader::Seek(int requested_frame) throw(TooManySeeks) // Seek to nearest key-frame (aka, i-frame) bool seek_worked = false; - // Seek video stream (if any) - int64_t seek_target = ConvertFrameToVideoPTS(requested_frame - buffer_amount); - if (info.has_video) { - if (av_seek_frame(pFormatCtx, info.video_stream_index, seek_target, AVSEEK_FLAG_BACKWARD) < 0) { - fprintf(stderr, "%s: error while seeking video stream\n", pFormatCtx->filename); - } else - { - // VIDEO SEEK - is_video_seek = true; - seek_worked = true; - } - } - // Seek audio stream (if not already seeked... and if an audio stream is found) + int64_t seek_target = ConvertFrameToVideoPTS(requested_frame - buffer_amount); if (!seek_worked && info.has_audio) { seek_target = ConvertFrameToAudioPTS(requested_frame - buffer_amount); @@ -1221,6 +1235,18 @@ void FFmpegReader::Seek(int requested_frame) throw(TooManySeeks) } } + // Seek video stream (if any) + if (info.has_video) { + if (av_seek_frame(pFormatCtx, info.video_stream_index, seek_target, AVSEEK_FLAG_BACKWARD) < 0) { + fprintf(stderr, "%s: error while seeking video stream\n", pFormatCtx->filename); + } else + { + // VIDEO SEEK + is_video_seek = true; + seek_worked = true; + } + } + // Was the seek successful? if (seek_worked) { @@ -1238,8 +1264,11 @@ void FFmpegReader::Seek(int requested_frame) throw(TooManySeeks) // init seek flags is_seeking = true; - seeking_pts = seek_target; - seeking_frame = requested_frame; + if (seek_count == 1) { + // Don't redefine this on multiple seek attempts for a specific frame + seeking_pts = seek_target; + seeking_frame = requested_frame; + } seek_audio_frame_found = 0; // used to detect which frames to throw away after a seek seek_video_frame_found = 0; // used to detect which frames to throw away after a seek @@ -1255,7 +1284,7 @@ void FFmpegReader::Seek(int requested_frame) throw(TooManySeeks) } // Get the PTS for the current video packet -int FFmpegReader::GetVideoPTS() +long int FFmpegReader::GetVideoPTS() { int current_pts = 0; if(packet->dts != AV_NOPTS_VALUE) @@ -1286,49 +1315,91 @@ void FFmpegReader::UpdatePTSOffset(bool is_video) } // Convert PTS into Frame Number -int FFmpegReader::ConvertVideoPTStoFrame(int pts) +long int FFmpegReader::ConvertVideoPTStoFrame(long int pts) { // Apply PTS offset pts = pts + video_pts_offset; + long int previous_video_frame = current_video_frame; // Get the video packet start time (in seconds) double video_seconds = double(pts) * info.video_timebase.ToDouble(); // Divide by the video timebase, to get the video frame number (frame # is decimal at this point) - int frame = round(video_seconds * info.fps.ToDouble()) + 1; + long int frame = round(video_seconds * info.fps.ToDouble()) + 1; + + // Keep track of the expected video frame # + if (current_video_frame == 0) + current_video_frame = frame; + else { + + // Sometimes frames are duplicated due to identical (or similar) timestamps + if (frame == previous_video_frame) { + duplicate_video_frames.insert(pair(frame, frame)); + + // return -1 frame number + frame = -1; + } + else + // Increment expected frame + current_video_frame++; + + if (current_video_frame < frame) + // has missing frames + AppendDebugMethod("FFmpegReader::ConvertVideoPTStoFrame (detected missing frame)", "calculated frame", frame, "previous_video_frame", previous_video_frame, "current_video_frame", current_video_frame, "", -1, "", -1, "", -1); + + // Sometimes frames are missing due to varying timestamps, or they were dropped. Determine + // if we are missing a video frame. + while (current_video_frame < frame) { + missing_video_frames.insert(pair(previous_video_frame, current_video_frame)); + cout << "missing frame detected: " << current_video_frame << ", previous frame: " << previous_video_frame << endl; + + // Mark this reader as containing missing frames + has_missing_frames = true; + + // Create missing frame (and copy image from previous frame) + tr1::shared_ptr frame_object = final_cache.GetFrame(previous_video_frame); + if (frame_object) { + // Move this related frame to the missing frames cache (so the missing frames can use it later) + missing_frames.Add(frame_object->number, frame_object); + } + + // Increment current frame + current_video_frame++; + } + } // Return frame # return frame; } // Convert Frame Number into Video PTS -int FFmpegReader::ConvertFrameToVideoPTS(int frame_number) +long int FFmpegReader::ConvertFrameToVideoPTS(long int frame_number) { // Get timestamp of this frame (in seconds) double seconds = double(frame_number) / info.fps.ToDouble(); // Calculate the # of video packets in this timestamp - int video_pts = round(seconds / info.video_timebase.ToDouble()); + long int video_pts = round(seconds / info.video_timebase.ToDouble()); // Apply PTS offset (opposite) return video_pts - video_pts_offset; } // Convert Frame Number into Video PTS -int FFmpegReader::ConvertFrameToAudioPTS(int frame_number) +long int FFmpegReader::ConvertFrameToAudioPTS(long int frame_number) { // Get timestamp of this frame (in seconds) double seconds = double(frame_number) / info.fps.ToDouble(); // Calculate the # of audio packets in this timestamp - int audio_pts = round(seconds / info.audio_timebase.ToDouble()); + long int audio_pts = round(seconds / info.audio_timebase.ToDouble()); // Apply PTS offset (opposite) return audio_pts - audio_pts_offset; } // Calculate Starting video frame and sample # for an audio PTS -AudioLocation FFmpegReader::GetAudioPTSLocation(int pts) +AudioLocation FFmpegReader::GetAudioPTSLocation(long int pts) { // Apply PTS offset pts = pts + audio_pts_offset; @@ -1392,15 +1463,11 @@ AudioLocation FFmpegReader::GetAudioPTSLocation(int pts) } // Create a new Frame (or return an existing one) and add it to the working queue. -tr1::shared_ptr FFmpegReader::CreateFrame(int requested_frame) +tr1::shared_ptr FFmpegReader::CreateFrame(long int requested_frame) { - tr1::shared_ptr output; // Check working cache - tr1::shared_ptr frame = working_cache.GetFrame(requested_frame); - if (frame) - // Return existing frame - output = frame; - else + tr1::shared_ptr output = working_cache.GetFrame(requested_frame); + if (!output) { // Create a new frame on the working cache output = tr1::shared_ptr(new Frame(requested_frame, info.width, info.height, "#000000", Frame::GetSamplesPerFrame(requested_frame, info.fps, info.sample_rate, info.channels), info.channels)); @@ -1420,11 +1487,11 @@ tr1::shared_ptr FFmpegReader::CreateFrame(int requested_frame) } // Determine if frame is partial due to seek -bool FFmpegReader::IsPartialFrame(int requested_frame) { +bool FFmpegReader::IsPartialFrame(long int requested_frame) { // Sometimes a seek gets partial frames, and we need to remove them bool seek_trash = false; - int max_seeked_frame = seek_audio_frame_found; // determine max seeked frame + long int max_seeked_frame = seek_audio_frame_found; // determine max seeked frame if (seek_video_frame_found > max_seeked_frame) max_seeked_frame = seek_video_frame_found; if ((info.has_audio && seek_audio_frame_found && max_seeked_frame >= requested_frame) || @@ -1434,19 +1501,75 @@ bool FFmpegReader::IsPartialFrame(int requested_frame) { return seek_trash; } +// Check if a frame is missing and attempt to replace it's frame image (and +bool FFmpegReader::CheckMissingFrame(long int requested_frame) +{ + // Debug output + AppendDebugMethod("FFmpegReader::CheckMissingFrame", "requested_frame", requested_frame, "has_missing_frames", has_missing_frames, "missing_video_frames.size()", missing_video_frames.size(), "", -1, "", -1, "", -1); + + // Missing frames (sometimes frame #'s are skipped due to invalid or missing timestamps) + map::iterator itr; + bool found_missing_frame = false; + for(itr = missing_video_frames.begin(); itr != missing_video_frames.end(); ++itr) + { + // Is requested frame missing? + if (requested_frame == itr->second) + { + // Create missing frame (and copy image from previous frame) + tr1::shared_ptr missing_frame = CreateFrame(requested_frame); + tr1::shared_ptr related_frame = missing_frames.GetFrame(itr->first); + if (related_frame != NULL) { + // Add the image from the related frame + missing_frame->AddImage(tr1::shared_ptr(new QImage(*related_frame->GetImage())), true); + + // Add this frame to the processed map (since it's already done) + { + const GenericScopedLock lock(processingCriticalSection); + processed_video_frames[requested_frame] = requested_frame; + processed_audio_frames[requested_frame] = requested_frame; + } + + // Move the frame manually to final cache + final_cache.Add(missing_frame->number, missing_frame); + + // Remove frame from working cache + working_cache.Remove(missing_frame->number); + + // Update last frame processed + last_frame = missing_frame->number; + + // Remove missing frame from map + missing_video_frames.erase(itr); + + // Break this loop + found_missing_frame = true; + break; + } + } + } + + return found_missing_frame; +} + // Check the working queue, and move finished frames to the finished queue -void FFmpegReader::CheckWorkingFrames(bool end_of_stream) +void FFmpegReader::CheckWorkingFrames(bool end_of_stream, long int requested_frame) { // Loop through all working queue frames while (true) { - // Break if no working frames - if (working_cache.Count() == 0) - break; - // Get the front frame of working cache tr1::shared_ptr f(working_cache.GetSmallestFrame()); + // Was a frame found? + if (!f) + // No frames found + break; + + // Only process frames smaller than or near the requested frame + if (f->number > (requested_frame + OPEN_MP_NUM_PROCESSORS)) + // This frame is too far in the future... ignore for now + break; + bool is_video_ready = false; bool is_audio_ready = false; { // limit scope of next few lines @@ -1466,8 +1589,23 @@ void FFmpegReader::CheckWorkingFrames(bool end_of_stream) // Debug output AppendDebugMethod("FFmpegReader::CheckWorkingFrames", "frame_number", f->number, "is_video_ready", is_video_ready, "is_audio_ready", is_audio_ready, "", -1, "", -1, "", -1); + // Check if any missing frames need to be created + if (is_video_ready) + { + // Check if this frame is related to any missing frames + int is_related_to_missing_frames = missing_video_frames.count(f->number); + + if (is_related_to_missing_frames > 0) { + // Move this related frame to the missing frames cache (so the missing frames can use it later) + missing_frames.Add(f->number, f); + } + } + + // Check for a missing video frame + CheckMissingFrame(f->number); + // Check if working frame is final - if ((!end_of_stream && is_video_ready && is_audio_ready) || end_of_stream || is_seek_trash || working_cache.Count() >= 200) + if ((!end_of_stream && is_video_ready && is_audio_ready) || end_of_stream || is_seek_trash) { // Debug output AppendDebugMethod("FFmpegReader::CheckWorkingFrames (mark frame as final)", "f->number", f->number, "is_seek_trash", is_seek_trash, "Working Cache Count", working_cache.Count(), "Final Cache Count", final_cache.Count(), "", -1, "", -1); @@ -1527,7 +1665,7 @@ void FFmpegReader::CheckFPS() UpdatePTSOffset(true); // Get PTS of this packet - int pts = GetVideoPTS(); + long int pts = GetVideoPTS(); // Remove pFrame RemoveAVFrame(pFrame); @@ -1660,10 +1798,10 @@ void FFmpegReader::RemoveAVPacket(AVPacket* remove_packet) } /// Get the smallest video frame that is still being processed -int FFmpegReader::GetSmallestVideoFrame() +long int FFmpegReader::GetSmallestVideoFrame() { // Loop through frame numbers - map::iterator itr; + map::iterator itr; int smallest_frame = -1; for(itr = processing_video_frames.begin(); itr != processing_video_frames.end(); ++itr) { @@ -1676,11 +1814,12 @@ int FFmpegReader::GetSmallestVideoFrame() } /// Get the smallest audio frame that is still being processed -int FFmpegReader::GetSmallestAudioFrame() +long int FFmpegReader::GetSmallestAudioFrame() { // Loop through frame numbers - map::iterator itr; + map::iterator itr; int smallest_frame = -1; + const GenericScopedLock lock(processingCriticalSection); for(itr = processing_audio_frames.begin(); itr != processing_audio_frames.end(); ++itr) { if (itr->first < smallest_frame || smallest_frame == -1) diff --git a/src/FFmpegWriter.cpp b/src/FFmpegWriter.cpp index 730b7b2b..d4402e95 100644 --- a/src/FFmpegWriter.cpp +++ b/src/FFmpegWriter.cpp @@ -484,12 +484,12 @@ void FFmpegWriter::write_queued_frames() } // Write a block of frames from a reader -void FFmpegWriter::WriteFrame(ReaderBase* reader, int start, int length) throw(WriterClosed) +void FFmpegWriter::WriteFrame(ReaderBase* reader, long int start, long int length) throw(WriterClosed) { AppendDebugMethod("FFmpegWriter::WriteFrame (from Reader)", "start", start, "length", length, "", -1, "", -1, "", -1, "", -1); // Loop through each frame (and encoded it) - for (int number = start; number <= length; number++) + for (long int number = start; number <= length; number++) { // Get the frame tr1::shared_ptr f = reader->GetFrame(number); diff --git a/src/Frame.cpp b/src/Frame.cpp index 1f008999..3003d334 100644 --- a/src/Frame.cpp +++ b/src/Frame.cpp @@ -42,7 +42,7 @@ Frame::Frame() : number(1), pixel_ratio(1,1), channels(2), width(1), height(1), }; // Constructor - image only (48kHz audio silence) -Frame::Frame(int number, int width, int height, string color) +Frame::Frame(long int number, int width, int height, string color) : number(number), pixel_ratio(1,1), channels(2), width(width), height(height), channel_layout(LAYOUT_STEREO), sample_rate(44100), qbuffer(NULL) { @@ -54,7 +54,7 @@ Frame::Frame(int number, int width, int height, string color) }; // Constructor - image only from pixel array (48kHz audio silence) -Frame::Frame(int number, int width, int height, const string map, const Magick::StorageType type, const void *pixels) +Frame::Frame(long int number, int width, int height, const string map, const Magick::StorageType type, const void *pixels) : number(number), pixel_ratio(1,1), channels(2), width(width), height(height), channel_layout(LAYOUT_STEREO), sample_rate(44100), qbuffer(NULL) { @@ -66,7 +66,7 @@ Frame::Frame(int number, int width, int height, const string map, const Magick:: }; // Constructor - audio only (300x200 blank image) -Frame::Frame(int number, int samples, int channels) : +Frame::Frame(long int number, int samples, int channels) : number(number), pixel_ratio(1,1), channels(channels), width(1), height(1), channel_layout(LAYOUT_STEREO), sample_rate(44100), qbuffer(NULL) { @@ -78,7 +78,7 @@ Frame::Frame(int number, int samples, int channels) : }; // Constructor - image & audio -Frame::Frame(int number, int width, int height, string color, int samples, int channels) +Frame::Frame(long int number, int width, int height, string color, int samples, int channels) : number(number), pixel_ratio(1,1), channels(channels), width(width), height(height), channel_layout(LAYOUT_STEREO), sample_rate(44100), qbuffer(NULL) { @@ -437,7 +437,7 @@ void Frame::SetFrameNumber(int new_number) } // Calculate the # of samples per video frame (for a specific frame number and frame rate) -int Frame::GetSamplesPerFrame(int number, Fraction fps, int sample_rate, int channels) +int Frame::GetSamplesPerFrame(long int number, Fraction fps, int sample_rate, int channels) { // Get the total # of samples for the previous frame, and the current frame (rounded) double fps_rate = fps.Reciprocal().ToDouble(); @@ -938,7 +938,6 @@ void Frame::cleanUpBuffer(void *info) // Remove buffer since QImage tells us to unsigned char* ptr_to_qbuffer = (unsigned char*) info; delete ptr_to_qbuffer; - ptr_to_qbuffer = NULL; } } diff --git a/src/FrameMapper.cpp b/src/FrameMapper.cpp index 4eda35e3..8b0440ce 100644 --- a/src/FrameMapper.cpp +++ b/src/FrameMapper.cpp @@ -56,7 +56,7 @@ FrameMapper::FrameMapper(ReaderBase *reader, Fraction target, PulldownType targe Init(); } -void FrameMapper::AddField(int frame) +void FrameMapper::AddField(long int frame) { // Add a field, and toggle the odd / even field AddField(Field(frame, field_toggle)); @@ -111,11 +111,11 @@ void FrameMapper::Init() // Calculate # of fields to map - int frame = 1; - int number_of_fields = reader->info.video_length * 2; + long int frame = 1; + long int number_of_fields = reader->info.video_length * 2; // Loop through all fields in the original video file - for (int field = 1; field <= number_of_fields; field++) + for (long int field = 1; field <= number_of_fields; field++) { if (difference == 0) // Same frame rate, NO pull-down or special techniques required @@ -183,7 +183,7 @@ void FrameMapper::Init() // Map the remaining framerates using a simple Keyframe curve // Calculate the difference (to be used as a multiplier) float rate_diff = target.ToFloat() / original.ToFloat(); - int new_length = reader->info.video_length * rate_diff; + long int new_length = reader->info.video_length * rate_diff; // Build curve for framerate mapping Keyframe rate_curve; @@ -191,7 +191,7 @@ void FrameMapper::Init() rate_curve.AddPoint(new_length, reader->info.video_length, LINEAR); // Loop through curve, and build list of frames - for (int frame_num = 1; frame_num <= new_length; frame_num++) + for (long int frame_num = 1; frame_num <= new_length; frame_num++) { // Add 2 fields per frame AddField(rate_curve.GetInt(frame_num)); @@ -207,7 +207,7 @@ void FrameMapper::Init() int start_samples_frame = 1; int start_samples_position = 0; - for (unsigned int field = 1; field <= fields.size(); field++) + for (long int field = 1; field <= fields.size(); field++) { // Get the current field Field f = fields[field - 1]; @@ -216,7 +216,7 @@ void FrameMapper::Init() if (field % 2 == 0 && field > 0) { // New frame number - int frame_number = field / 2; + long int frame_number = field / 2; // Set the bottom frame if (f.isOdd) @@ -283,7 +283,7 @@ void FrameMapper::Init() fields.clear(); } -MappedFrame FrameMapper::GetMappedFrame(int TargetFrameNumber) throw(OutOfBoundsFrame) +MappedFrame FrameMapper::GetMappedFrame(long int TargetFrameNumber) throw(OutOfBoundsFrame) { // Check if frame number is valid if(TargetFrameNumber < 1 || frames.size() == 0) @@ -299,7 +299,7 @@ MappedFrame FrameMapper::GetMappedFrame(int TargetFrameNumber) throw(OutOfBounds } // Get an openshot::Frame object for a specific frame number of this reader. -tr1::shared_ptr FrameMapper::GetFrame(int requested_frame) throw(ReaderClosed) +tr1::shared_ptr FrameMapper::GetFrame(long int requested_frame) throw(ReaderClosed) { // Check final cache, and just return the frame (if it's available) tr1::shared_ptr final_frame = final_cache.GetFrame(requested_frame); @@ -332,11 +332,15 @@ tr1::shared_ptr FrameMapper::GetFrame(int requested_frame) throw(ReaderCl // Loop through all requested frames, each frame gets it's own thread #pragma omp for ordered - for (int frame_number = requested_frame; frame_number < requested_frame + minimum_frames; frame_number++) + for (long int frame_number = requested_frame; frame_number < requested_frame + minimum_frames; frame_number++) { // Get the mapped frame MappedFrame mapped = GetMappedFrame(frame_number); - tr1::shared_ptr mapped_frame = reader->GetFrame(mapped.Odd.Frame); + tr1::shared_ptr mapped_frame; + + #pragma omp ordered + mapped_frame = reader->GetFrame(mapped.Odd.Frame); + int channels_in_frame = mapped_frame->GetAudioChannelsCount(); // Init some basic properties about this frame @@ -349,12 +353,16 @@ tr1::shared_ptr FrameMapper::GetFrame(int requested_frame) throw(ReaderCl // Copy the image from the odd field - tr1::shared_ptr odd_frame = reader->GetFrame(mapped.Odd.Frame); + tr1::shared_ptr odd_frame; + #pragma omp ordered + odd_frame = reader->GetFrame(mapped.Odd.Frame); if (odd_frame) frame->AddImage(tr1::shared_ptr(new QImage(*odd_frame->GetImage())), true); if (mapped.Odd.Frame != mapped.Even.Frame) { // Add even lines (if different than the previous image) - tr1::shared_ptr even_frame = reader->GetFrame(mapped.Even.Frame); + tr1::shared_ptr even_frame; + #pragma omp ordered + even_frame = reader->GetFrame(mapped.Even.Frame); if (even_frame) frame->AddImage(tr1::shared_ptr(new QImage(*even_frame->GetImage())), false); } @@ -587,7 +595,7 @@ void FrameMapper::ChangeMapping(Fraction target_fps, PulldownType target_pulldow } // Resample audio and map channels (if needed) -void FrameMapper::ResampleMappedAudio(tr1::shared_ptr frame, int original_frame_number) +void FrameMapper::ResampleMappedAudio(tr1::shared_ptr frame, long int original_frame_number) { // Init audio buffers / variables int total_frame_samples = 0; diff --git a/src/ImageReader.cpp b/src/ImageReader.cpp index fa0bc2a6..98876af5 100644 --- a/src/ImageReader.cpp +++ b/src/ImageReader.cpp @@ -103,7 +103,7 @@ void ImageReader::Close() } // Get an openshot::Frame object for a specific frame number of this reader. -tr1::shared_ptr ImageReader::GetFrame(int requested_frame) throw(ReaderClosed) +tr1::shared_ptr ImageReader::GetFrame(long int requested_frame) throw(ReaderClosed) { // Check for open reader (or throw exception) if (!is_open) diff --git a/src/ImageWriter.cpp b/src/ImageWriter.cpp index 0289c0a7..532e0df3 100644 --- a/src/ImageWriter.cpp +++ b/src/ImageWriter.cpp @@ -120,12 +120,12 @@ void ImageWriter::WriteFrame(tr1::shared_ptr frame) throw(WriterClosed) } // Write a block of frames from a reader -void ImageWriter::WriteFrame(ReaderBase* reader, int start, int length) throw(WriterClosed) +void ImageWriter::WriteFrame(ReaderBase* reader, long int start, long int length) throw(WriterClosed) { AppendDebugMethod("ImageWriter::WriteFrame (from Reader)", "start", start, "length", length, "", -1, "", -1, "", -1, "", -1); // Loop through each frame (and encoded it) - for (int number = start; number <= length; number++) + for (long int number = start; number <= length; number++) { // Get the frame tr1::shared_ptr f = reader->GetFrame(number); diff --git a/src/KeyFrame.cpp b/src/KeyFrame.cpp index 2d2f66e9..849366a3 100644 --- a/src/KeyFrame.cpp +++ b/src/KeyFrame.cpp @@ -35,11 +35,11 @@ using namespace openshot; // processing the curve, due to all the points going from left to right. void Keyframe::ReorderPoints() { // Loop through all coordinates, and sort them by the X attribute - for (int x = 0; x < Points.size(); x++) { - int compare_index = x; - int smallest_index = x; + for (long int x = 0; x < Points.size(); x++) { + long int compare_index = x; + long int smallest_index = x; - for (int compare_index = x + 1; compare_index < Points.size(); compare_index++) { + for (long int compare_index = x + 1; compare_index < Points.size(); compare_index++) { if (Points[compare_index].co.X < Points[smallest_index].co.X) { smallest_index = compare_index; } @@ -111,7 +111,7 @@ void Keyframe::SetHandles(Point current) needs_update = true; // Lookup the index of this point - int index = FindIndex(current); + long int index = FindIndex(current); Point *Current_Point = &Points[index]; // Find the previous point and next points (if any) @@ -148,9 +148,9 @@ void Keyframe::SetHandles(Point current) } // Get the index of a point by matching a coordinate -int Keyframe::FindIndex(Point p) throw(OutOfBoundsPoint) { +long int Keyframe::FindIndex(Point p) throw(OutOfBoundsPoint) { // loop through points, and find a matching coordinate - for (int x = 0; x < Points.size(); x++) { + for (long int x = 0; x < Points.size(); x++) { // Get each point Point existing_point = Points[x]; @@ -168,7 +168,7 @@ int Keyframe::FindIndex(Point p) throw(OutOfBoundsPoint) { // Determine if point already exists bool Keyframe::Contains(Point p) { // loop through points, and find a matching coordinate - for (int x = 0; x < Points.size(); x++) { + for (long int x = 0; x < Points.size(); x++) { // Get each point Point existing_point = Points[x]; @@ -188,7 +188,7 @@ Point Keyframe::GetClosestPoint(Point p) { Point closest(-1, -1); // loop through points, and find a matching coordinate - for (int x = 0; x < Points.size(); x++) { + for (long int x = 0; x < Points.size(); x++) { // Get each point Point existing_point = Points[x]; @@ -215,7 +215,7 @@ Point Keyframe::GetClosestPoint(Point p) { } // Get the value at a specific index -float Keyframe::GetValue(int index) +float Keyframe::GetValue(long int index) { // Check if it needs to be processed if (needs_update) @@ -237,7 +237,7 @@ float Keyframe::GetValue(int index) } // Get the rounded INT value at a specific index -int Keyframe::GetInt(int index) +int Keyframe::GetInt(long int index) { // Check if it needs to be processed if (needs_update) @@ -258,6 +258,28 @@ int Keyframe::GetInt(int index) return 0; } +// Get the rounded INT value at a specific index +long int Keyframe::GetLong(long int index) +{ + // Check if it needs to be processed + if (needs_update) + Process(); + + // Is index a valid point? + if (index >= 0 && index < Values.size()) + // Return value + return long(round(Values[index].Y)); + else if (index < 0 && Values.size() > 0) + // Return the minimum value + return long(round(Values[0].Y)); + else if (index >= Values.size() && Values.size() > 0) + // return the maximum value + return long(round(Values[Values.size() - 1].Y)); + else + // return a blank coordinate (0,0) + return 0; +} + // Get the direction of the curve at a specific index (increasing or decreasing) bool Keyframe::IsIncreasing(int index) { @@ -268,13 +290,13 @@ bool Keyframe::IsIncreasing(int index) // Is index a valid point? if (index >= 0 && index < Values.size()) // Return value - return int(round(Values[index].IsIncreasing())); + return long(round(Values[index].IsIncreasing())); else if (index < 0 && Values.size() > 0) // Return the minimum value - return int(round(Values[0].IsIncreasing())); + return long(round(Values[0].IsIncreasing())); else if (index >= Values.size() && Values.size() > 0) // return the maximum value - return int(round(Values[Values.size() - 1].IsIncreasing())); + return long(round(Values[Values.size() - 1].IsIncreasing())); else // return the default direction of most curves (i.e. increasing is true) return true; @@ -339,7 +361,7 @@ void Keyframe::SetJsonValue(Json::Value root) { if (!root["Points"].isNull()) // loop through points - for (int x = 0; x < root["Points"].size(); x++) { + for (long int x = 0; x < root["Points"].size(); x++) { // Get each point Json::Value existing_point = root["Points"][x]; @@ -359,7 +381,7 @@ void Keyframe::SetJsonValue(Json::Value root) { } // Get the fraction that represents how many times this value is repeated in the curve -Fraction Keyframe::GetRepeatFraction(int index) +Fraction Keyframe::GetRepeatFraction(long int index) { // Check if it needs to be processed if (needs_update) @@ -381,7 +403,7 @@ Fraction Keyframe::GetRepeatFraction(int index) } // Get the change in Y value (from the previous Y value) -float Keyframe::GetDelta(int index) +float Keyframe::GetDelta(long int index) { // Check if it needs to be processed if (needs_update) @@ -403,7 +425,7 @@ float Keyframe::GetDelta(int index) } // Get a point at a specific index -Point& Keyframe::GetPoint(int index) throw(OutOfBoundsPoint) { +Point& Keyframe::GetPoint(long int index) throw(OutOfBoundsPoint) { // Is index a valid point? if (index >= 0 && index < Points.size()) return Points[index]; @@ -413,7 +435,7 @@ Point& Keyframe::GetPoint(int index) throw(OutOfBoundsPoint) { } // Get the number of values (i.e. coordinates on the X axis) -int Keyframe::GetLength() { +long int Keyframe::GetLength() { // Check if it needs to be processed if (needs_update) Process(); @@ -423,7 +445,7 @@ int Keyframe::GetLength() { } // Get the number of points (i.e. # of points) -int Keyframe::GetCount() { +long int Keyframe::GetCount() { // return the size of the Values vector return Points.size(); @@ -435,7 +457,7 @@ void Keyframe::RemovePoint(Point p) throw(OutOfBoundsPoint) { needs_update = true; // loop through points, and find a matching coordinate - for (int x = 0; x < Points.size(); x++) { + for (long int x = 0; x < Points.size(); x++) { // Get each point Point existing_point = Points[x]; @@ -452,7 +474,7 @@ void Keyframe::RemovePoint(Point p) throw(OutOfBoundsPoint) { } // Remove a point by index -void Keyframe::RemovePoint(int index) throw(OutOfBoundsPoint) { +void Keyframe::RemovePoint(long int index) throw(OutOfBoundsPoint) { // mark as dirty needs_update = true; @@ -467,7 +489,7 @@ void Keyframe::RemovePoint(int index) throw(OutOfBoundsPoint) { throw OutOfBoundsPoint("Invalid point requested", index, Points.size()); } -void Keyframe::UpdatePoint(int index, Point p) { +void Keyframe::UpdatePoint(long int index, Point p) { // mark as dirty needs_update = true; @@ -503,7 +525,7 @@ void Keyframe::PrintValues() { for (vector::iterator it = Values.begin() + 1; it != Values.end(); it++) { Coordinate c = *it; - cout << int(round(c.X)) << "\t" << c.Y << "\t" << c.IsIncreasing() << "\t" << c.Repeat().num << "\t" << c.Repeat().den << "\t" << c.Delta() << endl; + cout << long(round(c.X)) << "\t" << c.Y << "\t" << c.IsIncreasing() << "\t" << c.Repeat().num << "\t" << c.Repeat().den << "\t" << c.Delta() << endl; } } @@ -522,7 +544,7 @@ void Keyframe::Process() { Point p1 = Points[0]; if (Points.size() > 1) // Fill in previous X values (before 1st point) - for (int x = 0; x < p1.co.X; x++) + for (long int x = 0; x < p1.co.X; x++) Values.push_back(Coordinate(Values.size(), p1.co.Y)); else // Add a single value (since we only have 1 point) @@ -531,7 +553,7 @@ void Keyframe::Process() { // Loop through each pair of points (1 less than the max points). Each // pair of points is used to process a segment of the keyframe. Point p2(0, 0); - for (int x = 0; x < Points.size() - 1; x++) { + for (long int x = 0; x < Points.size() - 1; x++) { p1 = Points[x]; p2 = Points[x + 1]; @@ -543,19 +565,19 @@ void Keyframe::Process() { // when time mapping, to determine what direction the audio waveforms play. bool increasing = true; int repeat_count = 1; - int last_value = 0; + long int last_value = 0; for (vector::iterator it = Values.begin() + 1; it != Values.end(); it++) { - int current_value = int(round((*it).Y)); - int next_value = int(round((*it).Y)); - int prev_value = int(round((*it).Y)); + int current_value = long(round((*it).Y)); + long int next_value = long(round((*it).Y)); + long int prev_value = long(round((*it).Y)); if (it + 1 != Values.end()) - next_value = int(round((*(it + 1)).Y)); + next_value = long(round((*(it + 1)).Y)); if (it - 1 >= Values.begin()) - prev_value = int(round((*(it - 1)).Y)); + prev_value = long(round((*(it - 1)).Y)); // Loop forward and look for the next unique value (to determine direction) for (vector::iterator direction_it = it + 1; direction_it != Values.end(); direction_it++) { - int next = int(round((*direction_it).Y)); + long int next = long(round((*direction_it).Y)); // Detect direction if (current_value < next) @@ -584,7 +606,7 @@ void Keyframe::Process() { // Detect how many 'more' times it's repeated int additional_repeats = 0; for (vector::iterator repeat_it = it + 1; repeat_it != Values.end(); repeat_it++) { - int next = int(round((*repeat_it).Y)); + long int next = long(round((*repeat_it).Y)); if (next == current_value) // repeated, so increment count additional_repeats++; @@ -610,7 +632,7 @@ void Keyframe::Process() { void Keyframe::ProcessSegment(int Segment, Point p1, Point p2) { // Determine the number of values for this segment - int number_of_values = round(p2.co.X) - round(p1.co.X); + long int number_of_values = round(p2.co.X) - round(p1.co.X); // Exit function if no values if (number_of_values == 0) @@ -640,7 +662,7 @@ void Keyframe::ProcessSegment(int Segment, Point p1, Point p2) { current_value += value_increment; // Add each increment to the values vector - for (int x = 0; x < number_of_values; x++) { + for (long int x = 0; x < number_of_values; x++) { // add value as a coordinate to the "values" vector Values.push_back(Coordinate(Values.size(), current_value)); @@ -667,8 +689,8 @@ void Keyframe::ProcessSegment(int Segment, Point p1, Point p2) { segment_coordinates.push_back(p2.co); vector raw_coordinates; - int npts = segment_coordinates.size(); - int icount, jcount; + long int npts = segment_coordinates.size(); + long int icount, jcount; double step, t; double last_x = -1; // small number init, to track the last used x @@ -678,7 +700,7 @@ void Keyframe::ProcessSegment(int Segment, Point p1, Point p2) { step = (double) 1.0 / (number_of_values - 1); - for (int i1 = 0; i1 < number_of_values; i1++) { + for (long int i1 = 0; i1 < number_of_values; i1++) { if ((1.0 - t) < 5e-6) t = 1.0; @@ -687,7 +709,7 @@ void Keyframe::ProcessSegment(int Segment, Point p1, Point p2) { float new_x = 0.0f; float new_y = 0.0f; - for (int i = 0; i < npts; i++) { + for (long int i = 0; i < npts; i++) { Coordinate co = segment_coordinates[i]; double basis = Bernstein(npts - 1, i, t); new_x += basis * co.X; @@ -707,9 +729,9 @@ void Keyframe::ProcessSegment(int Segment, Point p1, Point p2) { // Loop through the raw coordinates, and map them correctly to frame numbers. For example, // we can't have duplicate X values, since X represents our frame numbers. - int current_frame = p1.co.X; + long int current_frame = p1.co.X; float current_value = p1.co.Y; - for (int i = 0; i < raw_coordinates.size(); i++) + for (long int i = 0; i < raw_coordinates.size(); i++) { // Get the raw coordinate Coordinate raw = raw_coordinates[i]; @@ -720,8 +742,8 @@ void Keyframe::ProcessSegment(int Segment, Point p1, Point p2) { else { // Missing X values (use last known Y values) - int number_of_missing = round(raw.X) - current_frame; - for (int missing = 0; missing < number_of_missing; missing++) + long int number_of_missing = round(raw.X) - current_frame; + for (long int missing = 0; missing < number_of_missing; missing++) { // Add new value to the vector Coordinate new_coord(current_frame, current_value); @@ -756,7 +778,7 @@ void Keyframe::ProcessSegment(int Segment, Point p1, Point p2) { number_of_values++; // Add each increment to the values vector - for (int x = 0; x < number_of_values; x++) { + for (long int x = 0; x < number_of_values; x++) { if (x < (number_of_values - 1)) { // Not the last value of this segment // add coordinate to "values" @@ -783,13 +805,13 @@ void Keyframe::CreateFactorialTable() { } // Get a factorial for a coordinate -double Keyframe::Factorial(int n) { +double Keyframe::Factorial(long int n) { assert(n >= 0 && n <= 3); return FactorialLookup[n]; /* returns the value n! as a SUMORealing point number */ } // Calculate the factorial function for Bernstein basis -double Keyframe::Ni(int n, int i) { +double Keyframe::Ni(long int n, long int i) { double ni; double a1 = Factorial(n); double a2 = Factorial(i); @@ -799,7 +821,7 @@ double Keyframe::Ni(int n, int i) { } // Calculate Bernstein basis -double Keyframe::Bernstein(int n, int i, double t) { +double Keyframe::Bernstein(long int n, long int i, double t) { double basis; double ti; /* t^i */ double tni; /* (1 - t)^i */ @@ -825,7 +847,7 @@ double Keyframe::Bernstein(int n, int i, double t) { void Keyframe::ScalePoints(float scale) { // Loop through each point (skipping the 1st point) - for (int point_index = 0; point_index < Points.size(); point_index++) { + for (long int point_index = 0; point_index < Points.size(); point_index++) { // Skip the 1st point if (point_index == 0) continue; @@ -843,7 +865,7 @@ void Keyframe::FlipPoints() { // Loop through each point vector FlippedPoints; - for (int point_index = 0, reverse_index = Points.size() - 1; point_index < Points.size(); point_index++, reverse_index--) { + for (long int point_index = 0, reverse_index = Points.size() - 1; point_index < Points.size(); point_index++, reverse_index--) { // Flip the points Point p = Points[point_index]; p.co.Y = Points[reverse_index].co.Y; diff --git a/src/QtImageReader.cpp b/src/QtImageReader.cpp index c274ab28..4fd13ddd 100644 --- a/src/QtImageReader.cpp +++ b/src/QtImageReader.cpp @@ -102,7 +102,7 @@ void QtImageReader::Close() } // Get an openshot::Frame object for a specific frame number of this reader. -tr1::shared_ptr QtImageReader::GetFrame(int requested_frame) throw(ReaderClosed) +tr1::shared_ptr QtImageReader::GetFrame(long int requested_frame) throw(ReaderClosed) { // Check for open reader (or throw exception) if (!is_open) diff --git a/src/TextReader.cpp b/src/TextReader.cpp index 414be660..7791ddf7 100644 --- a/src/TextReader.cpp +++ b/src/TextReader.cpp @@ -143,7 +143,7 @@ void TextReader::Close() } // Get an openshot::Frame object for a specific frame number of this reader. -tr1::shared_ptr TextReader::GetFrame(int requested_frame) throw(ReaderClosed) +tr1::shared_ptr TextReader::GetFrame(long int requested_frame) throw(ReaderClosed) { if (image) { diff --git a/src/Timeline.cpp b/src/Timeline.cpp index 8f69d4ef..81b85964 100644 --- a/src/Timeline.cpp +++ b/src/Timeline.cpp @@ -140,7 +140,7 @@ void Timeline::ApplyMapperToClips() } // Calculate time of a frame number, based on a framerate -float Timeline::calculate_time(int number, Fraction rate) +float Timeline::calculate_time(long int number, Fraction rate) { // Get float version of fps fraction float raw_fps = rate.ToFloat(); @@ -150,7 +150,7 @@ float Timeline::calculate_time(int number, Fraction rate) } // Apply effects to the source frame (if any) -tr1::shared_ptr Timeline::apply_effects(tr1::shared_ptr frame, int timeline_frame_number, int layer) +tr1::shared_ptr Timeline::apply_effects(tr1::shared_ptr frame, long int timeline_frame_number, int layer) { // Calculate time of frame float requested_time = calculate_time(timeline_frame_number, info.fps); @@ -193,14 +193,14 @@ tr1::shared_ptr Timeline::apply_effects(tr1::shared_ptr frame, int } // Process a new layer of video or audio -void Timeline::add_layer(tr1::shared_ptr new_frame, Clip* source_clip, int clip_frame_number, int timeline_frame_number, bool is_top_clip) +void Timeline::add_layer(tr1::shared_ptr new_frame, Clip* source_clip, long int clip_frame_number, long int timeline_frame_number, bool is_top_clip) { // Get the clip's frame & image tr1::shared_ptr source_frame; - //#pragma omp ordered + #pragma omp ordered source_frame = tr1::shared_ptr(source_clip->GetFrame(clip_frame_number)); // No frame found... so bail @@ -551,7 +551,7 @@ bool Timeline::isEqual(double a, double b) } // Get an openshot::Frame object for a specific frame number of this reader. -tr1::shared_ptr Timeline::GetFrame(int requested_frame) throw(ReaderClosed, OutOfBoundsFrame) +tr1::shared_ptr Timeline::GetFrame(long int requested_frame) throw(ReaderClosed, OutOfBoundsFrame) { // Check for open reader (or throw exception) if (!is_open) @@ -605,8 +605,8 @@ tr1::shared_ptr Timeline::GetFrame(int requested_frame) throw(ReaderClose #pragma omp parallel { // Loop through all requested frames - #pragma omp for firstprivate(nearby_clips, requested_frame, minimum_frames) - for (int frame_number = requested_frame; frame_number < requested_frame + minimum_frames; frame_number++) + #pragma omp for ordered firstprivate(nearby_clips, requested_frame, minimum_frames) + for (long int frame_number = requested_frame; frame_number < requested_frame + minimum_frames; frame_number++) { // Debug output AppendDebugMethod("Timeline::GetFrame (processing frame)", "frame_number", frame_number, "omp_get_thread_num()", omp_get_thread_num(), "", -1, "", -1, "", -1, "", -1); @@ -695,7 +695,7 @@ tr1::shared_ptr Timeline::GetFrame(int requested_frame) throw(ReaderClose // Find intersecting clips (or non intersecting clips) -vector Timeline::find_intersecting_clips(int requested_frame, int number_of_frames, bool include) +vector Timeline::find_intersecting_clips(long int requested_frame, int number_of_frames, bool include) { // Find matching clips vector matching_clips; diff --git a/src/effects/Brightness.cpp b/src/effects/Brightness.cpp index a60d67b7..59526e04 100644 --- a/src/effects/Brightness.cpp +++ b/src/effects/Brightness.cpp @@ -75,7 +75,7 @@ int Brightness::constrain(int color_value) // This method is required for all derived classes of EffectBase, and returns a // modified openshot::Frame object -tr1::shared_ptr Brightness::GetFrame(tr1::shared_ptr frame, int frame_number) +tr1::shared_ptr Brightness::GetFrame(tr1::shared_ptr frame, long int frame_number) { // Get the frame's image tr1::shared_ptr frame_image = frame->GetImage(); @@ -174,7 +174,7 @@ void Brightness::SetJsonValue(Json::Value root) { } // Get all properties for a specific frame -string Brightness::PropertiesJSON(int requested_frame) { +string Brightness::PropertiesJSON(long int requested_frame) { // Requested Point Point requested_point(requested_frame, requested_frame); diff --git a/src/effects/ChromaKey.cpp b/src/effects/ChromaKey.cpp index 82867558..f1dcace9 100644 --- a/src/effects/ChromaKey.cpp +++ b/src/effects/ChromaKey.cpp @@ -63,7 +63,7 @@ void ChromaKey::init_effect_details() // This method is required for all derived classes of EffectBase, and returns a // modified openshot::Frame object -tr1::shared_ptr ChromaKey::GetFrame(tr1::shared_ptr frame, int frame_number) +tr1::shared_ptr ChromaKey::GetFrame(tr1::shared_ptr frame, long int frame_number) { // Determine the current HSL (Hue, Saturation, Lightness) for the Chrome int threshold = fuzz.GetInt(frame_number); @@ -154,7 +154,7 @@ void ChromaKey::SetJsonValue(Json::Value root) { } // Get all properties for a specific frame -string ChromaKey::PropertiesJSON(int requested_frame) { +string ChromaKey::PropertiesJSON(long int requested_frame) { // Requested Point Point requested_point(requested_frame, requested_frame); diff --git a/src/effects/Deinterlace.cpp b/src/effects/Deinterlace.cpp index 1f02175a..df3ff5d4 100644 --- a/src/effects/Deinterlace.cpp +++ b/src/effects/Deinterlace.cpp @@ -59,7 +59,7 @@ void Deinterlace::init_effect_details() // This method is required for all derived classes of EffectBase, and returns a // modified openshot::Frame object -tr1::shared_ptr Deinterlace::GetFrame(tr1::shared_ptr frame, int frame_number) +tr1::shared_ptr Deinterlace::GetFrame(tr1::shared_ptr frame, long int frame_number) { // Get original size of frame's image int original_width = frame->GetImage()->width(); @@ -146,7 +146,7 @@ void Deinterlace::SetJsonValue(Json::Value root) { } // Get all properties for a specific frame -string Deinterlace::PropertiesJSON(int requested_frame) { +string Deinterlace::PropertiesJSON(long int requested_frame) { // Requested Point Point requested_point(requested_frame, requested_frame); diff --git a/src/effects/Mask.cpp b/src/effects/Mask.cpp index 57616778..8389eadd 100644 --- a/src/effects/Mask.cpp +++ b/src/effects/Mask.cpp @@ -110,7 +110,7 @@ tr1::shared_ptr Mask::get_grayscale_mask(tr1::shared_ptr mask_fr // This method is required for all derived classes of EffectBase, and returns a // modified openshot::Frame object -tr1::shared_ptr Mask::GetFrame(tr1::shared_ptr frame, int frame_number) +tr1::shared_ptr Mask::GetFrame(tr1::shared_ptr frame, long int frame_number) { // Get the mask image (from the mask reader) tr1::shared_ptr frame_image = frame->GetImage(); @@ -265,7 +265,7 @@ void Mask::SetJsonValue(Json::Value root) { } // Get all properties for a specific frame -string Mask::PropertiesJSON(int requested_frame) { +string Mask::PropertiesJSON(long int requested_frame) { // Requested Point Point requested_point(requested_frame, requested_frame); diff --git a/src/effects/Negate.cpp b/src/effects/Negate.cpp index ddf58c06..5a5039ea 100644 --- a/src/effects/Negate.cpp +++ b/src/effects/Negate.cpp @@ -45,7 +45,7 @@ Negate::Negate() // This method is required for all derived classes of EffectBase, and returns a // modified openshot::Frame object -tr1::shared_ptr Negate::GetFrame(tr1::shared_ptr frame, int frame_number) +tr1::shared_ptr Negate::GetFrame(tr1::shared_ptr frame, long int frame_number) { // Make a negative of the images pixels frame->GetImage()->invertPixels(); @@ -104,7 +104,7 @@ void Negate::SetJsonValue(Json::Value root) { } // Get all properties for a specific frame -string Negate::PropertiesJSON(int requested_frame) { +string Negate::PropertiesJSON(long int requested_frame) { // Requested Point Point requested_point(requested_frame, requested_frame); diff --git a/src/effects/Saturation.cpp b/src/effects/Saturation.cpp index c094c6ff..ff789d17 100644 --- a/src/effects/Saturation.cpp +++ b/src/effects/Saturation.cpp @@ -73,7 +73,7 @@ int Saturation::constrain(int color_value) // This method is required for all derived classes of EffectBase, and returns a // modified openshot::Frame object -tr1::shared_ptr Saturation::GetFrame(tr1::shared_ptr frame, int frame_number) +tr1::shared_ptr Saturation::GetFrame(tr1::shared_ptr frame, long int frame_number) { // Get the frame's image tr1::shared_ptr frame_image = frame->GetImage(); @@ -173,7 +173,7 @@ void Saturation::SetJsonValue(Json::Value root) { } // Get all properties for a specific frame -string Saturation::PropertiesJSON(int requested_frame) { +string Saturation::PropertiesJSON(long int requested_frame) { // Requested Point Point requested_point(requested_frame, requested_frame); diff --git a/src/examples/Example.cpp b/src/examples/Example.cpp index 3ca3a54f..cfca63ed 100644 --- a/src/examples/Example.cpp +++ b/src/examples/Example.cpp @@ -37,12 +37,80 @@ using namespace tr1; int main(int argc, char* argv[]) { - EffectInfo::Json(); + // Create a reader + Clip clip_video("/home/jonathan/apps/libopenshot-git/src/examples/test.mp4"); + clip_video.Layer(0); + clip_video.Position(0.0); + + Clip clip_overlay("/home/jonathan/apps/libopenshot-git/src/examples/front3.png"); + clip_overlay.Layer(1); + //clip_overlay.Position(0.05); // Delay the overlay by 0.05 seconds + clip_overlay.End(0.5); // Make the duration of the overlay 1/2 second + + // Create a timeline + Timeline t(640, 480, Fraction(30, 1), 44100, 2, LAYOUT_STEREO); + + // Add clips + t.AddClip(&clip_video); + t.AddClip(&clip_overlay); + + // Open Timeline + t.Open(); + + t.GetFrame(2)->Display(); + + + return 0; +// +// FFmpegReader r110("/home/jonathan/Videos/PlaysTV/Team Fortress 2/2015_07_06_22_43_16-ses.mp4"); +// r110.Open(); +//// r110.debug = false; +//// r110.DisplayInfo(); +//// FrameMapper m110(&r110, Fraction(24,1), PULLDOWN_NONE, 48000, 2, LAYOUT_STEREO); +// +// Timeline t110(1280, 720, Fraction(24,1), 48000, 2, LAYOUT_STEREO); +// Clip c110("/home/jonathan/Videos/PlaysTV/Team Fortress 2/2015_07_06_22_43_16-ses.mp4"); +// c110.Position(1.0); +// t110.AddClip(&c110); +// t110.Open(); +// +//// m110.GetFrame(100); +//// m110.GetFrame(85); +//// m110.GetFrame(85); +//// m110.GetFrame(86); +//// m110.GetFrame(86); +//// m110.GetFrame(86); +//// m110.GetFrame(86); +//// m110.GetFrame(87); +//// m110.GetFrame(87); +// +// +// t110.GetFrame(1000); +//// r110.GetFrame(96); +//// r110.GetFrame(97); +//// r110.GetFrame(95); +//// r110.GetFrame(98); +//// r110.GetFrame(100); +//// r110.GetFrame(101); +//// r110.GetFrame(103); +// return 0; + +// for (int y = 600; y < 700; y++) { +// cout << y << endl; +// int random_frame_number = rand() % 1000; +// t110.GetFrame(y); +// } + +// srand (time(NULL)); +// for (int z = 0; z <= 1; z++) +// for (int y = 1000; y < 1300; y++) { +// cout << " --> " << y << endl; +// int random_frame_number = rand() % 1000; +// t110.GetFrame(y); +// } + return 0; -// FFmpegReader r110("/home/jonathan/apps/libopenshot/src/examples/piano-mono.wav"); -// r110.Open(); -// // FrameMapper m110(&r110, Fraction(24,1), PULLDOWN_NONE, 22050, 2, LAYOUT_STEREO); // m110.Open(); // @@ -142,7 +210,7 @@ int main(int argc, char* argv[]) // 147000 frames, 28100 frames //for (int frame = 1; frame <= (r9.info.video_length - 1); frame++) //for (int z = 0; z < 2; z++) - for (int frame = 1; frame <= 700; frame++) + for (long int frame = 1; frame <= 700; frame++) //int frame = 1; //while (true) { diff --git a/tests/Color_Tests.cpp b/tests/Color_Tests.cpp index 4c613d7c..b1976ea8 100644 --- a/tests/Color_Tests.cpp +++ b/tests/Color_Tests.cpp @@ -57,9 +57,9 @@ TEST(Color_Animate_Colors) c1.blue.AddPoint(1000, 65); // Check the color at frame 500 - CHECK_CLOSE(0, c1.red.GetInt(500), 0.01); - CHECK_CLOSE(187, c1.green.GetInt(500), 0.01); - CHECK_CLOSE(160, c1.blue.GetInt(500), 0.01); + CHECK_CLOSE(0, c1.red.GetLong(500), 0.01); + CHECK_CLOSE(187, c1.green.GetLong(500), 0.01); + CHECK_CLOSE(160, c1.blue.GetLong(500), 0.01); } TEST(Color_HEX_Value) diff --git a/tests/KeyFrame_Tests.cpp b/tests/KeyFrame_Tests.cpp index b2d1022b..33ba2bdd 100644 --- a/tests/KeyFrame_Tests.cpp +++ b/tests/KeyFrame_Tests.cpp @@ -211,13 +211,13 @@ TEST(Keyframe_Check_Direction_and_Repeat_Fractions) CHECK_EQUAL(kf.GetRepeatFraction(24).den, 4); CHECK_EQUAL(kf.GetDelta(24), 0); - CHECK_EQUAL(kf.GetInt(390), 101); + CHECK_EQUAL(kf.GetLong(390), 101); CHECK_EQUAL(kf.IsIncreasing(390), false); CHECK_EQUAL(kf.GetRepeatFraction(390).num, 8); CHECK_EQUAL(kf.GetRepeatFraction(390).den, 8); CHECK_EQUAL(kf.GetDelta(390), 0); - CHECK_EQUAL(kf.GetInt(391), 100); + CHECK_EQUAL(kf.GetLong(391), 100); CHECK_EQUAL(kf.IsIncreasing(391), true); CHECK_EQUAL(kf.GetRepeatFraction(391).num, 1); CHECK_EQUAL(kf.GetRepeatFraction(391).den, 12); diff --git a/tests/ReaderBase_Tests.cpp b/tests/ReaderBase_Tests.cpp index 247f083c..6c348fba 100644 --- a/tests/ReaderBase_Tests.cpp +++ b/tests/ReaderBase_Tests.cpp @@ -41,7 +41,7 @@ TEST(ReaderBase_Derived_Class) public: TestReader() { }; Cache* GetCache() { return NULL; }; - tr1::shared_ptr GetFrame(int number) { tr1::shared_ptr f(new Frame()); return f; } + tr1::shared_ptr GetFrame(long int number) { tr1::shared_ptr f(new Frame()); return f; } void Close() { }; void Open() { }; string Json() { };