Mercurial > libavcodec.hg
annotate dnxhdenc.c @ 10320:44f31c1c9acc libavcodec
Make sure that dv encoder initializes all encoded packet data.
The specification does not say which value to use for unused
parts, so fill all unused bytes with 0xff, which is consistent
with what DV usually uses for reserved or unused parts.
author | reimar |
---|---|
date | Tue, 29 Sep 2009 19:17:18 +0000 |
parents | 97f38ca4ed14 |
children | 59ec306245a4 |
rev | line source |
---|---|
5790 | 1 /* |
2 * VC3/DNxHD encoder | |
3 * Copyright (c) 2007 Baptiste Coudurier <baptiste dot coudurier at smartjog dot com> | |
4 * | |
5 * VC-3 encoder funded by the British Broadcasting Corporation | |
6 * | |
7 * This file is part of FFmpeg. | |
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 as published by the Free Software Foundation; either | |
12 * version 2.1 of the License, or (at your option) any later version. | |
13 * | |
14 * FFmpeg is distributed in the hope that it will be useful, | |
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
17 * Lesser General Public License for more details. | |
18 * | |
19 * You should have received a copy of the GNU Lesser General Public | |
20 * License along with FFmpeg; if not, write to the Free Software | |
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
22 */ | |
23 | |
24 //#define DEBUG | |
25 #define RC_VARIANCE 1 // use variance or ssd for fast rc | |
26 | |
27 #include "avcodec.h" | |
28 #include "dsputil.h" | |
29 #include "mpegvideo.h" | |
8294 | 30 #include "dnxhdenc.h" |
5790 | 31 |
32 int dct_quantize_c(MpegEncContext *s, DCTELEM *block, int n, int qscale, int *overflow); | |
33 | |
34 #define LAMBDA_FRAC_BITS 10 | |
35 | |
8302
f54976d6a8a5
Move get_pixels_8x4 before init func to avoid useless forward declaration.
bcoudurier
parents:
8301
diff
changeset
|
36 static av_always_inline void dnxhd_get_pixels_8x4(DCTELEM *restrict block, const uint8_t *pixels, int line_size) |
f54976d6a8a5
Move get_pixels_8x4 before init func to avoid useless forward declaration.
bcoudurier
parents:
8301
diff
changeset
|
37 { |
f54976d6a8a5
Move get_pixels_8x4 before init func to avoid useless forward declaration.
bcoudurier
parents:
8301
diff
changeset
|
38 int i; |
f54976d6a8a5
Move get_pixels_8x4 before init func to avoid useless forward declaration.
bcoudurier
parents:
8301
diff
changeset
|
39 for (i = 0; i < 4; i++) { |
f54976d6a8a5
Move get_pixels_8x4 before init func to avoid useless forward declaration.
bcoudurier
parents:
8301
diff
changeset
|
40 block[0] = pixels[0]; block[1] = pixels[1]; |
f54976d6a8a5
Move get_pixels_8x4 before init func to avoid useless forward declaration.
bcoudurier
parents:
8301
diff
changeset
|
41 block[2] = pixels[2]; block[3] = pixels[3]; |
f54976d6a8a5
Move get_pixels_8x4 before init func to avoid useless forward declaration.
bcoudurier
parents:
8301
diff
changeset
|
42 block[4] = pixels[4]; block[5] = pixels[5]; |
f54976d6a8a5
Move get_pixels_8x4 before init func to avoid useless forward declaration.
bcoudurier
parents:
8301
diff
changeset
|
43 block[6] = pixels[6]; block[7] = pixels[7]; |
f54976d6a8a5
Move get_pixels_8x4 before init func to avoid useless forward declaration.
bcoudurier
parents:
8301
diff
changeset
|
44 pixels += line_size; |
f54976d6a8a5
Move get_pixels_8x4 before init func to avoid useless forward declaration.
bcoudurier
parents:
8301
diff
changeset
|
45 block += 8; |
f54976d6a8a5
Move get_pixels_8x4 before init func to avoid useless forward declaration.
bcoudurier
parents:
8301
diff
changeset
|
46 } |
f54976d6a8a5
Move get_pixels_8x4 before init func to avoid useless forward declaration.
bcoudurier
parents:
8301
diff
changeset
|
47 memcpy(block , block- 8, sizeof(*block)*8); |
f54976d6a8a5
Move get_pixels_8x4 before init func to avoid useless forward declaration.
bcoudurier
parents:
8301
diff
changeset
|
48 memcpy(block+ 8, block-16, sizeof(*block)*8); |
f54976d6a8a5
Move get_pixels_8x4 before init func to avoid useless forward declaration.
bcoudurier
parents:
8301
diff
changeset
|
49 memcpy(block+16, block-24, sizeof(*block)*8); |
f54976d6a8a5
Move get_pixels_8x4 before init func to avoid useless forward declaration.
bcoudurier
parents:
8301
diff
changeset
|
50 memcpy(block+24, block-32, sizeof(*block)*8); |
f54976d6a8a5
Move get_pixels_8x4 before init func to avoid useless forward declaration.
bcoudurier
parents:
8301
diff
changeset
|
51 } |
f54976d6a8a5
Move get_pixels_8x4 before init func to avoid useless forward declaration.
bcoudurier
parents:
8301
diff
changeset
|
52 |
5790 | 53 static int dnxhd_init_vlc(DNXHDEncContext *ctx) |
54 { | |
6978 | 55 int i, j, level, run; |
56 int max_level = 1<<(ctx->cid_table->bit_depth+2); | |
5790 | 57 |
10137
9a670cfd1941
Rename CHECKED_ALLOC(Z) to FF_ALLOC(Z)_OR_GOTO and add context and label
ramiro
parents:
9618
diff
changeset
|
58 FF_ALLOCZ_OR_GOTO(ctx->m.avctx, ctx->vlc_codes, max_level*4*sizeof(*ctx->vlc_codes), fail); |
9a670cfd1941
Rename CHECKED_ALLOC(Z) to FF_ALLOC(Z)_OR_GOTO and add context and label
ramiro
parents:
9618
diff
changeset
|
59 FF_ALLOCZ_OR_GOTO(ctx->m.avctx, ctx->vlc_bits , max_level*4*sizeof(*ctx->vlc_bits ), fail); |
9a670cfd1941
Rename CHECKED_ALLOC(Z) to FF_ALLOC(Z)_OR_GOTO and add context and label
ramiro
parents:
9618
diff
changeset
|
60 FF_ALLOCZ_OR_GOTO(ctx->m.avctx, ctx->run_codes, 63*2 , fail); |
9a670cfd1941
Rename CHECKED_ALLOC(Z) to FF_ALLOC(Z)_OR_GOTO and add context and label
ramiro
parents:
9618
diff
changeset
|
61 FF_ALLOCZ_OR_GOTO(ctx->m.avctx, ctx->run_bits , 63 , fail); |
6978 | 62 |
6981 | 63 ctx->vlc_codes += max_level*2; |
64 ctx->vlc_bits += max_level*2; | |
6978 | 65 for (level = -max_level; level < max_level; level++) { |
66 for (run = 0; run < 2; run++) { | |
67 int index = (level<<1)|run; | |
68 int sign, offset = 0, alevel = level; | |
5790 | 69 |
6978 | 70 MASK_ABS(sign, alevel); |
71 if (alevel > 64) { | |
72 offset = (alevel-1)>>6; | |
73 alevel -= offset<<6; | |
74 } | |
75 for (j = 0; j < 257; j++) { | |
76 if (ctx->cid_table->ac_level[j] == alevel && | |
77 (!offset || (ctx->cid_table->ac_index_flag[j] && offset)) && | |
78 (!run || (ctx->cid_table->ac_run_flag [j] && run))) { | |
6981 | 79 assert(!ctx->vlc_codes[index]); |
6978 | 80 if (alevel) { |
6981 | 81 ctx->vlc_codes[index] = (ctx->cid_table->ac_codes[j]<<1)|(sign&1); |
82 ctx->vlc_bits [index] = ctx->cid_table->ac_bits[j]+1; | |
6978 | 83 } else { |
6981 | 84 ctx->vlc_codes[index] = ctx->cid_table->ac_codes[j]; |
85 ctx->vlc_bits [index] = ctx->cid_table->ac_bits [j]; | |
6978 | 86 } |
87 break; | |
88 } | |
89 } | |
90 assert(!alevel || j < 257); | |
91 if (offset) { | |
6981 | 92 ctx->vlc_codes[index] = (ctx->vlc_codes[index]<<ctx->cid_table->index_bits)|offset; |
93 ctx->vlc_bits [index]+= ctx->cid_table->index_bits; | |
6978 | 94 } |
95 } | |
5790 | 96 } |
97 for (i = 0; i < 62; i++) { | |
98 int run = ctx->cid_table->run[i]; | |
99 assert(run < 63); | |
6981 | 100 ctx->run_codes[run] = ctx->cid_table->run_codes[i]; |
101 ctx->run_bits [run] = ctx->cid_table->run_bits[i]; | |
5790 | 102 } |
103 return 0; | |
104 fail: | |
105 return -1; | |
106 } | |
107 | |
108 static int dnxhd_init_qmat(DNXHDEncContext *ctx, int lbias, int cbias) | |
109 { | |
110 // init first elem to 1 to avoid div by 0 in convert_matrix | |
111 uint16_t weight_matrix[64] = {1,}; // convert_matrix needs uint16_t* | |
112 int qscale, i; | |
113 | |
10137
9a670cfd1941
Rename CHECKED_ALLOC(Z) to FF_ALLOC(Z)_OR_GOTO and add context and label
ramiro
parents:
9618
diff
changeset
|
114 FF_ALLOCZ_OR_GOTO(ctx->m.avctx, ctx->qmatrix_l, (ctx->m.avctx->qmax+1) * 64 * sizeof(int) , fail); |
9a670cfd1941
Rename CHECKED_ALLOC(Z) to FF_ALLOC(Z)_OR_GOTO and add context and label
ramiro
parents:
9618
diff
changeset
|
115 FF_ALLOCZ_OR_GOTO(ctx->m.avctx, ctx->qmatrix_c, (ctx->m.avctx->qmax+1) * 64 * sizeof(int) , fail); |
9a670cfd1941
Rename CHECKED_ALLOC(Z) to FF_ALLOC(Z)_OR_GOTO and add context and label
ramiro
parents:
9618
diff
changeset
|
116 FF_ALLOCZ_OR_GOTO(ctx->m.avctx, ctx->qmatrix_l16, (ctx->m.avctx->qmax+1) * 64 * 2 * sizeof(uint16_t), fail); |
9a670cfd1941
Rename CHECKED_ALLOC(Z) to FF_ALLOC(Z)_OR_GOTO and add context and label
ramiro
parents:
9618
diff
changeset
|
117 FF_ALLOCZ_OR_GOTO(ctx->m.avctx, ctx->qmatrix_c16, (ctx->m.avctx->qmax+1) * 64 * 2 * sizeof(uint16_t), fail); |
5790 | 118 |
119 for (i = 1; i < 64; i++) { | |
120 int j = ctx->m.dsp.idct_permutation[ff_zigzag_direct[i]]; | |
5795 | 121 weight_matrix[j] = ctx->cid_table->luma_weight[i]; |
5790 | 122 } |
123 ff_convert_matrix(&ctx->m.dsp, ctx->qmatrix_l, ctx->qmatrix_l16, weight_matrix, | |
124 ctx->m.intra_quant_bias, 1, ctx->m.avctx->qmax, 1); | |
125 for (i = 1; i < 64; i++) { | |
126 int j = ctx->m.dsp.idct_permutation[ff_zigzag_direct[i]]; | |
5795 | 127 weight_matrix[j] = ctx->cid_table->chroma_weight[i]; |
5790 | 128 } |
129 ff_convert_matrix(&ctx->m.dsp, ctx->qmatrix_c, ctx->qmatrix_c16, weight_matrix, | |
130 ctx->m.intra_quant_bias, 1, ctx->m.avctx->qmax, 1); | |
131 for (qscale = 1; qscale <= ctx->m.avctx->qmax; qscale++) { | |
132 for (i = 0; i < 64; i++) { | |
133 ctx->qmatrix_l [qscale] [i] <<= 2; ctx->qmatrix_c [qscale] [i] <<= 2; | |
134 ctx->qmatrix_l16[qscale][0][i] <<= 2; ctx->qmatrix_l16[qscale][1][i] <<= 2; | |
135 ctx->qmatrix_c16[qscale][0][i] <<= 2; ctx->qmatrix_c16[qscale][1][i] <<= 2; | |
136 } | |
137 } | |
138 return 0; | |
139 fail: | |
140 return -1; | |
141 } | |
142 | |
143 static int dnxhd_init_rc(DNXHDEncContext *ctx) | |
144 { | |
10137
9a670cfd1941
Rename CHECKED_ALLOC(Z) to FF_ALLOC(Z)_OR_GOTO and add context and label
ramiro
parents:
9618
diff
changeset
|
145 FF_ALLOCZ_OR_GOTO(ctx->m.avctx, ctx->mb_rc, 8160*ctx->m.avctx->qmax*sizeof(RCEntry), fail); |
5790 | 146 if (ctx->m.avctx->mb_decision != FF_MB_DECISION_RD) |
10137
9a670cfd1941
Rename CHECKED_ALLOC(Z) to FF_ALLOC(Z)_OR_GOTO and add context and label
ramiro
parents:
9618
diff
changeset
|
147 FF_ALLOCZ_OR_GOTO(ctx->m.avctx, ctx->mb_cmp, ctx->m.mb_num*sizeof(RCCMPEntry), fail); |
5790 | 148 |
149 ctx->frame_bits = (ctx->cid_table->coding_unit_size - 640 - 4) * 8; | |
150 ctx->qscale = 1; | |
151 ctx->lambda = 2<<LAMBDA_FRAC_BITS; // qscale 2 | |
152 return 0; | |
153 fail: | |
154 return -1; | |
155 } | |
156 | |
157 static int dnxhd_encode_init(AVCodecContext *avctx) | |
158 { | |
159 DNXHDEncContext *ctx = avctx->priv_data; | |
160 int i, index; | |
161 | |
6041
bb4b486c6775
add bitrate helper to choose all dnxhd variants
bcoudurier
parents:
5972
diff
changeset
|
162 ctx->cid = ff_dnxhd_find_cid(avctx); |
5971 | 163 if (!ctx->cid || avctx->pix_fmt != PIX_FMT_YUV422P) { |
5790 | 164 av_log(avctx, AV_LOG_ERROR, "video parameters incompatible with DNxHD\n"); |
165 return -1; | |
166 } | |
6041
bb4b486c6775
add bitrate helper to choose all dnxhd variants
bcoudurier
parents:
5972
diff
changeset
|
167 av_log(avctx, AV_LOG_DEBUG, "cid %d\n", ctx->cid); |
5790 | 168 |
169 index = ff_dnxhd_get_cid_table(ctx->cid); | |
170 ctx->cid_table = &ff_dnxhd_cid_table[index]; | |
171 | |
172 ctx->m.avctx = avctx; | |
173 ctx->m.mb_intra = 1; | |
174 ctx->m.h263_aic = 1; | |
175 | |
8303 | 176 ctx->get_pixels_8x4_sym = dnxhd_get_pixels_8x4; |
177 | |
5790 | 178 dsputil_init(&ctx->m.dsp, avctx); |
179 ff_dct_common_init(&ctx->m); | |
8590 | 180 #if HAVE_MMX |
8303 | 181 ff_dnxhd_init_mmx(ctx); |
182 #endif | |
5790 | 183 if (!ctx->m.dct_quantize) |
184 ctx->m.dct_quantize = dct_quantize_c; | |
185 | |
186 ctx->m.mb_height = (avctx->height + 15) / 16; | |
187 ctx->m.mb_width = (avctx->width + 15) / 16; | |
188 | |
189 if (avctx->flags & CODEC_FLAG_INTERLACED_DCT) { | |
190 ctx->interlaced = 1; | |
191 ctx->m.mb_height /= 2; | |
192 } | |
193 | |
194 ctx->m.mb_num = ctx->m.mb_height * ctx->m.mb_width; | |
195 | |
196 if (avctx->intra_quant_bias != FF_DEFAULT_QUANT_BIAS) | |
197 ctx->m.intra_quant_bias = avctx->intra_quant_bias; | |
198 if (dnxhd_init_qmat(ctx, ctx->m.intra_quant_bias, 0) < 0) // XXX tune lbias/cbias | |
199 return -1; | |
200 | |
201 if (dnxhd_init_vlc(ctx) < 0) | |
202 return -1; | |
203 if (dnxhd_init_rc(ctx) < 0) | |
204 return -1; | |
205 | |
10137
9a670cfd1941
Rename CHECKED_ALLOC(Z) to FF_ALLOC(Z)_OR_GOTO and add context and label
ramiro
parents:
9618
diff
changeset
|
206 FF_ALLOCZ_OR_GOTO(ctx->m.avctx, ctx->slice_size, ctx->m.mb_height*sizeof(uint32_t), fail); |
9a670cfd1941
Rename CHECKED_ALLOC(Z) to FF_ALLOC(Z)_OR_GOTO and add context and label
ramiro
parents:
9618
diff
changeset
|
207 FF_ALLOCZ_OR_GOTO(ctx->m.avctx, ctx->mb_bits, ctx->m.mb_num *sizeof(uint16_t), fail); |
9a670cfd1941
Rename CHECKED_ALLOC(Z) to FF_ALLOC(Z)_OR_GOTO and add context and label
ramiro
parents:
9618
diff
changeset
|
208 FF_ALLOCZ_OR_GOTO(ctx->m.avctx, ctx->mb_qscale, ctx->m.mb_num *sizeof(uint8_t) , fail); |
5790 | 209 |
210 ctx->frame.key_frame = 1; | |
211 ctx->frame.pict_type = FF_I_TYPE; | |
212 ctx->m.avctx->coded_frame = &ctx->frame; | |
213 | |
214 if (avctx->thread_count > MAX_THREADS || (avctx->thread_count > ctx->m.mb_height)) { | |
215 av_log(avctx, AV_LOG_ERROR, "too many threads\n"); | |
216 return -1; | |
217 } | |
218 | |
219 ctx->thread[0] = ctx; | |
220 for (i = 1; i < avctx->thread_count; i++) { | |
221 ctx->thread[i] = av_malloc(sizeof(DNXHDEncContext)); | |
222 memcpy(ctx->thread[i], ctx, sizeof(DNXHDEncContext)); | |
223 } | |
224 | |
225 for (i = 0; i < avctx->thread_count; i++) { | |
226 ctx->thread[i]->m.start_mb_y = (ctx->m.mb_height*(i ) + avctx->thread_count/2) / avctx->thread_count; | |
227 ctx->thread[i]->m.end_mb_y = (ctx->m.mb_height*(i+1) + avctx->thread_count/2) / avctx->thread_count; | |
228 } | |
229 | |
230 return 0; | |
10137
9a670cfd1941
Rename CHECKED_ALLOC(Z) to FF_ALLOC(Z)_OR_GOTO and add context and label
ramiro
parents:
9618
diff
changeset
|
231 fail: //for FF_ALLOCZ_OR_GOTO |
5790 | 232 return -1; |
233 } | |
234 | |
235 static int dnxhd_write_header(AVCodecContext *avctx, uint8_t *buf) | |
236 { | |
237 DNXHDEncContext *ctx = avctx->priv_data; | |
238 const uint8_t header_prefix[5] = { 0x00,0x00,0x02,0x80,0x01 }; | |
239 | |
10186 | 240 memset(buf, 0, 640); |
241 | |
5790 | 242 memcpy(buf, header_prefix, 5); |
243 buf[5] = ctx->interlaced ? ctx->cur_field+2 : 0x01; | |
244 buf[6] = 0x80; // crc flag off | |
245 buf[7] = 0xa0; // reserved | |
246 AV_WB16(buf + 0x18, avctx->height); // ALPF | |
247 AV_WB16(buf + 0x1a, avctx->width); // SPL | |
248 AV_WB16(buf + 0x1d, avctx->height); // NAL | |
249 | |
250 buf[0x21] = 0x38; // FIXME 8 bit per comp | |
251 buf[0x22] = 0x88 + (ctx->frame.interlaced_frame<<2); | |
252 AV_WB32(buf + 0x28, ctx->cid); // CID | |
253 buf[0x2c] = ctx->interlaced ? 0 : 0x80; | |
254 | |
255 buf[0x5f] = 0x01; // UDL | |
256 | |
257 buf[0x167] = 0x02; // reserved | |
258 AV_WB16(buf + 0x16a, ctx->m.mb_height * 4 + 4); // MSIPS | |
259 buf[0x16d] = ctx->m.mb_height; // Ns | |
260 buf[0x16f] = 0x10; // reserved | |
261 | |
262 ctx->msip = buf + 0x170; | |
263 return 0; | |
264 } | |
265 | |
266 static av_always_inline void dnxhd_encode_dc(DNXHDEncContext *ctx, int diff) | |
267 { | |
268 int nbits; | |
269 if (diff < 0) { | |
270 nbits = av_log2_16bit(-2*diff); | |
271 diff--; | |
272 } else { | |
273 nbits = av_log2_16bit(2*diff); | |
274 } | |
275 put_bits(&ctx->m.pb, ctx->cid_table->dc_bits[nbits] + nbits, | |
276 (ctx->cid_table->dc_codes[nbits]<<nbits) + (diff & ((1 << nbits) - 1))); | |
277 } | |
278 | |
279 static av_always_inline void dnxhd_encode_block(DNXHDEncContext *ctx, DCTELEM *block, int last_index, int n) | |
280 { | |
281 int last_non_zero = 0; | |
282 int slevel, i, j; | |
283 | |
284 dnxhd_encode_dc(ctx, block[0] - ctx->m.last_dc[n]); | |
285 ctx->m.last_dc[n] = block[0]; | |
286 | |
287 for (i = 1; i <= last_index; i++) { | |
288 j = ctx->m.intra_scantable.permutated[i]; | |
289 slevel = block[j]; | |
290 if (slevel) { | |
291 int run_level = i - last_non_zero - 1; | |
6978 | 292 int rlevel = (slevel<<1)|!!run_level; |
6981 | 293 put_bits(&ctx->m.pb, ctx->vlc_bits[rlevel], ctx->vlc_codes[rlevel]); |
5790 | 294 if (run_level) |
6981 | 295 put_bits(&ctx->m.pb, ctx->run_bits[run_level], ctx->run_codes[run_level]); |
5790 | 296 last_non_zero = i; |
297 } | |
298 } | |
6981 | 299 put_bits(&ctx->m.pb, ctx->vlc_bits[0], ctx->vlc_codes[0]); // EOB |
5790 | 300 } |
301 | |
302 static av_always_inline void dnxhd_unquantize_c(DNXHDEncContext *ctx, DCTELEM *block, int n, int qscale, int last_index) | |
303 { | |
5795 | 304 const uint8_t *weight_matrix; |
5790 | 305 int level; |
306 int i; | |
307 | |
5795 | 308 weight_matrix = (n&2) ? ctx->cid_table->chroma_weight : ctx->cid_table->luma_weight; |
5790 | 309 |
310 for (i = 1; i <= last_index; i++) { | |
311 int j = ctx->m.intra_scantable.permutated[i]; | |
312 level = block[j]; | |
313 if (level) { | |
314 if (level < 0) { | |
5795 | 315 level = (1-2*level) * qscale * weight_matrix[i]; |
316 if (weight_matrix[i] != 32) | |
5790 | 317 level += 32; |
318 level >>= 6; | |
319 level = -level; | |
320 } else { | |
5795 | 321 level = (2*level+1) * qscale * weight_matrix[i]; |
322 if (weight_matrix[i] != 32) | |
5790 | 323 level += 32; |
324 level >>= 6; | |
325 } | |
326 block[j] = level; | |
327 } | |
328 } | |
329 } | |
330 | |
331 static av_always_inline int dnxhd_ssd_block(DCTELEM *qblock, DCTELEM *block) | |
332 { | |
333 int score = 0; | |
334 int i; | |
335 for (i = 0; i < 64; i++) | |
336 score += (block[i]-qblock[i])*(block[i]-qblock[i]); | |
337 return score; | |
338 } | |
339 | |
340 static av_always_inline int dnxhd_calc_ac_bits(DNXHDEncContext *ctx, DCTELEM *block, int last_index) | |
341 { | |
342 int last_non_zero = 0; | |
343 int bits = 0; | |
344 int i, j, level; | |
345 for (i = 1; i <= last_index; i++) { | |
346 j = ctx->m.intra_scantable.permutated[i]; | |
347 level = block[j]; | |
348 if (level) { | |
349 int run_level = i - last_non_zero - 1; | |
6981 | 350 bits += ctx->vlc_bits[(level<<1)|!!run_level]+ctx->run_bits[run_level]; |
5790 | 351 last_non_zero = i; |
352 } | |
353 } | |
354 return bits; | |
355 } | |
356 | |
357 static av_always_inline void dnxhd_get_blocks(DNXHDEncContext *ctx, int mb_x, int mb_y) | |
358 { | |
359 const uint8_t *ptr_y = ctx->thread[0]->src[0] + ((mb_y << 4) * ctx->m.linesize) + (mb_x << 4); | |
360 const uint8_t *ptr_u = ctx->thread[0]->src[1] + ((mb_y << 4) * ctx->m.uvlinesize) + (mb_x << 3); | |
361 const uint8_t *ptr_v = ctx->thread[0]->src[2] + ((mb_y << 4) * ctx->m.uvlinesize) + (mb_x << 3); | |
362 DSPContext *dsp = &ctx->m.dsp; | |
363 | |
364 dsp->get_pixels(ctx->blocks[0], ptr_y , ctx->m.linesize); | |
365 dsp->get_pixels(ctx->blocks[1], ptr_y + 8, ctx->m.linesize); | |
366 dsp->get_pixels(ctx->blocks[2], ptr_u , ctx->m.uvlinesize); | |
367 dsp->get_pixels(ctx->blocks[3], ptr_v , ctx->m.uvlinesize); | |
368 | |
5971 | 369 if (mb_y+1 == ctx->m.mb_height && ctx->m.avctx->height == 1080) { |
5790 | 370 if (ctx->interlaced) { |
8303 | 371 ctx->get_pixels_8x4_sym(ctx->blocks[4], ptr_y + ctx->dct_y_offset , ctx->m.linesize); |
372 ctx->get_pixels_8x4_sym(ctx->blocks[5], ptr_y + ctx->dct_y_offset + 8, ctx->m.linesize); | |
373 ctx->get_pixels_8x4_sym(ctx->blocks[6], ptr_u + ctx->dct_uv_offset , ctx->m.uvlinesize); | |
374 ctx->get_pixels_8x4_sym(ctx->blocks[7], ptr_v + ctx->dct_uv_offset , ctx->m.uvlinesize); | |
8292 | 375 } else { |
376 dsp->clear_block(ctx->blocks[4]); dsp->clear_block(ctx->blocks[5]); | |
377 dsp->clear_block(ctx->blocks[6]); dsp->clear_block(ctx->blocks[7]); | |
378 } | |
5790 | 379 } else { |
380 dsp->get_pixels(ctx->blocks[4], ptr_y + ctx->dct_y_offset , ctx->m.linesize); | |
381 dsp->get_pixels(ctx->blocks[5], ptr_y + ctx->dct_y_offset + 8, ctx->m.linesize); | |
382 dsp->get_pixels(ctx->blocks[6], ptr_u + ctx->dct_uv_offset , ctx->m.uvlinesize); | |
383 dsp->get_pixels(ctx->blocks[7], ptr_v + ctx->dct_uv_offset , ctx->m.uvlinesize); | |
384 } | |
385 } | |
386 | |
387 static av_always_inline int dnxhd_switch_matrix(DNXHDEncContext *ctx, int i) | |
388 { | |
389 if (i&2) { | |
390 ctx->m.q_intra_matrix16 = ctx->qmatrix_c16; | |
391 ctx->m.q_intra_matrix = ctx->qmatrix_c; | |
392 return 1 + (i&1); | |
393 } else { | |
394 ctx->m.q_intra_matrix16 = ctx->qmatrix_l16; | |
395 ctx->m.q_intra_matrix = ctx->qmatrix_l; | |
396 return 0; | |
397 } | |
398 } | |
399 | |
400 static int dnxhd_calc_bits_thread(AVCodecContext *avctx, void *arg) | |
401 { | |
8129
a9734fe0811e
Making it easier to send arbitrary structures as work orders to MT workers
romansh
parents:
7040
diff
changeset
|
402 DNXHDEncContext *ctx = *(void**)arg; |
5790 | 403 int mb_y, mb_x; |
404 int qscale = ctx->thread[0]->qscale; | |
405 | |
406 for (mb_y = ctx->m.start_mb_y; mb_y < ctx->m.end_mb_y; mb_y++) { | |
407 ctx->m.last_dc[0] = | |
408 ctx->m.last_dc[1] = | |
409 ctx->m.last_dc[2] = 1024; | |
410 | |
411 for (mb_x = 0; mb_x < ctx->m.mb_width; mb_x++) { | |
412 unsigned mb = mb_y * ctx->m.mb_width + mb_x; | |
413 int ssd = 0; | |
414 int ac_bits = 0; | |
415 int dc_bits = 0; | |
416 int i; | |
417 | |
418 dnxhd_get_blocks(ctx, mb_x, mb_y); | |
419 | |
420 for (i = 0; i < 8; i++) { | |
421 DECLARE_ALIGNED_16(DCTELEM, block[64]); | |
422 DCTELEM *src_block = ctx->blocks[i]; | |
423 int overflow, nbits, diff, last_index; | |
424 int n = dnxhd_switch_matrix(ctx, i); | |
425 | |
426 memcpy(block, src_block, sizeof(block)); | |
427 last_index = ctx->m.dct_quantize((MpegEncContext*)ctx, block, i, qscale, &overflow); | |
428 ac_bits += dnxhd_calc_ac_bits(ctx, block, last_index); | |
429 | |
430 diff = block[0] - ctx->m.last_dc[n]; | |
431 if (diff < 0) nbits = av_log2_16bit(-2*diff); | |
432 else nbits = av_log2_16bit( 2*diff); | |
433 dc_bits += ctx->cid_table->dc_bits[nbits] + nbits; | |
434 | |
435 ctx->m.last_dc[n] = block[0]; | |
436 | |
437 if (avctx->mb_decision == FF_MB_DECISION_RD || !RC_VARIANCE) { | |
438 dnxhd_unquantize_c(ctx, block, i, qscale, last_index); | |
439 ctx->m.dsp.idct(block); | |
440 ssd += dnxhd_ssd_block(block, src_block); | |
441 } | |
442 } | |
443 ctx->mb_rc[qscale][mb].ssd = ssd; | |
6981 | 444 ctx->mb_rc[qscale][mb].bits = ac_bits+dc_bits+12+8*ctx->vlc_bits[0]; |
5790 | 445 } |
446 } | |
447 return 0; | |
448 } | |
449 | |
450 static int dnxhd_encode_thread(AVCodecContext *avctx, void *arg) | |
451 { | |
8129
a9734fe0811e
Making it easier to send arbitrary structures as work orders to MT workers
romansh
parents:
7040
diff
changeset
|
452 DNXHDEncContext *ctx = *(void**)arg; |
5790 | 453 int mb_y, mb_x; |
454 | |
455 for (mb_y = ctx->m.start_mb_y; mb_y < ctx->m.end_mb_y; mb_y++) { | |
456 ctx->m.last_dc[0] = | |
457 ctx->m.last_dc[1] = | |
458 ctx->m.last_dc[2] = 1024; | |
459 for (mb_x = 0; mb_x < ctx->m.mb_width; mb_x++) { | |
460 unsigned mb = mb_y * ctx->m.mb_width + mb_x; | |
461 int qscale = ctx->mb_qscale[mb]; | |
462 int i; | |
463 | |
464 put_bits(&ctx->m.pb, 12, qscale<<1); | |
465 | |
466 dnxhd_get_blocks(ctx, mb_x, mb_y); | |
467 | |
468 for (i = 0; i < 8; i++) { | |
469 DCTELEM *block = ctx->blocks[i]; | |
470 int last_index, overflow; | |
471 int n = dnxhd_switch_matrix(ctx, i); | |
472 last_index = ctx->m.dct_quantize((MpegEncContext*)ctx, block, i, qscale, &overflow); | |
6978 | 473 //START_TIMER; |
5790 | 474 dnxhd_encode_block(ctx, block, last_index, n); |
6978 | 475 //STOP_TIMER("encode_block"); |
5790 | 476 } |
477 } | |
478 if (put_bits_count(&ctx->m.pb)&31) | |
479 put_bits(&ctx->m.pb, 32-(put_bits_count(&ctx->m.pb)&31), 0); | |
480 } | |
481 flush_put_bits(&ctx->m.pb); | |
482 return 0; | |
483 } | |
484 | |
485 static void dnxhd_setup_threads_slices(DNXHDEncContext *ctx, uint8_t *buf) | |
486 { | |
487 int mb_y, mb_x; | |
488 int i, offset = 0; | |
489 for (i = 0; i < ctx->m.avctx->thread_count; i++) { | |
490 int thread_size = 0; | |
491 for (mb_y = ctx->thread[i]->m.start_mb_y; mb_y < ctx->thread[i]->m.end_mb_y; mb_y++) { | |
492 ctx->slice_size[mb_y] = 0; | |
493 for (mb_x = 0; mb_x < ctx->m.mb_width; mb_x++) { | |
494 unsigned mb = mb_y * ctx->m.mb_width + mb_x; | |
495 ctx->slice_size[mb_y] += ctx->mb_bits[mb]; | |
496 } | |
497 ctx->slice_size[mb_y] = (ctx->slice_size[mb_y]+31)&~31; | |
498 ctx->slice_size[mb_y] >>= 3; | |
499 thread_size += ctx->slice_size[mb_y]; | |
500 } | |
501 init_put_bits(&ctx->thread[i]->m.pb, buf + 640 + offset, thread_size); | |
502 offset += thread_size; | |
503 } | |
504 } | |
505 | |
506 static int dnxhd_mb_var_thread(AVCodecContext *avctx, void *arg) | |
507 { | |
8129
a9734fe0811e
Making it easier to send arbitrary structures as work orders to MT workers
romansh
parents:
7040
diff
changeset
|
508 DNXHDEncContext *ctx = *(void**)arg; |
5790 | 509 int mb_y, mb_x; |
510 for (mb_y = ctx->m.start_mb_y; mb_y < ctx->m.end_mb_y; mb_y++) { | |
511 for (mb_x = 0; mb_x < ctx->m.mb_width; mb_x++) { | |
512 unsigned mb = mb_y * ctx->m.mb_width + mb_x; | |
513 uint8_t *pix = ctx->thread[0]->src[0] + ((mb_y<<4) * ctx->m.linesize) + (mb_x<<4); | |
514 int sum = ctx->m.dsp.pix_sum(pix, ctx->m.linesize); | |
515 int varc = (ctx->m.dsp.pix_norm1(pix, ctx->m.linesize) - (((unsigned)(sum*sum))>>8)+128)>>8; | |
516 ctx->mb_cmp[mb].value = varc; | |
517 ctx->mb_cmp[mb].mb = mb; | |
518 } | |
519 } | |
520 return 0; | |
521 } | |
522 | |
523 static int dnxhd_encode_rdo(AVCodecContext *avctx, DNXHDEncContext *ctx) | |
524 { | |
5802 | 525 int lambda, up_step, down_step; |
526 int last_lower = INT_MAX, last_higher = 0; | |
5790 | 527 int x, y, q; |
528 | |
529 for (q = 1; q < avctx->qmax; q++) { | |
530 ctx->qscale = q; | |
8129
a9734fe0811e
Making it easier to send arbitrary structures as work orders to MT workers
romansh
parents:
7040
diff
changeset
|
531 avctx->execute(avctx, dnxhd_calc_bits_thread, (void**)&ctx->thread[0], NULL, avctx->thread_count, sizeof(void*)); |
5790 | 532 } |
5802 | 533 up_step = down_step = 2<<LAMBDA_FRAC_BITS; |
5790 | 534 lambda = ctx->lambda; |
535 | |
536 for (;;) { | |
537 int bits = 0; | |
538 int end = 0; | |
5802 | 539 if (lambda == last_higher) { |
540 lambda++; | |
5790 | 541 end = 1; // need to set final qscales/bits |
542 } | |
543 for (y = 0; y < ctx->m.mb_height; y++) { | |
544 for (x = 0; x < ctx->m.mb_width; x++) { | |
545 unsigned min = UINT_MAX; | |
546 int qscale = 1; | |
547 int mb = y*ctx->m.mb_width+x; | |
548 for (q = 1; q < avctx->qmax; q++) { | |
549 unsigned score = ctx->mb_rc[q][mb].bits*lambda+(ctx->mb_rc[q][mb].ssd<<LAMBDA_FRAC_BITS); | |
550 if (score < min) { | |
551 min = score; | |
552 qscale = q; | |
553 } | |
554 } | |
555 bits += ctx->mb_rc[qscale][mb].bits; | |
556 ctx->mb_qscale[mb] = qscale; | |
557 ctx->mb_bits[mb] = ctx->mb_rc[qscale][mb].bits; | |
558 } | |
559 bits = (bits+31)&~31; // padding | |
560 if (bits > ctx->frame_bits) | |
561 break; | |
562 } | |
5802 | 563 //dprintf(ctx->m.avctx, "lambda %d, up %u, down %u, bits %d, frame %d\n", |
564 // lambda, last_higher, last_lower, bits, ctx->frame_bits); | |
5790 | 565 if (end) { |
566 if (bits > ctx->frame_bits) | |
567 return -1; | |
568 break; | |
569 } | |
570 if (bits < ctx->frame_bits) { | |
5802 | 571 last_lower = FFMIN(lambda, last_lower); |
572 if (last_higher != 0) | |
573 lambda = (lambda+last_higher)>>1; | |
574 else | |
575 lambda -= down_step; | |
576 down_step *= 5; // XXX tune ? | |
577 up_step = 1<<LAMBDA_FRAC_BITS; | |
578 lambda = FFMAX(1, lambda); | |
579 if (lambda == last_lower) | |
580 break; | |
5790 | 581 } else { |
5802 | 582 last_higher = FFMAX(lambda, last_higher); |
583 if (last_lower != INT_MAX) | |
584 lambda = (lambda+last_lower)>>1; | |
585 else | |
586 lambda += up_step; | |
587 up_step *= 5; | |
588 down_step = 1<<LAMBDA_FRAC_BITS; | |
5790 | 589 } |
590 } | |
5802 | 591 //dprintf(ctx->m.avctx, "out lambda %d\n", lambda); |
5790 | 592 ctx->lambda = lambda; |
593 return 0; | |
594 } | |
595 | |
596 static int dnxhd_find_qscale(DNXHDEncContext *ctx) | |
597 { | |
598 int bits = 0; | |
599 int up_step = 1; | |
600 int down_step = 1; | |
601 int last_higher = 0; | |
602 int last_lower = INT_MAX; | |
603 int qscale; | |
604 int x, y; | |
605 | |
606 qscale = ctx->qscale; | |
607 for (;;) { | |
608 bits = 0; | |
609 ctx->qscale = qscale; | |
610 // XXX avoid recalculating bits | |
8129
a9734fe0811e
Making it easier to send arbitrary structures as work orders to MT workers
romansh
parents:
7040
diff
changeset
|
611 ctx->m.avctx->execute(ctx->m.avctx, dnxhd_calc_bits_thread, (void**)&ctx->thread[0], NULL, ctx->m.avctx->thread_count, sizeof(void*)); |
5790 | 612 for (y = 0; y < ctx->m.mb_height; y++) { |
613 for (x = 0; x < ctx->m.mb_width; x++) | |
614 bits += ctx->mb_rc[qscale][y*ctx->m.mb_width+x].bits; | |
615 bits = (bits+31)&~31; // padding | |
616 if (bits > ctx->frame_bits) | |
617 break; | |
618 } | |
619 //dprintf(ctx->m.avctx, "%d, qscale %d, bits %d, frame %d, higher %d, lower %d\n", | |
620 // ctx->m.avctx->frame_number, qscale, bits, ctx->frame_bits, last_higher, last_lower); | |
621 if (bits < ctx->frame_bits) { | |
622 if (qscale == 1) | |
5969
c5d11f6f6a3d
fix corner case when qscale 1 bits < frame bits but max bits with worst padding > frame bits
bcoudurier
parents:
5802
diff
changeset
|
623 return 1; |
5790 | 624 if (last_higher == qscale - 1) { |
625 qscale = last_higher; | |
626 break; | |
627 } | |
628 last_lower = FFMIN(qscale, last_lower); | |
629 if (last_higher != 0) | |
630 qscale = (qscale+last_higher)>>1; | |
631 else | |
632 qscale -= down_step++; | |
633 if (qscale < 1) | |
634 qscale = 1; | |
635 up_step = 1; | |
636 } else { | |
637 if (last_lower == qscale + 1) | |
638 break; | |
639 last_higher = FFMAX(qscale, last_higher); | |
640 if (last_lower != INT_MAX) | |
641 qscale = (qscale+last_lower)>>1; | |
642 else | |
643 qscale += up_step++; | |
644 down_step = 1; | |
645 if (qscale >= ctx->m.avctx->qmax) | |
646 return -1; | |
647 } | |
648 } | |
649 //dprintf(ctx->m.avctx, "out qscale %d\n", qscale); | |
650 ctx->qscale = qscale; | |
651 return 0; | |
652 } | |
653 | |
10214
97f38ca4ed14
Use a custom radix sort implementation instead of qsort in dnxhd encoder.
reimar
parents:
10186
diff
changeset
|
654 #define BUCKET_BITS 8 |
97f38ca4ed14
Use a custom radix sort implementation instead of qsort in dnxhd encoder.
reimar
parents:
10186
diff
changeset
|
655 #define RADIX_PASSES 4 |
97f38ca4ed14
Use a custom radix sort implementation instead of qsort in dnxhd encoder.
reimar
parents:
10186
diff
changeset
|
656 #define NBUCKETS (1 << BUCKET_BITS) |
97f38ca4ed14
Use a custom radix sort implementation instead of qsort in dnxhd encoder.
reimar
parents:
10186
diff
changeset
|
657 |
97f38ca4ed14
Use a custom radix sort implementation instead of qsort in dnxhd encoder.
reimar
parents:
10186
diff
changeset
|
658 static inline int get_bucket(int value, int shift) |
97f38ca4ed14
Use a custom radix sort implementation instead of qsort in dnxhd encoder.
reimar
parents:
10186
diff
changeset
|
659 { |
97f38ca4ed14
Use a custom radix sort implementation instead of qsort in dnxhd encoder.
reimar
parents:
10186
diff
changeset
|
660 value >>= shift; |
97f38ca4ed14
Use a custom radix sort implementation instead of qsort in dnxhd encoder.
reimar
parents:
10186
diff
changeset
|
661 value &= NBUCKETS - 1; |
97f38ca4ed14
Use a custom radix sort implementation instead of qsort in dnxhd encoder.
reimar
parents:
10186
diff
changeset
|
662 return NBUCKETS - 1 - value; |
97f38ca4ed14
Use a custom radix sort implementation instead of qsort in dnxhd encoder.
reimar
parents:
10186
diff
changeset
|
663 } |
97f38ca4ed14
Use a custom radix sort implementation instead of qsort in dnxhd encoder.
reimar
parents:
10186
diff
changeset
|
664 |
97f38ca4ed14
Use a custom radix sort implementation instead of qsort in dnxhd encoder.
reimar
parents:
10186
diff
changeset
|
665 static void radix_count(const RCCMPEntry *data, int size, int buckets[RADIX_PASSES][NBUCKETS]) |
5790 | 666 { |
10214
97f38ca4ed14
Use a custom radix sort implementation instead of qsort in dnxhd encoder.
reimar
parents:
10186
diff
changeset
|
667 int i, j; |
97f38ca4ed14
Use a custom radix sort implementation instead of qsort in dnxhd encoder.
reimar
parents:
10186
diff
changeset
|
668 memset(buckets, 0, sizeof(buckets[0][0]) * RADIX_PASSES * NBUCKETS); |
97f38ca4ed14
Use a custom radix sort implementation instead of qsort in dnxhd encoder.
reimar
parents:
10186
diff
changeset
|
669 for (i = 0; i < size; i++) { |
97f38ca4ed14
Use a custom radix sort implementation instead of qsort in dnxhd encoder.
reimar
parents:
10186
diff
changeset
|
670 int v = data[i].value; |
97f38ca4ed14
Use a custom radix sort implementation instead of qsort in dnxhd encoder.
reimar
parents:
10186
diff
changeset
|
671 for (j = 0; j < RADIX_PASSES; j++) { |
97f38ca4ed14
Use a custom radix sort implementation instead of qsort in dnxhd encoder.
reimar
parents:
10186
diff
changeset
|
672 buckets[j][get_bucket(v, 0)]++; |
97f38ca4ed14
Use a custom radix sort implementation instead of qsort in dnxhd encoder.
reimar
parents:
10186
diff
changeset
|
673 v >>= BUCKET_BITS; |
97f38ca4ed14
Use a custom radix sort implementation instead of qsort in dnxhd encoder.
reimar
parents:
10186
diff
changeset
|
674 } |
97f38ca4ed14
Use a custom radix sort implementation instead of qsort in dnxhd encoder.
reimar
parents:
10186
diff
changeset
|
675 assert(!v); |
97f38ca4ed14
Use a custom radix sort implementation instead of qsort in dnxhd encoder.
reimar
parents:
10186
diff
changeset
|
676 } |
97f38ca4ed14
Use a custom radix sort implementation instead of qsort in dnxhd encoder.
reimar
parents:
10186
diff
changeset
|
677 for (j = 0; j < RADIX_PASSES; j++) { |
97f38ca4ed14
Use a custom radix sort implementation instead of qsort in dnxhd encoder.
reimar
parents:
10186
diff
changeset
|
678 int offset = size; |
97f38ca4ed14
Use a custom radix sort implementation instead of qsort in dnxhd encoder.
reimar
parents:
10186
diff
changeset
|
679 for (i = NBUCKETS - 1; i >= 0; i--) |
97f38ca4ed14
Use a custom radix sort implementation instead of qsort in dnxhd encoder.
reimar
parents:
10186
diff
changeset
|
680 buckets[j][i] = offset -= buckets[j][i]; |
97f38ca4ed14
Use a custom radix sort implementation instead of qsort in dnxhd encoder.
reimar
parents:
10186
diff
changeset
|
681 assert(!buckets[j][0]); |
97f38ca4ed14
Use a custom radix sort implementation instead of qsort in dnxhd encoder.
reimar
parents:
10186
diff
changeset
|
682 } |
97f38ca4ed14
Use a custom radix sort implementation instead of qsort in dnxhd encoder.
reimar
parents:
10186
diff
changeset
|
683 } |
97f38ca4ed14
Use a custom radix sort implementation instead of qsort in dnxhd encoder.
reimar
parents:
10186
diff
changeset
|
684 |
97f38ca4ed14
Use a custom radix sort implementation instead of qsort in dnxhd encoder.
reimar
parents:
10186
diff
changeset
|
685 static void radix_sort_pass(RCCMPEntry *dst, const RCCMPEntry *data, int size, int buckets[NBUCKETS], int pass) |
97f38ca4ed14
Use a custom radix sort implementation instead of qsort in dnxhd encoder.
reimar
parents:
10186
diff
changeset
|
686 { |
97f38ca4ed14
Use a custom radix sort implementation instead of qsort in dnxhd encoder.
reimar
parents:
10186
diff
changeset
|
687 int shift = pass * BUCKET_BITS; |
97f38ca4ed14
Use a custom radix sort implementation instead of qsort in dnxhd encoder.
reimar
parents:
10186
diff
changeset
|
688 int i; |
97f38ca4ed14
Use a custom radix sort implementation instead of qsort in dnxhd encoder.
reimar
parents:
10186
diff
changeset
|
689 for (i = 0; i < size; i++) { |
97f38ca4ed14
Use a custom radix sort implementation instead of qsort in dnxhd encoder.
reimar
parents:
10186
diff
changeset
|
690 int v = get_bucket(data[i].value, shift); |
97f38ca4ed14
Use a custom radix sort implementation instead of qsort in dnxhd encoder.
reimar
parents:
10186
diff
changeset
|
691 int pos = buckets[v]++; |
97f38ca4ed14
Use a custom radix sort implementation instead of qsort in dnxhd encoder.
reimar
parents:
10186
diff
changeset
|
692 dst[pos] = data[i]; |
97f38ca4ed14
Use a custom radix sort implementation instead of qsort in dnxhd encoder.
reimar
parents:
10186
diff
changeset
|
693 } |
97f38ca4ed14
Use a custom radix sort implementation instead of qsort in dnxhd encoder.
reimar
parents:
10186
diff
changeset
|
694 } |
97f38ca4ed14
Use a custom radix sort implementation instead of qsort in dnxhd encoder.
reimar
parents:
10186
diff
changeset
|
695 |
97f38ca4ed14
Use a custom radix sort implementation instead of qsort in dnxhd encoder.
reimar
parents:
10186
diff
changeset
|
696 static void radix_sort(RCCMPEntry *data, int size) |
97f38ca4ed14
Use a custom radix sort implementation instead of qsort in dnxhd encoder.
reimar
parents:
10186
diff
changeset
|
697 { |
97f38ca4ed14
Use a custom radix sort implementation instead of qsort in dnxhd encoder.
reimar
parents:
10186
diff
changeset
|
698 int buckets[RADIX_PASSES][NBUCKETS]; |
97f38ca4ed14
Use a custom radix sort implementation instead of qsort in dnxhd encoder.
reimar
parents:
10186
diff
changeset
|
699 RCCMPEntry *tmp = av_malloc(sizeof(*tmp) * size); |
97f38ca4ed14
Use a custom radix sort implementation instead of qsort in dnxhd encoder.
reimar
parents:
10186
diff
changeset
|
700 radix_count(data, size, buckets); |
97f38ca4ed14
Use a custom radix sort implementation instead of qsort in dnxhd encoder.
reimar
parents:
10186
diff
changeset
|
701 radix_sort_pass(tmp, data, size, buckets[0], 0); |
97f38ca4ed14
Use a custom radix sort implementation instead of qsort in dnxhd encoder.
reimar
parents:
10186
diff
changeset
|
702 radix_sort_pass(data, tmp, size, buckets[1], 1); |
97f38ca4ed14
Use a custom radix sort implementation instead of qsort in dnxhd encoder.
reimar
parents:
10186
diff
changeset
|
703 if (buckets[2][NBUCKETS - 1] || buckets[3][NBUCKETS - 1]) { |
97f38ca4ed14
Use a custom radix sort implementation instead of qsort in dnxhd encoder.
reimar
parents:
10186
diff
changeset
|
704 radix_sort_pass(tmp, data, size, buckets[2], 2); |
97f38ca4ed14
Use a custom radix sort implementation instead of qsort in dnxhd encoder.
reimar
parents:
10186
diff
changeset
|
705 radix_sort_pass(data, tmp, size, buckets[3], 3); |
97f38ca4ed14
Use a custom radix sort implementation instead of qsort in dnxhd encoder.
reimar
parents:
10186
diff
changeset
|
706 } |
97f38ca4ed14
Use a custom radix sort implementation instead of qsort in dnxhd encoder.
reimar
parents:
10186
diff
changeset
|
707 av_free(tmp); |
5790 | 708 } |
709 | |
5970 | 710 static int dnxhd_encode_fast(AVCodecContext *avctx, DNXHDEncContext *ctx) |
5790 | 711 { |
712 int max_bits = 0; | |
5969
c5d11f6f6a3d
fix corner case when qscale 1 bits < frame bits but max bits with worst padding > frame bits
bcoudurier
parents:
5802
diff
changeset
|
713 int ret, x, y; |
c5d11f6f6a3d
fix corner case when qscale 1 bits < frame bits but max bits with worst padding > frame bits
bcoudurier
parents:
5802
diff
changeset
|
714 if ((ret = dnxhd_find_qscale(ctx)) < 0) |
5790 | 715 return -1; |
716 for (y = 0; y < ctx->m.mb_height; y++) { | |
717 for (x = 0; x < ctx->m.mb_width; x++) { | |
718 int mb = y*ctx->m.mb_width+x; | |
719 int delta_bits; | |
720 ctx->mb_qscale[mb] = ctx->qscale; | |
721 ctx->mb_bits[mb] = ctx->mb_rc[ctx->qscale][mb].bits; | |
722 max_bits += ctx->mb_rc[ctx->qscale][mb].bits; | |
723 if (!RC_VARIANCE) { | |
724 delta_bits = ctx->mb_rc[ctx->qscale][mb].bits-ctx->mb_rc[ctx->qscale+1][mb].bits; | |
725 ctx->mb_cmp[mb].mb = mb; | |
726 ctx->mb_cmp[mb].value = delta_bits ? | |
727 ((ctx->mb_rc[ctx->qscale][mb].ssd-ctx->mb_rc[ctx->qscale+1][mb].ssd)*100)/delta_bits | |
728 : INT_MIN; //avoid increasing qscale | |
729 } | |
730 } | |
731 max_bits += 31; //worst padding | |
732 } | |
5969
c5d11f6f6a3d
fix corner case when qscale 1 bits < frame bits but max bits with worst padding > frame bits
bcoudurier
parents:
5802
diff
changeset
|
733 if (!ret) { |
5790 | 734 if (RC_VARIANCE) |
8129
a9734fe0811e
Making it easier to send arbitrary structures as work orders to MT workers
romansh
parents:
7040
diff
changeset
|
735 avctx->execute(avctx, dnxhd_mb_var_thread, (void**)&ctx->thread[0], NULL, avctx->thread_count, sizeof(void*)); |
10214
97f38ca4ed14
Use a custom radix sort implementation instead of qsort in dnxhd encoder.
reimar
parents:
10186
diff
changeset
|
736 radix_sort(ctx->mb_cmp, ctx->m.mb_num); |
5790 | 737 for (x = 0; x < ctx->m.mb_num && max_bits > ctx->frame_bits; x++) { |
738 int mb = ctx->mb_cmp[x].mb; | |
739 max_bits -= ctx->mb_rc[ctx->qscale][mb].bits - ctx->mb_rc[ctx->qscale+1][mb].bits; | |
740 ctx->mb_qscale[mb] = ctx->qscale+1; | |
741 ctx->mb_bits[mb] = ctx->mb_rc[ctx->qscale+1][mb].bits; | |
742 } | |
743 } | |
744 return 0; | |
745 } | |
746 | |
6218 | 747 static void dnxhd_load_picture(DNXHDEncContext *ctx, const AVFrame *frame) |
5790 | 748 { |
749 int i; | |
750 | |
751 for (i = 0; i < 3; i++) { | |
752 ctx->frame.data[i] = frame->data[i]; | |
753 ctx->frame.linesize[i] = frame->linesize[i]; | |
754 } | |
755 | |
756 for (i = 0; i < ctx->m.avctx->thread_count; i++) { | |
757 ctx->thread[i]->m.linesize = ctx->frame.linesize[0]<<ctx->interlaced; | |
758 ctx->thread[i]->m.uvlinesize = ctx->frame.linesize[1]<<ctx->interlaced; | |
759 ctx->thread[i]->dct_y_offset = ctx->m.linesize *8; | |
760 ctx->thread[i]->dct_uv_offset = ctx->m.uvlinesize*8; | |
761 } | |
762 | |
763 ctx->frame.interlaced_frame = frame->interlaced_frame; | |
764 ctx->cur_field = frame->interlaced_frame && !frame->top_field_first; | |
765 } | |
766 | |
9618
85ad5d68ec98
data parameter of dnxhd_encode_picture() should not be const.
diego
parents:
8590
diff
changeset
|
767 static int dnxhd_encode_picture(AVCodecContext *avctx, unsigned char *buf, int buf_size, void *data) |
5790 | 768 { |
769 DNXHDEncContext *ctx = avctx->priv_data; | |
770 int first_field = 1; | |
771 int offset, i, ret; | |
772 | |
773 if (buf_size < ctx->cid_table->frame_size) { | |
774 av_log(avctx, AV_LOG_ERROR, "output buffer is too small to compress picture\n"); | |
775 return -1; | |
776 } | |
777 | |
778 dnxhd_load_picture(ctx, data); | |
779 | |
780 encode_coding_unit: | |
781 for (i = 0; i < 3; i++) { | |
782 ctx->src[i] = ctx->frame.data[i]; | |
783 if (ctx->interlaced && ctx->cur_field) | |
784 ctx->src[i] += ctx->frame.linesize[i]; | |
785 } | |
786 | |
787 dnxhd_write_header(avctx, buf); | |
788 | |
789 if (avctx->mb_decision == FF_MB_DECISION_RD) | |
790 ret = dnxhd_encode_rdo(avctx, ctx); | |
791 else | |
5970 | 792 ret = dnxhd_encode_fast(avctx, ctx); |
5790 | 793 if (ret < 0) { |
794 av_log(avctx, AV_LOG_ERROR, "picture could not fit ratecontrol constraints\n"); | |
795 return -1; | |
796 } | |
797 | |
798 dnxhd_setup_threads_slices(ctx, buf); | |
799 | |
800 offset = 0; | |
801 for (i = 0; i < ctx->m.mb_height; i++) { | |
802 AV_WB32(ctx->msip + i * 4, offset); | |
803 offset += ctx->slice_size[i]; | |
804 assert(!(ctx->slice_size[i] & 3)); | |
805 } | |
806 | |
8129
a9734fe0811e
Making it easier to send arbitrary structures as work orders to MT workers
romansh
parents:
7040
diff
changeset
|
807 avctx->execute(avctx, dnxhd_encode_thread, (void**)&ctx->thread[0], NULL, avctx->thread_count, sizeof(void*)); |
5790 | 808 |
10186 | 809 assert(640 + offset + 4 <= ctx->cid_table->coding_unit_size); |
810 memset(buf + 640 + offset, 0, ctx->cid_table->coding_unit_size - 4 - offset - 640); | |
811 | |
5790 | 812 AV_WB32(buf + ctx->cid_table->coding_unit_size - 4, 0x600DC0DE); // EOF |
813 | |
814 if (ctx->interlaced && first_field) { | |
815 first_field = 0; | |
816 ctx->cur_field ^= 1; | |
817 buf += ctx->cid_table->coding_unit_size; | |
818 buf_size -= ctx->cid_table->coding_unit_size; | |
819 goto encode_coding_unit; | |
820 } | |
821 | |
6752 | 822 ctx->frame.quality = ctx->qscale*FF_QP2LAMBDA; |
823 | |
5790 | 824 return ctx->cid_table->frame_size; |
825 } | |
826 | |
827 static int dnxhd_encode_end(AVCodecContext *avctx) | |
828 { | |
829 DNXHDEncContext *ctx = avctx->priv_data; | |
6978 | 830 int max_level = 1<<(ctx->cid_table->bit_depth+2); |
5790 | 831 int i; |
832 | |
6981 | 833 av_free(ctx->vlc_codes-max_level*2); |
834 av_free(ctx->vlc_bits -max_level*2); | |
835 av_freep(&ctx->run_codes); | |
836 av_freep(&ctx->run_bits); | |
5790 | 837 |
838 av_freep(&ctx->mb_bits); | |
839 av_freep(&ctx->mb_qscale); | |
840 av_freep(&ctx->mb_rc); | |
841 av_freep(&ctx->mb_cmp); | |
842 av_freep(&ctx->slice_size); | |
843 | |
844 av_freep(&ctx->qmatrix_c); | |
845 av_freep(&ctx->qmatrix_l); | |
846 av_freep(&ctx->qmatrix_c16); | |
847 av_freep(&ctx->qmatrix_l16); | |
848 | |
849 for (i = 1; i < avctx->thread_count; i++) | |
850 av_freep(&ctx->thread[i]); | |
851 | |
852 return 0; | |
853 } | |
854 | |
855 AVCodec dnxhd_encoder = { | |
856 "dnxhd", | |
857 CODEC_TYPE_VIDEO, | |
858 CODEC_ID_DNXHD, | |
859 sizeof(DNXHDEncContext), | |
860 dnxhd_encode_init, | |
861 dnxhd_encode_picture, | |
862 dnxhd_encode_end, | |
10146
38cfe222e1a4
Mark all pix_fmts and supported_framerates compound literals as const.
reimar
parents:
10137
diff
changeset
|
863 .pix_fmts = (const enum PixelFormat[]){PIX_FMT_YUV422P, PIX_FMT_NONE}, |
7040
e943e1409077
Make AVCodec long_names definition conditional depending on CONFIG_SMALL.
stefano
parents:
6981
diff
changeset
|
864 .long_name = NULL_IF_CONFIG_SMALL("VC3/DNxHD"), |
5790 | 865 }; |