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