OpenShot Library | libopenshot  0.5.0
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 
22 using namespace openshot;
23 
24 ChunkReader::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
42 bool 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
49 void 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
120 ChunkLocation 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
161 std::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.
184 std::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
245 std::string ChunkReader::Json() const {
246 
247  // Return formatted string
248  return JsonValue().toStyledString();
249 }
250 
251 // Generate Json::Value for this object
252 Json::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
268 void 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
284 void 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: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:24
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:103
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:157
virtual Json::Value JsonValue() const =0
Generate Json::Value for this object.
Definition: ReaderBase.cpp:106
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