Add AVIF encoder

This commit is contained in:
Surma
2020-02-05 17:45:48 -08:00
committed by Ingvar Stepanyan
parent 409df481db
commit e1ab43b76f
9 changed files with 1353 additions and 0 deletions

18
codecs/avif_enc/README.md Normal file
View File

@ -0,0 +1,18 @@
# AVIF encoder
- Source: <https://github.com/AOMediaCodec/libavif>
- Version: v0.5.4
## Example
Run example.js
## API
### `RawImage decode(std::string buffer)`
Decodes the given avif buffer into raw RGBA. `RawImage` is a class with 3 fields: `buffer`, `width`, and `height`.
### `void free_result()`
Frees the result created by `decode()`.

View File

@ -0,0 +1,49 @@
#include "avif/avif.h"
#include <emscripten/bind.h>
#include <emscripten/val.h>
using namespace emscripten;
avifRWData output = AVIF_DATA_EMPTY;
val encode(std::string buffer, int width, int height) {
int depth = 8;
avifPixelFormat format = AVIF_PIXEL_FORMAT_YUV420;
avifImage *image = avifImageCreate(width, height, depth, format);
uint8_t *rgba = (uint8_t *)buffer.c_str();
avifImageAllocatePlanes(image, AVIF_PLANES_RGB);
avifImageAllocatePlanes(image, AVIF_PLANES_A);
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
int pixelOffset = y * width + x;
image->rgbPlanes[0][pixelOffset] = rgba[pixelOffset * 4 + 0];
image->rgbPlanes[1][pixelOffset] = rgba[pixelOffset * 4 + 1];
image->rgbPlanes[2][pixelOffset] = rgba[pixelOffset * 4 + 2];
image->alphaPlane[pixelOffset] = rgba[pixelOffset * 4 + 3];
}
}
avifEncoder *encoder = avifEncoderCreate();
encoder->maxThreads = 1;
encoder->minQuantizer = AVIF_QUANTIZER_LOSSLESS;
encoder->maxQuantizer = AVIF_QUANTIZER_LOSSLESS;
avifResult encodeResult = avifEncoderWrite(encoder, image, &output);
if (encodeResult != AVIF_RESULT_OK) {
return val::null();
}
// output contains a valid .avif file's contents
// ... output.data;
// ... output.size;
avifImageDestroy(image);
avifEncoderDestroy(encoder);
return val(typed_memory_view(output.size, output.data));
}
void free_result() { avifRWDataFree(&output); }
EMSCRIPTEN_BINDINGS(my_module) {
function("encode", &encode);
function("free_result", &free_result);
}

9
codecs/avif_enc/avif_enc.d.ts vendored Normal file
View File

@ -0,0 +1,9 @@
// import { EncodeOptions } from '../../src/codecs/webp/encoder-meta';
interface WebPModule extends EmscriptenWasm.Module {
encode(data: BufferSource, width: number, height: number): Uint8Array;
free_result(): void;
}
export default function(opts: EmscriptenWasm.ModuleOpts): WebPModule;

File diff suppressed because one or more lines are too long

Binary file not shown.

84
codecs/avif_enc/build.sh Executable file
View File

@ -0,0 +1,84 @@
#!/bin/bash
set -e
export OPTIMIZE="-Os"
export LDFLAGS="${OPTIMIZE}"
export CFLAGS="${OPTIMIZE}"
export CPPFLAGS="${OPTIMIZE}"
echo "============================================="
echo "Compiling libaom"
echo "============================================="
test -n "$SKIP_LIBAOM" || (
cd node_modules/libavif/ext
test -d aom || git clone -b v1.0.0-errata1-avif --depth 1 https://aomedia.googlesource.com/aom aom
cd aom
mkdir -p build.libavif
cd build.libavif
emcmake cmake \
-DCMAKE_BUILD_TYPE=Release \
-DENABLE_CCACHE=0 \
-DAOM_TARGET_CPU=generic \
-DENABLE_DOCS=0 \
-DENABLE_TESTS=0 \
-DCONFIG_ACCOUNTING=1 \
-DCONFIG_INSPECTION=0 \
-DCONFIG_MULTITHREAD=0 \
-DCONFIG_RUNTIME_CPU_DETECT=0 \
-DCONFIG_WEBM_IO=0 \
../
emmake make
)
echo "============================================="
echo "Compiling libaom done"
echo "============================================="
echo "============================================="
echo "Compiling libavif"
echo "============================================="
test -n "$SKIP_LIBAVIF" || (
cd node_modules/libavif
mkdir -p build
cd build
emcmake cmake \
DCMAKE_BUILD_TYPE=Release \
-DAVIF_CODEC_AOM=1 \
-DAVIF_LOCAL_AOM=1 \
../
emmake make
)
echo "============================================="
echo "Compiling libavif done"
echo "============================================="
echo "============================================="
echo "Compiling wasm bindings"
echo "============================================="
(
emcc \
${OPTIMIZE} \
--bind \
-s ALLOW_MEMORY_GROWTH=1 \
-s MODULARIZE=1 \
-s 'EXPORT_NAME="avif_enc"' \
--std=c++11 \
-I ./node_modules/libavif/include \
-o ./avif_enc.js \
-x c++ \
avif_enc.cpp \
./node_modules/libavif/build/libavif.a \
./node_modules/libavif/ext/aom/build.libavif/libaom.a
)
echo "============================================="
echo "Compiling wasm bindings done"
echo "============================================="
echo "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
echo "Did you update your docker image?"
echo "Run \`docker pull trzeci/emscripten\`"
echo "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"

View File

@ -0,0 +1,11 @@
const fs = require("fs");
const avifEnc = require("./avif_enc.js")(fs.readFileSync("./avif_enc.wasm"));
avifEnc.onRuntimeInitialized = () => {
const avif = avifEnc.encode(
new Uint8Array([255, 0, 0, 255, 0, 255, 0, 255, 0, 0, 255, 255]),
3,
1
);
fs.writeFileSync("lol.avif", avif);
};

1147
codecs/avif_enc/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,13 @@
{
"name": "avif_enc",
"scripts": {
"install": "napa",
"build": "docker run --rm -v $(pwd):/src trzeci/emscripten ./build.sh"
},
"napa": {
"libavif": "AOMediaCodec/libavif#v0.5.4"
},
"devDependencies": {
"napa": "3.0.0"
}
}