OpenShot Library | libopenshot 0.2.7
ChunkReader.cpp
Go to the documentation of this file.
1/**
2 * @file
3 * @brief Source file for ChunkReader class
4 * @author Jonathan Thomas <jonathan@openshot.org>
5 *
6 * @ref License
7 */
8
9/* LICENSE
10 *
11 * Copyright (c) 2008-2019 OpenShot Studios, LLC
12 * <http://www.openshotstudios.com/>. This file is part of
13 * OpenShot Library (libopenshot), an open-source project dedicated to
14 * delivering high quality video editing and animation solutions to the
15 * world. For more information visit <http://www.openshot.org/>.
16 *
17 * OpenShot Library (libopenshot) is free software: you can redistribute it
18 * and/or modify it under the terms of the GNU Lesser General Public License
19 * as published by the Free Software Foundation, either version 3 of the
20 * License, or (at your option) any later version.
21 *
22 * OpenShot Library (libopenshot) is distributed in the hope that it will be
23 * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 * GNU Lesser General Public License for more details.
26 *
27 * You should have received a copy of the GNU Lesser General Public License
28 * along with OpenShot Library. If not, see <http://www.gnu.org/licenses/>.
29 */
30
31#include "ChunkReader.h"
32#include "Exceptions.h"
33#include "FFmpegReader.h"
34
35#include <QDir>
36
37using namespace openshot;
38
39ChunkReader::ChunkReader(std::string path, ChunkVersion chunk_version)
40 : path(path), chunk_size(24 * 3), is_open(false), version(chunk_version), local_reader(NULL)
41{
42 // Check if folder exists?
43 if (!does_folder_exist(path))
44 // Raise exception
45 throw InvalidFile("Chunk folder could not be opened.", path);
46
47 // Init previous location
48 previous_location.number = 0;
49 previous_location.frame = 0;
50
51 // Open and Close the reader, to populate its attributes (such as height, width, etc...)
52 Open();
53 Close();
54}
55
56// Check if folder path existing
57bool ChunkReader::does_folder_exist(std::string path)
58{
59 QDir dir(path.c_str());
60 return dir.exists();
61}
62
63// Load JSON meta data about this chunk folder
64void ChunkReader::load_json()
65{
66 // Load path of chunk folder
67 std::string json_path = QDir::cleanPath(QString(path.c_str()) + QDir::separator() + "info.json").toStdString();
68 std::stringstream json_string;
69
70 // Read the JSON file
71 std::ifstream myfile (json_path.c_str());
72 std::string line = "";
73 if (myfile.is_open())
74 {
75 while (myfile.good())
76 {
77 getline (myfile, line);
78 json_string << line;
79 }
80 myfile.close();
81 }
82
83 // Parse JSON string into JSON objects
84 Json::Value root;
85 Json::CharReaderBuilder rbuilder;
86
87 std::string errors;
88 bool success = Json::parseFromStream(rbuilder, json_string, &root, &errors);
89 if (!success)
90 // Raise exception
91 throw InvalidJSON("Chunk folder could not be opened.", path);
92
93
94 // Set info from the JSON objects
95 try
96 {
97 info.has_video = root["has_video"].asBool();
98 info.has_audio = root["has_audio"].asBool();
99 info.duration = root["duration"].asDouble();
100 info.file_size = std::stoll(root["file_size"].asString());
101 info.height = root["height"].asInt();
102 info.width = root["width"].asInt();
103 info.pixel_format = root["pixel_format"].asInt();
104 info.fps.num = root["fps"]["num"].asInt();
105 info.fps.den = root["fps"]["den"].asInt();
106 info.video_bit_rate = root["video_bit_rate"].asUInt();
107 info.pixel_ratio.num = root["pixel_ratio"]["num"].asInt();
108 info.pixel_ratio.den = root["pixel_ratio"]["den"].asInt();
109 info.display_ratio.num = root["display_ratio"]["num"].asInt();
110 info.display_ratio.den = root["display_ratio"]["den"].asInt();
111 info.vcodec = root["vcodec"].asString();
112 info.video_length = std::stoll(root["video_length"].asString());
113 info.video_stream_index = root["video_stream_index"].asInt();
114 info.video_timebase.num = root["video_timebase"]["num"].asInt();
115 info.video_timebase.den = root["video_timebase"]["den"].asInt();
116 info.interlaced_frame = root["interlaced_frame"].asBool();
117 info.top_field_first = root["top_field_first"].asBool();
118 info.acodec = root["acodec"].asString();
119 info.audio_bit_rate = root["audio_bit_rate"].asUInt();
120 info.sample_rate = root["sample_rate"].asUInt();
121 info.channels = root["channels"].asInt();
122 info.audio_stream_index = root["audio_stream_index"].asInt();
123 info.audio_timebase.num = root["audio_timebase"]["num"].asInt();
124 info.audio_timebase.den = root["audio_timebase"]["den"].asInt();
125
126 }
127 catch (const std::exception& e)
128 {
129 // Error parsing JSON (or missing keys)
130 throw InvalidJSON("JSON could not be parsed (or is invalid).", path);
131 }
132}
133
134// Find the location of a frame in a chunk
135ChunkLocation ChunkReader::find_chunk_frame(int64_t requested_frame)
136{
137 // Determine which chunk contains this frame.
138 int64_t chunk_number = (requested_frame / chunk_size) + 1;
139
140 // Determine which frame in this chunk
141 int64_t start_frame_of_chunk = (chunk_number - 1) * chunk_size;
142 int64_t chunk_frame_number = (requested_frame - start_frame_of_chunk) + 1; // Add 1 to adjust for the 1st frame of every chunk is just there to "stoke" the audio samples from the previous chunk.
143
144 // Prepare chunk location struct
145 ChunkLocation location = {chunk_number, chunk_frame_number};
146
147 return location;
148}
149
150// Open chunk folder or file
152{
153 // Open reader if not already open
154 if (!is_open)
155 {
156 // parse JSON and load info.json file
157 load_json();
158
159 // Mark as "open"
160 is_open = true;
161 }
162}
163
164// Close image file
166{
167 // Close all objects, if reader is 'open'
168 if (is_open)
169 {
170 // Mark as "closed"
171 is_open = false;
172 }
173}
174
175// get a formatted path of a specific chunk
176std::string ChunkReader::get_chunk_path(int64_t chunk_number, std::string folder, std::string extension)
177{
178 // Create path of new chunk video
179 std::stringstream chunk_count_string;
180 chunk_count_string << chunk_number;
181 QString padded_count = "%1"; //chunk_count_string.str().c_str();
182 padded_count = padded_count.arg(chunk_count_string.str().c_str(), 6, '0');
183 if (folder.length() != 0 && extension.length() != 0)
184 // Return path with FOLDER and EXTENSION name
185 return QDir::cleanPath(QString(path.c_str()) + QDir::separator() + folder.c_str() + QDir::separator() + padded_count + extension.c_str()).toStdString();
186
187 else if (folder.length() == 0 && extension.length() != 0)
188 // Return path with NO FOLDER and EXTENSION name
189 return QDir::cleanPath(QString(path.c_str()) + QDir::separator() + padded_count + extension.c_str()).toStdString();
190
191 else if (folder.length() != 0 && extension.length() == 0)
192 // Return path with FOLDER and NO EXTENSION
193 return QDir::cleanPath(QString(path.c_str()) + QDir::separator() + folder.c_str()).toStdString();
194 else
195 return "";
196}
197
198// Get an openshot::Frame object for a specific frame number of this reader.
199std::shared_ptr<Frame> ChunkReader::GetFrame(int64_t requested_frame)
200{
201 // Determine what chunk contains this frame
202 ChunkLocation location = find_chunk_frame(requested_frame);
203
204 // New Chunk (Close the old reader, and open the new one)
205 if (previous_location.number != location.number)
206 {
207 // Determine version of chunk
208 std::string folder_name = "";
209 switch (version)
210 {
211 case THUMBNAIL:
212 folder_name = "thumb";
213 break;
214 case PREVIEW:
215 folder_name = "preview";
216 break;
217 case FINAL:
218 folder_name = "final";
219 break;
220 }
221
222 // Load path of chunk video
223 std::string chunk_video_path = get_chunk_path(location.number, folder_name, ".webm");
224
225 // Close existing reader (if needed)
226 if (local_reader)
227 {
228 // Close and delete old reader
229 local_reader->Close();
230 delete local_reader;
231 }
232
233 try
234 {
235 // Load new FFmpegReader
236 local_reader = new FFmpegReader(chunk_video_path);
237 local_reader->Open(); // open reader
238
239 } catch (const InvalidFile& e)
240 {
241 // Invalid Chunk (possibly it is not found)
242 throw ChunkNotFound(path, requested_frame, location.number, location.frame);
243 }
244
245 // Set the new location
246 previous_location = location;
247 }
248
249 // Get the frame (from the current reader)
250 last_frame = local_reader->GetFrame(location.frame);
251
252 // Update the frame number property
253 last_frame->number = requested_frame;
254
255 // Return the frame
256 return last_frame;
257}
258
259// Generate JSON string of this object
260std::string ChunkReader::Json() const {
261
262 // Return formatted string
263 return JsonValue().toStyledString();
264}
265
266// Generate Json::Value for this object
267Json::Value ChunkReader::JsonValue() const {
268
269 // Create root json object
270 Json::Value root = ReaderBase::JsonValue(); // get parent properties
271 root["type"] = "ChunkReader";
272 root["path"] = path;
273 std::stringstream chunk_size_stream;
274 chunk_size_stream << chunk_size;
275 root["chunk_size"] = chunk_size_stream.str();
276 root["chunk_version"] = version;
277
278 // return JsonValue
279 return root;
280}
281
282// Load JSON string into this object
283void ChunkReader::SetJson(const std::string value) {
284
285 try
286 {
287 const Json::Value root = openshot::stringToJson(value);
288 // Set all values that match
289 SetJsonValue(root);
290 }
291 catch (const std::exception& e)
292 {
293 // Error parsing JSON (or missing keys)
294 throw InvalidJSON("JSON is invalid (missing keys or invalid data types)");
295 }
296}
297
298// Load Json::Value into this object
299void ChunkReader::SetJsonValue(const Json::Value root) {
300
301 // Set parent data
303
304 // Set data from Json (if key is found)
305 if (!root["path"].isNull())
306 path = root["path"].asString();
307 if (!root["chunk_size"].isNull())
308 chunk_size = std::stoll(root["chunk_size"].asString());
309 if (!root["chunk_version"].isNull())
310 version = (ChunkVersion) root["chunk_version"].asInt();
311
312 // Re-Open path, and re-init everything (if needed)
313 if (is_open)
314 {
315 Close();
316 Open();
317 }
318}
Header file for ChunkReader class.
Header file for all Exception classes.
Header file for FFmpegReader class.
Exception when a required chunk is missing.
Definition: Exceptions.h:59
std::string Json() const override
Generate JSON string of this object.
void Close() override
Close the reader.
void Open() override
Open the reader. This is required before you can access frames or data from the reader.
Json::Value JsonValue() const override
Generate Json::Value for this object.
std::shared_ptr< openshot::Frame > GetFrame(int64_t requested_frame) override
Get an openshot::Frame object for a specific frame number of this reader.
void SetJsonValue(const Json::Value root) override
Load Json::Value into this object.
void SetJson(const std::string value) override
Load JSON string into this object.
This class uses the FFmpeg libraries, to open video files and audio files, and return openshot::Frame...
Definition: FFmpegReader.h:93
int num
Numerator for the fraction.
Definition: Fraction.h:50
int den
Denominator for the fraction.
Definition: Fraction.h:51
Exception for files that can not be found or opened.
Definition: Exceptions.h:174
Exception for invalid JSON.
Definition: Exceptions.h:206
openshot::ReaderInfo info
Information about the current media file.
Definition: ReaderBase.h:111
virtual void SetJsonValue(const Json::Value root)=0
Load Json::Value into this object.
Definition: ReaderBase.cpp:171
virtual Json::Value JsonValue() const =0
Generate Json::Value for this object.
Definition: ReaderBase.cpp:116
virtual void Open()=0
Open the reader (and start consuming resources, such as images or video files)
virtual std::shared_ptr< openshot::Frame > GetFrame(int64_t number)=0
virtual void Close()=0
Close the reader (and any resources it was consuming)
This namespace is the default namespace for all code in the openshot library.
Definition: Compressor.h:47
ChunkVersion
This enumeration allows the user to choose which version of the chunk they would like (low,...
Definition: ChunkReader.h:69
@ THUMBNAIL
The lowest quality stream contained in this chunk file.
Definition: ChunkReader.h:70
@ FINAL
The highest quality stream contained in this chunk file.
Definition: ChunkReader.h:72
@ PREVIEW
The medium quality stream contained in this chunk file.
Definition: ChunkReader.h:71
const Json::Value stringToJson(const std::string value)
Definition: Json.cpp:34
This struct holds the location of a frame within a chunk.
Definition: ChunkReader.h:53
int64_t number
The chunk number.
Definition: ChunkReader.h:54
int64_t frame
The frame number.
Definition: ChunkReader.h:55
int audio_bit_rate
The bit rate of the audio stream (in bytes)
Definition: ReaderBase.h:81
int video_bit_rate
The bit rate of the video stream (in bytes)
Definition: ReaderBase.h:71
float duration
Length of time (in seconds)
Definition: ReaderBase.h:65
openshot::Fraction audio_timebase
The audio timebase determines how long each audio packet should be played.
Definition: ReaderBase.h:86
int width
The width of the video (in pixesl)
Definition: ReaderBase.h:68
int channels
The number of audio channels used in the audio stream.
Definition: ReaderBase.h:83
openshot::Fraction fps
Frames per second, as a fraction (i.e. 24/1 = 24 fps)
Definition: ReaderBase.h:70
openshot::Fraction display_ratio
The ratio of width to height of the video stream (i.e. 640x480 has a ratio of 4/3)
Definition: ReaderBase.h:73
int height
The height of the video (in pixels)
Definition: ReaderBase.h:67
int pixel_format
The pixel format (i.e. YUV420P, RGB24, etc...)
Definition: ReaderBase.h:69
int64_t video_length
The number of frames in the video stream.
Definition: ReaderBase.h:75
std::string acodec
The name of the audio codec used to encode / decode the video stream.
Definition: ReaderBase.h:80
std::string vcodec
The name of the video codec used to encode / decode the video stream.
Definition: ReaderBase.h:74
openshot::Fraction pixel_ratio
The pixel ratio of the video stream as a fraction (i.e. some pixels are not square)
Definition: ReaderBase.h:72
bool has_video
Determines if this file has a video stream.
Definition: ReaderBase.h:62
bool has_audio
Determines if this file has an audio stream.
Definition: ReaderBase.h:63
openshot::Fraction video_timebase
The video timebase determines how long each frame stays on the screen.
Definition: ReaderBase.h:77
int video_stream_index
The index of the video stream.
Definition: ReaderBase.h:76
int sample_rate
The number of audio samples per second (44100 is a common sample rate)
Definition: ReaderBase.h:82
int audio_stream_index
The index of the audio stream.
Definition: ReaderBase.h:85
int64_t file_size
Size of file (in bytes)
Definition: ReaderBase.h:66