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 
37 using namespace openshot;
38 
39 ChunkReader::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
57 bool 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
64 void 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
135 ChunkLocation 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
176 std::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.
199 std::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
260 std::string ChunkReader::Json() const {
261 
262  // Return formatted string
263  return JsonValue().toStyledString();
264 }
265 
266 // Generate Json::Value for this object
267 Json::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
283 void 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
299 void 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.
ChunkReader(std::string path, ChunkVersion chunk_version)
Constructor for ChunkReader. This automatically opens the chunk file or folder and loads frame 1,...
Definition: ChunkReader.cpp:39
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 std::shared_ptr< openshot::Frame > GetFrame(int64_t number)=0
virtual void Open()=0
Open the reader (and start consuming resources, such as images or video files)
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