bp2008 / ui3

A powerful, modern HTML5 web interface for Blue Iris.
GNU Lesser General Public License v3.0
120 stars 18 forks source link

Add Picture-in-Picture button #68

Closed editter closed 3 years ago

editter commented 3 years ago

Hello,

I was wondering if you would be interested in adding Picture-in-Picture support to UI3.

I did a basic proof of concept and simply running await document.getElementById("html5MseVideoEle").requestPictureInPicture() works so maybe adding a button to #pcButtonContainer would make sense?

I was also thinking that you could use the media controls for the Picture-in-Picture windows for previoustrack/nexttrack to cycle through the available cameras?

https://developers.google.com/web/updates/2018/10/watch-video-using-picture-in-picture

bp2008 commented 3 years ago

Thanks for the suggestion. Consider it on the todo list.

editter commented 3 years ago

I put together something that works in the ui3-local-overrides.js file but I'm sure there are better approaches that could be used.

(function () {

  if ('pictureInPictureEnabled' in document) {
    const icon = '<svg class="icon noflip" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M19 7h-8v6h8V7zm2-4H3c-1.1 0-2 .9-2 2v14c0 1.1.9 1.98 2 1.98h18c1.1 0 2-.88 2-1.98V5c0-1.1-.9-2-2-2zm0 16.01H3V4.98h18v14.03z"/></svg>';
    var btn = $('<div class="pcButton rightSide showWhenLive" title="Toggle Picture-in-Picture">' + icon + '</div>')
    btn.on('click', async function () {
      const video = document.getElementById("html5MseVideoEle");
      if (video !== document.pictureInPictureElement) {
        await video.requestPictureInPicture();
      } else {
        await document.exitPictureInPicture();
      }
    });

    $("#prioritizeTriggeredButton").after(btn);

    navigator.mediaSession.setActionHandler('previoustrack', function () {
      // maybe determine if its a group or a camera and respond accordingly
      BI_Hotkey_PreviousCamera()
    });

    navigator.mediaSession.setActionHandler('nexttrack', function () {
      // maybe determine if its a group or a camera and respond accordingly
      BI_Hotkey_NextCamera()
    });

    navigator.mediaSession.setActionHandler('play', function () {
      // Reset to default group view
      videoPlayer.SelectCameraGroup(settings.ui3_defaultCameraGroupId);
    });

    navigator.mediaSession.setActionHandler('pause', function () {
      // Reset to default group view
      videoPlayer.SelectCameraGroup(settings.ui3_defaultCameraGroupId);
    });
  }
})();
bp2008 commented 3 years ago

I appreciate your efforts here. This will be useful as a working example when I get around to implementing it directly.

I'm not sure if I should show the button by default or not. I could hide the button by default but have Picture in Picture as a context menu option.

bp2008 commented 3 years ago

Implemented in UI3-148!!

Thank you for the suggestion and the example.

My implementation includes a much fuller usage of the MediaSession API, and I only tested in Chrome on Windows so I would not be surprised if something is broken in other browsers or on mobile devices. Chrome for example would not accept Infinity as a value for duration or position even though the draft spec suggests to use these during a live stream -- so during a live stream I told it the duration and position are 86400.