I want to achieve the following, but it remains unclear if this is possible.
The current scenario:
Someone is streaming a video with audio through
OBS to a media server, clients connect through a website.
[OBS Stream/Video Stream] -> [AWS/External Streaming Service] -> Clients
The wanted scenario:
capture this stream through a custom media server
and manipulate it by injecting certain metadata at certain moments
during the livestream. Note the importance of live.
[OBS Stream/Video Stream] -> [My Custom Node.js Server to insert metadata] -> [AWS/External Streaming Service] -> Clients
The idea:
The idea is that I want to synchronize the stream to some popup for example. The default protocol stream seems to be RTMP from OBS, but maybe this can be changed. At a given time during the livestream, an html5 videoplayer on the website can read these tags from the livestream (through some additional library such as video.js) and tell the JS application to show some text. In the end, it boils down to synchronizing the video stream to a text stream (eg from a websocket connection)
Potential solutions:
ID3 tags. I read about ID3 tags in MP3 files, but this does not seem to be what i'm looking as it needs a complete .mp3 file upfront and is not used for streams (Dynamically Inject ID3 in FFMPEG Live Stream). What I want is to dynamically inject metadata into this stream. For example, inject an id at any time (dynamically chosen) which references to a database for example should suffice.
LTC/Linear Time Code/SMPTE is this possible to embed that in a video stream somehow with node.js? that would enable me to match timings with an id on the client.
Is this possible to do given an incoming video stream with audio? and if so, what is the format of the stream and how do I inject metadata?
EDIT: it seems RTMP is not supported without flash in the browser. This is a no-go so I will need to use another stream format such as HLS/FLV?
Sounds like using something like Liquidsoap as your streaming server would do the trick for inserting the metadata into the stream. Plenty of options for manipulating metadata for you to explore.
As for client side decoding you could perhaps use a javascript readable stream within a service worker to split the server output into metadata/video and process as you see fit.
I did a similar thing for processing inband metadata on an infinite mp3 stream which might give you some ideas on where to start. You can find the code for that here
Related
I'm trying to make a basic online video editor with nodeJS and ffmpeg.
To do this I need 2 steps:
set the in-and-out times of the videos from the client, which requires the client to view the video at specific times, and switch the position of the video. Meaning, if a single video is used as an input, and split it into smaller parts, it needs to replay from the starting time of the next edited segment, if that makes sense.
send the input-output data to nodejs and export it with ffmpeg as a finished vide.
At first I wanted to do 1. purely on the client, then upload the source video(s) to nodeJS, and generate the same result with ffmpeg, and send back the result.
But there are may problems with video processing on the client side in HTML at the moment, so now I have a change of plans: to do all of the processing on the nodeJS server, including the video playing.
This is the part I am stuck at now. I'm aware that ffmpeg can be used in many different ways from nodeJS, but I have not found a way to play a .mp4 webm video in realtime with ffmpeg, at a specific timestamp, and send the streaming video (again, at a certain timestamp) to the client.
I've seen the pipe:1 attribute from ffmpeg, but I couldn't find any tutorials to get it working with an mp4 webm video, and to parse the stdout data somehow with nodejs and send it to the client. And even if I could get that part to work, I still have no idea to play the video, in realtime, at a certain timestamp.
I've also seen ffplay, but that's only for testing as far as I know; I haven't seen any way of getting the video data from it in realtime with nodejs.
So:
how can I play a video, in nodeJS, at a specific time (preferably with ffmpeg), and send it back to the client in realtime?
What I have already seen:
Best approach to real time http streaming to HTML5 video client
Live streaming using FFMPEG to web audio api
Ffmpeg - How to force MJPEG output of whole frames?
ffmpeg: Render webm from stdin using NodeJS
No data written to stdin or stderr from ffmpeg
node.js live streaming ffmpeg stdout to res
Realtime video conversion using nodejs and ffmpeg
Pipe output of ffmpeg using nodejs stdout
can't re-stream using FFMPEG to MP4 HTML5 video
FFmpeg live streaming webm video to multiple http clients over Nodejs
http://www.mobiuso.com/blog/2018/04/18/video-processing-with-node-ffmpeg-and-gearman/
stream mp4 video with node fluent-ffmpeg
How to get specific start & end time in ffmpeg by Node JS?
Live streaming: node-media-server + Dash.js configured for real-time low latency
Low Latency (50ms) Video Streaming with NODE.JS and html5
Server node.js for livestreaming
HLS Streaming using node JS
Stream part of the video to the client
Video streaming with HTML 5 via node.js
Streaming a video file to an html5 video player with Node.js so that the video controls continue to work?
How to (pseudo) stream H.264 video - in a cross browser and html5 way?
Pseudo Streaming an MP4 file
How to stream video data to a video element?
How do I convert an h.264 stream to MP4 using ffmpeg and pipe the result to the client?
https://medium.com/#brianshaler/on-the-fly-video-rendering-with-node-js-and-ffmpeg-165590314f2
node.js live streaming ffmpeg stdout to res
Can Node.js edit video files?
This question is a bit broad, but I've built similar things and will try to answer this in pieces for you:
set the in-and-out times of the videos from the client, which requires the client to view the video at specific times, and switch the position of the video. Meaning, if a single video is used as an input, and split it into smaller parts, it needs to replay from the starting time of the next edited segment, if that makes sense.
Client-side, when you play back, you can simply use multiple HTMLVideoElement instances that reference the same URL.
For the timing, you can manage this yourself using the .currentTime property. However, you'll find that your JavaScript timing isn't going to be perfect. If you know your start/end points at the time of instantiation, you can use Media Fragment URIs:
video.src = 'https://example.com/video.webm#t=5.5,30';
In this example, the video starts at 5.5 seconds, and stops at 30 seconds. You can use the ended event to know when to start playing the next clip. This isn't guaranteed to be perfectly frame-accurate, but is pretty good for something like a live preview.
But there are may problems with video processing on the client side in HTML at the moment, so now I have a change of plans: to do all of the processing on the nodeJS server,...
Not a bad plan, if consistency is important.
... including the video playing.
There is a serious tradeoff you're making here, as far as latency to controlling that video, and quality of preview. I'd suggest a hybrid approach where editing is done client-side, but your final bounce/compositing/whatever is done server-side.
This isn't unlike how desktop video editing software works anyway.
This is the part I am stuck at now. I'm aware that ffmpeg can be used in many different ways from nodeJS, but I have not found a way to play a .mp4 webm video in realtime with ffmpeg, at a specific timestamp, and send the streaming video (again, at a certain timestamp) to the client.
Is it MP4, or is it WebM? Those are two distinct container formats. WebM is easily streamable, as piped directly out of FFmpeg. MP4 requires futzing with the MOOV atom (-movflags faststart), and can be a bit of a hassle.
In any case, sounds like you just need to set timestamps on the input:
ffmpeg -ss 00:01:23 -i video.mp4 -to 00:04:56 -f webm -
I've seen the pipe:1 attribute from ffmpeg, but I couldn't find any tutorials to get it working with an mp4 webm video, and to parse the stdout data somehow with nodejs and send it to the client.
Just use a hyphen - as the output filename and FFmpeg will output to STDOUT. Then, there's nothing else you need to do in your Node.js application... pipe that output directly to the client. Untested, but you're looking for something like this, assuming a typical Express app:
app.get('/stream', (req, res, next) => {
const ffmpeg = child_process.spawn('ffmpeg', [
'-i', 'video.mp4',
'-f', 'webm',
'-'
]);
res.set('Content-Type', 'video/webm'); // TODO: Might want to set your codecs here also
ffmpeg.stdout.pipe(res);
});
And even if I could get that part to work, I still have no idea to play the video, in realtime, at a certain timestamp.
Well, for this, you're just playing a stream so you can just do:
<video src="https://your-nodejs-server.example.com/stream" preload="none" />
The preload="none" part is important, to keep it "live".
An alternative to all of this is to set up a GStreamer pipeline, and probably utilize its built-in WebRTC stack. This is not trivial, but has the advantage of potentially lower latency, and automatic handling of "catching up" to live video from the server. If you use the normal video tag, you'll have to handle that yourself by monitoring the buffered data and managing the playback speed.
I've also seen ffplay...
FFplay isn't relevant to your project.
Hopefully this pile of notes will give you some things to consider and look at.
Setup: I'm working on a video upload tool. I use a 3rd party javascript library that loads content from a users various storage locations (Hard Drive, Dropbox, Facebook, etc )
The library pushes the videos to our S3 bucket and returns the url of the uploaded file.
Goal: I would like to get the metadata (Height / Width / Duration / Etc) about the video without having to load the entire video binary.
Context: I use a service that handles video transcoding, and eventually posts the transcoded metadata to one of our backend servers. The transcoding can take a few minutes.
I need to get the temporary metadata of the uploaded file, but i don't want to load the full video.
Setting preload="metadata" on an HTML video tag means the browser is supposed to fetch metadata but not the whole stream. It's only considered a hint, i.e., browsers are not required to follow it, but you could try it and see if it works on the browsers you need to support. What it should do, I believe, is fetch just the first part of the video file, so it can read the header.
If that doesn't work, you probably need to implement a separate Ajax call to fetch the metadata. Hopefully your transcoding service gives you the metadata in a way that you can access it server-side. Otherwise you might need to extract it yourself, on the server. For example, you could use the ffmpeg library (or spawn an ffmpeg command line process) to parse out the metadata.
I am trying to capture the microphone and send the recording to my server.. I tried this method here but it records only a big WAV and the upload can be slow sometimes.
Is there a way to capture the voice and compress it on the client side?
Best method would be to send the recording while recording, but I have no Idea if this is possible. (It works for YouTube Live Webcam recording, it must work for Audio only too..)
Hey check out this post where i replied to a guy with a similar question as you.
How do I embed a Flash audio recorder in my site
i dont know about client side compressing (i have looked into it before and couldnt find anything). But i know you can severely reduce the size of the file by limiting the rate of recording via these numbers here, where if i recall correctly 16 is 16khz recording
recorder = new MicRecorder(wavencoder,null,50,16);
also sending to the server is not that hard, just look up how to post data, because the wav file is essentially binary data
You can compress the file on the clientside using libmp3lame.js: https://github.com/akrennmair/libmp3lame-js
There is already a gitHub project that uses this library to record audio and save it in MP3 format directly in the browser:
https://github.com/nusofthq/Recordmp3js
I am using audio element to stream an ogg source from an icecast server. Does the audio element extract icy metadata and is there a way to access it through javascript?
Basically, I want to show "currently playing" information of a radio station I am streaming. What are my options?
Thanks!
No, your HTML5 elements are only aware of the stream data, and aren't even making the appropriate request to fetch the metadata.
See these posts:
Developing the client for the icecast server
Pulling Track Info From an Audio Stream Using PHP
http://www.smackfu.com/stuff/programming/shoutcast.html
Now, this isn't impossible by any means. You just have to do it server-side. (See that second link in particular.)
I should also point out that on a full-blown SHOUTcast Server (haven't tested with Icecast, but its worth a try) generates "7.html" which contains data on the number of listeners, max listeners, peak listeners, stereo/mono, bitrate, and current track name as comma-separated values. Like this:
2,1,33,625,2,128,J Mascis - Not Enough
If you can fetch http://yourstreamingserver:port/7.html, then you can get this data very easily.
In case of an Ogg container stream (So both Vorbis and Opus), at least Firefox supports javascript access to the metadata. This is currently only "vendor specific" Javascript API: audio.mozGetMetadata();
On the other hand if you go with Icecast 2.4.1 you can access metadata independently through a JSON API. Lack of synchronization as pointed out in other comments applies. It's usually "close enough" though.
What is the best way given the YouTube url to send the audio to a list view like (http://opentape.fm/mixtape/). I would have to it streaming from the YouTube player, rather than downloading and uploading the actual file to the server. Any help would be awesome, thanks!
The big problem you have here is that YouTube does not take mp3 files directly, a video must be created from the mp3 file.
Dynamically creating a video within the browser without any server-side assistance would be near impossible, it is hard enough to get data access to the mp3s (or any image source for the video stream) and writing a codec in JavaScript is not going to be fun.
You could probably do it server-side in a streaming fashion if you can find/write software that can chunk the mp3 audio appropriately and just shove a flat image in to a simple video stream on each key frame, multiplexing as you go.
Should you be able to do all that, the API details for uploading detail the process. You can do this without any metadata at all, simplifying the process somewhat for streaming.
But generally, the answer is no - not easy to do this client-side. You could make an AJAX service out of the server-side idea that takes a URL as a parameter, but that's about the limit.