-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathVideoFramework.m
189 lines (169 loc) · 7.06 KB
/
VideoFramework.m
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
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
classdef VideoFramework < handle
% Framework for creating videos.
%
% Gerhard Kurz
%
% Example usage:
% e = ExampleVideo
% e.preview
% e.createVideo
properties
totalFrames = 100;
framerate = 30; %number of frames per second
projectName = '';
mode = 'fw' %supported modes are fw, bw and fwbw
end
methods
function this = VideoFramework()
addpath(pwd);
end
function preview(this)
% Runs the video, but does not save anything
this.projectName = class(this);
this.init();
this.runVideo(false);
end
function createVideo(this)
% Runs the video, saves frames as PNG, and encodes them as video files
this.clean();
[~,~,~] = mkdir(this.projectName);
this.runVideo(true);
this.encode();
end
function encode(this)
% Encodes the PNG frames as a video.
if isempty(this.projectName)
this.projectName = class(this);
end
this.init();
cd(this.projectName)
try
% MATLAB encoder
this.encodeMatlab();
% ffmpeg
% -y
% Overwrite output files without asking.
% -f image2 -framerate %i -i %%06d.png
% read consecutively numbered images with 6 digits, use
% user-defined framerate
% -vf crop=in_w-1:in_h-1
% crop 1 pixel because PNGs have odd number of pixels
% -b 2000k
% bitrate (2000k = 2MBit/s)
% -qscale 1
% highest quality
% best version (h264)
system(sprintf('ffmpeg -y -f image2 -framerate %i -i %%06d.png -vcodec libx264 -vf crop=in_w-1:in_h-1 output.mp4', this.framerate));
% h264 for Powerpoint
% https://msdn.microsoft.com/de-de/library/windows/desktop/dd797815%28v=vs.85%29.aspx
% maximum resolution is 1920 x 1088 pixels, thus we use 720p
% only supports yuv420p pixel format
system(sprintf('ffmpeg -y -f image2 -framerate %i -i %%06d.png -vcodec libx264 -pix_fmt yuv420p -vf crop="in_w-1:in_h-1, scale=-1:720" output-ppt.mp4', this.framerate));
% wmv for Powerpoint, different resolutions, needs higher
% bitrate than h264
system(sprintf('ffmpeg -y -f image2 -framerate %i -i %%06d.png -vf crop=in_w-1:in_h-1 -b 3000k -qscale 1 output.wmv', this.framerate));
system(sprintf('ffmpeg -y -f image2 -framerate %i -i %%06d.png -vf crop="in_w-1:in_h-1, scale=-1:720" -b 2000k -qscale 1 output-720p.wmv', this.framerate));
system(sprintf('ffmpeg -y -f image2 -framerate %i -i %%06d.png -vf crop="in_w-1:in_h-1, scale=-1:480" -b 1500k -qscale 1 output-480p.wmv', this.framerate));
catch ex
ex
end
cd('..')
end
function clean(this)
% Deletes all created pngs
if isempty(this.projectName)
this.projectName = class(this);
end
this.init();
if exist(this.projectName, 'dir');
cd(this.projectName)
delete('./*.png')
cd('..')
end
end
end
methods (Access = private)
function encodeMatlab(this)
try
if ispc || ismac
vw = VideoWriter('output-matlab','MPEG-4');
else
% MATLAB on Linux does not support MPEG-4
vw = VideoWriter('output-matlab.avi');
end
vw.Quality = 100;
vw.FrameRate = this.framerate;
vw.open()
n = 1;
fprintf('encoding with MATLAB Videowriter\n');
while true
filename = sprintf('%06d.png', n);
if ~exist(filename,'file')
break
end
nBytes = fprintf('frame %i', n); %display progress
img1 = imread(filename);
img2 = imresize(img1, min(1088/size(img1,1),1920/size(img1,2)) ); %resize image to be no larger than 1088 x 1920
img3 = padarray(img2, mod([size(img2,1), size(img2,2)] ,4), 'replicate', 'post'); % pad to make size divisble by four
vw.writeVideo(img3);
fprintf(repmat('\b',1,nBytes))
n = n + 1;
end
vw.close()
catch ex
ex
end
end
function runVideo(this, saveImages)
n=0;
if strcmp(this.mode,'fw') || strcmp(this.mode,'fwbw')
for i=1:this.totalFrames
fprintf('frame %06d/%06d\n', i, this.totalFrames);
f1 = figure(1);
this.drawFrame(i);
if saveImages
n=n+1;
VideoFramework.saveFigure(f1, [this.projectName sprintf('/%06d', n)]);
end
end
end
if strcmp(this.mode,'bw') || strcmp(this.mode,'fwbw')
for i=this.totalFrames:-1:1
fprintf('frame %06d/%06d\n', i, this.totalFrames);
f1 = figure(1);
this.drawFrame(i);
if saveImages
n=n+1;
VideoFramework.saveFigure(f1, [this.projectName sprintf('/%06d', n)]);
end
end
end
end
end
methods (Abstract)
init(this)
drawFrame(this, nr)
end
methods (Static)
%saves the given figure as a PNG file
function saveFigure(fig, filename)
%preserve old settings
oldscreenunits = get(fig,'Units');
oldpaperunits = get(fig,'PaperUnits');
oldpaperpos = get(fig,'PaperPosition');
%change settings before saving
set(fig,'Units','pixels');
scrpos = get(fig,'Position');
newpos = scrpos/110;
set(fig,'PaperUnits','inches',...
'PaperPosition',newpos)
%save file
%print(fig,'-dpng', [filename '.png'], '-r300', '-painters');
print(fig,'-dpng', [filename '.png'], '-r300');
%restore old settings
set(fig,'Units',oldscreenunits,...
'PaperUnits',oldpaperunits,...
'PaperPosition',oldpaperpos)
end
end
end