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 |
|
|
}; |