diff --git a/src/AudioReaderSource.cpp b/src/AudioReaderSource.cpp index acd69deb..19fbb6ca 100644 --- a/src/AudioReaderSource.cpp +++ b/src/AudioReaderSource.cpp @@ -35,21 +35,25 @@ using namespace std; using namespace openshot; // Constructor that reads samples from a reader -AudioReaderSource::AudioReaderSource(ReaderBase *audio_reader, int64_t starting_frame_number, int buffer_size) - : reader(audio_reader), frame_number(starting_frame_number), - size(buffer_size), position(0), frame_position(0), estimated_frame(0), speed(1) { - - // Initialize an audio buffer (based on reader) - buffer = new juce::AudioSampleBuffer(reader->info.channels, size); - - // initialize the audio samples to zero (silence) +AudioReaderSource::AudioReaderSource( + ReaderBase *audio_reader, int64_t starting_frame_number, int buffer_size +) : + position(0), + size(buffer_size), + buffer(new juce::AudioSampleBuffer(audio_reader->info.channels, buffer_size)), + speed(1), + reader(audio_reader), + frame_number(starting_frame_number), + frame_position(0), + estimated_frame(0) +{ + // Zero the buffer contents buffer->clear(); } // Destructor AudioReaderSource::~AudioReaderSource() { - // Clear and delete the buffer delete buffer; buffer = NULL; } diff --git a/src/ClipBase.h b/src/ClipBase.h index c38b9790..2f138a5c 100644 --- a/src/ClipBase.h +++ b/src/ClipBase.h @@ -68,15 +68,13 @@ namespace openshot { CacheMemory cache; /// Constructor for the base clip - ClipBase() { - // Initialize values - position = 0.0; - layer = 0; - start = 0.0; - end = 0.0; - previous_properties = ""; - timeline = NULL; - }; + ClipBase() : + position(0.0), + layer(0), + start(0.0), + end(0.0), + previous_properties(""), + timeline(nullptr) {} // Compare a clip using the Position() property bool operator< ( ClipBase& a) { return (Position() < a.Position()); } diff --git a/src/Color.cpp b/src/Color.cpp index e848f1f7..c877cbd4 100644 --- a/src/Color.cpp +++ b/src/Color.cpp @@ -28,6 +28,8 @@ * along with OpenShot Library. If not, see . */ +#include + #include "Color.h" #include "Exceptions.h" diff --git a/src/Coordinate.cpp b/src/Coordinate.cpp index 6a4abb21..d2a2ed3c 100644 --- a/src/Coordinate.cpp +++ b/src/Coordinate.cpp @@ -34,14 +34,14 @@ using namespace openshot; // Default constructor for a coordinate, delegating to the full signature -Coordinate::Coordinate() : Coordinate::Coordinate(0, 0) {}; +Coordinate::Coordinate() : Coordinate::Coordinate(0, 0) {} // Constructor which also allows the user to set the X and Y -Coordinate::Coordinate(double x, double y) : X(x), Y(y) {}; +Coordinate::Coordinate(double x, double y) : X(x), Y(y) {} // Constructor which accepts a std::pair for (X, Y) Coordinate::Coordinate(const std::pair& co) - : X(co.first), Y(co.second) {}; + : X(co.first), Y(co.second) {} // Generate JSON string of this object std::string Coordinate::Json() const { diff --git a/src/Coordinate.h b/src/Coordinate.h index 0a3ba978..d4576cd2 100644 --- a/src/Coordinate.h +++ b/src/Coordinate.h @@ -37,43 +37,57 @@ namespace openshot { - /** - * @brief This class represents a Cartesian coordinate (X, Y) used in the Keyframe animation system. - * - * Animation involves the changing (i.e. interpolation) of numbers over time. A series of Coordinate - * objects allows us to plot a specific curve or line used during interpolation. In other words, it helps us - * control how a number changes over time (quickly or slowly). - * - * Please see the following Example Code: - * \code - * Coordinate c1(2,4); - * assert(c1.X == 2.0f); - * assert(c1.Y == 4.0f); - * \endcode - */ - class Coordinate { - public: - double X; ///< The X value of the coordinate (usually representing the frame #) - double Y; ///< The Y value of the coordinate (usually representing the value of the property being animated) +/** + * @brief A Cartesian coordinate (X, Y) used in the Keyframe animation system. + * + * Animation involves the changing (i.e. interpolation) of numbers over time. + * A series of Coordinate objects allows us to plot a specific curve or line + * used during interpolation. In other words, it helps us control how a + * value changes over time — whether it's increasing or decreasing + * (the direction of the slope) and how quickly (the steepness of the curve). + * + * Please see the following Example Code: + * \code + * Coordinate c1(2,4); + * assert(c1.X == 2.0f); + * assert(c1.Y == 4.0f); + * \endcode + */ +class Coordinate { +public: + double X; ///< The X value of the coordinate (usually representing the frame #) + double Y; ///< The Y value of the coordinate (usually representing the value of the property being animated) - /// The default constructor, which defaults to (0,0) - Coordinate(); + /// The default constructor, which defaults to (0,0) + Coordinate(); - /// @brief Constructor which also sets the X and Y - /// @param x The X coordinate (usually representing the frame #) - /// @param y The Y coordinate (usually representing the value of the property being animated) - Coordinate(double x, double y); + /// @brief Constructor which also sets the X and Y + /// @param x The X coordinate (usually representing the frame #) + /// @param y The Y coordinate (usually representing the value of the property being animated) + Coordinate(double x, double y); - /// @brief Constructor which accepts a std::pair tuple for {X, Y} - /// @param co A std::pair tuple containing (X, Y) - Coordinate(const std::pair& co); + /// @brief Constructor which accepts a std::pair tuple for {X, Y} + /// @param co A std::pair tuple containing (X, Y) + Coordinate(const std::pair& co); - // Get and Set JSON methods - std::string Json() const; ///< Generate JSON string of this object - Json::Value JsonValue() const; ///< Generate Json::Value for this object - void SetJson(const std::string value); ///< Load JSON string into this object - void SetJsonValue(const Json::Value root); ///< Load Json::Value into this object - }; + // Get and Set JSON methods + std::string Json() const; ///< Generate JSON string of this object + Json::Value JsonValue() const; ///< Generate Json::Value for this object + void SetJson(const std::string value); ///< Load JSON string into this object + void SetJsonValue(const Json::Value root); ///< Load Json::Value into this object +}; + +/// Stream output operator for openshot::Coordinate +template +std::basic_ostream& +operator<<(std::basic_ostream& o, const openshot::Coordinate& co) { + std::basic_ostringstream s; + s.flags(o.flags()); + s.imbue(o.getloc()); + s.precision(o.precision()); + s << "(" << co.X << ", " << co.Y << ")"; + return o << s.str(); +} } diff --git a/src/EffectBase.cpp b/src/EffectBase.cpp index b75a0820..a475c7eb 100644 --- a/src/EffectBase.cpp +++ b/src/EffectBase.cpp @@ -28,6 +28,9 @@ * along with OpenShot Library. If not, see . */ +#include +#include + #include "EffectBase.h" #include "Exceptions.h" @@ -57,16 +60,16 @@ void EffectBase::InitEffectInfo() } // Display file information -void EffectBase::DisplayInfo() { - std::cout << std::fixed << std::setprecision(2) << std::boolalpha; - std::cout << "----------------------------" << std::endl; - std::cout << "----- Effect Information -----" << std::endl; - std::cout << "----------------------------" << std::endl; - std::cout << "--> Name: " << info.name << std::endl; - std::cout << "--> Description: " << info.description << std::endl; - std::cout << "--> Has Video: " << info.has_video << std::endl; - std::cout << "--> Has Audio: " << info.has_audio << std::endl; - std::cout << "----------------------------" << std::endl; +void EffectBase::DisplayInfo(std::ostream* out) { + *out << std::fixed << std::setprecision(2) << std::boolalpha; + *out << "----------------------------" << std::endl; + *out << "----- Effect Information -----" << std::endl; + *out << "----------------------------" << std::endl; + *out << "--> Name: " << info.name << std::endl; + *out << "--> Description: " << info.description << std::endl; + *out << "--> Has Video: " << info.has_video << std::endl; + *out << "--> Has Audio: " << info.has_audio << std::endl; + *out << "----------------------------" << std::endl; } // Constrain a color value from 0 to 255 diff --git a/src/EffectBase.h b/src/EffectBase.h index dc78a7c9..05936500 100644 --- a/src/EffectBase.h +++ b/src/EffectBase.h @@ -87,7 +87,7 @@ namespace openshot EffectInfoStruct info; /// Display effect information in the standard output stream (stdout) - void DisplayInfo(); + void DisplayInfo(std::ostream* out=&std::cout); /// Constrain a color value from 0 to 255 int constrain(int color_value); diff --git a/src/Fraction.cpp b/src/Fraction.cpp index d4898326..cb13c393 100644 --- a/src/Fraction.cpp +++ b/src/Fraction.cpp @@ -34,21 +34,20 @@ using namespace openshot; // Delegating constructors -Fraction::Fraction() : Fraction::Fraction(1, 1) {}; +Fraction::Fraction() : Fraction::Fraction(1, 1) {} Fraction::Fraction(std::pair pair) - : Fraction::Fraction(pair.first, pair.second) {}; + : Fraction::Fraction(pair.first, pair.second) {} Fraction::Fraction(std::map mapping) - : Fraction::Fraction(mapping["num"], mapping["den"]) {}; + : Fraction::Fraction(mapping["num"], mapping["den"]) {} Fraction::Fraction(std::vector vector) - : Fraction::Fraction(vector[0], vector[1]) {}; + : Fraction::Fraction(vector[0], vector[1]) {} // Full constructor Fraction::Fraction(int num, int den) : - num(num), den(den) { -} + num(num), den(den) {} // Return this fraction as a float (i.e. 1/2 = 0.5) float Fraction::ToFloat() { diff --git a/src/Fraction.h b/src/Fraction.h index fb36e88b..3033cb92 100644 --- a/src/Fraction.h +++ b/src/Fraction.h @@ -38,53 +38,63 @@ namespace openshot { - /** - * @brief This class represents a fraction - * - * Fractions are often used in video editing to represent ratios and rates, for example: - * pixel ratios, frames per second, timebase, and other common ratios. Fractions are preferred - * over decimals due to their increased precision. - */ - class Fraction { - public: - int num; /// pair); + /// Constructor that accepts a (num, den) pair + Fraction(std::pair pair); - /// Constructor that takes a vector of length 2 (containing {num, den}) - Fraction(std::vector vector); + /// Constructor that takes a vector of length 2 (containing {num, den}) + Fraction(std::vector vector); - /// Constructor that takes a key-value mapping (keys: 'num'. 'den') - Fraction(std::map mapping); + /// Constructor that takes a key-value mapping (keys: 'num'. 'den') + Fraction(std::map mapping); - /// Calculate the greatest common denominator - int GreatestCommonDenominator(); + /// Calculate the greatest common denominator + int GreatestCommonDenominator(); - /// Reduce this fraction (i.e. 640/480 = 4/3) - void Reduce(); + /// Reduce this fraction (i.e. 640/480 = 4/3) + void Reduce(); - /// Return this fraction as a float (i.e. 1/2 = 0.5) - float ToFloat(); + /// Return this fraction as a float (i.e. 1/2 = 0.5) + float ToFloat(); - /// Return this fraction as a double (i.e. 1/2 = 0.5) - double ToDouble() const; + /// Return this fraction as a double (i.e. 1/2 = 0.5) + double ToDouble() const; - /// Return a rounded integer of the fraction (for example 30000/1001 returns 30) - int ToInt(); - - /// Return the reciprocal as a Fraction - Fraction Reciprocal() const; - }; + /// Return a rounded integer of the fraction (for example 30000/1001 returns 30) + int ToInt(); + /// Return the reciprocal as a Fraction + Fraction Reciprocal() const; +}; +// Stream output operator for openshot::Fraction +template +std::basic_ostream& +operator<<(std::basic_ostream& o, const openshot::Fraction& frac) { + std::basic_ostringstream s; + s.flags(o.flags()); + s.imbue(o.getloc()); + s.precision(o.precision()); + s << "Fraction(" << frac.num << ", " << frac.den << ")"; + return o << s.str(); } +} // namespace openshot #endif diff --git a/src/Frame.cpp b/src/Frame.cpp index 244b065f..aed38777 100644 --- a/src/Frame.cpp +++ b/src/Frame.cpp @@ -66,15 +66,15 @@ Frame::Frame(int64_t number, int width, int height, std::string color, int sampl } // Delegating Constructor - blank frame -Frame::Frame() : Frame::Frame(1, 1, 1, "#000000", 0, 2) {}; +Frame::Frame() : Frame::Frame(1, 1, 1, "#000000", 0, 2) {} // Delegating Constructor - image only Frame::Frame(int64_t number, int width, int height, std::string color) - : Frame::Frame(number, width, height, color, 0, 2) {}; + : Frame::Frame(number, width, height, color, 0, 2) {} // Delegating Constructor - audio only Frame::Frame(int64_t number, int samples, int channels) - : Frame::Frame(number, 1, 1, "#000000", samples, channels) {}; + : Frame::Frame(number, 1, 1, "#000000", samples, channels) {} // Copy constructor @@ -918,7 +918,7 @@ cv::Mat Frame::Qimage2mat( std::shared_ptr& qimage) { cv::mixChannels( &mat, 1, &mat2, 1, from_to, 3 ); cv::cvtColor(mat2, mat2, cv::COLOR_RGB2BGR); return mat2; -}; +} // Get pointer to OpenCV image object cv::Mat Frame::GetImageCV() diff --git a/src/FrameMapper.cpp b/src/FrameMapper.cpp index 9700b6ea..687ac595 100644 --- a/src/FrameMapper.cpp +++ b/src/FrameMapper.cpp @@ -28,6 +28,10 @@ * along with OpenShot Library. If not, see . */ +#include +#include +#include + #include "FrameMapper.h" #include "Exceptions.h" #include "Clip.h" @@ -517,7 +521,7 @@ std::shared_ptr FrameMapper::GetFrame(int64_t requested_frame) copy_samples.sample_end += EXTRA_INPUT_SAMPLES; int samples_per_end_frame = Frame::GetSamplesPerFrame(copy_samples.frame_end, original, - reader->info.sample_rate, reader->info.channels); + reader->info.sample_rate, reader->info.channels); if (copy_samples.sample_end >= samples_per_end_frame) { // check for wrapping @@ -533,7 +537,7 @@ std::shared_ptr FrameMapper::GetFrame(int64_t requested_frame) copy_samples.sample_start += EXTRA_INPUT_SAMPLES; int samples_per_start_frame = Frame::GetSamplesPerFrame(copy_samples.frame_start, original, - reader->info.sample_rate, reader->info.channels); + reader->info.sample_rate, reader->info.channels); if (copy_samples.sample_start >= samples_per_start_frame) { // check for wrapping @@ -611,7 +615,7 @@ std::shared_ptr FrameMapper::GetFrame(int64_t requested_frame) return final_cache.GetFrame(requested_frame); } -void FrameMapper::PrintMapping() +void FrameMapper::PrintMapping(std::ostream* out) { // Check if mappings are dirty (and need to be recalculated) if (is_dirty) @@ -622,8 +626,16 @@ void FrameMapper::PrintMapping() for (float map = 1; map <= frames.size(); map++) { MappedFrame frame = frames[map - 1]; - cout << "Target frame #: " << map << " mapped to original frame #:\t(" << frame.Odd.Frame << " odd, " << frame.Even.Frame << " even)" << endl; - cout << " - Audio samples mapped to frame " << frame.Samples.frame_start << ":" << frame.Samples.sample_start << " to frame " << frame.Samples.frame_end << ":" << frame.Samples.sample_end << endl; + *out << "Target frame #: " << map + << " mapped to original frame #:\t(" + << frame.Odd.Frame << " odd, " + << frame.Even.Frame << " even)" << std::endl; + + *out << " - Audio samples mapped to frame " + << frame.Samples.frame_start << ":" + << frame.Samples.sample_start << " to frame " + << frame.Samples.frame_end << ":" + << frame.Samples.sample_end << endl; } } @@ -733,7 +745,14 @@ void FrameMapper::SetJsonValue(const Json::Value root) { // Change frame rate or audio mapping details void FrameMapper::ChangeMapping(Fraction target_fps, PulldownType target_pulldown, int target_sample_rate, int target_channels, ChannelLayout target_channel_layout) { - ZmqLogger::Instance()->AppendDebugMethod("FrameMapper::ChangeMapping", "target_fps.num", target_fps.num, "target_fps.den", target_fps.den, "target_pulldown", target_pulldown, "target_sample_rate", target_sample_rate, "target_channels", target_channels, "target_channel_layout", target_channel_layout); + ZmqLogger::Instance()->AppendDebugMethod( + "FrameMapper::ChangeMapping", + "target_fps.num", target_fps.num, + "target_fps.den", target_fps.den, + "target_pulldown", target_pulldown, + "target_sample_rate", target_sample_rate, + "target_channels", target_channels, + "target_channel_layout", target_channel_layout); // Mark as dirty is_dirty = true; @@ -779,7 +798,13 @@ void FrameMapper::ResampleMappedAudio(std::shared_ptr frame, int64_t orig int samples_in_frame = frame->GetAudioSamplesCount(); ChannelLayout channel_layout_in_frame = frame->ChannelsLayout(); - ZmqLogger::Instance()->AppendDebugMethod("FrameMapper::ResampleMappedAudio", "frame->number", frame->number, "original_frame_number", original_frame_number, "channels_in_frame", channels_in_frame, "samples_in_frame", samples_in_frame, "sample_rate_in_frame", sample_rate_in_frame); + ZmqLogger::Instance()->AppendDebugMethod( + "FrameMapper::ResampleMappedAudio", + "frame->number", frame->number, + "original_frame_number", original_frame_number, + "channels_in_frame", channels_in_frame, + "samples_in_frame", samples_in_frame, + "sample_rate_in_frame", sample_rate_in_frame); // Get audio sample array float* frame_samples_float = NULL; @@ -815,7 +840,14 @@ void FrameMapper::ResampleMappedAudio(std::shared_ptr frame, int64_t orig delete[] frame_samples_float; frame_samples_float = NULL; - ZmqLogger::Instance()->AppendDebugMethod("FrameMapper::ResampleMappedAudio (got sample data from frame)", "frame->number", frame->number, "total_frame_samples", total_frame_samples, "target channels", info.channels, "channels_in_frame", channels_in_frame, "target sample_rate", info.sample_rate, "samples_in_frame", samples_in_frame); + ZmqLogger::Instance()->AppendDebugMethod( + "FrameMapper::ResampleMappedAudio (got sample data from frame)", + "frame->number", frame->number, + "total_frame_samples", total_frame_samples, + "target channels", info.channels, + "channels_in_frame", channels_in_frame, + "target sample_rate", info.sample_rate, + "samples_in_frame", samples_in_frame); // Create input frame (and allocate arrays) @@ -823,8 +855,10 @@ void FrameMapper::ResampleMappedAudio(std::shared_ptr frame, int64_t orig AV_RESET_FRAME(audio_frame); audio_frame->nb_samples = total_frame_samples / channels_in_frame; - int error_code = avcodec_fill_audio_frame(audio_frame, channels_in_frame, AV_SAMPLE_FMT_S16, (uint8_t *) frame_samples, - audio_frame->nb_samples * av_get_bytes_per_sample(AV_SAMPLE_FMT_S16) * channels_in_frame, 1); + int buf_size = audio_frame->nb_samples * av_get_bytes_per_sample(AV_SAMPLE_FMT_S16) * channels_in_frame; + int error_code = avcodec_fill_audio_frame( + audio_frame, channels_in_frame, AV_SAMPLE_FMT_S16, + (uint8_t *) frame_samples, buf_size, 1); if (error_code < 0) { @@ -837,7 +871,14 @@ void FrameMapper::ResampleMappedAudio(std::shared_ptr frame, int64_t orig // Update total samples & input frame size (due to bigger or smaller data types) total_frame_samples = Frame::GetSamplesPerFrame(AdjustFrameNumber(frame->number), target, info.sample_rate, info.channels); - ZmqLogger::Instance()->AppendDebugMethod("FrameMapper::ResampleMappedAudio (adjust # of samples)", "total_frame_samples", total_frame_samples, "info.sample_rate", info.sample_rate, "sample_rate_in_frame", sample_rate_in_frame, "info.channels", info.channels, "channels_in_frame", channels_in_frame, "original_frame_number", original_frame_number); + ZmqLogger::Instance()->AppendDebugMethod( + "FrameMapper::ResampleMappedAudio (adjust # of samples)", + "total_frame_samples", total_frame_samples, + "info.sample_rate", info.sample_rate, + "sample_rate_in_frame", sample_rate_in_frame, + "info.channels", info.channels, + "channels_in_frame", channels_in_frame, + "original_frame_number", original_frame_number); // Create output frame (and allocate arrays) AVFrame *audio_converted = AV_ALLOCATE_FRAME(); @@ -845,32 +886,39 @@ void FrameMapper::ResampleMappedAudio(std::shared_ptr frame, int64_t orig audio_converted->nb_samples = total_frame_samples; av_samples_alloc(audio_converted->data, audio_converted->linesize, info.channels, total_frame_samples, AV_SAMPLE_FMT_S16, 0); - ZmqLogger::Instance()->AppendDebugMethod("FrameMapper::ResampleMappedAudio (preparing for resample)", "in_sample_fmt", AV_SAMPLE_FMT_S16, "out_sample_fmt", AV_SAMPLE_FMT_S16, "in_sample_rate", sample_rate_in_frame, "out_sample_rate", info.sample_rate, "in_channels", channels_in_frame, "out_channels", info.channels); + ZmqLogger::Instance()->AppendDebugMethod( + "FrameMapper::ResampleMappedAudio (preparing for resample)", + "in_sample_fmt", AV_SAMPLE_FMT_S16, + "out_sample_fmt", AV_SAMPLE_FMT_S16, + "in_sample_rate", sample_rate_in_frame, + "out_sample_rate", info.sample_rate, + "in_channels", channels_in_frame, + "out_channels", info.channels); int nb_samples = 0; // setup resample context if (!avr) { avr = SWR_ALLOC(); - av_opt_set_int(avr, "in_channel_layout", channel_layout_in_frame, 0); - av_opt_set_int(avr, "out_channel_layout", info.channel_layout, 0); - av_opt_set_int(avr, "in_sample_fmt", AV_SAMPLE_FMT_S16, 0); - av_opt_set_int(avr, "out_sample_fmt", AV_SAMPLE_FMT_S16, 0); - av_opt_set_int(avr, "in_sample_rate", sample_rate_in_frame, 0); - av_opt_set_int(avr, "out_sample_rate", info.sample_rate, 0); - av_opt_set_int(avr, "in_channels", channels_in_frame, 0); - av_opt_set_int(avr, "out_channels", info.channels, 0); + av_opt_set_int(avr, "in_channel_layout", channel_layout_in_frame, 0); + av_opt_set_int(avr, "out_channel_layout", info.channel_layout, 0); + av_opt_set_int(avr, "in_sample_fmt", AV_SAMPLE_FMT_S16, 0); + av_opt_set_int(avr, "out_sample_fmt", AV_SAMPLE_FMT_S16, 0); + av_opt_set_int(avr, "in_sample_rate", sample_rate_in_frame, 0); + av_opt_set_int(avr, "out_sample_rate", info.sample_rate, 0); + av_opt_set_int(avr, "in_channels", channels_in_frame, 0); + av_opt_set_int(avr, "out_channels", info.channels, 0); SWR_INIT(avr); } // Convert audio samples - nb_samples = SWR_CONVERT(avr, // audio resample context - audio_converted->data, // output data pointers - audio_converted->linesize[0], // output plane size, in bytes. (0 if unknown) - audio_converted->nb_samples, // maximum number of samples that the output buffer can hold - audio_frame->data, // input data pointers - audio_frame->linesize[0], // input plane size, in bytes (0 if unknown) - audio_frame->nb_samples); // number of input samples to convert + nb_samples = SWR_CONVERT(avr, // audio resample context + audio_converted->data, // output data pointers + audio_converted->linesize[0], // output plane size, in bytes. (0 if unknown) + audio_converted->nb_samples, // maximum number of samples that the output buffer can hold + audio_frame->data, // input data pointers + audio_frame->linesize[0], // input plane size, in bytes (0 if unknown) + audio_frame->nb_samples); // number of input samples to convert // Create a new array (to hold all resampled S16 audio samples) int16_t* resampled_samples = new int16_t[(nb_samples * info.channels)]; @@ -889,7 +937,14 @@ void FrameMapper::ResampleMappedAudio(std::shared_ptr frame, int64_t orig int channel_buffer_size = nb_samples; frame->ResizeAudio(info.channels, channel_buffer_size, info.sample_rate, info.channel_layout); - ZmqLogger::Instance()->AppendDebugMethod("FrameMapper::ResampleMappedAudio (Audio successfully resampled)", "nb_samples", nb_samples, "total_frame_samples", total_frame_samples, "info.sample_rate", info.sample_rate, "channels_in_frame", channels_in_frame, "info.channels", info.channels, "info.channel_layout", info.channel_layout); + ZmqLogger::Instance()->AppendDebugMethod( + "FrameMapper::ResampleMappedAudio (Audio successfully resampled)", + "nb_samples", nb_samples, + "total_frame_samples", total_frame_samples, + "info.sample_rate", info.sample_rate, + "channels_in_frame", channels_in_frame, + "info.channels", info.channels, + "info.channel_layout", info.channel_layout); // Array of floats (to hold samples for each channel) float *channel_buffer = new float[channel_buffer_size]; @@ -929,7 +984,10 @@ void FrameMapper::ResampleMappedAudio(std::shared_ptr frame, int64_t orig // Add samples to frame for this channel frame->AddAudio(true, channel_filter, 0, channel_buffer, position, 1.0f); - ZmqLogger::Instance()->AppendDebugMethod("FrameMapper::ResampleMappedAudio (Add audio to channel)", "number of samples", position, "channel_filter", channel_filter); + ZmqLogger::Instance()->AppendDebugMethod( + "FrameMapper::ResampleMappedAudio (Add audio to channel)", + "number of samples", position, + "channel_filter", channel_filter); } // Update frame's audio meta data @@ -957,9 +1015,10 @@ int64_t FrameMapper::AdjustFrameNumber(int64_t clip_frame_number) { start = parent->Start(); } - // Adjust start frame and position based on parent clip. This prevents ensures the same - // frame # is used by mapped readers and clips, when calculating samples per frame. Thus, - // this prevents gaps and mismatches in # of samples. + // Adjust start frame and position based on parent clip. + // This ensures the same frame # is used by mapped readers and clips, + // when calculating samples per frame. + // Thus, this prevents gaps and mismatches in # of samples. int64_t clip_start_frame = (start * info.fps.ToDouble()) + 1; int64_t clip_start_position = round(position * info.fps.ToDouble()) + 1; int64_t frame_number = clip_frame_number + clip_start_position - clip_start_frame; diff --git a/src/FrameMapper.h b/src/FrameMapper.h index 62615cfb..813c644f 100644 --- a/src/FrameMapper.h +++ b/src/FrameMapper.h @@ -33,9 +33,9 @@ #include #include -#include #include #include + #include "CacheMemory.h" #include "ReaderBase.h" #include "Frame.h" @@ -211,7 +211,7 @@ namespace openshot void Open() override; /// Print all of the original frames and which new frames they map to - void PrintMapping(); + void PrintMapping(std::ostream* out=&std::cout); /// Get the current reader ReaderBase* Reader(); diff --git a/src/KeyFrame.cpp b/src/KeyFrame.cpp index 4107f2de..e25f4d7c 100644 --- a/src/KeyFrame.cpp +++ b/src/KeyFrame.cpp @@ -31,12 +31,14 @@ #include "KeyFrame.h" #include "Exceptions.h" -#include -#include -#include -#include // For assert() -#include // For std::cout -#include // For std::setprecision +#include // For std::lower_bound, std::move_backward +#include // For std::less, std::less_equal, etc… +#include // For std::swap +#include // For std::accumulate +#include // For assert() +#include // For fabs, round +#include // For std::cout +#include // For std::setprecision using namespace std; using namespace openshot; @@ -559,22 +561,51 @@ void Keyframe::UpdatePoint(int64_t index, Point p) { AddPoint(p); } -void Keyframe::PrintPoints() const { - cout << fixed << setprecision(4); - for (std::vector::const_iterator it = Points.begin(); it != Points.end(); it++) { - Point p = *it; - cout << p.co.X << "\t" << p.co.Y << endl; - } +void Keyframe::PrintPoints(std::ostream* out) const { + *out << std::right << std::setprecision(4) << std::setfill(' '); + for (const auto& p : Points) { + *out << std::defaultfloat + << std::setw(6) << p.co.X + << std::setw(14) << std::fixed << p.co.Y + << '\n'; + } + *out << std::flush; } -void Keyframe::PrintValues() const { - cout << fixed << setprecision(4); - cout << "Frame Number (X)\tValue (Y)\tIs Increasing\tRepeat Numerator\tRepeat Denominator\tDelta (Y Difference)\n"; +void Keyframe::PrintValues(std::ostream* out) const { + // Column widths + std::vector w{10, 12, 8, 11, 19}; - for (int64_t i = 1; i < GetLength(); ++i) { - cout << i << "\t" << GetValue(i) << "\t" << IsIncreasing(i) << "\t" ; - cout << GetRepeatFraction(i).num << "\t" << GetRepeatFraction(i).den << "\t" << GetDelta(i) << "\n"; - } + *out << std::right << std::setfill(' ') << std::boolalpha + << std::setprecision(4); + // Headings + *out << "│" + << std::setw(w[0]) << "Frame# (X)" << " │" + << std::setw(w[1]) << "Y Value" << " │" + << std::setw(w[2]) << "Delta Y" << " │ " + << std::setw(w[3]) << "Increasing?" << " │ " + << std::setw(w[4]) << std::left << "Repeat Fraction" << std::right + << "│\n"; + // Divider + *out << "├───────────" + << "┼─────────────" + << "┼─────────" + << "┼─────────────" + << "┼────────────────────┤\n"; + + for (int64_t i = 1; i < GetLength(); ++i) { + *out << "│" + << std::setw(w[0]-2) << std::defaultfloat << i + << (Contains(Point(i, 1)) ? " *" : " ") << " │" + << std::setw(w[1]) << std::fixed << GetValue(i) << " │" + << std::setw(w[2]) << std::defaultfloat << std::showpos + << GetDelta(i) << " │ " << std::noshowpos + << std::setw(w[3]) << IsIncreasing(i) << " │ " + << std::setw(w[4]) << std::left << GetRepeatFraction(i) + << std::right << "│\n"; + } + *out << " * = Keyframe point (non-interpolated)\n"; + *out << std::flush; } diff --git a/src/KeyFrame.h b/src/KeyFrame.h index 6da34cac..45624dd2 100644 --- a/src/KeyFrame.h +++ b/src/KeyFrame.h @@ -31,7 +31,7 @@ #ifndef OPENSHOT_KEYFRAME_H #define OPENSHOT_KEYFRAME_H -#include +#include #include #include "Fraction.h" @@ -160,10 +160,10 @@ namespace openshot { void UpdatePoint(int64_t index, Point p); /// Print a list of points - void PrintPoints() const; + void PrintPoints(std::ostream* out=&std::cout) const; /// Print just the Y value of the point's primary coordinate - void PrintValues() const; + void PrintValues(std::ostream* out=&std::cout) const; }; diff --git a/src/Point.cpp b/src/Point.cpp index 44b6883f..b11aa7ce 100644 --- a/src/Point.cpp +++ b/src/Point.cpp @@ -35,24 +35,24 @@ using namespace std; using namespace openshot; // Default constructor -Point::Point() : Point::Point(Coordinate(1, 0), BEZIER, AUTO) {}; +Point::Point() : Point::Point(Coordinate(1, 0), BEZIER, AUTO) {} // Constructor which creates a single coordinate at X=1 -Point::Point(float y) : Point::Point(Coordinate(1, y), CONSTANT, AUTO) {}; +Point::Point(float y) : Point::Point(Coordinate(1, y), CONSTANT, AUTO) {} // Constructor which creates a Bezier curve with point at (x, y) -Point::Point(float x, float y) : Point::Point(Coordinate(x, y), BEZIER, AUTO) {}; +Point::Point(float x, float y) : Point::Point(Coordinate(x, y), BEZIER, AUTO) {} // Constructor which also creates a Point, setting X,Y, and interpolation. Point::Point(float x, float y, InterpolationType interpolation) - : Point::Point(Coordinate(x, y), interpolation, AUTO) {}; + : Point::Point(Coordinate(x, y), interpolation, AUTO) {} // Direct Coordinate-accepting constructors -Point::Point(const Coordinate& co) : Point::Point(co, BEZIER, AUTO) {}; +Point::Point(const Coordinate& co) : Point::Point(co, BEZIER, AUTO) {} Point::Point(const Coordinate& co, InterpolationType interpolation) - : Point::Point(co, interpolation, AUTO) {}; + : Point::Point(co, interpolation, AUTO) {} Point::Point(const Coordinate& co, InterpolationType interpolation, HandleType handle_type) : co(co), interpolation(interpolation), handle_type(handle_type) { diff --git a/src/Point.h b/src/Point.h index 1795c469..118e6d39 100644 --- a/src/Point.h +++ b/src/Point.h @@ -37,95 +37,118 @@ namespace openshot { - /** - * @brief This controls how a Keyframe uses this point to interpolate between two points. - * - * Bezier is a smooth curve. Linear is a straight line. Constant is a jump from the - * previous point to this one. - */ - enum InterpolationType { - BEZIER, ///< Bezier curves are quadratic curves, which create a smooth curve. - LINEAR, ///< Linear curves are angular, straight lines between two points. - CONSTANT ///< Constant curves jump from their previous position to a new one (with no interpolation). - }; +/** + * @brief This controls how a Keyframe uses this point to interpolate between two points. + * + * Bezier is a smooth curve. Linear is a straight line. Constant is a jump from the + * previous point to this one. + */ +enum InterpolationType { + BEZIER, ///< Bezier curves are quadratic curves, which create a smooth curve. + LINEAR, ///< Linear curves are angular, straight lines between two points. + CONSTANT ///< Constant curves jump from their previous position to a new one (with no interpolation). +}; - /** - * @brief When BEZIER interpolation is used, the point's left and right handles are used - * to influence the direction of the curve. - * - * AUTO will try and adjust the handles automatically, to achieve the smoothest curves. - * MANUAL will leave the handles alone, making it the responsibility of the user to set them. - */ - enum HandleType { - AUTO, ///< Automatically adjust the handles to achieve the smoothest curve - MANUAL ///< Do not automatically adjust handles (set them manually) - }; +/** + * @brief When BEZIER interpolation is used, the point's left and right handles are used + * to influence the direction of the curve. + * + * AUTO will try and adjust the handles automatically, to achieve the smoothest curves. + * MANUAL will leave the handles alone, making it the responsibility of the user to set them. + */ +enum HandleType { + AUTO, ///< Automatically adjust the handles to achieve the smoothest curve + MANUAL ///< Do not automatically adjust handles (set them manually) +}; - /** - * @brief A Point is the basic building block of a key-frame curve. - * - * Points have a primary coordinate and a left and right handle coordinate. - * The handles are used to influence the direction of the curve as it - * moves between the primary coordinate and the next primary coordinate when the - * interpolation mode is BEZIER. When using LINEAR or CONSTANT, the handles are - * ignored. - * - * Please see the following Example Code: - * \code - * Coordinate c1(3,9); - * Point p1(c1, BEZIER); - * assert(c1.X == 3); - * assert(c1.Y == 9); - * - * \endcode - */ - class Point { - public: - Coordinate co; ///< This is the primary coordinate - Coordinate handle_left; ///< This is the left handle coordinate (in percentages from 0 to 1) - Coordinate handle_right; ///< This is the right handle coordinate (in percentages from 0 to 1) - InterpolationType interpolation; ///< This is the interpolation mode - HandleType handle_type; ///< This is the handle mode +/** + * @brief A Point is the basic building block of a key-frame curve. + * + * Points have a primary coordinate and a left and right handle coordinate. + * The handles are used to influence the direction of the curve as it + * moves between the primary coordinate and the next primary coordinate when the + * interpolation mode is BEZIER. When using LINEAR or CONSTANT, the handles are + * ignored. + * + * Please see the following Example Code: + * \code + * Coordinate c1(3,9); + * Point p1(c1, BEZIER); + * assert(c1.X == 3); + * assert(c1.Y == 9); + * + * \endcode + */ +class Point { +public: + Coordinate co; ///< This is the primary coordinate + Coordinate handle_left; ///< This is the left handle coordinate (in percentages from 0 to 1) + Coordinate handle_right; ///< This is the right handle coordinate (in percentages from 0 to 1) + InterpolationType interpolation; ///< This is the interpolation mode + HandleType handle_type; ///< This is the handle mode - /// Default constructor (defaults to 1,0) - Point(); + /// Default constructor (defaults to 1,0) + Point(); - /// Constructor which creates a single coordinate at X=1 - Point(float y); + /// Constructor which creates a single coordinate at X=1 + Point(float y); - /// Constructor which also creates a Point and sets the X and Y of the Point. - Point(float x, float y); + /// Constructor which also creates a Point and sets the X and Y of the Point. + Point(float x, float y); - /// Constructor which also creates a Point and sets the X,Y, and interpolation of the Point. - Point(float x, float y, InterpolationType interpolation); + /// Constructor which also creates a Point and sets the X,Y, and interpolation of the Point. + Point(float x, float y, InterpolationType interpolation); - /// Constructor which takes a coordinate - Point(const Coordinate& co); + /// Constructor which takes a coordinate + Point(const Coordinate& co); - /// Constructor which takes a coordinate and interpolation mode - Point(const Coordinate& co, InterpolationType interpolation); + /// Constructor which takes a coordinate and interpolation mode + Point(const Coordinate& co, InterpolationType interpolation); - /// Constructor which takes a coordinate, interpolation mode, and handle type - Point(const Coordinate& co, InterpolationType interpolation, HandleType handle_type); + /// Constructor which takes a coordinate, interpolation mode, and handle type + Point(const Coordinate& co, InterpolationType interpolation, HandleType handle_type); - /// Set the left and right handles to a percent of the primary coordinate (0 to 1) - /// Defaults to a smooth curve (Ease in and out) - void Initialize_Handles(); + /// Set the left and right handles to a percent of the primary coordinate (0 to 1) + /// Defaults to a smooth curve (Ease in and out) + void Initialize_Handles(); - /// Set the left handle to a percent of the primary coordinate (0 to 1) - void Initialize_LeftHandle(float x, float y); + /// Set the left handle to a percent of the primary coordinate (0 to 1) + void Initialize_LeftHandle(float x, float y); - /// Set the right handle to a percent of the primary coordinate (0 to 1) - void Initialize_RightHandle(float x, float y); + /// Set the right handle to a percent of the primary coordinate (0 to 1) + void Initialize_RightHandle(float x, float y); - // Get and Set JSON methods - std::string Json() const; ///< Generate JSON string of this object - Json::Value JsonValue() const; ///< Generate Json::Value for this object - void SetJson(const std::string value); ///< Load JSON string into this object - void SetJsonValue(const Json::Value root); ///< Load Json::Value into this object + // Get and Set JSON methods + std::string Json() const; ///< Generate JSON string of this object + Json::Value JsonValue() const; ///< Generate Json::Value for this object + void SetJson(const std::string value); ///< Load JSON string into this object + void SetJsonValue(const Json::Value root); ///< Load Json::Value into this object - }; +}; +// Stream output operator for openshot::Point +template +std::basic_ostream& +operator<<(std::basic_ostream& o, const openshot::Point& p) { + std::basic_ostringstream s; + s.flags(o.flags()); + s.imbue(o.getloc()); + s.precision(o.precision()); + s << "co" << p.co; + switch(p.interpolation) { + case(InterpolationType::LINEAR): + s << " LINEAR"; + break; + case(InterpolationType::CONSTANT): + s << " CONSTANT"; + break; + case(InterpolationType::BEZIER): + s << " BEZIER[L" << p.handle_left << ",R" << p.handle_right << ']'; + break; + } + return o << s.str(); } +} // namespace openshot + #endif diff --git a/src/ReaderBase.cpp b/src/ReaderBase.cpp index 127fefbe..63b5cada 100644 --- a/src/ReaderBase.cpp +++ b/src/ReaderBase.cpp @@ -28,8 +28,14 @@ * along with OpenShot Library. If not, see . */ +#include +#include +#include + #include "ReaderBase.h" +#include "Json.h" + using namespace openshot; /// Constructor for the base reader, where many things are initialized. @@ -67,49 +73,49 @@ ReaderBase::ReaderBase() } // Display file information -void ReaderBase::DisplayInfo() { - std::cout << std::fixed << std::setprecision(2) << std::boolalpha; - std::cout << "----------------------------" << std::endl; - std::cout << "----- File Information -----" << std::endl; - std::cout << "----------------------------" << std::endl; - std::cout << "--> Has Video: " << info.has_video << std::endl; - std::cout << "--> Has Audio: " << info.has_audio << std::endl; - std::cout << "--> Has Single Image: " << info.has_single_image << std::endl; - std::cout << "--> Duration: " << info.duration << " Seconds" << std::endl; - std::cout << "--> File Size: " << double(info.file_size) / 1024 / 1024 << " MB" << std::endl; - std::cout << "----------------------------" << std::endl; - std::cout << "----- Video Attributes -----" << std::endl; - std::cout << "----------------------------" << std::endl; - std::cout << "--> Width: " << info.width << std::endl; - std::cout << "--> Height: " << info.height << std::endl; - std::cout << "--> Pixel Format: " << info.pixel_format << std::endl; - std::cout << "--> Frames Per Second: " << info.fps.ToDouble() << " (" << info.fps.num << "/" << info.fps.den << ")" << std::endl; - std::cout << "--> Video Bit Rate: " << info.video_bit_rate/1000 << " kb/s" << std::endl; - std::cout << "--> Pixel Ratio: " << info.pixel_ratio.ToDouble() << " (" << info.pixel_ratio.num << "/" << info.pixel_ratio.den << ")" << std::endl; - std::cout << "--> Display Aspect Ratio: " << info.display_ratio.ToDouble() << " (" << info.display_ratio.num << "/" << info.display_ratio.den << ")" << std::endl; - std::cout << "--> Video Codec: " << info.vcodec << std::endl; - std::cout << "--> Video Length: " << info.video_length << " Frames" << std::endl; - std::cout << "--> Video Stream Index: " << info.video_stream_index << std::endl; - std::cout << "--> Video Timebase: " << info.video_timebase.ToDouble() << " (" << info.video_timebase.num << "/" << info.video_timebase.den << ")" << std::endl; - std::cout << "--> Interlaced: " << info.interlaced_frame << std::endl; - std::cout << "--> Interlaced: Top Field First: " << info.top_field_first << std::endl; - std::cout << "----------------------------" << std::endl; - std::cout << "----- Audio Attributes -----" << std::endl; - std::cout << "----------------------------" << std::endl; - std::cout << "--> Audio Codec: " << info.acodec << std::endl; - std::cout << "--> Audio Bit Rate: " << info.audio_bit_rate/1000 << " kb/s" << std::endl; - std::cout << "--> Sample Rate: " << info.sample_rate << " Hz" << std::endl; - std::cout << "--> # of Channels: " << info.channels << std::endl; - std::cout << "--> Channel Layout: " << info.channel_layout << std::endl; - std::cout << "--> Audio Stream Index: " << info.audio_stream_index << std::endl; - std::cout << "--> Audio Timebase: " << info.audio_timebase.ToDouble() << " (" << info.audio_timebase.num << "/" << info.audio_timebase.den << ")" << std::endl; - std::cout << "----------------------------" << std::endl; - std::cout << "--------- Metadata ---------" << std::endl; - std::cout << "----------------------------" << std::endl; +void ReaderBase::DisplayInfo(std::ostream* out) { + *out << std::fixed << std::setprecision(2) << std::boolalpha; + *out << "----------------------------" << std::endl; + *out << "----- File Information -----" << std::endl; + *out << "----------------------------" << std::endl; + *out << "--> Has Video: " << info.has_video << std::endl; + *out << "--> Has Audio: " << info.has_audio << std::endl; + *out << "--> Has Single Image: " << info.has_single_image << std::endl; + *out << "--> Duration: " << info.duration << " Seconds" << std::endl; + *out << "--> File Size: " << double(info.file_size) / 1024 / 1024 << " MB" << std::endl; + *out << "----------------------------" << std::endl; + *out << "----- Video Attributes -----" << std::endl; + *out << "----------------------------" << std::endl; + *out << "--> Width: " << info.width << std::endl; + *out << "--> Height: " << info.height << std::endl; + *out << "--> Pixel Format: " << info.pixel_format << std::endl; + *out << "--> Frames Per Second: " << info.fps.ToDouble() << " (" << info.fps.num << "/" << info.fps.den << ")" << std::endl; + *out << "--> Video Bit Rate: " << info.video_bit_rate/1000 << " kb/s" << std::endl; + *out << "--> Pixel Ratio: " << info.pixel_ratio.ToDouble() << " (" << info.pixel_ratio.num << "/" << info.pixel_ratio.den << ")" << std::endl; + *out << "--> Display Aspect Ratio: " << info.display_ratio.ToDouble() << " (" << info.display_ratio.num << "/" << info.display_ratio.den << ")" << std::endl; + *out << "--> Video Codec: " << info.vcodec << std::endl; + *out << "--> Video Length: " << info.video_length << " Frames" << std::endl; + *out << "--> Video Stream Index: " << info.video_stream_index << std::endl; + *out << "--> Video Timebase: " << info.video_timebase.ToDouble() << " (" << info.video_timebase.num << "/" << info.video_timebase.den << ")" << std::endl; + *out << "--> Interlaced: " << info.interlaced_frame << std::endl; + *out << "--> Interlaced: Top Field First: " << info.top_field_first << std::endl; + *out << "----------------------------" << std::endl; + *out << "----- Audio Attributes -----" << std::endl; + *out << "----------------------------" << std::endl; + *out << "--> Audio Codec: " << info.acodec << std::endl; + *out << "--> Audio Bit Rate: " << info.audio_bit_rate/1000 << " kb/s" << std::endl; + *out << "--> Sample Rate: " << info.sample_rate << " Hz" << std::endl; + *out << "--> # of Channels: " << info.channels << std::endl; + *out << "--> Channel Layout: " << info.channel_layout << std::endl; + *out << "--> Audio Stream Index: " << info.audio_stream_index << std::endl; + *out << "--> Audio Timebase: " << info.audio_timebase.ToDouble() << " (" << info.audio_timebase.num << "/" << info.audio_timebase.den << ")" << std::endl; + *out << "----------------------------" << std::endl; + *out << "--------- Metadata ---------" << std::endl; + *out << "----------------------------" << std::endl; // Iterate through metadata for (auto it : info.metadata) - std::cout << "--> " << it.first << ": " << it.second << std::endl; + *out << "--> " << it.first << ": " << it.second << std::endl; } // Generate Json::Value for this object diff --git a/src/ReaderBase.h b/src/ReaderBase.h index 7b7847a8..4d2d3afa 100644 --- a/src/ReaderBase.h +++ b/src/ReaderBase.h @@ -31,11 +31,9 @@ #ifndef OPENSHOT_READER_BASE_H #define OPENSHOT_READER_BASE_H -#include -#include #include -#include -#include +#include + #include "CacheMemory.h" #include "ChannelLayouts.h" #include "ClipBase.h" @@ -120,7 +118,7 @@ namespace openshot virtual void Close() = 0; /// Display file information in the standard output stream (stdout) - void DisplayInfo(); + void DisplayInfo(std::ostream* out=&std::cout); /// Get the cache object used by this reader (note: not all readers use cache) virtual openshot::CacheBase* GetCache() = 0; diff --git a/src/WriterBase.cpp b/src/WriterBase.cpp index fff93988..8faab981 100644 --- a/src/WriterBase.cpp +++ b/src/WriterBase.cpp @@ -28,6 +28,9 @@ * along with OpenShot Library. If not, see . */ +#include +#include + #include "WriterBase.h" #include "Exceptions.h" @@ -100,43 +103,43 @@ void WriterBase::CopyReaderInfo(ReaderBase* reader) } // Display file information -void WriterBase::DisplayInfo() { - std::cout << std::fixed << std::setprecision(2) << std::boolalpha; - std::cout << "----------------------------" << std::endl; - std::cout << "----- File Information -----" << std::endl; - std::cout << "----------------------------" << std::endl; - std::cout << "--> Has Video: " << info.has_video << std::endl; - std::cout << "--> Has Audio: " << info.has_audio << std::endl; - std::cout << "--> Has Single Image: " << info.has_single_image << std::endl; - std::cout << "--> Duration: " << info.duration << " Seconds" << std::endl; - std::cout << "--> File Size: " << double(info.file_size) / 1024 / 1024 << " MB" << std::endl; - std::cout << "----------------------------" << std::endl; - std::cout << "----- Video Attributes -----" << std::endl; - std::cout << "----------------------------" << std::endl; - std::cout << "--> Width: " << info.width << std::endl; - std::cout << "--> Height: " << info.height << std::endl; - std::cout << "--> Pixel Format: " << info.pixel_format << std::endl; - std::cout << "--> Frames Per Second: " << info.fps.ToDouble() << " (" << info.fps.num << "/" << info.fps.den << ")" << std::endl; - std::cout << "--> Video Bit Rate: " << info.video_bit_rate/1000 << " kb/s" << std::endl; - std::cout << "--> Pixel Ratio: " << info.pixel_ratio.ToDouble() << " (" << info.pixel_ratio.num << "/" << info.pixel_ratio.den << ")" << std::endl; - std::cout << "--> Display Aspect Ratio: " << info.display_ratio.ToDouble() << " (" << info.display_ratio.num << "/" << info.display_ratio.den << ")" << std::endl; - std::cout << "--> Video Codec: " << info.vcodec << std::endl; - std::cout << "--> Video Length: " << info.video_length << " Frames" << std::endl; - std::cout << "--> Video Stream Index: " << info.video_stream_index << std::endl; - std::cout << "--> Video Timebase: " << info.video_timebase.ToDouble() << " (" << info.video_timebase.num << "/" << info.video_timebase.den << ")" << std::endl; - std::cout << "--> Interlaced: " << info.interlaced_frame << std::endl; - std::cout << "--> Interlaced: Top Field First: " << info.top_field_first << std::endl; - std::cout << "----------------------------" << std::endl; - std::cout << "----- Audio Attributes -----" << std::endl; - std::cout << "----------------------------" << std::endl; - std::cout << "--> Audio Codec: " << info.acodec << std::endl; - std::cout << "--> Audio Bit Rate: " << info.audio_bit_rate/1000 << " kb/s" << std::endl; - std::cout << "--> Sample Rate: " << info.sample_rate << " Hz" << std::endl; - std::cout << "--> # of Channels: " << info.channels << std::endl; - std::cout << "--> Channel Layout: " << info.channel_layout << std::endl; - std::cout << "--> Audio Stream Index: " << info.audio_stream_index << std::endl; - std::cout << "--> Audio Timebase: " << info.audio_timebase.ToDouble() << " (" << info.audio_timebase.num << "/" << info.audio_timebase.den << ")" << std::endl; - std::cout << "----------------------------" << std::endl; +void WriterBase::DisplayInfo(std::ostream* out) { + *out << std::fixed << std::setprecision(2) << std::boolalpha; + *out << "----------------------------" << std::endl; + *out << "----- File Information -----" << std::endl; + *out << "----------------------------" << std::endl; + *out << "--> Has Video: " << info.has_video << std::endl; + *out << "--> Has Audio: " << info.has_audio << std::endl; + *out << "--> Has Single Image: " << info.has_single_image << std::endl; + *out << "--> Duration: " << info.duration << " Seconds" << std::endl; + *out << "--> File Size: " << double(info.file_size) / 1024 / 1024 << " MB" << std::endl; + *out << "----------------------------" << std::endl; + *out << "----- Video Attributes -----" << std::endl; + *out << "----------------------------" << std::endl; + *out << "--> Width: " << info.width << std::endl; + *out << "--> Height: " << info.height << std::endl; + *out << "--> Pixel Format: " << info.pixel_format << std::endl; + *out << "--> Frames Per Second: " << info.fps.ToDouble() << " (" << info.fps.num << "/" << info.fps.den << ")" << std::endl; + *out << "--> Video Bit Rate: " << info.video_bit_rate/1000 << " kb/s" << std::endl; + *out << "--> Pixel Ratio: " << info.pixel_ratio.ToDouble() << " (" << info.pixel_ratio.num << "/" << info.pixel_ratio.den << ")" << std::endl; + *out << "--> Display Aspect Ratio: " << info.display_ratio.ToDouble() << " (" << info.display_ratio.num << "/" << info.display_ratio.den << ")" << std::endl; + *out << "--> Video Codec: " << info.vcodec << std::endl; + *out << "--> Video Length: " << info.video_length << " Frames" << std::endl; + *out << "--> Video Stream Index: " << info.video_stream_index << std::endl; + *out << "--> Video Timebase: " << info.video_timebase.ToDouble() << " (" << info.video_timebase.num << "/" << info.video_timebase.den << ")" << std::endl; + *out << "--> Interlaced: " << info.interlaced_frame << std::endl; + *out << "--> Interlaced: Top Field First: " << info.top_field_first << std::endl; + *out << "----------------------------" << std::endl; + *out << "----- Audio Attributes -----" << std::endl; + *out << "----------------------------" << std::endl; + *out << "--> Audio Codec: " << info.acodec << std::endl; + *out << "--> Audio Bit Rate: " << info.audio_bit_rate/1000 << " kb/s" << std::endl; + *out << "--> Sample Rate: " << info.sample_rate << " Hz" << std::endl; + *out << "--> # of Channels: " << info.channels << std::endl; + *out << "--> Channel Layout: " << info.channel_layout << std::endl; + *out << "--> Audio Stream Index: " << info.audio_stream_index << std::endl; + *out << "--> Audio Timebase: " << info.audio_timebase.ToDouble() << " (" << info.audio_timebase.num << "/" << info.audio_timebase.den << ")" << std::endl; + *out << "----------------------------" << std::endl; } // Generate JSON string of this object diff --git a/src/WriterBase.h b/src/WriterBase.h index d18f329d..3939ca6e 100644 --- a/src/WriterBase.h +++ b/src/WriterBase.h @@ -32,7 +32,7 @@ #define OPENSHOT_WRITER_BASE_H #include -#include + #include "ChannelLayouts.h" #include "Fraction.h" #include "Frame.h" @@ -113,7 +113,7 @@ namespace openshot void SetJsonValue(const Json::Value root); ///< Load Json::Value into this object /// Display file information in the standard output stream (stdout) - void DisplayInfo(); + void DisplayInfo(std::ostream* out=&std::cout); /// Open the writer (and start initializing streams) virtual void Open() = 0; diff --git a/tests/FFmpegReader.cpp b/tests/FFmpegReader.cpp index 217d601c..747ae0e2 100644 --- a/tests/FFmpegReader.cpp +++ b/tests/FFmpegReader.cpp @@ -39,7 +39,6 @@ #include "Timeline.h" #include "Json.h" -using namespace std; using namespace openshot; TEST_CASE( "Invalid_Path", "[libopenshot][ffmpegreader]" ) @@ -51,7 +50,7 @@ TEST_CASE( "Invalid_Path", "[libopenshot][ffmpegreader]" ) TEST_CASE( "GetFrame_Before_Opening", "[libopenshot][ffmpegreader]" ) { // Create a reader - stringstream path; + std::stringstream path; path << TEST_MEDIA_PATH << "piano.wav"; FFmpegReader r(path.str()); @@ -62,7 +61,7 @@ TEST_CASE( "GetFrame_Before_Opening", "[libopenshot][ffmpegreader]" ) TEST_CASE( "Check_Audio_File", "[libopenshot][ffmpegreader]" ) { // Create a reader - stringstream path; + std::stringstream path; path << TEST_MEDIA_PATH << "piano.wav"; FFmpegReader r(path.str()); r.Open(); @@ -92,7 +91,7 @@ TEST_CASE( "Check_Audio_File", "[libopenshot][ffmpegreader]" ) TEST_CASE( "Check_Video_File", "[libopenshot][ffmpegreader]" ) { // Create a reader - stringstream path; + std::stringstream path; path << TEST_MEDIA_PATH << "test.mp4"; FFmpegReader r(path.str()); r.Open(); @@ -138,7 +137,7 @@ TEST_CASE( "Check_Video_File", "[libopenshot][ffmpegreader]" ) TEST_CASE( "Seek", "[libopenshot][ffmpegreader]" ) { // Create a reader - stringstream path; + std::stringstream path; path << TEST_MEDIA_PATH << "sintel_trailer-720p.mp4"; FFmpegReader r(path.str()); r.Open(); @@ -195,7 +194,7 @@ TEST_CASE( "Seek", "[libopenshot][ffmpegreader]" ) TEST_CASE( "Frame_Rate", "[libopenshot][ffmpegreader]" ) { // Create a reader - stringstream path; + std::stringstream path; path << TEST_MEDIA_PATH << "sintel_trailer-720p.mp4"; FFmpegReader r(path.str()); r.Open(); @@ -211,7 +210,7 @@ TEST_CASE( "Frame_Rate", "[libopenshot][ffmpegreader]" ) TEST_CASE( "Multiple_Open_and_Close", "[libopenshot][ffmpegreader]" ) { // Create a reader - stringstream path; + std::stringstream path; path << TEST_MEDIA_PATH << "sintel_trailer-720p.mp4"; FFmpegReader r(path.str()); r.Open(); @@ -247,7 +246,7 @@ TEST_CASE( "Multiple_Open_and_Close", "[libopenshot][ffmpegreader]" ) TEST_CASE( "verify parent Timeline", "[libopenshot][ffmpegreader]" ) { // Create a reader - stringstream path; + std::stringstream path; path << TEST_MEDIA_PATH << "sintel_trailer-720p.mp4"; FFmpegReader r(path.str()); r.Open(); @@ -273,3 +272,34 @@ TEST_CASE( "verify parent Timeline", "[libopenshot][ffmpegreader]" ) CHECK(r.GetFrame(1)->GetImage()->width() == 640); CHECK(r.GetFrame(1)->GetImage()->height() == 360); } + +TEST_CASE( "DisplayInfo", "[libopenshot][ffmpegreader]" ) +{ + // Create a reader + std::stringstream path; + path << TEST_MEDIA_PATH << "sintel_trailer-720p.mp4"; + FFmpegReader r(path.str()); + r.Open(); + + std::string expected(R"(---------------------------- +----- File Information ----- +---------------------------- +--> Has Video: true +--> Has Audio: true +--> Has Single Image: false +--> Duration: 51.95 Seconds +--> File Size: 7.26 MB +---------------------------- +----- Video Attributes ----- +---------------------------- +--> Width: 1280 +--> Height: 720)"); + + // Store the DisplayInfo() text in 'output' + std::stringstream output; + r.DisplayInfo(&output); + + // Compare a [0, expected.size()) substring of output to expected + auto compare_value = output.str().compare(0, expected.size(), expected); + CHECK(compare_value == 0); +} diff --git a/tests/FFmpegWriter.cpp b/tests/FFmpegWriter.cpp index 059bbb4d..adb555b2 100644 --- a/tests/FFmpegWriter.cpp +++ b/tests/FFmpegWriter.cpp @@ -45,7 +45,7 @@ using namespace openshot; TEST_CASE( "Webm", "[libopenshot][ffmpegwriter]" ) { // Reader - stringstream path; + std::stringstream path; path << TEST_MEDIA_PATH << "sintel_trailer-720p.mp4"; FFmpegReader r(path.str()); r.Open(); @@ -92,7 +92,7 @@ TEST_CASE( "Webm", "[libopenshot][ffmpegwriter]" ) TEST_CASE( "Options_Overloads", "[libopenshot][ffmpegwriter]" ) { // Reader - stringstream path; + std::stringstream path; path << TEST_MEDIA_PATH << "sintel_trailer-720p.mp4"; FFmpegReader r(path.str()); r.Open(); @@ -129,3 +129,76 @@ TEST_CASE( "Options_Overloads", "[libopenshot][ffmpegwriter]" ) CHECK_FALSE(r1.info.interlaced_frame); CHECK(r1.info.top_field_first == true); } + + +TEST_CASE( "DisplayInfo", "[libopenshot][ffmpegwriter]" ) +{ + // Reader + std::stringstream path; + path << TEST_MEDIA_PATH << "sintel_trailer-720p.mp4"; + FFmpegReader r(path.str()); + r.Open(); + + /* WRITER ---------------- */ + FFmpegWriter w("output1.webm"); + + // Set options + w.SetAudioOptions(true, "libvorbis", 44100, 2, LAYOUT_STEREO, 188000); + w.SetVideoOptions( + true, "libvpx", + Fraction(24,1), + 1280, 720, + Fraction(1,1), + false, false, + 30000000); + + // Open writer + w.Open(); + + std::string expected( + R"(---------------------------- +----- File Information ----- +---------------------------- +--> Has Video: true +--> Has Audio: true +--> Has Single Image: false +--> Duration: 0.00 Seconds +--> File Size: 0.00 MB +---------------------------- +----- Video Attributes ----- +---------------------------- +--> Width: 1280 +--> Height: 720 +--> Pixel Format: -1 +--> Frames Per Second: 24.00 (24/1) +--> Video Bit Rate: 30000 kb/s +--> Pixel Ratio: 1.00 (1/1) +--> Display Aspect Ratio: 1.78 (16/9) +--> Video Codec: libvpx +--> Video Length: 0 Frames +--> Video Stream Index: -1 +--> Video Timebase: 0.04 (1/24) +--> Interlaced: false +--> Interlaced: Top Field First: false +---------------------------- +----- Audio Attributes ----- +---------------------------- +--> Audio Codec: libvorbis +--> Audio Bit Rate: 188 kb/s +--> Sample Rate: 44100 Hz +--> # of Channels: 2 +--> Channel Layout: 3 +--> Audio Stream Index: -1 +--> Audio Timebase: 1.00 (1/1) +----------------------------)"); + + // Store the DisplayInfo() text in 'output' + std::stringstream output; + w.DisplayInfo(&output); + + w.Close(); + + // Compare a [0, expected.size()) substring of output to expected + auto compare_value = output.str().compare(0, expected.size(), expected); + CHECK(compare_value == 0); +} diff --git a/tests/Fraction.cpp b/tests/Fraction.cpp index 8736abaf..57d37a79 100644 --- a/tests/Fraction.cpp +++ b/tests/Fraction.cpp @@ -32,6 +32,10 @@ #include "Fraction.h" +#include +#include +#include + using namespace std; using namespace openshot; @@ -148,3 +152,12 @@ TEST_CASE( "Reciprocal", "[libopenshot][fraction]" ) CHECK(f1.ToFloat() == Approx(1.77777f).margin(0.00001)); CHECK(f1.ToDouble() == Approx(1.77777f).margin(0.00001)); } + +TEST_CASE( "Operator ostream", "[libopenshot][fraction]" ) +{ + std::stringstream output; + openshot::Fraction f3(30000, 1001); + + output << f3; + CHECK(output.str() == "Fraction(30000, 1001)"); +} diff --git a/tests/FrameMapper.cpp b/tests/FrameMapper.cpp index 20ca76e8..fc1f70d4 100644 --- a/tests/FrameMapper.cpp +++ b/tests/FrameMapper.cpp @@ -191,7 +191,7 @@ TEST_CASE( "30_fps_to_24_fps_Pulldown_None", "[libopenshot][framemapper]" ) TEST_CASE( "resample_audio_48000_to_41000", "[libopenshot][framemapper]" ) { - // Create a reader: 24 fps, 2 channels, 48000 sample rate + // Create a reader std::stringstream path; path << TEST_MEDIA_PATH << "sintel_trailer-720p.mp4"; FFmpegReader r(path.str()); @@ -619,6 +619,42 @@ TEST_CASE( "Distribute samples", "[libopenshot][framemapper]" ) { } // for rates } +TEST_CASE( "PrintMapping", "[libopenshot][framemapper]" ) +{ + const std::string expected( + R"(Target frame #: 1 mapped to original frame #: (1 odd, 1 even) + - Audio samples mapped to frame 1:0 to frame 1:1599 +Target frame #: 2 mapped to original frame #: (2 odd, 2 even) + - Audio samples mapped to frame 1:1600 to frame 2:1199 +Target frame #: 3 mapped to original frame #: (2 odd, 3 even) + - Audio samples mapped to frame 2:1200 to frame 3:799 +Target frame #: 4 mapped to original frame #: (3 odd, 4 even) + - Audio samples mapped to frame 3:800 to frame 4:399 +Target frame #: 5 mapped to original frame #: (4 odd, 4 even) + - Audio samples mapped to frame 4:400 to frame 4:1999 +Target frame #: 6 mapped to original frame #: (5 odd, 5 even) + - Audio samples mapped to frame 5:0 to frame 5:1599 +Target frame #: 7 mapped to original frame #: (6 odd, 6 even) + - Audio samples mapped to frame 5:1600 to frame 6:1199 +Target frame #: 8 mapped to original frame #: (6 odd, 7 even) + - Audio samples mapped to frame 6:1200 to frame 7:799 +Target frame #: 9 mapped to original frame #: (7 odd, 8 even) + - Audio samples mapped to frame 7:800 to frame 8:399 +Target frame #: 10 mapped to original frame #: (8 odd, 8 even) + - Audio samples mapped to frame 8:400 to frame 8:1999)"); + + DummyReader r(Fraction(24,1), 720, 480, 48000, 2, 5.0); + // Create mapping 24 fps and 30 fps + FrameMapper mapping( + &r, Fraction(30, 1), PULLDOWN_CLASSIC, 48000, 2, LAYOUT_STEREO); + std::stringstream mapping_out; + mapping.PrintMapping(&mapping_out); + + // Compare a [0, expected.size()) substring of output to expected + auto compare_value = mapping_out.str().compare(0, expected.size(), expected); + CHECK(compare_value == 0); +} + TEST_CASE( "Json", "[libopenshot][framemapper]" ) { DummyReader r(Fraction(30,1), 1280, 720, 48000, 2, 5.0); diff --git a/tests/KeyFrame.cpp b/tests/KeyFrame.cpp index 599c973f..3f186729 100644 --- a/tests/KeyFrame.cpp +++ b/tests/KeyFrame.cpp @@ -516,6 +516,75 @@ TEST_CASE( "std::vector constructor", "[libopenshot][keyframe]" ) CHECK(k1.GetValue(10) == Approx(30.0f).margin(0.0001)); } +TEST_CASE( "PrintPoints", "[libopenshot][keyframe]" ) +{ + std::vector points{ + Point(1, 10), + Point(225, 397), + Point(430, -153.4), + Point(999, 12345.678) + }; + Keyframe k1(points); + + std::stringstream output; + k1.PrintPoints(&output); + + const std::string expected = +R"( 1 10.0000 + 225 397.0000 + 430 -153.4000 + 999 12345.6777)"; + + // Ensure the two strings are equal up to the limits of 'expected' + CHECK(output.str().compare(0, expected.size(), expected) == 0); +} + +TEST_CASE( "PrintValues", "[libopenshot][keyframe]" ) +{ + std::vector points{ + Point(1, 10), + Point(225, 397), + Point(430, -153.4), + Point(999, 12345.678) + }; + Keyframe k1(points); + + std::stringstream output; + k1.PrintValues(&output); + + const std::string expected = +R"(│Frame# (X) │ Y Value │ Delta Y │ Increasing? │ Repeat Fraction │ +├───────────┼─────────────┼─────────┼─────────────┼────────────────────┤ +│ 1 * │ 10.0000 │ +10 │ true │ Fraction(1, 7) │ +│ 2 │ 10.0104 │ +0 │ true │ Fraction(2, 7) │ +│ 3 │ 10.0414 │ +0 │ true │ Fraction(3, 7) │ +│ 4 │ 10.0942 │ +0 │ true │ Fraction(4, 7) │ +│ 5 │ 10.1665 │ +0 │ true │ Fraction(5, 7) │ +│ 6 │ 10.2633 │ +0 │ true │ Fraction(6, 7) │ +│ 7 │ 10.3794 │ +0 │ true │ Fraction(7, 7) │ +│ 8 │ 10.5193 │ +1 │ true │ Fraction(1, 5) │ +│ 9 │ 10.6807 │ +0 │ true │ Fraction(2, 5) │ +│ 10 │ 10.8636 │ +0 │ true │ Fraction(3, 5) │ +│ 11 │ 11.0719 │ +0 │ true │ Fraction(4, 5) │ +│ 12 │ 11.3021 │ +0 │ true │ Fraction(5, 5) │ +│ 13 │ 11.5542 │ +1 │ true │ Fraction(1, 4) │ +│ 14 │ 11.8334 │ +0 │ true │ Fraction(2, 4) │ +│ 15 │ 12.1349 │ +0 │ true │ Fraction(3, 4) │ +│ 16 │ 12.4587 │ +0 │ true │ Fraction(4, 4) │ +│ 17 │ 12.8111 │ +1 │ true │ Fraction(1, 2) │ +│ 18 │ 13.1863 │ +0 │ true │ Fraction(2, 2) │ +│ 19 │ 13.5840 │ +1 │ true │ Fraction(1, 3) │ +│ 20 │ 14.0121 │ +0 │ true │ Fraction(2, 3) │ +│ 21 │ 14.4632 │ +0 │ true │ Fraction(3, 3) │ +│ 22 │ 14.9460 │ +1 │ true │ Fraction(1, 2) │ +│ 23 │ 15.4522 │ +0 │ true │ Fraction(2, 2) │ +│ 24 │ 15.9818 │ +1 │ true │ Fraction(1, 1) │ +│ 25 │ 16.5446 │ +1 │ true │ Fraction(1, 2) │)"; + + // Ensure the two strings are equal up to the limits of 'expected' + CHECK(output.str().compare(0, expected.size(), expected) == 0); +} + #ifdef USE_OPENCV TEST_CASE( "TrackedObjectBBox init", "[libopenshot][keyframe]" ) { @@ -735,4 +804,4 @@ TEST_CASE( "GetBoxValues", "[libopenshot][keyframe]" ) CHECK(boxValues["h"] == 20.0); CHECK(boxValues["ang"] == 30.0); } -#endif \ No newline at end of file +#endif diff --git a/tests/Point.cpp b/tests/Point.cpp index 6d53f65b..57cff7c7 100644 --- a/tests/Point.cpp +++ b/tests/Point.cpp @@ -52,7 +52,7 @@ TEST_CASE( "default constructor", "[libopenshot][point]" ) CHECK(p.interpolation == openshot::InterpolationType::BEZIER); CHECK(p.handle_type == openshot::HandleType::AUTO); } -TEST_CASE( "XY constructor", "[libopenshot][point]" ) +TEST_CASE( "x,y ctor", "[libopenshot][point]" ) { // Create a point with X and Y values openshot::Point p1(2,9); @@ -62,7 +62,7 @@ TEST_CASE( "XY constructor", "[libopenshot][point]" ) CHECK(p1.interpolation == openshot::InterpolationType::BEZIER); } -TEST_CASE( "std::pair constructor", "[libopenshot][point]" ) +TEST_CASE( "std::pair ctor", "[libopenshot][point]" ) { // Create a point from a std::pair std::pair coordinates(22, 5); @@ -72,7 +72,7 @@ TEST_CASE( "std::pair constructor", "[libopenshot][point]" ) CHECK(p1.co.Y == Approx(5.0f).margin(0.00001)); } -TEST_CASE( "constructor from Coordinate", "[libopenshot][point]" ) +TEST_CASE( "Coordinate ctor", "[libopenshot][point]" ) { // Create a point with a coordinate openshot::Coordinate c1(3,7); @@ -83,7 +83,7 @@ TEST_CASE( "constructor from Coordinate", "[libopenshot][point]" ) CHECK(p1.interpolation == openshot::InterpolationType::BEZIER); } -TEST_CASE( "constructor from Coordinate, LINEAR", "[libopenshot][point]" ) +TEST_CASE( "Coordinate ctor, LINEAR", "[libopenshot][point]" ) { // Create a point with a coordinate and interpolation openshot::Coordinate c1(3,9); @@ -95,7 +95,7 @@ TEST_CASE( "constructor from Coordinate, LINEAR", "[libopenshot][point]" ) CHECK(p1.interpolation == openshot::InterpolationType::LINEAR); } -TEST_CASE( "constructor from Coordinate, BEZIER", "[libopenshot][point]" ) +TEST_CASE( "Coordinate ctor, BEZIER", "[libopenshot][point]" ) { // Create a point with a coordinate and interpolation openshot::Coordinate c1(3,9); @@ -107,7 +107,7 @@ TEST_CASE( "constructor from Coordinate, BEZIER", "[libopenshot][point]" ) CHECK(p1.interpolation == openshot::InterpolationType::BEZIER); } -TEST_CASE( "constructor from Coordinate, CONSTANT", "[libopenshot][point]" ) +TEST_CASE( "Coordinate ctor, CONSTANT", "[libopenshot][point]" ) { // Create a point with a coordinate and interpolation openshot::Coordinate c1(2,8); @@ -119,7 +119,7 @@ TEST_CASE( "constructor from Coordinate, CONSTANT", "[libopenshot][point]" ) CHECK(p1.interpolation == openshot::InterpolationType::CONSTANT); } -TEST_CASE( "constructor from Coordinate, BEZIER+AUTO", "[libopenshot][point]" ) +TEST_CASE( "Coordinate ctor, BEZIER+AUTO", "[libopenshot][point]" ) { // Create a point with a coordinate and interpolation openshot::Coordinate c1(3,9); @@ -133,7 +133,7 @@ TEST_CASE( "constructor from Coordinate, BEZIER+AUTO", "[libopenshot][point]" ) CHECK(p1.handle_type == openshot::HandleType::AUTO); } -TEST_CASE( "constructor from Coordinate, BEZIER+MANUAL", "[libopenshot][point]" ) +TEST_CASE( "Coordinate ctor, BEZIER+MANUAL", "[libopenshot][point]" ) { // Create a point with a coordinate and interpolation openshot::Coordinate c1(3,9); @@ -188,3 +188,24 @@ TEST_CASE( "SetJson", "[libopenshot][point]" ) CHECK(p1.handle_type == openshot::HandleType::MANUAL); CHECK(p1.interpolation == openshot::InterpolationType::CONSTANT); } + + +TEST_CASE( "Operator ostream", "[libopenshot][point]" ) +{ + openshot::Coordinate c1(10, 5); + + std::stringstream output1; + openshot::Point p1(c1, openshot::InterpolationType::LINEAR); + output1 << p1; + CHECK(output1.str() == "co(10, 5) LINEAR"); + + std::stringstream output2; + openshot::Point p2(c1, openshot::InterpolationType::CONSTANT); + output2 << p2; + CHECK(output2.str() == "co(10, 5) CONSTANT"); + + std::stringstream output3; + openshot::Point p3(c1, openshot::InterpolationType::BEZIER); + output3 << p3; + CHECK(output3.str() == "co(10, 5) BEZIER[L(0.5, 1),R(0.5, 0)]"); +} diff --git a/tests/ReaderBase.cpp b/tests/ReaderBase.cpp index 94880e00..d071d36d 100644 --- a/tests/ReaderBase.cpp +++ b/tests/ReaderBase.cpp @@ -42,7 +42,7 @@ using namespace openshot; // Since it is not possible to instantiate an abstract class, this test creates // a new derived class, in order to test the base class file info struct. -TEST_CASE( "ReaderBase_Derived_Class", "[libopenshot][readerbase]" ) +TEST_CASE( "derived class", "[libopenshot][readerbase]" ) { // Create a new derived class from type ReaderBase class TestReader : public ReaderBase