Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to save video and audio? #1322

Closed
wilsontamarozzi opened this issue Aug 31, 2017 · 8 comments
Closed

How to save video and audio? #1322

wilsontamarozzi opened this issue Aug 31, 2017 · 8 comments
Labels

Comments

@wilsontamarozzi
Copy link

How to save video and audio?

I tried to unify the audio with the video, but I'm a little newbie.

My idea is to perform multiple recordings at the same time. I'm getting the data as follows.

var arrayRecord = [];

function stopRecord(url) {
   arrayRecord.forEach(function (item) {
        if (item.url === url) {
            downloadMP4(item.data['video']);
            item.hls.destroy();
            return false;
        }
    });
}

function startRecord(url) {
    var video = document.createElement('video');
    var dataStream = {'video':[], 'audio':[]};
    var hls = new Hls({startLevel: 3});
    hls.loadSource(url);
    hls.attachMedia(video);
    hls.on(Hls.Events.MANIFEST_PARSED, function () {
        video.play();
        hls.on(Hls.Events.BUFFER_APPENDING, function (event, data) {
            dataStream[data.type].push(data.data);
        });
    });
   arrayRecord.push({url: url, hls: hls, data: dataStream});
}

function downloadMP4(data) {
    console.log('downloading...');
    var blob = new Blob([arrayConcat(data)], {type: 'application/octet-stream'});
    var filename = 'video-' + new Date().toISOString() + '.mp4';
    saveAs(blob,filename);
}

function arrayConcat(inputArray) {
    var totalLength = inputArray.reduce( function(prev,cur) { return prev+cur.length} ,0);
    var result = new Uint8Array(totalLength);
    var offset = 0;
    inputArray.forEach(function(element) {
        result.set(element, offset);
        offset += element.length;
    });
    return result;
}
@stale
Copy link

stale bot commented Jun 16, 2018

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

@stale stale bot added the Wontfix label Jun 16, 2018
@stale stale bot closed this as completed Jun 23, 2018
@weituotian
Copy link

so how to save it to file?

@deromka
Copy link

deromka commented Jun 8, 2020

Did you do that?

@polpanka
Copy link

any news about saving file?

@deromka
Copy link

deromka commented Sep 10, 2020

Hi All,

I solved this issue as follows by listening to the events:

Since I could not find a way to read the fragments directly from player's memory,
I'm recording all the fragments in the FRAG_PARSING_DATA events into a local buffer (yes, I know it increases browser's memory...)
and then when recorded is started by a user, I'm recording only the fragments that have been seen by the user during the FRAG_CHANGED event

     let hls = new Hls(hlsConfig);

     hls.on(Hls.Events.FRAG_PARSING_INIT_SEGMENT, (event, data) => {
            console.log("HLS Player Frag Parsing Init Segment")
            console.log("data = " + inspect(data))
            if (data && data.tracks && data.tracks.video && data.tracks.video.initSegment)
            {
                this.latestInitSegment = data.tracks.video.initSegment
                console.log("saved init segment " + this.latestInitSegment.length + " bytes")
            }
        })
     hls.on(Hls.Events.FRAG_PARSING_DATA, (event, data) => {
            //console.log("HLS Player Frag Parsing Data")
            //console.log("Data = " + inspect(data))
            // save only video fragments
            if (data.type === "video" || !data.type )
            {
                this.fragments[data.frag.sn]=data
                console.log("saved sn(" + data.frag.sn + ") - fragment")
            }
        })
     hls.on(Hls.Events.FRAG_CHANGED, (event, data) => {
            console.log("HLS Player Frag Changed")
            let currentFragmentSN = data.frag.sn
            let keepLastFragmentSN = currentFragmentSN - KEEP_LAST_FRAGMENTS
            console.log("Current Fragment SN = " + currentFragmentSN)
            if (this.state.recording) {
                let recdata = this.fragments[currentFragmentSN]
                let dataToRecord = []
                // handle video only - we're not interested in audio fragments
                if (recdata && recdata.type === "video")
                {
                    if (recdata.data1 && recdata.data2){
                        dataToRecord = [...recdata.data1,...recdata.data2]
                    }
                    else
                    {
                        dataToRecord = recdata.data1
                    }
                    this.dataStream.push(new Uint8Array(dataToRecord))
                    this.fileSize += dataToRecord.length
                    console.log("recording video data sn(" + currentFragmentSN + ") " + dataToRecord.length + " bytes  ...")
                }
                else
                {
                    console.log("No fragment " + currentFragmentSN)
                }
            }
            // clean up the old fragments
            let fragmentsSize=0
            for (var fragKey in this.fragments)
            {
                if (fragKey < keepLastFragmentSN){
                    // clean up old fragments
                    this.fragments[fragKey] = null
                    delete this.fragments[fragKey];
                    console.log('cleaned up old fragment SN(' + fragKey + ') < keepLastFragmentSN (' + keepLastFragmentSN + ')')
                }
                else{
                    let fragData = this.fragments[fragKey]
                    if (fragData.data1 && fragData.data2){
                        fragmentsSize += ([...fragData.data1,...fragData.data2]).length
                    }
                    else if (fragData.data1)
                    {
                        fragmentsSize += fragData.data1.length
                    }
                }
            }
            console.log("all fragments size " + Math.floor(fragmentsSize / (1024*1024)) + " MB ...")
        })

Not ideal solution, but it works for my usecase - the main problem here is that I need to pre-record all the fragments into my buffer which increases browser memory too much.
The better solution would be to somehow to get the fragment itself during the FRAG_CHANGED event, since there is only metadata available with SN, but no the video/audio data itself

@FelixSelter
Copy link

so how to save it to file?

function saveAs(blob, filename) {
var url = URL.createObjectURL(blob);
var a = document.createElement("a");
document.body.appendChild(a);
a.style = "display: none";
a.href = url;
a.download = filename;
a.click();
window.URL.revokeObjectURL(url);
}

@FelixSelter
Copy link

Did you do that?

function saveAs(blob, filename) {
var url = URL.createObjectURL(blob);
var a = document.createElement("a");
document.body.appendChild(a);
a.style = "display: none";
a.href = url;
a.download = filename;
a.click();
window.URL.revokeObjectURL(url);
}

@FelixSelter
Copy link

any news about saving file?

function saveAs(blob, filename) {
var url = URL.createObjectURL(blob);
var a = document.createElement("a");
document.body.appendChild(a);
a.style = "display: none";
a.href = url;
a.download = filename;
a.click();
window.URL.revokeObjectURL(url);
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

5 participants