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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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 if(s
->bytestream
+ n
*avctx
->height
> s
->bytestream_end
)
203 for(i
= 0; i
< avctx
->height
; i
++) {
204 memcpy(ptr
, s
->bytestream
, n
);
209 case PIX_FMT_YUV420P
:
211 unsigned char *ptr1
, *ptr2
;
215 linesize
= p
->linesize
[0];
216 if(s
->bytestream
+ n
*avctx
->height
*3/2 > s
->bytestream_end
)
218 for(i
= 0; i
< avctx
->height
; i
++) {
219 memcpy(ptr
, s
->bytestream
, n
);
226 h
= avctx
->height
>> 1;
227 for(i
= 0; i
< h
; i
++) {
228 memcpy(ptr1
, s
->bytestream
, n
);
230 memcpy(ptr2
, s
->bytestream
, n
);
232 ptr1
+= p
->linesize
[1];
233 ptr2
+= p
->linesize
[2];
239 linesize
= p
->linesize
[0];
240 if(s
->bytestream
+ avctx
->width
*avctx
->height
*4 > s
->bytestream_end
)
242 for(i
= 0; i
< avctx
->height
; i
++) {
245 for(j
= 0;j
< avctx
->width
; j
++) {
246 r
= *s
->bytestream
++;
247 g
= *s
->bytestream
++;
248 b
= *s
->bytestream
++;
249 a
= *s
->bytestream
++;
250 ((uint32_t *)ptr
)[j
] = (a
<< 24) | (r
<< 16) | (g
<< 8) | b
;
256 *picture
= *(AVFrame
*)&s
->picture
;
257 *data_size
= sizeof(AVPicture
);
259 return s
->bytestream
- s
->bytestream_start
;
262 static int pnm_encode_frame(AVCodecContext
*avctx
, unsigned char *outbuf
, int buf_size
, void *data
){
263 PNMContext
*s
= avctx
->priv_data
;
264 AVFrame
*pict
= data
;
265 AVFrame
* const p
= (AVFrame
*)&s
->picture
;
266 int i
, h
, h1
, c
, n
, linesize
;
267 uint8_t *ptr
, *ptr1
, *ptr2
;
269 if(buf_size
< avpicture_get_size(avctx
->pix_fmt
, avctx
->width
, avctx
->height
) + 200){
270 av_log(avctx
, AV_LOG_ERROR
, "encoded frame too large\n");
275 p
->pict_type
= FF_I_TYPE
;
279 s
->bytestream
= outbuf
;
280 s
->bytestream_end
= outbuf
+buf_size
;
284 switch(avctx
->pix_fmt
) {
285 case PIX_FMT_MONOWHITE
:
287 n
= (avctx
->width
+ 7) >> 3;
295 n
= avctx
->width
* 3;
297 case PIX_FMT_YUV420P
:
305 snprintf(s
->bytestream
, s
->bytestream_end
- s
->bytestream
,
307 c
, avctx
->width
, h1
);
308 s
->bytestream
+= strlen(s
->bytestream
);
309 if (avctx
->pix_fmt
!= PIX_FMT_MONOWHITE
) {
310 snprintf(s
->bytestream
, s
->bytestream_end
- s
->bytestream
,
312 s
->bytestream
+= strlen(s
->bytestream
);
316 linesize
= p
->linesize
[0];
318 memcpy(s
->bytestream
, ptr
, n
);
323 if (avctx
->pix_fmt
== PIX_FMT_YUV420P
) {
329 memcpy(s
->bytestream
, ptr1
, n
);
331 memcpy(s
->bytestream
, ptr2
, n
);
333 ptr1
+= p
->linesize
[1];
334 ptr2
+= p
->linesize
[2];
337 return s
->bytestream
- s
->bytestream_start
;
340 static int pam_encode_frame(AVCodecContext
*avctx
, unsigned char *outbuf
, int buf_size
, void *data
){
341 PNMContext
*s
= avctx
->priv_data
;
342 AVFrame
*pict
= data
;
343 AVFrame
* const p
= (AVFrame
*)&s
->picture
;
344 int i
, h
, w
, n
, linesize
, depth
, maxval
;
345 const char *tuple_type
;
348 if(buf_size
< avpicture_get_size(avctx
->pix_fmt
, avctx
->width
, avctx
->height
) + 200){
349 av_log(avctx
, AV_LOG_ERROR
, "encoded frame too large\n");
354 p
->pict_type
= FF_I_TYPE
;
358 s
->bytestream
= outbuf
;
359 s
->bytestream_end
= outbuf
+buf_size
;
363 switch(avctx
->pix_fmt
) {
364 case PIX_FMT_MONOWHITE
:
368 tuple_type
= "BLACKANDWHITE";
374 tuple_type
= "GRAYSCALE";
386 tuple_type
= "RGB_ALPHA";
391 snprintf(s
->bytestream
, s
->bytestream_end
- s
->bytestream
,
392 "P7\nWIDTH %d\nHEIGHT %d\nDEPTH %d\nMAXVAL %d\nTUPLETYPE %s\nENDHDR\n",
393 w
, h
, depth
, maxval
, tuple_type
);
394 s
->bytestream
+= strlen(s
->bytestream
);
397 linesize
= p
->linesize
[0];
399 if (avctx
->pix_fmt
== PIX_FMT_RGBA32
) {
405 v
= ((uint32_t *)ptr
)[j
];
406 *s
->bytestream
++ = v
>> 16;
407 *s
->bytestream
++ = v
>> 8;
408 *s
->bytestream
++ = v
;
409 *s
->bytestream
++ = v
>> 24;
415 memcpy(s
->bytestream
, ptr
, n
);
420 return s
->bytestream
- s
->bytestream_start
;
424 static int pnm_probe(AVProbeData
*pd
)
426 const char *p
= pd
->buf
;
427 if (pd
->buf_size
>= 8 &&
429 p
[1] >= '4' && p
[1] <= '6' &&
431 return AVPROBE_SCORE_MAX
- 1; /* to permit pgmyuv probe */
436 static int pgmyuv_probe(AVProbeData
*pd
)
438 if (match_ext(pd
->filename
, "pgmyuv"))
439 return AVPROBE_SCORE_MAX
;
444 static int pam_probe(AVProbeData
*pd
)
446 const char *p
= pd
->buf
;
447 if (pd
->buf_size
>= 8 &&
451 return AVPROBE_SCORE_MAX
;
457 #ifdef CONFIG_PNM_PARSER
458 static int pnm_parse(AVCodecParserContext
*s
,
459 AVCodecContext
*avctx
,
460 uint8_t **poutbuf
, int *poutbuf_size
,
461 const uint8_t *buf
, int buf_size
)
463 ParseContext
*pc
= s
->priv_data
;
467 for(; pc
->overread
>0; pc
->overread
--){
468 pc
->buffer
[pc
->index
++]= pc
->buffer
[pc
->overread_index
++];
472 pnmctx
.bytestream_start
=
473 pnmctx
.bytestream
= pc
->buffer
;
474 pnmctx
.bytestream_end
= pc
->buffer
+ pc
->index
;
476 pnmctx
.bytestream_start
=
477 pnmctx
.bytestream
= (uint8_t *) buf
; /* casts avoid warnings */
478 pnmctx
.bytestream_end
= (uint8_t *) buf
+ buf_size
;
480 if(pnm_decode_header(avctx
, &pnmctx
) < 0){
481 if(pnmctx
.bytestream
< pnmctx
.bytestream_end
){
491 if(pc
->index
&& pc
->index
*2 + FF_INPUT_BUFFER_PADDING_SIZE
< pc
->buffer_size
&& buf_size
> pc
->index
){
492 memcpy(pc
->buffer
+ pc
->index
, buf
, pc
->index
);
493 pc
->index
+= pc
->index
;
495 buf_size
-= pc
->index
;
501 next
= pnmctx
.bytestream
- pnmctx
.bytestream_start
502 + avpicture_get_size(avctx
->pix_fmt
, avctx
->width
, avctx
->height
);
503 if(pnmctx
.bytestream_start
!=buf
)
509 if(ff_combine_frame(pc
, next
, (uint8_t **)&buf
, &buf_size
)<0){
514 *poutbuf
= (uint8_t *)buf
;
515 *poutbuf_size
= buf_size
;
519 AVCodecParser pnm_parser
= {
520 { CODEC_ID_PGM
, CODEC_ID_PGMYUV
, CODEC_ID_PPM
, CODEC_ID_PBM
, CODEC_ID_PAM
},
521 sizeof(ParseContext
),
526 #endif /* CONFIG_PNM_PARSER */
528 #ifdef CONFIG_PGM_ENCODER
529 AVCodec pgm_encoder
= {
538 .pix_fmts
= (enum PixelFormat
[]){PIX_FMT_GRAY8
, -1},
540 #endif // CONFIG_PGM_ENCODER
542 #ifdef CONFIG_PGMYUV_ENCODER
543 AVCodec pgmyuv_encoder
= {
552 .pix_fmts
= (enum PixelFormat
[]){PIX_FMT_YUV420P
, -1},
554 #endif // CONFIG_PGMYUV_ENCODER
556 #ifdef CONFIG_PPM_ENCODER
557 AVCodec ppm_encoder
= {
566 .pix_fmts
= (enum PixelFormat
[]){PIX_FMT_RGB24
, -1},
568 #endif // CONFIG_PPM_ENCODER
570 #ifdef CONFIG_PBM_ENCODER
571 AVCodec pbm_encoder
= {
580 .pix_fmts
= (enum PixelFormat
[]){PIX_FMT_MONOWHITE
, -1},
582 #endif // CONFIG_PBM_ENCODER
584 #ifdef CONFIG_PAM_ENCODER
585 AVCodec pam_encoder
= {
594 .pix_fmts
= (enum PixelFormat
[]){PIX_FMT_RGB24
, PIX_FMT_RGBA32
, PIX_FMT_GRAY8
, PIX_FMT_MONOWHITE
, -1},
596 #endif // CONFIG_PAM_ENCODER