Mercurial > libavcodec.hg
annotate qtrleenc.c @ 12043:f9a0bd0888a4 libavcodec
mpegaudio: call ff_mpegaudiodec_init_mmx() only from float decoder
The mmx code is floating-point only, and this function does not know
from which decoder it is called. Without this change, the integer
decoder only "works" because the size of the context struct is smaller
in this case, and the mmx init function writes the function pointer
outside the allocated context.
author | mru |
---|---|
date | Thu, 01 Jul 2010 23:21:17 +0000 |
parents | fdafbcef52f5 |
children | 914f484bb476 |
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 | |
25 #include "avcodec.h" | |
26 #include "bytestream.h" | |
27 | |
28 /** Maximum RLE code for bulk copy */ | |
29 #define MAX_RLE_BULK 127 | |
30 /** Maximum RLE code for repeat */ | |
31 #define MAX_RLE_REPEAT 128 | |
32 /** Maximum RLE code for skip */ | |
33 #define MAX_RLE_SKIP 254 | |
34 | |
35 typedef struct QtrleEncContext { | |
36 AVCodecContext *avctx; | |
37 AVFrame frame; | |
38 int pixel_size; | |
39 AVPicture previous_frame; | |
40 unsigned int max_buf_size; | |
41 /** | |
42 * This array will contain at ith position the value of the best RLE code | |
43 * if the line started at pixel i | |
44 * There can be 3 values : | |
45 * skip (0) : skip as much as possible pixels because they are equal to the | |
46 * previous frame ones | |
47 * repeat (<-1) : repeat that pixel -rle_code times, still as much as | |
48 * possible | |
49 * copy (>0) : copy the raw next rle_code pixels */ | |
50 signed char *rlecode_table; | |
51 /** | |
52 * This array will contain the length of the best rle encoding of the line | |
53 * starting at ith pixel */ | |
54 int *length_table; | |
55 /** | |
56 * Will contain at ith position the number of consecutive pixels equal to the previous | |
57 * frame starting from pixel i */ | |
58 uint8_t* skip_table; | |
59 } QtrleEncContext; | |
60 | |
6517
48759bfbd073
Apply 'cold' attribute to init/uninit functions in libavcodec
zuxy
parents:
6204
diff
changeset
|
61 static av_cold int qtrle_encode_init(AVCodecContext *avctx) |
5195 | 62 { |
63 QtrleEncContext *s = avctx->priv_data; | |
64 | |
65 if (avcodec_check_dimensions(avctx, avctx->width, avctx->height) < 0) { | |
66 return -1; | |
67 } | |
68 s->avctx=avctx; | |
69 | |
70 switch (avctx->pix_fmt) { | |
11505 | 71 case PIX_FMT_RGB555BE: |
5195 | 72 s->pixel_size = 2; |
11505 | 73 break; |
5195 | 74 case PIX_FMT_RGB24: |
75 s->pixel_size = 3; | |
76 break; | |
9932 | 77 case PIX_FMT_ARGB: |
78 s->pixel_size = 4; | |
79 break; | |
5195 | 80 default: |
81 av_log(avctx, AV_LOG_ERROR, "Unsupported colorspace.\n"); | |
82 break; | |
83 } | |
7823
4525dcd81357
Bump Major version, this commit is almost just renaming bits_per_sample to
michael
parents:
7820
diff
changeset
|
84 avctx->bits_per_coded_sample = s->pixel_size*8; |
5195 | 85 |
86 s->rlecode_table = av_mallocz(s->avctx->width); | |
87 s->skip_table = av_mallocz(s->avctx->width); | |
88 s->length_table = av_mallocz((s->avctx->width + 1)*sizeof(int)); | |
89 if (!s->skip_table || !s->length_table || !s->rlecode_table) { | |
90 av_log(avctx, AV_LOG_ERROR, "Error allocating memory.\n"); | |
91 return -1; | |
92 } | |
93 if (avpicture_alloc(&s->previous_frame, avctx->pix_fmt, avctx->width, avctx->height) < 0) { | |
94 av_log(avctx, AV_LOG_ERROR, "Error allocating picture\n"); | |
95 return -1; | |
96 } | |
97 | |
98 s->max_buf_size = s->avctx->width*s->avctx->height*s->pixel_size /* image base material */ | |
99 + 15 /* header + footer */ | |
100 + s->avctx->height*2 /* skip code+rle end */ | |
101 + s->avctx->width/MAX_RLE_BULK + 1 /* rle codes */; | |
102 avctx->coded_frame = &s->frame; | |
103 return 0; | |
104 } | |
105 | |
106 /** | |
12024 | 107 * Compute the best RLE sequence for a line |
5195 | 108 */ |
109 static void qtrle_encode_line(QtrleEncContext *s, AVFrame *p, int line, uint8_t **buf) | |
110 { | |
111 int width=s->avctx->width; | |
112 int i; | |
113 signed char rlecode; | |
114 | |
115 /* We will use it to compute the best bulk copy sequence */ | |
116 unsigned int bulkcount; | |
117 /* This will be the number of pixels equal to the preivous frame one's | |
118 * starting from the ith pixel */ | |
119 unsigned int skipcount; | |
120 /* This will be the number of consecutive equal pixels in the current | |
121 * 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
|
122 unsigned int av_uninit(repeatcount); |
5195 | 123 |
124 /* The cost of the three different possibilities */ | |
125 int total_bulk_cost; | |
126 int total_skip_cost; | |
127 int total_repeat_cost; | |
128 | |
129 int temp_cost; | |
130 int j; | |
131 | |
9691
9447a746f2cb
fix qtrle encoding when previous frame linesize differs, fix #998
bcoudurier
parents:
9593
diff
changeset
|
132 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
|
133 (width - 1)*s->pixel_size; |
9447a746f2cb
fix qtrle encoding when previous frame linesize differs, fix #998
bcoudurier
parents:
9593
diff
changeset
|
134 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
|
135 (width - 1)*s->pixel_size; |
5195 | 136 |
137 s->length_table[width] = 0; | |
138 skipcount = 0; | |
139 | |
140 for (i = width - 1; i >= 0; i--) { | |
141 | |
142 if (!s->frame.key_frame && !memcmp(this_line, prev_line, s->pixel_size)) | |
143 skipcount = FFMIN(skipcount + 1, MAX_RLE_SKIP); | |
144 else | |
145 skipcount = 0; | |
146 | |
147 total_skip_cost = s->length_table[i + skipcount] + 2; | |
148 s->skip_table[i] = skipcount; | |
149 | |
150 | |
151 if (i < width - 1 && !memcmp(this_line, this_line + s->pixel_size, s->pixel_size)) | |
152 repeatcount = FFMIN(repeatcount + 1, MAX_RLE_REPEAT); | |
153 else | |
154 repeatcount = 1; | |
155 | |
156 total_repeat_cost = s->length_table[i + repeatcount] + 1 + s->pixel_size; | |
157 | |
158 /* skip code is free for the first pixel, it costs one byte for repeat and bulk copy | |
159 * so let's make it aware */ | |
160 if (i == 0) { | |
161 total_skip_cost--; | |
162 total_repeat_cost++; | |
163 } | |
164 | |
165 if (repeatcount > 1 && (skipcount == 0 || total_repeat_cost < total_skip_cost)) { | |
166 /* repeat is the best */ | |
167 s->length_table[i] = total_repeat_cost; | |
168 s->rlecode_table[i] = -repeatcount; | |
169 } | |
170 else if (skipcount > 0) { | |
171 /* skip is the best choice here */ | |
172 s->length_table[i] = total_skip_cost; | |
173 s->rlecode_table[i] = 0; | |
174 } | |
175 else { | |
176 /* We cannot do neither skip nor repeat | |
177 * thus we search for the best bulk copy to do */ | |
178 | |
179 int limit = FFMIN(width - i, MAX_RLE_BULK); | |
180 | |
181 temp_cost = 1 + s->pixel_size + !i; | |
182 total_bulk_cost = INT_MAX; | |
183 | |
184 for (j = 1; j <= limit; j++) { | |
185 if (s->length_table[i + j] + temp_cost < total_bulk_cost) { | |
186 /* We have found a better bulk copy ... */ | |
187 total_bulk_cost = s->length_table[i + j] + temp_cost; | |
188 bulkcount = j; | |
189 } | |
190 temp_cost += s->pixel_size; | |
191 } | |
192 | |
193 s->length_table[i] = total_bulk_cost; | |
194 s->rlecode_table[i] = bulkcount; | |
195 } | |
196 | |
197 this_line -= s->pixel_size; | |
198 prev_line -= s->pixel_size; | |
199 } | |
200 | |
201 /* Good ! Now we have the best sequence for this line, let's ouput it */ | |
202 | |
203 /* We do a special case for the first pixel so that we avoid testing it in | |
204 * the whole loop */ | |
205 | |
206 i=0; | |
207 this_line = p-> data[0] + line*p->linesize[0]; | |
208 | |
209 if (s->rlecode_table[0] == 0) { | |
210 bytestream_put_byte(buf, s->skip_table[0] + 1); | |
211 i += s->skip_table[0]; | |
212 } | |
213 else bytestream_put_byte(buf, 1); | |
214 | |
215 | |
216 while (i < width) { | |
217 rlecode = s->rlecode_table[i]; | |
218 bytestream_put_byte(buf, rlecode); | |
219 if (rlecode == 0) { | |
220 /* Write a skip sequence */ | |
221 bytestream_put_byte(buf, s->skip_table[i] + 1); | |
222 i += s->skip_table[i]; | |
223 } | |
224 else if (rlecode > 0) { | |
225 /* bulk copy */ | |
226 bytestream_put_buffer(buf, this_line + i*s->pixel_size, rlecode*s->pixel_size); | |
227 i += rlecode; | |
228 } | |
229 else { | |
230 /* repeat the bits */ | |
231 bytestream_put_buffer(buf, this_line + i*s->pixel_size, s->pixel_size); | |
232 i -= rlecode; | |
233 } | |
234 } | |
235 bytestream_put_byte(buf, -1); // end RLE line | |
236 } | |
237 | |
12024 | 238 /** Encode frame including header */ |
5195 | 239 static int encode_frame(QtrleEncContext *s, AVFrame *p, uint8_t *buf) |
240 { | |
241 int i; | |
242 int start_line = 0; | |
243 int end_line = s->avctx->height; | |
244 uint8_t *orig_buf = buf; | |
245 | |
246 if (!s->frame.key_frame) { | |
9691
9447a746f2cb
fix qtrle encoding when previous frame linesize differs, fix #998
bcoudurier
parents:
9593
diff
changeset
|
247 unsigned line_size = s->avctx->width * s->pixel_size; |
5195 | 248 for (start_line = 0; start_line < s->avctx->height; start_line++) |
249 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
|
250 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
|
251 line_size)) |
5195 | 252 break; |
253 | |
254 for (end_line=s->avctx->height; end_line > start_line; end_line--) | |
255 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
|
256 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
|
257 line_size)) |
5195 | 258 break; |
259 } | |
260 | |
261 bytestream_put_be32(&buf, 0); // CHUNK SIZE, patched later | |
262 | |
6204
2265a9c096a4
add parenthesis, fix warning: qtrleenc.c:257: warning: suggest parentheses around && within ||
bcoudurier
parents:
5215
diff
changeset
|
263 if ((start_line == 0 && end_line == s->avctx->height) || start_line == s->avctx->height) |
5195 | 264 bytestream_put_be16(&buf, 0); // header |
265 else { | |
266 bytestream_put_be16(&buf, 8); // header | |
267 bytestream_put_be16(&buf, start_line); // starting line | |
268 bytestream_put_be16(&buf, 0); // unknown | |
269 bytestream_put_be16(&buf, end_line - start_line); // lines to update | |
270 bytestream_put_be16(&buf, 0); // unknown | |
271 } | |
272 for (i = start_line; i < end_line; i++) | |
273 qtrle_encode_line(s, p, i, &buf); | |
274 | |
275 bytestream_put_byte(&buf, 0); // zero skip code = frame finished | |
276 AV_WB32(orig_buf, buf - orig_buf); // patch the chunk size | |
277 return buf - orig_buf; | |
278 } | |
279 | |
280 static int qtrle_encode_frame(AVCodecContext *avctx, uint8_t *buf, int buf_size, void *data) | |
281 { | |
282 QtrleEncContext * const s = avctx->priv_data; | |
283 AVFrame *pict = data; | |
284 AVFrame * const p = &s->frame; | |
285 int chunksize; | |
286 | |
287 *p = *pict; | |
288 | |
289 if (buf_size < s->max_buf_size) { | |
290 /* Upper bound check for compressed data */ | |
291 av_log(avctx, AV_LOG_ERROR, "buf_size %d < %d\n", buf_size, s->max_buf_size); | |
292 return -1; | |
293 } | |
294 | |
295 if (avctx->gop_size == 0 || (s->avctx->frame_number % avctx->gop_size) == 0) { | |
296 /* I-Frame */ | |
297 p->pict_type = FF_I_TYPE; | |
298 p->key_frame = 1; | |
299 } else { | |
300 /* P-Frame */ | |
301 p->pict_type = FF_P_TYPE; | |
302 p->key_frame = 0; | |
303 } | |
304 | |
305 chunksize = encode_frame(s, pict, buf); | |
306 | |
307 /* save the current frame */ | |
308 av_picture_copy(&s->previous_frame, (AVPicture *)p, avctx->pix_fmt, avctx->width, avctx->height); | |
309 return chunksize; | |
310 } | |
311 | |
6517
48759bfbd073
Apply 'cold' attribute to init/uninit functions in libavcodec
zuxy
parents:
6204
diff
changeset
|
312 static av_cold int qtrle_encode_end(AVCodecContext *avctx) |
5195 | 313 { |
314 QtrleEncContext *s = avctx->priv_data; | |
315 | |
316 avpicture_free(&s->previous_frame); | |
317 av_free(s->rlecode_table); | |
318 av_free(s->length_table); | |
319 av_free(s->skip_table); | |
320 return 0; | |
321 } | |
322 | |
323 AVCodec qtrle_encoder = { | |
324 "qtrle", | |
11560
8a4984c5cacc
Define AVMediaType enum, and use it instead of enum CodecType, which
stefano
parents:
11505
diff
changeset
|
325 AVMEDIA_TYPE_VIDEO, |
5195 | 326 CODEC_ID_QTRLE, |
327 sizeof(QtrleEncContext), | |
328 qtrle_encode_init, | |
329 qtrle_encode_frame, | |
330 qtrle_encode_end, | |
11505 | 331 .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
|
332 .long_name = NULL_IF_CONFIG_SMALL("QuickTime Animation (RLE) video"), |
5195 | 333 }; |