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