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

Reply via email to