4

I have video files hosted on the CDN, the video file is encrypted. So I need the decrypt it before play it in the browser. But the web video tag has no interface to modify the media stream.

So I want to run a proxy in the client side with javascript to proxy the media stream request, and decrypt the stream before feet to the video tag.

Is it possible?


By math-chen's answer, I have tryed below code, but when I paly it, the video keep spin and not render the frame like below image.

enter image description here

I use a very small unencrypted video file out.mp4, so it can be loaded by once.

<html>
    <video id="video" controls src="out.mp4">
    </video>

    <script>
        const video = document.querySelector('#video');
        const mediaSource = new MediaSource();
        video.src = URL.createObjectURL(mediaSource);
        mediaSource.addEventListener('sourceopen', sourceOpen);
        function sourceOpen() {
            var mime = 'video/mp4; codecs="avc1.42E01E, mp4a.40.2"'
            var sourceBuffer = mediaSource.addSourceBuffer(mime);
            fetchBuffer('out.mp4', buffer => {
                sourceBuffer.appendBuffer(buffer)
            })
        }

        function fetchBuffer (url, callback) {
            var xhr = new XMLHttpRequest;
            xhr.open('get', url);
            xhr.responseType = 'arraybuffer';
            xhr.onload = function () {
                callback(xhr.response);
            };
            xhr.send();
        }
    </script>    
</html>
LF00
  • 27,015
  • 29
  • 156
  • 295
  • How are you decrypting (is it a function that expects a bytes Array or something)? What do you get (returned) as output of decryption, again is an Array/Buffer? Are you **possibly** asking "How to play an Array (Buffer) of byte values using a video tag"? – VC.One Dec 17 '21 at 20:07
  • Did you encrypt the video yourself and uploaded on CDN? If yes, then [fragment](https://stackoverflow.com/a/42241121/15273968) the mp4s before the encryption. Or does the CDN deliver the videos in encrypted format? If yes, then you need to check if the CDN provides their on video player or JavaScript APIs to decode videos at client side before playing. – the Hutt Dec 20 '21 at 04:18
  • _"I want to proxy the media stream request, and decrypt the stream before feeding to the video tag"_ **(1)** Why not use the `Fetch` or `XMLHttpRequest` API to receive the stream data (it can only go into a Array as a buffer of bytes, I don't know if that fits into your decryption system). **(2)** If you have a complete video file decrypted (as Array) then you could convert to blob and use blob as `.src` of video tag. If you get only pieces at a time then use MSE to play what's available as it arrives from decryption. However MSE needs extra work (understand fMP4 format structure). – VC.One Dec 23 '21 at 17:22
  • PS: Try using PHP (_eg:_ use `readFile`) if Javascript cannot get bytes from the CDN (for example if you get cross-domain CORS errors about reading a file from external server). – VC.One Dec 23 '21 at 17:28

1 Answers1

2

it does not need a proxy

const video = document.querySelector('#video');
const mediaSource = new MediaSource();
video.src = URL.createObjectURL(mediaSource);
mediaSource.addEventListener('sourceopen', sourceOpen);
//you can implement logic in function sourceOpen
function sourceOpen() {
  //mime is type of video
  const sourceBuffer = mediaSource.addSourceBuffer(mime);
  fetch(videoUrl).then(function(response) {
     //decrypt
     return response.arrayBuffer();
  }).then(buffer => {
    sourceBuffer.appendBuffer(arrayBuffer);
  });
}
math-chen
  • 256
  • 1
  • 4
  • It's the right way. Can you add more detail. Thank you. – LF00 Dec 17 '21 at 09:16
  • Can you check my code, in my edit, where I did it wrong? – LF00 Dec 17 '21 at 09:29
  • 2
    @LF00 PS: You can't use a regular MP4 with MediaSource API. It has to be encoded as a fMP4 (Fragmented MP4). – VC.One Dec 18 '21 at 15:21
  • @VC.One Thank you. Is it possible to make the convertion from the client side? – LF00 Dec 20 '21 at 01:19
  • @LF00 I don't know what you've tried so far but maybe try Googling `mux.js`. It should convert MP4 to fMP4 using Arrays, if I remember correctly. **PS** Why do you care to play an MP4 via MSE with regards to your question? MSE is for when the bytes have been decrypted into playable video data (I assume the encryped bytes are not usable)... Since you won't have full file at once, each chunk that gets decrypted might provide only few seconds of video so use MSE to dynamically add more video data as you get it. Do you even get any bytes from the decrypt process??? Not obvious what's going on... – VC.One Dec 23 '21 at 16:54