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