jsvpx
Version:
Javascript implementation of libvpx
350 lines (249 loc) • 8.97 kB
JavaScript
'use strict';
//var abs = Math.abs;
function abs(value ){
return (value ^ (value >> 31)) - (value >> 31);
}
function saturate_int8(x) {
//return min(max(x, -128), 127);
return Math.min(Math.max(x, -128), 127);
}
function saturate_uint8(x) {
//return min(max(x, 0), 255);
return Math.min(Math.max(x, 0), 255);
}
//possible vp8_simple_filter
function vp8_filter(pixels, pixels_off, stride, use_outer_taps) {
var stride2 = 2 * stride;
var p1 = pixels[pixels_off - stride2];
var p0 = pixels[pixels_off - stride];
var q0 = pixels[pixels_off];
var q1 = pixels[pixels_off + stride];
var a = 0;
var f1 = 0;
var f2 = 0;
a = 3 * (q0 - p0);
if (use_outer_taps)
a += saturate_int8(p1 - q1);
a = saturate_int8(a);
if((a + 4) > 127){
f1 = 15;
f2 = 15;
}else{
f1 = (a + 4) >> 3;
f2 = (a + 3) >> 3;
}
p0 = saturate_uint8(p0 + f2);
q0 = saturate_uint8(q0 - f1);
if (!use_outer_taps)
{
a = (f1 + 1) >> 1;
p1 = saturate_uint8(p1 + a);
q1 = saturate_uint8(q1 - a);
}
pixels[pixels_off - stride2] = p1;
pixels[pixels_off - stride] = p0;
pixels[pixels_off] = q0;
pixels[pixels_off + stride] = q1;
}
function vp8_filter_2(pixels, pixels_off, use_outer_taps) {
//console.warn(pixels_off);
var pixels_16 = pixels.data_16[(pixels_off - 2)/2];
var p1 = pixels_16 & 0xFF;
var p0 = (pixels_16 >> 8 )& 0xFF;
pixels_16 = pixels.data_16[(pixels_off)/2];
var q0 = pixels_16 & 0xFF;
var q1 = (pixels_16 >> 8 )& 0xFF;
var a = 0;
var f1 = 0;
var f2 = 0;
a = 3 * (q0 - p0);
if (use_outer_taps)
a += saturate_int8(p1 - q1);
a = saturate_int8(a);
if((a + 4) > 127){
f1 = 15;
f2 = 15;
}else{
f1 = (a + 4) >> 3;
f2 = (a + 3) >> 3;
}
p0 = saturate_uint8(p0 + f2);
q0 = saturate_uint8(q0 - f1);
if (!use_outer_taps)
{
a = (f1 + 1) >> 1;
p1 = saturate_uint8(p1 + a);
q1 = saturate_uint8(q1 - a);
}
pixels[pixels_off - 2] = p1;
pixels[pixels_off - 1] = p0;
pixels[pixels_off] = q0;
pixels[pixels_off + 1] = q1;
}
//vp8_loop_filter_simple_bh
function vp8_loop_filter_bhs_c(y, y_ptr, y_stride, blimit) {
vp8_loop_filter_simple_horizontal_edge_c(y, y_ptr + 4 * y_stride, y_stride, blimit);
vp8_loop_filter_simple_horizontal_edge_c(y, y_ptr + 8 * y_stride, y_stride, blimit);
vp8_loop_filter_simple_horizontal_edge_c(y, y_ptr + 12 * y_stride, y_stride, blimit);
}
//vp8_loop_filter_mbh_c
function vp8_loop_filter_simple_horizontal_edge_c(src, src_off, stride, filter_limit) {
var i = 0;
for (i = 0; i < 16; i++) {
if (simple_threshold(src, src_off, stride, filter_limit) === 1)
vp8_filter(src, src_off, stride, 1);
src_off += 1;
}
}
function simple_threshold(pixels, pixels_off, stride, filter_limit) {
var p1 = pixels[pixels_off - (stride << 1)];
var p0 = pixels[pixels_off - stride];
var q0 = pixels[pixels_off];
var q1 = pixels[pixels_off + stride];
return (((abs(p0 - q0) << 1) + (abs(p1 - q1) >> 1)) <= filter_limit) | 0;
}
function vp8_loop_filter_bvs_c(y, y_off, stride, b_limit) {
vp8_loop_filter_simple_vertical_edge_c(y, y_off + 4, stride, b_limit);
vp8_loop_filter_simple_vertical_edge_c(y, y_off + 8, stride, b_limit);
vp8_loop_filter_simple_vertical_edge_c(y, y_off + 12, stride, b_limit);
}
function vp8_loop_filter_simple_vertical_edge_c(src, src_off, stride, filter_limit) {
var i = 0;
for (i = 0; i < 16; i++) {
if (simple_threshold(src, src_off, 1, filter_limit))
vp8_filter(src, src_off, 1, 1);
src_off += stride;
}
}
/*
function vp8_loop_filter_simple_horizontal_edge_c(src, src_off, stride, filter_limit) {
var i = 0;
for (i = 0; i < 16; i++) {
if (simple_threshold(src, src_off, 1, filter_limit))
vp8_filter(src, src_off, 1, 1);
src_off += stride;
}
}
*/
function vp8_loop_filter_mbv(y, y_off, u_off, v_off, stride, uv_stride, edge_limit, interior_limit, hev_threshold) {
//vp8_loop_filter_mbv
filter_mb_v_edge(y, y_off, stride, edge_limit + 2,
interior_limit, hev_threshold, 2);
filter_mb_v_edge(y, u_off, uv_stride, edge_limit + 2,
interior_limit, hev_threshold, 1);
filter_mb_v_edge(y, v_off, uv_stride, edge_limit + 2,
interior_limit, hev_threshold, 1);
}
function filter_mb_v_edge(src,
src_off,
stride,
edge_limit,
interior_limit,
hev_threshold,
size) {
var i = 0;
var length = size << 3;
for (i = 0; i < length; i++) {
if (normal_threshold(src, src_off, 1, edge_limit, interior_limit)) {
if (high_edge_variance(src, src_off, 1, hev_threshold))
vp8_filter(src, src_off, 1 , 1);
else
filter_mb_edge(src, src_off, 1);
}
src_off += stride;
}
}
function normal_threshold(pixels, pixels_off, stride, E, I) {
if (simple_threshold(pixels, pixels_off, stride, 2 * E + I) === 0)
return 0;
var p3 = pixels[pixels_off - 4 * stride];
var p2 = pixels[pixels_off - 3 * stride];
if (abs(p3 - p2) > I)
return 0;
var p1 = pixels[pixels_off - 2 * stride];
if (abs(p2 - p1) > I)
return 0;
var p0 = pixels[pixels_off - stride];
if(abs(p1 - p0) > I)
return 0;
var q2 = pixels[pixels_off + 2 * stride];
var q3 = pixels[pixels_off + 3 * stride];
if(abs(q3 - q2) > I)
return 0;
var q0 = pixels[pixels_off];
var q1 = pixels[pixels_off + stride];
if(abs(q2 - q1) > I)
return 0;
return abs(q1 - q0) <= I;
}
//vp8_mbfilter
function filter_mb_edge(pixels, pixels_off, stride) {
//var p3 = pixels[pixels_off -4*stride];
var stride2 = stride << 1;
var stride3 = 3 * stride;
var p2 = pixels[pixels_off - stride3];
var p1 = pixels[pixels_off - stride2];
var p0 = pixels[pixels_off - stride];
var q0 = pixels[pixels_off];
var q1 = pixels[pixels_off + stride];
var q2 = pixels[pixels_off + stride2];
var w = 0, a = 0;
w = saturate_int8(saturate_int8(p1 - q1) + 3 * (q0 - p0));
a = (27 * w + 63) >> 7;
p0 = saturate_uint8(p0 + a);
q0 = saturate_uint8(q0 - a);
a = (18 * w + 63) >> 7;
p1 = saturate_uint8(p1 + a);
q1 = saturate_uint8(q1 - a);
a = (9 * w + 63) >> 7;
p2 = saturate_uint8(p2 + a);
q2 = saturate_uint8(q2 - a);
pixels[pixels_off - stride3] = p2;
pixels[pixels_off - stride2] = p1;
pixels[pixels_off - stride] = p0;
pixels[pixels_off] = q0;
pixels[pixels_off + stride] = q1;
pixels[pixels_off + stride2] = q2;
}
function high_edge_variance(pixels, pixels_off, stride, hev_threshold) {
var p1 = pixels[pixels_off - 2 * stride];
var p0 = pixels[pixels_off - stride];
if(abs(p1 - p0) > hev_threshold)
return 1;
var q0 = pixels[pixels_off];
var q1 = pixels[pixels_off + stride];
return abs(q1 - q0) > hev_threshold;
}
function vp8_loop_filter_bv_c(y, y_off, u_off, v_off, stride, uv_stride, edge_limit, interior_limit, hev_threshold) {
var dat = y;
filter_subblock_v_edge(y, y_off + 4, stride, edge_limit,
interior_limit, hev_threshold, 2);
filter_subblock_v_edge(dat, y_off + 8, stride, edge_limit,
interior_limit, hev_threshold, 2);
filter_subblock_v_edge(dat, y_off + 12, stride, edge_limit,
interior_limit, hev_threshold, 2);
filter_subblock_v_edge(dat, u_off + 4, uv_stride, edge_limit,
interior_limit, hev_threshold, 1);
filter_subblock_v_edge(dat, v_off + 4, uv_stride, edge_limit,
interior_limit, hev_threshold, 1);
}
function filter_subblock_v_edge(src, src_off, stride, edge_limit, interior_limit, hev_threshold, size) {
var i = 0;
var limit = 8 * size;
for (i = 0; i < limit; i++) {
if (normal_threshold(src, src_off, 1, edge_limit, interior_limit))
vp8_filter(src, src_off, 1, high_edge_variance(src, src_off, 1, hev_threshold));
src_off += stride;
}
}
module.exports = {};
module.exports.vp8_filter = vp8_filter;
module.exports.vp8_loop_filter_bhs_c = vp8_loop_filter_bhs_c;
module.exports.vp8_loop_filter_bvs_c = vp8_loop_filter_bvs_c;
module.exports.vp8_loop_filter_simple_horizontal_edge_c = vp8_loop_filter_simple_horizontal_edge_c;
module.exports.vp8_loop_filter_simple_vertical_edge_c = vp8_loop_filter_simple_vertical_edge_c;
module.exports.vp8_loop_filter_mbv = vp8_loop_filter_mbv;
module.exports.vp8_loop_filter_bv_c = vp8_loop_filter_bv_c;
module.exports.filter_mb_edge = filter_mb_edge;
module.exports.normal_threshold = normal_threshold;
module.exports.high_edge_variance = high_edge_variance;