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

Transcode server for remote #611

Draft
wants to merge 7 commits into
base: main
Choose a base branch
from
Draft

Transcode server for remote #611

wants to merge 7 commits into from

Conversation

whyboris
Copy link
Owner

@whyboris whyboris commented Dec 18, 2020

Huge thank you to @cal2195 for his code 🙇

This code comes from his transcoding-video branch 🥇

This is meant to be released in tandem with whyboris/Video-Hub-App-remote#9 🤝

Help wanted

update: Thank you @cal2195 for the on-finished suggestion -- I think it fixed the below problem

When running this branch in tandem with the Remote - after a little bit (playing the video 10-20 times) the server fails:

x264 [error]: malloc of size 2840448 failed
Video encoding failed

I messed on my PC with the pagefile settings, so it could be me. But I also wonder if, since for every HTTP request that comes to this server, we're spawning a new ffmpeg process, and perhaps never killing it, something goes wrong? 😅

Help still wanted:

Also, I set '-frag_duration', '15' to test a different value, but originally it was 3600 ... I'm unsure about what it's meant to do - the unit is seconds, and 3600 is 1 hour which seems awfully long (though I still don't understand what the flag does) 😅

Documentation is conflicting (see comment in discussion below).

@cal2195
Copy link
Collaborator

cal2195 commented Dec 18, 2020

Sounds like you're correct - we need something like this to catch the connection closed event, and then .kill() the ffmpeg process, possibly with the correct signal: ⚠️

https://github.com/jshttp/on-finished

@cal2195
Copy link
Collaborator

cal2195 commented Dec 18, 2020

Also note, for MOV/MP4/ISMV (Smooth Streaming) muxer, -frag_duration is in _micro_seconds, not seconds! 😄

https://ffmpeg.org/ffmpeg-formats.html#Options-9

@whyboris
Copy link
Owner Author

whyboris commented Dec 19, 2020

@cal2195 the FFmpeg documentation seems confusing 😅

frag_duration duration
Set the length in seconds of fragments within segments (fractional value can be set).

-frag_duration duration
Create fragments that are duration microseconds long.

:trollface:

Also, microseconds !?!! 😱 that's 1,000,000 microseconds in 1 second ... that's a million :trollface: ... they must have messed up in the documentation, right? Especially that they allow fractional value ... right? 😖

@whyboris
Copy link
Owner Author

whyboris commented Dec 19, 2020

Thanks @cal2195 -- I think the on-finished did the trick: the server no longer crashes (no malloc error) 🤞 44ead95

@cal2195
Copy link
Collaborator

cal2195 commented Dec 21, 2020

@cal2195 the FFmpeg documentation seems confusing 😅

frag_duration duration
Set the length in seconds of fragments within segments (fractional value can be set).

-frag_duration duration
Create fragments that are duration microseconds long.

:trollface:

Also, microseconds !?!! 😱 that's 1,000,000 microseconds in 1 second ... that's a million :trollface: ... they must have messed up in the documentation, right? Especially that they allow fractional value ... right? 😖

The one that is in seconds is for the dash muxer, each muxer had it's own options. :) Only the one in seconds allows fractional values.

We want the mp4 muxer, which is in microseconds! 😄

@whyboris
Copy link
Owner Author

I don't know what's a sensible values (as measured in seconds is). Is there a way to tell whether the value affects anything?

I can't see any difference whether it was 3600 as originally, or when it's 15 :trollface: - what would I expect to happen when I change it? Perhaps it gets ignored if it's too short to matter, and any effect is only noticeable at values above 1 million (1second)?

Sorry to ask about questions that I should be able to research on my own -- but the documentation is so terse 😕 I glanced around online (not too long, just a quick search) and found nothing of value to explain.

Or if it's easier, please let me know how you figured this stuff out 🙇

@whyboris whyboris added the ⛑️ WIP Work in progress label Dec 23, 2020
'-crf', '17',
'-preset', 'ultrafast',
'-movflags', 'frag_keyframe+empty_moov+faststart',
'-frag_duration', '15',
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can probably remove this - I think it might have a sensible default anyway. We can change it later.

The idea with fragmenting, is that you can seek and stream much easier, without having to download the entire mp4 file before playback can begin. Each fragment contains metadata about the video, rather than all the metadata being store at the end of the file!

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can look into finding the best options, but if the code works as is, may as well use that for now!

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks Cal for looking at this again. I've paused this feature for a while because I had at least two days of trying hard with no success: getting the video to play in Chrome ✅ no problem 👌 but getting Safari on iOS (on my phone) to play anything was a no-go 😓 which is the sole purpose of this feature.

I'll come back to this with renewed energy once I move in to the new house (these few months have been busy).

😅 also I've been working on an image-centric analogous-to-VHA app this past month -- I want to finish it first before returning to this headache :trollface:

Comment on lines +106 to +133
app.get('/video', (req, res) => {
const seekTime = req.query.seek || 0;
const file = req.query.file || '';
// see https://trac.ffmpeg.org/wiki/Encode/H.264#a2.Chooseapreset for more options
const ffmpeg = spawn(ffmpegPath, [
'-ss', seekTime,
'-i', file,
'-f', 'mp4',
'-crf', '17',
'-preset', 'ultrafast',
'-movflags', 'frag_keyframe+empty_moov+faststart',
'-frag_duration', '15',
'pipe:1'
]);
res.writeHead(200, {
'Content-Type': 'video/mp4'
});
ffmpeg.stdout.pipe(res);
// error logging
ffmpeg.stderr.setEncoding('utf8');
ffmpeg.stderr.on('data', (data) => {
console.log(data);
});
onFinished(res, () => {
console.log('about to kill!');
ffmpeg.kill();
});
});

Check failure

Code scanning / CodeQL

Missing rate limiting

This route handler performs [a system command](1), but is not rate-limited.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
help wanted Extra attention is needed server ⛑️ WIP Work in progress
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants