Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | RSS feed

  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.  
  25. typedef struct {
  26.     AVFrame  previous_frame;
  27.     z_stream zstream;
  28. } ZeroCodecContext;
  29.  
  30. static 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.  
  103. static av_cold int zerocodec_decode_close(AVCodecContext *avctx)
  104. {
  105.     ZeroCodecContext *zc = avctx->priv_data;
  106.  
  107.     av_frame_unref(&zc->previous_frame);
  108.  
  109.     inflateEnd(&zc->zstream);
  110.  
  111.     return 0;
  112. }
  113.  
  114. static 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.     return 0;
  134. }
  135.  
  136. AVCodec ff_zerocodec_decoder = {
  137.     .type           = AVMEDIA_TYPE_VIDEO,
  138.     .name           = "zerocodec",
  139.     .long_name      = NULL_IF_CONFIG_SMALL("ZeroCodec Lossless Video"),
  140.     .id             = AV_CODEC_ID_ZEROCODEC,
  141.     .priv_data_size = sizeof(ZeroCodecContext),
  142.     .init           = zerocodec_decode_init,
  143.     .decode         = zerocodec_decode_frame,
  144.     .close          = zerocodec_decode_close,
  145.     .capabilities   = CODEC_CAP_DR1,
  146. };
  147.