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 "codec_internal.h" 33#include "internal.h" 34 35static av_cold int sgirle_decode_init(AVCodecContext *avctx) 36{ 37 avctx->pix_fmt = AV_PIX_FMT_BGR8; 38 return 0; 39} 40 41/** 42 * Convert SGI RBG323 pixel into AV_PIX_FMT_BGR8 43 * SGI RGB data is packed as 8bpp, (msb)3R 2B 3G(lsb) 44 */ 45#define RBG323_TO_BGR8(x) ((((x) << 3) & 0xC0) | \ 46 (((x) << 3) & 0x38) | \ 47 (((x) >> 5) & 7)) 48static av_always_inline 49void rbg323_to_bgr8(uint8_t *dst, const uint8_t *src, int size) 50{ 51 int i; 52 for (i = 0; i < size; i++) 53 dst[i] = RBG323_TO_BGR8(src[i]); 54} 55 56/** 57 * @param[out] dst Destination buffer 58 * @param[in] src Source buffer 59 * @param src_size Source buffer size (bytes) 60 * @param width Width of destination buffer (pixels) 61 * @param height Height of destination buffer (pixels) 62 * @param linesize Line size of destination buffer (bytes) 63 * 64 * @return <0 on error 65 */ 66static int decode_sgirle8(AVCodecContext *avctx, uint8_t *dst, 67 const uint8_t *src, int src_size, 68 int width, int height, ptrdiff_t linesize) 69{ 70 const uint8_t *src_end = src + src_size; 71 int x = 0, y = 0; 72 73#define INC_XY(n) \ 74 x += n; \ 75 if (x >= width) { \ 76 y++; \ 77 if (y >= height) \ 78 return 0; \ 79 x = 0; \ 80 } 81 82 while (src_end - src >= 2) { 83 uint8_t v = *src++; 84 if (v > 0 && v < 0xC0) { 85 do { 86 int length = FFMIN(v, width - x); 87 if (length <= 0) 88 break; 89 memset(dst + y * linesize + x, RBG323_TO_BGR8(*src), length); 90 INC_XY(length); 91 v -= length; 92 } while (v > 0); 93 src++; 94 } else if (v >= 0xC1) { 95 v -= 0xC0; 96 do { 97 int length = FFMIN3(v, width - x, src_end - src); 98 if (src_end - src < length || length <= 0) 99 break; 100 rbg323_to_bgr8(dst + y * linesize + x, src, length); 101 INC_XY(length); 102 src += length; 103 v -= length; 104 } while (v > 0); 105 } else { 106 avpriv_request_sample(avctx, "opcode %d", v); 107 return AVERROR_PATCHWELCOME; 108 } 109 } 110 return 0; 111} 112 113static int sgirle_decode_frame(AVCodecContext *avctx, AVFrame *frame, 114 int *got_frame, AVPacket *avpkt) 115{ 116 int ret; 117 118 if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) 119 return ret; 120 121 ret = decode_sgirle8(avctx, frame->data[0], avpkt->data, avpkt->size, 122 avctx->width, avctx->height, frame->linesize[0]); 123 if (ret < 0) 124 return ret; 125 126 frame->pict_type = AV_PICTURE_TYPE_I; 127 frame->key_frame = 1; 128 129 *got_frame = 1; 130 131 return avpkt->size; 132} 133 134const FFCodec ff_sgirle_decoder = { 135 .p.name = "sgirle", 136 .p.long_name = NULL_IF_CONFIG_SMALL("Silicon Graphics RLE 8-bit video"), 137 .p.type = AVMEDIA_TYPE_VIDEO, 138 .p.id = AV_CODEC_ID_SGIRLE, 139 .init = sgirle_decode_init, 140 FF_CODEC_DECODE_CB(sgirle_decode_frame), 141 .p.capabilities = AV_CODEC_CAP_DR1, 142 .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE, 143}; 144