Can ffprobe consume piped ffmpeg output? - node.js

The Situation
I'm writing a NodeJS script that takes a video stream (or file), pipes it to ffmpeg to standardize the format, and then sends it to various ETL processes to extract data from the video.
I want my node-level data stream to have awareness of how far into the video it is, and it seems the best (only?) way to do this is to use ffprobe to extract times from the stream packets.
The Problem
Before I actually start spawning ffmpeg commands, I'm trying to test at the CLI level. When I pipe ffmpeg's output directly to ffprobe, I receive a complaint:
av_interleaved_write_frame(): Broken pipe
Error writing trailer of pipe:: Broken pipe
The command in question:
ffmpeg -i /path/to/in.mp4 -f mpegts - | ffprobe -i - -print_format json
The Question
Am I misunderstanding something about what ffprobe accepts? I haven't found a single example of ffmpeg piping to ffprobe, which makes me nervous.
Is it possible to pipe ffmpeg data directly to ffprobe?
Bonus points: if you have a better way of extracting timing information from the ffmpeg stream, take a look at this question

Related

ffmpeg audio encoding based on codec and not on stream identifier

I have an RTSP Stream with one video stream and three audio streams as the source. Two of the audio streams are encoded with .mp2 and one is encoded with .ac-3. I want to convert the .mp2 streams to AAC. This would be easy if the .mp2streams would have the same stream identifier every time I start ffmpeg, but unfortunately the stream identifiers change. This means sometimes the two .mp2 streams are 0:a:0 and 0:a:1 and the next time they are 0:a:1 and 0:a:2.
Is there an option to re-encode only the .mp2 streams and keep the .ac-3 stream untouched?
I should probably also mention that this encoding is used for live TV so it is not an option to produce intermediate files or have several ffmpeg commands.
Try
ffprobe -show_entries stream_tags -select_streams a INPUT_URL
and see if there are any stream tags (metadata) that distinguishes mp2 streams. Then you can use the metadata stream specifier to selectively set re-encoding:
ffmpeg ... -c copy -c:a:m:{name}:{value} ac3 ...
where {name} and {value} are the name and value of the tag, respectively.
Reference on stream specifier: https://ffmpeg.org/ffmpeg.html#Stream-specifiers-1
If there isn't any usable tag, your only solution likely is to run ffprobe first to identify the stream # before running ffmpeg.

Is there a way to ensure mp3 duration accuracy with variable bit rate using FFMPEG?

