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