Three.js видео текстуры отображения низкого качества / разрешения
Я собираюсь создать видеоплеер с панорамным обзором 360 с управлением ориентацией устройства для Android и IOS с помощью cocoon.js и three.js.
Я успешно построил демонстрацию на примерах на сайте threejs.org, но столкнулся с проблемой: мой исходный тестовый видеофайл имеет разрешение 4000x1618 и всего 30 секунд. Загрузка это делает слышимый голос, но нет изображения. Однако, если я попытаюсь с файлом, преобразованным в 720x292, то он прекрасно работает как на Android, так и на iOS! К сожалению, это более низкое разрешение. видеофайл слишком плохого качества, но если я попытаюсь загрузить еще один файл большего размера, он будет воспроизводить только звук и изображение не будет снова.
Я нашел эти журналы ошибок в adb logcat при запуске фильма:
E/OMXNodeInstance( 124): setParameter(4b:Nvidia.h264.decode, ParamPortDefinition(0x2000001)
W/ACodec ( 124): [OMX.Nvidia.h264.decode] setting nBufferCountActual to 13 failed: -1010
Мой код:
<!DOCTYPE html>
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
<script src='cordova.js'></script>
<script src='js/three.js'></script>
<script src='js/OrbitControls.js'></script>
<script src='js/PointerLockControls.js'></script>
<script src='js/DeviceOrientationControls.js'></script>
<script src='js/stats.min.js'></script>
<body style='margin: 0px;; overflow: hidden; text-align:center;'>
<div id="btn" style='background: red; width: 200px; height: 200px; position: absolute; z-index: 1000;' onclick="start_video()">START VIDEÓ</div>
<script>
var video = document.createElement('video');
video.loop = true;
video.src = 'heroes-new-720p.mp4';
function start_video() {
document.getElementById('btn').style.visibility = 'hidden';
video.play();
}
window.addEventListener('load', function() {
var renderer = new THREE.WebGLRenderer({
antialias : true,
});
renderer.setClearColor(new THREE.Color('lightgrey'), 1)
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
var onRenderFcts= [];
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.01, 1000);
camera.position.z = 3;
var texture = new THREE.VideoTexture( video );
texture.minFilter = THREE.LinearFilter;
texture.format = THREE.RGBFormat;
texture.generateMipmaps = false;
var controls = new THREE.OrbitControls(camera)
controls.target.copy(scene.position)
function onDeviceOrientation(event){
if( !event.alpha ) return;
controls.enabled = false
controls = new THREE.DeviceOrientationControls(camera);
controls.connect();
window.removeEventListener('deviceorientation', onDeviceOrientation, false);
renderer.domElement.addEventListener('click', function(){
var domElement = renderer.domElement
if(domElement.requestFullscreen) domElement.requestFullscreen();
else if(domElement.msRequestFullscreen) domElement.msRequestFullscreen();
else if(domElement.mozRequestFullScreen) domElement.mozRequestFullScreen();
else if(domElement.webkitRequestFullscreen) domElement.webkitRequestFullscreen();
}, false);
}
window.addEventListener('deviceorientation', onDeviceOrientation, false);
onRenderFcts.push(function(){
controls.update()
})
;(function(){
var geometry = new THREE.SphereGeometry(10, 32, 16);
var material = new THREE.MeshBasicMaterial({
// opacity : 0.5,
// transparent : true,
// side : THREE.DoubleSide,
map: texture
});
var mesh = new THREE.Mesh( geometry, material );
mesh.scale.x = -1
scene.add( mesh );
})()
onRenderFcts.push(function(){
onWindowResize();
renderable();
})
function renderable() {
if ( video.readyState === video.HAVE_ENOUGH_DATA ) {
renderer.render( scene, camera );
}
}
function onWindowResize(){
renderer.setSize( window.innerWidth, window.innerHeight )
camera.aspect = window.innerWidth / window.innerHeight
camera.updateProjectionMatrix()
}
window.addEventListener('resize', onWindowResize, false)
// run the rendering loop
var lastTimeMsec= null
requestAnimationFrame(function animate(nowMsec){
// keep looping
requestAnimationFrame( animate );
// measure time
lastTimeMsec = lastTimeMsec || nowMsec-1000/60
var deltaMsec = Math.min(200, nowMsec - lastTimeMsec)
lastTimeMsec = nowMsec
// call each update function
onRenderFcts.forEach(function(onRenderFct){
onRenderFct(deltaMsec/1000, nowMsec/1000)
})
})
})
</script>
</body>
ОБНОВЛЕНИЕ: С тех пор я понял, что проблема не в самом разрешении видео, а в размерах. Я создал версию оригинального видео 1920x1080, которая отлично работает, поэтому меня беспокоит только качество. Даже видео в формате Full HD со скоростью 16000 кбит / с выглядит довольно неровным на моем Nexus 7 и ipad 4, я уверен, что это должно быть лучше...
2 ответа
Ну, наконец, я понял, что ни одно из моих протестированных устройств (Moto G, Nexus 7, iPad4, HTC m8) не может обрабатывать видео как текстуру в сфере Three.js, которая больше, чем 1920x1080. Я не уверен в причине, но я нашел очень интересную статью о разрешениях для панорамного видео, которая также осветила проблему качества.
Короче говоря: в видео 360, ширина 2K видео в формате Full HD при 120 градусах становится шириной 682 пикселя, поэтому я считаю, что качество моих видео неудовлетворительное.
Вот статья, если кому-то интересно:
http://www.360heros.com/2015/02/4k-vr-360-video-what-is-it-and-how-can-i-produce-it/
Это не трижды и не связано. Разрешения выше 1080p не имеют смысла на мобильных экранах (кроме вашего случая использования), поэтому аппаратное обеспечение не поддерживает их (в большинстве случаев). Вы можете проверить, соответствует ли профиль h264 разрешению вашего видеофайла. Особый iphone очень требователен в случае неправильного кодирования!