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