#javascript #video #mediastream #mediastreamtrack
#javascript #Видео #mediastream #mediastreamtrack
Вопрос:
У меня есть MediaStream
1 звуковая дорожка и 2 видеодорожки. Этот поток создается путем объединения аудио- и видеодорожки из navigator.mediaDevices.getUserMedia
с видеодорожкой из navigator.mediaDevices.getDisplayMedia
.
var camStream = await navigator.mediaDevices.getUserMedia({audio: true, video: true, width: "1280"});
var screenStream = await navigator.mediaDevices.getDisplayMedia({video: true, width: "1280"});
var screenTrack = screenStream.getVideoTracks()[0];
camStream.addTrack(screenTrack);
На данный момент camStream
имеет 1 звуковую дорожку и 2 видеодорожки.
У меня есть HTML-элемент <video id="local-video"></video>
, который я использую для воспроизведения потока, установив атрибут srcObject:
document.getElementById("local-video").srcObject = camStream;
Проблема в том, что я не могу выбрать, какой трек воспроизводится. Видеодорожка camStream всегда воспроизводится поверх видеодорожки screenStream. Есть ли способ сохранить обе видеодорожки в потоке, но выбрать, какая из них воспроизводится в данный момент в элементе video?
Пока единственное, что сработало, это удалить одну из видеодорожек из потока, чтобы другая могла воспроизводиться, но я бы хотел сохранить обе видеодорожки в потоке, чтобы я мог переключать их между ними.
Ответ №1:
MediaElement.videoTracks
И MediaElement.audioTracks
должно быть общим решением этой проблемы, но на сегодняшний день поддержка браузеров по-прежнему невелика, поскольку ни один браузер не поддерживает это официально, и никто вообще не поддерживает его с помощью MediaStreams…
Итак, ниже приведен фрагмент, показывающий, как это должно быть, но это на будущее.
const vid = document.querySelector("video");
const btn = document.querySelector("button");
const track1 = makeVideoTrack("red");
const track2 = makeVideoTrack("blue");
const stream = new MediaStream([track1, track2]);
vid.srcObject = stream;
btn.onclick = () => {
// setting one track to selected will unselect the previously selected one
// so we need to grab the current state to switch it
const state = vid.videoTracks[0].selected;
vid.videoTracks[1].selected = state;
vid.videoTracks[0].selected = !state;
};
function makeVideoTrack(color) {
const canvas = document.createElement("canvas");
const ctx = canvas.getContext("2d");
ctx.fillStyle = color;
let x = 0;
const anim = () => {
x = (x 1) % canvas.width;
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.fillRect(x-5, 0, 10, canvas.height);
requestAnimationFrame( anim );
};
anim();
return canvas.captureStream().getVideoTracks()[0];
}
<video controls autoplay muted></video>
<button>switch video track</button>
На сегодняшний день, что можно сделать в вашей ситуации, когда у вас есть доступ к медиапотоку, это создать новый медиапоток, содержащий только videoTrack
то, что вы хотите. (Может возникнуть соблазн просто изменить порядок этих дорожек, но это будет работать только в текущих Chrome и Firefox, и спецификации дают понять, что мы не должны полагаться на такое поведение)
const vid = document.querySelector("video");
const btn = document.querySelector("button");
const tracks = [makeVideoTrack("red"), makeVideoTrack("blue")];
let selected_index = 0;
vid.srcObject = new MediaStream([ tracks[selected_index] ]);
btn.onclick = () => {
selected_index = (selected_index 1) % tracks.length
vid.srcObject = new MediaStream([ tracks[selected_index] ]);
};
function makeVideoTrack(color) {
const canvas = document.createElement("canvas");
const ctx = canvas.getContext("2d");
ctx.fillStyle = color;
let x = 0;
const anim = () => {
x = (x 1) % canvas.width;
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.fillRect(x-5, 0, 10, canvas.height);
requestAnimationFrame( anim );
};
anim();
return canvas.captureStream().getVideoTracks()[0];
}
<video controls autoplay muted></video>
<button>switch video track</button>
Комментарии:
1. Спасибо Kaiido. Было бы неплохо, если бы вы могли просто сделать VideoTrack.selected = true.
2. Да, верно… Также будьте осторожны, я отредактировал вопрос с тех пор, как вы его приняли, моя первая редакция основывалась на поведении Chrome и Firefox, но в соответствии со спецификациями на это поведение полагаться не следует, и, действительно, Safari уже отклоняется от него.