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