Originally committed as revision 9452 to svn://svn.ffmpeg.org/ffmpeg/trunk
Alexis Ballier authored on 2007/07/02 16:06:28... | ... |
@@ -1030,7 +1030,7 @@ following image formats are supported: |
1030 | 1030 |
@item Id RoQ @tab X @tab X @tab Used in Quake III, Jedi Knight 2, other computer games. |
1031 | 1031 |
@item Xan/WC3 @tab @tab X @tab Used in Wing Commander III .MVE files. |
1032 | 1032 |
@item Interplay Video @tab @tab X @tab Used in Interplay .MVE files. |
1033 |
-@item Apple Animation @tab @tab X @tab fourcc: 'rle ' |
|
1033 |
+@item Apple Animation @tab X @tab X @tab fourcc: 'rle ' |
|
1034 | 1034 |
@item Apple Graphics @tab @tab X @tab fourcc: 'smc ' |
1035 | 1035 |
@item Apple Video @tab @tab X @tab fourcc: rpza |
1036 | 1036 |
@item Apple QuickDraw @tab @tab X @tab fourcc: qdrw |
... | ... |
@@ -132,6 +132,7 @@ OBJS-$(CONFIG_QDM2_DECODER) += qdm2.o mdct.o fft.o mpegaudiodec.o mpe |
132 | 132 |
OBJS-$(CONFIG_QDRAW_DECODER) += qdrw.o |
133 | 133 |
OBJS-$(CONFIG_QPEG_DECODER) += qpeg.o |
134 | 134 |
OBJS-$(CONFIG_QTRLE_DECODER) += qtrle.o |
135 |
+OBJS-$(CONFIG_QTRLE_ENCODER) += qtrleenc.o |
|
135 | 136 |
OBJS-$(CONFIG_RA_144_DECODER) += ra144.o |
136 | 137 |
OBJS-$(CONFIG_RA_288_DECODER) += ra288.o |
137 | 138 |
OBJS-$(CONFIG_ROQ_DECODER) += roqvideodec.o roqvideo.o |
... | ... |
@@ -122,7 +122,7 @@ void avcodec_register_all(void) |
122 | 122 |
REGISTER_DECODER(PTX, ptx); |
123 | 123 |
REGISTER_DECODER(QDRAW, qdraw); |
124 | 124 |
REGISTER_DECODER(QPEG, qpeg); |
125 |
- REGISTER_DECODER(QTRLE, qtrle); |
|
125 |
+ REGISTER_ENCDEC (QTRLE, qtrle); |
|
126 | 126 |
REGISTER_ENCDEC (RAWVIDEO, rawvideo); |
127 | 127 |
REGISTER_ENCDEC (ROQ, roq); |
128 | 128 |
REGISTER_DECODER(RPZA, rpza); |
... | ... |
@@ -56,6 +56,7 @@ extern AVCodec pgm_encoder; |
56 | 56 |
extern AVCodec pgmyuv_encoder; |
57 | 57 |
extern AVCodec png_encoder; |
58 | 58 |
extern AVCodec ppm_encoder; |
59 |
+extern AVCodec qtrle_encoder; |
|
59 | 60 |
extern AVCodec roq_dpcm_encoder; |
60 | 61 |
extern AVCodec roq_encoder; |
61 | 62 |
extern AVCodec rv10_encoder; |
62 | 63 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,327 @@ |
0 |
+/* |
|
1 |
+ * Quicktime Animation (RLE) Video Encoder |
|
2 |
+ * Copyright (C) 2007 Clemens Fruhwirth |
|
3 |
+ * Copyright (C) 2007 Alexis Ballier |
|
4 |
+ * |
|
5 |
+ * This file is part of FFmpeg. |
|
6 |
+ * |
|
7 |
+ * This file is based on flashsvenc.c |
|
8 |
+ * |
|
9 |
+ * FFmpeg is free software; you can redistribute it and/or |
|
10 |
+ * modify it under the terms of the GNU Lesser General Public |
|
11 |
+ * License, version 2.1, as published by the Free Software Foundation |
|
12 |
+ * |
|
13 |
+ * FFmpeg is distributed in the hope that it will be useful, |
|
14 |
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
15 |
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|
16 |
+ * Lesser General Public License for more details. |
|
17 |
+ * |
|
18 |
+ * You should have received a copy of the GNU Lesser General Public |
|
19 |
+ * License along with FFmpeg; if not, write to the Free Software |
|
20 |
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
|
21 |
+ * |
|
22 |
+ */ |
|
23 |
+ |
|
24 |
+#include "avcodec.h" |
|
25 |
+#include "bytestream.h" |
|
26 |
+ |
|
27 |
+/** Maximum RLE code for bulk copy */ |
|
28 |
+#define MAX_RLE_BULK 127 |
|
29 |
+/** Maximum RLE code for repeat */ |
|
30 |
+#define MAX_RLE_REPEAT 128 |
|
31 |
+/** Maximum RLE code for skip */ |
|
32 |
+#define MAX_RLE_SKIP 254 |
|
33 |
+ |
|
34 |
+typedef struct QtrleEncContext { |
|
35 |
+ AVCodecContext *avctx; |
|
36 |
+ AVFrame frame; |
|
37 |
+ int pixel_size; |
|
38 |
+ AVPicture previous_frame; |
|
39 |
+ unsigned int max_buf_size; |
|
40 |
+ /** |
|
41 |
+ * This array will contain at ith position the value of the best RLE code |
|
42 |
+ * if the line started at pixel i |
|
43 |
+ * There can be 3 values : |
|
44 |
+ * skip (0) : skip as much as possible pixels because they are equal to the |
|
45 |
+ * previous frame ones |
|
46 |
+ * repeat (<-1) : repeat that pixel -rle_code times, still as much as |
|
47 |
+ * possible |
|
48 |
+ * copy (>0) : copy the raw next rle_code pixels */ |
|
49 |
+ signed char *rlecode_table; |
|
50 |
+ /** |
|
51 |
+ * This array will contain the length of the best rle encoding of the line |
|
52 |
+ * starting at ith pixel */ |
|
53 |
+ int *length_table; |
|
54 |
+ /** |
|
55 |
+ * Will contain at ith position the number of consecutive pixels equal to the previous |
|
56 |
+ * frame starting from pixel i */ |
|
57 |
+ uint8_t* skip_table; |
|
58 |
+} QtrleEncContext; |
|
59 |
+ |
|
60 |
+static int qtrle_encode_init(AVCodecContext *avctx) |
|
61 |
+{ |
|
62 |
+ QtrleEncContext *s = avctx->priv_data; |
|
63 |
+ |
|
64 |
+ if (avcodec_check_dimensions(avctx, avctx->width, avctx->height) < 0) { |
|
65 |
+ return -1; |
|
66 |
+ } |
|
67 |
+ s->avctx=avctx; |
|
68 |
+ |
|
69 |
+ switch (avctx->pix_fmt) { |
|
70 |
+/* case PIX_FMT_RGB555: |
|
71 |
+ s->pixel_size = 2; |
|
72 |
+ break;*/ |
|
73 |
+ case PIX_FMT_RGB24: |
|
74 |
+ s->pixel_size = 3; |
|
75 |
+ break; |
|
76 |
+ default: |
|
77 |
+ av_log(avctx, AV_LOG_ERROR, "Unsupported colorspace.\n"); |
|
78 |
+ break; |
|
79 |
+ } |
|
80 |
+ avctx->bits_per_sample = s->pixel_size*8; |
|
81 |
+ |
|
82 |
+ s->rlecode_table = av_mallocz(s->avctx->width); |
|
83 |
+ s->skip_table = av_mallocz(s->avctx->width); |
|
84 |
+ s->length_table = av_mallocz((s->avctx->width + 1)*sizeof(int)); |
|
85 |
+ if (!s->skip_table || !s->length_table || !s->rlecode_table) { |
|
86 |
+ av_log(avctx, AV_LOG_ERROR, "Error allocating memory.\n"); |
|
87 |
+ return -1; |
|
88 |
+ } |
|
89 |
+ if (avpicture_alloc(&s->previous_frame, avctx->pix_fmt, avctx->width, avctx->height) < 0) { |
|
90 |
+ av_log(avctx, AV_LOG_ERROR, "Error allocating picture\n"); |
|
91 |
+ return -1; |
|
92 |
+ } |
|
93 |
+ |
|
94 |
+ s->max_buf_size = s->avctx->width*s->avctx->height*s->pixel_size /* image base material */ |
|
95 |
+ + 15 /* header + footer */ |
|
96 |
+ + s->avctx->height*2 /* skip code+rle end */ |
|
97 |
+ + s->avctx->width/MAX_RLE_BULK + 1 /* rle codes */; |
|
98 |
+ avctx->coded_frame = &s->frame; |
|
99 |
+ return 0; |
|
100 |
+} |
|
101 |
+ |
|
102 |
+/** |
|
103 |
+ * Computes the best RLE sequence for a line |
|
104 |
+ */ |
|
105 |
+static void qtrle_encode_line(QtrleEncContext *s, AVFrame *p, int line, uint8_t **buf) |
|
106 |
+{ |
|
107 |
+ int width=s->avctx->width; |
|
108 |
+ int i; |
|
109 |
+ signed char rlecode; |
|
110 |
+ |
|
111 |
+ /* We will use it to compute the best bulk copy sequence */ |
|
112 |
+ unsigned int bulkcount; |
|
113 |
+ /* This will be the number of pixels equal to the preivous frame one's |
|
114 |
+ * starting from the ith pixel */ |
|
115 |
+ unsigned int skipcount; |
|
116 |
+ /* This will be the number of consecutive equal pixels in the current |
|
117 |
+ * frame, starting from the ith one also */ |
|
118 |
+ unsigned int repeatcount; |
|
119 |
+ |
|
120 |
+ /* The cost of the three different possibilities */ |
|
121 |
+ int total_bulk_cost; |
|
122 |
+ int total_skip_cost; |
|
123 |
+ int total_repeat_cost; |
|
124 |
+ |
|
125 |
+ int temp_cost; |
|
126 |
+ int j; |
|
127 |
+ |
|
128 |
+ uint8_t *this_line = p-> data[0] + line*p->linesize[0] + (width - 1)*s->pixel_size; |
|
129 |
+ uint8_t *prev_line = s->previous_frame.data[0] + line*p->linesize[0] + (width - 1)*s->pixel_size; |
|
130 |
+ |
|
131 |
+ s->length_table[width] = 0; |
|
132 |
+ skipcount = 0; |
|
133 |
+ |
|
134 |
+ for (i = width - 1; i >= 0; i--) { |
|
135 |
+ |
|
136 |
+ if (!s->frame.key_frame && !memcmp(this_line, prev_line, s->pixel_size)) |
|
137 |
+ skipcount = FFMIN(skipcount + 1, MAX_RLE_SKIP); |
|
138 |
+ else |
|
139 |
+ skipcount = 0; |
|
140 |
+ |
|
141 |
+ total_skip_cost = s->length_table[i + skipcount] + 2; |
|
142 |
+ s->skip_table[i] = skipcount; |
|
143 |
+ |
|
144 |
+ |
|
145 |
+ if (i < width - 1 && !memcmp(this_line, this_line + s->pixel_size, s->pixel_size)) |
|
146 |
+ repeatcount = FFMIN(repeatcount + 1, MAX_RLE_REPEAT); |
|
147 |
+ else |
|
148 |
+ repeatcount = 1; |
|
149 |
+ |
|
150 |
+ total_repeat_cost = s->length_table[i + repeatcount] + 1 + s->pixel_size; |
|
151 |
+ |
|
152 |
+ /* skip code is free for the first pixel, it costs one byte for repeat and bulk copy |
|
153 |
+ * so let's make it aware */ |
|
154 |
+ if (i == 0) { |
|
155 |
+ total_skip_cost--; |
|
156 |
+ total_repeat_cost++; |
|
157 |
+ } |
|
158 |
+ |
|
159 |
+ if (repeatcount > 1 && (skipcount == 0 || total_repeat_cost < total_skip_cost)) { |
|
160 |
+ /* repeat is the best */ |
|
161 |
+ s->length_table[i] = total_repeat_cost; |
|
162 |
+ s->rlecode_table[i] = -repeatcount; |
|
163 |
+ } |
|
164 |
+ else if (skipcount > 0) { |
|
165 |
+ /* skip is the best choice here */ |
|
166 |
+ s->length_table[i] = total_skip_cost; |
|
167 |
+ s->rlecode_table[i] = 0; |
|
168 |
+ } |
|
169 |
+ else { |
|
170 |
+ /* We cannot do neither skip nor repeat |
|
171 |
+ * thus we search for the best bulk copy to do */ |
|
172 |
+ |
|
173 |
+ int limit = FFMIN(width - i, MAX_RLE_BULK); |
|
174 |
+ |
|
175 |
+ temp_cost = 1 + s->pixel_size + !i; |
|
176 |
+ total_bulk_cost = INT_MAX; |
|
177 |
+ |
|
178 |
+ for (j = 1; j <= limit; j++) { |
|
179 |
+ if (s->length_table[i + j] + temp_cost < total_bulk_cost) { |
|
180 |
+ /* We have found a better bulk copy ... */ |
|
181 |
+ total_bulk_cost = s->length_table[i + j] + temp_cost; |
|
182 |
+ bulkcount = j; |
|
183 |
+ } |
|
184 |
+ temp_cost += s->pixel_size; |
|
185 |
+ } |
|
186 |
+ |
|
187 |
+ s->length_table[i] = total_bulk_cost; |
|
188 |
+ s->rlecode_table[i] = bulkcount; |
|
189 |
+ } |
|
190 |
+ |
|
191 |
+ this_line -= s->pixel_size; |
|
192 |
+ prev_line -= s->pixel_size; |
|
193 |
+ } |
|
194 |
+ |
|
195 |
+ /* Good ! Now we have the best sequence for this line, let's ouput it */ |
|
196 |
+ |
|
197 |
+ /* We do a special case for the first pixel so that we avoid testing it in |
|
198 |
+ * the whole loop */ |
|
199 |
+ |
|
200 |
+ i=0; |
|
201 |
+ this_line = p-> data[0] + line*p->linesize[0]; |
|
202 |
+ prev_line = s->previous_frame.data[0] + line*p->linesize[0]; |
|
203 |
+ |
|
204 |
+ if (s->rlecode_table[0] == 0) { |
|
205 |
+ bytestream_put_byte(buf, s->skip_table[0] + 1); |
|
206 |
+ i += s->skip_table[0]; |
|
207 |
+ } |
|
208 |
+ else bytestream_put_byte(buf, 1); |
|
209 |
+ |
|
210 |
+ |
|
211 |
+ while (i < width) { |
|
212 |
+ rlecode = s->rlecode_table[i]; |
|
213 |
+ bytestream_put_byte(buf, rlecode); |
|
214 |
+ if (rlecode == 0) { |
|
215 |
+ /* Write a skip sequence */ |
|
216 |
+ bytestream_put_byte(buf, s->skip_table[i] + 1); |
|
217 |
+ i += s->skip_table[i]; |
|
218 |
+ } |
|
219 |
+ else if (rlecode > 0) { |
|
220 |
+ /* bulk copy */ |
|
221 |
+ bytestream_put_buffer(buf, this_line + i*s->pixel_size, rlecode*s->pixel_size); |
|
222 |
+ i += rlecode; |
|
223 |
+ } |
|
224 |
+ else { |
|
225 |
+ /* repeat the bits */ |
|
226 |
+ bytestream_put_buffer(buf, this_line + i*s->pixel_size, s->pixel_size); |
|
227 |
+ i -= rlecode; |
|
228 |
+ } |
|
229 |
+ } |
|
230 |
+ bytestream_put_byte(buf, -1); // end RLE line |
|
231 |
+} |
|
232 |
+ |
|
233 |
+/** Encodes frame including header */ |
|
234 |
+static int encode_frame(QtrleEncContext *s, AVFrame *p, uint8_t *buf) |
|
235 |
+{ |
|
236 |
+ int i; |
|
237 |
+ int start_line = 0; |
|
238 |
+ int end_line = s->avctx->height; |
|
239 |
+ uint8_t *orig_buf = buf; |
|
240 |
+ |
|
241 |
+ if (!s->frame.key_frame) { |
|
242 |
+ for (start_line = 0; start_line < s->avctx->height; start_line++) |
|
243 |
+ if (memcmp(p->data[0] + start_line*p->linesize[0], |
|
244 |
+ s->previous_frame.data[0] + start_line*p->linesize[0], |
|
245 |
+ p->linesize[0])) |
|
246 |
+ break; |
|
247 |
+ |
|
248 |
+ for (end_line=s->avctx->height; end_line > start_line; end_line--) |
|
249 |
+ if (memcmp(p->data[0] + (end_line - 1)*p->linesize[0], |
|
250 |
+ s->previous_frame.data[0] + (end_line - 1)*p->linesize[0], |
|
251 |
+ p->linesize[0])) |
|
252 |
+ break; |
|
253 |
+ } |
|
254 |
+ |
|
255 |
+ bytestream_put_be32(&buf, 0); // CHUNK SIZE, patched later |
|
256 |
+ |
|
257 |
+ if (start_line == 0 && end_line == s->avctx->height || start_line == s->avctx->height) |
|
258 |
+ bytestream_put_be16(&buf, 0); // header |
|
259 |
+ else { |
|
260 |
+ bytestream_put_be16(&buf, 8); // header |
|
261 |
+ bytestream_put_be16(&buf, start_line); // starting line |
|
262 |
+ bytestream_put_be16(&buf, 0); // unknown |
|
263 |
+ bytestream_put_be16(&buf, end_line - start_line); // lines to update |
|
264 |
+ bytestream_put_be16(&buf, 0); // unknown |
|
265 |
+ } |
|
266 |
+ for (i = start_line; i < end_line; i++) |
|
267 |
+ qtrle_encode_line(s, p, i, &buf); |
|
268 |
+ |
|
269 |
+ bytestream_put_byte(&buf, 0); // zero skip code = frame finished |
|
270 |
+ AV_WB32(orig_buf, buf - orig_buf); // patch the chunk size |
|
271 |
+ return buf - orig_buf; |
|
272 |
+} |
|
273 |
+ |
|
274 |
+static int qtrle_encode_frame(AVCodecContext *avctx, uint8_t *buf, int buf_size, void *data) |
|
275 |
+{ |
|
276 |
+ QtrleEncContext * const s = avctx->priv_data; |
|
277 |
+ AVFrame *pict = data; |
|
278 |
+ AVFrame * const p = &s->frame; |
|
279 |
+ int chunksize; |
|
280 |
+ |
|
281 |
+ *p = *pict; |
|
282 |
+ |
|
283 |
+ if (buf_size < s->max_buf_size) { |
|
284 |
+ /* Upper bound check for compressed data */ |
|
285 |
+ av_log(avctx, AV_LOG_ERROR, "buf_size %d < %d\n", buf_size, s->max_buf_size); |
|
286 |
+ return -1; |
|
287 |
+ } |
|
288 |
+ |
|
289 |
+ if (avctx->gop_size == 0 || (s->avctx->frame_number % avctx->gop_size) == 0) { |
|
290 |
+ /* I-Frame */ |
|
291 |
+ p->pict_type = FF_I_TYPE; |
|
292 |
+ p->key_frame = 1; |
|
293 |
+ } else { |
|
294 |
+ /* P-Frame */ |
|
295 |
+ p->pict_type = FF_P_TYPE; |
|
296 |
+ p->key_frame = 0; |
|
297 |
+ } |
|
298 |
+ |
|
299 |
+ chunksize = encode_frame(s, pict, buf); |
|
300 |
+ |
|
301 |
+ /* save the current frame */ |
|
302 |
+ av_picture_copy(&s->previous_frame, (AVPicture *)p, avctx->pix_fmt, avctx->width, avctx->height); |
|
303 |
+ return chunksize; |
|
304 |
+} |
|
305 |
+ |
|
306 |
+static int qtrle_encode_end(AVCodecContext *avctx) |
|
307 |
+{ |
|
308 |
+ QtrleEncContext *s = avctx->priv_data; |
|
309 |
+ |
|
310 |
+ avpicture_free(&s->previous_frame); |
|
311 |
+ av_free(s->rlecode_table); |
|
312 |
+ av_free(s->length_table); |
|
313 |
+ av_free(s->skip_table); |
|
314 |
+ return 0; |
|
315 |
+} |
|
316 |
+ |
|
317 |
+AVCodec qtrle_encoder = { |
|
318 |
+ "qtrle", |
|
319 |
+ CODEC_TYPE_VIDEO, |
|
320 |
+ CODEC_ID_QTRLE, |
|
321 |
+ sizeof(QtrleEncContext), |
|
322 |
+ qtrle_encode_init, |
|
323 |
+ qtrle_encode_frame, |
|
324 |
+ qtrle_encode_end, |
|
325 |
+ .pix_fmts = (enum PixelFormat[]){PIX_FMT_RGB24, -1}, |
|
326 |
+}; |