📄 dnxhdenc.c
字号:
dsp->get_pixels(ctx->blocks[7], ptr_v + ctx->dct_uv_offset , ctx->m.uvlinesize); }}static av_always_inline int dnxhd_switch_matrix(DNXHDEncContext *ctx, int i){ if (i&2) { ctx->m.q_intra_matrix16 = ctx->qmatrix_c16; ctx->m.q_intra_matrix = ctx->qmatrix_c; return 1 + (i&1); } else { ctx->m.q_intra_matrix16 = ctx->qmatrix_l16; ctx->m.q_intra_matrix = ctx->qmatrix_l; return 0; }}static int dnxhd_calc_bits_thread(AVCodecContext *avctx, void *arg){ DNXHDEncContext *ctx = arg; int mb_y, mb_x; int qscale = ctx->thread[0]->qscale; for (mb_y = ctx->m.start_mb_y; mb_y < ctx->m.end_mb_y; mb_y++) { ctx->m.last_dc[0] = ctx->m.last_dc[1] = ctx->m.last_dc[2] = 1024; for (mb_x = 0; mb_x < ctx->m.mb_width; mb_x++) { unsigned mb = mb_y * ctx->m.mb_width + mb_x; int ssd = 0; int ac_bits = 0; int dc_bits = 0; int i; dnxhd_get_blocks(ctx, mb_x, mb_y); for (i = 0; i < 8; i++) { DECLARE_ALIGNED_16(DCTELEM, block[64]); DCTELEM *src_block = ctx->blocks[i]; int overflow, nbits, diff, last_index; int n = dnxhd_switch_matrix(ctx, i); memcpy(block, src_block, sizeof(block)); last_index = ctx->m.dct_quantize((MpegEncContext*)ctx, block, i, qscale, &overflow); ac_bits += dnxhd_calc_ac_bits(ctx, block, last_index); diff = block[0] - ctx->m.last_dc[n]; if (diff < 0) nbits = av_log2_16bit(-2*diff); else nbits = av_log2_16bit( 2*diff); dc_bits += ctx->cid_table->dc_bits[nbits] + nbits; ctx->m.last_dc[n] = block[0]; if (avctx->mb_decision == FF_MB_DECISION_RD || !RC_VARIANCE) { dnxhd_unquantize_c(ctx, block, i, qscale, last_index); ctx->m.dsp.idct(block); ssd += dnxhd_ssd_block(block, src_block); } } ctx->mb_rc[qscale][mb].ssd = ssd; ctx->mb_rc[qscale][mb].bits = ac_bits+dc_bits+12+8*ctx->table_vlc_bits[0]; } } return 0;}static int dnxhd_encode_thread(AVCodecContext *avctx, void *arg){ DNXHDEncContext *ctx = arg; int mb_y, mb_x; for (mb_y = ctx->m.start_mb_y; mb_y < ctx->m.end_mb_y; mb_y++) { ctx->m.last_dc[0] = ctx->m.last_dc[1] = ctx->m.last_dc[2] = 1024; for (mb_x = 0; mb_x < ctx->m.mb_width; mb_x++) { unsigned mb = mb_y * ctx->m.mb_width + mb_x; int qscale = ctx->mb_qscale[mb]; int i; put_bits(&ctx->m.pb, 12, qscale<<1); dnxhd_get_blocks(ctx, mb_x, mb_y); for (i = 0; i < 8; i++) { DCTELEM *block = ctx->blocks[i]; int last_index, overflow; int n = dnxhd_switch_matrix(ctx, i); last_index = ctx->m.dct_quantize((MpegEncContext*)ctx, block, i, qscale, &overflow); dnxhd_encode_block(ctx, block, last_index, n); } } if (put_bits_count(&ctx->m.pb)&31) put_bits(&ctx->m.pb, 32-(put_bits_count(&ctx->m.pb)&31), 0); } flush_put_bits(&ctx->m.pb); return 0;}static void dnxhd_setup_threads_slices(DNXHDEncContext *ctx, uint8_t *buf){ int mb_y, mb_x; int i, offset = 0; for (i = 0; i < ctx->m.avctx->thread_count; i++) { int thread_size = 0; for (mb_y = ctx->thread[i]->m.start_mb_y; mb_y < ctx->thread[i]->m.end_mb_y; mb_y++) { ctx->slice_size[mb_y] = 0; for (mb_x = 0; mb_x < ctx->m.mb_width; mb_x++) { unsigned mb = mb_y * ctx->m.mb_width + mb_x; ctx->slice_size[mb_y] += ctx->mb_bits[mb]; } ctx->slice_size[mb_y] = (ctx->slice_size[mb_y]+31)&~31; ctx->slice_size[mb_y] >>= 3; thread_size += ctx->slice_size[mb_y]; } init_put_bits(&ctx->thread[i]->m.pb, buf + 640 + offset, thread_size); offset += thread_size; }}static int dnxhd_mb_var_thread(AVCodecContext *avctx, void *arg){ DNXHDEncContext *ctx = arg; int mb_y, mb_x; for (mb_y = ctx->m.start_mb_y; mb_y < ctx->m.end_mb_y; mb_y++) { for (mb_x = 0; mb_x < ctx->m.mb_width; mb_x++) { unsigned mb = mb_y * ctx->m.mb_width + mb_x; uint8_t *pix = ctx->thread[0]->src[0] + ((mb_y<<4) * ctx->m.linesize) + (mb_x<<4); int sum = ctx->m.dsp.pix_sum(pix, ctx->m.linesize); int varc = (ctx->m.dsp.pix_norm1(pix, ctx->m.linesize) - (((unsigned)(sum*sum))>>8)+128)>>8; ctx->mb_cmp[mb].value = varc; ctx->mb_cmp[mb].mb = mb; } } return 0;}static int dnxhd_encode_rdo(AVCodecContext *avctx, DNXHDEncContext *ctx){ int lambda, up_step, down_step; int last_lower = INT_MAX, last_higher = 0; int x, y, q; for (q = 1; q < avctx->qmax; q++) { ctx->qscale = q; avctx->execute(avctx, dnxhd_calc_bits_thread, (void**)&ctx->thread[0], NULL, avctx->thread_count); } up_step = down_step = 2<<LAMBDA_FRAC_BITS; lambda = ctx->lambda; for (;;) { int bits = 0; int end = 0; if (lambda == last_higher) { lambda++; end = 1; // need to set final qscales/bits } for (y = 0; y < ctx->m.mb_height; y++) { for (x = 0; x < ctx->m.mb_width; x++) { unsigned min = UINT_MAX; int qscale = 1; int mb = y*ctx->m.mb_width+x; for (q = 1; q < avctx->qmax; q++) { unsigned score = ctx->mb_rc[q][mb].bits*lambda+(ctx->mb_rc[q][mb].ssd<<LAMBDA_FRAC_BITS); if (score < min) { min = score; qscale = q; } } bits += ctx->mb_rc[qscale][mb].bits; ctx->mb_qscale[mb] = qscale; ctx->mb_bits[mb] = ctx->mb_rc[qscale][mb].bits; } bits = (bits+31)&~31; // padding if (bits > ctx->frame_bits) break; } //dprintf(ctx->m.avctx, "lambda %d, up %u, down %u, bits %d, frame %d\n", // lambda, last_higher, last_lower, bits, ctx->frame_bits); if (end) { if (bits > ctx->frame_bits) return -1; break; } if (bits < ctx->frame_bits) { last_lower = FFMIN(lambda, last_lower); if (last_higher != 0) lambda = (lambda+last_higher)>>1; else lambda -= down_step; down_step *= 5; // XXX tune ? up_step = 1<<LAMBDA_FRAC_BITS; lambda = FFMAX(1, lambda); if (lambda == last_lower) break; } else { last_higher = FFMAX(lambda, last_higher); if (last_lower != INT_MAX) lambda = (lambda+last_lower)>>1; else lambda += up_step; up_step *= 5; down_step = 1<<LAMBDA_FRAC_BITS; } } //dprintf(ctx->m.avctx, "out lambda %d\n", lambda); ctx->lambda = lambda; return 0;}static int dnxhd_find_qscale(DNXHDEncContext *ctx){ int bits = 0; int up_step = 1; int down_step = 1; int last_higher = 0; int last_lower = INT_MAX; int qscale; int x, y; qscale = ctx->qscale; for (;;) { bits = 0; ctx->qscale = qscale; // XXX avoid recalculating bits ctx->m.avctx->execute(ctx->m.avctx, dnxhd_calc_bits_thread, (void**)&ctx->thread[0], NULL, ctx->m.avctx->thread_count); for (y = 0; y < ctx->m.mb_height; y++) { for (x = 0; x < ctx->m.mb_width; x++) bits += ctx->mb_rc[qscale][y*ctx->m.mb_width+x].bits; bits = (bits+31)&~31; // padding if (bits > ctx->frame_bits) break; } //dprintf(ctx->m.avctx, "%d, qscale %d, bits %d, frame %d, higher %d, lower %d\n", // ctx->m.avctx->frame_number, qscale, bits, ctx->frame_bits, last_higher, last_lower); if (bits < ctx->frame_bits) { if (qscale == 1) return 1; if (last_higher == qscale - 1) { qscale = last_higher; break; } last_lower = FFMIN(qscale, last_lower); if (last_higher != 0) qscale = (qscale+last_higher)>>1; else qscale -= down_step++; if (qscale < 1) qscale = 1; up_step = 1; } else { if (last_lower == qscale + 1) break; last_higher = FFMAX(qscale, last_higher); if (last_lower != INT_MAX) qscale = (qscale+last_lower)>>1; else qscale += up_step++; down_step = 1; if (qscale >= ctx->m.avctx->qmax) return -1; } } //dprintf(ctx->m.avctx, "out qscale %d\n", qscale); ctx->qscale = qscale; return 0;}static int dnxhd_rc_cmp(const void *a, const void *b){ return ((const RCCMPEntry *)b)->value - ((const RCCMPEntry *)a)->value;}static int dnxhd_encode_fast(AVCodecContext *avctx, DNXHDEncContext *ctx){ int max_bits = 0; int ret, x, y; if ((ret = dnxhd_find_qscale(ctx)) < 0) return -1; for (y = 0; y < ctx->m.mb_height; y++) { for (x = 0; x < ctx->m.mb_width; x++) { int mb = y*ctx->m.mb_width+x; int delta_bits; ctx->mb_qscale[mb] = ctx->qscale; ctx->mb_bits[mb] = ctx->mb_rc[ctx->qscale][mb].bits; max_bits += ctx->mb_rc[ctx->qscale][mb].bits; if (!RC_VARIANCE) { delta_bits = ctx->mb_rc[ctx->qscale][mb].bits-ctx->mb_rc[ctx->qscale+1][mb].bits; ctx->mb_cmp[mb].mb = mb; ctx->mb_cmp[mb].value = delta_bits ? ((ctx->mb_rc[ctx->qscale][mb].ssd-ctx->mb_rc[ctx->qscale+1][mb].ssd)*100)/delta_bits : INT_MIN; //avoid increasing qscale } } max_bits += 31; //worst padding } if (!ret) { if (RC_VARIANCE) avctx->execute(avctx, dnxhd_mb_var_thread, (void**)&ctx->thread[0], NULL, avctx->thread_count); qsort(ctx->mb_cmp, ctx->m.mb_num, sizeof(RCEntry), dnxhd_rc_cmp); for (x = 0; x < ctx->m.mb_num && max_bits > ctx->frame_bits; x++) { int mb = ctx->mb_cmp[x].mb; max_bits -= ctx->mb_rc[ctx->qscale][mb].bits - ctx->mb_rc[ctx->qscale+1][mb].bits; ctx->mb_qscale[mb] = ctx->qscale+1; ctx->mb_bits[mb] = ctx->mb_rc[ctx->qscale+1][mb].bits; } } return 0;}static void dnxhd_load_picture(DNXHDEncContext *ctx, const AVFrame *frame){ int i; for (i = 0; i < 3; i++) { ctx->frame.data[i] = frame->data[i]; ctx->frame.linesize[i] = frame->linesize[i]; } for (i = 0; i < ctx->m.avctx->thread_count; i++) { ctx->thread[i]->m.linesize = ctx->frame.linesize[0]<<ctx->interlaced; ctx->thread[i]->m.uvlinesize = ctx->frame.linesize[1]<<ctx->interlaced; ctx->thread[i]->dct_y_offset = ctx->m.linesize *8; ctx->thread[i]->dct_uv_offset = ctx->m.uvlinesize*8; } ctx->frame.interlaced_frame = frame->interlaced_frame; ctx->cur_field = frame->interlaced_frame && !frame->top_field_first;}static int dnxhd_encode_picture(AVCodecContext *avctx, unsigned char *buf, int buf_size, const void *data){ DNXHDEncContext *ctx = avctx->priv_data; int first_field = 1; int offset, i, ret; if (buf_size < ctx->cid_table->frame_size) { av_log(avctx, AV_LOG_ERROR, "output buffer is too small to compress picture\n"); return -1; } dnxhd_load_picture(ctx, data); encode_coding_unit: for (i = 0; i < 3; i++) { ctx->src[i] = ctx->frame.data[i]; if (ctx->interlaced && ctx->cur_field) ctx->src[i] += ctx->frame.linesize[i]; } dnxhd_write_header(avctx, buf); if (avctx->mb_decision == FF_MB_DECISION_RD) ret = dnxhd_encode_rdo(avctx, ctx); else ret = dnxhd_encode_fast(avctx, ctx); if (ret < 0) { av_log(avctx, AV_LOG_ERROR, "picture could not fit ratecontrol constraints\n"); return -1; } dnxhd_setup_threads_slices(ctx, buf); offset = 0; for (i = 0; i < ctx->m.mb_height; i++) { AV_WB32(ctx->msip + i * 4, offset); offset += ctx->slice_size[i]; assert(!(ctx->slice_size[i] & 3)); } avctx->execute(avctx, dnxhd_encode_thread, (void**)&ctx->thread[0], NULL, avctx->thread_count); AV_WB32(buf + ctx->cid_table->coding_unit_size - 4, 0x600DC0DE); // EOF if (ctx->interlaced && first_field) { first_field = 0; ctx->cur_field ^= 1; buf += ctx->cid_table->coding_unit_size; buf_size -= ctx->cid_table->coding_unit_size; goto encode_coding_unit; } return ctx->cid_table->frame_size;}static int dnxhd_encode_end(AVCodecContext *avctx){ DNXHDEncContext *ctx = avctx->priv_data; int i; av_freep(&ctx->table_vlc_codes); av_freep(&ctx->table_vlc_bits); av_freep(&ctx->table_run_codes); av_freep(&ctx->table_run_bits); av_freep(&ctx->mb_bits); av_freep(&ctx->mb_qscale); av_freep(&ctx->mb_rc); av_freep(&ctx->mb_cmp); av_freep(&ctx->slice_size); av_freep(&ctx->qmatrix_c); av_freep(&ctx->qmatrix_l); av_freep(&ctx->qmatrix_c16); av_freep(&ctx->qmatrix_l16); for (i = 1; i < avctx->thread_count; i++) av_freep(&ctx->thread[i]); return 0;}AVCodec dnxhd_encoder = { "dnxhd", CODEC_TYPE_VIDEO, CODEC_ID_DNXHD, sizeof(DNXHDEncContext), dnxhd_encode_init, dnxhd_encode_picture, dnxhd_encode_end, .pix_fmts = (enum PixelFormat[]){PIX_FMT_YUV422P, -1},};
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -