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
 
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;
e13a9293
     int buf_size       = avpkt->size;
     AVFrame *const p   = data;
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
 
3ca1dd25
     if (avctx->width % 4) {
94b42da6
         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;
     }
 
1ec94b0f
     if ((ret = ff_get_buffer(avctx, p, 0)) < 0)
24e5cb48
         return ret;
51bcf8ac
     p->pict_type = AV_PICTURE_TYPE_I;
     p->key_frame = 1;
ab711b3c
 
759001c5
     Y = p->data[0];
     U = p->data[1];
     V = p->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 */
e13a9293
             val  = AV_RL32(buf);
ab711b3c
             buf -= 4;
e13a9293
             val  = ((val >> 16) & 0xFFFF) | ((val & 0xFFFF) << 16);
115329f1
 
e13a9293
             if (!j)
ab711b3c
                 y0 = (val & 0x1F) << 2;
             else
                 y0 = y3 + xl_table[val & 0x1F];
             val >>= 5;
e13a9293
             y1    = y0 + xl_table[val & 0x1F];
ab711b3c
             val >>= 5;
e13a9293
             y2    = y1 + xl_table[val & 0x1F];
ab711b3c
             val >>= 6; /* align to word */
e13a9293
             y3    = y2 + xl_table[val & 0x1F];
ab711b3c
             val >>= 5;
e13a9293
             if (!j)
ab711b3c
                 c0 = (val & 0x1F) << 2;
             else
                 c0 += xl_table[val & 0x1F];
             val >>= 5;
e13a9293
             if (!j)
ab711b3c
                 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;
e13a9293
         Y   += p->linesize[0];
         U   += p->linesize[1];
         V   += p->linesize[2];
ab711b3c
     }
 
df9b9567
     *got_frame = 1;
115329f1
 
ab711b3c
     return buf_size;
 }
 
51bcf8ac
 static av_cold int decode_init(AVCodecContext *avctx)
 {
     avctx->pix_fmt = AV_PIX_FMT_YUV411P;
ab711b3c
 
     return 0;
 }
 
e7e2df27
 AVCodec ff_xl_decoder = {
e13a9293
     .name         = "xl",
b2bed932
     .long_name    = NULL_IF_CONFIG_SMALL("Miro VideoXL"),
e13a9293
     .type         = AVMEDIA_TYPE_VIDEO,
     .id           = AV_CODEC_ID_VIXL,
     .init         = decode_init,
     .decode       = decode_frame,
def97856
     .capabilities = AV_CODEC_CAP_DR1,
ab711b3c
 };