yading@10: /* yading@10: * ZeroCodec Decoder yading@10: * yading@10: * Copyright (c) 2012, Derek Buitenhuis yading@10: * yading@10: * Permission to use, copy, modify, and/or distribute this software for any yading@10: * purpose with or without fee is hereby granted, provided that the above yading@10: * copyright notice and this permission notice appear in all copies. yading@10: * yading@10: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES yading@10: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF yading@10: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR yading@10: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES yading@10: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN yading@10: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF yading@10: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. yading@10: */ yading@10: yading@10: #include yading@10: yading@10: #include "avcodec.h" yading@10: #include "internal.h" yading@10: #include "libavutil/common.h" yading@10: yading@10: typedef struct { yading@10: AVFrame previous_frame; yading@10: z_stream zstream; yading@10: } ZeroCodecContext; yading@10: yading@10: static int zerocodec_decode_frame(AVCodecContext *avctx, void *data, yading@10: int *got_frame, AVPacket *avpkt) yading@10: { yading@10: ZeroCodecContext *zc = avctx->priv_data; yading@10: AVFrame *pic = data; yading@10: AVFrame *prev_pic = &zc->previous_frame; yading@10: z_stream *zstream = &zc->zstream; yading@10: uint8_t *prev = prev_pic->data[0]; yading@10: uint8_t *dst; yading@10: int i, j, zret, ret; yading@10: yading@10: if (avpkt->flags & AV_PKT_FLAG_KEY) { yading@10: pic->key_frame = 1; yading@10: pic->pict_type = AV_PICTURE_TYPE_I; yading@10: } else { yading@10: if (!prev) { yading@10: av_log(avctx, AV_LOG_ERROR, "Missing reference frame.\n"); yading@10: return AVERROR_INVALIDDATA; yading@10: } yading@10: yading@10: prev += (avctx->height - 1) * prev_pic->linesize[0]; yading@10: yading@10: pic->key_frame = 0; yading@10: pic->pict_type = AV_PICTURE_TYPE_P; yading@10: } yading@10: yading@10: zret = inflateReset(zstream); yading@10: if (zret != Z_OK) { yading@10: av_log(avctx, AV_LOG_ERROR, "Could not reset inflate: %d.\n", zret); yading@10: return AVERROR_INVALIDDATA; yading@10: } yading@10: yading@10: if ((ret = ff_get_buffer(avctx, pic, AV_GET_BUFFER_FLAG_REF)) < 0) yading@10: return ret; yading@10: yading@10: zstream->next_in = avpkt->data; yading@10: zstream->avail_in = avpkt->size; yading@10: yading@10: dst = pic->data[0] + (avctx->height - 1) * pic->linesize[0]; yading@10: yading@10: /** yading@10: * ZeroCodec has very simple interframe compression. If a value yading@10: * is the same as the previous frame, set it to 0. yading@10: */ yading@10: yading@10: for (i = 0; i < avctx->height; i++) { yading@10: zstream->next_out = dst; yading@10: zstream->avail_out = avctx->width << 1; yading@10: yading@10: zret = inflate(zstream, Z_SYNC_FLUSH); yading@10: if (zret != Z_OK && zret != Z_STREAM_END) { yading@10: av_log(avctx, AV_LOG_ERROR, yading@10: "Inflate failed with return code: %d.\n", zret); yading@10: return AVERROR_INVALIDDATA; yading@10: } yading@10: yading@10: if (!(avpkt->flags & AV_PKT_FLAG_KEY)) yading@10: for (j = 0; j < avctx->width << 1; j++) yading@10: dst[j] += prev[j] & -!dst[j]; yading@10: yading@10: prev -= prev_pic->linesize[0]; yading@10: dst -= pic->linesize[0]; yading@10: } yading@10: yading@10: av_frame_unref(&zc->previous_frame); yading@10: if ((ret = av_frame_ref(&zc->previous_frame, pic)) < 0) yading@10: return ret; yading@10: yading@10: *got_frame = 1; yading@10: yading@10: return avpkt->size; yading@10: } yading@10: yading@10: static av_cold int zerocodec_decode_close(AVCodecContext *avctx) yading@10: { yading@10: ZeroCodecContext *zc = avctx->priv_data; yading@10: yading@10: av_frame_unref(&zc->previous_frame); yading@10: yading@10: inflateEnd(&zc->zstream); yading@10: yading@10: return 0; yading@10: } yading@10: yading@10: static av_cold int zerocodec_decode_init(AVCodecContext *avctx) yading@10: { yading@10: ZeroCodecContext *zc = avctx->priv_data; yading@10: z_stream *zstream = &zc->zstream; yading@10: int zret; yading@10: yading@10: avctx->pix_fmt = AV_PIX_FMT_UYVY422; yading@10: avctx->bits_per_raw_sample = 8; yading@10: yading@10: zstream->zalloc = Z_NULL; yading@10: zstream->zfree = Z_NULL; yading@10: zstream->opaque = Z_NULL; yading@10: yading@10: zret = inflateInit(zstream); yading@10: if (zret != Z_OK) { yading@10: av_log(avctx, AV_LOG_ERROR, "Could not initialize inflate: %d.\n", zret); yading@10: return AVERROR(ENOMEM); yading@10: } yading@10: yading@10: return 0; yading@10: } yading@10: yading@10: AVCodec ff_zerocodec_decoder = { yading@10: .type = AVMEDIA_TYPE_VIDEO, yading@10: .name = "zerocodec", yading@10: .id = AV_CODEC_ID_ZEROCODEC, yading@10: .priv_data_size = sizeof(ZeroCodecContext), yading@10: .init = zerocodec_decode_init, yading@10: .decode = zerocodec_decode_frame, yading@10: .close = zerocodec_decode_close, yading@10: .capabilities = CODEC_CAP_DR1, yading@10: .long_name = NULL_IF_CONFIG_SMALL("ZeroCodec Lossless Video"), yading@10: };