diff --git a/Changelog b/Changelog index 4a23d22665..493b323bdb 100644 --- a/Changelog +++ b/Changelog @@ -14,6 +14,7 @@ version : - WMA Lossless decoder - XBM encoder - RealAudio Lossless decoder +- ZeroCodec decoder version 0.8: diff --git a/configure b/configure index 29fb432fb9..eba9cfea19 100755 --- a/configure +++ b/configure @@ -1399,6 +1399,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 bbadb2150e..0c14003dee 100644 --- a/doc/general.texi +++ b/doc/general.texi @@ -329,6 +329,7 @@ library: @tab Microsoft audio container used by XAudio 2. @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 9d4266e355..0c459f690f 100644 --- a/libavcodec/Makefile +++ b/libavcodec/Makefile @@ -448,6 +448,7 @@ OBJS-$(CONFIG_XSUB_ENCODER) += xsubenc.o OBJS-$(CONFIG_XWD_DECODER) += xwddec.o OBJS-$(CONFIG_XWD_ENCODER) += xwdenc.o OBJS-$(CONFIG_YOP_DECODER) += yop.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 f7fc7ce015..60b3e08d17 100644 --- a/libavcodec/allcodecs.c +++ b/libavcodec/allcodecs.c @@ -234,6 +234,7 @@ void avcodec_register_all(void) REGISTER_DECODER (XL, xl); REGISTER_ENCDEC (XWD, xwd); REGISTER_DECODER (YOP, yop); + REGISTER_DECODER (ZEROCODEC, zerocodec); REGISTER_ENCDEC (ZLIB, zlib); REGISTER_ENCDEC (ZMBV, zmbv); diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h index f09ee363ab..3af4df1010 100644 --- a/libavcodec/avcodec.h +++ b/libavcodec/avcodec.h @@ -246,6 +246,7 @@ enum CodecID { CODEC_ID_XWD, CODEC_ID_CDXL, CODEC_ID_XBM, + CODEC_ID_ZEROCODEC, /* various PCM "codecs" */ CODEC_ID_FIRST_AUDIO = 0x10000, ///< A dummy id pointing at the start of audio codecs diff --git a/libavcodec/version.h b/libavcodec/version.h index 39ecd6894b..9e42a27ebb 100644 --- a/libavcodec/version.h +++ b/libavcodec/version.h @@ -21,7 +21,7 @@ #define AVCODEC_VERSION_H #define LIBAVCODEC_VERSION_MAJOR 54 -#define LIBAVCODEC_VERSION_MINOR 10 +#define LIBAVCODEC_VERSION_MINOR 11 #define LIBAVCODEC_VERSION_MICRO 0 #define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \ diff --git a/libavcodec/zerocodec.c b/libavcodec/zerocodec.c new file mode 100644 index 0000000000..3bf1fd93f4 --- /dev/null +++ b/libavcodec/zerocodec.c @@ -0,0 +1,183 @@ +/* + * ZeroCodec Decoder + * + * Copyright (c) 2012, Derek Buitenhuis + * + * 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 5b2fd80893..2b6165e990 100644 --- a/libavformat/riff.c +++ b/libavformat/riff.c @@ -283,6 +283,7 @@ const AVCodecTag ff_codec_bmp_tags[] = { { CODEC_ID_UTVIDEO, MKTAG('U', 'L', 'Y', '2') }, { CODEC_ID_VBLE, MKTAG('V', 'B', 'L', 'E') }, { CODEC_ID_DXTORY, MKTAG('x', 't', 'o', 'r') }, + { CODEC_ID_ZEROCODEC, MKTAG('Z', 'E', 'C', 'O') }, { CODEC_ID_NONE, 0 } };