OpenShot Library | libopenshot  0.3.3
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 
21 using namespace openshot;
22 
23 ChunkReader::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
41 bool 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
48 void 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
119 ChunkLocation 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
160 std::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.
183 std::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
244 std::string ChunkReader::Json() const {
245 
246  // Return formatted string
247  return JsonValue().toStyledString();
248 }
249 
250 // Generate Json::Value for this object
251 Json::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
267 void 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
283 void 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,...
Definition: ChunkReader.cpp:23
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:101
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.
Definition: ReaderBase.cpp:162
virtual Json::Value JsonValue() const =0
Generate Json::Value for this object.
Definition: ReaderBase.cpp:107
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: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