blob: ba9478d0da517c1fc7b56b917138e4b8e039c9bd
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 | |
22 | #include "libavutil/imgutils.h" |
23 | #include "libavutil/pixdesc.h" |
24 | #include "avcodec.h" |
25 | #include "internal.h" |
26 | |
27 | static int pnm_encode_frame(AVCodecContext *avctx, AVPacket *pkt, |
28 | const AVFrame *p, int *got_packet) |
29 | { |
30 | uint8_t *bytestream, *bytestream_start, *bytestream_end; |
31 | int i, h, h1, c, n, linesize, ret; |
32 | uint8_t *ptr, *ptr1, *ptr2; |
33 | int size = av_image_get_buffer_size(avctx->pix_fmt, |
34 | avctx->width, avctx->height, 1); |
35 | |
36 | if ((ret = ff_alloc_packet2(avctx, pkt, size + 200, 0)) < 0) |
37 | return ret; |
38 | |
39 | bytestream_start = |
40 | bytestream = pkt->data; |
41 | bytestream_end = pkt->data + pkt->size; |
42 | |
43 | h = avctx->height; |
44 | h1 = h; |
45 | switch (avctx->pix_fmt) { |
46 | case AV_PIX_FMT_MONOWHITE: |
47 | c = '4'; |
48 | n = (avctx->width + 7) >> 3; |
49 | break; |
50 | case AV_PIX_FMT_GRAY8: |
51 | c = '5'; |
52 | n = avctx->width; |
53 | break; |
54 | case AV_PIX_FMT_GRAY16BE: |
55 | c = '5'; |
56 | n = avctx->width * 2; |
57 | break; |
58 | case AV_PIX_FMT_RGB24: |
59 | c = '6'; |
60 | n = avctx->width * 3; |
61 | break; |
62 | case AV_PIX_FMT_RGB48BE: |
63 | c = '6'; |
64 | n = avctx->width * 6; |
65 | break; |
66 | case AV_PIX_FMT_YUV420P: |
67 | if (avctx->width & 1 || avctx->height & 1) { |
68 | av_log(avctx, AV_LOG_ERROR, "pgmyuv needs even width and height\n"); |
69 | return AVERROR(EINVAL); |
70 | } |
71 | c = '5'; |
72 | n = avctx->width; |
73 | h1 = (h * 3) / 2; |
74 | break; |
75 | case AV_PIX_FMT_YUV420P16BE: |
76 | c = '5'; |
77 | n = avctx->width * 2; |
78 | h1 = (h * 3) / 2; |
79 | break; |
80 | default: |
81 | return -1; |
82 | } |
83 | snprintf(bytestream, bytestream_end - bytestream, |
84 | "P%c\n%d %d\n", c, avctx->width, h1); |
85 | bytestream += strlen(bytestream); |
86 | if (avctx->pix_fmt != AV_PIX_FMT_MONOWHITE) { |
87 | int maxdepth = (1 << av_pix_fmt_desc_get(avctx->pix_fmt)->comp[0].depth) - 1; |
88 | snprintf(bytestream, bytestream_end - bytestream, |
89 | "%d\n", maxdepth); |
90 | bytestream += strlen(bytestream); |
91 | } |
92 | |
93 | ptr = p->data[0]; |
94 | linesize = p->linesize[0]; |
95 | for (i = 0; i < h; i++) { |
96 | memcpy(bytestream, ptr, n); |
97 | bytestream += n; |
98 | ptr += linesize; |
99 | } |
100 | |
101 | if (avctx->pix_fmt == AV_PIX_FMT_YUV420P || avctx->pix_fmt == AV_PIX_FMT_YUV420P16BE) { |
102 | h >>= 1; |
103 | n >>= 1; |
104 | ptr1 = p->data[1]; |
105 | ptr2 = p->data[2]; |
106 | for (i = 0; i < h; i++) { |
107 | memcpy(bytestream, ptr1, n); |
108 | bytestream += n; |
109 | memcpy(bytestream, ptr2, n); |
110 | bytestream += n; |
111 | ptr1 += p->linesize[1]; |
112 | ptr2 += p->linesize[2]; |
113 | } |
114 | } |
115 | pkt->size = bytestream - bytestream_start; |
116 | pkt->flags |= AV_PKT_FLAG_KEY; |
117 | *got_packet = 1; |
118 | |
119 | return 0; |
120 | } |
121 | |
122 | static av_cold int pnm_encode_init(AVCodecContext *avctx) |
123 | { |
124 | #if FF_API_CODED_FRAME |
125 | FF_DISABLE_DEPRECATION_WARNINGS |
126 | avctx->coded_frame->pict_type = AV_PICTURE_TYPE_I; |
127 | avctx->coded_frame->key_frame = 1; |
128 | FF_ENABLE_DEPRECATION_WARNINGS |
129 | #endif |
130 | |
131 | return 0; |
132 | } |
133 | |
134 | #if CONFIG_PGM_ENCODER |
135 | AVCodec ff_pgm_encoder = { |
136 | .name = "pgm", |
137 | .long_name = NULL_IF_CONFIG_SMALL("PGM (Portable GrayMap) image"), |
138 | .type = AVMEDIA_TYPE_VIDEO, |
139 | .id = AV_CODEC_ID_PGM, |
140 | .init = pnm_encode_init, |
141 | .encode2 = pnm_encode_frame, |
142 | .pix_fmts = (const enum AVPixelFormat[]){ |
143 | AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY16BE, AV_PIX_FMT_NONE |
144 | }, |
145 | }; |
146 | #endif |
147 | |
148 | #if CONFIG_PGMYUV_ENCODER |
149 | AVCodec ff_pgmyuv_encoder = { |
150 | .name = "pgmyuv", |
151 | .long_name = NULL_IF_CONFIG_SMALL("PGMYUV (Portable GrayMap YUV) image"), |
152 | .type = AVMEDIA_TYPE_VIDEO, |
153 | .id = AV_CODEC_ID_PGMYUV, |
154 | .init = pnm_encode_init, |
155 | .encode2 = pnm_encode_frame, |
156 | .pix_fmts = (const enum AVPixelFormat[]){ |
157 | AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV420P16BE, AV_PIX_FMT_NONE |
158 | }, |
159 | }; |
160 | #endif |
161 | |
162 | #if CONFIG_PPM_ENCODER |
163 | AVCodec ff_ppm_encoder = { |
164 | .name = "ppm", |
165 | .long_name = NULL_IF_CONFIG_SMALL("PPM (Portable PixelMap) image"), |
166 | .type = AVMEDIA_TYPE_VIDEO, |
167 | .id = AV_CODEC_ID_PPM, |
168 | .init = pnm_encode_init, |
169 | .encode2 = pnm_encode_frame, |
170 | .pix_fmts = (const enum AVPixelFormat[]){ |
171 | AV_PIX_FMT_RGB24, AV_PIX_FMT_RGB48BE, AV_PIX_FMT_NONE |
172 | }, |
173 | }; |
174 | #endif |
175 | |
176 | #if CONFIG_PBM_ENCODER |
177 | AVCodec ff_pbm_encoder = { |
178 | .name = "pbm", |
179 | .long_name = NULL_IF_CONFIG_SMALL("PBM (Portable BitMap) image"), |
180 | .type = AVMEDIA_TYPE_VIDEO, |
181 | .id = AV_CODEC_ID_PBM, |
182 | .init = pnm_encode_init, |
183 | .encode2 = pnm_encode_frame, |
184 | .pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_MONOWHITE, |
185 | AV_PIX_FMT_NONE }, |
186 | }; |
187 | #endif |
188 |