-
Notifications
You must be signed in to change notification settings - Fork 261
/
ImageWriter.cpp
163 lines (131 loc) · 4.78 KB
/
ImageWriter.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
/**
* @file
* @brief Source file for ImageWriter class
* @author Jonathan Thomas <jonathan@openshot.org>, Fabrice Bellard
*
* @ref License
*/
/* LICENSE
*
* Copyright (c) 2008-2019 OpenShot Studios, LLC, Fabrice Bellard
* (http://www.openshotstudios.com). This file is part of
* OpenShot Library (http://www.openshot.org), an open-source project
* dedicated to delivering high quality video editing and animation solutions
* to the world.
*
* This file is originally based on the Libavformat API example, and then modified
* by the libopenshot project.
*
* OpenShot Library (libopenshot) is free software: you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* OpenShot Library (libopenshot) is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with OpenShot Library. If not, see <http://www.gnu.org/licenses/>.
*/
//Require ImageMagick support
#ifdef USE_IMAGEMAGICK
#include "ImageWriter.h"
#include "Exceptions.h"
using namespace openshot;
ImageWriter::ImageWriter(std::string path) :
path(path), cache_size(8), write_video_count(0), image_quality(75), number_of_loops(1),
combine_frames(true), is_open(false)
{
// Disable audio & video (so they can be independently enabled)
info.has_audio = false;
info.has_video = true;
}
// Set video export options
void ImageWriter::SetVideoOptions(std::string format, Fraction fps, int width, int height,
int quality, int loops, bool combine)
{
// Set frames per second (if provided)
info.fps.num = fps.num;
info.fps.den = fps.den;
// Set image magic properties
image_quality = quality;
number_of_loops = loops;
combine_frames = combine;
info.vcodec = format;
// Set the timebase (inverse of fps)
info.video_timebase.num = info.fps.den;
info.video_timebase.den = info.fps.num;
if (width >= 1)
info.width = width;
if (height >= 1)
info.height = height;
info.video_bit_rate = quality;
// Calculate the DAR (display aspect ratio)
Fraction size(info.width * info.pixel_ratio.num, info.height * info.pixel_ratio.den);
// Reduce size fraction
size.Reduce();
// Set the ratio based on the reduced fraction
info.display_ratio.num = size.num;
info.display_ratio.den = size.den;
ZmqLogger::Instance()->AppendDebugMethod("ImageWriter::SetVideoOptions (" + format + ")", "width", width, "height", height, "size.num", size.num, "size.den", size.den, "fps.num", fps.num, "fps.den", fps.den);
}
// Open the writer
void ImageWriter::Open()
{
is_open = true;
}
// Add a frame to the queue waiting to be encoded.
void ImageWriter::WriteFrame(std::shared_ptr<Frame> frame)
{
// Check for open reader (or throw exception)
if (!is_open)
throw WriterClosed("The ImageWriter is closed. Call Open() before calling this method.", path);
// Copy and resize image
std::shared_ptr<Magick::Image> frame_image = frame->GetMagickImage();
frame_image->magick( info.vcodec );
frame_image->backgroundColor(Magick::Color("none"));
MAGICK_IMAGE_ALPHA(frame_image, true);
frame_image->quality(image_quality);
frame_image->animationDelay(info.video_timebase.ToFloat() * 100);
frame_image->animationIterations(number_of_loops);
// Calculate correct DAR (display aspect ratio)
int new_width = info.width;
int new_height = info.height * frame->GetPixelRatio().Reciprocal().ToDouble();
// Resize image
Magick::Geometry new_size(new_width, new_height);
new_size.aspect(true);
frame_image->resize(new_size);
// Put resized frame in vector (waiting to be written)
frames.push_back(*frame_image.get());
// Keep track of the last frame added
last_frame = frame;
}
// Write a block of frames from a reader
void ImageWriter::WriteFrame(ReaderBase* reader, int64_t start, int64_t length)
{
ZmqLogger::Instance()->AppendDebugMethod("ImageWriter::WriteFrame (from Reader)", "start", start, "length", length);
// Loop through each frame (and encoded it)
for (int64_t number = start; number <= length; number++)
{
// Get the frame
std::shared_ptr<Frame> f = reader->GetFrame(number);
// Encode frame
WriteFrame(f);
}
}
// Close the writer and encode/output final image to the disk.
void ImageWriter::Close()
{
// Write frame's image to file
Magick::writeImages(frames.begin(), frames.end(), path, combine_frames);
// Clear frames vector
frames.clear();
// Reset frame counters
write_video_count = 0;
// Close writer
is_open = false;
ZmqLogger::Instance()->AppendDebugMethod("ImageWriter::Close");
}
#endif //USE_IMAGEMAGICK