OpenShot Library | libopenshot 0.5.0
Loading...
Searching...
No Matches
Profiles.cpp
Go to the documentation of this file.
1
9// Copyright (c) 2008-2019 OpenShot Studios, LLC
10//
11// SPDX-License-Identifier: LGPL-3.0-or-later
12
13#include <iomanip>
14#include "Profiles.h"
15#include "Exceptions.h"
16
17using namespace openshot;
18
19// default constructor
21 // Initialize info values
22 info.description = "";
23 info.height = 0;
24 info.width = 0;
26 info.fps.num = 0;
27 info.fps.den = 0;
32 info.interlaced_frame = false;
33 info.spherical = false; // Default to non-spherical (regular) video
34}
35
36// @brief Constructor for Profile.
37// @param path The folder path / location of a profile file
38Profile::Profile(std::string path) {
39
40 bool read_file = false;
41
42 // Initialize all values to defaults (same as default constructor)
43 info.description = "";
44 info.height = 0;
45 info.width = 0;
47 info.fps.num = 0;
48 info.fps.den = 0;
53 info.interlaced_frame = false;
54 info.spherical = false; // Default to non-spherical (regular) video
55
56 try
57 {
58 QFile inputFile(path.c_str());
59 if (inputFile.open(QIODevice::ReadOnly))
60 {
61 QTextStream in(&inputFile);
62 while (!in.atEnd())
63 {
64 QString line = in.readLine();
65
66 if (line.length() <= 0)
67 continue;
68
69 // Split current line
70 QStringList parts = line.split( "=" );
71 std::string setting = parts[0].toStdString();
72 std::string value = parts[1].toStdString();
73 int value_int = 0;
74
75 // update struct (based on line number)
76 if (setting == "description") {
77 info.description = value;
78 }
79 else if (setting == "frame_rate_num") {
80 value_int = std::stoi(value);
81 info.fps.num = value_int;
82 }
83 else if (setting == "frame_rate_den") {
84 value_int = std::stoi(value);
85 info.fps.den = value_int;
86 }
87 else if (setting == "width") {
88 value_int = std::stoi(value);
89 info.width = value_int;
90 }
91 else if (setting == "height") {
92 value_int = std::stoi(value);
93 info.height = value_int;
94 }
95 else if (setting == "progressive") {
96 value_int = std::stoi(value);
97 info.interlaced_frame = !(bool)value_int;
98 }
99 else if (setting == "sample_aspect_num") {
100 value_int = std::stoi(value);
101 info.pixel_ratio.num = value_int;
102 }
103 else if (setting == "sample_aspect_den") {
104 value_int = std::stoi(value);
105 info.pixel_ratio.den = value_int;
106 }
107 else if (setting == "display_aspect_num") {
108 value_int = std::stoi(value);
109 info.display_ratio.num = value_int;
110 }
111 else if (setting == "display_aspect_den") {
112 value_int = std::stoi(value);
113 info.display_ratio.den = value_int;
114 }
115 else if (setting == "colorspace") {
116 value_int = std::stoi(value);
117 info.pixel_format = value_int;
118 }
119 else if (setting == "spherical") {
120 value_int = std::stoi(value);
121 info.spherical = (bool)value_int;
122 }
123 }
124 read_file = true;
125 inputFile.close();
126 }
127
128 }
129 catch (const std::exception& e)
130 {
131 // Error parsing profile file
132 throw InvalidFile("Profile could not be found or loaded (or is invalid).", path);
133 }
134
135 // Throw error if file was not read
136 if (!read_file)
137 // Error parsing profile file
138 throw InvalidFile("Profile could not be found or loaded (or is invalid).", path);
139}
140
141// Return a formatted FPS
142std::string Profile::formattedFPS(bool include_decimal) {
143 // Format FPS to use 2 decimals (if needed)
144 if (!include_decimal) {
145 int fps_code = 0;
146
147 if (info.fps.den == 1) {
148 // Exact integer FPS (e.g. 24 → 0024)
149 fps_code = info.fps.num;
150 } else {
151 // Fractional FPS, scale by 100 (e.g. 29.97 → 2997)
152 fps_code = static_cast<int>((info.fps.num * 100.0) / info.fps.den + 0.5);
153 }
154
155 char buffer[5];
156 std::snprintf(buffer, sizeof(buffer), "%04d", fps_code);
157 return std::string(buffer);
158 }
159
160 // Human-readable version for display
161 float fps = info.fps.ToFloat();
162
163 if (std::fabs(fps - std::round(fps)) < 0.01) {
164 return std::to_string(static_cast<int>(std::round(fps)));
165 }
166
167 char buffer[16];
168 std::snprintf(buffer, sizeof(buffer), "%.2f", fps);
169 return std::string(buffer);
170}
171
172// Return a unique key of this profile (01920x1080i2997_16-09)
173std::string Profile::Key() {
174 std::string raw_fps = formattedFPS(false);
175
176 // Pad FPS string to 4 characters with leading zeros
177 std::string fps_padded = std::string(4 - raw_fps.length(), '0') + raw_fps;
178
179 char buffer[64];
180 std::snprintf(buffer, sizeof(buffer), "%05dx%04d%s%s_%02d-%02d",
181 info.width,
182 info.height,
183 info.interlaced_frame ? "i" : "p",
184 fps_padded.c_str(),
187 );
188
189 std::string result(buffer);
190 if (info.spherical)
191 result += "_360";
192 return result;
193}
194
195// Return the name of this profile (1920x1080p29.97)
196std::string Profile::ShortName() {
197 std::string progressive_str = info.interlaced_frame ? "i" : "p";
198 std::string fps_string = formattedFPS(true);
199 std::string result = std::to_string(info.width) + "x" + std::to_string(info.height) + progressive_str + fps_string;
200
201 if (info.spherical)
202 result += " 360°";
203 return result;
204}
205
206// Return a longer format name (1920x1080p @ 29.97 fps (16:9))
207std::string Profile::LongName() {
208 std::string progressive_str = info.interlaced_frame ? "i" : "p";
209 std::string fps_string = formattedFPS(true);
210 std::string result = std::to_string(info.width) + "x" + std::to_string(info.height) +
211 progressive_str + " @ " + fps_string +
212 " fps (" + std::to_string(info.display_ratio.num) + ":" +
213 std::to_string(info.display_ratio.den) + ")";
214
215 if (info.spherical)
216 result += " 360°";
217 return result;
218}
219
220// Return a longer format name (1920x1080p @ 29.97 fps (16:9) HD 1080i 29.97 fps)
222 std::string progressive_str = info.interlaced_frame ? "i" : "p";
223 std::string fps_string = formattedFPS(true);
224
225 std::string result = std::to_string(info.width) + "x" + std::to_string(info.height) +
226 progressive_str + " @ " + fps_string +
227 " fps (" + std::to_string(info.display_ratio.num) + ":" +
228 std::to_string(info.display_ratio.den) + ")";
229
230 if (info.spherical)
231 result += " 360°";
232
233 if (!info.description.empty())
234 result += " " + info.description;
235
236 return result;
237}
238
239// Save profile to file system
240void Profile::Save(const std::string& file_path) const {
241 std::ofstream file(file_path);
242 if (!file.is_open()) {
243 throw std::ios_base::failure("Failed to save profile.");
244 }
245
246 file << "description=" << info.description << "\n";
247 file << "frame_rate_num=" << info.fps.num << "\n";
248 file << "frame_rate_den=" << info.fps.den << "\n";
249 file << "width=" << info.width << "\n";
250 file << "height=" << info.height << "\n";
251 file << "progressive=" << !info.interlaced_frame << "\n"; // Correct the boolean value for progressive/interlaced
252 file << "sample_aspect_num=" << info.pixel_ratio.num << "\n";
253 file << "sample_aspect_den=" << info.pixel_ratio.den << "\n";
254 file << "display_aspect_num=" << info.display_ratio.num << "\n";
255 file << "display_aspect_den=" << info.display_ratio.den << "\n";
256 file << "pixel_format=" << info.pixel_format << "\n";
257 file << "spherical=" << info.spherical;
258
259 file.close();
260}
261
262// Generate JSON string of this object
263std::string Profile::Json() const {
264
265 // Return formatted string
266 return JsonValue().toStyledString();
267}
268
269// Generate Json::Value for this object
270Json::Value Profile::JsonValue() const {
271
272 // Create root json object
273 Json::Value root;
274 root["description"] = info.description;
275 root["height"] = info.height;
276 root["width"] = info.width;
277 root["pixel_format"] = info.pixel_format;
278 root["fps"] = Json::Value(Json::objectValue);
279 root["fps"]["num"] = info.fps.num;
280 root["fps"]["den"] = info.fps.den;
281 root["pixel_ratio"] = Json::Value(Json::objectValue);
282 root["pixel_ratio"]["num"] = info.pixel_ratio.num;
283 root["pixel_ratio"]["den"] = info.pixel_ratio.den;
284 root["display_ratio"] = Json::Value(Json::objectValue);
285 root["display_ratio"]["num"] = info.display_ratio.num;
286 root["display_ratio"]["den"] = info.display_ratio.den;
287 root["progressive"] = !info.interlaced_frame;
288 root["spherical"] = info.spherical;
289
290 // return JsonValue
291 return root;
292}
293
294// Load JSON string into this object
295void Profile::SetJson(const std::string value) {
296
297 // Parse JSON string into JSON objects
298 try
299 {
300 const Json::Value root = openshot::stringToJson(value);
301 // Set all values that match
302 SetJsonValue(root);
303 }
304 catch (const std::exception& e)
305 {
306 // Error parsing JSON (or missing keys)
307 throw InvalidJSON("JSON is invalid (missing keys or invalid data types)");
308 }
309}
310
311// Load Json::Value into this object
312void Profile::SetJsonValue(const Json::Value root) {
313
314 if (!root["description"].isNull())
315 info.description = root["description"].asString();
316 if (!root["height"].isNull())
317 info.height = root["height"].asInt();
318 if (!root["width"].isNull())
319 info.width = root["width"].asInt();
320 if (!root["pixel_format"].isNull())
321 info.pixel_format = root["pixel_format"].asInt();
322 if (!root["fps"].isNull()) {
323 info.fps.num = root["fps"]["num"].asInt();
324 info.fps.den = root["fps"]["den"].asInt();
325 }
326 if (!root["pixel_ratio"].isNull()) {
327 info.pixel_ratio.num = root["pixel_ratio"]["num"].asInt();
328 info.pixel_ratio.den = root["pixel_ratio"]["den"].asInt();
330 }
331 if (!root["display_ratio"].isNull()) {
332 info.display_ratio.num = root["display_ratio"]["num"].asInt();
333 info.display_ratio.den = root["display_ratio"]["den"].asInt();
335 }
336 if (!root["progressive"].isNull())
337 info.interlaced_frame = !root["progressive"].asBool();
338 if (!root["spherical"].isNull())
339 info.spherical = root["spherical"].asBool();
340
341}
Header file for all Exception classes.
Header file for Profile class.
int num
Numerator for the fraction.
Definition Fraction.h:32
float ToFloat()
Return this fraction as a float (i.e. 1/2 = 0.5)
Definition Fraction.cpp:35
void Reduce()
Reduce this fraction (i.e. 640/480 = 4/3)
Definition Fraction.cpp:65
int den
Denominator for the fraction.
Definition Fraction.h:33
Exception for files that can not be found or opened.
Definition Exceptions.h:188
Exception for invalid JSON.
Definition Exceptions.h:218
std::string LongName()
Return a longer format name (1920x1080p @ 29.97 fps (16:9))
Definition Profiles.cpp:207
void SetJsonValue(const Json::Value root)
Load Json::Value into this object.
Definition Profiles.cpp:312
std::string ShortName()
Return the name of this profile (1920x1080p29.97)
Definition Profiles.cpp:196
Profile()
Default Constructor for Profile.
Definition Profiles.cpp:20
void Save(const std::string &file_path) const
Save profile to a text file (label=value, one per line format)
Definition Profiles.cpp:240
std::string LongNameWithDesc()
Return a longer format name with description (1920x1080p @ 29.97 fps (16:9) HD 1080i 29....
Definition Profiles.cpp:221
std::string Json() const
Generate JSON string of this object.
Definition Profiles.cpp:263
ProfileInfo info
Profile data stored here.
Definition Profiles.h:136
void SetJson(const std::string value)
Load JSON string into this object.
Definition Profiles.cpp:295
std::string Key()
Return a unique key of this profile with padding (01920x1080i2997_16:09)
Definition Profiles.cpp:173
Json::Value JsonValue() const
Generate Json::Value for this object.
Definition Profiles.cpp:270
This namespace is the default namespace for all code in the openshot library.
Definition Compressor.h:29
const Json::Value stringToJson(const std::string value)
Definition Json.cpp:16
std::string description
The description of this profile.
Definition Profiles.h:40
int width
The width of the video (in pixels)
Definition Profiles.h:42
bool interlaced_frame
Are the contents of this frame interlaced.
Definition Profiles.h:47
Fraction pixel_ratio
The pixel ratio of the video stream as a fraction (i.e. some pixels are not square)
Definition Profiles.h:45
Fraction display_ratio
The ratio of width to height of the video stream (i.e. 640x480 has a ratio of 4/3)
Definition Profiles.h:46
Fraction fps
Frames per second, as a fraction (i.e. 24/1 = 24 fps)
Definition Profiles.h:44
int height
The height of the video (in pixels)
Definition Profiles.h:41
bool spherical
Is this video a spherical/360° video.
Definition Profiles.h:48
int pixel_format
The pixel format (i.e. YUV420P, RGB24, etc...)
Definition Profiles.h:43