Improved Profile Class (Helper methods, Sortable, Unit tests) (#895)

* Removing legacy profile property. Add new operators for Profile classes (for comparison). Also added new functions to generate different variations of the Profile data (key, short name, long name, long name w/description).

* Add empty constructor for Profile class, and new Profile unit tets

* Adding zero padding to profile Key function, for easier sorting: 01920x1080i2997_16:09

* Clear setfill flag after creating Key() output

* Updating example exe to load an *.osp project file via C++, which makes debugging complex broken projects much easier.

* - Add new unit test to FFmpegWriter to create an animated GIF and verify it can be wrapped with a FrameMapper (with no audio track)
- Improve FrameMapper to ignore missing audio data (i.e. when no audio samples present, don't try and find them or resample them)

* Fix some whitespace issues

* Fix inline documentation mistype

* Fixed missing reuse licensing on new example profile files

* Changing Profile::Key() format to exclude the : character, since Windows file names cannot contain that

* - Large memory leak fixed in FFmpegWriter when closing the video & audio contexts
- Reducing # of cached frames and rescalers to 1, since we no longer use OMP and this is unneeded - we need to refactor much of this code out eventually

* - Fixing whitespace issues
- Code clean-up / line wrapping / etc...
This commit is contained in:
Jonathan Thomas
2023-02-02 16:29:38 -06:00
committed by GitHub
parent 510a7690f6
commit 70e86ef044
11 changed files with 1064 additions and 647 deletions

View File

@@ -3,7 +3,7 @@ Upstream-Name: libopenshot
Upstream-Contact: Jonathan Thomas <jonathan@openshot.org>
Source: https://github.com/OpenShot/libopenshot
Files: examples/*.png examples/*.svg examples/*.wav examples/*.mp4 examples/*.avi doc/images/*
Files: examples/*.png examples/*.svg examples/*.wav examples/*.mp4 examples/* doc/images/*
Copyright: OpenShot Studios, LLC
License: LGPL-3.0-or-later

View File

@@ -13,25 +13,56 @@
#include <fstream>
#include <iostream>
#include <memory>
#include <QFileDialog>
#include "Clip.h"
#include "Frame.h"
#include "FFmpegReader.h"
#include "Timeline.h"
#include "Profiles.h"
using namespace openshot;
int main(int argc, char* argv[]) {
// FFmpeg Reader performance test
FFmpegReader r9("/home/jonathan/Downloads/pts-test-files/broken-files/lady-talking-1.mp4");
r9.Open();
for (long int frame = 1; frame <= r9.info.video_length; frame++)
{
std::cout << "Requesting Frame: #: " << frame << std::endl;
std::shared_ptr<Frame> f = r9.GetFrame(frame);
QString filename = "/home/jonathan/test-crash.osp";
//QString filename = "/home/jonathan/Downloads/drive-download-20221123T185423Z-001/project-3363/project-3363.osp";
//QString filename = "/home/jonathan/Downloads/drive-download-20221123T185423Z-001/project-3372/project-3372.osp";
//QString filename = "/home/jonathan/Downloads/drive-download-20221123T185423Z-001/project-3512/project-3512.osp";
QString project_json = "";
QFile file(filename);
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
std::cout << "File error!" << std::endl;
exit(1);
} else {
while (!file.atEnd()) {
QByteArray line = file.readLine();
project_json += line;
}
}
r9.Close();
// Open timeline reader
std::cout << "Project JSON length: " << project_json.length() << std::endl;
Timeline r(1280, 720, openshot::Fraction(30, 1), 44100, 2, openshot::LAYOUT_STEREO);
r.SetJson(project_json.toStdString());
r.DisplayInfo();
r.Open();
// Get max frame
int64_t max_frame = r.GetMaxFrame();
std::cout << "max_frame: " << max_frame << ", r.info.video_length: " << r.info.video_length << std::endl;
for (long int frame = 1; frame <= max_frame; frame++)
{
float percent = (float(frame) / max_frame) * 100.0;
std::cout << "Requesting Frame #: " << frame << " (" << percent << "%)" << std::endl;
std::shared_ptr<Frame> f = r.GetFrame(frame);
// Preview frame image
if (frame % 1 == 0) {
f->Save("preview.jpg", 1.0, "jpg", 100);
}
}
r.Close();
exit(0);
}

11
examples/example_profile1 Normal file
View File

@@ -0,0 +1,11 @@
description=HD 720p 24 fps
frame_rate_num=24
frame_rate_den=1
width=1280
height=720
progressive=1
sample_aspect_num=1
sample_aspect_den=1
display_aspect_num=16
display_aspect_den=9
colorspace=709

11
examples/example_profile2 Normal file
View File

@@ -0,0 +1,11 @@
description=HD 1080i 29.97 fps
frame_rate_num=30000
frame_rate_den=1001
width=1920
height=1080
progressive=0
sample_aspect_num=1
sample_aspect_den=1
display_aspect_num=16
display_aspect_den=9
colorspace=709

File diff suppressed because it is too large Load Diff

View File

@@ -41,6 +41,9 @@ FrameMapper::FrameMapper(ReaderBase *reader, Fraction target, PulldownType targe
info.width = reader->info.width;
info.height = reader->info.height;
// Enable/Disable audio (based on settings)
info.has_audio = info.sample_rate > 0 && info.channels > 0;
// Used to toggle odd / even fields
field_toggle = true;
@@ -60,11 +63,11 @@ FrameMapper::~FrameMapper() {
/// Get the current reader
ReaderBase* FrameMapper::Reader()
{
if (reader)
return reader;
else
// Throw error if reader not initialized
throw ReaderClosed("No Reader has been initialized for FrameMapper. Call Reader(*reader) before calling this method.");
if (reader)
return reader;
else
// Throw error if reader not initialized
throw ReaderClosed("No Reader has been initialized for FrameMapper. Call Reader(*reader) before calling this method.");
}
void FrameMapper::AddField(int64_t frame)
@@ -84,14 +87,14 @@ void FrameMapper::AddField(Field field)
// Clear both the fields & frames lists
void FrameMapper::Clear() {
// Prevent async calls to the following code
const std::lock_guard<std::recursive_mutex> lock(getFrameMutex);
// Prevent async calls to the following code
const std::lock_guard<std::recursive_mutex> lock(getFrameMutex);
// Clear the fields & frames lists
fields.clear();
fields.shrink_to_fit();
frames.clear();
frames.shrink_to_fit();
// Clear the fields & frames lists
fields.clear();
fields.shrink_to_fit();
frames.clear();
frames.shrink_to_fit();
}
// Use the original and target frame rates and a pull-down technique to create
@@ -114,14 +117,14 @@ void FrameMapper::Init()
Clear();
// Find parent position (if any)
Clip *parent = (Clip *) ParentClip();
if (parent) {
parent_position = parent->Position();
parent_start = parent->Start();
} else {
parent_position = 0.0;
parent_start = 0.0;
}
Clip *parent = (Clip *) ParentClip();
if (parent) {
parent_position = parent->Position();
parent_start = parent->Start();
} else {
parent_position = 0.0;
parent_start = 0.0;
}
// Mark as not dirty
is_dirty = false;
@@ -419,19 +422,19 @@ std::shared_ptr<Frame> FrameMapper::GetFrame(int64_t requested_frame)
// Create a scoped lock, allowing only a single thread to run the following code at one time
const std::lock_guard<std::recursive_mutex> lock(getFrameMutex);
// Find parent properties (if any)
Clip *parent = (Clip *) ParentClip();
if (parent) {
float position = parent->Position();
float start = parent->Start();
if (parent_position != position || parent_start != start) {
// Force dirty if parent clip has moved or been trimmed
// since this heavily affects frame #s and audio mappings
is_dirty = true;
}
}
// Find parent properties (if any)
Clip *parent = (Clip *) ParentClip();
if (parent) {
float position = parent->Position();
float start = parent->Start();
if (parent_position != position || parent_start != start) {
// Force dirty if parent clip has moved or been trimmed
// since this heavily affects frame #s and audio mappings
is_dirty = true;
}
}
// Check if mappings are dirty (and need to be recalculated)
// Check if mappings are dirty (and need to be recalculated)
if (is_dirty)
Init();
@@ -513,9 +516,12 @@ std::shared_ptr<Frame> FrameMapper::GetFrame(int64_t requested_frame)
std::make_shared<QImage>(*even_frame->GetImage()), false);
}
// Determine if reader contains audio samples
bool reader_has_audio = frame->SampleRate() > 0 && frame->GetAudioChannelsCount() > 0;
// Resample audio on frame (if needed)
bool need_resampling = false;
if (info.has_audio &&
if ((info.has_audio && reader_has_audio) &&
(info.sample_rate != frame->SampleRate() ||
info.channels != frame->GetAudioChannelsCount() ||
info.channel_layout != frame->ChannelsLayout()))
@@ -537,7 +543,7 @@ std::shared_ptr<Frame> 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
@@ -553,7 +559,7 @@ std::shared_ptr<Frame> 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
@@ -643,15 +649,15 @@ void FrameMapper::PrintMapping(std::ostream* out)
{
MappedFrame frame = frames[map - 1];
*out << "Target frame #: " << map
<< " mapped to original frame #:\t("
<< frame.Odd.Frame << " odd, "
<< frame.Even.Frame << " even)" << std::endl;
<< " 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;
<< frame.Samples.frame_start << ":"
<< frame.Samples.sample_start << " to frame "
<< frame.Samples.frame_end << ":"
<< frame.Samples.sample_end << endl;
}
}
@@ -690,21 +696,21 @@ void FrameMapper::Close()
reader->Close();
}
// Clear the fields & frames lists
Clear();
// Clear the fields & frames lists
Clear();
// Mark as dirty
is_dirty = true;
// Mark as dirty
is_dirty = true;
// Clear cache
final_cache.Clear();
// Clear cache
final_cache.Clear();
// Deallocate resample buffer
if (avr) {
SWR_CLOSE(avr);
SWR_FREE(&avr);
avr = NULL;
}
// Deallocate resample buffer
if (avr) {
SWR_CLOSE(avr);
SWR_FREE(&avr);
avr = NULL;
}
}
@@ -785,6 +791,9 @@ void FrameMapper::ChangeMapping(Fraction target_fps, PulldownType target_pulldow
info.channels = target_channels;
info.channel_layout = target_channel_layout;
// Enable/Disable audio (based on settings)
info.has_audio = info.sample_rate > 0 && info.channels > 0;
// Clear cache
final_cache.Clear();
@@ -913,28 +922,28 @@ void FrameMapper::ResampleMappedAudio(std::shared_ptr<Frame> frame, int64_t orig
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);
SWR_INIT(avr);
}
// 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);
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
// 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
// Create a new array (to hold all resampled S16 audio samples)
int16_t* resampled_samples = new int16_t[(nb_samples * info.channels)];

View File

@@ -10,11 +10,27 @@
//
// SPDX-License-Identifier: LGPL-3.0-or-later
#include <iomanip>
#include "Profiles.h"
#include "Exceptions.h"
using namespace openshot;
// default constructor
Profile::Profile() {
// Initialize info values
info.description = "";
info.height = 0;
info.width = 0;
info.pixel_format = 0;
info.fps.num = 0;
info.fps.den = 0;
info.pixel_ratio.num = 0;
info.pixel_ratio.den = 0;
info.display_ratio.num = 0;
info.display_ratio.den = 0;
info.interlaced_frame = false;
}
// @brief Constructor for Profile.
// @param path The folder path / location of a profile file
@@ -22,21 +38,11 @@ Profile::Profile(std::string path) {
bool read_file = false;
// Call default constructor
Profile();
try
{
// Initialize info values
info.description = "";
info.height = 0;
info.width = 0;
info.pixel_format = 0;
info.fps.num = 0;
info.fps.den = 0;
info.pixel_ratio.num = 0;
info.pixel_ratio.den = 0;
info.display_ratio.num = 0;
info.display_ratio.den = 0;
info.interlaced_frame = false;
QFile inputFile(path.c_str());
if (inputFile.open(QIODevice::ReadOnly))
{
@@ -55,8 +61,9 @@ Profile::Profile(std::string path) {
int value_int = 0;
// update struct (based on line number)
if (setting == "description")
if (setting == "description") {
info.description = value;
}
else if (setting == "frame_rate_num") {
std::stringstream(value) >> value_int;
info.fps.num = value_int;
@@ -98,7 +105,7 @@ Profile::Profile(std::string path) {
info.pixel_format = value_int;
}
}
read_file = true;
read_file = true;
inputFile.close();
}
@@ -115,6 +122,81 @@ Profile::Profile(std::string path) {
throw InvalidFile("Profile could not be found or loaded (or is invalid).", path);
}
// Return a formatted FPS
std::string Profile::formattedFPS(bool include_decimal) {
// Format FPS to use 2 decimals (if needed)
float fps = info.fps.ToFloat();
std::stringstream fps_string;
if (info.fps.den == 1) {
// For example: 24.0 will become 24
fps_string << std::fixed << std::setprecision(0) << fps;
} else {
// For example: 29.97002997 will become 29.97
fps_string << std::fixed << std::setprecision(2) << fps;
// Remove decimal place using QString (for convenience)
if (!include_decimal) {
QString fps_qstring = QString::fromStdString(fps_string.str());
fps_qstring.replace(".", "");
fps_string.str(fps_qstring.toStdString());
}
}
return fps_string.str();
}
// Return a unique key of this profile (01920x1080i2997_16-09)
std::string Profile::Key() {
std::stringstream output;
std::string progressive_str = "p";
if (info.interlaced_frame) {
progressive_str = "i";
}
std::string fps_string = formattedFPS(false);
output << std::setfill('0') << std::setw(5) << info.width << std::setfill('\0') << "x";
output << std::setfill('0') << std::setw(4) << info.height << std::setfill('\0') << progressive_str;
output << std::setfill('0') << std::setw(4) << fps_string << std::setfill('\0') << "_";
output << std::setfill('0') << std::setw(2) << info.display_ratio.num << std::setfill('\0') << "-";
output << std::setfill('0') << std::setw(2) << info.display_ratio.den << std::setfill('\0');
return output.str();
}
// Return the name of this profile (1920x1080p29.97)
std::string Profile::ShortName() {
std::stringstream output;
std::string progressive_str = "p";
if (info.interlaced_frame) {
progressive_str = "i";
}
std::string fps_string = formattedFPS(true);
output << info.width << "x" << info.height << progressive_str << fps_string;
return output.str();
}
// Return a longer format name (1920x1080p @ 29.97 fps (16:9))
std::string Profile::LongName() {
std::stringstream output;
std::string progressive_str = "p";
if (info.interlaced_frame) {
progressive_str = "i";
}
std::string fps_string = formattedFPS(true);
output << info.width << "x" << info.height << progressive_str << " @ " << fps_string
<< " fps (" << info.display_ratio.num << ":" << info.display_ratio.den << ")";
return output.str();
}
// Return a longer format name (1920x1080p @ 29.97 fps (16:9) HD 1080i 29.97 fps)
std::string Profile::LongNameWithDesc() {
std::stringstream output;
std::string progressive_str = "p";
if (info.interlaced_frame) {
progressive_str = "i";
}
std::string fps_string = formattedFPS(true);
output << info.width << "x" << info.height << progressive_str << " @ " << fps_string
<< " fps (" << info.display_ratio.num << ":" << info.display_ratio.den << ") " << info.description;
return output.str();
}
// Generate JSON string of this object
std::string Profile::Json() const {

View File

@@ -16,6 +16,7 @@
#include <iostream>
#include <string>
#include <sstream>
#include <math.h>
#include <fstream>
#include <QtCore/QString>
#include <QtCore/QStringList>
@@ -62,14 +63,90 @@ namespace openshot
*/
class Profile
{
private:
std::string formattedFPS(bool include_decimal); ///< Return a formatted FPS
/// Less than operator (compare profile objects)
/// Compare # of pixels, then FPS, then DAR
friend bool operator<(const Profile& l, const Profile& r)
{
double left_fps = l.info.fps.ToDouble();
double right_fps = r.info.fps.ToDouble();
double left_pixels = l.info.width * l.info.height;
double right_pixels = r.info.width * r.info.height;
double left_dar = l.info.display_ratio.ToDouble();
double right_dar = r.info.display_ratio.ToDouble();
if (left_pixels < right_pixels) {
// less pixels
return true;
} else {
if (left_fps < right_fps) {
// less FPS
return true;
} else {
if (left_dar < right_dar) {
// less DAR
return true;
} else {
return false;
}
}
}
}
/// Greater than operator (compare profile objects)
/// Compare # of pixels, then FPS, then DAR
friend bool operator>(const Profile& l, const Profile& r)
{
double left_fps = l.info.fps.ToDouble();
double right_fps = r.info.fps.ToDouble();
double left_pixels = l.info.width * l.info.height;
double right_pixels = r.info.width * r.info.height;
double left_dar = l.info.display_ratio.ToDouble();
double right_dar = r.info.display_ratio.ToDouble();
if (left_pixels > right_pixels) {
// less pixels
return true;
} else {
if (left_fps > right_fps) {
// less FPS
return true;
} else {
if (left_dar > right_dar) {
// less DAR
return true;
} else {
return false;
}
}
}
}
/// Equality operator (compare profile objects)
friend bool operator==(const Profile& l, const Profile& r)
{
return std::tie(l.info.width, l.info.height, l.info.fps.num, l.info.fps.den, l.info.display_ratio.num, l.info.display_ratio.den, l.info.interlaced_frame)
== std::tie(r.info.width, r.info.height, r.info.fps.num, r.info.fps.den, r.info.display_ratio.num, r.info.display_ratio.den, r.info.interlaced_frame);
}
public:
/// Profile data stored here
ProfileInfo info;
/// @brief Default Constructor for Profile.
Profile();
/// @brief Constructor for Profile.
/// @param path The folder path / location of a profile file
Profile(std::string path);
std::string Key(); ///< Return a unique key of this profile with padding (01920x1080i2997_16:09)
std::string ShortName(); ///< Return the name of this profile (1920x1080p29.97)
std::string LongName(); ///< Return a longer format name (1920x1080p @ 29.97 fps (16:9))
std::string LongNameWithDesc(); ///< Return a longer format name with description (1920x1080p @ 29.97 fps (16:9) HD 1080i 29.97 fps)
// 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

View File

@@ -35,6 +35,7 @@ set(OPENSHOT_TESTS
FrameMapper
KeyFrame
Point
Profiles
QtImageReader
ReaderBase
Settings

View File

@@ -20,6 +20,7 @@
#include "FFmpegReader.h"
#include "Fraction.h"
#include "Frame.h"
#include "Timeline.h"
using namespace std;
using namespace openshot;
@@ -183,3 +184,52 @@ TEST_CASE( "DisplayInfo", "[libopenshot][ffmpegwriter]" )
// Compare a [0, expected.size()) substring of output to expected
CHECK(output.str().substr(0, expected.size()) == expected);
}
TEST_CASE( "Gif", "[libopenshot][ffmpegwriter]" )
{
// Reader
std::stringstream path;
path << TEST_MEDIA_PATH << "sintel_trailer-720p.mp4";
// Create Gif Clip
Clip clip_video(path.str());
clip_video.Layer(0);
clip_video.Position(0.0);
clip_video.Open();
// Create Timeline w/ 1 Gif Clip (with 0 sample rate, and 0 channels)
openshot::Timeline t(1280, 720, Fraction(30,1), 0, 0, LAYOUT_MONO);
t.AddClip(&clip_video);
t.Open();
/* WRITER ---------------- */
FFmpegWriter w("output1.gif");
// Set options (no audio options are set)
w.SetVideoOptions(true, "gif", Fraction(24,1), 1280, 720, Fraction(1,1), false, false, 15000000);
// Create streams
w.PrepareStreams();
// Open writer
w.Open();
// Write some frames
w.WriteFrame(&t, 1, 60);
// Close writer & reader
w.Close();
t.Close();
FFmpegReader r1("output1.gif");
r1.Open();
// Verify various settings on new Gif
CHECK(r1.GetFrame(1)->GetAudioChannelsCount() == 0);
CHECK(r1.GetFrame(1)->GetAudioSamplesCount() == 0);
CHECK(r1.info.fps.num == 24);
CHECK(r1.info.fps.den == 1);
// Close reader
r1.Close();
}

136
tests/Profiles.cpp Normal file
View File

@@ -0,0 +1,136 @@
/**
* @file
* @brief Unit tests for openshot::Profile
* @author Jonathan Thomas <jonathan@openshot.org>
*
* @ref License
*/
// Copyright (c) 2008-2023 OpenShot Studios, LLC
//
// SPDX-License-Identifier: LGPL-3.0-or-later
#include "openshot_catch.h"
#include "Profiles.h"
TEST_CASE( "empty constructor", "[libopenshot][profile]" )
{
openshot::Profile p1;
// Default values
CHECK(p1.info.width == 0);
CHECK(p1.info.height == 0);
CHECK(p1.info.fps.num == 0);
CHECK(p1.info.fps.den == 0);
CHECK(p1.info.display_ratio.num == 0);
CHECK(p1.info.display_ratio.den == 0);
CHECK(p1.info.pixel_ratio.num == 0);
CHECK(p1.info.pixel_ratio.den == 0);
CHECK(p1.info.interlaced_frame == false);
}
TEST_CASE( "constructor with example profiles", "[libopenshot][profile]" )
{
std::stringstream profile1;
profile1 << TEST_MEDIA_PATH << "example_profile1";
openshot::Profile p1(profile1.str());
// Default values
CHECK(p1.info.width == 1280);
CHECK(p1.info.height == 720);
CHECK(p1.info.fps.num == 24);
CHECK(p1.info.fps.den == 1);
CHECK(p1.info.display_ratio.num == 16);
CHECK(p1.info.display_ratio.den == 9);
CHECK(p1.info.pixel_ratio.num == 1);
CHECK(p1.info.pixel_ratio.den == 1);
CHECK(p1.info.interlaced_frame == false);
std::stringstream profile2;
profile2 << TEST_MEDIA_PATH << "example_profile2";
openshot::Profile p2(profile2.str());
// Default values
CHECK(p2.info.width == 1920);
CHECK(p2.info.height == 1080);
CHECK(p2.info.fps.num == 30000);
CHECK(p2.info.fps.den == 1001);
CHECK(p2.info.display_ratio.num == 16);
CHECK(p2.info.display_ratio.den == 9);
CHECK(p2.info.pixel_ratio.num == 1);
CHECK(p2.info.pixel_ratio.den == 1);
CHECK(p2.info.interlaced_frame == true);
}
TEST_CASE( "24 fps names", "[libopenshot][profile]" )
{
std::stringstream path;
path << TEST_MEDIA_PATH << "example_profile1";
openshot::Profile p(path.str());
// Default values
CHECK(p.Key() == "01280x0720p0024_16-09");
CHECK(p.ShortName() == "1280x720p24");
CHECK(p.LongName() == "1280x720p @ 24 fps (16:9)");
CHECK(p.LongNameWithDesc() == "1280x720p @ 24 fps (16:9) HD 720p 24 fps");
}
TEST_CASE( "29.97 fps names", "[libopenshot][profile]" )
{
std::stringstream path;
path << TEST_MEDIA_PATH << "example_profile2";
openshot::Profile p(path.str());
// Default values
CHECK(p.Key() == "01920x1080i2997_16-09");
CHECK(p.ShortName() == "1920x1080i29.97");
CHECK(p.LongName() == "1920x1080i @ 29.97 fps (16:9)");
CHECK(p.LongNameWithDesc() == "1920x1080i @ 29.97 fps (16:9) HD 1080i 29.97 fps");
}
TEST_CASE( "compare profiles", "[libopenshot][profile]" )
{
// 720p24
std::stringstream profile1;
profile1 << TEST_MEDIA_PATH << "example_profile1";
openshot::Profile p1(profile1.str());
// 720p24 (copy)
openshot::Profile p1copy(profile1.str());
// 1080i2997
std::stringstream profile2;
profile2 << TEST_MEDIA_PATH << "example_profile2";
openshot::Profile p2(profile2.str());
// 1080i2997 (copy)
openshot::Profile p2copy(profile2.str());
CHECK(p1 < p2);
CHECK(p2 > p1);
CHECK(p1 == p1copy);
CHECK(p2 == p2copy);
// 720p60
openshot::Profile p3(profile1.str());
p3.info.fps.num = 60;
CHECK(p1 < p3);
CHECK_FALSE(p1 == p3);
// 72024, DAR: 4:3
p3.info.fps.num = 24;
p3.info.display_ratio.num = 4;
p3.info.display_ratio.den = 3;
CHECK(p1 > p3);
CHECK(p3 < p1);
CHECK_FALSE(p1 == p3);
}