Как выбрать, какой 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. Есть ли способ сохранить обе видеодорожки в потоке, но выбрать, какая из них воспроизводится в данный момент в видеоэлементе?

Пока единственное, что сработало, это удалить одну из видеодорожек из потока, чтобы другая могла воспроизводиться, но я хотел бы сохранить обе видеодорожки в потоке, чтобы я мог переключать их ч/б.


person heartmo    schedule 20.12.2020    source источник


Ответы (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>

На сегодняшний день, что можно сделать в вашей ситуации, когда у вас есть доступ к MediaStream, так это создать новый MediaStream, содержащий только те 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>

person Kaiido    schedule 21.12.2020
comment
Спасибо, Кайидо. Будет хорошо, когда можно будет просто сделать VideoTrack.selected=true. - person heartmo; 21.12.2020
comment
Да, верно ... Также будьте осторожны, я отредактировал вопрос, поскольку вы его приняли, моя первая редакция полагалась на поведение Chrome и Firefox, но согласно спецификациям на это поведение нельзя полагаться, и действительно, Safari уже отклоняется от него. - person Kaiido; 21.12.2020