libavcodec/xl.c
ab711b3c
 /*
  * Miro VideoXL codec
  * Copyright (c) 2004 Konstantin Shishkov
  *
b78e7197
  * This file is part of FFmpeg.
  *
  * FFmpeg is free software; you can redistribute it and/or
ab711b3c
  * modify it under the terms of the GNU Lesser General Public
  * License as published by the Free Software Foundation; either
b78e7197
  * version 2.1 of the License, or (at your option) any later version.
ab711b3c
  *
b78e7197
  * FFmpeg is distributed in the hope that it will be useful,
ab711b3c
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  * Lesser General Public License for more details.
  *
  * You should have received a copy of the GNU Lesser General Public
b78e7197
  * License along with FFmpeg; if not, write to the Free Software
5509bffa
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
ab711b3c
  */
115329f1
 
ab711b3c
 /**
ba87f080
  * @file
ab711b3c
  * Miro VideoXL codec.
  */
115329f1
 
1d9c2dc8
 #include "libavutil/common.h"
6a5d31ac
 #include "libavutil/intreadwrite.h"
ab711b3c
 #include "avcodec.h"
594d4d5d
 #include "internal.h"
ab711b3c
 
 typedef struct VideoXLContext{
     AVCodecContext *avctx;
     AVFrame pic;
 } VideoXLContext;
 
8e981daf
 static const int xl_table[32] = {
ab711b3c
    0,   1,   2,   3,   4,   5,   6,   7,
    8,   9,  12,  15,  20,  25,  34,  46,
   64,  82,  94, 103, 108, 113, 116, 119,
51bcf8ac
  120, 121, 122, 123, 124, 125, 126, 127
 };
ab711b3c
 
115329f1
 static int decode_frame(AVCodecContext *avctx,
df9b9567
                         void *data, int *got_frame,
7a00bbad
                         AVPacket *avpkt)
ab711b3c
 {
7a00bbad
     const uint8_t *buf = avpkt->data;
     int buf_size = avpkt->size;
ab711b3c
     VideoXLContext * const a = avctx->priv_data;
562b6c74
     AVFrame * const p = &a->pic;
ab711b3c
     uint8_t *Y, *U, *V;
24e5cb48
     int i, j, ret;
ab711b3c
     int stride;
     uint32_t val;
55b557ec
     int y0, y1, y2, y3 = 0, c0 = 0, c1 = 0;
ab711b3c
 
94b42da6
     if (avctx->width & 3) {
         av_log(avctx, AV_LOG_ERROR, "width is not a multiple of 4\n");
         return AVERROR_INVALIDDATA;
     }
 
8c59e0c3
     if (buf_size < avctx->width * avctx->height) {
         av_log(avctx, AV_LOG_ERROR, "Packet is too small\n");
         return AVERROR_INVALIDDATA;
     }
 
51bcf8ac
     if (p->data[0])
ab711b3c
         avctx->release_buffer(avctx, p);
 
     p->reference = 0;
874c5b02
     if ((ret = ff_get_buffer(avctx, p)) < 0) {
ab711b3c
         av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
24e5cb48
         return ret;
ab711b3c
     }
51bcf8ac
     p->pict_type = AV_PICTURE_TYPE_I;
     p->key_frame = 1;
ab711b3c
 
     Y = a->pic.data[0];
     U = a->pic.data[1];
     V = a->pic.data[2];
115329f1
 
ab711b3c
     stride = avctx->width - 4;
00aad121
 
ab711b3c
     for (i = 0; i < avctx->height; i++) {
         /* lines are stored in reversed order */
         buf += stride;
115329f1
 
ab711b3c
         for (j = 0; j < avctx->width; j += 4) {
             /* value is stored in LE dword with word swapped */
fead30d4
             val = AV_RL32(buf);
ab711b3c
             buf -= 4;
             val = ((val >> 16) & 0xFFFF) | ((val & 0xFFFF) << 16);
115329f1
 
ab711b3c
             if(!j)
                 y0 = (val & 0x1F) << 2;
             else
                 y0 = y3 + xl_table[val & 0x1F];
             val >>= 5;
             y1 = y0 + xl_table[val & 0x1F];
             val >>= 5;
             y2 = y1 + xl_table[val & 0x1F];
             val >>= 6; /* align to word */
             y3 = y2 + xl_table[val & 0x1F];
             val >>= 5;
             if(!j)
                 c0 = (val & 0x1F) << 2;
             else
                 c0 += xl_table[val & 0x1F];
             val >>= 5;
             if(!j)
                 c1 = (val & 0x1F) << 2;
             else
                 c1 += xl_table[val & 0x1F];
115329f1
 
ab711b3c
             Y[j + 0] = y0 << 1;
             Y[j + 1] = y1 << 1;
             Y[j + 2] = y2 << 1;
             Y[j + 3] = y3 << 1;
115329f1
 
ab711b3c
             U[j >> 2] = c0 << 1;
             V[j >> 2] = c1 << 1;
         }
115329f1
 
ab711b3c
         buf += avctx->width + 4;
         Y += a->pic.linesize[0];
         U += a->pic.linesize[1];
         V += a->pic.linesize[2];
     }
 
df9b9567
     *got_frame = 1;
ab711b3c
     *(AVFrame*)data = a->pic;
115329f1
 
ab711b3c
     return buf_size;
 }
 
51bcf8ac
 static av_cold int decode_init(AVCodecContext *avctx)
 {
01042d41
     VideoXLContext * const a = avctx->priv_data;
ab711b3c
 
01042d41
     avcodec_get_frame_defaults(&a->pic);
51bcf8ac
     avctx->pix_fmt = AV_PIX_FMT_YUV411P;
ab711b3c
 
     return 0;
 }
 
51bcf8ac
 static av_cold int decode_end(AVCodecContext *avctx)
 {
6d924b5a
     VideoXLContext * const a = avctx->priv_data;
     AVFrame *pic = &a->pic;
 
     if (pic->data[0])
         avctx->release_buffer(avctx, pic);
 
     return 0;
 }
 
e7e2df27
 AVCodec ff_xl_decoder = {
ec6402b7
     .name           = "xl",
     .type           = AVMEDIA_TYPE_VIDEO,
36ef5369
     .id             = AV_CODEC_ID_VIXL,
ec6402b7
     .priv_data_size = sizeof(VideoXLContext),
     .init           = decode_init,
     .close          = decode_end,
     .decode         = decode_frame,
     .capabilities   = CODEC_CAP_DR1,
00c3b67b
     .long_name      = NULL_IF_CONFIG_SMALL("Miro VideoXL"),
ab711b3c
 };