How to properly unload/destroy a VIDEO element

Viewed 98866

I'm working on a realtime media browsing/playback application that uses <video> objects in the browser for playback, when available.

I'm using a mix of straight javascript, and jQuery,

My concern is specifically with memory. The application never reloads in the window, and the user can watch many videos, so memory management becomes a large concern over time. In testing today, I see the memory profile jumping by the size of the video to be streamed with each subsequent load, and never dropping back down to the baseline.

I've tried the following things with the same result:

1 - Empty the parent container containing the created element, eg:

$(container_selector).empty();

2 - Pause and remove children matching 'video', and then empty the parent container:

$(container_selector).children().filter("video").each(function(){
    this.pause();
    $(this).remove();
});
$(container_selector).empty();

Has anyone else run into this issue, and is there a better way to do this?

18 Answers

I was having an issue while dynamically loading some videos. I had two sources in my <video> element. One mp4 and the other webm as fallback. So I had to iterate through the <source>'s like so.

function removeMedia(){
    let videos = document.getElementsByTagName('video');
    for(let vid in videos){
        if(typeof videos[vid] == 'object'){
            let srcs = videos[vid].getElementsByTagName('source');
            videos[vid].pause();
            for(let xsrc in srcs){
                if(srcs[xsrc].src !== undefined){
                    srcs[xsrc].src = '';
                }
            }
            videos[vid].load();
            videos[vid].parentNode.removeChild(videos[vid]);
        }
    }
}
var video = document.getElementById('video');
        if (video.firstChild) {
            video.removeChild(video.firstChild);
            video.load();
        }

I've encountered this problem on a more complicated level where we are loading ~80 videos on a page, and having problems with memory management in IE and Edge. I posted our solution on a similar question I asked specifically about our issue: https://stackoverflow.com/a/52119742/1253298

My code did not use a <video> element with a src tag, but instead used multiple <source> children to set a video in multiple formats.

To properly destroy and unload this video, I had to use a combination of multiple answers on this page, which resulted in:

var videoElement = $('#my-video')
videoElement[0].pause()  // Pause video
videoElement.empty()     // Remove all <source> children
videoElement.load()      // Load the now sourceless video
delete videoElement      // The call mentioned in other answers
videoElement.remove()    // Removing the video element altogether

Hope this helps someone.

Not much complicated. Just put your src to null.

Eg: document.querySelector('#yourVideo').src = null;

It will remove your video src attribute. Done.

This is what I did to solve this problem. I created 2 video elements (video1 & video2). After finished using video1, get the source(src) attribute value and then remove video1 from DOM.

Then set video2 source (src) to whatever value you got from video1.

Do not use stream from video1 as it is cached in memory.

Hope this will help.

One solution that worked for me in AngularJS is using below code: In case you don't want to remove your source url, and reset to start of the video

let videoElement = $document[0].getElementById('video-id');
videoElement.pause();
videoElement.seekable.start(0);
videoElement.load();

And in case you want to remove the source from video tag:

let videoElement = $document[0].getElementById('video-id');
videoElement.pause();
videoElement.src="";
videoElement.load();

Hope someone finds it useful.

I know this is an old question, but I came across the same issue, and tried almost every solution mentioning <video>'s src attribute, and all solutions seemed to have their drawbacks.

In my specify case, besides <video> elements, I am also using <audio> elements at the same time.

I was reading an article at MDN when I realized that dealing with the src attribute could be the wrong thing to do. Instead, I rewrote all my code to append and remove <source> elements to both <video> and <audio> elements.

That was the only way I found that does not trigger a new load or generates error or other undesirable notifications.

This is a minimal/simplified version of the code I am using (tested on Firefox 86 and Chrome 88).

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" lang="en-us">
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1, minimal-ui, shrink-to-fit=no" />
</head>
<body>
    <button type="button" onclick="play()">Play</button>

    <button type="button" onclick="stop()">Stop</button>

    <video id="myVideo"></video>

    <script type="text/javascript">
        "use strict";

        var myVideo = document.getElementById("myVideo");

        myVideo.onloadstart = () => {
            console.log("onloadstart");
        };

        myVideo.onloadeddata = () => {
            console.log("onloadeddata");
        };

        myVideo.onload = () => {
            console.log("onload");
        };

        myVideo.onerror = () => {
            console.log("onerror");
        };

        function play() {
            while (myVideo.firstChild)
                myVideo.removeChild(myVideo.firstChild);

            var source = document.createElement("source");
            source.src = "example.mp4";
            myVideo.appendChild(source);
            myVideo.load();
            myVideo.play();
        }

        function stop() {
            while (myVideo.firstChild)
                myVideo.removeChild(myVideo.firstChild);

            myVideo.load();
        }
    </script>
</body>
</html>

In my case, i used the solution mentioned above by @toon lite:

 Array.from(document.getElementsByTagName('video')).forEach(video => {
   video.pause();
   video.removeAttribute('src');
   video.load();
 })

But it occurs the another problem in Chrome browser (version 93):

[Intervention] Blocked attempt to create a WebMediaPlayer as there are too many WebMediaPlayers already in existence. See crbug.com/1144736#c27

I guess it is all about the browser version's limit (mine is too old), anyway i fixed this bug by adding some extra operations:

video.src = '';
video.srcObject = null;  
video.remove()

Finally the code looks like:

Array.from(document.getElementsByTagName('video')).forEach(video => {
  video.pause();
  video.removeAttribute('src'); // video.src = '' works so this line can be deleted
  video.load();
  video.src = '';
  video.srcObject = null;  
  video.remove()
})
Related