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 "codec_internal.h" 27#include "encode.h" 28 29#define ALIAS_HEADER_SIZE 10 30 31static int encode_frame(AVCodecContext *avctx, AVPacket *pkt, 32 const AVFrame *frame, int *got_packet) 33{ 34 int width, height, bits_pixel, length, ret; 35 uint8_t *buf; 36 37 width = avctx->width; 38 height = avctx->height; 39 40 if (width > 65535 || height > 65535 || 41 width * height >= INT_MAX / 4 - ALIAS_HEADER_SIZE) { 42 av_log(avctx, AV_LOG_ERROR, "Invalid image size %dx%d.\n", width, height); 43 return AVERROR_INVALIDDATA; 44 } 45 46 switch (avctx->pix_fmt) { 47 case AV_PIX_FMT_GRAY8: 48 bits_pixel = 8; 49 break; 50 case AV_PIX_FMT_BGR24: 51 bits_pixel = 24; 52 break; 53 default: 54 return AVERROR(EINVAL); 55 } 56 57 length = ALIAS_HEADER_SIZE + 4 * width * height; // max possible 58 if ((ret = ff_alloc_packet(avctx, pkt, length)) < 0) 59 return ret; 60 61 buf = pkt->data; 62 63 /* Encode header. */ 64 bytestream_put_be16(&buf, width); 65 bytestream_put_be16(&buf, height); 66 bytestream_put_be32(&buf, 0); /* X, Y offset */ 67 bytestream_put_be16(&buf, bits_pixel); 68 69 for (int j = 0, bytes_pixel = bits_pixel >> 3; j < height; j++) { 70 const uint8_t *in_buf = frame->data[0] + frame->linesize[0] * j; 71 const uint8_t *const line_end = in_buf + bytes_pixel * width; 72 while (in_buf < line_end) { 73 int count = 0; 74 int pixel; 75 76 if (avctx->pix_fmt == AV_PIX_FMT_GRAY8) { 77 pixel = *in_buf; 78 while (count < 255 && in_buf < line_end && pixel == *in_buf) { 79 count++; 80 in_buf++; 81 } 82 bytestream_put_byte(&buf, count); 83 bytestream_put_byte(&buf, pixel); 84 } else { /* AV_PIX_FMT_BGR24 */ 85 pixel = AV_RB24(in_buf); 86 while (count < 255 && in_buf < line_end && 87 pixel == AV_RB24(in_buf)) { 88 count++; 89 in_buf += 3; 90 } 91 bytestream_put_byte(&buf, count); 92 bytestream_put_be24(&buf, pixel); 93 } 94 } 95 } 96 97 /* Total length */ 98 av_shrink_packet(pkt, buf - pkt->data); 99 *got_packet = 1; 100 101 return 0; 102} 103 104const FFCodec ff_alias_pix_encoder = { 105 .p.name = "alias_pix", 106 .p.long_name = NULL_IF_CONFIG_SMALL("Alias/Wavefront PIX image"), 107 .p.type = AVMEDIA_TYPE_VIDEO, 108 .p.id = AV_CODEC_ID_ALIAS_PIX, 109 FF_CODEC_ENCODE_CB(encode_frame), 110 .p.pix_fmts = (const enum AVPixelFormat[]) { 111 AV_PIX_FMT_BGR24, AV_PIX_FMT_GRAY8, AV_PIX_FMT_NONE 112 }, 113}; 114