diff --git a/CMakeLists.txt b/CMakeLists.txt index 2e3a49c3..03c5a761 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -75,6 +75,13 @@ Generating build files for OpenShot SO/API/ABI Version: ${SO_VERSION} ") +#### Work around a GCC < 9 bug with handling of _Pragma() in macros +#### See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=55578 +if ((${CMAKE_CXX_COMPILER_ID} STREQUAL "GNU") AND + (${CMAKE_CXX_COMPILER_VERSION} VERSION_LESS "9.0.0")) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -no-integrated-cpp") +endif() + #### Enable C++11 (for std::shared_ptr support) set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_STANDARD_REQUIRED ON) diff --git a/include/CacheBase.h b/include/CacheBase.h index aaef5320..c764b2d9 100644 --- a/include/CacheBase.h +++ b/include/CacheBase.h @@ -60,6 +60,8 @@ namespace openshot { /// @param max_bytes The maximum bytes to allow in the cache. Once exceeded, the cache will purge the oldest frames. CacheBase(int64_t max_bytes); + virtual ~CacheBase(); + /// @brief Add a Frame to the cache /// @param frame The openshot::Frame object needing to be cached. virtual void Add(std::shared_ptr frame) = 0; diff --git a/include/CacheMemory.h b/include/CacheMemory.h index 2f3f018b..29187799 100644 --- a/include/CacheMemory.h +++ b/include/CacheMemory.h @@ -71,7 +71,7 @@ namespace openshot { CacheMemory(int64_t max_bytes); // Default destructor - ~CacheMemory(); + virtual ~CacheMemory(); /// @brief Add a Frame to the cache /// @param frame The openshot::Frame object needing to be cached. diff --git a/include/Clip.h b/include/Clip.h index 346629e4..58eacab7 100644 --- a/include/Clip.h +++ b/include/Clip.h @@ -112,7 +112,10 @@ namespace openshot { // File Reader object ReaderBase* reader; - bool manage_reader; + + /// If we allocated a reader, we store it here to free it later + /// (reader member variable itself may have been replaced) + ReaderBase* allocated_reader; /// Adjust frame number minimum value int64_t adjust_frame_number_minimum(int64_t frame_number); @@ -160,7 +163,7 @@ namespace openshot { Clip(ReaderBase* new_reader); /// Destructor - ~Clip(); + virtual ~Clip(); /// @brief Add an effect to the clip /// @param effect Add an effect to the clip. An effect can modify the audio or video of an openshot::Frame. diff --git a/include/ClipBase.h b/include/ClipBase.h index 3dae8a53..1c5534fc 100644 --- a/include/ClipBase.h +++ b/include/ClipBase.h @@ -69,6 +69,7 @@ namespace openshot { /// Constructor for the base clip ClipBase() { }; + virtual ~ClipBase(); // Compare a clip using the Position() property bool operator< ( ClipBase& a) { return (Position() < a.Position()); } diff --git a/include/DummyReader.h b/include/DummyReader.h index 559215de..e9bce1b5 100644 --- a/include/DummyReader.h +++ b/include/DummyReader.h @@ -64,6 +64,8 @@ namespace openshot /// Constructor for DummyReader. DummyReader(Fraction fps, int width, int height, int sample_rate, int channels, float duration); + virtual ~DummyReader(); + /// Close File void Close(); diff --git a/include/FFmpegReader.h b/include/FFmpegReader.h index abf1af57..7ef44c50 100644 --- a/include/FFmpegReader.h +++ b/include/FFmpegReader.h @@ -243,7 +243,7 @@ namespace openshot { FFmpegReader(string path, bool inspect_reader); /// Destructor - ~FFmpegReader(); + virtual ~FFmpegReader(); /// Close File void Close(); diff --git a/include/Frame.h b/include/Frame.h index 66d8ccfa..6b682edb 100644 --- a/include/Frame.h +++ b/include/Frame.h @@ -159,7 +159,7 @@ namespace openshot Frame& operator= (const Frame& other); /// Destructor - ~Frame(); + virtual ~Frame(); /// Add (or replace) pixel data to the frame (based on a solid color) void AddColor(int new_width, int new_height, string new_color); @@ -249,6 +249,9 @@ namespace openshot /// Get pixel data (for only a single scan-line) const unsigned char* GetPixels(int row); + /// Check a specific pixel color value (returns True/False) + bool CheckPixel(int row, int col, int red, int green, int blue, int alpha, int threshold); + /// Get height of image int GetHeight(); diff --git a/include/FrameMapper.h b/include/FrameMapper.h index 216fe73f..d046af25 100644 --- a/include/FrameMapper.h +++ b/include/FrameMapper.h @@ -170,7 +170,7 @@ namespace openshot FrameMapper(ReaderBase *reader, Fraction target_fps, PulldownType target_pulldown, int target_sample_rate, int target_channels, ChannelLayout target_channel_layout); /// Destructor - ~FrameMapper(); + virtual ~FrameMapper(); /// Change frame rate or audio mapping details void ChangeMapping(Fraction target_fps, PulldownType pulldown, int target_sample_rate, int target_channels, ChannelLayout target_channel_layout); @@ -213,6 +213,9 @@ namespace openshot /// Get the current reader ReaderBase* Reader(); + /// Set the current reader + void Reader(ReaderBase *new_reader) { reader = new_reader; } + /// Resample audio and map channels (if needed) void ResampleMappedAudio(std::shared_ptr frame, int64_t original_frame_number); diff --git a/include/QtImageReader.h b/include/QtImageReader.h index 6b260f15..d26c9b79 100644 --- a/include/QtImageReader.h +++ b/include/QtImageReader.h @@ -65,9 +65,10 @@ namespace openshot { private: string path; - std::shared_ptr image; ///> Original image (full quality) - std::shared_ptr cached_image; ///> Scaled for performance - bool is_open; + std::shared_ptr image; ///> Original image (full quality) + std::shared_ptr cached_image; ///> Scaled for performance + bool is_open; ///> Is Reader opened + QSize max_size; ///> Current max_size as calculated with Clip properties public: @@ -80,6 +81,8 @@ namespace openshot /// when you are inflating the object using JSON after instantiating it. QtImageReader(string path, bool inspect_reader); + virtual ~QtImageReader(); + /// Close File void Close(); diff --git a/include/ReaderBase.h b/include/ReaderBase.h index b0a1b3db..efbd5bc7 100644 --- a/include/ReaderBase.h +++ b/include/ReaderBase.h @@ -107,6 +107,8 @@ namespace openshot /// Constructor for the base reader, where many things are initialized. ReaderBase(); + virtual ~ReaderBase(); + /// Information about the current media file ReaderInfo info; diff --git a/include/Timeline.h b/include/Timeline.h index 312add2e..11911d40 100644 --- a/include/Timeline.h +++ b/include/Timeline.h @@ -30,6 +30,7 @@ #include #include +#include #include #include #include "CacheBase.h" @@ -152,6 +153,8 @@ namespace openshot { map open_clips; /// effects; /// allocated_frame_mappers; ///< all the frame mappers we allocated and must free + bool managed_cache; ///< Does this timeline instance manage the cache object /// Process a new layer of video or audio void add_layer(std::shared_ptr new_frame, Clip* source_clip, int64_t clip_frame_number, int64_t timeline_frame_number, bool is_top_clip, float max_volume); @@ -205,6 +208,8 @@ namespace openshot { /// @param channel_layout The channel layout (i.e. mono, stereo, 3 point surround, etc...) Timeline(int width, int height, Fraction fps, int sample_rate, int channels, ChannelLayout channel_layout); + virtual ~Timeline(); + /// @brief Add an openshot::Clip to the timeline /// @param clip Add an openshot::Clip to the timeline. A clip can contain any type of Reader. void AddClip(Clip* clip); @@ -237,7 +242,8 @@ namespace openshot { /// Get the cache object used by this reader CacheBase* GetCache() { return final_cache; }; - /// Get the cache object used by this reader + /// Set the cache object used by this reader. You must now manage the lifecycle + /// of this cache object though (Timeline will not delete it for you). void SetCache(CacheBase* new_cache); /// Get an openshot::Frame object for a specific frame number of this timeline. diff --git a/src/CacheBase.cpp b/src/CacheBase.cpp index cffd995d..874674c0 100644 --- a/src/CacheBase.cpp +++ b/src/CacheBase.cpp @@ -42,6 +42,9 @@ CacheBase::CacheBase(int64_t max_bytes) : max_bytes(max_bytes) { cacheCriticalSection = new CriticalSection(); }; +CacheBase::~CacheBase() { +}; + // Set maximum bytes to a different amount based on a ReaderInfo struct void CacheBase::SetMaxBytesFromInfo(int64_t number_of_frames, int width, int height, int sample_rate, int channels) { @@ -69,4 +72,4 @@ void CacheBase::SetJsonValue(Json::Value root) { // Set data from Json (if key is found) if (!root["max_bytes"].isNull()) max_bytes = atoll(root["max_bytes"].asString().c_str()); -} \ No newline at end of file +} diff --git a/src/Clip.cpp b/src/Clip.cpp index 207494e3..2099705d 100644 --- a/src/Clip.cpp +++ b/src/Clip.cpp @@ -101,9 +101,6 @@ void Clip::init_settings() // Init audio and video overrides has_audio = Keyframe(-1.0); has_video = Keyframe(-1.0); - - // Default pointers - manage_reader = false; } // Init reader's rotation (if any) @@ -131,14 +128,14 @@ void Clip::init_reader_rotation() { } // Default Constructor for a clip -Clip::Clip() : reader(NULL), resampler(NULL), audio_cache(NULL) +Clip::Clip() : resampler(NULL), audio_cache(NULL), reader(NULL), allocated_reader(NULL) { // Init all default settings init_settings(); } // Constructor with reader -Clip::Clip(ReaderBase* new_reader) : reader(new_reader), resampler(NULL), audio_cache(NULL) +Clip::Clip(ReaderBase* new_reader) : resampler(NULL), audio_cache(NULL), reader(new_reader), allocated_reader(NULL) { // Init all default settings init_settings(); @@ -152,7 +149,7 @@ Clip::Clip(ReaderBase* new_reader) : reader(new_reader), resampler(NULL), audio_ } // Constructor with filepath -Clip::Clip(string path) : reader(NULL), resampler(NULL), audio_cache(NULL) +Clip::Clip(string path) : resampler(NULL), audio_cache(NULL), reader(NULL), allocated_reader(NULL) { // Init all default settings init_settings(); @@ -194,7 +191,7 @@ Clip::Clip(string path) : reader(NULL), resampler(NULL), audio_cache(NULL) // Update duration if (reader) { End(reader->info.duration); - manage_reader = true; + allocated_reader = reader; init_reader_rotation(); } } @@ -203,9 +200,9 @@ Clip::Clip(string path) : reader(NULL), resampler(NULL), audio_cache(NULL) Clip::~Clip() { // Delete the reader if clip created it - if (manage_reader && reader) { - delete reader; - reader = NULL; + if (allocated_reader) { + delete allocated_reader; + allocated_reader = NULL; } // Close the resampler @@ -968,7 +965,7 @@ void Clip::SetJsonValue(Json::Value root) { // mark as managed reader and set parent if (reader) { reader->SetClip(this); - manage_reader = true; + allocated_reader = reader; } // Re-Open reader (if needed) diff --git a/src/ClipBase.cpp b/src/ClipBase.cpp index 80cad87d..b2926244 100644 --- a/src/ClipBase.cpp +++ b/src/ClipBase.cpp @@ -29,6 +29,9 @@ using namespace openshot; +ClipBase::~ClipBase() { +} + // Generate Json::JsonValue for this object Json::Value ClipBase::JsonValue() { @@ -108,4 +111,4 @@ Json::Value ClipBase::add_property_choice_json(string name, int value, int selec // return JsonValue return new_choice; -} \ No newline at end of file +} diff --git a/src/DummyReader.cpp b/src/DummyReader.cpp index 8fe039ab..dc77db5b 100644 --- a/src/DummyReader.cpp +++ b/src/DummyReader.cpp @@ -71,6 +71,9 @@ DummyReader::DummyReader(Fraction fps, int width, int height, int sample_rate, i Close(); } +DummyReader::~DummyReader() { +} + // Open image file void DummyReader::Open() { diff --git a/src/FFmpegReader.cpp b/src/FFmpegReader.cpp index acd3b55f..6aa0938e 100644 --- a/src/FFmpegReader.cpp +++ b/src/FFmpegReader.cpp @@ -576,6 +576,12 @@ void FFmpegReader::Close() { ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::Close", "", -1, "", -1, "", -1, "", -1, "", -1, "", -1); + if (packet) { + // Remove previous packet before getting next one + RemoveAVPacket(packet); + packet = NULL; + } + // Close the codec if (info.has_video) { avcodec_flush_buffers(pCodecCtx); @@ -624,6 +630,8 @@ void FFmpegReader::Close() { seek_video_frame_found = 0; current_video_frame = 0; has_missing_frames = false; + + last_video_frame.reset(); } } @@ -1028,6 +1036,8 @@ int FFmpegReader::GetNextPacket() { // Update current packet pointer packet = next_packet; } + else + delete next_packet; } // Return if packet was found (or error number) return found_packet; @@ -1063,7 +1073,7 @@ bool FFmpegReader::GetAVFrame() { { next_frame2 = next_frame; } - pFrame = new AVFrame(); + pFrame = AV_ALLOCATE_FRAME(); while (ret >= 0) { ret = avcodec_receive_frame(pCodecCtx, next_frame2); if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) { @@ -1110,11 +1120,13 @@ bool FFmpegReader::GetAVFrame() { #else avcodec_decode_video2(pCodecCtx, next_frame, &frameFinished, packet); + // always allocate pFrame (because we do that in the ffmpeg >= 3.2 as well); it will always be freed later + pFrame = AV_ALLOCATE_FRAME(); + // is frame finished if (frameFinished) { // AVFrames are clobbered on the each call to avcodec_decode_video, so we // must make a copy of the image data before this method is called again. - pFrame = AV_ALLOCATE_FRAME(); avpicture_alloc((AVPicture *) pFrame, pCodecCtx->pix_fmt, info.width, info.height); av_picture_copy((AVPicture *) pFrame, (AVPicture *) next_frame, pCodecCtx->pix_fmt, info.width, info.height); @@ -1206,6 +1218,7 @@ void FFmpegReader::ProcessVideoPacket(int64_t requested_frame) { int width = info.width; int64_t video_length = info.video_length; AVFrame *my_frame = pFrame; + pFrame = NULL; // Add video frame to list of processing video frames const GenericScopedLock lock(processingCriticalSection); diff --git a/src/FFmpegWriter.cpp b/src/FFmpegWriter.cpp index 072ac6d7..ddcd4e16 100644 --- a/src/FFmpegWriter.cpp +++ b/src/FFmpegWriter.cpp @@ -884,9 +884,8 @@ void FFmpegWriter::flush_encoders() { } // Close the video codec -void FFmpegWriter::close_video(AVFormatContext *oc, AVStream *st) { - AV_FREE_CONTEXT(video_codec); - video_codec = NULL; +void FFmpegWriter::close_video(AVFormatContext *oc, AVStream *st) +{ #if IS_FFMPEG_3_2 // #if defined(__linux__) if (hw_en_on && hw_en_supported) { @@ -900,10 +899,8 @@ void FFmpegWriter::close_video(AVFormatContext *oc, AVStream *st) { } // Close the audio codec -void FFmpegWriter::close_audio(AVFormatContext *oc, AVStream *st) { - AV_FREE_CONTEXT(audio_codec); - audio_codec = NULL; - +void FFmpegWriter::close_audio(AVFormatContext *oc, AVStream *st) +{ // Clear buffers delete[] samples; delete[] audio_outbuf; @@ -942,12 +939,6 @@ void FFmpegWriter::Close() { if (image_rescalers.size() > 0) RemoveScalers(); - // Free the streams - for (int i = 0; i < oc->nb_streams; i++) { - av_freep(AV_GET_CODEC_ATTRIBUTES(&oc->streams[i], &oc->streams[i])); - av_freep(&oc->streams[i]); - } - if (!(fmt->flags & AVFMT_NOFILE)) { /* close the output file */ avio_close(oc->pb); @@ -957,8 +948,9 @@ void FFmpegWriter::Close() { write_video_count = 0; write_audio_count = 0; - // Free the context - av_freep(&oc); + // Free the context which frees the streams too + avformat_free_context(oc); + oc = NULL; // Close writer is_open = false; diff --git a/src/Frame.cpp b/src/Frame.cpp index 24b653a9..aa7c0d87 100644 --- a/src/Frame.cpp +++ b/src/Frame.cpp @@ -120,7 +120,7 @@ void Frame::DeepCopy(const Frame& other) wave_image = std::shared_ptr(new QImage(*(other.wave_image))); } -// Descructor +// Destructor Frame::~Frame() { // Clear all pointers image.reset(); @@ -480,6 +480,28 @@ const unsigned char* Frame::GetPixels(int row) return image->scanLine(row); } +// Check a specific pixel color value (returns True/False) +bool Frame::CheckPixel(int row, int col, int red, int green, int blue, int alpha, int threshold) { + int col_pos = col * 4; // Find column array position + if (!image || row < 0 || row >= (height - 1) || + col_pos < 0 || col_pos >= (width - 1) ) { + // invalid row / col + return false; + } + // Check pixel color + const unsigned char* pixels = GetPixels(row); + if (pixels[col_pos + 0] >= (red - threshold) && pixels[col_pos + 0] <= (red + threshold) && + pixels[col_pos + 1] >= (green - threshold) && pixels[col_pos + 1] <= (green + threshold) && + pixels[col_pos + 2] >= (blue - threshold) && pixels[col_pos + 2] <= (blue + threshold) && + pixels[col_pos + 3] >= (alpha - threshold) && pixels[col_pos + 3] <= (alpha + threshold)) { + // Pixel color matches successfully + return true; + } else { + // Pixel color does not match + return false; + } +} + // Set Pixel Aspect Ratio void Frame::SetPixelRatio(int num, int den) { diff --git a/src/FrameMapper.cpp b/src/FrameMapper.cpp index 73b7bb22..113171a2 100644 --- a/src/FrameMapper.cpp +++ b/src/FrameMapper.cpp @@ -61,6 +61,8 @@ FrameMapper::~FrameMapper() { if (is_open) // Auto Close if not already Close(); + + reader = NULL; } /// Get the current reader @@ -649,6 +651,16 @@ void FrameMapper::Close() // Close internal reader reader->Close(); + // Clear the fields & frames lists + fields.clear(); + frames.clear(); + + // Mark as dirty + is_dirty = true; + + // Clear cache + final_cache.Clear(); + // Deallocate resample buffer if (avr) { SWR_CLOSE(avr); diff --git a/src/QtImageReader.cpp b/src/QtImageReader.cpp index c500d221..502ddb9a 100644 --- a/src/QtImageReader.cpp +++ b/src/QtImageReader.cpp @@ -57,6 +57,10 @@ QtImageReader::QtImageReader(string path, bool inspect_reader) : path(path), is_ } } +QtImageReader::~QtImageReader() +{ +} + // Open image file void QtImageReader::Open() { @@ -130,6 +134,10 @@ void QtImageReader::Open() info.display_ratio.num = size.num; info.display_ratio.den = size.den; + // Set current max size + max_size.setWidth(info.width); + max_size.setHeight(info.height); + // Mark as "open" is_open = true; } @@ -143,7 +151,7 @@ void QtImageReader::Close() { // Mark as "closed" is_open = false; - + // Delete the image image.reset(); @@ -209,8 +217,7 @@ std::shared_ptr QtImageReader::GetFrame(int64_t requested_frame) } // Scale image smaller (or use a previous scaled image) - if (!cached_image || (cached_image && cached_image->width() != max_width || cached_image->height() != max_height)) { - + if (!cached_image || (cached_image && max_size.width() != max_width || max_size.height() != max_height)) { #if USE_RESVG == 1 // If defined and found in CMake, utilize the libresvg for parsing // SVG files and rasterizing them to QImages. @@ -239,6 +246,10 @@ std::shared_ptr QtImageReader::GetFrame(int64_t requested_frame) cached_image = std::shared_ptr(new QImage(image->scaled(max_width, max_height, Qt::KeepAspectRatio, Qt::SmoothTransformation))); cached_image = std::shared_ptr(new QImage(cached_image->convertToFormat(QImage::Format_RGBA8888))); #endif + + // Set max size (to later determine if max_size is changed) + max_size.setWidth(max_width); + max_size.setHeight(max_height); } // Create or get frame object diff --git a/src/ReaderBase.cpp b/src/ReaderBase.cpp index f2607cfd..3b1bb76f 100644 --- a/src/ReaderBase.cpp +++ b/src/ReaderBase.cpp @@ -63,6 +63,9 @@ ReaderBase::ReaderBase() parent = NULL; } +ReaderBase::~ReaderBase() { +} + // Display file information void ReaderBase::DisplayInfo() { cout << fixed << setprecision(2) << boolalpha; diff --git a/src/Timeline.cpp b/src/Timeline.cpp index b229a3de..37d3f71c 100644 --- a/src/Timeline.cpp +++ b/src/Timeline.cpp @@ -31,7 +31,7 @@ using namespace openshot; // Default Constructor for the timeline (which sets the canvas width and height) Timeline::Timeline(int width, int height, Fraction fps, int sample_rate, int channels, ChannelLayout channel_layout) : - is_open(false), auto_map_clips(true) + is_open(false), auto_map_clips(true), managed_cache(true) { // Create CrashHandler and Attach (incase of errors) CrashHandler::Instance(); @@ -70,6 +70,29 @@ Timeline::Timeline(int width, int height, Fraction fps, int sample_rate, int cha final_cache->SetMaxBytesFromInfo(OPEN_MP_NUM_PROCESSORS * 2, info.width, info.height, info.sample_rate, info.channels); } +Timeline::~Timeline() { + if (is_open) + // Auto Close if not already + Close(); + + // Free all allocated frame mappers + set::iterator frame_mapper_itr; + for (frame_mapper_itr = allocated_frame_mappers.begin(); frame_mapper_itr != allocated_frame_mappers.end(); ++frame_mapper_itr) { + // Get frame mapper object from the iterator + FrameMapper *frame_mapper = (*frame_mapper_itr); + frame_mapper->Reader(NULL); + frame_mapper->Close(); + delete frame_mapper; + } + allocated_frame_mappers.clear(); + + // Destroy previous cache (if managed by timeline) + if (managed_cache && final_cache) { + delete final_cache; + final_cache = NULL; + } +} + // Add an openshot::Clip to the timeline void Timeline::AddClip(Clip* clip) { @@ -123,7 +146,9 @@ void Timeline::apply_mapper_to_clip(Clip* clip) } else { // Create a new FrameMapper to wrap the current reader - clip_reader = (ReaderBase*) new FrameMapper(clip->Reader(), info.fps, PULLDOWN_NONE, info.sample_rate, info.channels, info.channel_layout); + FrameMapper* mapper = new FrameMapper(clip->Reader(), info.fps, PULLDOWN_NONE, info.sample_rate, info.channels, info.channel_layout); + allocated_frame_mappers.insert(mapper); + clip_reader = (ReaderBase*) mapper; } // Update the mapping @@ -898,8 +923,15 @@ vector Timeline::find_intersecting_clips(int64_t requested_frame, int num return matching_clips; } -// Get the cache object used by this reader +// Set the cache object used by this reader void Timeline::SetCache(CacheBase* new_cache) { + // Destroy previous cache (if managed by timeline) + if (managed_cache && final_cache) { + delete final_cache; + final_cache = NULL; + managed_cache = false; + } + // Set new cache final_cache = new_cache; } @@ -1481,4 +1513,4 @@ void Timeline::SetMaxSize(int width, int height) { // Set max size Settings::Instance()->MAX_WIDTH = display_ratio_size.width(); Settings::Instance()->MAX_HEIGHT = display_ratio_size.height(); -} \ No newline at end of file +} diff --git a/src/examples/Example.cpp b/src/examples/Example.cpp index 80339684..1e19f4d9 100644 --- a/src/examples/Example.cpp +++ b/src/examples/Example.cpp @@ -38,7 +38,7 @@ int main(int argc, char* argv[]) { Settings *s = Settings::Instance(); s->HARDWARE_DECODER = 2; // 1 VA-API, 2 NVDEC - s->HW_DE_DEVICE_SET = 1; + s->HW_DE_DEVICE_SET = 0; FFmpegReader r9("/home/jonathan/Videos/sintel_trailer-720p.mp4"); r9.Open(); diff --git a/tests/FFmpegReader_Tests.cpp b/tests/FFmpegReader_Tests.cpp index 53563cac..462a77c3 100644 --- a/tests/FFmpegReader_Tests.cpp +++ b/tests/FFmpegReader_Tests.cpp @@ -100,6 +100,10 @@ TEST(FFmpegReader_Check_Video_File) CHECK_EQUAL(0, (int)pixels[pixel_index + 2]); CHECK_EQUAL(255, (int)pixels[pixel_index + 3]); + // Check pixel function + CHECK_EQUAL(true, f->CheckPixel(10, 112, 21, 191, 0, 255, 5)); + CHECK_EQUAL(false, f->CheckPixel(10, 112, 0, 0, 0, 0, 5)); + // Get frame 1 f = r.GetFrame(2); @@ -113,6 +117,10 @@ TEST(FFmpegReader_Check_Video_File) CHECK_EQUAL(188, (int)pixels[pixel_index + 2]); CHECK_EQUAL(255, (int)pixels[pixel_index + 3]); + // Check pixel function + CHECK_EQUAL(true, f->CheckPixel(10, 112, 0, 96, 188, 255, 5)); + CHECK_EQUAL(false, f->CheckPixel(10, 112, 0, 0, 0, 0, 5)); + // Close reader r.Close(); } diff --git a/tests/Timeline_Tests.cpp b/tests/Timeline_Tests.cpp index 8c81579c..22f33894 100644 --- a/tests/Timeline_Tests.cpp +++ b/tests/Timeline_Tests.cpp @@ -243,7 +243,6 @@ TEST(Timeline_Clip_Order) clip_middle1.Position(0.5); t.AddClip(&clip_middle1); - // Loop through clips again, and re-check order counter = 0; clips = t.Clips();