46afbab56035e2e94a295880edb2e832910affbc
[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 #include "avcodec.h"
22 #include "bytestream.h"
23 #include "pnm.h"
24
25
26 static av_cold int common_init(AVCodecContext *avctx){
27     PNMContext *s = avctx->priv_data;
28
29     avcodec_get_frame_defaults((AVFrame*)&s->picture);
30     avctx->coded_frame= (AVFrame*)&s->picture;
31
32     return 0;
33 }
34
35 static int pnm_decode_frame(AVCodecContext *avctx,
36                         void *data, int *data_size,
37                         const uint8_t *buf, int buf_size)
38 {
39     PNMContext * const s = avctx->priv_data;
40     AVFrame *picture = data;
41     AVFrame * const p= (AVFrame*)&s->picture;
42     int i, n, linesize, h, upgrade = 0;
43     unsigned char *ptr;
44
45     s->bytestream_start=
46     s->bytestream= buf;
47     s->bytestream_end= buf + buf_size;
48
49     if(ff_pnm_decode_header(avctx, s) < 0)
50         return -1;
51
52     if(p->data[0])
53         avctx->release_buffer(avctx, p);
54
55     p->reference= 0;
56     if(avctx->get_buffer(avctx, p) < 0){
57         av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
58         return -1;
59     }
60     p->pict_type= FF_I_TYPE;
61     p->key_frame= 1;
62
63     switch(avctx->pix_fmt) {
64     default:
65         return -1;
66     case PIX_FMT_RGB48BE:
67         n = avctx->width * 6;
68         goto do_read;
69     case PIX_FMT_RGB24:
70         n = avctx->width * 3;
71         goto do_read;
72     case PIX_FMT_GRAY8:
73         n = avctx->width;
74         if (s->maxval < 255)
75             upgrade = 1;
76         goto do_read;
77     case PIX_FMT_GRAY16BE:
78     case PIX_FMT_GRAY16LE:
79         n = avctx->width * 2;
80         if (s->maxval < 65535)
81             upgrade = 2;
82         goto do_read;
83     case PIX_FMT_MONOWHITE:
84     case PIX_FMT_MONOBLACK:
85         n = (avctx->width + 7) >> 3;
86     do_read:
87         ptr = p->data[0];
88         linesize = p->linesize[0];
89         if(s->bytestream + n*avctx->height > s->bytestream_end)
90             return -1;
91         for(i = 0; i < avctx->height; i++) {
92             if (!upgrade)
93                 memcpy(ptr, s->bytestream, n);
94             else if (upgrade == 1) {
95                 unsigned int j, f = (255*128 + s->maxval/2) / s->maxval;
96                 for (j=0; j<n; j++)
97                     ptr[j] = (s->bytestream[j] * f + 64) >> 7;
98             } else if (upgrade == 2) {
99                 unsigned int j, v, f = (65535*32768 + s->maxval/2) / s->maxval;
100                 for (j=0; j<n/2; j++) {
101                     v = be2me_16(((uint16_t *)s->bytestream)[j]);
102                     ((uint16_t *)ptr)[j] = (v * f + 16384) >> 15;
103                 }
104             }
105             s->bytestream += n;
106             ptr += linesize;
107         }
108         break;
109     case PIX_FMT_YUV420P:
110         {
111             unsigned char *ptr1, *ptr2;
112
113             n = avctx->width;
114             ptr = p->data[0];
115             linesize = p->linesize[0];
116             if(s->bytestream + n*avctx->height*3/2 > s->bytestream_end)
117                 return -1;
118             for(i = 0; i < avctx->height; i++) {
119                 memcpy(ptr, s->bytestream, n);
120                 s->bytestream += n;
121                 ptr += linesize;
122             }
123             ptr1 = p->data[1];
124             ptr2 = p->data[2];
125             n >>= 1;
126             h = avctx->height >> 1;
127             for(i = 0; i < h; i++) {
128                 memcpy(ptr1, s->bytestream, n);
129                 s->bytestream += n;
130                 memcpy(ptr2, s->bytestream, n);
131                 s->bytestream += n;
132                 ptr1 += p->linesize[1];
133                 ptr2 += p->linesize[2];
134             }
135         }
136         break;
137     case PIX_FMT_RGB32:
138         ptr = p->data[0];
139         linesize = p->linesize[0];
140         if(s->bytestream + avctx->width*avctx->height*4 > s->bytestream_end)
141             return -1;
142         for(i = 0; i < avctx->height; i++) {
143             int j, r, g, b, a;
144
145             for(j = 0;j < avctx->width; j++) {
146                 r = *s->bytestream++;
147                 g = *s->bytestream++;
148                 b = *s->bytestream++;
149                 a = *s->bytestream++;
150                 ((uint32_t *)ptr)[j] = (a << 24) | (r << 16) | (g << 8) | b;
151             }
152             ptr += linesize;
153         }
154         break;
155     }
156     *picture= *(AVFrame*)&s->picture;
157     *data_size = sizeof(AVPicture);
158
159     return s->bytestream - s->bytestream_start;
160 }
161
162 static int pnm_encode_frame(AVCodecContext *avctx, unsigned char *outbuf, int buf_size, void *data){
163     PNMContext *s = avctx->priv_data;
164     AVFrame *pict = data;
165     AVFrame * const p= (AVFrame*)&s->picture;
166     int i, h, h1, c, n, linesize;
167     uint8_t *ptr, *ptr1, *ptr2;
168
169     if(buf_size < avpicture_get_size(avctx->pix_fmt, avctx->width, avctx->height) + 200){
170         av_log(avctx, AV_LOG_ERROR, "encoded frame too large\n");
171         return -1;
172     }
173
174     *p = *pict;
175     p->pict_type= FF_I_TYPE;
176     p->key_frame= 1;
177
178     s->bytestream_start=
179     s->bytestream= outbuf;
180     s->bytestream_end= outbuf+buf_size;
181
182     h = avctx->height;
183     h1 = h;
184     switch(avctx->pix_fmt) {
185     case PIX_FMT_MONOWHITE:
186         c = '4';
187         n = (avctx->width + 7) >> 3;
188         break;
189     case PIX_FMT_GRAY8:
190         c = '5';
191         n = avctx->width;
192         break;
193     case PIX_FMT_GRAY16BE:
194         c = '5';
195         n = avctx->width * 2;
196         break;
197     case PIX_FMT_RGB24:
198         c = '6';
199         n = avctx->width * 3;
200         break;
201     case PIX_FMT_RGB48BE:
202         c = '6';
203         n = avctx->width * 6;
204         break;
205     case PIX_FMT_YUV420P:
206         c = '5';
207         n = avctx->width;
208         h1 = (h * 3) / 2;
209         break;
210     default:
211         return -1;
212     }
213     snprintf(s->bytestream, s->bytestream_end - s->bytestream,
214              "P%c\n%d %d\n",
215              c, avctx->width, h1);
216     s->bytestream += strlen(s->bytestream);
217     if (avctx->pix_fmt != PIX_FMT_MONOWHITE) {
218         snprintf(s->bytestream, s->bytestream_end - s->bytestream,
219                  "%d\n", (avctx->pix_fmt != PIX_FMT_GRAY16BE && avctx->pix_fmt != PIX_FMT_RGB48BE) ? 255 : 65535);
220         s->bytestream += strlen(s->bytestream);
221     }
222
223     ptr = p->data[0];
224     linesize = p->linesize[0];
225     for(i=0;i<h;i++) {
226         memcpy(s->bytestream, ptr, n);
227         s->bytestream += n;
228         ptr += linesize;
229     }
230
231     if (avctx->pix_fmt == PIX_FMT_YUV420P) {
232         h >>= 1;
233         n >>= 1;
234         ptr1 = p->data[1];
235         ptr2 = p->data[2];
236         for(i=0;i<h;i++) {
237             memcpy(s->bytestream, ptr1, n);
238             s->bytestream += n;
239             memcpy(s->bytestream, ptr2, n);
240             s->bytestream += n;
241                 ptr1 += p->linesize[1];
242                 ptr2 += p->linesize[2];
243         }
244     }
245     return s->bytestream - s->bytestream_start;
246 }
247
248 static int pam_encode_frame(AVCodecContext *avctx, unsigned char *outbuf, int buf_size, void *data){
249     PNMContext *s = avctx->priv_data;
250     AVFrame *pict = data;
251     AVFrame * const p= (AVFrame*)&s->picture;
252     int i, h, w, n, linesize, depth, maxval;
253     const char *tuple_type;
254     uint8_t *ptr;
255
256     if(buf_size < avpicture_get_size(avctx->pix_fmt, avctx->width, avctx->height) + 200){
257         av_log(avctx, AV_LOG_ERROR, "encoded frame too large\n");
258         return -1;
259     }
260
261     *p = *pict;
262     p->pict_type= FF_I_TYPE;
263     p->key_frame= 1;
264
265     s->bytestream_start=
266     s->bytestream= outbuf;
267     s->bytestream_end= outbuf+buf_size;
268
269     h = avctx->height;
270     w = avctx->width;
271     switch(avctx->pix_fmt) {
272     case PIX_FMT_MONOWHITE:
273         n = (w + 7) >> 3;
274         depth = 1;
275         maxval = 1;
276         tuple_type = "BLACKANDWHITE";
277         break;
278     case PIX_FMT_GRAY8:
279         n = w;
280         depth = 1;
281         maxval = 255;
282         tuple_type = "GRAYSCALE";
283         break;
284     case PIX_FMT_RGB24:
285         n = w * 3;
286         depth = 3;
287         maxval = 255;
288         tuple_type = "RGB";
289         break;
290     case PIX_FMT_RGB32:
291         n = w * 4;
292         depth = 4;
293         maxval = 255;
294         tuple_type = "RGB_ALPHA";
295         break;
296     default:
297         return -1;
298     }
299     snprintf(s->bytestream, s->bytestream_end - s->bytestream,
300              "P7\nWIDTH %d\nHEIGHT %d\nDEPTH %d\nMAXVAL %d\nTUPLETYPE %s\nENDHDR\n",
301              w, h, depth, maxval, tuple_type);
302     s->bytestream += strlen(s->bytestream);
303
304     ptr = p->data[0];
305     linesize = p->linesize[0];
306
307     if (avctx->pix_fmt == PIX_FMT_RGB32) {
308         int j;
309         unsigned int v;
310
311         for(i=0;i<h;i++) {
312             for(j=0;j<w;j++) {
313                 v = ((uint32_t *)ptr)[j];
314                 bytestream_put_be24(&s->bytestream, v);
315                 *s->bytestream++ = v >> 24;
316             }
317             ptr += linesize;
318         }
319     } else {
320         for(i=0;i<h;i++) {
321             memcpy(s->bytestream, ptr, n);
322             s->bytestream += n;
323             ptr += linesize;
324         }
325     }
326     return s->bytestream - s->bytestream_start;
327 }
328
329 #if 0
330 static int pnm_probe(AVProbeData *pd)
331 {
332     const char *p = pd->buf;
333     if (pd->buf_size >= 8 &&
334         p[0] == 'P' &&
335         p[1] >= '4' && p[1] <= '6' &&
336         pnm_space(p[2]) )
337         return AVPROBE_SCORE_MAX - 1; /* to permit pgmyuv probe */
338     else
339         return 0;
340 }
341
342 static int pgmyuv_probe(AVProbeData *pd)
343 {
344     if (match_ext(pd->filename, "pgmyuv"))
345         return AVPROBE_SCORE_MAX;
346     else
347         return 0;
348 }
349
350 static int pam_probe(AVProbeData *pd)
351 {
352     const char *p = pd->buf;
353     if (pd->buf_size >= 8 &&
354         p[0] == 'P' &&
355         p[1] == '7' &&
356         p[2] == '\n')
357         return AVPROBE_SCORE_MAX;
358     else
359         return 0;
360 }
361 #endif
362
363
364 #if CONFIG_PGM_ENCODER
365 AVCodec pgm_encoder = {
366     "pgm",
367     CODEC_TYPE_VIDEO,
368     CODEC_ID_PGM,
369     sizeof(PNMContext),
370     common_init,
371     pnm_encode_frame,
372     NULL, //encode_end,
373     pnm_decode_frame,
374     .pix_fmts= (enum PixelFormat[]){PIX_FMT_GRAY8, PIX_FMT_GRAY16BE, PIX_FMT_NONE},
375     .long_name= NULL_IF_CONFIG_SMALL("PGM (Portable GrayMap) image"),
376 };
377 #endif // CONFIG_PGM_ENCODER
378
379 #if CONFIG_PGMYUV_ENCODER
380 AVCodec pgmyuv_encoder = {
381     "pgmyuv",
382     CODEC_TYPE_VIDEO,
383     CODEC_ID_PGMYUV,
384     sizeof(PNMContext),
385     common_init,
386     pnm_encode_frame,
387     NULL, //encode_end,
388     pnm_decode_frame,
389     .pix_fmts= (enum PixelFormat[]){PIX_FMT_YUV420P, PIX_FMT_NONE},
390     .long_name= NULL_IF_CONFIG_SMALL("PGMYUV (Portable GrayMap YUV) image"),
391 };
392 #endif // CONFIG_PGMYUV_ENCODER
393
394 #if CONFIG_PPM_ENCODER
395 AVCodec ppm_encoder = {
396     "ppm",
397     CODEC_TYPE_VIDEO,
398     CODEC_ID_PPM,
399     sizeof(PNMContext),
400     common_init,
401     pnm_encode_frame,
402     NULL, //encode_end,
403     pnm_decode_frame,
404     .pix_fmts= (enum PixelFormat[]){PIX_FMT_RGB24, PIX_FMT_RGB48BE, PIX_FMT_NONE},
405     .long_name= NULL_IF_CONFIG_SMALL("PPM (Portable PixelMap) image"),
406 };
407 #endif // CONFIG_PPM_ENCODER
408
409 #if CONFIG_PBM_ENCODER
410 AVCodec pbm_encoder = {
411     "pbm",
412     CODEC_TYPE_VIDEO,
413     CODEC_ID_PBM,
414     sizeof(PNMContext),
415     common_init,
416     pnm_encode_frame,
417     NULL, //encode_end,
418     pnm_decode_frame,
419     .pix_fmts= (enum PixelFormat[]){PIX_FMT_MONOWHITE, PIX_FMT_NONE},
420     .long_name= NULL_IF_CONFIG_SMALL("PBM (Portable BitMap) image"),
421 };
422 #endif // CONFIG_PBM_ENCODER
423
424 #if CONFIG_PAM_ENCODER
425 AVCodec pam_encoder = {
426     "pam",
427     CODEC_TYPE_VIDEO,
428     CODEC_ID_PAM,
429     sizeof(PNMContext),
430     common_init,
431     pam_encode_frame,
432     NULL, //encode_end,
433     pnm_decode_frame,
434     .pix_fmts= (enum PixelFormat[]){PIX_FMT_RGB24, PIX_FMT_RGB32, PIX_FMT_GRAY8, PIX_FMT_MONOWHITE, PIX_FMT_NONE},
435     .long_name= NULL_IF_CONFIG_SMALL("PAM (Portable AnyMap) image"),
436 };
437 #endif // CONFIG_PAM_ENCODER