On Fri, Jul 17, 2015 at 1:11 PM, Tom Butterworth <[email protected]> wrote:
> ---
> libavcodec/Makefile | 4 +-
> libavcodec/hap.c | 51 +++++++++
> libavcodec/hap.h | 68 ++++++++----
> libavcodec/hapdec.c | 278
> ++++++++++++++++++++++++++++++++++++-----------
> libavcodec/hapenc.c | 190 ++++++++++++++++++++++++++------
> tests/fate/video.mak | 3 +
> tests/ref/fate/hap-chunk | 2 +
> 7 files changed, 481 insertions(+), 115 deletions(-)
> create mode 100644 libavcodec/hap.c
> create mode 100644 tests/ref/fate/hap-chunk
second part
> @@ -42,8 +43,7 @@
> #include "internal.h"
> #include "texturedsp.h"
>
> -/* A fixed header size allows to skip a memcpy */
> -#define HEADER_SIZE 8
> +#define HAP_MAX_CHUNKS 64
could you keep the define here instead of using 8 below and/or add a
similar define for the short version? it makes the code a little
easier to read
feel free to rename it however you think is fit
> static void compress_texture(AVCodecContext *avctx, const AVFrame *f)
> {
> @@ -60,13 +60,139 @@ static void compress_texture(AVCodecContext *avctx,
> const AVFrame *f)
> }
> }
>
> +/*
> + - header_length is 4 or 8
> + - section_length does not include the header
> + */
> +static void hap_write_section_header(PutByteContext *pbc, int header_length,
> + int section_length,
> + enum HapSectionType section_type)
> +{
> + /*
> + The first three bytes are the length of the section (not including the
> header) or zero
> + if using an eight-byte header.
> + For an eight-byte header, the length is in the last four bytes.
> + The fourth byte stores the section type.
> + */
> + bytestream2_put_le24(pbc, header_length == 8 ? 0 : section_length);
> + bytestream2_put_byte(pbc, section_type);
> +
> + if (header_length == 8)
> + {
> + bytestream2_put_le32(pbc, section_length);
> + }
nit: you may skip the {} here
> +}
> +
> +static int hap_compress_frame(AVCodecContext *avctx, uint8_t *dst)
> +{
> + HapContext *ctx = avctx->priv_data;
> + int i, final_size = 0;
> +
> + for (i = 0; i < ctx->chunk_count; i++) {
> + HapChunk *chunk = &ctx->chunks[i];
> + uint8_t *chunk_src, *chunk_dst;
> + int ret;
> +
> + if (i == 0) {
> + chunk->compressed_offset = 0;
> + } else {
> + chunk->compressed_offset = ctx->chunks[i-1].compressed_offset
> + + ctx->chunks[i-1].compressed_size;
> + }
> + chunk->uncompressed_size = ctx->tex_size / ctx->chunk_count;
> + chunk->uncompressed_offset = i * chunk->uncompressed_size;
> + chunk->compressed_size = ctx->max_snappy;
> + chunk_src = ctx->tex_buf + chunk->uncompressed_offset;
> + chunk_dst = dst + chunk->compressed_offset;
> +
> + /* Compress with snappy too, write directly on packet buffer. */
> + ret = snappy_compress(chunk_src, chunk->uncompressed_size,
> + chunk_dst, &chunk->compressed_size);
> + if (ret != SNAPPY_OK) {
> + av_log(avctx, AV_LOG_ERROR, "Snappy compress error.\n");
> + return AVERROR_BUG;
> + }
> +
> + /* If there is no gain from snappy, just use the raw texture. */
> + if (chunk->compressed_size >= chunk->uncompressed_size) {
> + av_log(avctx, AV_LOG_VERBOSE,
> + "Snappy buffer bigger than uncompressed (%lu >= %lu
> bytes).\n",
> + chunk->compressed_size, chunk->uncompressed_size);
> + memcpy(chunk_dst, chunk_src, chunk->uncompressed_size);
> + chunk->compressor = HAP_COMP_NONE;
> + chunk->compressed_size = chunk->uncompressed_size;
> + } else {
> + chunk->compressor = HAP_COMP_SNAPPY;
> + }
> +
> + final_size += chunk->compressed_size;
> + }
> +
> + return final_size;
> +}
> +
> +static int hap_decode_instructions_length(HapContext *ctx)
> +{
> + /*
> + = Second-Stage Compressor Table + Chunk Size Table + headers for both
> sections
> + = chunk_count + (4 * chunk_count) + 4 + 4
> + */
nit: comment = -> *
> + return (5 * ctx->chunk_count) + 8;
> +}
> +
> +static int hap_header_length(HapContext *ctx)
> +{
> + /* Top section header (long version) */
> + int length = 8;
> +
> + if (ctx->chunk_count > 1) {
> + /* Decode Instructions header (short version)
> + + Decode Instructions Container */
> + length += 4U + hap_decode_instructions_length(ctx);
> + }
> +
> + return length;
> +}
> +
> +static void hap_write_frame_header(HapContext *ctx, uint8_t *dst, int
> frame_length)
> +{
> + PutByteContext pbc;
> + int i;
> +
> + bytestream2_init_writer(&pbc, dst, frame_length);
> + if (ctx->chunk_count == 1) {
> + /* Write a simple header */
> + hap_write_section_header(&pbc, 8, frame_length - 8,
> + ctx->chunks[0].compressor |
> ctx->opt_tex_fmt);
> + } else {
> + /* Write a complex header with Decode Instructions Container */
> + hap_write_section_header(&pbc, 8, frame_length - 8,
> + HAP_COMP_COMPLEX | ctx->opt_tex_fmt);
> + hap_write_section_header(&pbc, 4,
> hap_decode_instructions_length(ctx),
> + HAP_ST_DECODE_INSTRUCTIONS);
> + hap_write_section_header(&pbc, 4, ctx->chunk_count,
> + HAP_ST_COMPRESSOR_TABLE);
> +
> + for (i = 0; i < ctx->chunk_count; i++) {
> + bytestream2_put_byte(&pbc, ctx->chunks[i].compressor >> 4);
> + }
> +
> + hap_write_section_header(&pbc, 4, ctx->chunk_count * 4,
> + HAP_ST_SIZE_TABLE);
> +
> + for (i = 0; i < ctx->chunk_count; i++) {
> + bytestream2_put_le32(&pbc, ctx->chunks[i].compressed_size);
> + }
> + }
> +}
> +
> static int hap_encode(AVCodecContext *avctx, AVPacket *pkt,
> const AVFrame *frame, int *got_packet)
> {
> HapContext *ctx = avctx->priv_data;
> - size_t final_size = ctx->max_snappy;
> - int ret, comp = HAP_COMP_SNAPPY;
> - int pktsize = FFMAX(ctx->tex_size, ctx->max_snappy) + HEADER_SIZE;
> + int header_length = hap_header_length(ctx);
> + int final_data_size, ret;
> + int pktsize = FFMAX(ctx->tex_size, ctx->max_snappy * ctx->chunk_count) +
> header_length;
good idea
> /* Allocate maximum size packet, shrink later. */
> ret = ff_alloc_packet(pkt, pktsize);
> @@ -171,11 +297,11 @@ static av_cold int hap_close(AVCodecContext *avctx)
> #define OFFSET(x) offsetof(HapContext, x)
> #define FLAGS AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM
> static const AVOption options[] = {
> - { "format", NULL, OFFSET(section_type), AV_OPT_TYPE_INT, { .i64 =
> HAP_FMT_RGBDXT1 }, HAP_FMT_RGBDXT1, HAP_FMT_YCOCGDXT5, FLAGS, "format" },
> + { "format", NULL, OFFSET(opt_tex_fmt), AV_OPT_TYPE_INT, { .i64 =
> HAP_FMT_RGBDXT1 }, HAP_FMT_RGBDXT1, HAP_FMT_YCOCGDXT5, FLAGS, "format" },
> { "hap", "Hap 1 (DXT1 textures)", 0, AV_OPT_TYPE_CONST, { .i64
> = HAP_FMT_RGBDXT1 }, 0, 0, FLAGS, "format" },
> { "hap_alpha", "Hap Alpha (DXT5 textures)", 0, AV_OPT_TYPE_CONST, {
> .i64 = HAP_FMT_RGBADXT5 }, 0, 0, FLAGS, "format" },
> { "hap_q", "Hap Q (DXT5-YCoCg textures)", 0, AV_OPT_TYPE_CONST,
> { .i64 = HAP_FMT_YCOCGDXT5 }, 0, 0, FLAGS, "format" },
> -
> + { "chunks", "chunk count", OFFSET(opt_chunk_count), AV_OPT_TYPE_INT,
> {.i64 = 1 }, 1, HAP_MAX_CHUNKS, FLAGS, },
> { NULL },
> };
is there any way to automate this? Eg ideally
chunks = -1 -> no complex encoding
chunks = 0 -> automatic selection of the optimal chunk number
chunks = N -> user selection of chunk number
Look ok overall, thanks for your contribution.
--
Vittorio
_______________________________________________
libav-devel mailing list
[email protected]
https://lists.libav.org/mailman/listinfo/libav-devel