1/* 2 * Alias PIX image encoder 3 * Copyright (C) 2014 Vittorio Giovara <vittorio.giovara@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/intreadwrite.h" 23 24#include "avcodec.h" 25#include "bytestream.h" 26#include "internal.h" 27 28#define ALIAS_HEADER_SIZE 10 29 30static av_cold int encode_init(AVCodecContext *avctx) 31{ 32 avctx->coded_frame = av_frame_alloc(); 33 if (!avctx->coded_frame) 34 return AVERROR(ENOMEM); 35 return 0; 36} 37 38static int encode_frame(AVCodecContext *avctx, AVPacket *pkt, 39 const AVFrame *frame, int *got_packet) 40{ 41 int width, height, bits_pixel, i, j, length, ret; 42 uint8_t *in_buf, *buf; 43 44 avctx->coded_frame->pict_type = AV_PICTURE_TYPE_I; 45 avctx->coded_frame->key_frame = 1; 46 47 width = avctx->width; 48 height = avctx->height; 49 50 if (width > 65535 || height > 65535 || 51 width * height >= INT_MAX / 4 - ALIAS_HEADER_SIZE) { 52 av_log(avctx, AV_LOG_ERROR, "Invalid image size %dx%d.\n", width, height); 53 return AVERROR_INVALIDDATA; 54 } 55 56 switch (avctx->pix_fmt) { 57 case AV_PIX_FMT_GRAY8: 58 bits_pixel = 8; 59 break; 60 case AV_PIX_FMT_BGR24: 61 bits_pixel = 24; 62 break; 63 default: 64 return AVERROR(EINVAL); 65 } 66 67 length = ALIAS_HEADER_SIZE + 4 * width * height; // max possible 68 if ((ret = ff_alloc_packet(pkt, length)) < 0) { 69 av_log(avctx, AV_LOG_ERROR, "Error getting output packet of size %d.\n", length); 70 return ret; 71 } 72 73 buf = pkt->data; 74 75 /* Encode header. */ 76 bytestream_put_be16(&buf, width); 77 bytestream_put_be16(&buf, height); 78 bytestream_put_be32(&buf, 0); /* X, Y offset */ 79 bytestream_put_be16(&buf, bits_pixel); 80 81 for (j = 0; j < height; j++) { 82 in_buf = frame->data[0] + frame->linesize[0] * j; 83 for (i = 0; i < width; ) { 84 int count = 0; 85 int pixel; 86 87 if (avctx->pix_fmt == AV_PIX_FMT_GRAY8) { 88 pixel = *in_buf; 89 while (count < 255 && count + i < width && pixel == *in_buf) { 90 count++; 91 in_buf++; 92 } 93 bytestream_put_byte(&buf, count); 94 bytestream_put_byte(&buf, pixel); 95 } else { /* AV_PIX_FMT_BGR24 */ 96 pixel = AV_RB24(in_buf); 97 while (count < 255 && count + i < width && 98 pixel == AV_RB24(in_buf)) { 99 count++; 100 in_buf += 3; 101 } 102 bytestream_put_byte(&buf, count); 103 bytestream_put_be24(&buf, pixel); 104 } 105 i += count; 106 } 107 } 108 109 /* Total length */ 110 av_shrink_packet(pkt, buf - pkt->data); 111 pkt->flags |= AV_PKT_FLAG_KEY; 112 *got_packet = 1; 113 114 return 0; 115} 116 117static av_cold int encode_close(AVCodecContext *avctx) 118{ 119 av_frame_free(&avctx->coded_frame); 120 return 0; 121} 122 123AVCodec ff_alias_pix_encoder = { 124 .name = "alias_pix", 125 .long_name = NULL_IF_CONFIG_SMALL("Alias/Wavefront PIX image"), 126 .type = AVMEDIA_TYPE_VIDEO, 127 .id = AV_CODEC_ID_ALIAS_PIX, 128 .init = encode_init, 129 .encode2 = encode_frame, 130 .close = encode_close, 131 .pix_fmts = (const enum AVPixelFormat[]) { 132 AV_PIX_FMT_BGR24, AV_PIX_FMT_GRAY8, AV_PIX_FMT_NONE 133 }, 134}; 135