2 * Alias PIX image encoder
3 * Copyright (C) 2014 Vittorio Giovara <vittorio.giovara@gmail.com>
5 * This file is part of FFmpeg.
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.
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.
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
22 #include "libavutil/intreadwrite.h"
25 #include "bytestream.h"
28 #define ALIAS_HEADER_SIZE 10
30 static av_cold
int encode_init(AVCodecContext
*avctx
)
32 avctx
->coded_frame
= av_frame_alloc();
33 if (!avctx
->coded_frame
)
34 return AVERROR(ENOMEM
);
38 static int encode_frame(AVCodecContext
*avctx
, AVPacket
*pkt
,
39 const AVFrame
*frame
, int *got_packet
)
41 int width
, height
, bits_pixel
, i
, j
, length
, ret
;
42 uint8_t *in_buf
, *buf
;
44 avctx
->coded_frame
->pict_type
= AV_PICTURE_TYPE_I
;
45 avctx
->coded_frame
->key_frame
= 1;
48 height
= avctx
->height
;
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
;
56 switch (avctx
->pix_fmt
) {
57 case AV_PIX_FMT_GRAY8
:
60 case AV_PIX_FMT_BGR24
:
64 return AVERROR(EINVAL
);
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
);
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
);
81 for (j
= 0; j
< height
; j
++) {
82 in_buf
= frame
->data
[0] + frame
->linesize
[0] * j
;
83 for (i
= 0; i
< width
; ) {
87 if (avctx
->pix_fmt
== AV_PIX_FMT_GRAY8
) {
89 while (count
< 255 && count
+ i
< width
&& pixel
== *in_buf
) {
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
)) {
102 bytestream_put_byte(&buf
, count
);
103 bytestream_put_be24(&buf
, pixel
);
110 av_shrink_packet(pkt
, buf
- pkt
->data
);
111 pkt
->flags
|= AV_PKT_FLAG_KEY
;
117 static av_cold
int encode_close(AVCodecContext
*avctx
)
119 av_frame_free(&avctx
->coded_frame
);
123 AVCodec ff_alias_pix_encoder
= {
125 .long_name
= NULL_IF_CONFIG_SMALL("Alias/Wavefront PIX image"),
126 .type
= AVMEDIA_TYPE_VIDEO
,
127 .id
= AV_CODEC_ID_ALIAS_PIX
,
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