6f0832427ccbc3647ab54315056cbfe635a2499c
[ffmpeg.git] / libavcodec / pnmenc.c
1 /*
2  * PNM image format
3  * Copyright (c) 2002, 2003 Fabrice Bellard
4  *
5  * This file is part of FFmpeg.
6  *
7  * FFmpeg is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * FFmpeg is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with FFmpeg; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20  */
21
22 #include "avcodec.h"
23 #include "bytestream.h"
24 #include "pnm.h"
25
26
27 static av_cold int common_init(AVCodecContext *avctx)
28 {
29     PNMContext *s = avctx->priv_data;
30
31     avcodec_get_frame_defaults((AVFrame*)&s->picture);
32     avctx->coded_frame = (AVFrame*)&s->picture;
33
34     return 0;
35 }
36
37 static int pnm_decode_frame(AVCodecContext *avctx, void *data,
38                             int *data_size, AVPacket *avpkt)
39 {
40     const uint8_t *buf   = avpkt->data;
41     int buf_size         = avpkt->size;
42     PNMContext * const s = avctx->priv_data;
43     AVFrame *picture     = data;
44     AVFrame * const p    = (AVFrame*)&s->picture;
45     int i, n, linesize, h, upgrade = 0;
46     unsigned char *ptr;
47
48     s->bytestream_start =
49     s->bytestream       = buf;
50     s->bytestream_end   = buf + buf_size;
51
52     if (ff_pnm_decode_header(avctx, s) < 0)
53         return -1;
54
55     if (p->data[0])
56         avctx->release_buffer(avctx, p);
57
58     p->reference = 0;
59     if (avctx->get_buffer(avctx, p) < 0) {
60         av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
61         return -1;
62     }
63     p->pict_type = FF_I_TYPE;
64     p->key_frame = 1;
65
66     switch (avctx->pix_fmt) {
67     default:
68         return -1;
69     case PIX_FMT_RGB48BE:
70         n = avctx->width * 6;
71         goto do_read;
72     case PIX_FMT_RGB24:
73         n = avctx->width * 3;
74         goto do_read;
75     case PIX_FMT_GRAY8:
76         n = avctx->width;
77         if (s->maxval < 255)
78             upgrade = 1;
79         goto do_read;
80     case PIX_FMT_GRAY16BE:
81     case PIX_FMT_GRAY16LE:
82         n = avctx->width * 2;
83         if (s->maxval < 65535)
84             upgrade = 2;
85         goto do_read;
86     case PIX_FMT_MONOWHITE:
87     case PIX_FMT_MONOBLACK:
88         n = (avctx->width + 7) >> 3;
89     do_read:
90         ptr      = p->data[0];
91         linesize = p->linesize[0];
92         if (s->bytestream + n * avctx->height > s->bytestream_end)
93             return -1;
94         for (i = 0; i < avctx->height; i++) {
95             if (!upgrade)
96                 memcpy(ptr, s->bytestream, n);
97             else if (upgrade == 1) {
98                 unsigned int j, f = (255 * 128 + s->maxval / 2) / s->maxval;
99                 for (j = 0; j < n; j++)
100                     ptr[j] = (s->bytestream[j] * f + 64) >> 7;
101             } else if (upgrade == 2) {
102                 unsigned int j, v, f = (65535 * 32768 + s->maxval / 2) / s->maxval;
103                 for (j = 0; j < n / 2; j++) {
104                     v = be2me_16(((uint16_t *)s->bytestream)[j]);
105                     ((uint16_t *)ptr)[j] = (v * f + 16384) >> 15;
106                 }
107             }
108             s->bytestream += n;
109             ptr           += linesize;
110         }
111         break;
112     case PIX_FMT_YUV420P:
113         {
114             unsigned char *ptr1, *ptr2;
115
116             n        = avctx->width;
117             ptr      = p->data[0];
118             linesize = p->linesize[0];
119             if (s->bytestream + n * avctx->height * 3 / 2 > s->bytestream_end)
120                 return -1;
121             for (i = 0; i < avctx->height; i++) {
122                 memcpy(ptr, s->bytestream, n);
123                 s->bytestream += n;
124                 ptr           += linesize;
125             }
126             ptr1 = p->data[1];
127             ptr2 = p->data[2];
128             n >>= 1;
129             h = avctx->height >> 1;
130             for (i = 0; i < h; i++) {
131                 memcpy(ptr1, s->bytestream, n);
132                 s->bytestream += n;
133                 memcpy(ptr2, s->bytestream, n);
134                 s->bytestream += n;
135                 ptr1 += p->linesize[1];
136                 ptr2 += p->linesize[2];
137             }
138         }
139         break;
140     case PIX_FMT_RGB32:
141         ptr      = p->data[0];
142         linesize = p->linesize[0];
143         if (s->bytestream + avctx->width * avctx->height * 4 > s->bytestream_end)
144             return -1;
145         for (i = 0; i < avctx->height; i++) {
146             int j, r, g, b, a;
147
148             for (j = 0; j < avctx->width; j++) {
149                 r = *s->bytestream++;
150                 g = *s->bytestream++;
151                 b = *s->bytestream++;
152                 a = *s->bytestream++;
153                 ((uint32_t *)ptr)[j] = (a << 24) | (r << 16) | (g << 8) | b;
154             }
155             ptr += linesize;
156         }
157         break;
158     }
159     *picture   = *(AVFrame*)&s->picture;
160     *data_size = sizeof(AVPicture);
161
162     return s->bytestream - s->bytestream_start;
163 }
164
165 static int pnm_encode_frame(AVCodecContext *avctx, unsigned char *outbuf,
166                             int buf_size, void *data)
167 {
168     PNMContext *s     = avctx->priv_data;
169     AVFrame *pict     = data;
170     AVFrame * const p = (AVFrame*)&s->picture;
171     int i, h, h1, c, n, linesize;
172     uint8_t *ptr, *ptr1, *ptr2;
173
174     if (buf_size < avpicture_get_size(avctx->pix_fmt, avctx->width, avctx->height) + 200) {
175         av_log(avctx, AV_LOG_ERROR, "encoded frame too large\n");
176         return -1;
177     }
178
179     *p           = *pict;
180     p->pict_type = FF_I_TYPE;
181     p->key_frame = 1;
182
183     s->bytestream_start =
184     s->bytestream       = outbuf;
185     s->bytestream_end   = outbuf + buf_size;
186
187     h  = avctx->height;
188     h1 = h;
189     switch (avctx->pix_fmt) {
190     case PIX_FMT_MONOWHITE:
191         c  = '4';
192         n  = (avctx->width + 7) >> 3;
193         break;
194     case PIX_FMT_GRAY8:
195         c  = '5';
196         n  = avctx->width;
197         break;
198     case PIX_FMT_GRAY16BE:
199         c  = '5';
200         n  = avctx->width * 2;
201         break;
202     case PIX_FMT_RGB24:
203         c  = '6';
204         n  = avctx->width * 3;
205         break;
206     case PIX_FMT_RGB48BE:
207         c  = '6';
208         n  = avctx->width * 6;
209         break;
210     case PIX_FMT_YUV420P:
211         c  = '5';
212         n  = avctx->width;
213         h1 = (h * 3) / 2;
214         break;
215     default:
216         return -1;
217     }
218     snprintf(s->bytestream, s->bytestream_end - s->bytestream,
219              "P%c\n%d %d\n", c, avctx->width, h1);
220     s->bytestream += strlen(s->bytestream);
221     if (avctx->pix_fmt != PIX_FMT_MONOWHITE) {
222         snprintf(s->bytestream, s->bytestream_end - s->bytestream,
223                  "%d\n", (avctx->pix_fmt != PIX_FMT_GRAY16BE && avctx->pix_fmt != PIX_FMT_RGB48BE) ? 255 : 65535);
224         s->bytestream += strlen(s->bytestream);
225     }
226
227     ptr      = p->data[0];
228     linesize = p->linesize[0];
229     for (i = 0; i < h; i++) {
230         memcpy(s->bytestream, ptr, n);
231         s->bytestream += n;
232         ptr           += linesize;
233     }
234
235     if (avctx->pix_fmt == PIX_FMT_YUV420P) {
236         h >>= 1;
237         n >>= 1;
238         ptr1 = p->data[1];
239         ptr2 = p->data[2];
240         for (i = 0; i < h; i++) {
241             memcpy(s->bytestream, ptr1, n);
242             s->bytestream += n;
243             memcpy(s->bytestream, ptr2, n);
244             s->bytestream += n;
245                 ptr1 += p->linesize[1];
246                 ptr2 += p->linesize[2];
247         }
248     }
249     return s->bytestream - s->bytestream_start;
250 }
251
252 static int pam_encode_frame(AVCodecContext *avctx, unsigned char *outbuf,
253                             int buf_size, void *data)
254 {
255     PNMContext *s     = avctx->priv_data;
256     AVFrame *pict     = data;
257     AVFrame * const p = (AVFrame*)&s->picture;
258     int i, h, w, n, linesize, depth, maxval;
259     const char *tuple_type;
260     uint8_t *ptr;
261
262     if (buf_size < avpicture_get_size(avctx->pix_fmt, avctx->width, avctx->height) + 200) {
263         av_log(avctx, AV_LOG_ERROR, "encoded frame too large\n");
264         return -1;
265     }
266
267     *p           = *pict;
268     p->pict_type = FF_I_TYPE;
269     p->key_frame = 1;
270
271     s->bytestream_start =
272     s->bytestream       = outbuf;
273     s->bytestream_end   = outbuf+buf_size;
274
275     h = avctx->height;
276     w = avctx->width;
277     switch (avctx->pix_fmt) {
278     case PIX_FMT_MONOWHITE:
279         n          = (w + 7) >> 3;
280         depth      = 1;
281         maxval     = 1;
282         tuple_type = "BLACKANDWHITE";
283         break;
284     case PIX_FMT_GRAY8:
285         n          = w;
286         depth      = 1;
287         maxval     = 255;
288         tuple_type = "GRAYSCALE";
289         break;
290     case PIX_FMT_RGB24:
291         n          = w * 3;
292         depth      = 3;
293         maxval     = 255;
294         tuple_type = "RGB";
295         break;
296     case PIX_FMT_RGB32:
297         n          = w * 4;
298         depth      = 4;
299         maxval     = 255;
300         tuple_type = "RGB_ALPHA";
301         break;
302     default:
303         return -1;
304     }
305     snprintf(s->bytestream, s->bytestream_end - s->bytestream,
306              "P7\nWIDTH %d\nHEIGHT %d\nDEPTH %d\nMAXVAL %d\nTUPLETYPE %s\nENDHDR\n",
307              w, h, depth, maxval, tuple_type);
308     s->bytestream += strlen(s->bytestream);
309
310     ptr      = p->data[0];
311     linesize = p->linesize[0];
312
313     if (avctx->pix_fmt == PIX_FMT_RGB32) {
314         int j;
315         unsigned int v;
316
317         for (i = 0; i < h; i++) {
318             for (j = 0; j < w; j++) {
319                 v = ((uint32_t *)ptr)[j];
320                 bytestream_put_be24(&s->bytestream, v);
321                 *s->bytestream++ = v >> 24;
322             }
323             ptr += linesize;
324         }
325     } else {
326         for (i = 0; i < h; i++) {
327             memcpy(s->bytestream, ptr, n);
328             s->bytestream += n;
329             ptr           += linesize;
330         }
331     }
332     return s->bytestream - s->bytestream_start;
333 }
334
335 static av_cold int common_end(AVCodecContext *avctx)
336 {
337     PNMContext *s = avctx->priv_data;
338
339     if (s->picture.data[0])
340         avctx->release_buffer(avctx, &s->picture);
341
342     return 0;
343 }
344
345
346 #if CONFIG_PGM_DECODER
347 AVCodec pgm_decoder = {
348     "pgm",
349     CODEC_TYPE_VIDEO,
350     CODEC_ID_PGM,
351     sizeof(PNMContext),
352     common_init,
353     NULL,
354     common_end,
355     pnm_decode_frame,
356     CODEC_CAP_DR1,
357     .pix_fmts  = (const enum PixelFormat[]){PIX_FMT_GRAY8, PIX_FMT_GRAY16BE, PIX_FMT_NONE},
358     .long_name = NULL_IF_CONFIG_SMALL("PGM (Portable GrayMap) image"),
359 };
360 #endif
361
362 #if CONFIG_PGM_ENCODER
363 AVCodec pgm_encoder = {
364     "pgm",
365     CODEC_TYPE_VIDEO,
366     CODEC_ID_PGM,
367     sizeof(PNMContext),
368     common_init,
369     pnm_encode_frame,
370     .pix_fmts  = (const enum PixelFormat[]){PIX_FMT_GRAY8, PIX_FMT_GRAY16BE, PIX_FMT_NONE},
371     .long_name = NULL_IF_CONFIG_SMALL("PGM (Portable GrayMap) image"),
372 };
373 #endif
374
375 #if CONFIG_PGMYUV_DECODER
376 AVCodec pgmyuv_decoder = {
377     "pgmyuv",
378     CODEC_TYPE_VIDEO,
379     CODEC_ID_PGMYUV,
380     sizeof(PNMContext),
381     common_init,
382     NULL,
383     common_end,
384     pnm_decode_frame,
385     CODEC_CAP_DR1,
386     .pix_fmts  = (const enum PixelFormat[]){PIX_FMT_YUV420P, PIX_FMT_NONE},
387     .long_name = NULL_IF_CONFIG_SMALL("PGMYUV (Portable GrayMap YUV) image"),
388 };
389 #endif
390
391 #if CONFIG_PGMYUV_ENCODER
392 AVCodec pgmyuv_encoder = {
393     "pgmyuv",
394     CODEC_TYPE_VIDEO,
395     CODEC_ID_PGMYUV,
396     sizeof(PNMContext),
397     common_init,
398     pnm_encode_frame,
399     .pix_fmts  = (const enum PixelFormat[]){PIX_FMT_YUV420P, PIX_FMT_NONE},
400     .long_name = NULL_IF_CONFIG_SMALL("PGMYUV (Portable GrayMap YUV) image"),
401 };
402 #endif
403
404 #if CONFIG_PPM_DECODER
405 AVCodec ppm_decoder = {
406     "ppm",
407     CODEC_TYPE_VIDEO,
408     CODEC_ID_PPM,
409     sizeof(PNMContext),
410     common_init,
411     NULL,
412     common_end,
413     pnm_decode_frame,
414     CODEC_CAP_DR1,
415     .pix_fmts  = (const enum PixelFormat[]){PIX_FMT_RGB24, PIX_FMT_RGB48BE, PIX_FMT_NONE},
416     .long_name = NULL_IF_CONFIG_SMALL("PPM (Portable PixelMap) image"),
417 };
418 #endif
419
420 #if CONFIG_PPM_ENCODER
421 AVCodec ppm_encoder = {
422     "ppm",
423     CODEC_TYPE_VIDEO,
424     CODEC_ID_PPM,
425     sizeof(PNMContext),
426     common_init,
427     pnm_encode_frame,
428     .pix_fmts  = (const enum PixelFormat[]){PIX_FMT_RGB24, PIX_FMT_RGB48BE, PIX_FMT_NONE},
429     .long_name = NULL_IF_CONFIG_SMALL("PPM (Portable PixelMap) image"),
430 };
431 #endif
432
433 #if CONFIG_PBM_DECODER
434 AVCodec pbm_decoder = {
435     "pbm",
436     CODEC_TYPE_VIDEO,
437     CODEC_ID_PBM,
438     sizeof(PNMContext),
439     common_init,
440     NULL,
441     common_end,
442     pnm_decode_frame,
443     CODEC_CAP_DR1,
444     .pix_fmts  = (const enum PixelFormat[]){PIX_FMT_MONOWHITE, PIX_FMT_NONE},
445     .long_name = NULL_IF_CONFIG_SMALL("PBM (Portable BitMap) image"),
446 };
447 #endif
448
449 #if CONFIG_PBM_ENCODER
450 AVCodec pbm_encoder = {
451     "pbm",
452     CODEC_TYPE_VIDEO,
453     CODEC_ID_PBM,
454     sizeof(PNMContext),
455     common_init,
456     pnm_encode_frame,
457     .pix_fmts  = (const enum PixelFormat[]){PIX_FMT_MONOWHITE, PIX_FMT_NONE},
458     .long_name = NULL_IF_CONFIG_SMALL("PBM (Portable BitMap) image"),
459 };
460 #endif
461
462 #if CONFIG_PAM_DECODER
463 AVCodec pam_decoder = {
464     "pam",
465     CODEC_TYPE_VIDEO,
466     CODEC_ID_PAM,
467     sizeof(PNMContext),
468     common_init,
469     NULL,
470     common_end,
471     pnm_decode_frame,
472     CODEC_CAP_DR1,
473     .pix_fmts  = (const enum PixelFormat[]){PIX_FMT_RGB24, PIX_FMT_RGB32, PIX_FMT_GRAY8, PIX_FMT_MONOWHITE, PIX_FMT_NONE},
474     .long_name = NULL_IF_CONFIG_SMALL("PAM (Portable AnyMap) image"),
475 };
476 #endif
477
478 #if CONFIG_PAM_ENCODER
479 AVCodec pam_encoder = {
480     "pam",
481     CODEC_TYPE_VIDEO,
482     CODEC_ID_PAM,
483     sizeof(PNMContext),
484     common_init,
485     pam_encode_frame,
486     .pix_fmts  = (const enum PixelFormat[]){PIX_FMT_RGB24, PIX_FMT_RGB32, PIX_FMT_GRAY8, PIX_FMT_MONOWHITE, PIX_FMT_NONE},
487     .long_name = NULL_IF_CONFIG_SMALL("PAM (Portable AnyMap) image"),
488 };
489 #endif