> diff --git a/Changelog b/Changelog
> index 9d73449..f7c59e9 100644
> --- a/Changelog
> +++ b/Changelog
> @@ -30,6 +30,7 @@ version <next>:
>  - Canopus HQ/HQA decoder
>  - Automatically rotate videos based on metadata in avconv
>  - improved Quickdraw compatibility
> +- HAP decoder and encoder
>

Hap, not HAP (throughout your patch)
Also Vidvox not VidVox or VideoVox as it appears variously


>
>  version 11:
> diff --git a/configure b/configure
> index 5bcc2df..80cda8e 100755
> --- a/configure
> +++ b/configure
> @@ -220,6 +220,7 @@ External library support:
>                             native MPEG-4/Xvid encoder exists [no]
>    --enable-mmal            enable decoding via MMAL [no]
>    --enable-openssl         enable openssl [no]
> +  --enable-snappy          enable snappy decompression [no]
>    --enable-x11grab         enable X11 grabbing (legacy) [no]
>    --enable-zlib            enable zlib [autodetect]
>

Can it be autodetected?


> diff --git a/libavcodec/hapdec.c b/libavcodec/hapdec.c
>
<snip>

+
> +/* The first three bytes are the size of the section past the header, or
> zero
> + * if the length is stored in the next long word. The fourth byte in the
> first
> + * long word indicates the type of the current section. */
> +static int parse_section_header(AVCodecContext *avctx)
> +{
> +    HAPContext *ctx = avctx->priv_data;
> +    GetByteContext *gbc = &ctx->gbc;
> +    int length;
> +
> +    if (bytestream2_get_bytes_left(gbc) < 8)
> +        return AVERROR_INVALIDDATA;
>

A valid section header can be 4 bytes, check for 4 here


> +
> +    length = bytestream2_get_le24(gbc);
> +
> +    ctx->section_type = bytestream2_get_byte(gbc);
> +
> +    if (length == 0)
>

and the next 4 here if you are about to consume them

<snip>

+/* Prepare the texture to be decompressed */
> +static int setup_texture(AVCodecContext *avctx, size_t length)
> +{
> +    HAPContext *ctx = avctx->priv_data;
> +    GetByteContext *gbc = &ctx->gbc;
> +    size_t snappy_size;
> +    const char *texture_name;
> +    const char *compressor_name;
> +    int ret;
> +
> +    switch (ctx->section_type & 0x0F) {
> +    case FMT_RGBDXT1:
> +        ctx->tex_rat = 8;
> +        ctx->tex_fun = ctx->dxtc.dxt1_block;
> +        texture_name = "DXT1";
> +        break;
> +    case FMT_RGBADXT5:
> +        ctx->tex_rat = 16;
> +        ctx->tex_fun = ctx->dxtc.dxt5_block;
> +        texture_name = "DXT5";
> +        break;
> +    case FMT_YCOCGDXT5:
> +        ctx->tex_rat = 16;
> +        ctx->tex_fun = ctx->dxtc.dxt5ys_block;
> +        texture_name = "DXT5-YCoCg-scaled";
> +        break;
> +    default:
> +        av_log(avctx, AV_LOG_ERROR,
> +               "Invalid format mode %02X.\n", ctx->section_type);
> +        return AVERROR_INVALIDDATA;
> +    }
> +
> +    switch (ctx->section_type & 0xF0) {
> +    case COMP_NONE:
> +        /* Only texture compression */
> +        ctx->tex_data = gbc->buffer;
> +        ctx->tex_size = length;
> +        compressor_name = "none";
> +        break;
> +    case COMP_SNAPPY:
> +        /* Get the size of the output buffer */
> +        ret = snappy_uncompressed_length(gbc->buffer, length,
> &snappy_size);
> +        if (ret != SNAPPY_OK) {
> +            av_log(avctx, AV_LOG_ERROR, "Snappy size error\n");
> +            return AVERROR_BUG;
>

This would most likely be due to malformed input so AVERROR_INVALIDDATA

<snip>

+
> +static int decompress_texture_thread(AVCodecContext *avctx, void *arg,
> +                                     int block_nb, int thread_nb)
> +{
> +    HAPContext *ctx = avctx->priv_data;
> +    AVFrame *frame = arg;
> +    int x = (BLOCK_W * block_nb) % avctx->coded_width;
> +    int y = BLOCK_H * (BLOCK_W * block_nb / avctx->coded_width);
> +    uint8_t *p = frame->data[0] + x * PIXEL_SIZE + y * frame->linesize[0];
> +    const uint8_t *d = ctx->tex_data + block_nb * ctx->tex_rat;
> +
> +    ctx->tex_fun(p, frame->linesize[0], d);
> +    return 0;
> +}
>

This will write outside image boundaries when dimensions aren't a multiple
of 4



> diff --git a/libavcodec/hapenc.c b/libavcodec/hapenc.c
>
<snip>

> +static void compress_texture(AVCodecContext *avctx, const AVFrame *f)
> +{
> +    HAPContext *ctx = avctx->priv_data;
> +    uint8_t *out = ctx->tex_buf;
> +    int i, j;
> +
> +    for (j = 0; j < avctx->height; j += 4) {
> +        for (i = 0; i < avctx->width; i += 4) {
> +            uint8_t *p = f->data[0] + i * PIXEL_SIZE + j * f->linesize[0];
> +            const int step = ctx->tex_fun(out, f->linesize[0], p);
> +            out += step;
> +        }
> +    }
> +}
>

This will read outside image boundaries when dimensions aren't a multiple
of 4.
Additionally for such images it gives very poor quality along image edges
because it uses garbage pixels to determine colour values.


> +
> +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 = COMP_SNAPPY;
> +    int pktsize = FFMAX(ctx->tex_size, ctx->max_snappy) + HEADER_SIZE;
> +
> +    /* Allocate maximum size packet, shrink later */
> +    ret = ff_alloc_packet(pkt, pktsize);
> +    if (ret < 0)
> +        return ret;
> +
> +    /* DXTC compression */
> +    compress_texture(avctx, frame);
> +
> +    /* Compress with snappy too, write directly on packet buffer */
> +    ret = snappy_compress(ctx->tex_buf, ctx->tex_size,
> +                          pkt->data + HEADER_SIZE, &final_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 (final_size > ctx->tex_size) {
> +        comp = COMP_NONE;
> +        av_log(avctx, AV_LOG_WARNING,
> +               "Snappy buffer bigger than uncompressed (%lu > %lu
> bytes).\n",
> +               final_size, ctx->tex_size);
>

Is this worthy of a warning?

<snip>

> +static av_cold int hap_init(AVCodecContext *avctx)
> +{
> +    HAPContext *ctx = avctx->priv_data;
> +    int ratio;
> +    int ret = av_image_check_size(avctx->width, avctx->height, 0, avctx);
> +
> +    if (ret < 0) {
> +        av_log(avctx, AV_LOG_ERROR, "Invalid video size %dx%d.\n",
> +               avctx->width, avctx->height);
> +        return ret;
> +    }
> +
> +    ff_dxtc_compression_init(&ctx->dxtc);
> +
> +    switch (ctx->section_type & 0x0F) {
> +    case FMT_RGBDXT1:
> +        ratio = 8;
> +        avctx->codec_tag = MKTAG('H', 'a', 'p', '1');
> +        ctx->tex_fun = ctx->dxtc.dxt1_block;
> +        break;
> +    case FMT_RGBADXT5:
> +        ratio = 4;
> +        avctx->codec_tag = MKTAG('H', 'a', 'p', '5');
> +        ctx->tex_fun = ctx->dxtc.dxt5_block;
> +        break;
> +    case FMT_YCOCGDXT5:
> +        ratio = 4;
> +        avctx->codec_tag = MKTAG('H', 'a', 'p', 'Y');
> +        ctx->tex_fun = ctx->dxtc.dxt5ys_block;
> +        break;
> +    default:
> +        av_log(avctx, AV_LOG_ERROR, "Invalid format %02X\n",
> ctx->section_type);
> +        return AVERROR_INVALIDDATA;
> +    }
> +
> +    /* Texture compression ratio is constant, so can we computer
> +     * beforehand the final size of the uncompressed buffer */
> +    ctx->tex_size   = avctx->width * avctx->height * PIXEL_SIZE / ratio;
>

You need to align the dimensions to 4 to arrive at tex_size

<snip>

diff --git a/libavformat/isom.c b/libavformat/isom.c
> @@ -250,6 +250,10 @@ const AVCodecTag ff_codec_movvideo_tags[] = {
>
>      { AV_CODEC_ID_AIC, MKTAG('i', 'c', 'o', 'd') },
>
> +    { AV_CODEC_ID_HAP, MKTAG('H', 'A', 'P', '1') },
> +    { AV_CODEC_ID_HAP, MKTAG('H', 'A', 'P', '5') },
> +    { AV_CODEC_ID_HAP, MKTAG('H', 'A', 'P', 'Y') },
> +
>      { AV_CODEC_ID_NONE, 0 },
>  };
>

I know these are compared internally without consideration of case, but
Hap1, Hap5, HapY

Cheers - Tom
_______________________________________________
libav-devel mailing list
[email protected]
https://lists.libav.org/mailman/listinfo/libav-devel

Reply via email to