3 * Copyright (c) 2002, 2003 Fabrice Bellard.
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 #include "mpegvideo.h" //only for ParseContext
22 typedef struct PNMContext
{
24 uint8_t *bytestream_start
;
25 uint8_t *bytestream_end
;
29 static inline int pnm_space(int c
)
31 return (c
== ' ' || c
== '\n' || c
== '\r' || c
== '\t');
34 static void pnm_get(PNMContext
*sc
, char *str
, int buf_size
)
39 /* skip spaces and comments */
41 c
= *sc
->bytestream
++;
44 c
= *sc
->bytestream
++;
45 } while (c
!= '\n' && sc
->bytestream
< sc
->bytestream_end
);
46 } else if (!pnm_space(c
)) {
52 while (sc
->bytestream
< sc
->bytestream_end
&& !pnm_space(c
)) {
53 if ((s
- str
) < buf_size
- 1)
55 c
= *sc
->bytestream
++;
60 static int common_init(AVCodecContext
*avctx
){
61 PNMContext
*s
= avctx
->priv_data
;
63 avcodec_get_frame_defaults((AVFrame
*)&s
->picture
);
64 avctx
->coded_frame
= (AVFrame
*)&s
->picture
;
69 static int pnm_decode_header(AVCodecContext
*avctx
, PNMContext
* const s
){
70 char buf1
[32], tuple_type
[32];
71 int h
, w
, depth
, maxval
;;
73 pnm_get(s
, buf1
, sizeof(buf1
));
74 if (!strcmp(buf1
, "P4")) {
75 avctx
->pix_fmt
= PIX_FMT_MONOWHITE
;
76 } else if (!strcmp(buf1
, "P5")) {
77 if (avctx
->codec_id
== CODEC_ID_PGMYUV
)
78 avctx
->pix_fmt
= PIX_FMT_YUV420P
;
80 avctx
->pix_fmt
= PIX_FMT_GRAY8
;
81 } else if (!strcmp(buf1
, "P6")) {
82 avctx
->pix_fmt
= PIX_FMT_RGB24
;
83 } else if (!strcmp(buf1
, "P7")) {
90 pnm_get(s
, buf1
, sizeof(buf1
));
91 if (!strcmp(buf1
, "WIDTH")) {
92 pnm_get(s
, buf1
, sizeof(buf1
));
93 w
= strtol(buf1
, NULL
, 10);
94 } else if (!strcmp(buf1
, "HEIGHT")) {
95 pnm_get(s
, buf1
, sizeof(buf1
));
96 h
= strtol(buf1
, NULL
, 10);
97 } else if (!strcmp(buf1
, "DEPTH")) {
98 pnm_get(s
, buf1
, sizeof(buf1
));
99 depth
= strtol(buf1
, NULL
, 10);
100 } else if (!strcmp(buf1
, "MAXVAL")) {
101 pnm_get(s
, buf1
, sizeof(buf1
));
102 maxval
= strtol(buf1
, NULL
, 10);
103 } else if (!strcmp(buf1
, "TUPLETYPE")) {
104 pnm_get(s
, tuple_type
, sizeof(tuple_type
));
105 } else if (!strcmp(buf1
, "ENDHDR")) {
111 /* check that all tags are present */
112 if (w
<= 0 || h
<= 0 || maxval
<= 0 || depth
<= 0 || tuple_type
[0] == '\0' || avcodec_check_dimensions(avctx
, w
, h
))
119 avctx
->pix_fmt
= PIX_FMT_MONOWHITE
;
121 avctx
->pix_fmt
= PIX_FMT_GRAY8
;
122 } else if (depth
== 3) {
123 avctx
->pix_fmt
= PIX_FMT_RGB24
;
124 } else if (depth
== 4) {
125 avctx
->pix_fmt
= PIX_FMT_RGBA32
;
133 pnm_get(s
, buf1
, sizeof(buf1
));
134 avctx
->width
= atoi(buf1
);
135 if (avctx
->width
<= 0)
137 pnm_get(s
, buf1
, sizeof(buf1
));
138 avctx
->height
= atoi(buf1
);
139 if(avcodec_check_dimensions(avctx
, avctx
->width
, avctx
->height
))
141 if (avctx
->pix_fmt
!= PIX_FMT_MONOWHITE
) {
142 pnm_get(s
, buf1
, sizeof(buf1
));
145 /* more check if YUV420 */
146 if (avctx
->pix_fmt
== PIX_FMT_YUV420P
) {
147 if ((avctx
->width
& 1) != 0)
149 h
= (avctx
->height
* 2);
158 static int pnm_decode_frame(AVCodecContext
*avctx
,
159 void *data
, int *data_size
,
160 uint8_t *buf
, int buf_size
)
162 PNMContext
* const s
= avctx
->priv_data
;
163 AVFrame
*picture
= data
;
164 AVFrame
* const p
= (AVFrame
*)&s
->picture
;
165 int i
, n
, linesize
, h
;
170 s
->bytestream_end
= buf
+ buf_size
;
172 if(pnm_decode_header(avctx
, s
) < 0)
176 avctx
->release_buffer(avctx
, p
);
179 if(avctx
->get_buffer(avctx
, p
) < 0){
180 av_log(avctx
, AV_LOG_ERROR
, "get_buffer() failed\n");
183 p
->pict_type
= FF_I_TYPE
;
186 switch(avctx
->pix_fmt
) {
190 n
= avctx
->width
* 3;
195 case PIX_FMT_MONOWHITE
:
196 case PIX_FMT_MONOBLACK
:
197 n
= (avctx
->width
+ 7) >> 3;
200 linesize
= p
->linesize
[0];
201 for(i
= 0; i
< avctx
->height
; i
++) {
202 memcpy(ptr
, s
->bytestream
, n
);
207 case PIX_FMT_YUV420P
:
209 unsigned char *ptr1
, *ptr2
;
213 linesize
= p
->linesize
[0];
214 for(i
= 0; i
< avctx
->height
; i
++) {
215 memcpy(ptr
, s
->bytestream
, n
);
222 h
= avctx
->height
>> 1;
223 for(i
= 0; i
< h
; i
++) {
224 memcpy(ptr1
, s
->bytestream
, n
);
226 memcpy(ptr2
, s
->bytestream
, n
);
228 ptr1
+= p
->linesize
[1];
229 ptr2
+= p
->linesize
[2];
235 linesize
= p
->linesize
[0];
236 for(i
= 0; i
< avctx
->height
; i
++) {
239 for(j
= 0;j
< avctx
->width
; j
++) {
240 r
= *s
->bytestream
++;
241 g
= *s
->bytestream
++;
242 b
= *s
->bytestream
++;
243 a
= *s
->bytestream
++;
244 ((uint32_t *)ptr
)[j
] = (a
<< 24) | (r
<< 16) | (g
<< 8) | b
;
250 *picture
= *(AVFrame
*)&s
->picture
;
251 *data_size
= sizeof(AVPicture
);
253 return s
->bytestream
- s
->bytestream_start
;
256 static int pnm_encode_frame(AVCodecContext
*avctx
, unsigned char *outbuf
, int buf_size
, void *data
){
257 PNMContext
*s
= avctx
->priv_data
;
258 AVFrame
*pict
= data
;
259 AVFrame
* const p
= (AVFrame
*)&s
->picture
;
260 int i
, h
, h1
, c
, n
, linesize
;
261 uint8_t *ptr
, *ptr1
, *ptr2
;
263 if(buf_size
< avpicture_get_size(avctx
->pix_fmt
, avctx
->width
, avctx
->height
) + 200){
264 av_log(avctx
, AV_LOG_ERROR
, "encoded frame too large\n");
269 p
->pict_type
= FF_I_TYPE
;
273 s
->bytestream
= outbuf
;
274 s
->bytestream_end
= outbuf
+buf_size
;
278 switch(avctx
->pix_fmt
) {
279 case PIX_FMT_MONOWHITE
:
281 n
= (avctx
->width
+ 7) >> 3;
289 n
= avctx
->width
* 3;
291 case PIX_FMT_YUV420P
:
299 snprintf(s
->bytestream
, s
->bytestream_end
- s
->bytestream
,
301 c
, avctx
->width
, h1
);
302 s
->bytestream
+= strlen(s
->bytestream
);
303 if (avctx
->pix_fmt
!= PIX_FMT_MONOWHITE
) {
304 snprintf(s
->bytestream
, s
->bytestream_end
- s
->bytestream
,
306 s
->bytestream
+= strlen(s
->bytestream
);
310 linesize
= p
->linesize
[0];
312 memcpy(s
->bytestream
, ptr
, n
);
317 if (avctx
->pix_fmt
== PIX_FMT_YUV420P
) {
323 memcpy(s
->bytestream
, ptr1
, n
);
325 memcpy(s
->bytestream
, ptr2
, n
);
327 ptr1
+= p
->linesize
[1];
328 ptr2
+= p
->linesize
[2];
331 return s
->bytestream
- s
->bytestream_start
;
334 static int pam_encode_frame(AVCodecContext
*avctx
, unsigned char *outbuf
, int buf_size
, void *data
){
335 PNMContext
*s
= avctx
->priv_data
;
336 AVFrame
*pict
= data
;
337 AVFrame
* const p
= (AVFrame
*)&s
->picture
;
338 int i
, h
, w
, n
, linesize
, depth
, maxval
;
339 const char *tuple_type
;
342 if(buf_size
< avpicture_get_size(avctx
->pix_fmt
, avctx
->width
, avctx
->height
) + 200){
343 av_log(avctx
, AV_LOG_ERROR
, "encoded frame too large\n");
348 p
->pict_type
= FF_I_TYPE
;
352 s
->bytestream
= outbuf
;
353 s
->bytestream_end
= outbuf
+buf_size
;
357 switch(avctx
->pix_fmt
) {
358 case PIX_FMT_MONOWHITE
:
362 tuple_type
= "BLACKANDWHITE";
368 tuple_type
= "GRAYSCALE";
380 tuple_type
= "RGB_ALPHA";
385 snprintf(s
->bytestream
, s
->bytestream_end
- s
->bytestream
,
386 "P7\nWIDTH %d\nHEIGHT %d\nDEPTH %d\nMAXVAL %d\nTUPLETYPE %s\nENDHDR\n",
387 w
, h
, depth
, maxval
, tuple_type
);
388 s
->bytestream
+= strlen(s
->bytestream
);
391 linesize
= p
->linesize
[0];
393 if (avctx
->pix_fmt
== PIX_FMT_RGBA32
) {
399 v
= ((uint32_t *)ptr
)[j
];
400 *s
->bytestream
++ = v
>> 16;
401 *s
->bytestream
++ = v
>> 8;
402 *s
->bytestream
++ = v
;
403 *s
->bytestream
++ = v
>> 24;
409 memcpy(s
->bytestream
, ptr
, n
);
414 return s
->bytestream
- s
->bytestream_start
;
418 static int pnm_probe(AVProbeData
*pd
)
420 const char *p
= pd
->buf
;
421 if (pd
->buf_size
>= 8 &&
423 p
[1] >= '4' && p
[1] <= '6' &&
425 return AVPROBE_SCORE_MAX
- 1; /* to permit pgmyuv probe */
430 static int pgmyuv_probe(AVProbeData
*pd
)
432 if (match_ext(pd
->filename
, "pgmyuv"))
433 return AVPROBE_SCORE_MAX
;
438 static int pam_probe(AVProbeData
*pd
)
440 const char *p
= pd
->buf
;
441 if (pd
->buf_size
>= 8 &&
445 return AVPROBE_SCORE_MAX
;
451 static int pnm_parse(AVCodecParserContext
*s
,
452 AVCodecContext
*avctx
,
453 uint8_t **poutbuf
, int *poutbuf_size
,
454 const uint8_t *buf
, int buf_size
)
456 ParseContext
*pc
= s
->priv_data
;
460 for(; pc
->overread
>0; pc
->overread
--){
461 pc
->buffer
[pc
->index
++]= pc
->buffer
[pc
->overread_index
++];
465 pnmctx
.bytestream_start
=
466 pnmctx
.bytestream
= pc
->buffer
;
467 pnmctx
.bytestream_end
= pc
->buffer
+ pc
->index
;
469 pnmctx
.bytestream_start
=
470 pnmctx
.bytestream
= buf
;
471 pnmctx
.bytestream_end
= buf
+ buf_size
;
473 if(pnm_decode_header(avctx
, &pnmctx
) < 0){
474 if(pnmctx
.bytestream
< pnmctx
.bytestream_end
){
484 if(pc
->index
&& pc
->index
*2 + FF_INPUT_BUFFER_PADDING_SIZE
< pc
->buffer_size
&& buf_size
> pc
->index
){
485 memcpy(pc
->buffer
+ pc
->index
, buf
, pc
->index
);
486 pc
->index
+= pc
->index
;
488 buf_size
-= pc
->index
;
494 next
= pnmctx
.bytestream
- pnmctx
.bytestream_start
495 + avpicture_get_size(avctx
->pix_fmt
, avctx
->width
, avctx
->height
);
496 if(pnmctx
.bytestream_start
!=buf
)
502 if(ff_combine_frame(pc
, next
, (uint8_t **)&buf
, &buf_size
)<0){
507 *poutbuf
= (uint8_t *)buf
;
508 *poutbuf_size
= buf_size
;
512 AVCodecParser pnm_parser
= {
513 { CODEC_ID_PGM
, CODEC_ID_PGMYUV
, CODEC_ID_PPM
, CODEC_ID_PBM
, CODEC_ID_PAM
},
514 sizeof(ParseContext
),
520 #ifdef CONFIG_PGM_ENCODER
521 AVCodec pgm_encoder
= {
530 .pix_fmts
= (enum PixelFormat
[]){PIX_FMT_GRAY8
, -1},
532 #endif // CONFIG_PGM_ENCODER
534 #ifdef CONFIG_PGMYUV_ENCODER
535 AVCodec pgmyuv_encoder
= {
544 .pix_fmts
= (enum PixelFormat
[]){PIX_FMT_YUV420P
, -1},
546 #endif // CONFIG_PGMYUV_ENCODER
548 #ifdef CONFIG_PPM_ENCODER
549 AVCodec ppm_encoder
= {
558 .pix_fmts
= (enum PixelFormat
[]){PIX_FMT_RGB24
, -1},
560 #endif // CONFIG_PPM_ENCODER
562 #ifdef CONFIG_PBM_ENCODER
563 AVCodec pbm_encoder
= {
572 .pix_fmts
= (enum PixelFormat
[]){PIX_FMT_MONOWHITE
, -1},
574 #endif // CONFIG_PBM_ENCODER
576 #ifdef CONFIG_PAM_ENCODER
577 AVCodec pam_encoder
= {
586 .pix_fmts
= (enum PixelFormat
[]){PIX_FMT_RGB24
, PIX_FMT_RGBA32
, PIX_FMT_GRAY8
, PIX_FMT_MONOWHITE
, -1},
588 #endif // CONFIG_PAM_ENCODER