1/* 2 * ZeroCodec Decoder 3 * 4 * Copyright (c) 2012, Derek Buitenhuis 5 * 6 * Permission to use, copy, modify, and/or distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19#include <zlib.h> 20 21#include "avcodec.h" 22#include "internal.h" 23#include "libavutil/common.h" 24 25typedef struct { 26 AVFrame *previous_frame; 27 z_stream zstream; 28} ZeroCodecContext; 29 30static int zerocodec_decode_frame(AVCodecContext *avctx, void *data, 31 int *got_frame, AVPacket *avpkt) 32{ 33 ZeroCodecContext *zc = avctx->priv_data; 34 AVFrame *pic = data; 35 AVFrame *prev_pic = zc->previous_frame; 36 z_stream *zstream = &zc->zstream; 37 uint8_t *prev = prev_pic->data[0]; 38 uint8_t *dst; 39 int i, j, zret, ret; 40 41 if (avpkt->flags & AV_PKT_FLAG_KEY) { 42 pic->key_frame = 1; 43 pic->pict_type = AV_PICTURE_TYPE_I; 44 } else { 45 if (!prev) { 46 av_log(avctx, AV_LOG_ERROR, "Missing reference frame.\n"); 47 return AVERROR_INVALIDDATA; 48 } 49 50 prev += (avctx->height - 1) * prev_pic->linesize[0]; 51 52 pic->key_frame = 0; 53 pic->pict_type = AV_PICTURE_TYPE_P; 54 } 55 56 zret = inflateReset(zstream); 57 if (zret != Z_OK) { 58 av_log(avctx, AV_LOG_ERROR, "Could not reset inflate: %d.\n", zret); 59 return AVERROR_INVALIDDATA; 60 } 61 62 if ((ret = ff_get_buffer(avctx, pic, AV_GET_BUFFER_FLAG_REF)) < 0) 63 return ret; 64 65 zstream->next_in = avpkt->data; 66 zstream->avail_in = avpkt->size; 67 68 dst = pic->data[0] + (avctx->height - 1) * pic->linesize[0]; 69 70 /** 71 * ZeroCodec has very simple interframe compression. If a value 72 * is the same as the previous frame, set it to 0. 73 */ 74 75 for (i = 0; i < avctx->height; i++) { 76 zstream->next_out = dst; 77 zstream->avail_out = avctx->width << 1; 78 79 zret = inflate(zstream, Z_SYNC_FLUSH); 80 if (zret != Z_OK && zret != Z_STREAM_END) { 81 av_log(avctx, AV_LOG_ERROR, 82 "Inflate failed with return code: %d.\n", zret); 83 return AVERROR_INVALIDDATA; 84 } 85 86 if (!(avpkt->flags & AV_PKT_FLAG_KEY)) 87 for (j = 0; j < avctx->width << 1; j++) 88 dst[j] += prev[j] & -!dst[j]; 89 90 prev -= prev_pic->linesize[0]; 91 dst -= pic->linesize[0]; 92 } 93 94 av_frame_unref(zc->previous_frame); 95 if ((ret = av_frame_ref(zc->previous_frame, pic)) < 0) 96 return ret; 97 98 *got_frame = 1; 99 100 return avpkt->size; 101} 102 103static av_cold int zerocodec_decode_close(AVCodecContext *avctx) 104{ 105 ZeroCodecContext *zc = avctx->priv_data; 106 107 av_frame_free(&zc->previous_frame); 108 109 inflateEnd(&zc->zstream); 110 111 return 0; 112} 113 114static av_cold int zerocodec_decode_init(AVCodecContext *avctx) 115{ 116 ZeroCodecContext *zc = avctx->priv_data; 117 z_stream *zstream = &zc->zstream; 118 int zret; 119 120 avctx->pix_fmt = AV_PIX_FMT_UYVY422; 121 avctx->bits_per_raw_sample = 8; 122 123 zstream->zalloc = Z_NULL; 124 zstream->zfree = Z_NULL; 125 zstream->opaque = Z_NULL; 126 127 zret = inflateInit(zstream); 128 if (zret != Z_OK) { 129 av_log(avctx, AV_LOG_ERROR, "Could not initialize inflate: %d.\n", zret); 130 return AVERROR(ENOMEM); 131 } 132 133 zc->previous_frame = av_frame_alloc(); 134 if (!zc->previous_frame) { 135 zerocodec_decode_close(avctx); 136 return AVERROR(ENOMEM); 137 } 138 139 return 0; 140} 141 142AVCodec ff_zerocodec_decoder = { 143 .type = AVMEDIA_TYPE_VIDEO, 144 .name = "zerocodec", 145 .long_name = NULL_IF_CONFIG_SMALL("ZeroCodec Lossless Video"), 146 .id = AV_CODEC_ID_ZEROCODEC, 147 .priv_data_size = sizeof(ZeroCodecContext), 148 .init = zerocodec_decode_init, 149 .decode = zerocodec_decode_frame, 150 .close = zerocodec_decode_close, 151 .capabilities = CODEC_CAP_DR1, 152}; 153