1/* 2 * Silicon Graphics RLE 8-bit video decoder 3 * Copyright (c) 2012 Peter Ross 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 * Silicon Graphics RLE 8-bit video decoder 25 * @note Data is packed in rbg323 with rle, contained in mv or mov. 26 * The algorithm and pixfmt are subtly different from SGI images. 27 */ 28 29#include "libavutil/common.h" 30 31#include "avcodec.h" 32#include "internal.h" 33 34typedef struct SGIRLEContext { 35 AVFrame *frame; 36} SGIRLEContext; 37 38static av_cold int sgirle_decode_init(AVCodecContext *avctx) 39{ 40 SGIRLEContext *s = avctx->priv_data; 41 avctx->pix_fmt = AV_PIX_FMT_BGR8; 42 s->frame = av_frame_alloc(); 43 if (!s->frame) 44 return AVERROR(ENOMEM); 45 return 0; 46} 47 48/** 49 * Convert SGI RBG323 pixel into AV_PIX_FMT_BGR8 50 * SGI RGB data is packed as 8bpp, (msb)3R 2B 3G(lsb) 51 */ 52#define RBG323_TO_BGR8(x) ((((x) << 3) & 0xC0) | \ 53 (((x) << 3) & 0x38) | \ 54 (((x) >> 5) & 7)) 55static av_always_inline 56void rbg323_to_bgr8(uint8_t *dst, const uint8_t *src, int size) 57{ 58 int i; 59 for (i = 0; i < size; i++) 60 dst[i] = RBG323_TO_BGR8(src[i]); 61} 62 63/** 64 * @param[out] dst Destination buffer 65 * @param[in] src Source buffer 66 * @param src_size Source buffer size (bytes) 67 * @param width Width of destination buffer (pixels) 68 * @param height Height of destination buffer (pixels) 69 * @param linesize Line size of destination buffer (bytes) 70 * 71 * @return <0 on error 72 */ 73static int decode_sgirle8(AVCodecContext *avctx, uint8_t *dst, 74 const uint8_t *src, int src_size, 75 int width, int height, ptrdiff_t linesize) 76{ 77 const uint8_t *src_end = src + src_size; 78 int x = 0, y = 0; 79 80#define INC_XY(n) \ 81 x += n; \ 82 if (x >= width) { \ 83 y++; \ 84 if (y >= height) \ 85 return 0; \ 86 x = 0; \ 87 } 88 89 while (src_end - src >= 2) { 90 uint8_t v = *src++; 91 if (v > 0 && v < 0xC0) { 92 do { 93 int length = FFMIN(v, width - x); 94 if (length <= 0) 95 break; 96 memset(dst + y * linesize + x, RBG323_TO_BGR8(*src), length); 97 INC_XY(length); 98 v -= length; 99 } while (v > 0); 100 src++; 101 } else if (v >= 0xC1) { 102 v -= 0xC0; 103 do { 104 int length = FFMIN3(v, width - x, src_end - src); 105 if (src_end - src < length || length <= 0) 106 break; 107 rbg323_to_bgr8(dst + y * linesize + x, src, length); 108 INC_XY(length); 109 src += length; 110 v -= length; 111 } while (v > 0); 112 } else { 113 avpriv_request_sample(avctx, "opcode %d", v); 114 return AVERROR_PATCHWELCOME; 115 } 116 } 117 return 0; 118} 119 120static int sgirle_decode_frame(AVCodecContext *avctx, void *data, 121 int *got_frame, AVPacket *avpkt) 122{ 123 SGIRLEContext *s = avctx->priv_data; 124 int ret; 125 126 if ((ret = ff_reget_buffer(avctx, s->frame)) < 0) 127 return ret; 128 129 ret = decode_sgirle8(avctx, s->frame->data[0], avpkt->data, avpkt->size, 130 avctx->width, avctx->height, s->frame->linesize[0]); 131 if (ret < 0) 132 return ret; 133 134 *got_frame = 1; 135 if ((ret = av_frame_ref(data, s->frame)) < 0) 136 return ret; 137 138 return avpkt->size; 139} 140 141static av_cold int sgirle_decode_end(AVCodecContext *avctx) 142{ 143 SGIRLEContext *s = avctx->priv_data; 144 145 av_frame_free(&s->frame); 146 147 return 0; 148} 149 150AVCodec ff_sgirle_decoder = { 151 .name = "sgirle", 152 .long_name = NULL_IF_CONFIG_SMALL("Silicon Graphics RLE 8-bit video"), 153 .type = AVMEDIA_TYPE_VIDEO, 154 .id = AV_CODEC_ID_SGIRLE, 155 .priv_data_size = sizeof(SGIRLEContext), 156 .init = sgirle_decode_init, 157 .close = sgirle_decode_end, 158 .decode = sgirle_decode_frame, 159 .capabilities = CODEC_CAP_DR1, 160}; 161