/src/ffmpeg/libavcodec/pnmenc.c
Line | Count | Source (jump to first uncovered line) |
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 "config_components.h" |
23 | | |
24 | | #include "libavutil/intreadwrite.h" |
25 | | #include "libavutil/imgutils.h" |
26 | | #include "libavutil/pixdesc.h" |
27 | | #include "libavutil/float2half.h" |
28 | | #include "avcodec.h" |
29 | | #include "codec_internal.h" |
30 | | #include "encode.h" |
31 | | |
32 | | typedef struct PHMEncContext { |
33 | | Float2HalfTables f2h_tables; |
34 | | } PHMEncContext; |
35 | | |
36 | | static int pnm_encode_frame(AVCodecContext *avctx, AVPacket *pkt, |
37 | | const AVFrame *p, int *got_packet) |
38 | 39.0k | { |
39 | 39.0k | PHMEncContext *s = avctx->priv_data; |
40 | 39.0k | uint8_t *bytestream, *bytestream_start, *bytestream_end; |
41 | 39.0k | int i, h, h1, c, n, linesize, ret; |
42 | 39.0k | int size = av_image_get_buffer_size(avctx->pix_fmt, |
43 | 39.0k | avctx->width, avctx->height, 1); |
44 | | |
45 | 39.0k | if (size < 0) |
46 | 0 | return size; |
47 | | |
48 | 39.0k | if ((ret = ff_get_encode_buffer(avctx, pkt, size + 200U, 0)) < 0) |
49 | 0 | return ret; |
50 | | |
51 | 39.0k | bytestream_start = |
52 | 39.0k | bytestream = pkt->data; |
53 | 39.0k | bytestream_end = pkt->data + pkt->size; |
54 | | |
55 | 39.0k | h = avctx->height; |
56 | 39.0k | h1 = h; |
57 | 39.0k | switch (avctx->pix_fmt) { |
58 | 7.40k | case AV_PIX_FMT_MONOWHITE: |
59 | 7.40k | c = '4'; |
60 | 7.40k | n = (avctx->width + 7) >> 3; |
61 | 7.40k | break; |
62 | 5.10k | case AV_PIX_FMT_GRAY8: |
63 | 5.10k | c = '5'; |
64 | 5.10k | n = avctx->width; |
65 | 5.10k | break; |
66 | 2.12k | case AV_PIX_FMT_GRAY16BE: |
67 | 2.12k | c = '5'; |
68 | 2.12k | n = avctx->width * 2; |
69 | 2.12k | break; |
70 | 2.64k | case AV_PIX_FMT_RGB24: |
71 | 2.64k | c = '6'; |
72 | 2.64k | n = avctx->width * 3; |
73 | 2.64k | break; |
74 | 822 | case AV_PIX_FMT_RGB48BE: |
75 | 822 | c = '6'; |
76 | 822 | n = avctx->width * 6; |
77 | 822 | break; |
78 | 3.13k | case AV_PIX_FMT_YUV420P: |
79 | 3.13k | if (avctx->width & 1 || avctx->height & 1) { |
80 | 24 | av_log(avctx, AV_LOG_ERROR, "pgmyuv needs even width and height\n"); |
81 | 24 | return AVERROR(EINVAL); |
82 | 24 | } |
83 | 3.11k | c = '5'; |
84 | 3.11k | n = avctx->width; |
85 | 3.11k | h1 = (h * 3) / 2; |
86 | 3.11k | break; |
87 | 2.29k | case AV_PIX_FMT_YUV420P16BE: |
88 | 2.29k | c = '5'; |
89 | 2.29k | n = avctx->width * 2; |
90 | 2.29k | h1 = (h * 3) / 2; |
91 | 2.29k | break; |
92 | 315 | case AV_PIX_FMT_GBRPF32BE: |
93 | 2.26k | case AV_PIX_FMT_GBRPF32LE: |
94 | 2.26k | if (avctx->codec_id == AV_CODEC_ID_PFM) { |
95 | 1.31k | c = 'F'; |
96 | 1.31k | n = avctx->width * 4; |
97 | 1.31k | } else { |
98 | 948 | c = 'H'; |
99 | 948 | n = avctx->width * 2; |
100 | 948 | } |
101 | 2.26k | break; |
102 | 4.24k | case AV_PIX_FMT_GRAYF32BE: |
103 | 13.2k | case AV_PIX_FMT_GRAYF32LE: |
104 | 13.2k | if (avctx->codec_id == AV_CODEC_ID_PFM) { |
105 | 6.46k | c = 'f'; |
106 | 6.46k | n = avctx->width * 4; |
107 | 6.81k | } else { |
108 | 6.81k | c = 'h'; |
109 | 6.81k | n = avctx->width * 2; |
110 | 6.81k | } |
111 | 13.2k | break; |
112 | 0 | default: |
113 | 0 | return -1; |
114 | 39.0k | } |
115 | 39.0k | snprintf(bytestream, bytestream_end - bytestream, |
116 | 39.0k | "P%c\n%d %d\n", c, avctx->width, h1); |
117 | 39.0k | bytestream += strlen(bytestream); |
118 | 39.0k | if (avctx->pix_fmt == AV_PIX_FMT_GBRPF32LE || |
119 | 39.0k | avctx->pix_fmt == AV_PIX_FMT_GRAYF32LE || |
120 | 39.0k | avctx->pix_fmt == AV_PIX_FMT_GBRPF32BE || |
121 | 39.0k | avctx->pix_fmt == AV_PIX_FMT_GRAYF32BE) |
122 | 15.5k | snprintf(bytestream, bytestream_end - bytestream, |
123 | 15.5k | "%f\n", (avctx->pix_fmt == AV_PIX_FMT_GBRPF32BE || |
124 | 15.5k | avctx->pix_fmt == AV_PIX_FMT_GRAYF32BE) ? 1.f: -1.f); |
125 | 39.0k | bytestream += strlen(bytestream); |
126 | 39.0k | if (avctx->pix_fmt != AV_PIX_FMT_MONOWHITE && |
127 | 39.0k | avctx->pix_fmt != AV_PIX_FMT_GBRPF32LE && |
128 | 39.0k | avctx->pix_fmt != AV_PIX_FMT_GRAYF32LE && |
129 | 39.0k | avctx->pix_fmt != AV_PIX_FMT_GBRPF32BE && |
130 | 39.0k | avctx->pix_fmt != AV_PIX_FMT_GRAYF32BE) { |
131 | 16.1k | int maxdepth = (1 << av_pix_fmt_desc_get(avctx->pix_fmt)->comp[0].depth) - 1; |
132 | 16.1k | snprintf(bytestream, bytestream_end - bytestream, |
133 | 16.1k | "%d\n", maxdepth); |
134 | 16.1k | bytestream += strlen(bytestream); |
135 | 16.1k | } |
136 | | |
137 | 39.0k | if ((avctx->pix_fmt == AV_PIX_FMT_GBRPF32LE || |
138 | 39.0k | avctx->pix_fmt == AV_PIX_FMT_GBRPF32BE) && c == 'F') { |
139 | | /* PFM is encoded from bottom to top */ |
140 | 1.31k | const float *r = (const float *)(p->data[2] + p->linesize[2] * (avctx->height - 1)); |
141 | 1.31k | const float *g = (const float *)(p->data[0] + p->linesize[0] * (avctx->height - 1)); |
142 | 1.31k | const float *b = (const float *)(p->data[1] + p->linesize[1] * (avctx->height - 1)); |
143 | | |
144 | 847k | for (int i = 0; i < avctx->height; i++) { |
145 | 6.82M | for (int j = 0; j < avctx->width; j++) { |
146 | 5.97M | AV_WN32(bytestream + 0, av_float2int(r[j])); |
147 | 5.97M | AV_WN32(bytestream + 4, av_float2int(g[j])); |
148 | 5.97M | AV_WN32(bytestream + 8, av_float2int(b[j])); |
149 | 5.97M | bytestream += 12; |
150 | 5.97M | } |
151 | | |
152 | 845k | r -= p->linesize[2] / 4; |
153 | 845k | g -= p->linesize[0] / 4; |
154 | 845k | b -= p->linesize[1] / 4; |
155 | 845k | } |
156 | 37.7k | } else if ((avctx->pix_fmt == AV_PIX_FMT_GRAYF32LE || |
157 | 37.7k | avctx->pix_fmt == AV_PIX_FMT_GRAYF32BE) && c == 'f') { |
158 | | /* PFM is encoded from bottom to top */ |
159 | 6.46k | const float *g = (const float *)(p->data[0] + p->linesize[0] * (avctx->height - 1)); |
160 | | |
161 | 705k | for (int i = 0; i < avctx->height; i++) { |
162 | 4.21M | for (int j = 0; j < avctx->width; j++) { |
163 | 3.51M | AV_WN32(bytestream, av_float2int(g[j])); |
164 | 3.51M | bytestream += 4; |
165 | 3.51M | } |
166 | | |
167 | 698k | g -= p->linesize[0] / 4; |
168 | 698k | } |
169 | 31.2k | } else if (avctx->pix_fmt == AV_PIX_FMT_GBRPF32 && c == 'H') { |
170 | 948 | const float *r = (const float *)p->data[2]; |
171 | 948 | const float *g = (const float *)p->data[0]; |
172 | 948 | const float *b = (const float *)p->data[1]; |
173 | | |
174 | 939k | for (int i = 0; i < avctx->height; i++) { |
175 | 7.24M | for (int j = 0; j < avctx->width; j++) { |
176 | 6.30M | AV_WN16(bytestream + 0, float2half(av_float2int(r[j]), &s->f2h_tables)); |
177 | 6.30M | AV_WN16(bytestream + 2, float2half(av_float2int(g[j]), &s->f2h_tables)); |
178 | 6.30M | AV_WN16(bytestream + 4, float2half(av_float2int(b[j]), &s->f2h_tables)); |
179 | 6.30M | bytestream += 6; |
180 | 6.30M | } |
181 | | |
182 | 938k | r += p->linesize[2] / 4; |
183 | 938k | g += p->linesize[0] / 4; |
184 | 938k | b += p->linesize[1] / 4; |
185 | 938k | } |
186 | 30.3k | } else if (avctx->pix_fmt == AV_PIX_FMT_GRAYF32 && c == 'h') { |
187 | 6.81k | const float *g = (const float *)p->data[0]; |
188 | | |
189 | 616k | for (int i = 0; i < avctx->height; i++) { |
190 | 3.53M | for (int j = 0; j < avctx->width; j++) { |
191 | 2.92M | AV_WN16(bytestream, float2half(av_float2int(g[j]), &s->f2h_tables)); |
192 | 2.92M | bytestream += 2; |
193 | 2.92M | } |
194 | | |
195 | 610k | g += p->linesize[0] / 4; |
196 | 610k | } |
197 | 23.5k | } else { |
198 | 23.5k | const uint8_t *ptr = p->data[0]; |
199 | 23.5k | linesize = p->linesize[0]; |
200 | 5.71M | for (i = 0; i < h; i++) { |
201 | 5.69M | memcpy(bytestream, ptr, n); |
202 | 5.69M | bytestream += n; |
203 | 5.69M | ptr += linesize; |
204 | 5.69M | } |
205 | 23.5k | } |
206 | | |
207 | 39.0k | if (avctx->pix_fmt == AV_PIX_FMT_YUV420P || avctx->pix_fmt == AV_PIX_FMT_YUV420P16BE) { |
208 | 5.40k | const uint8_t *ptr1 = p->data[1], *ptr2 = p->data[2]; |
209 | 5.40k | h >>= 1; |
210 | 5.40k | n >>= 1; |
211 | 496k | for (i = 0; i < h; i++) { |
212 | 490k | memcpy(bytestream, ptr1, n); |
213 | 490k | bytestream += n; |
214 | 490k | memcpy(bytestream, ptr2, n); |
215 | 490k | bytestream += n; |
216 | 490k | ptr1 += p->linesize[1]; |
217 | 490k | ptr2 += p->linesize[2]; |
218 | 490k | } |
219 | 5.40k | } |
220 | 39.0k | av_shrink_packet(pkt, bytestream - bytestream_start); |
221 | 39.0k | *got_packet = 1; |
222 | | |
223 | 39.0k | return 0; |
224 | 39.0k | } |
225 | | |
226 | | #if CONFIG_PGM_ENCODER |
227 | | const FFCodec ff_pgm_encoder = { |
228 | | .p.name = "pgm", |
229 | | CODEC_LONG_NAME("PGM (Portable GrayMap) image"), |
230 | | .p.type = AVMEDIA_TYPE_VIDEO, |
231 | | .p.id = AV_CODEC_ID_PGM, |
232 | | .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, |
233 | | FF_CODEC_ENCODE_CB(pnm_encode_frame), |
234 | | .p.pix_fmts = (const enum AVPixelFormat[]){ |
235 | | AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY16BE, AV_PIX_FMT_NONE |
236 | | }, |
237 | | }; |
238 | | #endif |
239 | | |
240 | | #if CONFIG_PGMYUV_ENCODER |
241 | | const FFCodec ff_pgmyuv_encoder = { |
242 | | .p.name = "pgmyuv", |
243 | | CODEC_LONG_NAME("PGMYUV (Portable GrayMap YUV) image"), |
244 | | .p.type = AVMEDIA_TYPE_VIDEO, |
245 | | .p.id = AV_CODEC_ID_PGMYUV, |
246 | | .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, |
247 | | FF_CODEC_ENCODE_CB(pnm_encode_frame), |
248 | | .p.pix_fmts = (const enum AVPixelFormat[]){ |
249 | | AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV420P16BE, AV_PIX_FMT_NONE |
250 | | }, |
251 | | }; |
252 | | #endif |
253 | | |
254 | | #if CONFIG_PPM_ENCODER |
255 | | const FFCodec ff_ppm_encoder = { |
256 | | .p.name = "ppm", |
257 | | CODEC_LONG_NAME("PPM (Portable PixelMap) image"), |
258 | | .p.type = AVMEDIA_TYPE_VIDEO, |
259 | | .p.id = AV_CODEC_ID_PPM, |
260 | | .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, |
261 | | FF_CODEC_ENCODE_CB(pnm_encode_frame), |
262 | | .p.pix_fmts = (const enum AVPixelFormat[]){ |
263 | | AV_PIX_FMT_RGB24, AV_PIX_FMT_RGB48BE, AV_PIX_FMT_NONE |
264 | | }, |
265 | | }; |
266 | | #endif |
267 | | |
268 | | #if CONFIG_PBM_ENCODER |
269 | | const FFCodec ff_pbm_encoder = { |
270 | | .p.name = "pbm", |
271 | | CODEC_LONG_NAME("PBM (Portable BitMap) image"), |
272 | | .p.type = AVMEDIA_TYPE_VIDEO, |
273 | | .p.id = AV_CODEC_ID_PBM, |
274 | | .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, |
275 | | FF_CODEC_ENCODE_CB(pnm_encode_frame), |
276 | | .p.pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_MONOWHITE, |
277 | | AV_PIX_FMT_NONE }, |
278 | | }; |
279 | | #endif |
280 | | |
281 | | #if CONFIG_PFM_ENCODER |
282 | | const FFCodec ff_pfm_encoder = { |
283 | | .p.name = "pfm", |
284 | | CODEC_LONG_NAME("PFM (Portable FloatMap) image"), |
285 | | .p.type = AVMEDIA_TYPE_VIDEO, |
286 | | .p.id = AV_CODEC_ID_PFM, |
287 | | .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, |
288 | | FF_CODEC_ENCODE_CB(pnm_encode_frame), |
289 | | .p.pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_GBRPF32LE, |
290 | | AV_PIX_FMT_GRAYF32LE, |
291 | | AV_PIX_FMT_GBRPF32BE, |
292 | | AV_PIX_FMT_GRAYF32BE, |
293 | | AV_PIX_FMT_NONE }, |
294 | | }; |
295 | | #endif |
296 | | |
297 | | #if CONFIG_PHM_ENCODER |
298 | | static av_cold int phm_enc_init(AVCodecContext *avctx) |
299 | 299 | { |
300 | 299 | PHMEncContext *s = avctx->priv_data; |
301 | | |
302 | 299 | ff_init_float2half_tables(&s->f2h_tables); |
303 | | |
304 | 299 | return 0; |
305 | 299 | } |
306 | | |
307 | | const FFCodec ff_phm_encoder = { |
308 | | .p.name = "phm", |
309 | | CODEC_LONG_NAME("PHM (Portable HalfFloatMap) image"), |
310 | | .p.type = AVMEDIA_TYPE_VIDEO, |
311 | | .p.id = AV_CODEC_ID_PHM, |
312 | | .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, |
313 | | .priv_data_size = sizeof(PHMEncContext), |
314 | | .init = phm_enc_init, |
315 | | FF_CODEC_ENCODE_CB(pnm_encode_frame), |
316 | | .p.pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_GBRPF32, |
317 | | AV_PIX_FMT_GRAYF32, |
318 | | AV_PIX_FMT_NONE }, |
319 | | }; |
320 | | #endif |