Extract audio from Transport Stream and preserve length - audio

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.

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.

Detecting video volume

I'm streaming few RTMP streams through nginx and I want to check every few seconds what stream has the highest volume.
Specifically these streams are of talking heads and I assume that usually only one of them is speaking at a time, and I'm trying to find which one.
Since nginx can output hls (Apple http live streaming) I decided to check every few seconds the last segment of each stream using ffmpeg.
Example:
ffmpeg -f mp3 -i /my/path/camera67/123.ts -af "volumedetect" -f null /dev/null
For some reason the max_volume is always zero (max_volume: 0.0 dB) and mean_volume seems meaningless regarding the volume.
Do you have any idea why it's always zero?
Is there a helpful way to understand mean_volume?
Can you think of a different tool that may give me the volume (e.g. mediainfo or ffprobe)?
I also tried:
ffmpeg -f lavfi -i amovie=/my/path/camera67/123.ts,volumedetect
This time I got:
[mpegts # 0x130bf40] start time for stream 1 is not set in estimate_timings_from_pts
[mpegts # 0x130bf40] Could not find codec parameters for stream 1 (Audio: aac ([15][0][0][0] / 0x000F), 0 channels, fltp): unspecified sample rate
Consider increasing the value for the 'analyzeduration' and 'probesize' options
[Parsed_amovie_0 # 0x130bcc0] No audio stream with index '-1' found
[lavfi # 0x130abc0] Error initializing filter 'amovie' with args '/my/path/camera67/123.ts'
amovie=/my/path/camera67/123.ts,volumedetect: Invalid argument
Any idea?
Thanks,
T.
So that's what happened.
I streamed MP3 to nginx that transcoded the input to HLS segments that doesn't support MP3.
Listening to the RTMP output caused me thinking that the audio is working fine, but when I listened to the HLS output I heard nothing.
I changed my original stream to AAC, then the HLS stream gave the right output and immediately I saw correlation between the music and the mean and max volumes.
Thank you all.

AAC bitstream not in ADTS format and extradata missing

With FFMPEG, I'm sending a stream from Computer A over to Computer B, via UDP.
This is done over a MPEGTS stream, encoded with libx264 and aac.
Computer B takes this stream with FFMPEG and puts it into an m3u8 playlist.
After a random time (2-35 minutes), the message
[mpegts # 0533f000] AAC bitstream not in ADTS format and extradata missing
av_interleaved_write_frame(): Invalid data found when processing input
appears.
What I figures is that the receiving FFMPEG can't read the header file of the audio part for this particular package, and since it can't put video and audio together anymore, it stops creating the .ts files and just stops running.
Here's the cmdline of the receiving stream:
ffmpeg -i udp://address -vcodec copy -acodec copy -map 0 -f segment -segment_list playlist.m3u8 -analyzeduration 100000 -probesize 100000-segment_list_flags +live-cache -segment_time 8 -segment_wrap 10 out%03d.ts
Now I need to know the answer to either one of these 2 questions:
1) Can I put something in my commandline in order to avoid this particular problem or
2) Can I tell FFMPEG to just ignore it for this particular message, quite possibly creating weird audio or none at all, and to simply move on to the next one?

Download ONLY audio from a youtube video

I know that there are a million ways to download a video from youtube and then convert it to audio or do further processing on it. But recently I was surprised to see an app called YoutubeToMp3 on mac actually showing "Skipping X mb of video" and supposedly only downloading the audio from the video, without the need to use bandwith to download the entire video and then convert it. I was wondering if this is actually correct and possible at all because I cant find any way to do that. Do you have any ideas ?
EDIT:
After some tests here is some additional information on the topic. The video which I tried to get the audio from is just a sample mp4 file from the internet:
http://download.wavetlan.com/SVV/Media/HTTP/MP4/ConvertedFiles/MediaCoder/MediaCoder_test6_1m9s_XVID_VBR_306kbps_320x240_25fps_MPEG1Layer3_CBR_320kbps_Stereo_44100Hz.mp4
I tried
ffmpeg -i "input" out.mp3
ffmpeg -i "input" -vn out.mp3
ffmpeg -i “input” -vn -ac 2 -ar 44100 -ab 320k -f mp3 output.mp3
ffmpeg -i “input” -vn -acodec copy output.mp3
Unfortunately non of these commands seems to be using less bandwith. They all download the entire video. Now that you have the video can you confirm if there is actually a command that downloads only the audio stream from it and lowers the bandwith usage? Thanks!
After a lot of research I found out that this is not possible and developed an alternative approach:
Download the mp4 header
Parse the header and get the locations of the audio bytes
Download the audio bytes with http range requests and offsets
Assemble the audio bytes and wrap them in a simple ADTS container to produce a playing m4a file
That way only bandwidth for the audio bytes is used. If you find a better approach of doing it please let me know.
For a sample Android APP and implementation check out:
https://github.com/feribg/audiogetter/blob/master/audiogetter/src/main/java/com/github/feribg/audiogetter/tasks/download/VideoTask.java
FFmpeg is capable of accepting an URL as input. If the URL is seekable, then FFmpeg could theoretically skip all the video frames, and thus it would need to download only the data for the audio stream.
Try using
ffmpeg -i http://myvideo.avi out.mp3
and see if it takes less bandwidth.

Resources