#ifdef-y hacks to build with Ubuntu 12.04's ffmpeg.
[dcpomatic.git] / src / lib / image.cc
1 /*
2     Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
3
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
18 */
19
20 /** @file src/image.cc
21  *  @brief A set of classes to describe video images.
22  */
23
24 #include <sstream>
25 #include <iomanip>
26 #include <iostream>
27 #include <execinfo.h>
28 #include <cxxabi.h>
29 #include <sys/time.h>
30 #include <boost/algorithm/string.hpp>
31 #include <openjpeg.h>
32 extern "C" {
33 #include <libavcodec/avcodec.h>
34 #include <libavformat/avformat.h>
35 #include <libswscale/swscale.h>
36 #include <libavfilter/avfiltergraph.h>
37 #include <libpostproc/postprocess.h>
38 #include <libavutil/pixfmt.h>
39 }
40 #include "image.h"
41 #include "exceptions.h"
42 #include "scaler.h"
43
44 #ifdef DEBUG_HASH
45 #include <mhash.h>
46 #endif
47
48 using namespace std;
49 using namespace boost;
50
51 /** @param n Component index.
52  *  @return Number of lines in the image for the given component.
53  */
54 int
55 Image::lines (int n) const
56 {
57         switch (_pixel_format) {
58         case PIX_FMT_YUV420P:
59                 if (n == 0) {
60                         return size().height;
61                 } else {
62                         return size().height / 2;
63                 }
64                 break;
65         case PIX_FMT_RGB24:
66                 return size().height;
67         default:
68                 assert (false);
69         }
70
71         return 0;
72 }
73
74 /** @return Number of components */
75 int
76 Image::components () const
77 {
78         switch (_pixel_format) {
79         case PIX_FMT_YUV420P:
80                 return 3;
81         case PIX_FMT_RGB24:
82                 return 1;
83         default:
84                 assert (false);
85         }
86
87         return 0;
88 }
89
90 #ifdef DEBUG_HASH
91 /** Write a MD5 hash of the image's data to stdout.
92  *  @param n Title to give the output.
93  */
94 void
95 Image::hash (string n) const
96 {
97         MHASH ht = mhash_init (MHASH_MD5);
98         if (ht == MHASH_FAILED) {
99                 throw EncodeError ("could not create hash thread");
100         }
101         
102         for (int i = 0; i < components(); ++i) {
103                 mhash (ht, data()[i], line_size()[i] * lines(i));
104         }
105         
106         uint8_t hash[16];
107         mhash_deinit (ht, hash);
108         
109         printf ("%s: ", n.c_str ());
110         for (int i = 0; i < int (mhash_get_block_size (MHASH_MD5)); ++i) {
111                 printf ("%.2x", hash[i]);
112         }
113         printf ("\n");
114 }
115 #endif
116
117 /** Scale this image to a given size and convert it to RGB.
118  *  @param out_size Output image size in pixels.
119  *  @param scaler Scaler to use.
120  */
121 shared_ptr<RGBFrameImage>
122 Image::scale_and_convert_to_rgb (Size out_size, int padding, Scaler const * scaler) const
123 {
124         assert (scaler);
125
126         Size content_size = out_size;
127         content_size.width -= (padding * 2);
128
129         shared_ptr<RGBFrameImage> rgb (new RGBFrameImage (content_size));
130         
131         struct SwsContext* scale_context = sws_getContext (
132                 size().width, size().height, pixel_format(),
133                 content_size.width, content_size.height, PIX_FMT_RGB24,
134                 scaler->ffmpeg_id (), 0, 0, 0
135                 );
136
137         /* Scale and convert to RGB from whatever its currently in (which may be RGB) */
138         sws_scale (
139                 scale_context,
140                 data(), line_size(),
141                 0, size().height,
142                 rgb->data (), rgb->line_size ()
143                 );
144
145         /* Put the image in the right place in a black frame if are padding; this is
146            a bit grubby and expensive, but probably inconsequential in the great
147            scheme of things.
148         */
149         if (padding > 0) {
150                 shared_ptr<RGBFrameImage> padded_rgb (new RGBFrameImage (out_size));
151                 padded_rgb->make_black ();
152
153                 /* XXX: we are cheating a bit here; we know the frame is RGB so we can
154                    make assumptions about its composition.
155                 */
156                 uint8_t* p = padded_rgb->data()[0] + padding * 3;
157                 uint8_t* q = rgb->data()[0];
158                 for (int j = 0; j < rgb->lines(0); ++j) {
159                         memcpy (p, q, rgb->line_size()[0]);
160                         p += padded_rgb->line_size()[0];
161                         q += rgb->line_size()[0];
162                 }
163
164                 rgb = padded_rgb;
165         }
166
167         sws_freeContext (scale_context);
168
169         return rgb;
170 }
171
172 /** Run a FFmpeg post-process on this image and return the processed version.
173  *  @param pp Flags for the required set of post processes.
174  *  @return Post-processed image.
175  */
176 shared_ptr<PostProcessImage>
177 Image::post_process (string pp) const
178 {
179         shared_ptr<PostProcessImage> out (new PostProcessImage (PIX_FMT_YUV420P, size ()));
180         
181         pp_mode* mode = pp_get_mode_by_name_and_quality (pp.c_str (), PP_QUALITY_MAX);
182         pp_context* context = pp_get_context (size().width, size().height, PP_FORMAT_420 | PP_CPU_CAPS_MMX2);
183
184         pp_postprocess (
185                 (const uint8_t **) data(), line_size(),
186                 out->data(), out->line_size(),
187                 size().width, size().height,
188                 0, 0, mode, context, 0
189                 );
190                 
191         pp_free_mode (mode);
192         pp_free_context (context);
193
194         return out;
195 }
196
197 void
198 Image::make_black ()
199 {
200         switch (_pixel_format) {
201         case PIX_FMT_YUV420P:
202                 memset (data()[0], 0, lines(0) * line_size()[0]);
203                 memset (data()[1], 0x80, lines(1) * line_size()[1]);
204                 memset (data()[2], 0x80, lines(2) * line_size()[2]);
205                 break;
206
207         case PIX_FMT_RGB24:             
208                 memset (data()[0], 0, lines(0) * line_size()[0]);
209                 break;
210
211         default:
212                 assert (false);
213         }
214 }
215
216 /** Construct a SimpleImage of a given size and format, allocating memory
217  *  as required.
218  *
219  *  @param p Pixel format.
220  *  @param s Size in pixels.
221  */
222 SimpleImage::SimpleImage (PixelFormat p, Size s)
223         : Image (p)
224         , _size (s)
225 {
226         _data = (uint8_t **) av_malloc (components() * sizeof (uint8_t *));
227         _line_size = (int *) av_malloc (components() * sizeof (int));
228         
229         for (int i = 0; i < components(); ++i) {
230                 _data[i] = 0;
231                 _line_size[i] = 0;
232         }
233 }
234
235 /** Destroy a SimpleImage */
236 SimpleImage::~SimpleImage ()
237 {
238         for (int i = 0; i < components(); ++i) {
239                 av_free (_data[i]);
240         }
241
242         av_free (_data);
243         av_free (_line_size);
244 }
245
246 /** Set the size in bytes of each horizontal line of a given component.
247  *  @param i Component index.
248  *  @param s Size of line in bytes.
249  */
250 void
251 SimpleImage::set_line_size (int i, int s)
252 {
253         _line_size[i] = s;
254         _data[i] = (uint8_t *) av_malloc (s * lines (i));
255 }
256
257 uint8_t **
258 SimpleImage::data () const
259 {
260         return _data;
261 }
262
263 int *
264 SimpleImage::line_size () const
265 {
266         return _line_size;
267 }
268
269 Size
270 SimpleImage::size () const
271 {
272         return _size;
273 }
274
275
276 FilterBufferImage::FilterBufferImage (PixelFormat p, AVFilterBufferRef* b)
277         : Image (p)
278         , _buffer (b)
279 {
280
281 }
282
283 FilterBufferImage::~FilterBufferImage ()
284 {
285         avfilter_unref_buffer (_buffer);
286 }
287
288 uint8_t **
289 FilterBufferImage::data () const
290 {
291         return _buffer->data;
292 }
293
294 int *
295 FilterBufferImage::line_size () const
296 {
297         return _buffer->linesize;
298 }
299
300 Size
301 FilterBufferImage::size () const
302 {
303         return Size (_buffer->video->w, _buffer->video->h);
304 }
305
306 /** XXX: this could be generalised to use any format, but I don't
307  *  understand how avpicture_fill is supposed to be called with
308  *  multi-planar images.
309  */
310 RGBFrameImage::RGBFrameImage (Size s)
311         : Image (PIX_FMT_RGB24)
312         , _size (s)
313 {
314         _frame = avcodec_alloc_frame ();
315         if (_frame == 0) {
316                 throw EncodeError ("could not allocate frame");
317         }
318
319         _data = (uint8_t *) av_malloc (size().width * size().height * 3);
320         avpicture_fill ((AVPicture *) _frame, _data, PIX_FMT_RGB24, size().width, size().height);
321         _frame->width = size().width;
322         _frame->height = size().height;
323         _frame->format = PIX_FMT_RGB24;
324 }
325
326 RGBFrameImage::~RGBFrameImage ()
327 {
328         av_free (_data);
329         av_free (_frame);
330 }
331
332 uint8_t **
333 RGBFrameImage::data () const
334 {
335         return _frame->data;
336 }
337
338 int *
339 RGBFrameImage::line_size () const
340 {
341         return _frame->linesize;
342 }
343
344 Size
345 RGBFrameImage::size () const
346 {
347         return _size;
348 }
349
350 PostProcessImage::PostProcessImage (PixelFormat p, Size s)
351         : Image (p)
352         , _size (s)
353 {
354         _data = new uint8_t*[4];
355         _line_size = new int[4];
356         
357         for (int i = 0; i < 4; ++i) {
358                 _data[i] = (uint8_t *) av_malloc (s.width * s.height);
359                 _line_size[i] = s.width;
360         }
361 }
362
363 PostProcessImage::~PostProcessImage ()
364 {
365         for (int i = 0; i < 4; ++i) {
366                 av_free (_data[i]);
367         }
368         
369         delete[] _data;
370         delete[] _line_size;
371 }
372
373 uint8_t **
374 PostProcessImage::data () const
375 {
376         return _data;
377 }
378
379 int *
380 PostProcessImage::line_size () const
381 {
382         return _line_size;
383 }
384
385 Size
386 PostProcessImage::size () const
387 {
388         return _size;
389 }