On Thu, Mar 20, 2014 at 03:14:55AM +0100, Vittorio Giovara wrote: > --- > My first encoder/decoder \o/ > > A sum up of the format is available here > http://www.mediatel.lu/workshop/graphic/2D_fileformat/h_aliaspix.html > GIMP is able to read and write PIX images, it's completely compatibile with > the ones > produced/read from this decoder/encoder. > > Cheers, > Vittorio > > Changelog | 1 + > doc/general.texi | 2 + > libavcodec/Makefile | 2 + > libavcodec/alias.c | 222 > ++++++++++++++++++++++++++++++++++++++++++++++++ > libavcodec/allcodecs.c | 1 + > libavcodec/avcodec.h | 1 + > libavcodec/codec_desc.c | 7 ++ > libavcodec/version.h | 4 +- > libavformat/img2.c | 1 + > libavformat/img2enc.c | 2 +- > 10 files changed, 240 insertions(+), 3 deletions(-) > create mode 100644 libavcodec/alias.c > > diff --git a/libavcodec/alias.c b/libavcodec/alias.c > new file mode 100644 > index 0000000..2469c2c > --- /dev/null > +++ b/libavcodec/alias.c > @@ -0,0 +1,222 @@ > +/* > + * Alias PIX image > + * Copyright (C) 2014 Vittorio Giovara <vittorio.giov...@gmail.com> > + * > + * This file is part of Libav. > + * > + * Libav is free software; you can redistribute it and/or > + * modify it under the terms of the GNU Lesser General Public > + * License as published by the Free Software Foundation; either > + * version 2.1 of the License, or (at your option) any later version. > + * > + * Libav is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU > + * Lesser General Public License for more details. > + * > + * You should have received a copy of the GNU Lesser General Public > + * License along with Libav; if not, write to the Free Software > + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 > USA > + */ > + > +#include "libavutil/intreadwrite.h" > + > +#include "avcodec.h" > +#include "bytestream.h" > +#include "internal.h" > + > +#define ALIAS_HEADER_SIZE 10 > + > +static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame, > + AVPacket *avpkt) > +{ > + AVFrame *f = data; > + GetByteContext g; > + int width, height, ret, i; > + int format; > + uint8_t *out_buf; > + uint8_t packet[4]; > + int y = 0; > + > + bytestream2_init(&g, avpkt->data, avpkt->size); > + > + if (bytestream2_get_bytes_left(&g) < ALIAS_HEADER_SIZE) { > + av_log(avctx, AV_LOG_ERROR, "buf_size too small (%d)\n", > avpkt->size); > + return AVERROR_INVALIDDATA; > + } > + > + width = bytestream2_get_be16(&g); > + height = bytestream2_get_be16(&g); > + bytestream2_skip(&g, 4); // obsolete offset
sounds WTFy and it's hard to guess that's obsolete X,Y offset, not some pointer in the file > + format = bytestream2_get_be16(&g); > + > + if (format == 24) > + avctx->pix_fmt = AV_PIX_FMT_BGR24; > + else if (format == 8) > + avctx->pix_fmt = AV_PIX_FMT_GRAY8; > + else { > + av_log(avctx, AV_LOG_ERROR, "invalid format\n"); > + return AVERROR_INVALIDDATA; > + } > + > + ret = ff_set_dimensions(avctx, width, height); > + if (ret < 0) > + return ret; > + > + ret = ff_get_buffer(avctx, f, 0); > + if (ret < 0) > + return ret; > + > + f->pict_type = AV_PICTURE_TYPE_I; > + f->key_frame = 1; > + > + if (avctx->pix_fmt == AV_PIX_FMT_BGR24) { > + while (bytestream2_get_bytes_left(&g) > 0) { > + /* set buffer at the right position at every new line */ > + if (width == avctx->width) { > + width = 0; > + out_buf = f->data[0] + f->linesize[0] * y++; > + } > + /* read and copy data */ > + AV_WB32(packet, bytestream2_get_be32(&g)); > + for (i = 0; i < packet[0]; i++) { > + *out_buf++ = packet[1]; > + *out_buf++ = packet[2]; > + *out_buf++ = packet[3]; > + } WTF? run = get_byte(); r = get_byte(); g = get_byte(); b = get_byte(); for (i=0;i < run; i++){ *out++ = r; *out++ = g; *out++ = b; } or so > + width += i; also no check for overruns (e.g. image width = 16, i = 256, bye bye buffer boundary) > + } > + } else { // AV_PIX_FMT_GRAY8 > + while (bytestream2_get_bytes_left(&g) > 0) { > + /* set buffer at the right position at every new line */ > + if (width == avctx->width) { > + width = 0; > + out_buf = f->data[0] + f->linesize[0] * y++; > + } > + /* read and copy data */ > + AV_WB16(packet, bytestream2_get_be16(&g)); > + for (i = 0; i < packet[0]; i++) > + *out_buf++ = packet[1]; > + width += i; ditto > + } > + } > + > + *got_frame = 1; > + return avpkt->size; > +} > + > +static av_cold int encode_init(AVCodecContext *avctx) > +{ > + avctx->coded_frame = av_frame_alloc(); > + if (!avctx->coded_frame) > + return AVERROR(ENOMEM); > + > + return 0; > +} > + > +static int encode_frame(AVCodecContext *avctx, AVPacket *pkt, > + const AVFrame *frame, int *got_packet) > +{ > + int width, height, depth, i, j, length, ret; > + uint8_t *in_buf, *buf = pkt->data; > + > + avctx->coded_frame->pict_type = AV_PICTURE_TYPE_I; > + avctx->coded_frame->key_frame = 1; > + > + width = avctx->width; > + height = avctx->height; > + > + if (width > 65535 || height > 65536) { > + av_log(avctx, AV_LOG_ERROR, "unsupported size %dx%d\n", width, > height); > + return AVERROR_INVALIDDATA; > + } > + > + switch (avctx->pix_fmt) { > + case AV_PIX_FMT_GRAY8: > + depth = 8; > + break; > + case AV_PIX_FMT_RGB24: > + case AV_PIX_FMT_RGBA: > + depth = 24; > + break; > + default: > + return AVERROR_INVALIDDATA; > + } > + > + length = ALIAS_HEADER_SIZE + 4 * width * height; // max possible > + if ((ret = ff_alloc_packet(pkt, length)) < 0) { > + av_log(avctx, AV_LOG_ERROR, "Error getting output packet of size > %d.\n", length); > + return ret; > + } > + > + /* Encode header. */ > + bytestream_put_be16(&buf, width); > + bytestream_put_be16(&buf, height); > + bytestream_put_be32(&buf, 0L); /* offset */ > + bytestream_put_be16(&buf, depth); > + > + for (j = 0; j < height; j++) { > + int count = 0; > + in_buf = frame->data[0] + frame->linesize[0] * j; > + for (i = 0; i < width; i += count) { > + int pixel; > + > + if (avctx->pix_fmt == AV_PIX_FMT_GRAY8) { > + pixel = in_buf[0]; > + while (count < 255 && count + i < width && pixel == > in_buf[0]) { > + count++; > + in_buf++; > + } > + } else { > + // the mask removes alpha in RGBA case > + pixel = AV_RN32(in_buf) & 0x00FFFFFF; fishy > + while (count < 255 && count + i < width && > + pixel == (AV_RN32(in_buf) & 0x00FFFFFF) ) { > + count++; > + in_buf += avctx->pix_fmt == AV_PIX_FMT_RGB24 ? 3 : 4; > + } > + } > + > + bytestream_put_be32(&buf, (count << depth) | pixel); > + } > + } > + > + /* Total length */ > + pkt->size = buf - pkt->data; > + pkt->flags |= AV_PKT_FLAG_KEY; > + *got_packet = 1; > + > + return 0; > +} > + > +static av_cold int encode_close(AVCodecContext *avctx) > +{ > + av_frame_free(&avctx->coded_frame); > + return 0; > +} > + > +#if CONFIG_ALIAS_PIX_DECODER > +AVCodec ff_alias_pix_decoder = { > + .name = "alias_pix", > + .long_name = NULL_IF_CONFIG_SMALL("Alias/Wavefront PIX image"), > + .type = AVMEDIA_TYPE_VIDEO, > + .id = AV_CODEC_ID_ALIAS_PIX, > + .decode = decode_frame, > + .capabilities = CODEC_CAP_DR1, > +}; > +#endif > + > +#if CONFIG_ALIAS_PIX_ENCODER > +AVCodec ff_alias_pix_encoder = { > + .name = "alias_pix", > + .long_name = NULL_IF_CONFIG_SMALL("Alias/Wavefront PIX image"), > + .type = AVMEDIA_TYPE_VIDEO, > + .id = AV_CODEC_ID_ALIAS_PIX, > + .init = encode_init, > + .encode2 = encode_frame, > + .close = encode_close, > + .pix_fmts = (const enum AVPixelFormat[]) { > + AV_PIX_FMT_RGB24, AV_PIX_FMT_RGBA, AV_PIX_FMT_GRAY8, AV_PIX_FMT_NONE > + }, > +}; > +#endif the rest if up to Diego _______________________________________________ libav-devel mailing list libav-devel@libav.org https://lists.libav.org/mailman/listinfo/libav-devel