From f63c1e0a65c6d1031cd1a55e0dde1a75fd21830d Mon Sep 17 00:00:00 2001
From: eisneinechse <42617957+eisneinechse@users.noreply.github.com>
Date: Sun, 16 Feb 2020 10:00:18 -0800
Subject: [PATCH 01/26] Newer codecs
---
src/FFmpegWriter.cpp | 46 ++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 44 insertions(+), 2 deletions(-)
diff --git a/src/FFmpegWriter.cpp b/src/FFmpegWriter.cpp
index 8d060d77..dec430d1 100644
--- a/src/FFmpegWriter.cpp
+++ b/src/FFmpegWriter.cpp
@@ -255,7 +255,7 @@ void FFmpegWriter::SetVideoOptions(bool has_video, std::string codec, Fraction f
}
if (bit_rate >= 1000) // bit_rate is the bitrate in b/s
info.video_bit_rate = bit_rate;
- if ((bit_rate >= 0) && (bit_rate < 64)) // bit_rate is the bitrate in crf
+ if ((bit_rate >= 0) && (bit_rate < 256)) // bit_rate is the bitrate in crf
info.video_bit_rate = bit_rate;
info.interlaced_frame = interlaced;
@@ -341,7 +341,7 @@ void FFmpegWriter::SetOption(StreamType stream, std::string name, std::string va
// Was option found?
if (option || (name == "g" || name == "qmin" || name == "qmax" || name == "max_b_frames" || name == "mb_decision" ||
name == "level" || name == "profile" || name == "slices" || name == "rc_min_rate" || name == "rc_max_rate" ||
- name == "rc_buffer_size" || name == "crf" || name == "cqp")) {
+ name == "rc_buffer_size" || name == "crf" || name == "cqp" || name == "qp")) {
// Check for specific named options
if (name == "g")
// Set gop_size
@@ -462,6 +462,18 @@ void FFmpegWriter::SetOption(StreamType stream, std::string name, std::string va
case AV_CODEC_ID_AV1 :
c->bit_rate = 0;
av_opt_set_int(c->priv_data, "crf", std::min(std::stoi(value),63), 0);
+ if (strstr(info.vcodec.c_str(), "svt_av1") != NULL) {
+ //av_opt_set_int(c->priv_data, "qp", std::min(std::stoi(value),63), 0);
+ av_opt_set_int(c->priv_data, "preset", 6, 0);
+ av_opt_set_int(c->priv_data, "forced-idr",1,0);
+ }
+ if (strstr(info.vcodec.c_str(), "rav1e") != NULL) {
+ //av_opt_set_int(c->priv_data, "qp", std::min(std::stoi(value),255), 0);
+ av_opt_set_int(c->priv_data, "speed", 7, 0);
+ av_opt_set_int(c->priv_data, "tile-rows", 2, 0);
+ av_opt_set_int(c->priv_data, "tile-columns", 4, 0);
+ //av_opt_set(c->priv_data, "tile-row", "", 0);
+ }
break;
#endif
case AV_CODEC_ID_VP8 :
@@ -503,6 +515,36 @@ void FFmpegWriter::SetOption(StreamType stream, std::string name, std::string va
c->bit_rate = (int) (mbs);
}
}
+#endif
+ } else if (name == "qp") {
+ // encode quality and special settings like lossless
+ // This might be better in an extra methods as more options
+ // and way to set quality are possible
+#if (LIBAVCODEC_VERSION_MAJOR >= 58)
+ switch (c->codec_id) {
+ case AV_CODEC_ID_AV1 :
+ c->bit_rate = 0;
+ av_opt_set_int(c->priv_data, "qp", std::min(std::stoi(value),63), 0);
+ if (strstr(info.vcodec.c_str(), "svt_av1") != NULL) {
+ av_opt_set_int(c->priv_data, "qp", std::min(std::stoi(value),63), 0);
+ av_opt_set_int(c->priv_data, "preset", 6, 0);
+ av_opt_set_int(c->priv_data, "forced-idr",1,0);
+ }
+ if (strstr(info.vcodec.c_str(), "rav1e") != NULL) {
+ av_opt_set_int(c->priv_data, "qp", std::min(std::stoi(value),255), 0);
+ av_opt_set_int(c->priv_data, "speed", 7, 0);
+ av_opt_set_int(c->priv_data, "tile-rows", 2, 0);
+ av_opt_set_int(c->priv_data, "tile-columns", 4, 0);
+ //av_opt_set(c->priv_data, "tile-row", "", 0);
+ }
+ if (strstr(info.vcodec.c_str(), "aom") != NULL) {
+ // Hack to set tiles; libaom doesn have qp only crf
+ av_opt_set_int(c->priv_data, "crf", std::min(std::stoi(value),63), 0);
+ av_opt_set_int(c->priv_data, "tile-rows", 1, 0); // log2 of number of rows
+ av_opt_set_int(c->priv_data, "tile-columns", 2, 0); // log2 of number of columns
+ }
+ break;
+ }
#endif
} else {
// Set AVOption
From 6711c9c788eea07595b9627fb6e428f841dc557f Mon Sep 17 00:00:00 2001
From: eisneinechse <42617957+eisneinechse@users.noreply.github.com>
Date: Sun, 16 Feb 2020 19:16:45 -0800
Subject: [PATCH 02/26] Minor improvements
---
src/FFmpegWriter.cpp | 22 ++++++++++++----------
1 file changed, 12 insertions(+), 10 deletions(-)
diff --git a/src/FFmpegWriter.cpp b/src/FFmpegWriter.cpp
index dec430d1..b3a0b59c 100644
--- a/src/FFmpegWriter.cpp
+++ b/src/FFmpegWriter.cpp
@@ -463,16 +463,13 @@ void FFmpegWriter::SetOption(StreamType stream, std::string name, std::string va
c->bit_rate = 0;
av_opt_set_int(c->priv_data, "crf", std::min(std::stoi(value),63), 0);
if (strstr(info.vcodec.c_str(), "svt_av1") != NULL) {
- //av_opt_set_int(c->priv_data, "qp", std::min(std::stoi(value),63), 0);
av_opt_set_int(c->priv_data, "preset", 6, 0);
av_opt_set_int(c->priv_data, "forced-idr",1,0);
}
if (strstr(info.vcodec.c_str(), "rav1e") != NULL) {
- //av_opt_set_int(c->priv_data, "qp", std::min(std::stoi(value),255), 0);
av_opt_set_int(c->priv_data, "speed", 7, 0);
av_opt_set_int(c->priv_data, "tile-rows", 2, 0);
av_opt_set_int(c->priv_data, "tile-columns", 4, 0);
- //av_opt_set(c->priv_data, "tile-row", "", 0);
}
break;
#endif
@@ -524,25 +521,30 @@ void FFmpegWriter::SetOption(StreamType stream, std::string name, std::string va
switch (c->codec_id) {
case AV_CODEC_ID_AV1 :
c->bit_rate = 0;
- av_opt_set_int(c->priv_data, "qp", std::min(std::stoi(value),63), 0);
if (strstr(info.vcodec.c_str(), "svt_av1") != NULL) {
av_opt_set_int(c->priv_data, "qp", std::min(std::stoi(value),63), 0);
av_opt_set_int(c->priv_data, "preset", 6, 0);
av_opt_set_int(c->priv_data, "forced-idr",1,0);
}
- if (strstr(info.vcodec.c_str(), "rav1e") != NULL) {
+ else if (strstr(info.vcodec.c_str(), "rav1e") != NULL) {
+ // Set number of tiles to a fixed value
+ // TODO Let user choose number of tiles
av_opt_set_int(c->priv_data, "qp", std::min(std::stoi(value),255), 0);
av_opt_set_int(c->priv_data, "speed", 7, 0);
- av_opt_set_int(c->priv_data, "tile-rows", 2, 0);
- av_opt_set_int(c->priv_data, "tile-columns", 4, 0);
- //av_opt_set(c->priv_data, "tile-row", "", 0);
+ av_opt_set_int(c->priv_data, "tile-rows", 2, 0); // number of rows
+ av_opt_set_int(c->priv_data, "tile-columns", 4, 0); // number of columns
}
- if (strstr(info.vcodec.c_str(), "aom") != NULL) {
- // Hack to set tiles; libaom doesn have qp only crf
+ else if (strstr(info.vcodec.c_str(), "aom") != NULL) {
+ // Set number of tiles to a fixed value
+ // TODO Let user choose number of tiles
+ // libaom doesn't have qp only crf
av_opt_set_int(c->priv_data, "crf", std::min(std::stoi(value),63), 0);
av_opt_set_int(c->priv_data, "tile-rows", 1, 0); // log2 of number of rows
av_opt_set_int(c->priv_data, "tile-columns", 2, 0); // log2 of number of columns
}
+ else {
+ av_opt_set_int(c->priv_data, "crf", std::min(std::stoi(value),63), 0);
+ }
break;
}
#endif
From e03cd87373faf119057da3914af6dda1d06e9fa2 Mon Sep 17 00:00:00 2001
From: eisneinechse <42617957+eisneinechse@users.noreply.github.com>
Date: Mon, 17 Feb 2020 10:56:00 -0800
Subject: [PATCH 03/26] Initial svt-hevc (h.265) encoder support added
---
src/FFmpegWriter.cpp | 16 +++++++++++++++-
1 file changed, 15 insertions(+), 1 deletion(-)
diff --git a/src/FFmpegWriter.cpp b/src/FFmpegWriter.cpp
index b3a0b59c..beb19534 100644
--- a/src/FFmpegWriter.cpp
+++ b/src/FFmpegWriter.cpp
@@ -492,7 +492,14 @@ void FFmpegWriter::SetOption(StreamType stream, std::string name, std::string va
}
break;
case AV_CODEC_ID_HEVC :
- av_opt_set_int(c->priv_data, "crf", std::min(std::stoi(value), 51), 0); // 0-51
+ if (strstr(info.vcodec.c_str(), "svt_hevc") != NULL) {
+ av_opt_set_int(c->priv_data, "preset", 7, 0);
+ av_opt_set_int(c->priv_data, "forced-idr",1,0);
+ av_opt_set_int(c->priv_data, "qp",std::min(std::stoi(value), 51),0);
+ }
+ else {
+ av_opt_set_int(c->priv_data, "crf", std::min(std::stoi(value), 51), 0); // 0-51
+ }
if (std::stoi(value) == 0) {
av_opt_set(c->priv_data, "preset", "veryslow", 0);
av_opt_set_int(c->priv_data, "lossless", 1, 0);
@@ -545,6 +552,13 @@ void FFmpegWriter::SetOption(StreamType stream, std::string name, std::string va
else {
av_opt_set_int(c->priv_data, "crf", std::min(std::stoi(value),63), 0);
}
+ case AV_CODEC_ID_HEVC :
+ c->bit_rate = 0;
+ if (strstr(info.vcodec.c_str(), "svt_hevc") != NULL) {
+ av_opt_set_int(c->priv_data, "qp", std::min(std::stoi(value),51), 0);
+ av_opt_set_int(c->priv_data, "preset", 7, 0);
+ av_opt_set_int(c->priv_data, "forced-idr",1,0);
+ }
break;
}
#endif
From ddd52460e17f37d7078ee5ac4ae3335301c9ea86 Mon Sep 17 00:00:00 2001
From: eisneinechse <42617957+eisneinechse@users.noreply.github.com>
Date: Sun, 1 Mar 2020 16:59:06 -0800
Subject: [PATCH 04/26] Fix handling of RAWIMAGE under ffmpeg 4
---
src/FFmpegWriter.cpp | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/src/FFmpegWriter.cpp b/src/FFmpegWriter.cpp
index beb19534..cc71e11a 100644
--- a/src/FFmpegWriter.cpp
+++ b/src/FFmpegWriter.cpp
@@ -842,6 +842,9 @@ void FFmpegWriter::flush_encoders() {
#if (LIBAVFORMAT_VERSION_MAJOR < 58)
if (info.has_video && video_codec && AV_GET_CODEC_TYPE(video_st) == AVMEDIA_TYPE_VIDEO && (oc->oformat->flags & AVFMT_RAWPICTURE) && AV_FIND_DECODER_CODEC_ID(video_st) == AV_CODEC_ID_RAWVIDEO)
return;
+#else
+ if (info.has_video && video_codec && AV_GET_CODEC_TYPE(video_st) == AVMEDIA_TYPE_VIDEO && AV_FIND_DECODER_CODEC_ID(video_st) == AV_CODEC_ID_RAWVIDEO)
+ return;
#endif
int error_code = 0;
@@ -1991,10 +1994,14 @@ void FFmpegWriter::process_video_packet(std::shared_ptr frame) {
bool FFmpegWriter::write_video_packet(std::shared_ptr frame, AVFrame *frame_final) {
#if (LIBAVFORMAT_VERSION_MAJOR >= 58)
ZmqLogger::Instance()->AppendDebugMethod("FFmpegWriter::write_video_packet", "frame->number", frame->number, "oc->oformat->flags", oc->oformat->flags);
+
+ if (video_st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO &&
+ video_st->codecpar->codec_id == AV_CODEC_ID_RAWVIDEO) {
#else
ZmqLogger::Instance()->AppendDebugMethod("FFmpegWriter::write_video_packet", "frame->number", frame->number, "oc->oformat->flags & AVFMT_RAWPICTURE", oc->oformat->flags & AVFMT_RAWPICTURE);
if (oc->oformat->flags & AVFMT_RAWPICTURE) {
+#endif
// Raw video case.
AVPacket pkt;
av_init_packet(&pkt);
@@ -2019,7 +2026,6 @@ bool FFmpegWriter::write_video_packet(std::shared_ptr frame, AVFrame *fra
AV_FREE_PACKET(&pkt);
} else
-#endif
{
AVPacket pkt;
From 6476f930bb601cebe7f8470776e7a4f836e46ca6 Mon Sep 17 00:00:00 2001
From: eisneinechse <42617957+eisneinechse@users.noreply.github.com>
Date: Sun, 1 Mar 2020 17:10:39 -0800
Subject: [PATCH 05/26] Simplify fix for RAWVIDEO handling for ffmpeg 4+
---
src/FFmpegWriter.cpp | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/src/FFmpegWriter.cpp b/src/FFmpegWriter.cpp
index cc71e11a..cc4b3d3a 100644
--- a/src/FFmpegWriter.cpp
+++ b/src/FFmpegWriter.cpp
@@ -1995,8 +1995,7 @@ bool FFmpegWriter::write_video_packet(std::shared_ptr frame, AVFrame *fra
#if (LIBAVFORMAT_VERSION_MAJOR >= 58)
ZmqLogger::Instance()->AppendDebugMethod("FFmpegWriter::write_video_packet", "frame->number", frame->number, "oc->oformat->flags", oc->oformat->flags);
- if (video_st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO &&
- video_st->codecpar->codec_id == AV_CODEC_ID_RAWVIDEO) {
+ if (AV_GET_CODEC_TYPE(video_st) == AVMEDIA_TYPE_VIDEO && AV_FIND_DECODER_CODEC_ID(video_st) == AV_CODEC_ID_RAWVIDEO) {
#else
ZmqLogger::Instance()->AppendDebugMethod("FFmpegWriter::write_video_packet", "frame->number", frame->number, "oc->oformat->flags & AVFMT_RAWPICTURE", oc->oformat->flags & AVFMT_RAWPICTURE);
From 2bea436f3ea1a3e35f97af4af908750e2bf236d0 Mon Sep 17 00:00:00 2001
From: Jonathan Thomas
Date: Mon, 13 Apr 2020 16:55:29 -0500
Subject: [PATCH 06/26] Adding keyframable origin point (for shear and
rotation)
---
include/Clip.h | 24 +++++++++++++-----------
src/Clip.cpp | 10 ++++++++++
src/Timeline.cpp | 33 +++++++++++++++------------------
3 files changed, 38 insertions(+), 29 deletions(-)
diff --git a/include/Clip.h b/include/Clip.h
index 68d4622a..488f7efa 100644
--- a/include/Clip.h
+++ b/include/Clip.h
@@ -140,11 +140,11 @@ namespace openshot {
void reverse_buffer(juce::AudioSampleBuffer* buffer);
public:
- openshot::GravityType gravity; ///< The gravity of a clip determines where it snaps to its parent
- openshot::ScaleType scale; ///< The scale determines how a clip should be resized to fit its parent
- openshot::AnchorType anchor; ///< The anchor determines what parent a clip should snap to
- openshot::FrameDisplayType display; ///< The format to display the frame number (if any)
- openshot::VolumeMixType mixing; ///< What strategy should be followed when mixing audio with other clips
+ openshot::GravityType gravity; ///< The gravity of a clip determines where it snaps to its parent
+ openshot::ScaleType scale; ///< The scale determines how a clip should be resized to fit its parent
+ openshot::AnchorType anchor; ///< The anchor determines what parent a clip should snap to
+ openshot::FrameDisplayType display; ///< The format to display the frame number (if any)
+ openshot::VolumeMixType mixing; ///< What strategy should be followed when mixing audio with other clips
/// Default Constructor
Clip();
@@ -208,15 +208,19 @@ namespace openshot {
bool Waveform() { return waveform; } ///< Get the waveform property of this clip
void Waveform(bool value) { waveform = value; } ///< Set the waveform property of this clip
- // Scale and Location curves
+ // Scale, Location, and Alpha curves
openshot::Keyframe scale_x; ///< Curve representing the horizontal scaling in percent (0 to 1)
openshot::Keyframe scale_y; ///< Curve representing the vertical scaling in percent (0 to 1)
openshot::Keyframe location_x; ///< Curve representing the relative X position in percent based on the gravity (-1 to 1)
openshot::Keyframe location_y; ///< Curve representing the relative Y position in percent based on the gravity (-1 to 1)
-
- // Alpha and Rotation curves
openshot::Keyframe alpha; ///< Curve representing the alpha (1 to 0)
+
+ // Rotation and Shear curves (origin point (x,y) is adjustable for both rotation and shear)
openshot::Keyframe rotation; ///< Curve representing the rotation (0 to 360)
+ openshot::Keyframe shear_x; ///< Curve representing X shear angle in degrees (-45.0=left, 45.0=right)
+ openshot::Keyframe shear_y; ///< Curve representing Y shear angle in degrees (-45.0=down, 45.0=up)
+ openshot::Keyframe origin_x; ///< Curve representing X origin point (0.0=0% (left), 1.0=100% (right))
+ openshot::Keyframe origin_y; ///< Curve representing Y origin point (0.0=0% (top), 1.0=100% (bottom))
// Time and Volume curves
openshot::Keyframe time; ///< Curve representing the frames over time to play (used for speed and direction of video)
@@ -232,9 +236,7 @@ namespace openshot {
openshot::Keyframe crop_x; ///< Curve representing X offset in percent (-1.0=-100%, 0.0=0%, 1.0=100%)
openshot::Keyframe crop_y; ///< Curve representing Y offset in percent (-1.0=-100%, 0.0=0%, 1.0=100%)
- // Shear and perspective curves
- openshot::Keyframe shear_x; ///< Curve representing X shear angle in degrees (-45.0=left, 45.0=right)
- openshot::Keyframe shear_y; ///< Curve representing Y shear angle in degrees (-45.0=down, 45.0=up)
+ // Perspective curves
openshot::Keyframe perspective_c1_x; ///< Curves representing X for coordinate 1
openshot::Keyframe perspective_c1_y; ///< Curves representing Y for coordinate 1
openshot::Keyframe perspective_c2_x; ///< Curves representing X for coordinate 2
diff --git a/src/Clip.cpp b/src/Clip.cpp
index 1968bb3b..f4920ccd 100644
--- a/src/Clip.cpp
+++ b/src/Clip.cpp
@@ -89,6 +89,8 @@ void Clip::init_settings()
// Init shear and perspective curves
shear_x = Keyframe(0.0);
shear_y = Keyframe(0.0);
+ origin_x = Keyframe(0.5);
+ origin_y = Keyframe(0.5);
perspective_c1_x = Keyframe(-1.0);
perspective_c1_y = Keyframe(-1.0);
perspective_c2_x = Keyframe(-1.0);
@@ -718,6 +720,8 @@ std::string Clip::PropertiesJSON(int64_t requested_frame) const {
root["shear_x"] = add_property_json("Shear X", shear_x.GetValue(requested_frame), "float", "", &shear_x, -1.0, 1.0, false, requested_frame);
root["shear_y"] = add_property_json("Shear Y", shear_y.GetValue(requested_frame), "float", "", &shear_y, -1.0, 1.0, false, requested_frame);
root["rotation"] = add_property_json("Rotation", rotation.GetValue(requested_frame), "float", "", &rotation, -360, 360, false, requested_frame);
+ root["origin_x"] = add_property_json("Origin X", origin_x.GetValue(requested_frame), "float", "", &origin_x, 0.0, 1.0, false, requested_frame);
+ root["origin_y"] = add_property_json("Origin Y", origin_y.GetValue(requested_frame), "float", "", &origin_y, 0.0, 1.0, false, requested_frame);
root["volume"] = add_property_json("Volume", volume.GetValue(requested_frame), "float", "", &volume, 0.0, 1.0, false, requested_frame);
root["time"] = add_property_json("Time", time.GetValue(requested_frame), "float", "", &time, 0.0, 30 * 60 * 60 * 48, false, requested_frame);
root["channel_filter"] = add_property_json("Channel Filter", channel_filter.GetValue(requested_frame), "int", "", &channel_filter, -1, 10, false, requested_frame);
@@ -774,6 +778,8 @@ Json::Value Clip::JsonValue() const {
root["crop_y"] = crop_y.JsonValue();
root["shear_x"] = shear_x.JsonValue();
root["shear_y"] = shear_y.JsonValue();
+ root["origin_x"] = origin_x.JsonValue();
+ root["origin_y"] = origin_y.JsonValue();
root["channel_filter"] = channel_filter.JsonValue();
root["channel_mapping"] = channel_mapping.JsonValue();
root["has_audio"] = has_audio.JsonValue();
@@ -871,6 +877,10 @@ void Clip::SetJsonValue(const Json::Value root) {
shear_x.SetJsonValue(root["shear_x"]);
if (!root["shear_y"].isNull())
shear_y.SetJsonValue(root["shear_y"]);
+ if (!root["origin_x"].isNull())
+ origin_x.SetJsonValue(root["origin_x"]);
+ if (!root["origin_y"].isNull())
+ origin_y.SetJsonValue(root["origin_y"]);
if (!root["channel_filter"].isNull())
channel_filter.SetJsonValue(root["channel_filter"]);
if (!root["channel_mapping"].isNull())
diff --git a/src/Timeline.cpp b/src/Timeline.cpp
index 61ce31e3..079d2346 100644
--- a/src/Timeline.cpp
+++ b/src/Timeline.cpp
@@ -677,6 +677,8 @@ void Timeline::add_layer(std::shared_ptr new_frame, Clip* source_clip, in
y += (Settings::Instance()->MAX_HEIGHT * source_clip->location_y.GetValue(clip_frame_number)); // move in percentage of final height
float shear_x = source_clip->shear_x.GetValue(clip_frame_number);
float shear_y = source_clip->shear_y.GetValue(clip_frame_number);
+ float origin_x = source_clip->origin_x.GetValue(clip_frame_number);
+ float origin_y = source_clip->origin_y.GetValue(clip_frame_number);
bool transformed = false;
QTransform transform;
@@ -684,21 +686,22 @@ void Timeline::add_layer(std::shared_ptr new_frame, Clip* source_clip, in
// Transform source image (if needed)
ZmqLogger::Instance()->AppendDebugMethod("Timeline::add_layer (Build QTransform - if needed)", "source_frame->number", source_frame->number, "x", x, "y", y, "r", r, "sx", sx, "sy", sy);
- if (!isEqual(r, 0)) {
- // ROTATE CLIP
- float origin_x = x + (scaled_source_width / 2.0);
- float origin_y = y + (scaled_source_height / 2.0);
- transform.translate(origin_x, origin_y);
- transform.rotate(r);
- transform.translate(-origin_x,-origin_y);
+ if (!isEqual(x, 0) || !isEqual(y, 0)) {
+ // TRANSLATE/MOVE CLIP
+ transform.translate(x, y);
transformed = true;
}
- if (!isEqual(x, 0) || !isEqual(y, 0)) {
- // TRANSLATE/MOVE CLIP
- transform.translate(x, y);
- transformed = true;
- }
+ if (!isEqual(r, 0) || !isEqual(shear_x, 0) || !isEqual(shear_y, 0)) {
+ // ROTATE CLIP (around origin_x, origin_y)
+ float origin_x_value = (scaled_source_width * origin_x);
+ float origin_y_value = (scaled_source_height * origin_y);
+ transform.translate(origin_x_value, origin_y_value);
+ transform.rotate(r);
+ transform.shear(shear_x, shear_y);
+ transform.translate(-origin_x_value,-origin_y_value);
+ transformed = true;
+ }
// SCALE CLIP (if needed)
float source_width_scale = (float(source_size.width()) / float(source_image->width())) * sx;
@@ -709,12 +712,6 @@ void Timeline::add_layer(std::shared_ptr new_frame, Clip* source_clip, in
transformed = true;
}
- if (!isEqual(shear_x, 0) || !isEqual(shear_y, 0)) {
- // SHEAR HEIGHT/WIDTH
- transform.shear(shear_x, shear_y);
- transformed = true;
- }
-
// Debug output
ZmqLogger::Instance()->AppendDebugMethod("Timeline::add_layer (Transform: Composite Image Layer: Prepare)", "source_frame->number", source_frame->number, "new_frame->GetImage()->width()", new_frame->GetImage()->width(), "transformed", transformed);
From 6e7ad2316b56f6219e67b83e37ed43b5315544ce Mon Sep 17 00:00:00 2001
From: Frank Dana
Date: Thu, 7 May 2020 18:24:59 -0400
Subject: [PATCH 07/26] Add version.sh script (#500)
---
version.sh | 4 ++++
1 file changed, 4 insertions(+)
create mode 100755 version.sh
diff --git a/version.sh b/version.sh
new file mode 100755
index 00000000..86a664dc
--- /dev/null
+++ b/version.sh
@@ -0,0 +1,4 @@
+#!/bin/sh
+grep 'set.*(.*PROJECT_VERSION_FULL' CMakeLists.txt\
+ |sed -e 's#set(PROJECT_VERSION_FULL.*"\(.*\)\")#\1#;q'
+
From 13290364e7bea54164ab83d973951f2898ad9e23 Mon Sep 17 00:00:00 2001
From: Stefan Strogin
Date: Sat, 16 May 2020 02:33:37 +0300
Subject: [PATCH 08/26] FFmpegUtilities: replace variable definition with
statement expression
It is needed to avoid multiple definitions of AV_GET_CODEC_CONTEXT,
which is considered as an error with '-fno-common' which is default
since gcc-10.
Fixes: #511
---
include/FFmpegUtilities.h | 18 ++++++++----------
1 file changed, 8 insertions(+), 10 deletions(-)
diff --git a/include/FFmpegUtilities.h b/include/FFmpegUtilities.h
index 62d64df1..b4ec951f 100644
--- a/include/FFmpegUtilities.h
+++ b/include/FFmpegUtilities.h
@@ -163,11 +163,10 @@
#define AV_FREE_CONTEXT(av_context) avcodec_free_context(&av_context)
#define AV_GET_CODEC_TYPE(av_stream) av_stream->codecpar->codec_type
#define AV_FIND_DECODER_CODEC_ID(av_stream) av_stream->codecpar->codec_id
- auto AV_GET_CODEC_CONTEXT = [](AVStream* av_stream, AVCodec* av_codec) { \
- AVCodecContext *context = avcodec_alloc_context3(av_codec); \
- avcodec_parameters_to_context(context, av_stream->codecpar); \
- return context; \
- };
+ #define AV_GET_CODEC_CONTEXT(av_stream, av_codec) \
+ ({ AVCodecContext *context = avcodec_alloc_context3(av_codec); \
+ avcodec_parameters_to_context(context, av_stream->codecpar); \
+ context; })
#define AV_GET_CODEC_PAR_CONTEXT(av_stream, av_codec) av_codec;
#define AV_GET_CODEC_FROM_STREAM(av_stream,codec_in)
#define AV_GET_CODEC_ATTRIBUTES(av_stream, av_context) av_stream->codecpar
@@ -199,11 +198,10 @@
#define AV_FREE_CONTEXT(av_context) avcodec_free_context(&av_context)
#define AV_GET_CODEC_TYPE(av_stream) av_stream->codecpar->codec_type
#define AV_FIND_DECODER_CODEC_ID(av_stream) av_stream->codecpar->codec_id
- auto AV_GET_CODEC_CONTEXT = [](AVStream* av_stream, AVCodec* av_codec) { \
- AVCodecContext *context = avcodec_alloc_context3(av_codec); \
- avcodec_parameters_to_context(context, av_stream->codecpar); \
- return context; \
- };
+ #define AV_GET_CODEC_CONTEXT(av_stream, av_codec) \
+ ({ AVCodecContext *context = avcodec_alloc_context3(av_codec); \
+ avcodec_parameters_to_context(context, av_stream->codecpar); \
+ context; })
#define AV_GET_CODEC_PAR_CONTEXT(av_stream, av_codec) av_codec;
#define AV_GET_CODEC_FROM_STREAM(av_stream,codec_in)
#define AV_GET_CODEC_ATTRIBUTES(av_stream, av_context) av_stream->codecpar
From 4e6c1819b0af7e33ac27d22fa02a09ad268f25b1 Mon Sep 17 00:00:00 2001
From: Jeff Shillitto
Date: Sat, 16 May 2020 18:55:34 +1000
Subject: [PATCH 09/26] Set clip in constructor to resolve scale crop issue
---
src/Clip.cpp | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/src/Clip.cpp b/src/Clip.cpp
index 39aad35d..cdb83cdc 100644
--- a/src/Clip.cpp
+++ b/src/Clip.cpp
@@ -150,6 +150,10 @@ Clip::Clip(ReaderBase* new_reader) : resampler(NULL), reader(new_reader), alloca
// Update duration
End(reader->info.duration);
+
+ if (new_reader) {
+ new_reader->SetClip(this);
+ }
}
// Constructor with filepath
From 5b5950c9913501bfe11feacac32e4a0bdc4ce568 Mon Sep 17 00:00:00 2001
From: Jeff Shillitto
Date: Tue, 19 May 2020 19:57:06 +1000
Subject: [PATCH 10/26] use reader instead of new_reader
---
src/Clip.cpp | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/src/Clip.cpp b/src/Clip.cpp
index cdb83cdc..fa1bb7c7 100644
--- a/src/Clip.cpp
+++ b/src/Clip.cpp
@@ -148,11 +148,10 @@ Clip::Clip(ReaderBase* new_reader) : resampler(NULL), reader(new_reader), alloca
Open();
Close();
- // Update duration
- End(reader->info.duration);
-
- if (new_reader) {
- new_reader->SetClip(this);
+ // Update duration and set parent
+ if (reader) {
+ End(reader->info.duration);
+ reader->SetClip(this);
}
}
@@ -206,9 +205,10 @@ Clip::Clip(std::string path) : resampler(NULL), reader(NULL), allocated_reader(N
}
}
- // Update duration
+ // Update duration and set parent
if (reader) {
End(reader->info.duration);
+ reader->SetClip(this);
allocated_reader = reader;
init_reader_rotation();
}
From 216184dbb98308725b3715c5bc6a0f2ceff87ff3 Mon Sep 17 00:00:00 2001
From: "FeRD (Frank Dana)"
Date: Tue, 19 May 2020 06:30:54 -0400
Subject: [PATCH 11/26] Work around Ruby/JUCE isfinite() conflict properly
---
src/bindings/ruby/CMakeLists.txt | 3 +++
1 file changed, 3 insertions(+)
diff --git a/src/bindings/ruby/CMakeLists.txt b/src/bindings/ruby/CMakeLists.txt
index 2faa10fc..18964486 100644
--- a/src/bindings/ruby/CMakeLists.txt
+++ b/src/bindings/ruby/CMakeLists.txt
@@ -72,6 +72,9 @@ endif()
set_property(SOURCE openshot.i PROPERTY CPLUSPLUS ON)
set_property(SOURCE openshot.i PROPERTY SWIG_MODULE_NAME openshot)
+### Unbreak std::isfinite()
+add_compile_definitions(HAVE_ISFINITE=1)
+
### Suppress a ton of warnings in the generated SWIG C++ code
set(SWIG_CXX_FLAGS "-Wno-unused-variable -Wno-unused-function \
-Wno-deprecated-copy -Wno-class-memaccess -Wno-cast-function-type \
From 130829a41231b9ccb24493ab74d898e0d5bee339 Mon Sep 17 00:00:00 2001
From: "FeRD (Frank Dana)"
Date: Tue, 19 May 2020 06:32:35 -0400
Subject: [PATCH 12/26] Deprecated juce::ScopedPointer => std::unique_ptr
---
src/Frame.cpp | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/src/Frame.cpp b/src/Frame.cpp
index 9577a7f9..36e0af08 100644
--- a/src/Frame.cpp
+++ b/src/Frame.cpp
@@ -992,8 +992,8 @@ void Frame::Play()
juce::AudioSourcePlayer audioSourcePlayer;
deviceManager.addAudioCallback (&audioSourcePlayer);
- ScopedPointer my_source;
- my_source = new AudioBufferSource(audio.get());
+ std::unique_ptr my_source;
+ my_source.reset (new AudioBufferSource (audio.get()));
// Create TimeSliceThread for audio buffering
juce::TimeSliceThread my_thread("Audio buffer thread");
@@ -1002,7 +1002,7 @@ void Frame::Play()
my_thread.startThread();
AudioTransportSource transport1;
- transport1.setSource (my_source,
+ transport1.setSource (my_source.get(),
5000, // tells it to buffer this many samples ahead
&my_thread,
(double) sample_rate,
From affd4b248898a2958300a08697919e347d75aee0 Mon Sep 17 00:00:00 2001
From: "FeRD (Frank Dana)"
Date: Tue, 19 May 2020 06:33:30 -0400
Subject: [PATCH 13/26] Add some missing juce:: prefixing
---
include/Qt/AudioPlaybackThread.h | 8 ++++----
src/Frame.cpp | 7 ++++---
2 files changed, 8 insertions(+), 7 deletions(-)
diff --git a/include/Qt/AudioPlaybackThread.h b/include/Qt/AudioPlaybackThread.h
index 348a0f48..9a159448 100644
--- a/include/Qt/AudioPlaybackThread.h
+++ b/include/Qt/AudioPlaybackThread.h
@@ -75,7 +75,7 @@ namespace openshot
static AudioDeviceManagerSingleton * Instance();
/// Public device manager property
- AudioDeviceManager audioDeviceManager;
+ juce::AudioDeviceManager audioDeviceManager;
/// Close audio device
void CloseAudioDevice();
@@ -86,9 +86,9 @@ namespace openshot
*/
class AudioPlaybackThread : juce::Thread
{
- AudioSourcePlayer player;
- AudioTransportSource transport;
- MixerAudioSource mixer;
+ juce::AudioSourcePlayer player;
+ juce::AudioTransportSource transport;
+ juce::MixerAudioSource mixer;
AudioReaderSource *source;
double sampleRate;
int numChannels;
diff --git a/src/Frame.cpp b/src/Frame.cpp
index 36e0af08..ae9f1a4b 100644
--- a/src/Frame.cpp
+++ b/src/Frame.cpp
@@ -829,7 +829,7 @@ void Frame::AddImage(std::shared_ptr new_image, bool only_odd_lines)
if (ret) {
return;
}
-
+
// Get the frame's image
const GenericScopedLock lock(addingImageSection);
#pragma omp critical (AddImage)
@@ -979,7 +979,8 @@ void Frame::Play()
return;
juce::AudioDeviceManager deviceManager;
- String error = deviceManager.initialise (0, /* number of input channels */
+ juce::String error = deviceManager.initialise (
+ 0, /* number of input channels */
2, /* number of output channels */
0, /* no XML settings.. */
true /* select default device on failure */);
@@ -1001,7 +1002,7 @@ void Frame::Play()
// Start thread
my_thread.startThread();
- AudioTransportSource transport1;
+ juce::AudioTransportSource transport1;
transport1.setSource (my_source.get(),
5000, // tells it to buffer this many samples ahead
&my_thread,
From 128bacce708fb01ef9b6a63060b2c1ff29e91bc0 Mon Sep 17 00:00:00 2001
From: "FeRD (Frank Dana)"
Date: Tue, 19 May 2020 07:19:01 -0400
Subject: [PATCH 14/26] Support older CMake
add_compile_definitions() is CMake 3.12+ only.
---
src/bindings/ruby/CMakeLists.txt | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/bindings/ruby/CMakeLists.txt b/src/bindings/ruby/CMakeLists.txt
index 18964486..4d7b922a 100644
--- a/src/bindings/ruby/CMakeLists.txt
+++ b/src/bindings/ruby/CMakeLists.txt
@@ -73,7 +73,7 @@ set_property(SOURCE openshot.i PROPERTY CPLUSPLUS ON)
set_property(SOURCE openshot.i PROPERTY SWIG_MODULE_NAME openshot)
### Unbreak std::isfinite()
-add_compile_definitions(HAVE_ISFINITE=1)
+add_definitions(-DHAVE_ISFINITE=1)
### Suppress a ton of warnings in the generated SWIG C++ code
set(SWIG_CXX_FLAGS "-Wno-unused-variable -Wno-unused-function \
From e4dd72669f4778b92d139b12ef5c8d166934c94e Mon Sep 17 00:00:00 2001
From: Jonathan Thomas
Date: Mon, 1 Jun 2020 13:24:07 -0500
Subject: [PATCH 15/26] Fix FPS setting on FFmpeg 4, which currently is not
setting a valid FPS.
---
src/FFmpegWriter.cpp | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/src/FFmpegWriter.cpp b/src/FFmpegWriter.cpp
index ce8f6557..cd3185c4 100644
--- a/src/FFmpegWriter.cpp
+++ b/src/FFmpegWriter.cpp
@@ -1222,6 +1222,13 @@ AVStream *FFmpegWriter::add_video_stream() {
st->avg_frame_rate = av_inv_q(c->time_base);
st->time_base.num = info.video_timebase.num;
st->time_base.den = info.video_timebase.den;
+#if (LIBAVFORMAT_VERSION_MAJOR >= 58)
+ _Pragma ("GCC diagnostic push");
+ _Pragma ("GCC diagnostic ignored \"-Wdeprecated-declarations\""); \
+ st->codec->time_base.num = info.video_timebase.num;
+ st->codec->time_base.den = info.video_timebase.den;
+ _Pragma ("GCC diagnostic pop");
+#endif
c->gop_size = 12; /* TODO: add this to "info"... emit one intra frame every twelve frames at most */
c->max_b_frames = 10;
From 2a043014824822e74dd4d3710df55609d6919836 Mon Sep 17 00:00:00 2001
From: "FeRD (Frank Dana)"
Date: Mon, 1 Jun 2020 15:24:15 -0400
Subject: [PATCH 16/26] Travis: allow_failures for FFmpeg 3.2
---
.travis.yml | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/.travis.yml b/.travis.yml
index 24e772af..c8af86a7 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -32,8 +32,12 @@ addons:
- curl
jobs:
- include:
+ # The FFmpeg 3.2 backport PPA has gone missing
+ allow_failures:
+ - name: "FFmpeg 3.2 GCC (Ubuntu 16.04 Xenial)"
+
+ include:
- name: "Coverage + FFmpeg 3.4 GCC (Ubuntu 18.04 Bionic)"
env:
- BUILD_VERSION=coverage_ffmpeg34
From 58c971a57690b533fba40cd6da077bec538c8c02 Mon Sep 17 00:00:00 2001
From: "FeRD (Frank Dana)"
Date: Mon, 1 Jun 2020 15:24:15 -0400
Subject: [PATCH 17/26] Travis: allow_failures for FFmpeg 3.2
---
.travis.yml | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/.travis.yml b/.travis.yml
index 24e772af..c8af86a7 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -32,8 +32,12 @@ addons:
- curl
jobs:
- include:
+ # The FFmpeg 3.2 backport PPA has gone missing
+ allow_failures:
+ - name: "FFmpeg 3.2 GCC (Ubuntu 16.04 Xenial)"
+
+ include:
- name: "Coverage + FFmpeg 3.4 GCC (Ubuntu 18.04 Bionic)"
env:
- BUILD_VERSION=coverage_ffmpeg34
From 456715437a31471209c14a58c03d7a6abea48b1f Mon Sep 17 00:00:00 2001
From: "FeRD (Frank Dana)"
Date: Mon, 1 Jun 2020 17:05:18 -0400
Subject: [PATCH 18/26] Remove unused Qt PPAs
---
.travis.yml | 3 ---
1 file changed, 3 deletions(-)
diff --git a/.travis.yml b/.travis.yml
index c8af86a7..af54662f 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -49,7 +49,6 @@ jobs:
apt:
sources:
- sourceline: 'ppa:openshot.developers/libopenshot-daily'
- - sourceline: 'ppa:beineri/opt-qt-5.12.3-bionic'
packages:
- *p_common
- qt5-default
@@ -96,7 +95,6 @@ jobs:
apt:
sources:
- sourceline: 'ppa:openshot.developers/libopenshot-daily'
- - sourceline: 'ppa:beineri/opt-qt-5.12.3-bionic'
packages:
- *p_common
- qt5-default
@@ -114,7 +112,6 @@ jobs:
apt:
sources:
- sourceline: 'ppa:openshot.developers/libopenshot-daily'
- - sourceline: 'ppa:beineri/opt-qt-5.10.0-xenial'
- sourceline: 'ppa:jon-hedgerows/ffmpeg-backports'
packages:
- *p_common
From 1dd0281deb74d1287da15cf2c4309a76acd3a441 Mon Sep 17 00:00:00 2001
From: "FeRD (Frank Dana)"
Date: Mon, 1 Jun 2020 17:06:04 -0400
Subject: [PATCH 19/26] Use Ubuntu 20.04 for FFmpeg 4
---
.travis.yml | 6 ++----
1 file changed, 2 insertions(+), 4 deletions(-)
diff --git a/.travis.yml b/.travis.yml
index af54662f..241d5be3 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -57,19 +57,17 @@ jobs:
- lcov
- binutils-common # For c++filt
- - name: "FFmpeg 4 GCC (Ubuntu 18.04 Bionic)"
+ - name: "FFmpeg 4 GCC (Ubuntu 20.04 Focal)"
env:
- BUILD_VERSION=ffmpeg4
- CMAKE_EXTRA_ARGS=""
- TEST_TARGET=test
os: linux
- dist: bionic
+ dist: focal
addons:
apt:
sources:
- sourceline: 'ppa:openshot.developers/libopenshot-daily'
- - sourceline: 'ppa:beineri/opt-qt-5.12.3-bionic'
- - sourceline: 'ppa:jonathonf/ffmpeg-4'
packages:
- *p_common
- qt5-default
From 511a6b1da2e349afb593836498b239c5c21dac99 Mon Sep 17 00:00:00 2001
From: "FeRD (Frank Dana)"
Date: Mon, 1 Jun 2020 17:58:22 -0400
Subject: [PATCH 20/26] Update Ruby compatibility message
---
src/bindings/ruby/CMakeLists.txt | 14 ++++++++------
1 file changed, 8 insertions(+), 6 deletions(-)
diff --git a/src/bindings/ruby/CMakeLists.txt b/src/bindings/ruby/CMakeLists.txt
index 4d7b922a..2ec16dcf 100644
--- a/src/bindings/ruby/CMakeLists.txt
+++ b/src/bindings/ruby/CMakeLists.txt
@@ -48,13 +48,15 @@ option(SILENCE_RUBY_VERSION_WARNING
if (${RUBY_VERSION} VERSION_GREATER 2.6.9 AND ${SWIG_VERSION} VERSION_LESS 4.0.3)
if (NOT ${SILENCE_RUBY_VERSION_WARNING})
- message(WARNING "
+ message(WARNING "\
Ruby 2.7.0+ detected, building the libopenshot Ruby API bindings \
-requires a pre-release version of SWIG 4.0.3 with this commit: \
-https://github.com/swig/swig/commit/5542cc228ad10bdc5c91107afb77c808c43bf2a4")
- message(STATUS "
-To disable this warning, add -DSILENCE_RUBY_VERSION_WARNING:BOOL=1 to the cmake \
-command line, or enable the option in the CMake GUI.")
+requires either SWIG 4.0.3 or an older version patched with this commit: \
+https://github.com/swig/swig/commit/5542cc228ad10bdc5c91107afb77c808c43bf2a4 \
+(Recent Fedora and Ubuntu distro packages of SWIG 4.0.1 have already been \
+patched.)")
+ message(STATUS "To disable the previous warning, add \
+-DSILENCE_RUBY_VERSION_WARNING:BOOL=1 to the cmake command line, \
+or enable the option in the CMake GUI.")
endif()
endif()
From 93d12e7f14e8c4f002e5f98af14412b80a4cd53b Mon Sep 17 00:00:00 2001
From: eisneinechse <42617957+eisneinechse@users.noreply.github.com>
Date: Tue, 2 Jun 2020 08:53:39 -0700
Subject: [PATCH 21/26] Include data for fps in clip created by ffmpeg 4+
---
src/FFmpegWriter.cpp | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/src/FFmpegWriter.cpp b/src/FFmpegWriter.cpp
index cc4b3d3a..e10b7026 100644
--- a/src/FFmpegWriter.cpp
+++ b/src/FFmpegWriter.cpp
@@ -1266,6 +1266,13 @@ AVStream *FFmpegWriter::add_video_stream() {
st->avg_frame_rate = av_inv_q(c->time_base);
st->time_base.num = info.video_timebase.num;
st->time_base.den = info.video_timebase.den;
+#if (LIBAVFORMAT_VERSION_MAJOR >= 58)
+ _Pragma ("GCC diagnostic push");
+ _Pragma ("GCC diagnostic ignored \"-Wdeprecated-declarations\""); \
+ st->codec->time_base.num = info.video_timebase.num;
+ st->codec->time_base.den = info.video_timebase.den;
+ _Pragma ("GCC diagnostic pop");
+#endif
c->gop_size = 12; /* TODO: add this to "info"... emit one intra frame every twelve frames at most */
c->max_b_frames = 10;
From 7ed26cf0223fbfd0a6f4988b9dd1099324496e8a Mon Sep 17 00:00:00 2001
From: Jonathan Thomas
Date: Tue, 2 Jun 2020 13:30:05 -0500
Subject: [PATCH 22/26] Replace _Pragma with #pragma
Co-authored-by: Frank Dana
---
src/FFmpegWriter.cpp | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/src/FFmpegWriter.cpp b/src/FFmpegWriter.cpp
index cd3185c4..5b57218f 100644
--- a/src/FFmpegWriter.cpp
+++ b/src/FFmpegWriter.cpp
@@ -1223,11 +1223,11 @@ AVStream *FFmpegWriter::add_video_stream() {
st->time_base.num = info.video_timebase.num;
st->time_base.den = info.video_timebase.den;
#if (LIBAVFORMAT_VERSION_MAJOR >= 58)
- _Pragma ("GCC diagnostic push");
- _Pragma ("GCC diagnostic ignored \"-Wdeprecated-declarations\""); \
+ #pragma GCC diagnostic push
+ #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
st->codec->time_base.num = info.video_timebase.num;
st->codec->time_base.den = info.video_timebase.den;
- _Pragma ("GCC diagnostic pop");
+ #pragma GCC diagnostic pop
#endif
c->gop_size = 12; /* TODO: add this to "info"... emit one intra frame every twelve frames at most */
From d9e6af5cda54ad7d33569563d86653bcfc58a890 Mon Sep 17 00:00:00 2001
From: eisneinechse <42617957+eisneinechse@users.noreply.github.com>
Date: Tue, 2 Jun 2020 11:35:07 -0700
Subject: [PATCH 23/26] Refert last commit
---
src/FFmpegWriter.cpp | 7 -------
1 file changed, 7 deletions(-)
diff --git a/src/FFmpegWriter.cpp b/src/FFmpegWriter.cpp
index e10b7026..cc4b3d3a 100644
--- a/src/FFmpegWriter.cpp
+++ b/src/FFmpegWriter.cpp
@@ -1266,13 +1266,6 @@ AVStream *FFmpegWriter::add_video_stream() {
st->avg_frame_rate = av_inv_q(c->time_base);
st->time_base.num = info.video_timebase.num;
st->time_base.den = info.video_timebase.den;
-#if (LIBAVFORMAT_VERSION_MAJOR >= 58)
- _Pragma ("GCC diagnostic push");
- _Pragma ("GCC diagnostic ignored \"-Wdeprecated-declarations\""); \
- st->codec->time_base.num = info.video_timebase.num;
- st->codec->time_base.den = info.video_timebase.den;
- _Pragma ("GCC diagnostic pop");
-#endif
c->gop_size = 12; /* TODO: add this to "info"... emit one intra frame every twelve frames at most */
c->max_b_frames = 10;
From 7831cfe9128502ae894d85c14e033991cd9a3d1b Mon Sep 17 00:00:00 2001
From: Jonathan Thomas
Date: Sat, 6 Jun 2020 01:55:52 -0500
Subject: [PATCH 24/26] Adding some new functionality and documentation to
DummyReader. Adding the ability to add test frames, with fake image and audio
data. This will can be used in unittests, and will soon be used to verify
some new audio improvements (coming soon).
---
include/DummyReader.h | 50 +++++++++++++++++-
src/DummyReader.cpp | 31 +++++++++--
src/Frame.cpp | 5 ++
tests/CMakeLists.txt | 1 +
tests/DummyReader_Tests.cpp | 102 ++++++++++++++++++++++++++++++++++++
5 files changed, 185 insertions(+), 4 deletions(-)
create mode 100644 tests/DummyReader_Tests.cpp
diff --git a/include/DummyReader.h b/include/DummyReader.h
index 4c935103..576a0df8 100644
--- a/include/DummyReader.h
+++ b/include/DummyReader.h
@@ -46,14 +46,58 @@
namespace openshot
{
/**
- * @brief This class is used as a simple, dummy reader, which always returns a blank frame.
+ * @brief This class is used as a simple, dummy reader, which can be very useful when writing
+ * unit tests. It can return a single blank frame or it can return custom frame objects
+ * which were added using the WriteFrame() method.
*
* A dummy reader can be created with any framerate or samplerate. This is useful in unit
* tests that need to test different framerates or samplerates.
+ *
+ * @code
+ * // Create a reader (Fraction fps, int width, int height, int sample_rate, int channels, float duration)
+ * openshot::DummyReader r(openshot::Fraction(30, 1), 1920, 1080, 44100, 2, 30.0);
+ * r.Open(); // Open the reader
+ *
+ * // Get a frame (which will be blank, since we haven't added any frames yet)
+ * std::shared_ptr f = r.GetFrame(1);
+ *
+ * // Now let's create some test frames
+ * for (int64_t frame_number = 1; frame_number <= 30; frame_number++)
+ * {
+ * // Create blank frame (with specific frame #, samples, and channels)
+ * // Sample count should be 44100 / 30 fps = 1470 samples per frame
+ * int sample_count = 1470;
+ * std::shared_ptr f(new openshot::Frame(frame_number, sample_count, 2));
+ *
+ * // Create test samples with incrementing value
+ * float *audio_buffer = new float[sample_count];
+ * for (int64_t sample_number = 0; sample_number < sample_count; sample_number++)
+ * {
+ * // Generate an incrementing audio sample value (just as an example)
+ * audio_buffer[sample_number] = float(frame_number) + (float(sample_number) / float(sample_count));
+ * }
+ *
+ * // Add custom audio samples to Frame (bool replaceSamples, int destChannel, int destStartSample, const float* source,
+ * // int numSamples, float gainToApplyToSource = 1.0f)
+ * f->AddAudio(true, 0, 0, audio_buffer, sample_count, 1.0); // add channel 1
+ * f->AddAudio(true, 1, 0, audio_buffer, sample_count, 1.0); // add channel 2
+ *
+ * // Write test frame to dummy reader
+ * r.WriteFrame(f);
+ * }
+ *
+ * // Now let's verify our DummyReader works
+ * std::shared_ptr f = r.GetFrame(1);
+ * // r.GetFrame(1)->GetAudioSamples(0)[1] should equal 1.00068033 based on our above calculations
+ *
+ * // Close the reader
+ * r.Close();
+ * @endcode
*/
class DummyReader : public ReaderBase
{
private:
+ CacheMemory dummy_cache;
std::shared_ptr image_frame;
bool is_open;
@@ -94,6 +138,10 @@ namespace openshot
/// Open File - which is called by the constructor automatically
void Open() override;
+
+ /// @brief Add a frame to the dummy reader. This is useful when constructing unit tests that require custom frames.
+ /// @param frame The openshot::Frame object to write to this image
+ void WriteFrame(std::shared_ptr frame);
};
}
diff --git a/src/DummyReader.cpp b/src/DummyReader.cpp
index 8fd98bcb..1b663a07 100644
--- a/src/DummyReader.cpp
+++ b/src/DummyReader.cpp
@@ -99,24 +99,49 @@ void DummyReader::Close()
{
// Mark as "closed"
is_open = false;
+
+ // Clear cache
+ dummy_cache.Clear();
}
}
-// Get an openshot::Frame object for a specific frame number of this reader.
+// Add Frame objects to DummyReader
+void DummyReader::WriteFrame(std::shared_ptr frame)
+{
+ if (frame) {
+ dummy_cache.Add(frame);
+ }
+}
+
+// Get an openshot::Frame object for a specific frame number of this reader. It is either a blank frame
+// or a custom frame added with the WriteFrame() method.
std::shared_ptr DummyReader::GetFrame(int64_t requested_frame)
{
// Check for open reader (or throw exception)
if (!is_open)
throw ReaderClosed("The ImageReader is closed. Call Open() before calling this method.", "dummy");
- if (image_frame)
- {
+ if (dummy_cache.Count() == 0 && image_frame) {
// Create a scoped lock, allowing only a single thread to run the following code at one time
const GenericScopedLock lock(getFrameCriticalSection);
// Always return same frame (regardless of which frame number was requested)
image_frame->number = requested_frame;
return image_frame;
+
+ } else if (dummy_cache.Count() > 0) {
+ // Create a scoped lock, allowing only a single thread to run the following code at one time
+ const GenericScopedLock lock(getFrameCriticalSection);
+
+ // Get a frame from the dummy cache
+ std::shared_ptr f = dummy_cache.GetFrame(requested_frame);
+ if (f) {
+ // return frame from cache (if found)
+ return f;
+ } else {
+ // No cached frame found
+ throw InvalidFile("Requested frame not found. You can only access Frame numbers added with WriteFrame().", "dummy");
+ }
}
else
// no frame loaded
diff --git a/src/Frame.cpp b/src/Frame.cpp
index ae9f1a4b..764b9651 100644
--- a/src/Frame.cpp
+++ b/src/Frame.cpp
@@ -480,6 +480,11 @@ const unsigned char* Frame::GetPixels()
// Get pixel data (for only a single scan-line)
const unsigned char* Frame::GetPixels(int row)
{
+ // Check for blank image
+ if (!image)
+ // Fill with black
+ AddColor(width, height, color);
+
// Return array of pixel packets
return image->constScanLine(row);
}
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index 480dfb3d..7ccddba8 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -109,6 +109,7 @@ set(OPENSHOT_TEST_FILES
Clip_Tests.cpp
Color_Tests.cpp
Coordinate_Tests.cpp
+ DummyReader_Tests.cpp
ReaderBase_Tests.cpp
ImageWriter_Tests.cpp
FFmpegReader_Tests.cpp
diff --git a/tests/DummyReader_Tests.cpp b/tests/DummyReader_Tests.cpp
new file mode 100644
index 00000000..ea410ad0
--- /dev/null
+++ b/tests/DummyReader_Tests.cpp
@@ -0,0 +1,102 @@
+/**
+ * @file
+ * @brief Unit tests for openshot::DummyReader
+ * @author Jonathan Thomas
+ *
+ * @ref License
+ */
+
+/* LICENSE
+ *
+ * Copyright (c) 2008-2019 OpenShot Studios, LLC
+ * . This file is part of
+ * OpenShot Library (libopenshot), an open-source project dedicated to
+ * delivering high quality video editing and animation solutions to the
+ * world. For more information visit .
+ *
+ * OpenShot Library (libopenshot) is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * OpenShot Library (libopenshot) is distributed in the hope that it will be
+ * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with OpenShot Library. If not, see .
+ */
+
+#include "UnitTest++.h"
+// Prevent name clashes with juce::UnitTest
+#define DONT_SET_USING_JUCE_NAMESPACE 1
+
+#include "../include/OpenShot.h"
+
+using namespace std;
+using namespace openshot;
+
+TEST (DummyReader_Constructor) {
+ // Create a default fraction (should be 1/1)
+ openshot::DummyReader r(openshot::Fraction(30, 1), 1920, 1080, 44100, 2, 30.0);
+ r.Open(); // Open the reader
+
+ // Check values
+ CHECK_EQUAL(1920, r.info.width);
+ CHECK_EQUAL(1080, r.info.height);
+ CHECK_EQUAL(30, r.info.fps.num);
+ CHECK_EQUAL(1, r.info.fps.den);
+ CHECK_EQUAL(44100, r.info.sample_rate);
+ CHECK_EQUAL(2, r.info.channels);
+ CHECK_EQUAL(30.0, r.info.duration);
+}
+
+TEST (DummyReader_Blank_Frame) {
+ // Create a default fraction (should be 1/1)
+ openshot::DummyReader r(openshot::Fraction(30, 1), 1920, 1080, 44100, 2, 30.0);
+ r.Open(); // Open the reader
+
+ // Get a blank frame (because we have not added any frames using WriteFrame() yet)
+ // Check values
+ CHECK_EQUAL(1, r.GetFrame(1)->number);
+ CHECK_EQUAL(1, r.GetFrame(1)->GetPixels(700)[700] == 0); // black pixel
+ CHECK_EQUAL(1, r.GetFrame(1)->GetPixels(701)[701] == 0); // black pixel
+}
+
+TEST (DummyReader_Fake_Frame) {
+ // Create a default fraction (should be 1/1)
+ openshot::DummyReader r(openshot::Fraction(30, 1), 1920, 1080, 44100, 2, 30.0);
+ r.Open(); // Open the reader
+
+ // Let's create some test frames
+ for (int64_t frame_number = 1; frame_number <= 30; frame_number++) {
+ // Create blank frame (with specific frame #, samples, and channels)
+ // Sample count should be 44100 / 30 fps = 1470 samples per frame
+ int sample_count = 1470;
+ std::shared_ptr f(new openshot::Frame(frame_number, sample_count, 2));
+
+ // Create test samples with incrementing value
+ float *audio_buffer = new float[sample_count];
+ for (int64_t sample_number = 0; sample_number < sample_count; sample_number++) {
+ // Generate an incrementing audio sample value (just as an example)
+ audio_buffer[sample_number] = float(frame_number) + (float(sample_number) / float(sample_count));
+ }
+
+ // Add custom audio samples to Frame (bool replaceSamples, int destChannel, int destStartSample, const float* source,
+ f->AddAudio(true, 0, 0, audio_buffer, sample_count, 1.0); // add channel 1
+ f->AddAudio(true, 1, 0, audio_buffer, sample_count, 1.0); // add channel 2
+
+ // Write test frame to dummy reader
+ r.WriteFrame(f);
+ }
+
+ // Verify our artificial audio sample data is correct
+ CHECK_EQUAL(1, r.GetFrame(1)->number);
+ CHECK_EQUAL(1, r.GetFrame(1)->GetAudioSamples(0)[0]);
+ CHECK_CLOSE(1.00068033, r.GetFrame(1)->GetAudioSamples(0)[1], 0.00001);
+ CHECK_CLOSE(1.00136054, r.GetFrame(1)->GetAudioSamples(0)[2], 0.00001);
+ CHECK_EQUAL(2, r.GetFrame(2)->GetAudioSamples(0)[0]);
+ CHECK_CLOSE(2.00068033, r.GetFrame(2)->GetAudioSamples(0)[1], 0.00001);
+ CHECK_CLOSE(2.00136054, r.GetFrame(2)->GetAudioSamples(0)[2], 0.00001);
+}
\ No newline at end of file
From d29027ae30466f3aeb6ec0b78cc28754d7630174 Mon Sep 17 00:00:00 2001
From: Jonathan Thomas
Date: Sat, 6 Jun 2020 02:03:27 -0500
Subject: [PATCH 25/26] Added an additional unittest for DummyReader (for
invalid frame)
---
tests/DummyReader_Tests.cpp | 19 +++++++++++++++++++
1 file changed, 19 insertions(+)
diff --git a/tests/DummyReader_Tests.cpp b/tests/DummyReader_Tests.cpp
index ea410ad0..6ec11e08 100644
--- a/tests/DummyReader_Tests.cpp
+++ b/tests/DummyReader_Tests.cpp
@@ -99,4 +99,23 @@ TEST (DummyReader_Fake_Frame) {
CHECK_EQUAL(2, r.GetFrame(2)->GetAudioSamples(0)[0]);
CHECK_CLOSE(2.00068033, r.GetFrame(2)->GetAudioSamples(0)[1], 0.00001);
CHECK_CLOSE(2.00136054, r.GetFrame(2)->GetAudioSamples(0)[2], 0.00001);
+}
+
+TEST (DummyReader_Invalid_Fake_Frame) {
+ // Create a default fraction (should be 1/1)
+ openshot::DummyReader r(openshot::Fraction(30, 1), 1920, 1080, 44100, 2, 30.0);
+ r.Open();
+
+ // Create fake frames (with specific frame #, samples, and channels)
+ std::shared_ptr f1(new openshot::Frame(1, 1470, 2));
+ std::shared_ptr f2(new openshot::Frame(2, 1470, 2));
+
+ // Write test frames to dummy reader
+ r.WriteFrame(f1);
+ r.WriteFrame(f2);
+
+ // Verify exception
+ CHECK_EQUAL(1, r.GetFrame(1)->number);
+ CHECK_EQUAL(2, r.GetFrame(2)->number);
+ CHECK_THROW(r.GetFrame(3)->number, InvalidFile);
}
\ No newline at end of file
From 8b12c1fa2173db24246858e744118da544d7e320 Mon Sep 17 00:00:00 2001
From: Jonathan Thomas
Date: Sat, 6 Jun 2020 17:25:45 -0500
Subject: [PATCH 26/26] Replacing WriteFrame() method with custom constructor
which can accept a CacheBase* pointer, for instances where a DummyReader
needs some specific test Frame objects
---
include/DummyReader.h | 33 ++++++++++---------
src/DummyReader.cpp | 64 ++++++++++++++++++++-----------------
tests/DummyReader_Tests.cpp | 58 ++++++++++++++++++++++++---------
3 files changed, 96 insertions(+), 59 deletions(-)
diff --git a/include/DummyReader.h b/include/DummyReader.h
index 576a0df8..e9c90968 100644
--- a/include/DummyReader.h
+++ b/include/DummyReader.h
@@ -48,18 +48,14 @@ namespace openshot
/**
* @brief This class is used as a simple, dummy reader, which can be very useful when writing
* unit tests. It can return a single blank frame or it can return custom frame objects
- * which were added using the WriteFrame() method.
+ * which were passed into the constructor with a Cache object.
*
* A dummy reader can be created with any framerate or samplerate. This is useful in unit
* tests that need to test different framerates or samplerates.
*
* @code
- * // Create a reader (Fraction fps, int width, int height, int sample_rate, int channels, float duration)
- * openshot::DummyReader r(openshot::Fraction(30, 1), 1920, 1080, 44100, 2, 30.0);
- * r.Open(); // Open the reader
- *
- * // Get a frame (which will be blank, since we haven't added any frames yet)
- * std::shared_ptr f = r.GetFrame(1);
+ * // Create cache object to store fake Frame objects
+ * CacheMemory cache;
*
* // Now let's create some test frames
* for (int64_t frame_number = 1; frame_number <= 30; frame_number++)
@@ -82,25 +78,33 @@ namespace openshot
* f->AddAudio(true, 0, 0, audio_buffer, sample_count, 1.0); // add channel 1
* f->AddAudio(true, 1, 0, audio_buffer, sample_count, 1.0); // add channel 2
*
- * // Write test frame to dummy reader
- * r.WriteFrame(f);
+ * // Add test frame to cache
+ * cache.Add(f);
* }
*
+ * // Create a reader (Fraction fps, int width, int height, int sample_rate, int channels, float duration, CacheBase* cache)
+ * openshot::DummyReader r(openshot::Fraction(30, 1), 1920, 1080, 44100, 2, 30.0, &cache);
+ * r.Open(); // Open the reader
+ *
* // Now let's verify our DummyReader works
* std::shared_ptr f = r.GetFrame(1);
* // r.GetFrame(1)->GetAudioSamples(0)[1] should equal 1.00068033 based on our above calculations
*
- * // Close the reader
+ * // Clean up
* r.Close();
+ * cache.Clear()
* @endcode
*/
class DummyReader : public ReaderBase
{
private:
- CacheMemory dummy_cache;
+ CacheBase* dummy_cache;
std::shared_ptr image_frame;
bool is_open;
+ /// Initialize variables used by constructor
+ void init(Fraction fps, int width, int height, int sample_rate, int channels, float duration);
+
public:
/// Blank constructor for DummyReader, with default settings.
@@ -109,6 +113,9 @@ namespace openshot
/// Constructor for DummyReader.
DummyReader(openshot::Fraction fps, int width, int height, int sample_rate, int channels, float duration);
+ /// Constructor for DummyReader which takes a frame cache object.
+ DummyReader(openshot::Fraction fps, int width, int height, int sample_rate, int channels, float duration, CacheBase* cache);
+
virtual ~DummyReader();
/// Close File
@@ -138,10 +145,6 @@ namespace openshot
/// Open File - which is called by the constructor automatically
void Open() override;
-
- /// @brief Add a frame to the dummy reader. This is useful when constructing unit tests that require custom frames.
- /// @param frame The openshot::Frame object to write to this image
- void WriteFrame(std::shared_ptr frame);
};
}
diff --git a/src/DummyReader.cpp b/src/DummyReader.cpp
index 1b663a07..8b6f752f 100644
--- a/src/DummyReader.cpp
+++ b/src/DummyReader.cpp
@@ -32,16 +32,8 @@
using namespace openshot;
-// Blank constructor for DummyReader, with default settings.
-DummyReader::DummyReader() {
-
- // Call actual constructor with default values
- DummyReader(Fraction(24,1), 1280, 768, 44100, 2, 30.0);
-}
-
-// Constructor for DummyReader. Pass a framerate and samplerate.
-DummyReader::DummyReader(Fraction fps, int width, int height, int sample_rate, int channels, float duration) {
-
+// Initialize variables used by constructor
+void DummyReader::init(Fraction fps, int width, int height, int sample_rate, int channels, float duration) {
// Set key info settings
info.has_audio = false;
info.has_video = true;
@@ -68,10 +60,30 @@ DummyReader::DummyReader(Fraction fps, int width, int height, int sample_rate, i
// Set the ratio based on the reduced fraction
info.display_ratio.num = size.num;
info.display_ratio.den = size.den;
+}
- // Open and Close the reader, to populate its attributes (such as height, width, etc...)
- Open();
- Close();
+// Blank constructor for DummyReader, with default settings.
+DummyReader::DummyReader() : dummy_cache(NULL), is_open(false) {
+
+ // Initialize important variables
+ init(Fraction(24,1), 1280, 768, 44100, 2, 30.0);
+}
+
+// Constructor for DummyReader. Pass a framerate and samplerate.
+DummyReader::DummyReader(Fraction fps, int width, int height, int sample_rate, int channels, float duration) : dummy_cache(NULL), is_open(false) {
+
+ // Initialize important variables
+ init(fps, width, height, sample_rate, channels, duration);
+}
+
+// Constructor which also takes a cache object
+DummyReader::DummyReader(Fraction fps, int width, int height, int sample_rate, int channels, float duration, CacheBase* cache) : is_open(false) {
+
+ // Initialize important variables
+ init(fps, width, height, sample_rate, channels, duration);
+
+ // Set cache object
+ dummy_cache = (CacheBase*) cache;
}
DummyReader::~DummyReader() {
@@ -99,29 +111,23 @@ void DummyReader::Close()
{
// Mark as "closed"
is_open = false;
-
- // Clear cache
- dummy_cache.Clear();
- }
-}
-
-// Add Frame objects to DummyReader
-void DummyReader::WriteFrame(std::shared_ptr frame)
-{
- if (frame) {
- dummy_cache.Add(frame);
}
}
// Get an openshot::Frame object for a specific frame number of this reader. It is either a blank frame
-// or a custom frame added with the WriteFrame() method.
+// or a custom frame added with passing a Cache object to the constructor.
std::shared_ptr DummyReader::GetFrame(int64_t requested_frame)
{
// Check for open reader (or throw exception)
if (!is_open)
throw ReaderClosed("The ImageReader is closed. Call Open() before calling this method.", "dummy");
- if (dummy_cache.Count() == 0 && image_frame) {
+ int dummy_cache_count = 0;
+ if (dummy_cache) {
+ dummy_cache_count = dummy_cache->Count();
+ }
+
+ if (dummy_cache_count == 0 && image_frame) {
// Create a scoped lock, allowing only a single thread to run the following code at one time
const GenericScopedLock lock(getFrameCriticalSection);
@@ -129,18 +135,18 @@ std::shared_ptr DummyReader::GetFrame(int64_t requested_frame)
image_frame->number = requested_frame;
return image_frame;
- } else if (dummy_cache.Count() > 0) {
+ } else if (dummy_cache_count > 0) {
// Create a scoped lock, allowing only a single thread to run the following code at one time
const GenericScopedLock lock(getFrameCriticalSection);
// Get a frame from the dummy cache
- std::shared_ptr f = dummy_cache.GetFrame(requested_frame);
+ std::shared_ptr f = dummy_cache->GetFrame(requested_frame);
if (f) {
// return frame from cache (if found)
return f;
} else {
// No cached frame found
- throw InvalidFile("Requested frame not found. You can only access Frame numbers added with WriteFrame().", "dummy");
+ throw InvalidFile("Requested frame not found. You can only access Frame numbers that exist in the Cache object.", "dummy");
}
}
else
diff --git a/tests/DummyReader_Tests.cpp b/tests/DummyReader_Tests.cpp
index 6ec11e08..c72be2d9 100644
--- a/tests/DummyReader_Tests.cpp
+++ b/tests/DummyReader_Tests.cpp
@@ -37,9 +37,24 @@
using namespace std;
using namespace openshot;
+TEST (DummyReader_Basic_Constructor) {
+ // Create a default fraction (should be 1/1)
+ openshot::DummyReader r;
+ r.Open(); // Open the reader
+
+ // Check values
+ CHECK_EQUAL(1280, r.info.width);
+ CHECK_EQUAL(768, r.info.height);
+ CHECK_EQUAL(24, r.info.fps.num);
+ CHECK_EQUAL(1, r.info.fps.den);
+ CHECK_EQUAL(44100, r.info.sample_rate);
+ CHECK_EQUAL(2, r.info.channels);
+ CHECK_EQUAL(30.0, r.info.duration);
+}
+
TEST (DummyReader_Constructor) {
// Create a default fraction (should be 1/1)
- openshot::DummyReader r(openshot::Fraction(30, 1), 1920, 1080, 44100, 2, 30.0);
+ openshot::DummyReader r(openshot::Fraction(30, 1), 1920, 1080, 44100, 2, 60.0);
r.Open(); // Open the reader
// Check values
@@ -49,7 +64,7 @@ TEST (DummyReader_Constructor) {
CHECK_EQUAL(1, r.info.fps.den);
CHECK_EQUAL(44100, r.info.sample_rate);
CHECK_EQUAL(2, r.info.channels);
- CHECK_EQUAL(30.0, r.info.duration);
+ CHECK_EQUAL(60.0, r.info.duration);
}
TEST (DummyReader_Blank_Frame) {
@@ -57,7 +72,7 @@ TEST (DummyReader_Blank_Frame) {
openshot::DummyReader r(openshot::Fraction(30, 1), 1920, 1080, 44100, 2, 30.0);
r.Open(); // Open the reader
- // Get a blank frame (because we have not added any frames using WriteFrame() yet)
+ // Get a blank frame (because we have not passed a Cache object (full of Frame objects) to the constructor
// Check values
CHECK_EQUAL(1, r.GetFrame(1)->number);
CHECK_EQUAL(1, r.GetFrame(1)->GetPixels(700)[700] == 0); // black pixel
@@ -65,9 +80,9 @@ TEST (DummyReader_Blank_Frame) {
}
TEST (DummyReader_Fake_Frame) {
- // Create a default fraction (should be 1/1)
- openshot::DummyReader r(openshot::Fraction(30, 1), 1920, 1080, 44100, 2, 30.0);
- r.Open(); // Open the reader
+
+ // Create cache object to hold test frames
+ CacheMemory cache;
// Let's create some test frames
for (int64_t frame_number = 1; frame_number <= 30; frame_number++) {
@@ -87,10 +102,14 @@ TEST (DummyReader_Fake_Frame) {
f->AddAudio(true, 0, 0, audio_buffer, sample_count, 1.0); // add channel 1
f->AddAudio(true, 1, 0, audio_buffer, sample_count, 1.0); // add channel 2
- // Write test frame to dummy reader
- r.WriteFrame(f);
+ // Add test frame to dummy reader
+ cache.Add(f);
}
+ // Create a default fraction (should be 1/1)
+ openshot::DummyReader r(openshot::Fraction(30, 1), 1920, 1080, 44100, 2, 30.0, &cache);
+ r.Open(); // Open the reader
+
// Verify our artificial audio sample data is correct
CHECK_EQUAL(1, r.GetFrame(1)->number);
CHECK_EQUAL(1, r.GetFrame(1)->GetAudioSamples(0)[0]);
@@ -99,23 +118,32 @@ TEST (DummyReader_Fake_Frame) {
CHECK_EQUAL(2, r.GetFrame(2)->GetAudioSamples(0)[0]);
CHECK_CLOSE(2.00068033, r.GetFrame(2)->GetAudioSamples(0)[1], 0.00001);
CHECK_CLOSE(2.00136054, r.GetFrame(2)->GetAudioSamples(0)[2], 0.00001);
+
+ // Clean up
+ cache.Clear();
+ r.Close();
}
TEST (DummyReader_Invalid_Fake_Frame) {
- // Create a default fraction (should be 1/1)
- openshot::DummyReader r(openshot::Fraction(30, 1), 1920, 1080, 44100, 2, 30.0);
- r.Open();
-
// Create fake frames (with specific frame #, samples, and channels)
std::shared_ptr f1(new openshot::Frame(1, 1470, 2));
std::shared_ptr f2(new openshot::Frame(2, 1470, 2));
- // Write test frames to dummy reader
- r.WriteFrame(f1);
- r.WriteFrame(f2);
+ // Add test frames to cache object
+ CacheMemory cache;
+ cache.Add(f1);
+ cache.Add(f2);
+
+ // Create a default fraction (should be 1/1)
+ openshot::DummyReader r(openshot::Fraction(30, 1), 1920, 1080, 44100, 2, 30.0, &cache);
+ r.Open();
// Verify exception
CHECK_EQUAL(1, r.GetFrame(1)->number);
CHECK_EQUAL(2, r.GetFrame(2)->number);
CHECK_THROW(r.GetFrame(3)->number, InvalidFile);
+
+ // Clean up
+ cache.Clear();
+ r.Close();
}
\ No newline at end of file