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