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();