Mercurial > libavcodec.hg
annotate qtrleenc.c @ 12483:0159a19bfff7 libavcodec
aacdec: Rework channel mapping compatibility hacks.
For a PCE based configuration map the channels solely based on tags.
For an indexed configuration map the channels solely based on position.
This works with all known exotic samples including al17, elem_id0, bad_concat,
and lfe_is_sce.
author | alexc |
---|---|
date | Fri, 10 Sep 2010 18:01:48 +0000 |
parents | ffb3668ff7af |
children |
rev | line source |
---|---|
5195 | 1 /* |
2 * Quicktime Animation (RLE) Video Encoder | |
3 * Copyright (C) 2007 Clemens Fruhwirth | |
4 * Copyright (C) 2007 Alexis Ballier | |
5 * | |
7804 | 6 * This file is based on flashsvenc.c. |
5195 | 7 * |
7804 | 8 * This file is part of FFmpeg. |
5195 | 9 * |
10 * FFmpeg is free software; you can redistribute it and/or | |
11 * modify it under the terms of the GNU Lesser General Public | |
7820
9905b13b3399
Relicense from LGPL 2.1 to LGPL 2.1 or later with the authors' permission.
diego
parents:
7804
diff
changeset
|
12 * License as published by the Free Software Foundation; either |
9905b13b3399
Relicense from LGPL 2.1 to LGPL 2.1 or later with the authors' permission.
diego
parents:
7804
diff
changeset
|
13 * version 2.1 of the License, or (at your option) any later version. |
5195 | 14 * |
15 * FFmpeg is distributed in the hope that it will be useful, | |
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
18 * Lesser General Public License for more details. | |
19 * | |
20 * You should have received a copy of the GNU Lesser General Public | |
21 * License along with FFmpeg; if not, write to the Free Software | |
22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
23 */ | |
24 | |
12372
914f484bb476
Remove use of the deprecated function avcodec_check_dimensions(), use
stefano
parents:
12024
diff
changeset
|
25 #include "libavcore/imgutils.h" |
5195 | 26 #include "avcodec.h" |
27 #include "bytestream.h" | |
28 | |
29 /** Maximum RLE code for bulk copy */ | |
30 #define MAX_RLE_BULK 127 | |
31 /** Maximum RLE code for repeat */ | |
32 #define MAX_RLE_REPEAT 128 | |
33 /** Maximum RLE code for skip */ | |
34 #define MAX_RLE_SKIP 254 | |
35 | |
36 typedef struct QtrleEncContext { | |
37 AVCodecContext *avctx; | |
38 AVFrame frame; | |
39 int pixel_size; | |
40 AVPicture previous_frame; | |
41 unsigned int max_buf_size; | |
42 /** | |
43 * This array will contain at ith position the value of the best RLE code | |
44 * if the line started at pixel i | |
45 * There can be 3 values : | |
46 * skip (0) : skip as much as possible pixels because they are equal to the | |
47 * previous frame ones | |
48 * repeat (<-1) : repeat that pixel -rle_code times, still as much as | |
49 * possible | |
50 * copy (>0) : copy the raw next rle_code pixels */ | |
51 signed char *rlecode_table; | |
52 /** | |
53 * This array will contain the length of the best rle encoding of the line | |
54 * starting at ith pixel */ | |
55 int *length_table; | |
56 /** | |
57 * Will contain at ith position the number of consecutive pixels equal to the previous | |
58 * frame starting from pixel i */ | |
59 uint8_t* skip_table; | |
60 } QtrleEncContext; | |
61 | |
6517
48759bfbd073
Apply 'cold' attribute to init/uninit functions in libavcodec
zuxy
parents:
6204
diff
changeset
|
62 static av_cold int qtrle_encode_init(AVCodecContext *avctx) |
5195 | 63 { |
64 QtrleEncContext *s = avctx->priv_data; | |
65 | |
12462
ffb3668ff7af
Use new imgutils.h API names, fix deprecation warnings.
stefano
parents:
12372
diff
changeset
|
66 if (av_image_check_size(avctx->width, avctx->height, 0, avctx) < 0) { |
5195 | 67 return -1; |
68 } | |
69 s->avctx=avctx; | |
70 | |
71 switch (avctx->pix_fmt) { | |
11505 | 72 case PIX_FMT_RGB555BE: |
5195 | 73 s->pixel_size = 2; |
11505 | 74 break; |
5195 | 75 case PIX_FMT_RGB24: |
76 s->pixel_size = 3; | |
77 break; | |
9932 | 78 case PIX_FMT_ARGB: |
79 s->pixel_size = 4; | |
80 break; | |
5195 | 81 default: |
82 av_log(avctx, AV_LOG_ERROR, "Unsupported colorspace.\n"); | |
83 break; | |
84 } | |
7823
4525dcd81357
Bump Major version, this commit is almost just renaming bits_per_sample to
michael
parents:
7820
diff
changeset
|
85 avctx->bits_per_coded_sample = s->pixel_size*8; |
5195 | 86 |
87 s->rlecode_table = av_mallocz(s->avctx->width); | |
88 s->skip_table = av_mallocz(s->avctx->width); | |
89 s->length_table = av_mallocz((s->avctx->width + 1)*sizeof(int)); | |
90 if (!s->skip_table || !s->length_table || !s->rlecode_table) { | |
91 av_log(avctx, AV_LOG_ERROR, "Error allocating memory.\n"); | |
92 return -1; | |
93 } | |
94 if (avpicture_alloc(&s->previous_frame, avctx->pix_fmt, avctx->width, avctx->height) < 0) { | |
95 av_log(avctx, AV_LOG_ERROR, "Error allocating picture\n"); | |
96 return -1; | |
97 } | |
98 | |
99 s->max_buf_size = s->avctx->width*s->avctx->height*s->pixel_size /* image base material */ | |
100 + 15 /* header + footer */ | |
101 + s->avctx->height*2 /* skip code+rle end */ | |
102 + s->avctx->width/MAX_RLE_BULK + 1 /* rle codes */; | |
103 avctx->coded_frame = &s->frame; | |
104 return 0; | |
105 } | |
106 | |
107 /** | |
12024 | 108 * Compute the best RLE sequence for a line |
5195 | 109 */ |
110 static void qtrle_encode_line(QtrleEncContext *s, AVFrame *p, int line, uint8_t **buf) | |
111 { | |
112 int width=s->avctx->width; | |
113 int i; | |
114 signed char rlecode; | |
115 | |
116 /* We will use it to compute the best bulk copy sequence */ | |
117 unsigned int bulkcount; | |
118 /* This will be the number of pixels equal to the preivous frame one's | |
119 * starting from the ith pixel */ | |
120 unsigned int skipcount; | |
121 /* This will be the number of consecutive equal pixels in the current | |
122 * frame, starting from the ith one also */ | |
8802
7b81aa80ec46
Add av_uninit macro to variable to avoid false positive warning:
diego
parents:
7823
diff
changeset
|
123 unsigned int av_uninit(repeatcount); |
5195 | 124 |
125 /* The cost of the three different possibilities */ | |
126 int total_bulk_cost; | |
127 int total_skip_cost; | |
128 int total_repeat_cost; | |
129 | |
130 int temp_cost; | |
131 int j; | |
132 | |
9691
9447a746f2cb
fix qtrle encoding when previous frame linesize differs, fix #998
bcoudurier
parents:
9593
diff
changeset
|
133 uint8_t *this_line = p-> data[0] + line*p-> linesize[0] + |
9447a746f2cb
fix qtrle encoding when previous frame linesize differs, fix #998
bcoudurier
parents:
9593
diff
changeset
|
134 (width - 1)*s->pixel_size; |
9447a746f2cb
fix qtrle encoding when previous frame linesize differs, fix #998
bcoudurier
parents:
9593
diff
changeset
|
135 uint8_t *prev_line = s->previous_frame.data[0] + line*s->previous_frame.linesize[0] + |
9447a746f2cb
fix qtrle encoding when previous frame linesize differs, fix #998
bcoudurier
parents:
9593
diff
changeset
|
136 (width - 1)*s->pixel_size; |
5195 | 137 |
138 s->length_table[width] = 0; | |
139 skipcount = 0; | |
140 | |
141 for (i = width - 1; i >= 0; i--) { | |
142 | |
143 if (!s->frame.key_frame && !memcmp(this_line, prev_line, s->pixel_size)) | |
144 skipcount = FFMIN(skipcount + 1, MAX_RLE_SKIP); | |
145 else | |
146 skipcount = 0; | |
147 | |
148 total_skip_cost = s->length_table[i + skipcount] + 2; | |
149 s->skip_table[i] = skipcount; | |
150 | |
151 | |
152 if (i < width - 1 && !memcmp(this_line, this_line + s->pixel_size, s->pixel_size)) | |
153 repeatcount = FFMIN(repeatcount + 1, MAX_RLE_REPEAT); | |
154 else | |
155 repeatcount = 1; | |
156 | |
157 total_repeat_cost = s->length_table[i + repeatcount] + 1 + s->pixel_size; | |
158 | |
159 /* skip code is free for the first pixel, it costs one byte for repeat and bulk copy | |
160 * so let's make it aware */ | |
161 if (i == 0) { | |
162 total_skip_cost--; | |
163 total_repeat_cost++; | |
164 } | |
165 | |
166 if (repeatcount > 1 && (skipcount == 0 || total_repeat_cost < total_skip_cost)) { | |
167 /* repeat is the best */ | |
168 s->length_table[i] = total_repeat_cost; | |
169 s->rlecode_table[i] = -repeatcount; | |
170 } | |
171 else if (skipcount > 0) { | |
172 /* skip is the best choice here */ | |
173 s->length_table[i] = total_skip_cost; | |
174 s->rlecode_table[i] = 0; | |
175 } | |
176 else { | |
177 /* We cannot do neither skip nor repeat | |
178 * thus we search for the best bulk copy to do */ | |
179 | |
180 int limit = FFMIN(width - i, MAX_RLE_BULK); | |
181 | |
182 temp_cost = 1 + s->pixel_size + !i; | |
183 total_bulk_cost = INT_MAX; | |
184 | |
185 for (j = 1; j <= limit; j++) { | |
186 if (s->length_table[i + j] + temp_cost < total_bulk_cost) { | |
187 /* We have found a better bulk copy ... */ | |
188 total_bulk_cost = s->length_table[i + j] + temp_cost; | |
189 bulkcount = j; | |
190 } | |
191 temp_cost += s->pixel_size; | |
192 } | |
193 | |
194 s->length_table[i] = total_bulk_cost; | |
195 s->rlecode_table[i] = bulkcount; | |
196 } | |
197 | |
198 this_line -= s->pixel_size; | |
199 prev_line -= s->pixel_size; | |
200 } | |
201 | |
202 /* Good ! Now we have the best sequence for this line, let's ouput it */ | |
203 | |
204 /* We do a special case for the first pixel so that we avoid testing it in | |
205 * the whole loop */ | |
206 | |
207 i=0; | |
208 this_line = p-> data[0] + line*p->linesize[0]; | |
209 | |
210 if (s->rlecode_table[0] == 0) { | |
211 bytestream_put_byte(buf, s->skip_table[0] + 1); | |
212 i += s->skip_table[0]; | |
213 } | |
214 else bytestream_put_byte(buf, 1); | |
215 | |
216 | |
217 while (i < width) { | |
218 rlecode = s->rlecode_table[i]; | |
219 bytestream_put_byte(buf, rlecode); | |
220 if (rlecode == 0) { | |
221 /* Write a skip sequence */ | |
222 bytestream_put_byte(buf, s->skip_table[i] + 1); | |
223 i += s->skip_table[i]; | |
224 } | |
225 else if (rlecode > 0) { | |
226 /* bulk copy */ | |
227 bytestream_put_buffer(buf, this_line + i*s->pixel_size, rlecode*s->pixel_size); | |
228 i += rlecode; | |
229 } | |
230 else { | |
231 /* repeat the bits */ | |
232 bytestream_put_buffer(buf, this_line + i*s->pixel_size, s->pixel_size); | |
233 i -= rlecode; | |
234 } | |
235 } | |
236 bytestream_put_byte(buf, -1); // end RLE line | |
237 } | |
238 | |
12024 | 239 /** Encode frame including header */ |
5195 | 240 static int encode_frame(QtrleEncContext *s, AVFrame *p, uint8_t *buf) |
241 { | |
242 int i; | |
243 int start_line = 0; | |
244 int end_line = s->avctx->height; | |
245 uint8_t *orig_buf = buf; | |
246 | |
247 if (!s->frame.key_frame) { | |
9691
9447a746f2cb
fix qtrle encoding when previous frame linesize differs, fix #998
bcoudurier
parents:
9593
diff
changeset
|
248 unsigned line_size = s->avctx->width * s->pixel_size; |
5195 | 249 for (start_line = 0; start_line < s->avctx->height; start_line++) |
250 if (memcmp(p->data[0] + start_line*p->linesize[0], | |
9691
9447a746f2cb
fix qtrle encoding when previous frame linesize differs, fix #998
bcoudurier
parents:
9593
diff
changeset
|
251 s->previous_frame.data[0] + start_line*s->previous_frame.linesize[0], |
9447a746f2cb
fix qtrle encoding when previous frame linesize differs, fix #998
bcoudurier
parents:
9593
diff
changeset
|
252 line_size)) |
5195 | 253 break; |
254 | |
255 for (end_line=s->avctx->height; end_line > start_line; end_line--) | |
256 if (memcmp(p->data[0] + (end_line - 1)*p->linesize[0], | |
9691
9447a746f2cb
fix qtrle encoding when previous frame linesize differs, fix #998
bcoudurier
parents:
9593
diff
changeset
|
257 s->previous_frame.data[0] + (end_line - 1)*s->previous_frame.linesize[0], |
9447a746f2cb
fix qtrle encoding when previous frame linesize differs, fix #998
bcoudurier
parents:
9593
diff
changeset
|
258 line_size)) |
5195 | 259 break; |
260 } | |
261 | |
262 bytestream_put_be32(&buf, 0); // CHUNK SIZE, patched later | |
263 | |
6204
2265a9c096a4
add parenthesis, fix warning: qtrleenc.c:257: warning: suggest parentheses around && within ||
bcoudurier
parents:
5215
diff
changeset
|
264 if ((start_line == 0 && end_line == s->avctx->height) || start_line == s->avctx->height) |
5195 | 265 bytestream_put_be16(&buf, 0); // header |
266 else { | |
267 bytestream_put_be16(&buf, 8); // header | |
268 bytestream_put_be16(&buf, start_line); // starting line | |
269 bytestream_put_be16(&buf, 0); // unknown | |
270 bytestream_put_be16(&buf, end_line - start_line); // lines to update | |
271 bytestream_put_be16(&buf, 0); // unknown | |
272 } | |
273 for (i = start_line; i < end_line; i++) | |
274 qtrle_encode_line(s, p, i, &buf); | |
275 | |
276 bytestream_put_byte(&buf, 0); // zero skip code = frame finished | |
277 AV_WB32(orig_buf, buf - orig_buf); // patch the chunk size | |
278 return buf - orig_buf; | |
279 } | |
280 | |
281 static int qtrle_encode_frame(AVCodecContext *avctx, uint8_t *buf, int buf_size, void *data) | |
282 { | |
283 QtrleEncContext * const s = avctx->priv_data; | |
284 AVFrame *pict = data; | |
285 AVFrame * const p = &s->frame; | |
286 int chunksize; | |
287 | |
288 *p = *pict; | |
289 | |
290 if (buf_size < s->max_buf_size) { | |
291 /* Upper bound check for compressed data */ | |
292 av_log(avctx, AV_LOG_ERROR, "buf_size %d < %d\n", buf_size, s->max_buf_size); | |
293 return -1; | |
294 } | |
295 | |
296 if (avctx->gop_size == 0 || (s->avctx->frame_number % avctx->gop_size) == 0) { | |
297 /* I-Frame */ | |
298 p->pict_type = FF_I_TYPE; | |
299 p->key_frame = 1; | |
300 } else { | |
301 /* P-Frame */ | |
302 p->pict_type = FF_P_TYPE; | |
303 p->key_frame = 0; | |
304 } | |
305 | |
306 chunksize = encode_frame(s, pict, buf); | |
307 | |
308 /* save the current frame */ | |
309 av_picture_copy(&s->previous_frame, (AVPicture *)p, avctx->pix_fmt, avctx->width, avctx->height); | |
310 return chunksize; | |
311 } | |
312 | |
6517
48759bfbd073
Apply 'cold' attribute to init/uninit functions in libavcodec
zuxy
parents:
6204
diff
changeset
|
313 static av_cold int qtrle_encode_end(AVCodecContext *avctx) |
5195 | 314 { |
315 QtrleEncContext *s = avctx->priv_data; | |
316 | |
317 avpicture_free(&s->previous_frame); | |
318 av_free(s->rlecode_table); | |
319 av_free(s->length_table); | |
320 av_free(s->skip_table); | |
321 return 0; | |
322 } | |
323 | |
324 AVCodec qtrle_encoder = { | |
325 "qtrle", | |
11560
8a4984c5cacc
Define AVMediaType enum, and use it instead of enum CodecType, which
stefano
parents:
11505
diff
changeset
|
326 AVMEDIA_TYPE_VIDEO, |
5195 | 327 CODEC_ID_QTRLE, |
328 sizeof(QtrleEncContext), | |
329 qtrle_encode_init, | |
330 qtrle_encode_frame, | |
331 qtrle_encode_end, | |
11505 | 332 .pix_fmts = (const enum PixelFormat[]){PIX_FMT_RGB24, PIX_FMT_RGB555BE, PIX_FMT_ARGB, PIX_FMT_NONE}, |
7040
e943e1409077
Make AVCodec long_names definition conditional depending on CONFIG_SMALL.
stefano
parents:
6788
diff
changeset
|
333 .long_name = NULL_IF_CONFIG_SMALL("QuickTime Animation (RLE) video"), |
5195 | 334 }; |