OpenShot Library | libopenshot 0.6.0
Loading...
Searching...
No Matches
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
19using namespace openshot;
20
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
43std::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.
66void 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
183void 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
197void 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
254void 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
267void 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
276bool 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.
void Open()
Open writer.
void WriteFrame(std::shared_ptr< openshot::Frame > frame)
Add a frame to the stack waiting to be encoded.
This class uses the FFmpeg libraries, to write and encode video files and audio files.
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 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.
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