OpenShot Library | libopenshot 0.6.0
Loading...
Searching...
No Matches
ChunkReader.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 <fstream>
14#include <sstream>
15
16#include "ChunkReader.h"
17#include "Exceptions.h"
18#include "FFmpegReader.h"
19
20#include <QDir>
21
22using namespace openshot;
23
24ChunkReader::ChunkReader(std::string path, ChunkVersion chunk_version)
25 : path(path), chunk_size(24 * 3), is_open(false), version(chunk_version), local_reader(NULL)
26{
27 // Check if folder exists?
28 if (!does_folder_exist(path))
29 // Raise exception
30 throw InvalidFile("Chunk folder could not be opened.", path);
31
32 // Init previous location
33 previous_location.number = 0;
34 previous_location.frame = 0;
35
36 // Open and Close the reader, to populate its attributes (such as height, width, etc...)
37 Open();
38 Close();
39}
40
41// Check if folder path existing
42bool ChunkReader::does_folder_exist(std::string path)
43{
44 QDir dir(path.c_str());
45 return dir.exists();
46}
47
48// Load JSON meta data about this chunk folder
49void ChunkReader::load_json()
50{
51 // Load path of chunk folder
52 std::string json_path = QDir::cleanPath(QString(path.c_str()) + QDir::separator() + "info.json").toStdString();
53 std::stringstream json_string;
54
55 // Read the JSON file
56 std::ifstream myfile (json_path.c_str());
57 std::string line = "";
58 if (myfile.is_open())
59 {
60 while (myfile.good())
61 {
62 getline (myfile, line);
63 json_string << line;
64 }
65 myfile.close();
66 }
67
68 // Parse JSON string into JSON objects
69 Json::Value root;
70 Json::CharReaderBuilder rbuilder;
71
72 std::string errors;
73 bool success = Json::parseFromStream(rbuilder, json_string, &root, &errors);
74 if (!success)
75 // Raise exception
76 throw InvalidJSON("Chunk folder could not be opened.", path);
77
78
79 // Set info from the JSON objects
80 try
81 {
82 info.has_video = root["has_video"].asBool();
83 info.has_audio = root["has_audio"].asBool();
84 info.duration = root["duration"].asDouble();
85 info.file_size = std::stoll(root["file_size"].asString());
86 info.height = root["height"].asInt();
87 info.width = root["width"].asInt();
88 info.pixel_format = root["pixel_format"].asInt();
89 info.fps.num = root["fps"]["num"].asInt();
90 info.fps.den = root["fps"]["den"].asInt();
91 info.video_bit_rate = root["video_bit_rate"].asUInt();
92 info.pixel_ratio.num = root["pixel_ratio"]["num"].asInt();
93 info.pixel_ratio.den = root["pixel_ratio"]["den"].asInt();
94 info.display_ratio.num = root["display_ratio"]["num"].asInt();
95 info.display_ratio.den = root["display_ratio"]["den"].asInt();
96 info.vcodec = root["vcodec"].asString();
97 info.video_length = std::stoll(root["video_length"].asString());
98 info.video_stream_index = root["video_stream_index"].asInt();
99 info.video_timebase.num = root["video_timebase"]["num"].asInt();
100 info.video_timebase.den = root["video_timebase"]["den"].asInt();
101 info.interlaced_frame = root["interlaced_frame"].asBool();
102 info.top_field_first = root["top_field_first"].asBool();
103 info.acodec = root["acodec"].asString();
104 info.audio_bit_rate = root["audio_bit_rate"].asUInt();
105 info.sample_rate = root["sample_rate"].asUInt();
106 info.channels = root["channels"].asInt();
107 info.audio_stream_index = root["audio_stream_index"].asInt();
108 info.audio_timebase.num = root["audio_timebase"]["num"].asInt();
109 info.audio_timebase.den = root["audio_timebase"]["den"].asInt();
110
111 }
112 catch (const std::exception& e)
113 {
114 // Error parsing JSON (or missing keys)
115 throw InvalidJSON("JSON could not be parsed (or is invalid).", path);
116 }
117}
118
119// Find the location of a frame in a chunk
120ChunkLocation ChunkReader::find_chunk_frame(int64_t requested_frame)
121{
122 // Determine which chunk contains this frame.
123 int64_t chunk_number = (requested_frame / chunk_size) + 1;
124
125 // Determine which frame in this chunk
126 int64_t start_frame_of_chunk = (chunk_number - 1) * chunk_size;
127 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.
128
129 // Prepare chunk location struct
130 ChunkLocation location = {chunk_number, chunk_frame_number};
131
132 return location;
133}
134
135// Open chunk folder or file
137{
138 // Open reader if not already open
139 if (!is_open)
140 {
141 // parse JSON and load info.json file
142 load_json();
143
144 // Mark as "open"
145 is_open = true;
146 }
147}
148
149// Close image file
151{
152 // Close all objects, if reader is 'open'
153 if (is_open)
154 {
155 // Mark as "closed"
156 is_open = false;
157 }
158}
159
160// get a formatted path of a specific chunk
161std::string ChunkReader::get_chunk_path(int64_t chunk_number, std::string folder, std::string extension)
162{
163 // Create path of new chunk video
164 std::stringstream chunk_count_string;
165 chunk_count_string << chunk_number;
166 QString padded_count = "%1"; //chunk_count_string.str().c_str();
167 padded_count = padded_count.arg(chunk_count_string.str().c_str(), 6, '0');
168 if (folder.length() != 0 && extension.length() != 0)
169 // Return path with FOLDER and EXTENSION name
170 return QDir::cleanPath(QString(path.c_str()) + QDir::separator() + folder.c_str() + QDir::separator() + padded_count + extension.c_str()).toStdString();
171
172 else if (folder.length() == 0 && extension.length() != 0)
173 // Return path with NO FOLDER and EXTENSION name
174 return QDir::cleanPath(QString(path.c_str()) + QDir::separator() + padded_count + extension.c_str()).toStdString();
175
176 else if (folder.length() != 0 && extension.length() == 0)
177 // Return path with FOLDER and NO EXTENSION
178 return QDir::cleanPath(QString(path.c_str()) + QDir::separator() + folder.c_str()).toStdString();
179 else
180 return "";
181}
182
183// Get an openshot::Frame object for a specific frame number of this reader.
184std::shared_ptr<Frame> ChunkReader::GetFrame(int64_t requested_frame)
185{
186 // Determine what chunk contains this frame
187 ChunkLocation location = find_chunk_frame(requested_frame);
188
189 // New Chunk (Close the old reader, and open the new one)
190 if (previous_location.number != location.number)
191 {
192 // Determine version of chunk
193 std::string folder_name = "";
194 switch (version)
195 {
196 case THUMBNAIL:
197 folder_name = "thumb";
198 break;
199 case PREVIEW:
200 folder_name = "preview";
201 break;
202 case FINAL:
203 folder_name = "final";
204 break;
205 }
206
207 // Load path of chunk video
208 std::string chunk_video_path = get_chunk_path(location.number, folder_name, ".webm");
209
210 // Close existing reader (if needed)
211 if (local_reader)
212 {
213 // Close and delete old reader
214 local_reader->Close();
215 delete local_reader;
216 }
217
218 try
219 {
220 // Load new FFmpegReader
221 local_reader = new FFmpegReader(chunk_video_path);
222 local_reader->Open(); // open reader
223
224 } catch (const InvalidFile& e)
225 {
226 // Invalid Chunk (possibly it is not found)
227 throw ChunkNotFound(path, requested_frame, location.number, location.frame);
228 }
229
230 // Set the new location
231 previous_location = location;
232 }
233
234 // Get the frame (from the current reader)
235 last_frame = local_reader->GetFrame(location.frame);
236
237 // Update the frame number property
238 last_frame->number = requested_frame;
239
240 // Return the frame
241 return last_frame;
242}
243
244// Generate JSON string of this object
245std::string ChunkReader::Json() const {
246
247 // Return formatted string
248 return JsonValue().toStyledString();
249}
250
251// Generate Json::Value for this object
252Json::Value ChunkReader::JsonValue() const {
253
254 // Create root json object
255 Json::Value root = ReaderBase::JsonValue(); // get parent properties
256 root["type"] = "ChunkReader";
257 root["path"] = path;
258 std::stringstream chunk_size_stream;
259 chunk_size_stream << chunk_size;
260 root["chunk_size"] = chunk_size_stream.str();
261 root["chunk_version"] = version;
262
263 // return JsonValue
264 return root;
265}
266
267// Load JSON string into this object
268void ChunkReader::SetJson(const std::string value) {
269
270 try
271 {
272 const Json::Value root = openshot::stringToJson(value);
273 // Set all values that match
274 SetJsonValue(root);
275 }
276 catch (const std::exception& e)
277 {
278 // Error parsing JSON (or missing keys)
279 throw InvalidJSON("JSON is invalid (missing keys or invalid data types)");
280 }
281}
282
283// Load Json::Value into this object
284void ChunkReader::SetJsonValue(const Json::Value root) {
285
286 // Set parent data
288
289 // Set data from Json (if key is found)
290 if (!root["path"].isNull())
291 path = root["path"].asString();
292 if (!root["chunk_size"].isNull())
293 chunk_size = std::stoll(root["chunk_size"].asString());
294 if (!root["chunk_version"].isNull())
295 version = (ChunkVersion) root["chunk_version"].asInt();
296
297 // Re-Open path, and re-init everything (if needed)
298 if (is_open)
299 {
300 Close();
301 Open();
302 }
303}
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:85
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.
ChunkReader(std::string path, ChunkVersion chunk_version)
Constructor for ChunkReader. This automatically opens the chunk file or folder and loads frame 1,...
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...
int num
Numerator for the fraction.
Definition Fraction.h:32
int den
Denominator for the fraction.
Definition Fraction.h:33
Exception for files that can not be found or opened.
Definition Exceptions.h:194
Exception for invalid JSON.
Definition Exceptions.h:224
openshot::ReaderInfo info
Information about the current media file.
Definition ReaderBase.h:88
virtual void SetJsonValue(const Json::Value root)=0
Load Json::Value into this object.
virtual Json::Value JsonValue() const =0
Generate Json::Value for this object.
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:29
ChunkVersion
This enumeration allows the user to choose which version of the chunk they would like (low,...
Definition ChunkReader.h:50
@ THUMBNAIL
The lowest quality stream contained in this chunk file.
Definition ChunkReader.h:51
@ FINAL
The highest quality stream contained in this chunk file.
Definition ChunkReader.h:53
@ PREVIEW
The medium quality stream contained in this chunk file.
Definition ChunkReader.h:52
const Json::Value stringToJson(const std::string value)
Definition Json.cpp:16
This struct holds the location of a frame within a chunk.
Definition ChunkReader.h:34
int64_t number
The chunk number.
Definition ChunkReader.h:35
int64_t frame
The frame number.
Definition ChunkReader.h:36
int audio_bit_rate
The bit rate of the audio stream (in bytes)
Definition ReaderBase.h:59
int video_bit_rate
The bit rate of the video stream (in bytes)
Definition ReaderBase.h:49
float duration
Length of time (in seconds)
Definition ReaderBase.h:43
openshot::Fraction audio_timebase
The audio timebase determines how long each audio packet should be played.
Definition ReaderBase.h:64
int width
The width of the video (in pixesl)
Definition ReaderBase.h:46
int channels
The number of audio channels used in the audio stream.
Definition ReaderBase.h:61
openshot::Fraction fps
Frames per second, as a fraction (i.e. 24/1 = 24 fps)
Definition ReaderBase.h:48
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:51
int height
The height of the video (in pixels)
Definition ReaderBase.h:45
int pixel_format
The pixel format (i.e. YUV420P, RGB24, etc...)
Definition ReaderBase.h:47
int64_t video_length
The number of frames in the video stream.
Definition ReaderBase.h:53
std::string acodec
The name of the audio codec used to encode / decode the video stream.
Definition ReaderBase.h:58
std::string vcodec
The name of the video codec used to encode / decode the video stream.
Definition ReaderBase.h:52
openshot::Fraction pixel_ratio
The pixel ratio of the video stream as a fraction (i.e. some pixels are not square)
Definition ReaderBase.h:50
bool has_video
Determines if this file has a video stream.
Definition ReaderBase.h:40
bool has_audio
Determines if this file has an audio stream.
Definition ReaderBase.h:41
openshot::Fraction video_timebase
The video timebase determines how long each frame stays on the screen.
Definition ReaderBase.h:55
int video_stream_index
The index of the video stream.
Definition ReaderBase.h:54
int sample_rate
The number of audio samples per second (44100 is a common sample rate)
Definition ReaderBase.h:60
int audio_stream_index
The index of the audio stream.
Definition ReaderBase.h:63
int64_t file_size
Size of file (in bytes)
Definition ReaderBase.h:44