OpenShot Library | libopenshot  0.7.0
ChunkWriter.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 "ChunkWriter.h"
14 #include "Exceptions.h"
15 #include "Frame.h"
16 
17 #include <sstream>
18 
19 using namespace openshot;
20 
21 ChunkWriter::ChunkWriter(std::string path, ReaderBase *reader) :
22  local_reader(reader), path(path), chunk_size(24*3), chunk_count(1), frame_count(1), is_writing(false),
23  default_extension(".webm"), default_vcodec("libvpx"), default_acodec("libvorbis"), last_frame_needed(false), is_open(false)
24 {
25  // Change codecs to default
26  info.vcodec = default_vcodec;
27  info.acodec = default_acodec;
28 
29  // Copy info struct from the source reader
30  CopyReaderInfo(local_reader);
31 
32  // Create folder (if it does not exist)
33  create_folder(path);
34 
35  // Write JSON meta data file
36  write_json_meta_data();
37 
38  // Open reader
39  local_reader->Open();
40 }
41 
42 // get a formatted path of a specific chunk
43 std::string ChunkWriter::get_chunk_path(int64_t chunk_number, std::string folder, std::string extension)
44 {
45  // Create path of new chunk video
46  std::stringstream chunk_count_string;
47  chunk_count_string << chunk_number;
48  QString padded_count = "%1"; //chunk_count_string.str().c_str();
49  padded_count = padded_count.arg(chunk_count_string.str().c_str(), 6, '0');
50  if (folder.length() != 0 && extension.length() != 0)
51  // Return path with FOLDER and EXTENSION name
52  return QDir::cleanPath(QString(path.c_str()) + QDir::separator() + folder.c_str() + QDir::separator() + padded_count + extension.c_str()).toStdString();
53 
54  else if (folder.length() == 0 && extension.length() != 0)
55  // Return path with NO FOLDER and EXTENSION name
56  return QDir::cleanPath(QString(path.c_str()) + QDir::separator() + padded_count + extension.c_str()).toStdString();
57 
58  else if (folder.length() != 0 && extension.length() == 0)
59  // Return path with FOLDER and NO EXTENSION
60  return QDir::cleanPath(QString(path.c_str()) + QDir::separator() + folder.c_str()).toStdString();
61  else
62  return "";
63 }
64 
65 // Add a frame to the queue waiting to be encoded.
66 void ChunkWriter::WriteFrame(std::shared_ptr<openshot::Frame> frame)
67 {
68  // Check for open reader (or throw exception)
69  if (!is_open)
70  throw WriterClosed("The ChunkWriter is closed. Call Open() before calling this method.", path);
71 
72  // Check if currently writing chunks?
73  if (!is_writing)
74  {
75  // Save thumbnail of chunk start frame
76  frame->Save(get_chunk_path(chunk_count, "", ".jpeg"), 1.0);
77 
78  // Create FFmpegWriter (FINAL quality)
79  create_folder(get_chunk_path(chunk_count, "final", ""));
80  writer_final = new FFmpegWriter(get_chunk_path(chunk_count, "final", default_extension));
81  writer_final->SetAudioOptions(true, default_acodec, info.sample_rate, info.channels, info.channel_layout, 128000);
82  writer_final->SetVideoOptions(true, default_vcodec, info.fps, info.width, info.height, info.pixel_ratio, false, false, info.video_bit_rate);
83 
84  // Create FFmpegWriter (PREVIEW quality)
85  create_folder(get_chunk_path(chunk_count, "preview", ""));
86  writer_preview = new FFmpegWriter(get_chunk_path(chunk_count, "preview", default_extension));
87  writer_preview->SetAudioOptions(true, default_acodec, info.sample_rate, info.channels, info.channel_layout, 128000);
88  writer_preview->SetVideoOptions(true, default_vcodec, info.fps, info.width * 0.5, info.height * 0.5, info.pixel_ratio, false, false, info.video_bit_rate * 0.5);
89 
90  // Create FFmpegWriter (LOW quality)
91  create_folder(get_chunk_path(chunk_count, "thumb", ""));
92  writer_thumb = new FFmpegWriter(get_chunk_path(chunk_count, "thumb", default_extension));
93  writer_thumb->SetAudioOptions(true, default_acodec, info.sample_rate, info.channels, info.channel_layout, 128000);
94  writer_thumb->SetVideoOptions(true, default_vcodec, info.fps, info.width * 0.25, info.height * 0.25, info.pixel_ratio, false, false, info.video_bit_rate * 0.25);
95 
96  // Prepare Streams
97  writer_final->PrepareStreams();
98  writer_preview->PrepareStreams();
99  writer_thumb->PrepareStreams();
100 
101  // Write header
102  writer_final->WriteHeader();
103  writer_preview->WriteHeader();
104  writer_thumb->WriteHeader();
105 
106  // Keep track that a chunk is being written
107  is_writing = true;
108  last_frame_needed = true;
109  }
110 
111  // If this is not the 1st chunk, always start frame 1 with the last frame from the previous
112  // chunk. This helps to prevent audio resampling issues (because it "stokes" the sample array)
113  if (last_frame_needed)
114  {
115  if (last_frame)
116  {
117  // Write the previous chunks LAST FRAME to the current chunk
118  writer_final->WriteFrame(last_frame);
119  writer_preview->WriteFrame(last_frame);
120  writer_thumb->WriteFrame(last_frame);
121  } else {
122  // Write the 1st frame (of the 1st chunk)... since no previous chunk is available
123  auto blank_frame = std::make_shared<Frame>(
124  1, info.width, info.height, "#000000",
126  blank_frame->AddColor(info.width, info.height, "#000000");
127  writer_final->WriteFrame(blank_frame);
128  writer_preview->WriteFrame(blank_frame);
129  writer_thumb->WriteFrame(blank_frame);
130  }
131 
132  // disable last frame
133  last_frame_needed = false;
134  }
135 
136 
138  // WRITE THE CURRENT FRAME TO THE CURRENT CHUNK
139  writer_final->WriteFrame(frame);
140  writer_preview->WriteFrame(frame);
141  writer_thumb->WriteFrame(frame);
143 
144 
145  // Write the frames once it reaches the correct chunk size
146  if (frame_count % chunk_size == 0 && frame_count >= chunk_size)
147  {
148  // Pad an additional 12 frames
149  for (int z = 0; z<12; z++)
150  {
151  // Repeat frame
152  writer_final->WriteFrame(frame);
153  writer_preview->WriteFrame(frame);
154  writer_thumb->WriteFrame(frame);
155  }
156 
157  // Write Footer
158  writer_final->WriteTrailer();
159  writer_preview->WriteTrailer();
160  writer_thumb->WriteTrailer();
161 
162  // Close writer & reader
163  writer_final->Close();
164  writer_preview->Close();
165  writer_thumb->Close();
166 
167  // Increment chunk count
168  chunk_count++;
169 
170  // Stop writing chunk
171  is_writing = false;
172  }
173 
174  // Increment frame counter
175  frame_count++;
176 
177  // Keep track of the last frame added
178  last_frame = frame;
179 }
180 
181 
182 // Write a block of frames from a reader
183 void ChunkWriter::WriteFrame(ReaderBase* reader, int64_t start, int64_t length)
184 {
185  // Loop through each frame (and encoded it)
186  for (int64_t number = start; number <= length; number++)
187  {
188  // Get the frame
189  std::shared_ptr<Frame> f = reader->GetFrame(number);
190 
191  // Encode frame
192  WriteFrame(f);
193  }
194 }
195 
196 // Write a block of frames from the local cached reader
197 void ChunkWriter::WriteFrame(int64_t start, int64_t length)
198 {
199  // Loop through each frame (and encoded it)
200  for (int64_t number = start; number <= length; number++)
201  {
202  // Get the frame
203  std::shared_ptr<Frame> f = local_reader->GetFrame(number);
204 
205  // Encode frame
206  WriteFrame(f);
207  }
208 }
209 
210 // Close the writer
212 {
213  // Write the frames once it reaches the correct chunk size
214  if (is_writing)
215  {
216  // Pad an additional 12 frames
217  for (int z = 0; z<12; z++)
218  {
219  // Repeat frame
220  writer_final->WriteFrame(last_frame);
221  writer_preview->WriteFrame(last_frame);
222  writer_thumb->WriteFrame(last_frame);
223  }
224 
225  // Write Footer
226  writer_final->WriteTrailer();
227  writer_preview->WriteTrailer();
228  writer_thumb->WriteTrailer();
229 
230  // Close writer & reader
231  writer_final->Close();
232  writer_preview->Close();
233  writer_thumb->Close();
234 
235  // Increment chunk count
236  chunk_count++;
237 
238  // Stop writing chunk
239  is_writing = false;
240  }
241 
242  // close writer
243  is_open = false;
244 
245  // Reset frame counters
246  chunk_count = 0;
247  frame_count = 0;
248 
249  // Open reader
250  local_reader->Close();
251 }
252 
253 // write JSON meta data
254 void ChunkWriter::write_json_meta_data()
255 {
256  // Load path of chunk folder
257  std::string json_path = QDir::cleanPath(QString(path.c_str()) + QDir::separator() + "info.json").toStdString();
258 
259  // Write JSON file
260  std::ofstream myfile;
261  myfile.open (json_path.c_str());
262  myfile << local_reader->Json() << std::endl;
263  myfile.close();
264 }
265 
266 // check for chunk folder
267 void ChunkWriter::create_folder(std::string path)
268 {
269  QDir dir(path.c_str());
270  if (!dir.exists()) {
271  dir.mkpath(".");
272  }
273 }
274 
275 // check for valid chunk json
276 bool ChunkWriter::is_chunk_valid()
277 {
278  return true;
279 }
280 
281 // Open the writer
283 {
284  is_open = true;
285 }
Header file for ChunkWriter class.
Header file for all Exception classes.
Header file for Frame class.
void Close()
Close the writer.
ChunkWriter(std::string path, openshot::ReaderBase *reader)
Constructor for ChunkWriter. Throws one of the following exceptions.
Definition: ChunkWriter.cpp:21
void Open()
Open writer.
void WriteFrame(std::shared_ptr< openshot::Frame > frame)
Add a frame to the stack waiting to be encoded.
Definition: ChunkWriter.cpp:66
This class uses the FFmpeg libraries, to write and encode video files and audio files.
Definition: FFmpegWriter.h:116
void Close()
Close the writer.
void SetAudioOptions(bool has_audio, std::string codec, int sample_rate, int channels, openshot::ChannelLayout channel_layout, int bit_rate)
Set audio export options.
void PrepareStreams()
Prepare & initialize streams and open codecs. This method is called automatically by the Open() metho...
void SetVideoOptions(bool has_video, std::string codec, openshot::Fraction fps, int width, int height, openshot::Fraction pixel_ratio, bool interlaced, bool top_field_first, int bit_rate)
Set video export options.
void WriteHeader()
Write the file header (after the options are set). This method is called automatically by the Open() ...
void WriteFrame(std::shared_ptr< openshot::Frame > frame)
Add a frame to the stack waiting to be encoded.
void WriteTrailer()
Write the file trailer (after all frames are written). This is called automatically by the Close() me...
This abstract class is the base class, used by all readers in libopenshot.
Definition: ReaderBase.h:76
virtual std::string Json() const =0
Generate JSON string of this object.
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)
void CopyReaderInfo(openshot::ReaderBase *reader)
This method copy's the info struct of a reader, and sets the writer with the same info.
Definition: WriterBase.cpp:57
WriterInfo info
Information about the current media file.
Definition: WriterBase.h:76
Exception when a writer is closed, and a frame is requested.
Definition: Exceptions.h:422
This namespace is the default namespace for all code in the openshot library.
Definition: Compressor.h:29
int height
The height of the video (in pixels)
Definition: WriterBase.h:39
int video_bit_rate
The bit rate of the video stream (in bytes)
Definition: WriterBase.h:43
int channels
The number of audio channels used in the audio stream.
Definition: WriterBase.h:55
std::string vcodec
The name of the video codec used to encode / decode the video stream.
Definition: WriterBase.h:46
openshot::Fraction fps
Frames per second, as a fraction (i.e. 24/1 = 24 fps)
Definition: WriterBase.h:42
std::string acodec
The name of the audio codec used to encode / decode the video stream.
Definition: WriterBase.h:52
openshot::ChannelLayout channel_layout
The channel layout (mono, stereo, 5 point surround, etc...)
Definition: WriterBase.h:56
int width
The width of the video (in pixels)
Definition: WriterBase.h:40
openshot::Fraction pixel_ratio
The pixel ratio of the video stream as a fraction (i.e. some pixels are not square)
Definition: WriterBase.h:44
int sample_rate
The number of audio samples per second (44100 is a common sample rate)
Definition: WriterBase.h:54