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