In our application, we are processing audio files using ffmpeg. Specifically, we use the NodeJS library fluent-ffmpeg, (npm link).
Our audio files are generated from various text to speech providers. We recently noticed that when we converted audio using ssml to add pauses to the generated audio, the duration on the file is no longer correct. Upon further investigation, we noticed that the standard audios were also incorrect, just more accurate overall due to the more consistent data. When we put a pause at the beginning of the audio, the estimate was the worst, overshooting it by a very large margin (e.g., a 25s audio clip would read as 3 minutes long, but skip to the end when playing past the 25s mark.
I did some searching and research into the structure of MP3 files, and to me it seems like the issue is because the duration gets estimated by various audio players. Windows media player is an example, but Firefox's web player seems to also do this. I tried changing the ffmpeg command from using .audioQuality(0), which sets ffmpeg to use VBR, to .audioBitrate(320), which tells ffmpeg to use a constant bitrate.
For reference, the we are using libmp3lame, and the full command that gets run is the following, for the VBR and CBR cases respectively:
For VBR (broken durations): ffmpeg -i <URL> -acodec libmp3lame -aq 0 -f mp3 pipe:1
For CBR (correct duration): ffmpeg -i <URL> -acodec libmp3lame -b:a 320k -f mp3 pipe:1
Note: we then pipe the output to the requesting client application after sending the appropriate file headers, hence the pipe:1 output. The input is a cloud storage url where the source file is located
This fixes our problem of having a correct duration, and it makes sense to me why this would fix it if the problem was because the duration is being estimated by some of these players / audio consumers. But, this came at the cost that the file size was significantly larger, which also makes sense to me. While testing we found that compared to the same file in WAV, the VBR mp3 was about 10% of the WAV file size, while the CBR mp3 was still 50% of the WAV file size. This practically defeats the purpose of supporting the mp3 format for our use-case, which is a smaller but slightly lossy alternative to the large WAV file.
While researching, I found that there can be ID3 tags in a chunk at the beginning of the mp3 file, specifying information for the consumer of the audio to know the duration before potentially having processed the whole file. But, I also found that there doesn't seem to be a standard, at least for duration. More things like song title, album, artist, etc.
My question is, is there a way to get the proper duration onto an mp3 file, preferably via some ffmpeg mechanism, while still using VBR? Thanks!
FFmpeg does write a Xing header by default with duration info. However, that value is only known after the entire stream data has been received, so ffmpeg has to seek to the head to write it. Since you're piping the output, that can't be done.
Write the file locally or to some seekable destination, and then upload.

How do I end a pipe?

I have trouble using ffprobe from node.js. I need the audio lengths MP3 files. There is an npm package, get-audio-duration for this.
The package calls ffprobe through an execa command. It works well for .flac files both when when using a filename and a stream. However for .mp3 files it fails for streams.
I suspected some problems with execa so I checked from the command line (on Windows 10):
type file.mp3 | ffprobe -
(Where I left out the parameters to ffprobe for clarity.)
This kind of works, but says duration=N/A.
It looks to me like ffprobe didn't get the info that the input is finished. Or, it dint care about it. (There is a 4 year old bug report about this on the ffmpeg issue site which was closed for no obvious reason.)
Is it possible to somehow tell ffprobe that the pipe has ended?
It's not a matter of noticing that the pipe has ended.
ffprobe uses a different way of determining the file size than is allowed by piping stdout to stdin
See https://trac.ffmpeg.org/ticket/4358

Extract audio from Transport Stream and preserve length

I'm using ffmpeg to extract audio from MPEG Transport Stream file recorded by DVB-S card. The command:
ffmpeg -i video.ts -vn audio.wav
The source file seems to be corrupted. I noticed the corruption happens from time to time, especially for videos longer than 1 hour. I've got errors like these:
[mp2 # 0x1bb5500] Header missing
Error while decoding stream #0:1
[mpegts # 0x17eaf40] Continuity check failed for pid 5261 expected 2 got 6
The problem is that the resulting audio.wav is shorter than the source video (40m33s and 40m59s accordingly). I'm looking for the way to preserve the original length in the resulting audio file.
I tried the recent ffmpeg under Windows and avconv under Ubuntu, output format was MP3 and WAV. For every case I've got the same results.
I didn't find whether it's possible to do it with ffmpeg however I found ProjectX - a tool which tries to fix the broken TS stream. Website: http://project-x.sourceforge.net/
With:
java -jar ProjectX.jar -demux my_video.ts
the stream is demuxed into audio and video files which are guaranteed to have the same length. I simply mux them back using ffmpeg.

Capturing PCM audio data stream into file, and playing stream via ffmpeg, how?

Would like to do following four things (separately), and need a bit of help understanding how to approach this,
Dump audio data (from a serial-over-USB port), encoded as PCM, 16-bit, 8kHz, little-endian, into a file (plain binary data dump, not into any container format). Can this approach be used:
$ cat /dev/ttyUSB0 > somefile.dat
Can I do a ^C to close the file writing, while the dumping is in progress, as per the above command ?
Stream audio data (same as above described kind), directly into ffmpeg for it to play out ? Like this:
$ cat /dev/ttyUSB0 | ffmpeg
or, do I have to specify the device port as a "-source" ? If so, I couldn't figure out the format.
Note that, I've tried this,
$ cat /dev/urandom | aplay
which works as expected, by playing out white-noise..., but trying the following doesn't help:
$ cat /dev/ttyUSB1 | aplay -f S16_LE
Even though, opening /dev/ttyUSB1 using picocom # 115200bps, 8-bit, no parity, I do see gibbrish, indicating presence of audio data, exactly when I expect.
Use the audio data dumped into the file, use as a source in ffmpeg ? If so how, because so far I get the impression that ffmpeg can read a file in standard containers.
Use pre-recorded audio captured in any format (perhaps .mp3 or .wav) to be streamed by ffmpeg, into /dev/ttyUSB0 device. Should I be using this as a "-sink" parameter, or pipe into it or redirect into it ? Also, is it possible that in 2 terminal windows, I use ffmpeg to capture and transmit audio data from/into same device /dev/ttyUSB0, simultaneously ?
My knowledge of digital audio recording/processing formats, codecs is somewhat limited, so not sure if what I am trying to do qualifies as working with 'raw' audio or not ?
If ffmpeg is unable to do what I am hoping to achieve, could gstreamer be the solution ?
PS> If anyone thinks that the answer could be improved, please feel free to suggest specific points. Would be happy to add any detail requested, provided I have the information.

Resources