OpenShot Library | libopenshot  0.5.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 }
openshot::ChunkWriter::Open
void Open()
Open writer.
Definition: ChunkWriter.cpp:282
openshot::WriterInfo::video_bit_rate
int video_bit_rate
The bit rate of the video stream (in bytes)
Definition: WriterBase.h:43
openshot::WriterClosed
Exception when a writer is closed, and a frame is requested.
Definition: Exceptions.h:415
openshot::ReaderBase::GetFrame
virtual std::shared_ptr< openshot::Frame > GetFrame(int64_t number)=0
openshot::ReaderBase::Json
virtual std::string Json() const =0
Generate JSON string of this object.
openshot::WriterInfo::fps
openshot::Fraction fps
Frames per second, as a fraction (i.e. 24/1 = 24 fps)
Definition: WriterBase.h:42
openshot
This namespace is the default namespace for all code in the openshot library.
Definition: Compressor.h:28
openshot::WriterInfo::channels
int channels
The number of audio channels used in the audio stream.
Definition: WriterBase.h:55
ChunkWriter.h
Header file for ChunkWriter class.
openshot::FFmpegWriter::SetVideoOptions
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.
Definition: FFmpegWriter.cpp:165
openshot::ChunkWriter::WriteFrame
void WriteFrame(std::shared_ptr< openshot::Frame > frame)
Add a frame to the stack waiting to be encoded.
Definition: ChunkWriter.cpp:66
openshot::WriterInfo::width
int width
The width of the video (in pixels)
Definition: WriterBase.h:40
openshot::WriterInfo::acodec
std::string acodec
The name of the audio codec used to encode / decode the video stream.
Definition: WriterBase.h:52
openshot::FFmpegWriter
This class uses the FFmpeg libraries, to write and encode video files and audio files.
Definition: FFmpegWriter.h:116
openshot::WriterInfo::pixel_ratio
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
openshot::ReaderBase::Open
virtual void Open()=0
Open the reader (and start consuming resources, such as images or video files)
openshot::WriterInfo::channel_layout
openshot::ChannelLayout channel_layout
The channel layout (mono, stereo, 5 point surround, etc...)
Definition: WriterBase.h:56
path
path
Definition: FFmpegWriter.cpp:1469
Frame.h
Header file for Frame class.
openshot::FFmpegWriter::WriteFrame
void WriteFrame(std::shared_ptr< openshot::Frame > frame)
Add a frame to the stack waiting to be encoded.
Definition: FFmpegWriter.cpp:667
openshot::FFmpegWriter::Close
void Close()
Close the writer.
Definition: FFmpegWriter.cpp:957
openshot::WriterInfo::height
int height
The height of the video (in pixels)
Definition: WriterBase.h:39
openshot::FFmpegWriter::WriteTrailer
void WriteTrailer()
Write the file trailer (after all frames are written). This is called automatically by the Close() me...
Definition: FFmpegWriter.cpp:744
openshot::WriterBase::CopyReaderInfo
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
openshot::ChunkWriter::Close
void Close()
Close the writer.
Definition: ChunkWriter.cpp:211
openshot::ReaderBase
This abstract class is the base class, used by all readers in libopenshot.
Definition: ReaderBase.h:75
openshot::WriterInfo::vcodec
std::string vcodec
The name of the video codec used to encode / decode the video stream.
Definition: WriterBase.h:46
openshot::WriterInfo::sample_rate
int sample_rate
The number of audio samples per second (44100 is a common sample rate)
Definition: WriterBase.h:54
openshot::ReaderBase::Close
virtual void Close()=0
Close the reader (and any resources it was consuming)
openshot::FFmpegWriter::SetAudioOptions
void SetAudioOptions(bool has_audio, std::string codec, int sample_rate, int channels, openshot::ChannelLayout channel_layout, int bit_rate)
Set audio export options.
Definition: FFmpegWriter.cpp:288
openshot::ChunkWriter::ChunkWriter
ChunkWriter(std::string path, openshot::ReaderBase *reader)
Constructor for ChunkWriter. Throws one of the following exceptions.
Definition: ChunkWriter.cpp:21
openshot::FFmpegWriter::PrepareStreams
void PrepareStreams()
Prepare & initialize streams and open codecs. This method is called automatically by the Open() metho...
Definition: FFmpegWriter.cpp:608
openshot::WriterBase::info
WriterInfo info
Information about the current media file.
Definition: WriterBase.h:76
Exceptions.h
Header file for all Exception classes.
openshot::FFmpegWriter::WriteHeader
void WriteHeader()
Write the file header (after the options are set). This method is called automatically by the Open() ...
Definition: FFmpegWriter.cpp:625