From 6cabb679d6aef310277b2995a13d53695da3c15a Mon Sep 17 00:00:00 2001 From: Derek Buitenhuis Date: Sun, 18 Mar 2012 13:00:18 -0400 Subject: [PATCH] ZeroCodec Decoder An obscure Japanese lossless video codec, originally intended for use with a remote desktop application. Signed-off-by: Derek Buitenhuis Signed-off-by: Michael Niedermayer --- Changelog | 1 + MAINTAINERS | 1 + configure | 1 + doc/general.texi | 1 + libavcodec/Makefile | 1 + libavcodec/allcodecs.c | 1 + libavcodec/avcodec.h | 1 + libavcodec/zerocodec.c | 182 +++++++++++++++++++++++++++++++++++++++++ libavformat/riff.c | 1 + 9 files changed, 190 insertions(+) create mode 100644 libavcodec/zerocodec.c diff --git a/Changelog b/Changelog index cfcaf6b5a9..e427db7280 100644 --- a/Changelog +++ b/Changelog @@ -16,6 +16,7 @@ version next: - swapuv filter - bbox filter - XBM encoder +- ZeroCodec decoder version 0.10: diff --git a/MAINTAINERS b/MAINTAINERS index 21062be5f1..f1a46b7557 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -244,6 +244,7 @@ Codecs: xan.c Mike Melanson xl.c Kostya Shishkov xvmc.c Ivan Kalvachev + zerocodec.c Derek Buitenhuis zmbv* Kostya Shishkov Hardware acceleration: diff --git a/configure b/configure index 55a1f45e3c..c6a4d17107 100755 --- a/configure +++ b/configure @@ -1527,6 +1527,7 @@ wmv3_dxva2_hwaccel_select="vc1_dxva2_hwaccel" wmv3_vaapi_hwaccel_select="vc1_vaapi_hwaccel" wmv3_vdpau_decoder_select="vc1_vdpau_decoder" wmv3image_decoder_select="wmv3_decoder" +zerocodec_decoder_select="zlib" zlib_decoder_select="zlib" zlib_encoder_select="zlib" zmbv_decoder_select="zlib" diff --git a/doc/general.texi b/doc/general.texi index 0d520ad98c..f2c21b9065 100644 --- a/doc/general.texi +++ b/doc/general.texi @@ -351,6 +351,7 @@ library: @item eXtended BINary text (XBIN) @tab @tab X @item YUV4MPEG pipe @tab X @tab X @item Psygnosis YOP @tab @tab X +@item ZeroCodec Lossless Video @tab @tab X @end multitable @code{X} means that encoding (resp. decoding) is supported. diff --git a/libavcodec/Makefile b/libavcodec/Makefile index 08a5728185..77ba2562df 100644 --- a/libavcodec/Makefile +++ b/libavcodec/Makefile @@ -493,6 +493,7 @@ OBJS-$(CONFIG_Y41P_ENCODER) += y41penc.o OBJS-$(CONFIG_YOP_DECODER) += yop.o OBJS-$(CONFIG_YUV4_DECODER) += yuv4dec.o OBJS-$(CONFIG_YUV4_ENCODER) += yuv4enc.o +OBJS-$(CONFIG_ZEROCODEC_DECODER) += zerocodec.o OBJS-$(CONFIG_ZLIB_DECODER) += lcldec.o OBJS-$(CONFIG_ZLIB_ENCODER) += lclenc.o OBJS-$(CONFIG_ZMBV_DECODER) += zmbv.o diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c index 26ea1dc791..7337d8cac4 100644 --- a/libavcodec/allcodecs.c +++ b/libavcodec/allcodecs.c @@ -255,6 +255,7 @@ void avcodec_register_all(void) REGISTER_ENCDEC (Y41P, y41p); REGISTER_DECODER (YOP, yop); REGISTER_ENCDEC (YUV4, yuv4); + REGISTER_DECODER (ZEROCODEC, zerocodec); REGISTER_ENCDEC (ZLIB, zlib); REGISTER_ENCDEC (ZMBV, zmbv); diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h index 235ebf2ec6..2f8a8c3b10 100644 --- a/libavcodec/avcodec.h +++ b/libavcodec/avcodec.h @@ -248,6 +248,7 @@ enum CodecID { CODEC_ID_XWD, CODEC_ID_CDXL, CODEC_ID_XBM, + CODEC_ID_ZEROCODEC, CODEC_ID_Y41P = MKBETAG('Y','4','1','P'), CODEC_ID_ESCAPE130 = MKBETAG('E','1','3','0'), CODEC_ID_AVRP = MKBETAG('A','V','R','P'), diff --git a/libavcodec/zerocodec.c b/libavcodec/zerocodec.c new file mode 100644 index 0000000000..826063c679 --- /dev/null +++ b/libavcodec/zerocodec.c @@ -0,0 +1,182 @@ +/* + * ZeroCodec Decoder + * + * Copyright (c) 2012, Derek Buitenhuis + * + * This file is part of FFMpeg. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include "avcodec.h" + +typedef struct { + AVFrame previous_frame; + z_stream zstream; + int size; +} ZeroCodecContext; + +static int zerocodec_decode_frame(AVCodecContext *avctx, void *data, + int *data_size, AVPacket *avpkt) +{ + ZeroCodecContext *zc = avctx->priv_data; + AVFrame *pic = avctx->coded_frame; + AVFrame *prev_pic = &zc->previous_frame; + z_stream *zstream = &zc->zstream; + uint8_t *prev, *dst; + int i, j, zret; + + pic->reference = 3; + + if (avctx->get_buffer(avctx, pic) < 0) { + av_log(avctx, AV_LOG_ERROR, "Could not allocate buffer.\n"); + return AVERROR(ENOMEM); + } + + zret = inflateReset(zstream); + + if (zret != Z_OK) { + av_log(avctx, AV_LOG_ERROR, "Could not reset inflate: %d\n", zret); + return AVERROR(EINVAL); + } + + zstream->next_in = avpkt->data; + zstream->avail_in = avpkt->size; + + prev = prev_pic->data[0]; + dst = pic->data[0]; + + /** + * ZeroCodec has very simple interframe compression. If a value + * is the same as the previous frame, set it to 0. + */ + + if (avpkt->flags & AV_PKT_FLAG_KEY) { + + pic->key_frame = 1; + pic->pict_type = AV_PICTURE_TYPE_I; + + for (i = 0; i < avctx->height; i++) { + + zstream->next_out = dst; + zstream->avail_out = avctx->width << 1; + + zret = inflate(zstream, Z_SYNC_FLUSH); + + if (zret != Z_OK && zret != Z_STREAM_END) { + av_log(avctx, AV_LOG_ERROR, "Inflate failed with return code: %d\n", zret); + return AVERROR(EINVAL); + } + + dst += pic->linesize[0]; + } + } else { + + pic->key_frame = 0; + pic->pict_type = AV_PICTURE_TYPE_P; + + for (i = 0; i < avctx->height; i++) { + + zstream->next_out = dst; + zstream->avail_out = avctx->width << 1; + + zret = inflate(zstream, Z_SYNC_FLUSH); + + if (zret != Z_OK && zret != Z_STREAM_END) { + av_log(avctx, AV_LOG_ERROR, "Inflate failed with return code: %d\n", zret); + return AVERROR(EINVAL); + } + + for (j = 0; j < avctx->width << 1; j++) + dst[j] += prev[j] & -!dst[j]; + + prev += prev_pic->linesize[0]; + dst += pic->linesize[0]; + } + } + + /* Release the previous buffer if need be */ + if (prev_pic->data[0]) + avctx->release_buffer(avctx, prev_pic); + + /* Store the previouse frame for use later */ + *prev_pic = *pic; + + *data_size = sizeof(AVFrame); + *(AVFrame *)data = *pic; + + return avpkt->size; +} + +static av_cold int zerocodec_decode_close(AVCodecContext *avctx) +{ + ZeroCodecContext *zc = avctx->priv_data; + AVFrame *prev_pic = &zc->previous_frame; + + inflateEnd(&zc->zstream); + + /* Release last frame */ + if (prev_pic->data[0]) + avctx->release_buffer(avctx, prev_pic); + + av_freep(&avctx->coded_frame); + + return 0; +} + +static av_cold int zerocodec_decode_init(AVCodecContext *avctx) +{ + ZeroCodecContext *zc = avctx->priv_data; + z_stream *zstream = &zc->zstream; + int zret; + + avctx->pix_fmt = PIX_FMT_UYVY422; + avctx->bits_per_raw_sample = 8; + + zc->size = avpicture_get_size(avctx->pix_fmt, + avctx->width, avctx->height); + + zstream->zalloc = Z_NULL; + zstream->zfree = Z_NULL; + zstream->opaque = Z_NULL; + + zret = inflateInit(zstream); + + if (zret != Z_OK) { + av_log(avctx, AV_LOG_ERROR, "Could not initialize inflate: %d\n", zret); + return AVERROR(ENOMEM); + } + + avctx->coded_frame = avcodec_alloc_frame(); + + if (!avctx->coded_frame) { + av_log(avctx, AV_LOG_ERROR, "Could not allocate frame buffer.\n"); + zerocodec_decode_close(avctx); + return AVERROR(ENOMEM); + } + + return 0; +} + +AVCodec ff_zerocodec_decoder = { + .type = AVMEDIA_TYPE_VIDEO, + .name = "zerocodec", + .id = CODEC_ID_ZEROCODEC, + .priv_data_size = sizeof(ZeroCodecContext), + .init = zerocodec_decode_init, + .decode = zerocodec_decode_frame, + .close = zerocodec_decode_close, + .capabilities = CODEC_CAP_DR1, + .long_name = NULL_IF_CONFIG_SMALL("ZeroCodec Lossless Video"), +}; diff --git a/libavformat/riff.c b/libavformat/riff.c index 774a02f82d..650bea6f72 100644 --- a/libavformat/riff.c +++ b/libavformat/riff.c @@ -298,6 +298,7 @@ const AVCodecTag ff_codec_bmp_tags[] = { { CODEC_ID_VBLE, MKTAG('V', 'B', 'L', 'E') }, { CODEC_ID_ESCAPE130, MKTAG('E', '1', '3', '0') }, { CODEC_ID_DXTORY, MKTAG('x', 't', 'o', 'r') }, + { CODEC_ID_ZEROCODEC, MKTAG('Z', 'E', 'C', 'O') }, { CODEC_ID_Y41P, MKTAG('Y', '4', '1', 'P') }, { CODEC_ID_NONE, 0 } };