1/* 2 * Sun Rasterfile (.sun/.ras/im{1,8,24}/.sunras) image encoder 3 * Copyright (c) 2012 Aneesh Dogra (lionaneesh) <lionaneesh@gmail.com> 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#include "avcodec.h" 23#include "bytestream.h" 24#include "internal.h" 25#include "sunrast.h" 26 27typedef struct SUNRASTContext { 28 PutByteContext p; 29 int depth; ///< depth of pixel 30 int length; ///< length (bytes) of image 31 int type; ///< type of file 32 int maptype; ///< type of colormap 33 int maplength; ///< length (bytes) of colormap 34 int size; 35} SUNRASTContext; 36 37static void sunrast_image_write_header(AVCodecContext *avctx) 38{ 39 SUNRASTContext *s = avctx->priv_data; 40 41 bytestream2_put_be32u(&s->p, RAS_MAGIC); 42 bytestream2_put_be32u(&s->p, avctx->width); 43 bytestream2_put_be32u(&s->p, avctx->height); 44 bytestream2_put_be32u(&s->p, s->depth); 45 bytestream2_put_be32u(&s->p, s->length); 46 bytestream2_put_be32u(&s->p, s->type); 47 bytestream2_put_be32u(&s->p, s->maptype); 48 bytestream2_put_be32u(&s->p, s->maplength); 49} 50 51static void sunrast_image_write_image(AVCodecContext *avctx, 52 const uint8_t *pixels, 53 const uint32_t *palette_data, 54 int linesize) 55{ 56 SUNRASTContext *s = avctx->priv_data; 57 const uint8_t *ptr; 58 int len, alen, x, y; 59 60 if (s->maplength) { // palettized 61 PutByteContext pb_r, pb_g; 62 int len = s->maplength / 3; 63 64 pb_r = s->p; 65 bytestream2_skip_p(&s->p, len); 66 pb_g = s->p; 67 bytestream2_skip_p(&s->p, len); 68 69 for (x = 0; x < len; x++) { 70 uint32_t pixel = palette_data[x]; 71 72 bytestream2_put_byteu(&pb_r, (pixel >> 16) & 0xFF); 73 bytestream2_put_byteu(&pb_g, (pixel >> 8) & 0xFF); 74 bytestream2_put_byteu(&s->p, pixel & 0xFF); 75 } 76 } 77 78 len = (s->depth * avctx->width + 7) >> 3; 79 alen = len + (len & 1); 80 ptr = pixels; 81 82 if (s->type == RT_BYTE_ENCODED) { 83 uint8_t value, value2; 84 int run; 85 86 ptr = pixels; 87 88#define GET_VALUE y >= avctx->height ? 0 : x >= len ? ptr[len-1] : ptr[x] 89 90 x = 0, y = 0; 91 value2 = GET_VALUE; 92 while (y < avctx->height) { 93 run = 1; 94 value = value2; 95 x++; 96 if (x >= alen) { 97 x = 0; 98 ptr += linesize, y++; 99 } 100 101 value2 = GET_VALUE; 102 while (value2 == value && run < 256 && y < avctx->height) { 103 x++; 104 run++; 105 if (x >= alen) { 106 x = 0; 107 ptr += linesize, y++; 108 } 109 value2 = GET_VALUE; 110 } 111 112 if (run > 2 || value == RLE_TRIGGER) { 113 bytestream2_put_byteu(&s->p, RLE_TRIGGER); 114 bytestream2_put_byteu(&s->p, run - 1); 115 if (run > 1) 116 bytestream2_put_byteu(&s->p, value); 117 } else if (run == 1) { 118 bytestream2_put_byteu(&s->p, value); 119 } else 120 bytestream2_put_be16u(&s->p, (value << 8) | value); 121 } 122 123 // update data length for header 124 s->length = bytestream2_tell_p(&s->p) - 32 - s->maplength; 125 } else { 126 for (y = 0; y < avctx->height; y++) { 127 bytestream2_put_buffer(&s->p, ptr, len); 128 if (len < alen) 129 bytestream2_put_byteu(&s->p, 0); 130 ptr += linesize; 131 } 132 } 133} 134 135static av_cold int sunrast_encode_init(AVCodecContext *avctx) 136{ 137 SUNRASTContext *s = avctx->priv_data; 138 139 switch (avctx->coder_type) { 140 case FF_CODER_TYPE_RLE: 141 s->type = RT_BYTE_ENCODED; 142 break; 143 case FF_CODER_TYPE_RAW: 144 s->type = RT_STANDARD; 145 break; 146 default: 147 av_log(avctx, AV_LOG_ERROR, "invalid coder_type\n"); 148 return AVERROR(EINVAL); 149 } 150 151 s->maptype = RMT_NONE; 152 s->maplength = 0; 153 154 switch (avctx->pix_fmt) { 155 case AV_PIX_FMT_MONOWHITE: 156 s->depth = 1; 157 break; 158 case AV_PIX_FMT_PAL8 : 159 s->maptype = RMT_EQUAL_RGB; 160 s->maplength = 3 * 256; 161 case AV_PIX_FMT_GRAY8: 162 s->depth = 8; 163 break; 164 case AV_PIX_FMT_BGR24: 165 s->depth = 24; 166 break; 167 default: 168 return AVERROR_BUG; 169 } 170 s->length = avctx->height * (FFALIGN(avctx->width * s->depth, 16) >> 3); 171 s->size = 32 + s->maplength + 172 s->length * (s->type == RT_BYTE_ENCODED ? 2 : 1); 173 174 return 0; 175} 176 177static int sunrast_encode_frame(AVCodecContext *avctx, AVPacket *avpkt, 178 const AVFrame *frame, int *got_packet_ptr) 179{ 180 SUNRASTContext *s = avctx->priv_data; 181 int ret; 182 183 if ((ret = ff_alloc_packet2(avctx, avpkt, s->size)) < 0) 184 return ret; 185 186 bytestream2_init_writer(&s->p, avpkt->data, avpkt->size); 187 sunrast_image_write_header(avctx); 188 sunrast_image_write_image(avctx, frame->data[0], 189 (const uint32_t *)frame->data[1], 190 frame->linesize[0]); 191 // update data length in header after RLE 192 if (s->type == RT_BYTE_ENCODED) 193 AV_WB32(&avpkt->data[16], s->length); 194 195 *got_packet_ptr = 1; 196 avpkt->flags |= AV_PKT_FLAG_KEY; 197 avpkt->size = bytestream2_tell_p(&s->p); 198 return 0; 199} 200 201static av_cold int sunrast_encode_close(AVCodecContext *avctx) 202{ 203 av_frame_free(&avctx->coded_frame); 204 return 0; 205} 206 207static const AVCodecDefault sunrast_defaults[] = { 208 { "coder", "rle" }, 209 { NULL }, 210}; 211 212AVCodec ff_sunrast_encoder = { 213 .name = "sunrast", 214 .long_name = NULL_IF_CONFIG_SMALL("Sun Rasterfile image"), 215 .type = AVMEDIA_TYPE_VIDEO, 216 .id = AV_CODEC_ID_SUNRAST, 217 .priv_data_size = sizeof(SUNRASTContext), 218 .init = sunrast_encode_init, 219 .close = sunrast_encode_close, 220 .encode2 = sunrast_encode_frame, 221 .defaults = sunrast_defaults, 222 .pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_BGR24, 223 AV_PIX_FMT_PAL8, 224 AV_PIX_FMT_GRAY8, 225 AV_PIX_FMT_MONOWHITE, 226 AV_PIX_FMT_NONE }, 227}; 228