Line | Branch | Exec | Source |
---|---|---|---|
1 | /* | ||
2 | * Copyright (c) 2021 Paul B Mahol | ||
3 | * | ||
4 | * This file is part of FFmpeg. | ||
5 | * | ||
6 | * FFmpeg is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU Lesser General Public | ||
8 | * License as published by the Free Software Foundation; either | ||
9 | * version 2.1 of the License, or (at your option) any later version. | ||
10 | * | ||
11 | * FFmpeg is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
14 | * Lesser General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU Lesser General Public | ||
17 | * License along with FFmpeg; if not, write to the Free Software | ||
18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file | ||
23 | * OpenEXR encoder | ||
24 | */ | ||
25 | |||
26 | #include <float.h> | ||
27 | #include <zlib.h> | ||
28 | |||
29 | #include "libavutil/avassert.h" | ||
30 | #include "libavutil/mem.h" | ||
31 | #include "libavutil/opt.h" | ||
32 | #include "libavutil/imgutils.h" | ||
33 | #include "libavutil/float2half.h" | ||
34 | #include "avcodec.h" | ||
35 | #include "bytestream.h" | ||
36 | #include "codec_internal.h" | ||
37 | #include "encode.h" | ||
38 | |||
39 | enum ExrCompr { | ||
40 | EXR_RAW, | ||
41 | EXR_RLE, | ||
42 | EXR_ZIP1, | ||
43 | EXR_ZIP16, | ||
44 | EXR_NBCOMPR, | ||
45 | }; | ||
46 | |||
47 | enum ExrPixelType { | ||
48 | EXR_UINT, | ||
49 | EXR_HALF, | ||
50 | EXR_FLOAT, | ||
51 | EXR_UNKNOWN, | ||
52 | }; | ||
53 | |||
54 | static const char abgr_chlist[4] = { 'A', 'B', 'G', 'R' }; | ||
55 | static const char bgr_chlist[4] = { 'B', 'G', 'R', 'A' }; | ||
56 | static const char y_chlist[4] = { 'Y' }; | ||
57 | static const uint8_t gbra_order[4] = { 3, 1, 0, 2 }; | ||
58 | static const uint8_t gbr_order[4] = { 1, 0, 2, 0 }; | ||
59 | static const uint8_t y_order[4] = { 0 }; | ||
60 | |||
61 | typedef struct EXRScanlineData { | ||
62 | uint8_t *compressed_data; | ||
63 | unsigned int compressed_size; | ||
64 | |||
65 | uint8_t *uncompressed_data; | ||
66 | unsigned int uncompressed_size; | ||
67 | |||
68 | uint8_t *tmp; | ||
69 | unsigned int tmp_size; | ||
70 | |||
71 | int64_t actual_size; | ||
72 | } EXRScanlineData; | ||
73 | |||
74 | typedef struct EXRContext { | ||
75 | const AVClass *class; | ||
76 | |||
77 | int compression; | ||
78 | int pixel_type; | ||
79 | int planes; | ||
80 | int nb_scanlines; | ||
81 | int scanline_height; | ||
82 | float gamma; | ||
83 | const char *ch_names; | ||
84 | const uint8_t *ch_order; | ||
85 | PutByteContext pb; | ||
86 | |||
87 | EXRScanlineData *scanline; | ||
88 | |||
89 | Float2HalfTables f2h_tables; | ||
90 | } EXRContext; | ||
91 | |||
92 | 12 | static av_cold int encode_init(AVCodecContext *avctx) | |
93 | { | ||
94 | 12 | EXRContext *s = avctx->priv_data; | |
95 | |||
96 | 12 | ff_init_float2half_tables(&s->f2h_tables); | |
97 | |||
98 |
3/4✓ Branch 0 taken 4 times.
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
|
12 | switch (avctx->pix_fmt) { |
99 | 4 | case AV_PIX_FMT_GBRPF32: | |
100 | 4 | s->planes = 3; | |
101 | 4 | s->ch_names = bgr_chlist; | |
102 | 4 | s->ch_order = gbr_order; | |
103 | 4 | break; | |
104 | 4 | case AV_PIX_FMT_GBRAPF32: | |
105 | 4 | s->planes = 4; | |
106 | 4 | s->ch_names = abgr_chlist; | |
107 | 4 | s->ch_order = gbra_order; | |
108 | 4 | break; | |
109 | 4 | case AV_PIX_FMT_GRAYF32: | |
110 | 4 | s->planes = 1; | |
111 | 4 | s->ch_names = y_chlist; | |
112 | 4 | s->ch_order = y_order; | |
113 | 4 | break; | |
114 | ✗ | default: | |
115 | ✗ | av_assert0(0); | |
116 | } | ||
117 | |||
118 |
2/3✓ Branch 0 taken 9 times.
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
|
12 | switch (s->compression) { |
119 | 9 | case EXR_RAW: | |
120 | case EXR_RLE: | ||
121 | case EXR_ZIP1: | ||
122 | 9 | s->scanline_height = 1; | |
123 | 9 | s->nb_scanlines = avctx->height; | |
124 | 9 | break; | |
125 | 3 | case EXR_ZIP16: | |
126 | 3 | s->scanline_height = 16; | |
127 | 3 | s->nb_scanlines = (avctx->height + s->scanline_height - 1) / s->scanline_height; | |
128 | 3 | break; | |
129 | ✗ | default: | |
130 | ✗ | av_assert0(0); | |
131 | } | ||
132 | |||
133 | 12 | s->scanline = av_calloc(s->nb_scanlines, sizeof(*s->scanline)); | |
134 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
|
12 | if (!s->scanline) |
135 | ✗ | return AVERROR(ENOMEM); | |
136 | |||
137 | 12 | return 0; | |
138 | } | ||
139 | |||
140 | 12 | static av_cold int encode_close(AVCodecContext *avctx) | |
141 | { | ||
142 | 12 | EXRContext *s = avctx->priv_data; | |
143 | |||
144 |
3/4✓ Branch 0 taken 2646 times.
✓ Branch 1 taken 12 times.
✓ Branch 2 taken 2646 times.
✗ Branch 3 not taken.
|
2658 | for (int y = 0; y < s->nb_scanlines && s->scanline; y++) { |
145 | 2646 | EXRScanlineData *scanline = &s->scanline[y]; | |
146 | |||
147 | 2646 | av_freep(&scanline->tmp); | |
148 | 2646 | av_freep(&scanline->compressed_data); | |
149 | 2646 | av_freep(&scanline->uncompressed_data); | |
150 | } | ||
151 | |||
152 | 12 | av_freep(&s->scanline); | |
153 | |||
154 | 12 | return 0; | |
155 | } | ||
156 | |||
157 | 23166 | static void reorder_pixels(uint8_t *dst, const uint8_t *src, ptrdiff_t size) | |
158 | { | ||
159 | 23166 | const ptrdiff_t half_size = (size + 1) / 2; | |
160 | 23166 | uint8_t *t1 = dst; | |
161 | 23166 | uint8_t *t2 = dst + half_size; | |
162 | |||
163 |
2/2✓ Branch 0 taken 63258624 times.
✓ Branch 1 taken 23166 times.
|
63281790 | for (ptrdiff_t i = 0; i < half_size; i++) { |
164 | 63258624 | t1[i] = *(src++); | |
165 | 63258624 | t2[i] = *(src++); | |
166 | } | ||
167 | 23166 | } | |
168 | |||
169 | 23166 | static void predictor(uint8_t *src, ptrdiff_t size) | |
170 | { | ||
171 | 23166 | int p = src[0]; | |
172 | |||
173 |
2/2✓ Branch 0 taken 126494082 times.
✓ Branch 1 taken 23166 times.
|
126517248 | for (ptrdiff_t i = 1; i < size; i++) { |
174 | 126494082 | int d = src[i] - p + 384; | |
175 | |||
176 | 126494082 | p = src[i]; | |
177 | 126494082 | src[i] = d; | |
178 | } | ||
179 | 23166 | } | |
180 | |||
181 | 11232 | static int64_t rle_compress(uint8_t *out, int64_t out_size, | |
182 | const uint8_t *in, int64_t in_size) | ||
183 | { | ||
184 | 11232 | int64_t i = 0, o = 0, run = 1, copy = 0; | |
185 | |||
186 |
2/2✓ Branch 0 taken 1104099 times.
✓ Branch 1 taken 11160 times.
|
1115259 | while (i < in_size) { |
187 |
6/6✓ Branch 0 taken 4481360 times.
✓ Branch 1 taken 218090 times.
✓ Branch 2 taken 3614071 times.
✓ Branch 3 taken 867289 times.
✓ Branch 4 taken 3595351 times.
✓ Branch 5 taken 18720 times.
|
4699450 | while (i + run < in_size && in[i] == in[i + run] && run < 128) |
188 | 3595351 | run++; | |
189 | |||
190 |
2/2✓ Branch 0 taken 106157 times.
✓ Branch 1 taken 997942 times.
|
1104099 | if (run >= 3) { |
191 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 106157 times.
|
106157 | if (o + 2 >= out_size) |
192 | ✗ | return -1; | |
193 | 106157 | out[o++] = run - 1; | |
194 | 106157 | out[o++] = in[i]; | |
195 | 106157 | i += run; | |
196 | } else { | ||
197 |
2/2✓ Branch 0 taken 780024 times.
✓ Branch 1 taken 217918 times.
|
997942 | if (i + run < in_size) |
198 | 780024 | copy += run; | |
199 |
6/6✓ Branch 0 taken 38791597 times.
✓ Branch 1 taken 10988 times.
✓ Branch 2 taken 38647669 times.
✓ Branch 3 taken 143928 times.
✓ Branch 4 taken 37804643 times.
✓ Branch 5 taken 843026 times.
|
38802585 | while (i + copy < in_size && copy < 127 && in[i + copy] != in[i + copy - 1]) |
200 | 37804643 | copy++; | |
201 | |||
202 |
2/2✓ Branch 0 taken 72 times.
✓ Branch 1 taken 997870 times.
|
997942 | if (o + 1 + copy >= out_size) |
203 | 72 | return -1; | |
204 | 997870 | out[o++] = -copy; | |
205 | |||
206 |
2/2✓ Branch 0 taken 38789590 times.
✓ Branch 1 taken 997870 times.
|
39787460 | for (int x = 0; x < copy; x++) |
207 | 38789590 | out[o + x] = in[i + x]; | |
208 | |||
209 | 997870 | o += copy; | |
210 | 997870 | i += copy; | |
211 | 997870 | copy = 0; | |
212 | } | ||
213 | |||
214 | 1104027 | run = 1; | |
215 | } | ||
216 | |||
217 | 11160 | return o; | |
218 | } | ||
219 | |||
220 | 39 | static int encode_scanline_rle(EXRContext *s, const AVFrame *frame) | |
221 | { | ||
222 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 39 times.
|
39 | const int64_t element_size = s->pixel_type == EXR_HALF ? 2LL : 4LL; |
223 | |||
224 |
2/2✓ Branch 0 taken 11232 times.
✓ Branch 1 taken 39 times.
|
11271 | for (int y = 0; y < frame->height; y++) { |
225 | 11232 | EXRScanlineData *scanline = &s->scanline[y]; | |
226 | 11232 | int64_t tmp_size = element_size * s->planes * frame->width; | |
227 | 11232 | int64_t max_compressed_size = tmp_size * 3 / 2; | |
228 | |||
229 | 11232 | av_fast_padded_malloc(&scanline->uncompressed_data, &scanline->uncompressed_size, tmp_size); | |
230 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 11232 times.
|
11232 | if (!scanline->uncompressed_data) |
231 | ✗ | return AVERROR(ENOMEM); | |
232 | |||
233 | 11232 | av_fast_padded_malloc(&scanline->tmp, &scanline->tmp_size, tmp_size); | |
234 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 11232 times.
|
11232 | if (!scanline->tmp) |
235 | ✗ | return AVERROR(ENOMEM); | |
236 | |||
237 | 11232 | av_fast_padded_malloc(&scanline->compressed_data, &scanline->compressed_size, max_compressed_size); | |
238 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 11232 times.
|
11232 | if (!scanline->compressed_data) |
239 | ✗ | return AVERROR(ENOMEM); | |
240 | |||
241 |
1/3✓ Branch 0 taken 11232 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
|
11232 | switch (s->pixel_type) { |
242 | 11232 | case EXR_FLOAT: | |
243 |
2/2✓ Branch 0 taken 29952 times.
✓ Branch 1 taken 11232 times.
|
41184 | for (int p = 0; p < s->planes; p++) { |
244 | 29952 | int ch = s->ch_order[p]; | |
245 | |||
246 | 29952 | memcpy(scanline->uncompressed_data + frame->width * 4 * p, | |
247 | 29952 | frame->data[ch] + y * frame->linesize[ch], frame->width * 4); | |
248 | } | ||
249 | 11232 | break; | |
250 | ✗ | case EXR_HALF: | |
251 | ✗ | for (int p = 0; p < s->planes; p++) { | |
252 | ✗ | int ch = s->ch_order[p]; | |
253 | ✗ | uint16_t *dst = (uint16_t *)(scanline->uncompressed_data + frame->width * 2 * p); | |
254 | ✗ | const uint32_t *src = (const uint32_t *)(frame->data[ch] + y * frame->linesize[ch]); | |
255 | |||
256 | ✗ | for (int x = 0; x < frame->width; x++) | |
257 | ✗ | dst[x] = float2half(src[x], &s->f2h_tables); | |
258 | } | ||
259 | ✗ | break; | |
260 | } | ||
261 | |||
262 | 11232 | reorder_pixels(scanline->tmp, scanline->uncompressed_data, tmp_size); | |
263 | 11232 | predictor(scanline->tmp, tmp_size); | |
264 | 22464 | scanline->actual_size = rle_compress(scanline->compressed_data, | |
265 | max_compressed_size, | ||
266 | 11232 | scanline->tmp, tmp_size); | |
267 | |||
268 |
4/4✓ Branch 0 taken 11160 times.
✓ Branch 1 taken 72 times.
✓ Branch 2 taken 7005 times.
✓ Branch 3 taken 4155 times.
|
11232 | if (scanline->actual_size <= 0 || scanline->actual_size >= tmp_size) { |
269 | 7077 | FFSWAP(uint8_t *, scanline->uncompressed_data, scanline->compressed_data); | |
270 | 7077 | FFSWAP(int, scanline->uncompressed_size, scanline->compressed_size); | |
271 | 7077 | scanline->actual_size = tmp_size; | |
272 | } | ||
273 | } | ||
274 | |||
275 | 39 | return 0; | |
276 | } | ||
277 | |||
278 | 78 | static int encode_scanline_zip(EXRContext *s, const AVFrame *frame) | |
279 | { | ||
280 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 78 times.
|
78 | const int64_t element_size = s->pixel_type == EXR_HALF ? 2LL : 4LL; |
281 | |||
282 |
2/2✓ Branch 0 taken 11934 times.
✓ Branch 1 taken 78 times.
|
12012 | for (int y = 0; y < s->nb_scanlines; y++) { |
283 | 11934 | EXRScanlineData *scanline = &s->scanline[y]; | |
284 | 11934 | const int scanline_height = FFMIN(s->scanline_height, frame->height - y * s->scanline_height); | |
285 | 11934 | int64_t tmp_size = element_size * s->planes * frame->width * scanline_height; | |
286 | 11934 | int64_t max_compressed_size = tmp_size * 3 / 2; | |
287 | unsigned long actual_size, source_size; | ||
288 | |||
289 | 11934 | av_fast_padded_malloc(&scanline->uncompressed_data, &scanline->uncompressed_size, tmp_size); | |
290 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 11934 times.
|
11934 | if (!scanline->uncompressed_data) |
291 | ✗ | return AVERROR(ENOMEM); | |
292 | |||
293 | 11934 | av_fast_padded_malloc(&scanline->tmp, &scanline->tmp_size, tmp_size); | |
294 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 11934 times.
|
11934 | if (!scanline->tmp) |
295 | ✗ | return AVERROR(ENOMEM); | |
296 | |||
297 | 11934 | av_fast_padded_malloc(&scanline->compressed_data, &scanline->compressed_size, max_compressed_size); | |
298 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 11934 times.
|
11934 | if (!scanline->compressed_data) |
299 | ✗ | return AVERROR(ENOMEM); | |
300 | |||
301 |
1/3✓ Branch 0 taken 11934 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
|
11934 | switch (s->pixel_type) { |
302 | 11934 | case EXR_FLOAT: | |
303 |
2/2✓ Branch 0 taken 22464 times.
✓ Branch 1 taken 11934 times.
|
34398 | for (int l = 0; l < scanline_height; l++) { |
304 | 22464 | const int scanline_size = frame->width * 4 * s->planes; | |
305 | |||
306 |
2/2✓ Branch 0 taken 59904 times.
✓ Branch 1 taken 22464 times.
|
82368 | for (int p = 0; p < s->planes; p++) { |
307 | 59904 | int ch = s->ch_order[p]; | |
308 | |||
309 | 59904 | memcpy(scanline->uncompressed_data + scanline_size * l + p * frame->width * 4, | |
310 | 59904 | frame->data[ch] + (y * s->scanline_height + l) * frame->linesize[ch], | |
311 | 59904 | frame->width * 4); | |
312 | } | ||
313 | } | ||
314 | 11934 | break; | |
315 | ✗ | case EXR_HALF: | |
316 | ✗ | for (int l = 0; l < scanline_height; l++) { | |
317 | ✗ | const int scanline_size = frame->width * 2 * s->planes; | |
318 | |||
319 | ✗ | for (int p = 0; p < s->planes; p++) { | |
320 | ✗ | int ch = s->ch_order[p]; | |
321 | ✗ | uint16_t *dst = (uint16_t *)(scanline->uncompressed_data + scanline_size * l + p * frame->width * 2); | |
322 | ✗ | const uint32_t *src = (const uint32_t *)(frame->data[ch] + (y * s->scanline_height + l) * frame->linesize[ch]); | |
323 | |||
324 | ✗ | for (int x = 0; x < frame->width; x++) | |
325 | ✗ | dst[x] = float2half(src[x], &s->f2h_tables); | |
326 | } | ||
327 | } | ||
328 | ✗ | break; | |
329 | } | ||
330 | |||
331 | 11934 | reorder_pixels(scanline->tmp, scanline->uncompressed_data, tmp_size); | |
332 | 11934 | predictor(scanline->tmp, tmp_size); | |
333 | 11934 | source_size = tmp_size; | |
334 | 11934 | actual_size = max_compressed_size; | |
335 | 11934 | compress(scanline->compressed_data, &actual_size, | |
336 | 11934 | scanline->tmp, source_size); | |
337 | |||
338 | 11934 | scanline->actual_size = actual_size; | |
339 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 11934 times.
|
11934 | if (scanline->actual_size >= tmp_size) { |
340 | ✗ | FFSWAP(uint8_t *, scanline->uncompressed_data, scanline->compressed_data); | |
341 | ✗ | FFSWAP(int, scanline->uncompressed_size, scanline->compressed_size); | |
342 | ✗ | scanline->actual_size = tmp_size; | |
343 | } | ||
344 | } | ||
345 | |||
346 | 78 | return 0; | |
347 | } | ||
348 | |||
349 | 156 | static int encode_frame(AVCodecContext *avctx, AVPacket *pkt, | |
350 | const AVFrame *frame, int *got_packet) | ||
351 | { | ||
352 | 156 | EXRContext *s = avctx->priv_data; | |
353 | 156 | PutByteContext *pb = &s->pb; | |
354 | int64_t offset; | ||
355 | int ret; | ||
356 | 312 | int64_t out_size = 2048LL + avctx->height * 16LL + | |
357 | 156 | av_image_get_buffer_size(avctx->pix_fmt, | |
358 | avctx->width, | ||
359 | 156 | avctx->height, 64) * 3LL / 2; | |
360 | |||
361 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 156 times.
|
156 | if ((ret = ff_get_encode_buffer(avctx, pkt, out_size, 0)) < 0) |
362 | ✗ | return ret; | |
363 | |||
364 | 156 | bytestream2_init_writer(pb, pkt->data, pkt->size); | |
365 | |||
366 | 156 | bytestream2_put_le32(pb, 20000630); | |
367 | 156 | bytestream2_put_byte(pb, 2); | |
368 | 156 | bytestream2_put_le24(pb, 0); | |
369 | 156 | bytestream2_put_buffer(pb, "channels\0chlist\0", 16); | |
370 | 156 | bytestream2_put_le32(pb, s->planes * 18 + 1); | |
371 | |||
372 |
2/2✓ Branch 0 taken 416 times.
✓ Branch 1 taken 156 times.
|
572 | for (int p = 0; p < s->planes; p++) { |
373 | 416 | bytestream2_put_byte(pb, s->ch_names[p]); | |
374 | 416 | bytestream2_put_byte(pb, 0); | |
375 | 416 | bytestream2_put_le32(pb, s->pixel_type); | |
376 | 416 | bytestream2_put_le32(pb, 0); | |
377 | 416 | bytestream2_put_le32(pb, 1); | |
378 | 416 | bytestream2_put_le32(pb, 1); | |
379 | } | ||
380 | 156 | bytestream2_put_byte(pb, 0); | |
381 | |||
382 | 156 | bytestream2_put_buffer(pb, "compression\0compression\0", 24); | |
383 | 156 | bytestream2_put_le32(pb, 1); | |
384 | 156 | bytestream2_put_byte(pb, s->compression); | |
385 | |||
386 | 156 | bytestream2_put_buffer(pb, "dataWindow\0box2i\0", 17); | |
387 | 156 | bytestream2_put_le32(pb, 16); | |
388 | 156 | bytestream2_put_le32(pb, 0); | |
389 | 156 | bytestream2_put_le32(pb, 0); | |
390 | 156 | bytestream2_put_le32(pb, avctx->width - 1); | |
391 | 156 | bytestream2_put_le32(pb, avctx->height - 1); | |
392 | |||
393 | 156 | bytestream2_put_buffer(pb, "displayWindow\0box2i\0", 20); | |
394 | 156 | bytestream2_put_le32(pb, 16); | |
395 | 156 | bytestream2_put_le32(pb, 0); | |
396 | 156 | bytestream2_put_le32(pb, 0); | |
397 | 156 | bytestream2_put_le32(pb, avctx->width - 1); | |
398 | 156 | bytestream2_put_le32(pb, avctx->height - 1); | |
399 | |||
400 | 156 | bytestream2_put_buffer(pb, "lineOrder\0lineOrder\0", 20); | |
401 | 156 | bytestream2_put_le32(pb, 1); | |
402 | 156 | bytestream2_put_byte(pb, 0); | |
403 | |||
404 | 156 | bytestream2_put_buffer(pb, "screenWindowCenter\0v2f\0", 23); | |
405 | 156 | bytestream2_put_le32(pb, 8); | |
406 | 156 | bytestream2_put_le64(pb, 0); | |
407 | |||
408 | 156 | bytestream2_put_buffer(pb, "screenWindowWidth\0float\0", 24); | |
409 | 156 | bytestream2_put_le32(pb, 4); | |
410 | 156 | bytestream2_put_le32(pb, av_float2int(1.f)); | |
411 | |||
412 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 156 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
156 | if (avctx->sample_aspect_ratio.num && avctx->sample_aspect_ratio.den) { |
413 | ✗ | bytestream2_put_buffer(pb, "pixelAspectRatio\0float\0", 23); | |
414 | ✗ | bytestream2_put_le32(pb, 4); | |
415 | ✗ | bytestream2_put_le32(pb, av_float2int(av_q2d(avctx->sample_aspect_ratio))); | |
416 | } | ||
417 | |||
418 |
2/4✓ Branch 0 taken 156 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 156 times.
✗ Branch 3 not taken.
|
156 | if (avctx->framerate.num && avctx->framerate.den) { |
419 | 156 | bytestream2_put_buffer(pb, "framesPerSecond\0rational\0", 25); | |
420 | 156 | bytestream2_put_le32(pb, 8); | |
421 | 156 | bytestream2_put_le32(pb, avctx->framerate.num); | |
422 | 156 | bytestream2_put_le32(pb, avctx->framerate.den); | |
423 | } | ||
424 | |||
425 | 156 | bytestream2_put_buffer(pb, "gamma\0float\0", 12); | |
426 | 156 | bytestream2_put_le32(pb, 4); | |
427 | 156 | bytestream2_put_le32(pb, av_float2int(s->gamma)); | |
428 | |||
429 | 156 | bytestream2_put_buffer(pb, "writer\0string\0", 14); | |
430 | 156 | bytestream2_put_le32(pb, 4); | |
431 | 156 | bytestream2_put_buffer(pb, "lavc", 4); | |
432 | 156 | bytestream2_put_byte(pb, 0); | |
433 | |||
434 |
3/4✓ Branch 0 taken 39 times.
✓ Branch 1 taken 39 times.
✓ Branch 2 taken 78 times.
✗ Branch 3 not taken.
|
156 | switch (s->compression) { |
435 | 39 | case EXR_RAW: | |
436 | /* nothing to do */ | ||
437 | 39 | break; | |
438 | 39 | case EXR_RLE: | |
439 | 39 | encode_scanline_rle(s, frame); | |
440 | 39 | break; | |
441 | 78 | case EXR_ZIP16: | |
442 | case EXR_ZIP1: | ||
443 | 78 | encode_scanline_zip(s, frame); | |
444 | 78 | break; | |
445 | ✗ | default: | |
446 | ✗ | av_assert0(0); | |
447 | } | ||
448 | |||
449 |
2/3✓ Branch 0 taken 39 times.
✓ Branch 1 taken 117 times.
✗ Branch 2 not taken.
|
156 | switch (s->compression) { |
450 | 39 | case EXR_RAW: | |
451 | 39 | offset = bytestream2_tell_p(pb) + avctx->height * 8LL; | |
452 | |||
453 |
1/2✓ Branch 0 taken 39 times.
✗ Branch 1 not taken.
|
39 | if (s->pixel_type == EXR_FLOAT) { |
454 | |||
455 |
2/2✓ Branch 0 taken 11232 times.
✓ Branch 1 taken 39 times.
|
11271 | for (int y = 0; y < avctx->height; y++) { |
456 | 11232 | bytestream2_put_le64(pb, offset); | |
457 | 11232 | offset += avctx->width * s->planes * 4 + 8; | |
458 | } | ||
459 | |||
460 |
2/2✓ Branch 0 taken 11232 times.
✓ Branch 1 taken 39 times.
|
11271 | for (int y = 0; y < avctx->height; y++) { |
461 | 11232 | bytestream2_put_le32(pb, y); | |
462 | 11232 | bytestream2_put_le32(pb, s->planes * avctx->width * 4); | |
463 |
2/2✓ Branch 0 taken 29952 times.
✓ Branch 1 taken 11232 times.
|
41184 | for (int p = 0; p < s->planes; p++) { |
464 | 29952 | int ch = s->ch_order[p]; | |
465 | 29952 | bytestream2_put_buffer(pb, frame->data[ch] + y * frame->linesize[ch], | |
466 | 29952 | avctx->width * 4); | |
467 | } | ||
468 | } | ||
469 | } else { | ||
470 | ✗ | for (int y = 0; y < avctx->height; y++) { | |
471 | ✗ | bytestream2_put_le64(pb, offset); | |
472 | ✗ | offset += avctx->width * s->planes * 2 + 8; | |
473 | } | ||
474 | |||
475 | ✗ | for (int y = 0; y < avctx->height; y++) { | |
476 | ✗ | bytestream2_put_le32(pb, y); | |
477 | ✗ | bytestream2_put_le32(pb, s->planes * avctx->width * 2); | |
478 | ✗ | for (int p = 0; p < s->planes; p++) { | |
479 | ✗ | int ch = s->ch_order[p]; | |
480 | ✗ | const uint32_t *src = (const uint32_t *)(frame->data[ch] + y * frame->linesize[ch]); | |
481 | |||
482 | ✗ | for (int x = 0; x < frame->width; x++) | |
483 | ✗ | bytestream2_put_le16(pb, float2half(src[x], &s->f2h_tables)); | |
484 | } | ||
485 | } | ||
486 | } | ||
487 | 39 | break; | |
488 | 117 | case EXR_ZIP16: | |
489 | case EXR_ZIP1: | ||
490 | case EXR_RLE: | ||
491 | 117 | offset = bytestream2_tell_p(pb) + s->nb_scanlines * 8LL; | |
492 | |||
493 |
2/2✓ Branch 0 taken 23166 times.
✓ Branch 1 taken 117 times.
|
23283 | for (int y = 0; y < s->nb_scanlines; y++) { |
494 | 23166 | EXRScanlineData *scanline = &s->scanline[y]; | |
495 | |||
496 | 23166 | bytestream2_put_le64(pb, offset); | |
497 | 23166 | offset += scanline->actual_size + 8; | |
498 | } | ||
499 | |||
500 |
2/2✓ Branch 0 taken 23166 times.
✓ Branch 1 taken 117 times.
|
23283 | for (int y = 0; y < s->nb_scanlines; y++) { |
501 | 23166 | EXRScanlineData *scanline = &s->scanline[y]; | |
502 | |||
503 | 23166 | bytestream2_put_le32(pb, y * s->scanline_height); | |
504 | 23166 | bytestream2_put_le32(pb, scanline->actual_size); | |
505 | 23166 | bytestream2_put_buffer(pb, scanline->compressed_data, | |
506 | 23166 | scanline->actual_size); | |
507 | } | ||
508 | 117 | break; | |
509 | ✗ | default: | |
510 | ✗ | av_assert0(0); | |
511 | } | ||
512 | |||
513 | 156 | av_shrink_packet(pkt, bytestream2_tell_p(pb)); | |
514 | |||
515 | 156 | *got_packet = 1; | |
516 | |||
517 | 156 | return 0; | |
518 | } | ||
519 | |||
520 | #define OFFSET(x) offsetof(EXRContext, x) | ||
521 | #define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM | ||
522 | static const AVOption options[] = { | ||
523 | { "compression", "set compression type", OFFSET(compression), AV_OPT_TYPE_INT, {.i64=0}, 0, EXR_NBCOMPR-1, VE, .unit = "compr" }, | ||
524 | { "none", "none", 0, AV_OPT_TYPE_CONST, {.i64=EXR_RAW}, 0, 0, VE, .unit = "compr" }, | ||
525 | { "rle" , "RLE", 0, AV_OPT_TYPE_CONST, {.i64=EXR_RLE}, 0, 0, VE, .unit = "compr" }, | ||
526 | { "zip1", "ZIP1", 0, AV_OPT_TYPE_CONST, {.i64=EXR_ZIP1}, 0, 0, VE, .unit = "compr" }, | ||
527 | { "zip16", "ZIP16", 0, AV_OPT_TYPE_CONST, {.i64=EXR_ZIP16}, 0, 0, VE, .unit = "compr" }, | ||
528 | { "format", "set pixel type", OFFSET(pixel_type), AV_OPT_TYPE_INT, {.i64=EXR_FLOAT}, EXR_HALF, EXR_UNKNOWN-1, VE, .unit = "pixel" }, | ||
529 | { "half" , NULL, 0, AV_OPT_TYPE_CONST, {.i64=EXR_HALF}, 0, 0, VE, .unit = "pixel" }, | ||
530 | { "float", NULL, 0, AV_OPT_TYPE_CONST, {.i64=EXR_FLOAT}, 0, 0, VE, .unit = "pixel" }, | ||
531 | { "gamma", "set gamma", OFFSET(gamma), AV_OPT_TYPE_FLOAT, {.dbl=1.f}, 0.001, FLT_MAX, VE }, | ||
532 | { NULL}, | ||
533 | }; | ||
534 | |||
535 | static const AVClass exr_class = { | ||
536 | .class_name = "exr", | ||
537 | .item_name = av_default_item_name, | ||
538 | .option = options, | ||
539 | .version = LIBAVUTIL_VERSION_INT, | ||
540 | }; | ||
541 | |||
542 | const FFCodec ff_exr_encoder = { | ||
543 | .p.name = "exr", | ||
544 | CODEC_LONG_NAME("OpenEXR image"), | ||
545 | .priv_data_size = sizeof(EXRContext), | ||
546 | .p.priv_class = &exr_class, | ||
547 | .p.type = AVMEDIA_TYPE_VIDEO, | ||
548 | .p.id = AV_CODEC_ID_EXR, | ||
549 | .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_FRAME_THREADS | | ||
550 | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, | ||
551 | .init = encode_init, | ||
552 | FF_CODEC_ENCODE_CB(encode_frame), | ||
553 | .close = encode_close, | ||
554 | .p.pix_fmts = (const enum AVPixelFormat[]) { | ||
555 | AV_PIX_FMT_GRAYF32, | ||
556 | AV_PIX_FMT_GBRPF32, | ||
557 | AV_PIX_FMT_GBRAPF32, | ||
558 | AV_PIX_FMT_NONE }, | ||
559 | }; | ||
560 |