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