1/* 2 * Microsoft RLE video decoder 3 * Copyright (C) 2003 The FFmpeg project 4 * 5 * This file is part of FFmpeg. 6 * 7 * FFmpeg is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU Lesser General Public 9 * License as published by the Free Software Foundation; either 10 * version 2.1 of the License, or (at your option) any later version. 11 * 12 * FFmpeg is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * Lesser General Public License for more details. 16 * 17 * You should have received a copy of the GNU Lesser General Public 18 * License along with FFmpeg; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 20 */ 21 22/** 23 * @file 24 * MS RLE video decoder by Mike Melanson (melanson@pcisys.net) 25 * For more information about the MS RLE format, visit: 26 * http://www.pcisys.net/~melanson/codecs/ 27 * 28 * The MS RLE decoder outputs PAL8 colorspace data. 29 */ 30 31#include <stdio.h> 32#include <stdlib.h> 33#include <string.h> 34 35#include "avcodec.h" 36#include "codec_internal.h" 37#include "decode.h" 38#include "internal.h" 39#include "msrledec.h" 40#include "libavutil/imgutils.h" 41 42typedef struct MsrleContext { 43 AVCodecContext *avctx; 44 AVFrame *frame; 45 46 GetByteContext gb; 47 48 uint32_t pal[256]; 49} MsrleContext; 50 51static av_cold int msrle_decode_init(AVCodecContext *avctx) 52{ 53 MsrleContext *s = avctx->priv_data; 54 int i; 55 56 s->avctx = avctx; 57 58 switch (avctx->bits_per_coded_sample) { 59 case 1: 60 avctx->pix_fmt = AV_PIX_FMT_MONOWHITE; 61 break; 62 case 4: 63 case 8: 64 avctx->pix_fmt = AV_PIX_FMT_PAL8; 65 break; 66 case 24: 67 avctx->pix_fmt = AV_PIX_FMT_BGR24; 68 break; 69 default: 70 av_log(avctx, AV_LOG_ERROR, "unsupported bits per sample\n"); 71 return AVERROR_INVALIDDATA; 72 } 73 74 s->frame = av_frame_alloc(); 75 if (!s->frame) 76 return AVERROR(ENOMEM); 77 78 if (avctx->extradata_size >= 4) 79 for (i = 0; i < FFMIN(avctx->extradata_size, AVPALETTE_SIZE)/4; i++) 80 s->pal[i] = 0xFFU<<24 | AV_RL32(avctx->extradata+4*i); 81 82 return 0; 83} 84 85static int msrle_decode_frame(AVCodecContext *avctx, AVFrame *rframe, 86 int *got_frame, AVPacket *avpkt) 87{ 88 const uint8_t *buf = avpkt->data; 89 int buf_size = avpkt->size; 90 MsrleContext *s = avctx->priv_data; 91 int istride = FFALIGN(avctx->width*avctx->bits_per_coded_sample, 32) / 8; 92 int ret; 93 94 if (buf_size < 2) //Minimally a end of picture code should be there 95 return AVERROR_INVALIDDATA; 96 97 if ((ret = ff_reget_buffer(avctx, s->frame, 0)) < 0) 98 return ret; 99 100 if (avctx->bits_per_coded_sample > 1 && avctx->bits_per_coded_sample <= 8) { 101 s->frame->palette_has_changed = ff_copy_palette(s->pal, avpkt, avctx); 102 103 /* make the palette available */ 104 memcpy(s->frame->data[1], s->pal, AVPALETTE_SIZE); 105 } 106 107 /* FIXME how to correctly detect RLE ??? */ 108 if (avctx->height * istride == avpkt->size) { /* assume uncompressed */ 109 int linesize = av_image_get_linesize(avctx->pix_fmt, avctx->width, 0); 110 uint8_t *ptr = s->frame->data[0]; 111 const uint8_t *buf = avpkt->data + (avctx->height-1)*istride; 112 int i, j; 113 114 if (linesize < 0) 115 return linesize; 116 117 for (i = 0; i < avctx->height; i++) { 118 if (avctx->bits_per_coded_sample == 4) { 119 for (j = 0; j < avctx->width - 1; j += 2) { 120 ptr[j+0] = buf[j>>1] >> 4; 121 ptr[j+1] = buf[j>>1] & 0xF; 122 } 123 if (avctx->width & 1) 124 ptr[j+0] = buf[j>>1] >> 4; 125 } else { 126 memcpy(ptr, buf, linesize); 127 } 128 buf -= istride; 129 ptr += s->frame->linesize[0]; 130 } 131 } else { 132 bytestream2_init(&s->gb, buf, buf_size); 133 ff_msrle_decode(avctx, s->frame, avctx->bits_per_coded_sample, &s->gb); 134 } 135 136 if ((ret = av_frame_ref(rframe, s->frame)) < 0) 137 return ret; 138 139 *got_frame = 1; 140 141 /* report that the buffer was completely consumed */ 142 return buf_size; 143} 144 145static void msrle_decode_flush(AVCodecContext *avctx) 146{ 147 MsrleContext *s = avctx->priv_data; 148 149 av_frame_unref(s->frame); 150} 151 152static av_cold int msrle_decode_end(AVCodecContext *avctx) 153{ 154 MsrleContext *s = avctx->priv_data; 155 156 /* release the last frame */ 157 av_frame_free(&s->frame); 158 159 return 0; 160} 161 162const FFCodec ff_msrle_decoder = { 163 .p.name = "msrle", 164 .p.long_name = NULL_IF_CONFIG_SMALL("Microsoft RLE"), 165 .p.type = AVMEDIA_TYPE_VIDEO, 166 .p.id = AV_CODEC_ID_MSRLE, 167 .priv_data_size = sizeof(MsrleContext), 168 .init = msrle_decode_init, 169 .close = msrle_decode_end, 170 FF_CODEC_DECODE_CB(msrle_decode_frame), 171 .flush = msrle_decode_flush, 172 .p.capabilities = AV_CODEC_CAP_DR1, 173 .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE, 174}; 175