1 #include "image.h"
2 #include "error.h"
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <string.h>
6 #include <libswscale/swscale.h>
7
8 // Changes for ffmpeg 3.0
9 #if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57,24,0)
10 # include <libavutil/imgutils.h>
11 # define av_free_packet av_packet_unref
12 # define avpicture_get_size(fmt,w,h) av_image_get_buffer_size(fmt,w,h,1)
13 #endif
14
15 // PIX_FMT was renamed to AV_PIX_FMT on this version
16 #if LIBAVUTIL_VERSION_INT < AV_VERSION_INT(51,74,100)
17 # define AVPixelFormat PixelFormat
18 # define AV_PIX_FMT_RGB24 PIX_FMT_RGB24
19 # define AV_PIX_FMT_YUVJ420P PIX_FMT_YUVJ420P
20 # define AV_PIX_FMT_YUVJ422P PIX_FMT_YUVJ422P
21 # define AV_PIX_FMT_YUVJ440P PIX_FMT_YUVJ440P
22 # define AV_PIX_FMT_YUVJ444P PIX_FMT_YUVJ444P
23 # define AV_PIX_FMT_YUV420P PIX_FMT_YUV420P
24 # define AV_PIX_FMT_YUV422P PIX_FMT_YUV422P
25 # define AV_PIX_FMT_YUV440P PIX_FMT_YUV440P
26 # define AV_PIX_FMT_YUV444P PIX_FMT_YUV444P
27 #endif
28
29 #if LIBAVUTIL_VERSION_INT < AV_VERSION_INT(52, 8, 0)
30 # define av_frame_alloc avcodec_alloc_frame
31 # if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(54,59,100)
32 # define av_frame_free av_freep
33 # else
34 # define av_frame_free avcodec_free_frame
35 # endif
av_frame_get_buffer(AVFrame * frame,int magic)36 void av_frame_get_buffer(AVFrame *frame, int magic) { avpicture_alloc((AVPicture *)frame, frame->format, frame->width, frame->height); }
av_frame_copy(AVFrame * dst,AVFrame * src)37 void av_frame_copy(AVFrame *dst, AVFrame *src) { memcpy(dst->data[0], src->data[0], sizeof(uint8_t)*avpicture_get_size(AV_PIX_FMT_RGB24, dst->width, dst->height)); }
38 #endif
39
40 #define MAX_FILTER_SIZE 256
41
42 struct image {
43 AVFrame *frame;
44 };
45
image_init(const int width,const int height)46 image *image_init(const int width, const int height) {
47 image *i;
48 i = (image *) malloc(sizeof(image));
49
50 i->frame = (AVFrame *) av_frame_alloc();
51 i->frame->width = width;
52 i->frame->height = height;
53 i->frame->format = AV_PIX_FMT_RGB24; // best choice?
54 av_frame_get_buffer(i->frame, 16); // magic number?
55 return i;
56 }
57
image_width(const image * i)58 int image_width(const image *i) {
59 return i->frame->width;
60 }
61
image_height(const image * i)62 int image_height(const image *i) {
63 return i->frame->height;
64 }
65
image_set(const image * i,const int x,const int y,const unsigned char r,const unsigned char g,const unsigned char b)66 void image_set(const image *i, const int x, const int y, const unsigned char r, const unsigned char g, const unsigned char b) {
67 *(i->frame->data[0]+y*i->frame->linesize[0]+x*3+0) = r;
68 *(i->frame->data[0]+y*i->frame->linesize[0]+x*3+1) = g;
69 *(i->frame->data[0]+y*i->frame->linesize[0]+x*3+2) = b;
70 }
71
image_get_r(const image * i,const int x,const int y)72 unsigned char image_get_r(const image *i, const int x, const int y) {
73 return *(i->frame->data[0]+y*i->frame->linesize[0]+x*3+0);
74 }
75
image_get_g(const image * i,const int x,const int y)76 unsigned char image_get_g(const image *i, const int x, const int y) {
77 return *(i->frame->data[0]+y*i->frame->linesize[0]+x*3+1);
78 }
79
image_get_b(const image * i,const int x,const int y)80 unsigned char image_get_b(const image *i, const int x, const int y) {
81 return *(i->frame->data[0]+y*i->frame->linesize[0]+x*3+2);
82 }
83
image_to_bgra(unsigned char * target,const int width,const int height,const image * i,const int offset_x,const int offset_y)84 void image_to_bgra(unsigned char *target, const int width, const int height, const image *i, const int offset_x, const int offset_y) {
85 int x, y;
86 for (y = 0; y < image_height(i) && offset_y+y < height ; y++) {
87 for (x = 0; x < image_width(i) && offset_x+x < width; x++) {
88 *(target+width*4*(offset_y+y)+4*(offset_x+x)+0) = image_get_b(i, x, y);
89 *(target+width*4*(offset_y+y)+4*(offset_x+x)+1) = image_get_g(i, x, y);
90 *(target+width*4*(offset_y+y)+4*(offset_x+x)+2) = image_get_r(i, x, y);
91 *(target+width*4*(offset_y+y)+4*(offset_x+x)+3) = 255;
92 }
93 }
94 }
95
image_from_bgra(const unsigned char * source,const int width,const int height)96 image *image_from_bgra(const unsigned char *source, const int width, const int height) {
97 image *i = image_init(width, height);
98 int x, y;
99 for (y = 0; y < image_height(i); y++) {
100 for (x = 0; x < image_width(i); x++) {
101 image_set(i, x, y, *(source+width*4*y+4*x+2), *(source+width*4*y+4*x+1), *(source+width*4*y+4*x+0));
102 }
103 }
104 return i;
105 }
106
image_clone(const image * i)107 image* image_clone(const image *i) {
108 image *i2 = image_init(image_width(i), image_height(i));
109 av_frame_copy(i2->frame, i->frame);
110 return i2;
111 }
112
image_copy_avframe(const image * i,AVFrame * frame)113 void image_copy_avframe(const image *i, AVFrame *frame) {
114 av_frame_copy(i->frame, frame);
115 }
116
image_dumb_scale(const image * i,const int width,const int height)117 image* image_dumb_scale(const image *i, const int width, const int height) {
118 image *i2 = image_init(width, height);
119
120 float x_factor = 1.0*image_width(i)/width;
121 float y_factor = 1.0*image_height(i)/height;
122
123 int x, y;
124 for (x = 0; x < width; x++) {
125 int x_lower = x_factor*x + 0.5;
126 int x_upper = x_factor*(x+1) - 0.5;
127
128 if (x_lower > x_upper) {
129 // this can happen when upscaling. pick nearest-neighbour entry
130 x_lower = x_upper = x_factor*(x+0.5);
131 }
132
133 for (y = 0; y < height; y++) {
134 int y_lower = y_factor*y + 0.5;
135 int y_upper = y_factor*(y+1) - 0.5;
136
137 if (y_lower > y_upper) {
138 // this can happen when upscaling. pick nearest-neighbour entry
139 y_lower = y_upper = y_factor*(y+0.5);
140 }
141
142 int rsum = 0;
143 int gsum = 0;
144 int bsum = 0;
145 int xx, yy;
146 for (xx = x_lower; xx <= x_upper; xx++) {
147 for (yy = y_lower; yy <= y_upper; yy++) {
148 rsum += image_get_r(i, xx, yy);
149 gsum += image_get_g(i, xx, yy);
150 bsum += image_get_b(i, xx, yy);
151 }
152 }
153 int n = (x_upper-x_lower+1)*(y_upper-y_lower+1);
154 image_set(i2, x, y, rsum/n, gsum/n, bsum/n);
155 }
156 }
157
158 return i2;
159 }
160
image_scale(const image * i,int width,int height)161 image* image_scale(const image *i, int width, int height) {
162 int target_width = width;
163 int target_height = height;
164
165 if (width == image_width(i) && height == image_height(i)) {
166 return image_clone(i);
167 }
168
169 image *i2 = NULL;
170 image *tmp = (image *) i;
171 do {
172 width = target_width;
173 height = target_height;
174
175 #if LIBSWSCALE_VERSION_MICRO < 100 || LIBSWSCALE_VERSION_INT < AV_VERSION_INT(2, 1, 103)
176 if (width < 8) {
177 // libav and old FFmpeg versions don't allow scaling to a width of less than 8
178 if (image_width(tmp) > 8) {
179 // but we can use it to go down to 8
180 width = 8;
181 } else {
182 // all hope ist lost
183 image *i3 = image_dumb_scale(tmp, width, height);
184 if (tmp != i) {
185 image_free(tmp);
186 }
187 return i3;
188 }
189 }
190
191 if (height < 2) {
192 // This doesn't seem to work on libav...
193 if (image_height(tmp) > 2) {
194 height = 2;
195 } else {
196 image *i3 = image_dumb_scale(tmp, width, height);
197 if (tmp != i) {
198 image_free(tmp);
199 }
200 return i3;
201 }
202 }
203 #endif
204
205 // When scaling from a high width directly to 1, FFmpeg sometimes (?)
206 // introduces noise. So we avoid this situation.
207 if (width == 1 && image_width(tmp) > 2) {
208 width = 2;
209 }
210
211 if (image_width(tmp)/width > MAX_FILTER_SIZE) {
212 width = image_width(tmp)/MAX_FILTER_SIZE+1;
213 }
214 if (image_height(tmp)/height > MAX_FILTER_SIZE) {
215 height = image_height(tmp)/MAX_FILTER_SIZE+1;
216 }
217
218
219 i2 = image_init(width, height);
220
221 struct SwsContext *sws_context = sws_getContext(image_width(tmp), image_height(tmp), tmp->frame->format,
222 image_width(i2), image_height(i2), i2->frame->format,
223 SWS_AREA, NULL, NULL, NULL);
224 sws_scale(sws_context, (uint8_t const * const *)tmp->frame->data,
225 tmp->frame->linesize, 0, tmp->frame->height, i2->frame->data,
226 i2->frame->linesize);
227 sws_freeContext(sws_context);
228
229 if (tmp != i) {
230 image_free(tmp);
231 }
232
233 tmp = i2;
234 } while (image_width(i2) != target_width || image_height(i2) != target_height);
235
236 return i2;
237 }
238
image_flip(const image * i)239 image *image_flip(const image *i) {
240 image *i2 = image_init(image_height(i), image_width(i));
241 int x, y;
242 for (x = 0; x < image_width(i2); x++) {
243 for (y = 0; y < image_height(i2); y++) {
244 image_set(i2, x, y, image_get_r(i, y, x), image_get_g(i, y, x), image_get_b(i, y, x));
245 }
246 }
247 return i2;
248 }
249
image_column(const image * i,double percent)250 image* image_column(const image *i, double percent) {
251 image *i2 = image_init(1, image_height(i));
252
253 int y;
254 const int x = image_width(i)*percent;
255 for (y = 0; y < image_height(i); y++) {
256 image_set(i2, 0, y, image_get_r(i, x, y), image_get_g(i, x, y), image_get_b(i, x, y));
257 }
258
259 return i2;
260 }
261
image_write_png(const image * i,const char * file_path)262 int image_write_png(const image *i, const char *file_path) {
263 AVCodec *encoder = avcodec_find_encoder_by_name("png");
264 AVCodecContext *encoder_context;
265 encoder_context = avcodec_alloc_context3(encoder);
266 encoder_context->width = i->frame->width;
267 encoder_context->height = i->frame->height;
268 encoder_context->pix_fmt = AV_PIX_FMT_RGB24;
269 encoder_context->time_base.num = 1;
270 encoder_context->time_base.den = 1;
271 if (avcodec_open2(encoder_context, encoder, NULL) < 0) {
272 error("Could not open output codec.");
273 return -1;
274 }
275
276 AVPacket packet;
277 av_init_packet(&packet);
278 packet.data = NULL;
279 packet.size = 0;
280
281 #if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(54, 28, 0)
282 uint8_t buffer[200000]; // TODO: Why this size?
283 packet.size = avcodec_encode_video(encoder_context, buffer, 200000, i->frame);
284 packet.data = buffer;
285 #else
286 int got_packet = 0;
287 avcodec_encode_video2(encoder_context, &packet, i->frame, &got_packet);
288 if (! got_packet) {
289 error("Encoding error.");
290 return -1;
291 }
292 #endif
293
294 FILE *file;
295 file = fopen(file_path, "wb");
296 if (! file) {
297 error("Could not open output file.");
298 return -1;
299 }
300 fwrite(packet.data, 1, packet.size, file);
301 fclose(file);
302
303 av_free_packet(&packet);
304
305 avcodec_close(encoder_context);
306 av_free(encoder_context);
307 return 0;
308 }
309
image_free(image * i)310 void image_free(image *i) {
311 av_frame_free(&i->frame);
312 free(i);
313 }
314