diff options
author | Vittorio Giovara <vittorio.giovara@gmail.com> | 2015-04-25 23:58:57 +0100 |
---|---|---|
committer | Vittorio Giovara <vittorio.giovara@gmail.com> | 2015-06-22 15:23:08 +0100 |
commit | 7ca3e5203f133eb41a0b5c3a1d753a7427ba72e7 (patch) | |
tree | 900fdfc294a8fa00470326eee3ae98fb055febeb | |
parent | c0b105756f61d253bdabcc2bb49453a2557e7c3b (diff) | |
download | ffmpeg-7ca3e5203f133eb41a0b5c3a1d753a7427ba72e7.tar.gz |
Hap decoder and encoder
Signed-off-by: Vittorio Giovara <vittorio.giovara@gmail.com>
-rw-r--r-- | Changelog | 1 | ||||
-rwxr-xr-x | configure | 6 | ||||
-rw-r--r-- | doc/general.texi | 1 | ||||
-rw-r--r-- | libavcodec/Makefile | 2 | ||||
-rw-r--r-- | libavcodec/allcodecs.c | 1 | ||||
-rw-r--r-- | libavcodec/avcodec.h | 1 | ||||
-rw-r--r-- | libavcodec/codec_desc.c | 7 | ||||
-rw-r--r-- | libavcodec/hap.h | 65 | ||||
-rw-r--r-- | libavcodec/hapdec.c | 238 | ||||
-rw-r--r-- | libavcodec/hapenc.c | 204 | ||||
-rw-r--r-- | libavcodec/version.h | 4 | ||||
-rw-r--r-- | libavformat/isom.c | 4 | ||||
-rw-r--r-- | tests/fate/video.mak | 12 | ||||
-rw-r--r-- | tests/ref/fate/hap1 | 2 | ||||
-rw-r--r-- | tests/ref/fate/hap5 | 2 | ||||
-rw-r--r-- | tests/ref/fate/hapy | 2 |
16 files changed, 550 insertions, 2 deletions
@@ -34,6 +34,7 @@ version <next>: - NVIDIA NVENC-accelerated H.264 and HEVC encoding support - Multipart JPEG demuxer - Support the extended vp9 profiles in the libvpx wrapper +- Hap decoder and encoder version 11: @@ -202,6 +202,7 @@ External library support: --enable-libpulse enable Pulseaudio input via libpulse [no] --enable-librtmp enable RTMP[E] support via librtmp [no] --enable-libschroedinger enable Dirac de/encoding via libschroedinger [no] + --enable-libsnappy enable Snappy compression [no] --enable-libspeex enable Speex de/encoding via libspeex [no] --enable-libtheora enable Theora encoding via libtheora [no] --enable-libtwolame enable MP2 encoding via libtwolame [no] @@ -1176,6 +1177,7 @@ EXTERNAL_LIBRARY_LIST=" libpulse librtmp libschroedinger + libsnappy libspeex libtheora libtwolame @@ -1861,6 +1863,9 @@ h264_qsv_decoder_deps="libmfx" h264_qsv_decoder_select="h264_mp4toannexb_bsf h264_parser qsvdec h264_qsv_hwaccel" h264_qsv_encoder_deps="libmfx" h264_qsv_encoder_select="qsvenc" +hap_decoder_select="snappy texturedsp" +hap_encoder_deps="libsnappy" +hap_encoder_select="texturedspenc" hevc_decoder_select="bswapdsp cabac golomb videodsp" hevc_nvenc_encoder_deps="nvenc" huffyuv_decoder_select="bswapdsp huffyuvdsp" @@ -4308,6 +4313,7 @@ enabled libopus && require_pkg_config opus opus_multistream.h opus_mul enabled libpulse && require_pkg_config libpulse-simple pulse/simple.h pa_simple_new enabled librtmp && require_pkg_config librtmp librtmp/rtmp.h RTMP_Socket enabled libschroedinger && require_pkg_config schroedinger-1.0 schroedinger/schro.h schro_init +enabled libsnappy && require snappy snappy-c.h snappy_compress -lsnappy enabled libspeex && require_pkg_config speex speex/speex.h speex_decoder_init -lspeex enabled libtheora && require libtheora theora/theoraenc.h th_info_init -ltheoraenc -ltheoradec -logg enabled libtwolame && require libtwolame twolame.h twolame_init -ltwolame diff --git a/doc/general.texi b/doc/general.texi index ab8673a1c9..7dd9a8de20 100644 --- a/doc/general.texi +++ b/doc/general.texi @@ -424,6 +424,7 @@ library: @tab Tiertex .seq files used in the DOS CD-ROM version of the game Flashback. @item True Audio @tab @tab X @item VC-1 test bitstream @tab X @tab X +@item Vidvox Hap @tab X @tab X @item WAV @tab X @tab X @item WavPack @tab @tab X @item WebM @tab X @tab X diff --git a/libavcodec/Makefile b/libavcodec/Makefile index 26f1c072b1..e73d22ea20 100644 --- a/libavcodec/Makefile +++ b/libavcodec/Makefile @@ -235,6 +235,8 @@ OBJS-$(CONFIG_H264_MMAL_DECODER) += mmaldec.o OBJS-$(CONFIG_H264_NVENC_ENCODER) += nvenc_h264.o OBJS-$(CONFIG_H264_QSV_DECODER) += qsvdec_h264.o OBJS-$(CONFIG_H264_QSV_ENCODER) += qsvenc_h264.o +OBJS-$(CONFIG_HAP_DECODER) += hapdec.o +OBJS-$(CONFIG_HAP_ENCODER) += hapenc.o OBJS-$(CONFIG_HEVC_DECODER) += hevc.o hevc_mvs.o hevc_ps.o hevc_sei.o \ hevc_cabac.o hevc_refs.o hevcpred.o \ hevcdsp.o hevc_filter.o diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c index e2013c3050..086992fcee 100644 --- a/libavcodec/allcodecs.c +++ b/libavcodec/allcodecs.c @@ -169,6 +169,7 @@ void avcodec_register_all(void) REGISTER_DECODER(H264, h264); REGISTER_DECODER(H264_MMAL, h264_mmal); REGISTER_DECODER(H264_QSV, h264_qsv); + REGISTER_ENCDEC (HAP, hap); REGISTER_DECODER(HEVC, hevc); REGISTER_DECODER(HNM4_VIDEO, hnm4_video); REGISTER_DECODER(HQ_HQA, hq_hqa); diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h index e82867ecc0..b7c0d9576d 100644 --- a/libavcodec/avcodec.h +++ b/libavcodec/avcodec.h @@ -296,6 +296,7 @@ enum AVCodecID { AV_CODEC_ID_HQX, AV_CODEC_ID_TDSC, AV_CODEC_ID_HQ_HQA, + AV_CODEC_ID_HAP, /* various PCM "codecs" */ AV_CODEC_ID_FIRST_AUDIO = 0x10000, ///< A dummy id pointing at the start of audio codecs diff --git a/libavcodec/codec_desc.c b/libavcodec/codec_desc.c index 4f2a63a56d..950edbf01e 100644 --- a/libavcodec/codec_desc.c +++ b/libavcodec/codec_desc.c @@ -1148,6 +1148,13 @@ static const AVCodecDescriptor codec_descriptors[] = { .long_name = NULL_IF_CONFIG_SMALL("Canopus HQ/HQA"), .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY, }, + { + .id = AV_CODEC_ID_HAP, + .type = AVMEDIA_TYPE_VIDEO, + .name = "hap", + .long_name = NULL_IF_CONFIG_SMALL("Vidvox Hap decoder"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY, + }, /* image codecs */ { diff --git a/libavcodec/hap.h b/libavcodec/hap.h new file mode 100644 index 0000000000..1250a6f683 --- /dev/null +++ b/libavcodec/hap.h @@ -0,0 +1,65 @@ +/* + * Vidvox Hap + * Copyright (C) 2015 Vittorio Giovara <vittorio.giovara@gmail.com> + * + * This file is part of Libav. + * + * Libav is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * Libav is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with Libav; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_HAP_H +#define AVCODEC_HAP_H + +#include <stdint.h> + +#include "libavutil/opt.h" + +#include "bytestream.h" +#include "texturedsp.h" + +typedef struct HapContext { + AVClass *class; + + TextureDSPContext dxtc; + GetByteContext gbc; + PutByteContext pbc; + + int section_type; /* Header type */ + + int tex_rat; /* Compression ratio */ + const uint8_t *tex_data; /* Compressed texture */ + uint8_t *tex_buf; /* Uncompressed texture */ + size_t tex_size; /* Size of the compressed texture */ + + uint8_t *snappied; /* Buffer interacting with snappy */ + size_t max_snappy; /* Maximum compressed size for snappy buffer */ + + /* Pointer to the selected compress or decompress function */ + int (*tex_fun)(uint8_t *dst, ptrdiff_t stride, const uint8_t *block); +} HapContext; + +enum { + HAP_FMT_RGBDXT1 = 0x0B, + HAP_FMT_RGBADXT5 = 0x0E, + HAP_FMT_YCOCGDXT5 = 0x0F, +}; + +enum { + HAP_COMP_NONE = 0xA0, + HAP_COMP_SNAPPY = 0xB0, + HAP_COMP_COMPLEX = 0xC0, +}; + +#endif /* AVCODEC_HAP_H */ diff --git a/libavcodec/hapdec.c b/libavcodec/hapdec.c new file mode 100644 index 0000000000..72db9f4702 --- /dev/null +++ b/libavcodec/hapdec.c @@ -0,0 +1,238 @@ +/* + * Vidvox Hap decoder + * Copyright (C) 2015 Vittorio Giovara <vittorio.giovara@gmail.com> + * + * This file is part of Libav. + * + * Libav is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * Libav is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with Libav; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * Hap decoder + * + * Fourcc: Hap1, Hap5, HapY + * + * https://github.com/Vidvox/hap/blob/master/documentation/HapVideoDRAFT.md + */ + +#include <stdint.h> + +#include "libavutil/imgutils.h" + +#include "avcodec.h" +#include "bytestream.h" +#include "hap.h" +#include "internal.h" +#include "snappy.h" +#include "texturedsp.h" +#include "thread.h" + +/* 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) < 4) + return AVERROR_INVALIDDATA; + + length = bytestream2_get_le24(gbc); + + ctx->section_type = bytestream2_get_byte(gbc); + + if (length == 0) { + if (bytestream2_get_bytes_left(gbc) < 4) + return AVERROR_INVALIDDATA; + length = bytestream2_get_le32(gbc); + } + + if (length > bytestream2_get_bytes_left(gbc) || length == 0) + return AVERROR_INVALIDDATA; + + return length; +} + +/* Prepare the texture to be decompressed */ +static int setup_texture(AVCodecContext *avctx, size_t length) +{ + HapContext *ctx = avctx->priv_data; + GetByteContext *gbc = &ctx->gbc; + int64_t snappy_size; + const char *texture_name; + const char *compressorstr; + int ret; + + switch (ctx->section_type & 0x0F) { + case HAP_FMT_RGBDXT1: + ctx->tex_rat = 8; + ctx->tex_fun = ctx->dxtc.dxt1_block; + texture_name = "DXT1"; + break; + case HAP_FMT_RGBADXT5: + ctx->tex_rat = 16; + ctx->tex_fun = ctx->dxtc.dxt5_block; + texture_name = "DXT5"; + break; + case HAP_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 HAP_COMP_NONE: + /* Only DXTC texture compression */ + ctx->tex_data = gbc->buffer; + ctx->tex_size = length; + compressorstr = "none"; + break; + case HAP_COMP_SNAPPY: + /* Uncompress the frame */ + ret = ff_snappy_uncompress(gbc, &ctx->snappied, &snappy_size); + if (ret < 0) { + av_log(avctx, AV_LOG_ERROR, "Snappy uncompress error\n"); + return ret; + } + + ctx->tex_data = ctx->snappied; + ctx->tex_size = snappy_size; + compressorstr = "snappy"; + break; + case HAP_COMP_COMPLEX: + compressorstr = "complex"; + avpriv_request_sample(avctx, "Complex Hap compressor"); + return AVERROR_PATCHWELCOME; + break; + default: + av_log(avctx, AV_LOG_ERROR, + "Invalid compressor mode %02X.\n", ctx->section_type); + return AVERROR_INVALIDDATA; + } + + av_log(avctx, AV_LOG_DEBUG, "%s texture with %s compressor\n", + texture_name, compressorstr); + + return 0; +} + +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 = (TEXTURE_BLOCK_W * block_nb) % avctx->coded_width; + int y = TEXTURE_BLOCK_H * (TEXTURE_BLOCK_W * block_nb / avctx->coded_width); + uint8_t *p = frame->data[0] + x * 4 + 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; +} + +static int hap_decode(AVCodecContext *avctx, void *data, + int *got_frame, AVPacket *avpkt) +{ + HapContext *ctx = avctx->priv_data; + ThreadFrame tframe; + int ret, length; + int blocks = avctx->coded_width * avctx->coded_height / (TEXTURE_BLOCK_W * TEXTURE_BLOCK_H); + + bytestream2_init(&ctx->gbc, avpkt->data, avpkt->size); + + /* Check for section header */ + length = parse_section_header(avctx); + if (length < 0) { + av_log(avctx, AV_LOG_ERROR, "Frame is too small.\n"); + return length; + } + + /* Prepare the texture buffer and decompress function */ + ret = setup_texture(avctx, length); + if (ret < 0) + return ret; + + /* Get the output frame ready to receive data */ + tframe.f = data; + ret = ff_thread_get_buffer(avctx, &tframe, 0); + if (ret < 0) + return ret; + ff_thread_finish_setup(avctx); + + /* Use the decompress function on the texture, one block per thread */ + avctx->execute2(avctx, decompress_texture_thread, tframe.f, NULL, blocks); + + /* Frame is ready to be output */ + tframe.f->pict_type = AV_PICTURE_TYPE_I; + tframe.f->key_frame = 1; + *got_frame = 1; + + return avpkt->size; +} + +static av_cold int hap_init(AVCodecContext *avctx) +{ + HapContext *ctx = avctx->priv_data; + 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; + } + + /* Since codec is based on 4x4 blocks, size is aligned to 4 */ + avctx->coded_width = FFALIGN(avctx->width, TEXTURE_BLOCK_W); + avctx->coded_height = FFALIGN(avctx->height, TEXTURE_BLOCK_H); + + /* Technically only one mode has alpha, but 32 bits are easier to handle */ + avctx->pix_fmt = AV_PIX_FMT_RGBA; + + ff_texturedsp_init(&ctx->dxtc); + + return 0; +} + +static av_cold int hap_close(AVCodecContext *avctx) +{ + HapContext *ctx = avctx->priv_data; + + av_freep(&ctx->snappied); + + return 0; +} + +AVCodec ff_hap_decoder = { + .name = "hap", + .long_name = NULL_IF_CONFIG_SMALL("Vidvox Hap decoder"), + .type = AVMEDIA_TYPE_VIDEO, + .id = AV_CODEC_ID_HAP, + .init = hap_init, + .decode = hap_decode, + .close = hap_close, + .priv_data_size = sizeof(HapContext), + .capabilities = CODEC_CAP_FRAME_THREADS | CODEC_CAP_SLICE_THREADS | + CODEC_CAP_DR1, + .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE | + FF_CODEC_CAP_INIT_CLEANUP, +}; diff --git a/libavcodec/hapenc.c b/libavcodec/hapenc.c new file mode 100644 index 0000000000..d828a096d5 --- /dev/null +++ b/libavcodec/hapenc.c @@ -0,0 +1,204 @@ +/* + * Vidvox Hap encoder + * Copyright (C) 2015 Vittorio Giovara <vittorio.giovara@gmail.com> + * + * This file is part of Libav. + * + * Libav is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * Libav is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with Libav; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * Hap encoder + * + * Fourcc: Hap1, Hap5, HapY + * + * https://github.com/Vidvox/hap/blob/master/documentation/HapVideoDRAFT.md + */ + +#include <stdint.h> +#include "snappy-c.h" + +#include "libavutil/frame.h" +#include "libavutil/imgutils.h" +#include "libavutil/intreadwrite.h" +#include "libavutil/opt.h" + +#include "avcodec.h" +#include "bytestream.h" +#include "hap.h" +#include "internal.h" +#include "texturedsp.h" + +/* A fixed header size allows to skip a memcpy */ +#define HEADER_SIZE 8 + +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 * 4 + j * f->linesize[0]; + const int step = ctx->tex_fun(out, f->linesize[0], p); + out += step; + } + } +} + +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; + + /* 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 = HAP_COMP_NONE; + av_log(avctx, AV_LOG_VERBOSE, + "Snappy buffer bigger than uncompressed (%lu > %lu bytes).\n", + final_size, ctx->tex_size); + memcpy(pkt->data + HEADER_SIZE, ctx->tex_buf, ctx->tex_size); + final_size = ctx->tex_size; + } + + /* Write header at the start. */ + AV_WL24(pkt->data, 0); + AV_WL32(pkt->data + 4, final_size); + pkt->data[3] = comp | ctx->section_type; + + av_shrink_packet(pkt, final_size + HEADER_SIZE); + pkt->flags |= AV_PKT_FLAG_KEY; + *got_packet = 1; + return 0; +} + +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; + } + + if (avctx->width % 4 || avctx->height % 4) { + av_log(avctx, AV_LOG_ERROR, "Video size %dx%d is not multiple of 4.\n", + avctx->width, avctx->height); + return AVERROR_INVALIDDATA; + } + + ff_texturedspenc_init(&ctx->dxtc); + + switch (ctx->section_type & 0x0F) { + case HAP_FMT_RGBDXT1: + ratio = 8; + avctx->codec_tag = MKTAG('H', 'a', 'p', '1'); + ctx->tex_fun = ctx->dxtc.dxt1_block; + break; + case HAP_FMT_RGBADXT5: + ratio = 4; + avctx->codec_tag = MKTAG('H', 'a', 'p', '5'); + ctx->tex_fun = ctx->dxtc.dxt5_block; + break; + case HAP_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 = FFALIGN(avctx->width, TEXTURE_BLOCK_W) * + FFALIGN(avctx->height, TEXTURE_BLOCK_H) * 4 / ratio; + ctx->max_snappy = snappy_max_compressed_length(ctx->tex_size); + + ctx->tex_buf = av_malloc(ctx->tex_size); + if (!ctx->tex_buf) + return AVERROR(ENOMEM); + + return 0; +} + +static av_cold int hap_close(AVCodecContext *avctx) +{ + HapContext *ctx = avctx->priv_data; + + av_freep(&ctx->tex_buf); + + return 0; +} + +#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" }, + { "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" }, + + { NULL }, +}; + +static const AVClass hapenc_class = { + .class_name = "Hap encoder", + .item_name = av_default_item_name, + .option = options, + .version = LIBAVUTIL_VERSION_INT, +}; + +AVCodec ff_hap_encoder = { + .name = "hap", + .long_name = NULL_IF_CONFIG_SMALL("Vidvox Hap encoder"), + .type = AVMEDIA_TYPE_VIDEO, + .id = AV_CODEC_ID_HAP, + .priv_data_size = sizeof(HapContext), + .priv_class = &hapenc_class, + .init = hap_init, + .encode2 = hap_encode, + .close = hap_close, + .pix_fmts = (const enum AVPixelFormat[]) { + AV_PIX_FMT_RGBA, AV_PIX_FMT_NONE, + }, + .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE | + FF_CODEC_CAP_INIT_CLEANUP, +}; diff --git a/libavcodec/version.h b/libavcodec/version.h index 53f5f9791a..7f72a6b037 100644 --- a/libavcodec/version.h +++ b/libavcodec/version.h @@ -29,8 +29,8 @@ #include "libavutil/version.h" #define LIBAVCODEC_VERSION_MAJOR 56 -#define LIBAVCODEC_VERSION_MINOR 26 -#define LIBAVCODEC_VERSION_MICRO 1 +#define LIBAVCODEC_VERSION_MINOR 27 +#define LIBAVCODEC_VERSION_MICRO 0 #define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \ LIBAVCODEC_VERSION_MINOR, \ diff --git a/libavformat/isom.c b/libavformat/isom.c index f8cc4b2b9e..b4001772db 100644 --- 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 }, }; diff --git a/tests/fate/video.mak b/tests/fate/video.mak index 29d5ccee02..016df7c437 100644 --- a/tests/fate/video.mak +++ b/tests/fate/video.mak @@ -160,6 +160,18 @@ fate-id-cin-video: CMD = framecrc -i $(TARGET_SAMPLES)/idcin/idlog-2MB.cin -pix_ FATE_SAMPLES_AVCONV-$(call ENCDEC, ROQ PGMYUV, ROQ IMAGE2) += fate-idroq-video-encode fate-idroq-video-encode: CMD = md5 -f image2 -vcodec pgmyuv -i $(TARGET_SAMPLES)/ffmpeg-synthetic/vsynth1/%02d.pgm -sws_flags +bitexact -vf pad=512:512:80:112 -f roq -t 0.2 +FATE_HAP += fate-hap1 +fate-hap1: CMD = framecrc -i $(TARGET_SAMPLES)/hap/hap1.mov + +FATE_HAP += fate-hap5 +fate-hap5: CMD = framecrc -i $(TARGET_SAMPLES)/hap/hap5.mov + +FATE_HAP += fate-hapy +fate-hapy: CMD = framecrc -i $(TARGET_SAMPLES)/hap/hapy.mov + +FATE_SAMPLES_AVCONV-$(call DEMDEC, MOV, HAP) += $(FATE_HAP) +fate-hap: $(FATE_HAP) + FATE_IFF-$(CONFIG_IFF_BYTERUN1_DECODER) += fate-iff-byterun1 fate-iff-byterun1: CMD = framecrc -i $(TARGET_SAMPLES)/iff/ASH.LBM -pix_fmt rgb24 diff --git a/tests/ref/fate/hap1 b/tests/ref/fate/hap1 new file mode 100644 index 0000000000..0cabf8bf4f --- /dev/null +++ b/tests/ref/fate/hap1 @@ -0,0 +1,2 @@ +#tb 0: 1/2997 +0, 0, 0, 0, 1228800, 0x0fa946bc diff --git a/tests/ref/fate/hap5 b/tests/ref/fate/hap5 new file mode 100644 index 0000000000..a582c3952c --- /dev/null +++ b/tests/ref/fate/hap5 @@ -0,0 +1,2 @@ +#tb 0: 1/3000 +0, 0, 0, 0, 1228800, 0xb71ecf93 diff --git a/tests/ref/fate/hapy b/tests/ref/fate/hapy new file mode 100644 index 0000000000..e6dd4f5df5 --- /dev/null +++ b/tests/ref/fate/hapy @@ -0,0 +1,2 @@ +#tb 0: 1/2997 +0, 0, 0, 0, 1228800, 0x5993522d |