UNPKG

jsvpx

Version:

Javascript implementation of libvpx

478 lines (317 loc) 11.7 kB
'use strict'; var MotionVector = require('../common/mv.js'); var filter = require('../common/filter.js'); var filter_block2d = filter.filter_block2d; var SPLITMV = 9; var idctllm = require('../common/idctllm.js'); var vp8_short_inv_walsh4x4_c = idctllm.vp8_short_inv_walsh4x4_c; var vp8_short_idct4x4llm_c = idctllm.vp8_short_idct4x4llm_c; var c_utils = require('../../util/c_utils.js'); var memset = c_utils.memset; var memcpy = c_utils.memcpy; //Keep from having to redeclare this var chroma_mv = [ MotionVector.create(), MotionVector.create(), MotionVector.create(), MotionVector.create() ]; //build_inter_predictors4b function predict_inter_emulated_edge(ctx, img, coeffs, coeffs_off, mbi, mb_col, mb_row) { var emul_block = ctx.frame_strg[0].img.img_data; var emul_block_off = ctx.frame_strg[0].img.img_data_off; var reference = 0; var reference_off = 0; var output = 0; var output_off = 0; var reference_offset = 0; var w = 0, h = 0, x = 0, y = 0, b = 0; var ref_frame = mbi.mbmi.ref_frame; var u = img.u, v = img.v; var u_off = img.u_off; var v_off = img.v_off; var full_pixel = (ctx.common.version === 3) + 0; x = mb_col << 4; y = mb_row << 4; w = ctx.mb_cols << 4; h = ctx.mb_rows << 4; output = img.y; output_off = img.y_off; reference_off = output_off + reference_offset; var mode = mbi.mbmi.y_mode; var mvs = mbi.bmi.mvs; reference_offset = ctx.ref_frame_offsets[ref_frame]; reference = ctx.ref_frame_offsets_[ref_frame]; // Luma for (b = 0; b < 16; b++) { var ymv; if (mode !== SPLITMV) ymv = mbi.mbmi.mv; else ymv = mvs[b]; recon_1_edge_block(output, output_off, emul_block, emul_block_off, reference, reference_off, img.stride, ymv, ctx.subpixel_filters, coeffs, coeffs_off, mbi, x, y, w, h, b); x += 4; output_off += 4; reference_off += 4; if ((b & 3) === 3) { x -= 16; y += 4; output_off += (img.stride << 2) - 16; reference_off += (img.stride << 2) - 16; } } x = mb_col << 4; y = mb_row << 4; // Chroma x >>= 1; y >>= 1; w >>= 1; h >>= 1; //if (mbi.mbmi.y_mode !== SPLITMV) //{ var uv_stride_4_8 = 4 * img.uv_stride - 8; for (b = 0; b < 4; b++) { recon_1_edge_block(u, u_off, emul_block, emul_block_off, reference, u_off + reference_offset, //u img.uv_stride, chroma_mv[b], ctx.subpixel_filters, coeffs, coeffs_off, mbi, x, y, w, h, b + 16); recon_1_edge_block(v, v_off, emul_block, emul_block_off, reference, v_off + reference_offset, //v img.uv_stride, chroma_mv[b], ctx.subpixel_filters, coeffs, coeffs_off, mbi, x, y, w, h, b + 20); u_off += 4; v_off += 4; x += 4; if ((b & 1) === 1) { x -= 8; y += 4; u_off += uv_stride_4_8; v_off += uv_stride_4_8; } } //} } function build_4x4uvmvs(mbi, full_pixel) { var mvs = mbi.bmi.mvs; for (var i = 0; i < 2; ++i) { for (var j = 0; j < 2; ++j) { var b = (i << 3) + (j << 1); var chroma_ptr = (i << 1) + j; var chroma_mv_cache = chroma_mv[chroma_ptr]; var temp = 0; temp = mvs[b].as_row_col[0] + mvs[b + 1].as_row_col[0] + mvs[b + 4].as_row_col[0] + mvs[b + 5].as_row_col[0]; if (temp < 0) temp -= 4; else temp += 4; chroma_mv_cache.as_row_col[0] = (temp / 8 ) | 0; temp = mvs[b].as_row_col[1] + mvs[b + 1].as_row_col[1] + mvs[b + 4].as_row_col[1] + mvs[b + 5].as_row_col[1]; if (temp < 0) temp -= 4; else temp += 4; chroma_mv_cache.as_row_col[1] = (temp / 8) | 0; if (full_pixel === 1) { chroma_mv_cache.as_int[0] &= 0xFFF8FFF8; } } } } function build_mc_border(dst, dst_off, src, src_off, stride, x, y, b_w, b_h, w, h) { var ref_row = 0; var ref_row_off = 0; /* Get a pointer to the start of the real data for this row */ ref_row = src; ref_row_off = src_off - x - y * stride; if (y >= h) ref_row_off += (h - 1) * stride; else if (y > 0) ref_row_off += y * stride; do { var left = 0, right = 0, copy = 0; if (x < 0) { left = -x; } else { left = 0; } if (left > b_w) left = b_w; if (x + b_w > w) right = x + b_w - w; if (right > b_w) right = b_w; copy = b_w - left - right; if (left > 0) memset(dst, dst_off, ref_row[ref_row_off], left); if (copy > 0) memcpy(dst, dst_off + left, ref_row, ref_row_off + x + left, copy); if (right > 0) memset(dst, dst_off + left + copy, ref_row[ref_row_off + w - 1], right); dst_off += stride; y++; if (y < h && y > 0) ref_row_off += stride; } while (--b_h); } var uvmv = MotionVector.create(); //Slowest thing :( function predict_inter(ctx, img, coeffs, coeffs_off, mbi) { var y, u , v; var y = u = v = img.y; var y_off = img.y_off; var u_off = img.u_off; var v_off = img.v_off; var reference; var reference_offset = 0; var full_pixel = (ctx.common.version === 3) + 0; var b = 0; var mbmi_cache = mbi.mbmi; var mode = mbmi_cache.y_mode; reference_offset = ctx.ref_frame_offsets[mbi.mbmi.ref_frame]; reference = ctx.ref_frame_offsets_[mbi.mbmi.ref_frame]; var stride = img.stride; var subpixel_filters = ctx.subpixel_filters; var mvs = mbi.bmi.mvs; var mv = mbmi_cache.mv; for (b = 0; b < 16; b++) { var ymv; if (mode !== SPLITMV) ymv = mv; else ymv = mvs[b]; recon_1_block(y, y_off, reference, y_off + reference_offset, stride, //y ymv, subpixel_filters, coeffs, coeffs_off, mbi, b); y_off += 4; if ((b & 3) === 3) y_off += (img.stride << 2) - 16; } var uv_stride = img.uv_stride; for (b = 0; b < 4; b++) { recon_1_block(u, u_off, reference, u_off + reference_offset, //u uv_stride, chroma_mv[b], subpixel_filters, coeffs, coeffs_off, mbi, b + 16); recon_1_block(v, v_off, reference, v_off + reference_offset, //v uv_stride, chroma_mv[b], subpixel_filters, coeffs, coeffs_off, mbi, b + 20); u_off += 4; v_off += 4; if ((b & 1) === 1) { u_off += (uv_stride << 2) - 8; v_off += (uv_stride << 2) - 8; } } } //build_inter_predictors2b function recon_1_block(output, output_off, reference, reference_off, stride, mv, filters, coeffs, coeffs_off, mbi, b) { var predict = reference; var predict_off = reference_off; var mx = 0, my = 0; if (mv.as_int[0]) { mx = mv.as_row_col[0] & 7; my = mv.as_row_col[1] & 7; reference_off += ((mv.as_row_col[1] >> 3) * stride) + (mv.as_row_col[0] >> 3); filter_block2d(output, output_off, stride, reference, reference_off, stride, 4, 4, mx, my, filters); predict = output; predict_off = output_off; } else { predict_off = reference_off; } vp8_short_idct4x4llm_c(output, output_off, predict, predict_off, stride, coeffs, coeffs_off + 16 * b); } function recon_1_edge_block(output, output_off, emul_block, emul_block_off, reference, reference_off, stride, mv_, filters, coeffs, coeffs_off, mbi, x, y, w, h, start_b) { var predict = reference; var predict_off = reference_off; var b = start_b; var b_w = 4; var b_h = 4; var mx = 0, my = 0; x += mv_.as_row_col[0] >> 3; y += mv_.as_row_col[1] >> 3; if (x < 2 || x + b_w - 1 + 3 >= w || y < 2 || y + b_h - 1 + 3 >= h) { reference_off += (mv_.as_row_col[0] >> 3) + (mv_.as_row_col[1] >> 3) * stride; build_mc_border(emul_block, emul_block_off, reference, reference_off - 2 - (stride << 1), stride, x - 2, y - 2, b_w + 5, b_h + 5, w, h); reference = emul_block; reference_off = emul_block_off + (stride << 1) + 2; reference_off -= (mv_.as_row_col[0] >> 3) + (mv_.as_row_col[1] >> 3) * stride; } if (mv_.as_int[0]) { mx = mv_.as_row_col[0] & 7; my = mv_.as_row_col[1] & 7; reference_off += ((mv_.as_row_col[1] >> 3) * stride) + (mv_.as_row_col[0] >> 3); filter_block2d(output, output_off, stride, reference, reference_off, stride, 4, 4, mx, my, filters); predict = output; predict_off = output_off; } else { reference_off += ((mv_.as_row_col[1] >> 3) * stride) + (mv_.as_row_col[0] >> 3); predict = reference; predict_off = reference_off; } vp8_short_idct4x4llm_c(output, output_off, predict, predict_off, stride, coeffs, coeffs_off + 16 * b); } function build_inter4x4_predictors_mb(){ } function vp8_build_inter16x16_predictors_mb(mbi, full_pixel) { var mbmi_cache = mbi.mbmi; uvmv.as_int[0] = mbmi_cache.mv.as_int[0]; if (mbi.mbmi.need_mc_border === 1) { var x = uvmv.as_row_col[0]; var y = uvmv.as_row_col[1] ; uvmv.as_row_col[0] = (x + 1 + ((x >> 31) << 1)) / 2; uvmv.as_row_col[1] = (y + 1 + ((y >> 31) << 1)) / 2; } else { uvmv.as_row_col[0] = (uvmv.as_row_col[0] + 1) >> 1; uvmv.as_row_col[1] = (uvmv.as_row_col[1] + 1) >> 1; } if (full_pixel) { uvmv.as_int[0] &= 0xFFF8FFF8; } chroma_mv[0].as_int[0] = chroma_mv[1].as_int[0] = chroma_mv[2].as_int[0] = chroma_mv[3].as_int[0] = uvmv.as_int[0]; } //xd->subpixel_predict8x8 = vp8_sixtap_predict8x8; function vp8_build_inter_predictors_mb(ctx, img, coeffs, coeffs_off, mbi, mb_col, mb_row) { var y, u, v; var y = u = v = img.y; var y_off = img.y_off; var u_off = img.u_off; var v_off = img.v_off; var reference; var reference_offset = 0; var full_pixel = (ctx.common.version === 3) + 0; var b = 0; var mbmi_cache = mbi.mbmi; if (mbmi_cache.y_mode !== SPLITMV) { vp8_short_inv_walsh4x4_c(coeffs, coeffs_off + 384, coeffs_off); vp8_build_inter16x16_predictors_mb(mbi, full_pixel); } else { build_4x4uvmvs(mbi, full_pixel); build_inter4x4_predictors_mb(); } if (mbi.mbmi.need_mc_border === 1) predict_inter_emulated_edge(ctx, img, coeffs, coeffs_off, mbi, mb_col, mb_row); else predict_inter(ctx, img, coeffs, coeffs_off, mbi); } module.exports = {}; module.exports.predict_inter_emulated_edge = predict_inter_emulated_edge; module.exports.predict_inter = predict_inter; module.exports.vp8_build_inter_predictors_mb = vp8_build_inter_predictors_mb;