#include "avcodec.h"
#include "bytestream.h"
#include "internal.h"
+#include "float2half.h"
enum ExrCompr {
EXR_RAW,
const AVClass *class;
int compression;
+ int pixel_type;
int planes;
int nb_scanlines;
int scanline_height;
PutByteContext pb;
EXRScanlineData *scanline;
+
+ uint16_t basetable[512];
+ uint8_t shifttable[512];
} EXRContext;
static int encode_init(AVCodecContext *avctx)
{
EXRContext *s = avctx->priv_data;
+ float2half_tables(s->basetable, s->shifttable);
+
switch (avctx->pix_fmt) {
case AV_PIX_FMT_GBRPF32:
s->planes = 3;
run++;
if (run >= 3) {
- av_assert1(o + 2 <= out_size);
+ if (o + 2 >= out_size)
+ return -1;
out[o++] = run - 1;
out[o++] = in[i];
i += run;
while (i + copy < in_size && copy < 127 && in[i + copy] != in[i + copy - 1])
copy++;
- av_assert1(o + 1 + copy <= out_size);
+ if (o + 1 + copy >= out_size)
+ return -1;
out[o++] = -copy;
for (int x = 0; x < copy; x++)
static int encode_scanline_rle(EXRContext *s, const AVFrame *frame)
{
+ const int64_t element_size = s->pixel_type == EXR_HALF ? 2LL : 4LL;
+
for (int y = 0; y < frame->height; y++) {
EXRScanlineData *scanline = &s->scanline[y];
- int64_t tmp_size = 4LL * s->planes * frame->width;
+ int64_t tmp_size = element_size * s->planes * frame->width;
int64_t max_compressed_size = tmp_size * 3 / 2;
av_fast_padded_malloc(&scanline->uncompressed_data, &scanline->uncompressed_size, tmp_size);
if (!scanline->compressed_data)
return AVERROR(ENOMEM);
- for (int p = 0; p < s->planes; p++) {
- int ch = s->ch_order[p];
+ switch (s->pixel_type) {
+ case EXR_FLOAT:
+ for (int p = 0; p < s->planes; p++) {
+ int ch = s->ch_order[p];
- memcpy(scanline->uncompressed_data + frame->width * 4 * p,
- frame->data[ch] + y * frame->linesize[ch], frame->width * 4);
+ memcpy(scanline->uncompressed_data + frame->width * 4 * p,
+ frame->data[ch] + y * frame->linesize[ch], frame->width * 4);
+ }
+ break;
+ case EXR_HALF:
+ for (int p = 0; p < s->planes; p++) {
+ int ch = s->ch_order[p];
+ uint16_t *dst = (uint16_t *)(scanline->uncompressed_data + frame->width * 2 * p);
+ uint32_t *src = (uint32_t *)(frame->data[ch] + y * frame->linesize[ch]);
+
+ for (int x = 0; x < frame->width; x++)
+ dst[x] = float2half(src[x], s->basetable, s->shifttable);
+ }
+ break;
}
reorder_pixels(scanline->tmp, scanline->uncompressed_data, tmp_size);
max_compressed_size,
scanline->tmp, tmp_size);
- if (scanline->actual_size >= tmp_size) {
+ if (scanline->actual_size <= 0 || scanline->actual_size >= tmp_size) {
FFSWAP(uint8_t *, scanline->uncompressed_data, scanline->compressed_data);
FFSWAP(int, scanline->uncompressed_size, scanline->compressed_size);
scanline->actual_size = tmp_size;
static int encode_scanline_zip(EXRContext *s, const AVFrame *frame)
{
+ const int64_t element_size = s->pixel_type == EXR_HALF ? 2LL : 4LL;
+
for (int y = 0; y < s->nb_scanlines; y++) {
EXRScanlineData *scanline = &s->scanline[y];
const int scanline_height = FFMIN(s->scanline_height, frame->height - y * s->scanline_height);
- int64_t tmp_size = 4LL * s->planes * frame->width * scanline_height;
+ int64_t tmp_size = element_size * s->planes * frame->width * scanline_height;
int64_t max_compressed_size = tmp_size * 3 / 2;
+ unsigned long actual_size, source_size;
av_fast_padded_malloc(&scanline->uncompressed_data, &scanline->uncompressed_size, tmp_size);
if (!scanline->uncompressed_data)
if (!scanline->compressed_data)
return AVERROR(ENOMEM);
- for (int l = 0; l < scanline_height; l++) {
- const int scanline_size = frame->width * 4 * s->planes;
+ switch (s->pixel_type) {
+ case EXR_FLOAT:
+ for (int l = 0; l < scanline_height; l++) {
+ const int scanline_size = frame->width * 4 * s->planes;
- for (int p = 0; p < s->planes; p++) {
- int ch = s->ch_order[p];
+ for (int p = 0; p < s->planes; p++) {
+ int ch = s->ch_order[p];
- memcpy(scanline->uncompressed_data + scanline_size * l + p * frame->width * 4,
- frame->data[ch] + (y * s->scanline_height + l) * frame->linesize[ch],
- frame->width * 4);
+ memcpy(scanline->uncompressed_data + scanline_size * l + p * frame->width * 4,
+ frame->data[ch] + (y * s->scanline_height + l) * frame->linesize[ch],
+ frame->width * 4);
+ }
+ }
+ break;
+ case EXR_HALF:
+ for (int l = 0; l < scanline_height; l++) {
+ const int scanline_size = frame->width * 2 * s->planes;
+
+ for (int p = 0; p < s->planes; p++) {
+ int ch = s->ch_order[p];
+ uint16_t *dst = (uint16_t *)(scanline->uncompressed_data + scanline_size * l + p * frame->width * 2);
+ uint32_t *src = (uint32_t *)(frame->data[ch] + (y * s->scanline_height + l) * frame->linesize[ch]);
+
+ for (int x = 0; x < frame->width; x++)
+ dst[x] = float2half(src[x], s->basetable, s->shifttable);
+ }
}
+ break;
}
reorder_pixels(scanline->tmp, scanline->uncompressed_data, tmp_size);
predictor(scanline->tmp, tmp_size);
- scanline->actual_size = max_compressed_size;
- compress(scanline->compressed_data, &scanline->actual_size,
- scanline->tmp, tmp_size);
+ source_size = tmp_size;
+ actual_size = max_compressed_size;
+ compress(scanline->compressed_data, &actual_size,
+ scanline->tmp, source_size);
+ scanline->actual_size = actual_size;
if (scanline->actual_size >= tmp_size) {
FFSWAP(uint8_t *, scanline->uncompressed_data, scanline->compressed_data);
FFSWAP(int, scanline->uncompressed_size, scanline->compressed_size);
for (int p = 0; p < s->planes; p++) {
bytestream2_put_byte(pb, s->ch_names[p]);
bytestream2_put_byte(pb, 0);
- bytestream2_put_le32(pb, EXR_FLOAT);
+ bytestream2_put_le32(pb, s->pixel_type);
bytestream2_put_le32(pb, 0);
bytestream2_put_le32(pb, 1);
bytestream2_put_le32(pb, 1);
case EXR_RAW:
offset = bytestream2_tell_p(pb) + avctx->height * 8LL;
- for (int y = 0; y < avctx->height; y++) {
- bytestream2_put_le64(pb, offset);
- offset += avctx->width * s->planes * 4 + 8;
- }
+ if (s->pixel_type == EXR_FLOAT) {
- for (int y = 0; y < avctx->height; y++) {
- bytestream2_put_le32(pb, y);
- bytestream2_put_le32(pb, s->planes * avctx->width * 4);
- for (int p = 0; p < s->planes; p++) {
- int ch = s->ch_order[p];
- bytestream2_put_buffer(pb, frame->data[ch] + y * frame->linesize[ch],
- avctx->width * 4);
+ for (int y = 0; y < avctx->height; y++) {
+ bytestream2_put_le64(pb, offset);
+ offset += avctx->width * s->planes * 4 + 8;
+ }
+
+ for (int y = 0; y < avctx->height; y++) {
+ bytestream2_put_le32(pb, y);
+ bytestream2_put_le32(pb, s->planes * avctx->width * 4);
+ for (int p = 0; p < s->planes; p++) {
+ int ch = s->ch_order[p];
+ bytestream2_put_buffer(pb, frame->data[ch] + y * frame->linesize[ch],
+ avctx->width * 4);
+ }
+ }
+ } else {
+ for (int y = 0; y < avctx->height; y++) {
+ bytestream2_put_le64(pb, offset);
+ offset += avctx->width * s->planes * 2 + 8;
+ }
+
+ for (int y = 0; y < avctx->height; y++) {
+ bytestream2_put_le32(pb, y);
+ bytestream2_put_le32(pb, s->planes * avctx->width * 2);
+ for (int p = 0; p < s->planes; p++) {
+ int ch = s->ch_order[p];
+ uint32_t *src = (uint32_t *)(frame->data[ch] + y * frame->linesize[ch]);
+
+ for (int x = 0; x < frame->width; x++)
+ bytestream2_put_le16(pb, float2half(src[x], s->basetable, s->shifttable));
+ }
}
}
break;
{ "rle" , "RLE", 0, AV_OPT_TYPE_CONST, {.i64=EXR_RLE}, 0, 0, VE, "compr" },
{ "zip1", "ZIP1", 0, AV_OPT_TYPE_CONST, {.i64=EXR_ZIP1}, 0, 0, VE, "compr" },
{ "zip16", "ZIP16", 0, AV_OPT_TYPE_CONST, {.i64=EXR_ZIP16}, 0, 0, VE, "compr" },
+ { "format", "set pixel type", OFFSET(pixel_type), AV_OPT_TYPE_INT, {.i64=EXR_FLOAT}, EXR_HALF, EXR_UNKNOWN-1, VE, "pixel" },
+ { "half" , NULL, 0, AV_OPT_TYPE_CONST, {.i64=EXR_HALF}, 0, 0, VE, "pixel" },
+ { "float", NULL, 0, AV_OPT_TYPE_CONST, {.i64=EXR_FLOAT}, 0, 0, VE, "pixel" },
{ "gamma", "set gamma", OFFSET(gamma), AV_OPT_TYPE_FLOAT, {.dbl=1.f}, 0.001, FLT_MAX, VE },
{ NULL},
};
.version = LIBAVUTIL_VERSION_INT,
};
-AVCodec ff_exr_encoder = {
+const AVCodec ff_exr_encoder = {
.name = "exr",
.long_name = NULL_IF_CONFIG_SMALL("OpenEXR image"),
.priv_data_size = sizeof(EXRContext),