yading@10: /* yading@10: * SGI RLE 8-bit decoder yading@10: * Copyright (c) 2012 Peter Ross yading@10: * yading@10: * This file is part of FFmpeg. yading@10: * yading@10: * FFmpeg is free software; you can redistribute it and/or yading@10: * modify it under the terms of the GNU Lesser General Public yading@10: * License as published by the Free Software Foundation; either yading@10: * version 2.1 of the License, or (at your option) any later version. yading@10: * yading@10: * FFmpeg is distributed in the hope that it will be useful, yading@10: * but WITHOUT ANY WARRANTY; without even the implied warranty of yading@10: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU yading@10: * Lesser General Public License for more details. yading@10: * yading@10: * You should have received a copy of the GNU Lesser General Public yading@10: * License along with FFmpeg; if not, write to the Free Software yading@10: * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA yading@10: */ yading@10: yading@10: /** yading@10: * @file yading@10: * SGI RLE 8-bit decoder yading@10: */ yading@10: yading@10: #include "avcodec.h" yading@10: #include "internal.h" yading@10: yading@10: typedef struct SGIRLEContext { yading@10: AVFrame *frame; yading@10: } SGIRLEContext; yading@10: yading@10: static av_cold int sgirle_decode_init(AVCodecContext *avctx) yading@10: { yading@10: SGIRLEContext *s = avctx->priv_data; yading@10: avctx->pix_fmt = AV_PIX_FMT_BGR8; yading@10: s->frame = av_frame_alloc(); yading@10: if (!s->frame) yading@10: return AVERROR(ENOMEM); yading@10: return 0; yading@10: } yading@10: yading@10: /** yading@10: * Convert SGI RGB332 pixel into PIX_FMT_BGR8 yading@10: * SGI RGB332 is packed RGB 3:3:2, 8bpp, (msb)3R 2B 3G(lsb) yading@10: */ yading@10: #define RGB332_TO_BGR8(x) (((x << 3) & 0xC0) | ((x << 3) & 0x38) | ((x >> 5) & 7)) yading@10: yading@10: static av_always_inline void memcpy_rgb332_to_bgr8(uint8_t *dst, const uint8_t *src, int size) yading@10: { yading@10: int i; yading@10: for (i = 0; i < size; i++) yading@10: dst[i] = RGB332_TO_BGR8(src[i]); yading@10: } yading@10: yading@10: /** yading@10: * @param[out] dst Destination buffer yading@10: * @param[in] src Source buffer yading@10: * @param src_size Source buffer size (bytes) yading@10: * @param width Width of destination buffer (pixels) yading@10: * @param height Height of destination buffer (pixels) yading@10: * @param linesize Line size of destination buffer (bytes) yading@10: * @return <0 on error yading@10: */ yading@10: static int decode_sgirle8(AVCodecContext *avctx, uint8_t *dst, const uint8_t *src, int src_size, int width, int height, int linesize) yading@10: { yading@10: const uint8_t *src_end = src + src_size; yading@10: int x = 0, y = 0; yading@10: yading@10: #define INC_XY(n) \ yading@10: x += n; \ yading@10: if (x >= width) { \ yading@10: y++; \ yading@10: if (y >= height) \ yading@10: return 0; \ yading@10: x = 0; \ yading@10: } yading@10: yading@10: while (src_end - src >= 2) { yading@10: uint8_t v = *src++; yading@10: if (v > 0 && v < 0xC0) { yading@10: do { yading@10: int length = FFMIN(v, width - x); yading@10: memset(dst + y*linesize + x, RGB332_TO_BGR8(*src), length); yading@10: INC_XY(length); yading@10: v -= length; yading@10: } while (v > 0); yading@10: src++; yading@10: } else if (v >= 0xC1) { yading@10: v -= 0xC0; yading@10: do { yading@10: int length = FFMIN3(v, width - x, src_end - src); yading@10: if (src_end - src < length) yading@10: break; yading@10: memcpy_rgb332_to_bgr8(dst + y*linesize + x, src, length); yading@10: INC_XY(length); yading@10: src += length; yading@10: v -= length; yading@10: } while (v > 0); yading@10: } else { yading@10: avpriv_request_sample(avctx, "opcode %d", v); yading@10: return AVERROR_PATCHWELCOME; yading@10: } yading@10: } yading@10: return 0; yading@10: } yading@10: yading@10: static int sgirle_decode_frame(AVCodecContext *avctx, yading@10: void *data, int *got_frame, yading@10: AVPacket *avpkt) yading@10: { yading@10: SGIRLEContext *s = avctx->priv_data; yading@10: int ret; yading@10: yading@10: if ((ret = ff_reget_buffer(avctx, s->frame)) < 0) yading@10: return ret; yading@10: yading@10: ret = decode_sgirle8(avctx, s->frame->data[0], avpkt->data, avpkt->size, avctx->width, avctx->height, s->frame->linesize[0]); yading@10: if (ret < 0) yading@10: return ret; yading@10: yading@10: *got_frame = 1; yading@10: if ((ret = av_frame_ref(data, s->frame)) < 0) yading@10: return ret; yading@10: yading@10: return avpkt->size; yading@10: } yading@10: yading@10: static av_cold int sgirle_decode_end(AVCodecContext *avctx) yading@10: { yading@10: SGIRLEContext *s = avctx->priv_data; yading@10: yading@10: av_frame_free(&s->frame); yading@10: yading@10: return 0; yading@10: } yading@10: yading@10: AVCodec ff_sgirle_decoder = { yading@10: .name = "sgirle", yading@10: .type = AVMEDIA_TYPE_VIDEO, yading@10: .id = AV_CODEC_ID_SGIRLE, yading@10: .priv_data_size = sizeof(SGIRLEContext), yading@10: .init = sgirle_decode_init, yading@10: .close = sgirle_decode_end, yading@10: .decode = sgirle_decode_frame, yading@10: .capabilities = CODEC_CAP_DR1, yading@10: .long_name = NULL_IF_CONFIG_SMALL("SGI RLE 8-bit"), yading@10: };