libavcodec/msrle.c
2fdf638b
 /*
5ea20630
  * Microsoft RLE video decoder
6dfa70f2
  * Copyright (c) 2003 The FFmpeg Project
2fdf638b
  *
b78e7197
  * This file is part of FFmpeg.
  *
  * FFmpeg is free software; you can redistribute it and/or
2fdf638b
  * 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.
2fdf638b
  *
b78e7197
  * FFmpeg is distributed in the hope that it will be useful,
2fdf638b
  * 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
2fdf638b
  */
 
 /**
ba87f080
  * @file
5ea20630
  * MS RLE video decoder by Mike Melanson (melanson@pcisys.net)
2fdf638b
  * For more information about the MS RLE format, visit:
  *   http://www.pcisys.net/~melanson/codecs/
  *
  * The MS RLE decoder outputs PAL8 colorspace data.
  */
 
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 
 #include "avcodec.h"
759001c5
 #include "internal.h"
44aa9771
 #include "msrledec.h"
c919e1ca
 #include "libavutil/imgutils.h"
2fdf638b
 
 typedef struct MsrleContext {
     AVCodecContext *avctx;
c5dfb903
     AVFrame *frame;
2fdf638b
 
992f71e9
     GetByteContext gb;
7993df65
     const unsigned char *buf;
2fdf638b
     int size;
 
2d8591c2
     uint32_t pal[256];
2fdf638b
 } MsrleContext;
 
98a6fff9
 static av_cold int msrle_decode_init(AVCodecContext *avctx)
2fdf638b
 {
e4141433
     MsrleContext *s = avctx->priv_data;
21eafa18
     int i;
2fdf638b
 
     s->avctx = avctx;
 
54bbe3e2
     switch (avctx->bits_per_coded_sample) {
0b8002fd
     case 1:
ac627b3d
         avctx->pix_fmt = AV_PIX_FMT_MONOWHITE;
0b8002fd
         break;
2ed16f30
     case 4:
     case 8:
716d413c
         avctx->pix_fmt = AV_PIX_FMT_PAL8;
2ed16f30
         break;
     case 24:
716d413c
         avctx->pix_fmt = AV_PIX_FMT_BGR24;
2ed16f30
         break;
     default:
         av_log(avctx, AV_LOG_ERROR, "unsupported bits per sample\n");
9e676490
         return AVERROR_INVALIDDATA;
2ed16f30
     }
 
c5dfb903
     s->frame = av_frame_alloc();
     if (!s->frame)
         return AVERROR(ENOMEM);
2fdf638b
 
c98d3056
     if (avctx->extradata_size >= 4)
         for (i = 0; i < FFMIN(avctx->extradata_size, AVPALETTE_SIZE)/4; i++)
2fed05f5
             s->pal[i] = 0xFFU<<24 | AV_RL32(avctx->extradata+4*i);
21eafa18
 
2fdf638b
     return 0;
 }
 
 static int msrle_decode_frame(AVCodecContext *avctx,
df9b9567
                               void *data, int *got_frame,
7a00bbad
                               AVPacket *avpkt)
2fdf638b
 {
7a00bbad
     const uint8_t *buf = avpkt->data;
     int buf_size = avpkt->size;
e4141433
     MsrleContext *s = avctx->priv_data;
2ed16f30
     int istride = FFALIGN(avctx->width*avctx->bits_per_coded_sample, 32) / 8;
9e676490
     int ret;
2fdf638b
 
     s->buf = buf;
     s->size = buf_size;
 
9f890a16
     if ((ret = ff_reget_buffer(avctx, s->frame)) < 0)
9e676490
         return ret;
2fdf638b
 
445ee35e
     if (avctx->bits_per_coded_sample > 1 && avctx->bits_per_coded_sample <= 8) {
f39522b6
         int size;
         const uint8_t *pal = av_packet_get_side_data(avpkt, AV_PKT_DATA_PALETTE, &size);
2d8591c2
 
f39522b6
         if (pal && size == AVPALETTE_SIZE) {
c5dfb903
             s->frame->palette_has_changed = 1;
2d8591c2
             memcpy(s->pal, pal, AVPALETTE_SIZE);
f39522b6
         } else if (pal) {
             av_log(avctx, AV_LOG_ERROR, "Palette size %d is wrong\n", size);
30853173
         }
58825a18
         /* make the palette available */
c5dfb903
         memcpy(s->frame->data[1], s->pal, AVPALETTE_SIZE);
a7e56229
     }
2fdf638b
 
2ed16f30
     /* FIXME how to correctly detect RLE ??? */
     if (avctx->height * istride == avpkt->size) { /* assume uncompressed */
c919e1ca
         int linesize = av_image_get_linesize(avctx->pix_fmt, avctx->width, 0);
c5dfb903
         uint8_t *ptr = s->frame->data[0];
2ed16f30
         uint8_t *buf = avpkt->data + (avctx->height-1)*istride;
         int i, j;
 
754f8466
         if (linesize < 0)
             return linesize;
 
2ed16f30
         for (i = 0; i < avctx->height; i++) {
             if (avctx->bits_per_coded_sample == 4) {
                 for (j = 0; j < avctx->width - 1; j += 2) {
                     ptr[j+0] = buf[j>>1] >> 4;
                     ptr[j+1] = buf[j>>1] & 0xF;
                 }
                 if (avctx->width & 1)
                     ptr[j+0] = buf[j>>1] >> 4;
             } else {
                 memcpy(ptr, buf, linesize);
             }
             buf -= istride;
c5dfb903
             ptr += s->frame->linesize[0];
2ed16f30
         }
     } else {
992f71e9
         bytestream2_init(&s->gb, buf, buf_size);
c5dfb903
         ff_msrle_decode(avctx, (AVPicture*)s->frame, avctx->bits_per_coded_sample, &s->gb);
2ed16f30
     }
44aa9771
 
c5dfb903
     if ((ret = av_frame_ref(data, s->frame)) < 0)
759001c5
         return ret;
 
df9b9567
     *got_frame      = 1;
2fdf638b
 
     /* report that the buffer was completely consumed */
     return buf_size;
 }
 
98a6fff9
 static av_cold int msrle_decode_end(AVCodecContext *avctx)
2fdf638b
 {
e4141433
     MsrleContext *s = avctx->priv_data;
2fdf638b
 
     /* release the last frame */
c5dfb903
     av_frame_free(&s->frame);
2fdf638b
 
     return 0;
 }
 
e7e2df27
 AVCodec ff_msrle_decoder = {
ec6402b7
     .name           = "msrle",
b2bed932
     .long_name      = NULL_IF_CONFIG_SMALL("Microsoft RLE"),
ec6402b7
     .type           = AVMEDIA_TYPE_VIDEO,
36ef5369
     .id             = AV_CODEC_ID_MSRLE,
ec6402b7
     .priv_data_size = sizeof(MsrleContext),
     .init           = msrle_decode_init,
     .close          = msrle_decode_end,
     .decode         = msrle_decode_frame,
def97856
     .capabilities   = AV_CODEC_CAP_DR1,
2fdf638b
 };