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