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 "codec_internal.h" 23#include "internal.h" 24#include "zlib_wrapper.h" 25#include "libavutil/common.h" 26 27typedef struct ZeroCodecContext { 28 AVFrame *previous_frame; 29 FFZStream zstream; 30} ZeroCodecContext; 31 32static int zerocodec_decode_frame(AVCodecContext *avctx, AVFrame *pic, 33 int *got_frame, AVPacket *avpkt) 34{ 35 ZeroCodecContext *zc = avctx->priv_data; 36 AVFrame *prev_pic = zc->previous_frame; 37 z_stream *const zstream = &zc->zstream.zstream; 38 uint8_t *prev = prev_pic->data[0]; 39 uint8_t *dst; 40 int i, j, zret, ret; 41 42 if (avpkt->flags & AV_PKT_FLAG_KEY) { 43 pic->key_frame = 1; 44 pic->pict_type = AV_PICTURE_TYPE_I; 45 } else { 46 if (!prev) { 47 av_log(avctx, AV_LOG_ERROR, "Missing reference frame.\n"); 48 return AVERROR_INVALIDDATA; 49 } 50 51 prev += (avctx->height - 1) * prev_pic->linesize[0]; 52 53 pic->key_frame = 0; 54 pic->pict_type = AV_PICTURE_TYPE_P; 55 } 56 57 zret = inflateReset(zstream); 58 if (zret != Z_OK) { 59 av_log(avctx, AV_LOG_ERROR, "Could not reset inflate: %d.\n", zret); 60 return AVERROR_INVALIDDATA; 61 } 62 63 if ((ret = ff_get_buffer(avctx, pic, AV_GET_BUFFER_FLAG_REF)) < 0) 64 return ret; 65 66 zstream->next_in = avpkt->data; 67 zstream->avail_in = avpkt->size; 68 69 dst = pic->data[0] + (avctx->height - 1) * pic->linesize[0]; 70 71 /** 72 * ZeroCodec has very simple interframe compression. If a value 73 * is the same as the previous frame, set it to 0. 74 */ 75 76 for (i = 0; i < avctx->height; i++) { 77 zstream->next_out = dst; 78 zstream->avail_out = avctx->width << 1; 79 80 zret = inflate(zstream, Z_SYNC_FLUSH); 81 if (zret != Z_OK && zret != Z_STREAM_END) { 82 av_log(avctx, AV_LOG_ERROR, 83 "Inflate failed with return code: %d.\n", zret); 84 return AVERROR_INVALIDDATA; 85 } 86 87 if (!(avpkt->flags & AV_PKT_FLAG_KEY)) 88 for (j = 0; j < avctx->width << 1; j++) 89 dst[j] += prev[j] & -!dst[j]; 90 91 prev -= prev_pic->linesize[0]; 92 dst -= pic->linesize[0]; 93 } 94 95 av_frame_unref(zc->previous_frame); 96 if ((ret = av_frame_ref(zc->previous_frame, pic)) < 0) 97 return ret; 98 99 *got_frame = 1; 100 101 return avpkt->size; 102} 103 104static av_cold int zerocodec_decode_close(AVCodecContext *avctx) 105{ 106 ZeroCodecContext *zc = avctx->priv_data; 107 108 av_frame_free(&zc->previous_frame); 109 110 ff_inflate_end(&zc->zstream); 111 112 return 0; 113} 114 115static av_cold int zerocodec_decode_init(AVCodecContext *avctx) 116{ 117 ZeroCodecContext *zc = avctx->priv_data; 118 119 avctx->pix_fmt = AV_PIX_FMT_UYVY422; 120 avctx->bits_per_raw_sample = 8; 121 122 zc->previous_frame = av_frame_alloc(); 123 if (!zc->previous_frame) 124 return AVERROR(ENOMEM); 125 126 return ff_inflate_init(&zc->zstream, avctx); 127} 128 129static void zerocodec_decode_flush(AVCodecContext *avctx) 130{ 131 ZeroCodecContext *zc = avctx->priv_data; 132 133 av_frame_unref(zc->previous_frame); 134} 135 136const FFCodec ff_zerocodec_decoder = { 137 .p.type = AVMEDIA_TYPE_VIDEO, 138 .p.name = "zerocodec", 139 .p.long_name = NULL_IF_CONFIG_SMALL("ZeroCodec Lossless Video"), 140 .p.id = AV_CODEC_ID_ZEROCODEC, 141 .priv_data_size = sizeof(ZeroCodecContext), 142 .init = zerocodec_decode_init, 143 FF_CODEC_DECODE_CB(zerocodec_decode_frame), 144 .flush = zerocodec_decode_flush, 145 .close = zerocodec_decode_close, 146 .p.capabilities = AV_CODEC_CAP_DR1, 147 .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE | 148 FF_CODEC_CAP_INIT_CLEANUP, 149}; 150