Setting HLS segment times - linux

I am passing a processed video from openCV to ffmpeg via a pipe here is the code
./OpenCV & \
tail -n +0 -f out.avi | ffmpeg -i pipe:0 -hls_time 1 -hls_list_size 0 -hls_wrap 10 -hls_segment_filename '%03d.ts' stream.m3u8
My issue is the output .ts files are not in a uniformed duration they change from file to file.
These are mostly long say 60 seconds. This means the connecting client has to wait for the first stream to finish before the playlist file (.m3u8) file is created. Therefor in this example they are 60 seconds or so behind live video and if the next .ts file is larger the streaming stops until this is finished. If the client tries to play before the next .ts file is created they are played the first .ts file.
The frame rate from openCV is 1 frame per second.
tail changes the output file of openCV called (out.avi) to a stdout.
Any help would be great.

I know I am answering my own question but I have changed the code below
./OpenCV & \
tail -n +0 -f out.avi | ffmpeg -i pipe:0 -hls_time 1 -hls_list_size 0 -hls_wrap 10 -hls_segment_filename '%03d.ts' stream.m3u8 `
to
./OpenCV & \
tail -n +0 -f out.avi | ffmpeg -i pipe:0 -f hls -g 2 -hls_time 2 -hls_list_size 0 -hls_wrap 10 -hls_segment_filename '%03d.ts' stream.m3u8 `
Seems to have done the trick.

Related

Audio and Video not synced after ffmpeg filter_complex select between

I am trying to trim a video shoot on an iPhone.
When I execute:
ffmpeg -i IMG_8555.MOV \
-filter_complex " \
[0:v] select='between(t,448.856,1279.240)', setpts=N/FR/TB; \
[0:a] aselect='between(t,448.856,1279.240)', asetpts=N/SR/TB \
" \
output.mov
the output audio is out of sync - audio is faster (noticeable towards the end of the output video).
I noticed that the outputs frame rate is 29.97 while the inputs is 29.98.
So I did some experimenting and changed setpts to setpts=N/29.98/TB; but still the video is falling behind.
So I changed it even more to setpts=N/30.00/TB; - then it feels almost ok.
I tired adding -vsync 1 - no luck
I tried adding -async 1 - no luck
I tried adding -async 7000 - no luck
edit: If i put setpts=N/29.99/TB then it is ideal.
Any ideas how can I make it always synced (no matter what is the input)?
Try this:
ffmpeg -ss 448.86 -to 1279.240 -i IMG_8555.MOV output.mov
<addendum>
If you have more cuts, then you can try one of the following 2 approaches:
specify them as different inputs then concat
ffmpeg -ss 0 -to 1 -i IMG_8555.MOV \
-ss 4 to 5 -i IMG_8555.MOV \
...
-ss 448.86 -to 1279.240 -i IMG_8555.MOV \
-filter_complex [0:v][0:a][1:v][1:a]...[99:v][99:a]concat
output.mov
(Unverified but likely work) Use concat demuxer. First create a concat file, name it say IMG_8555_trim.ffconcat and save it on the same folder as the video file
ffconcat version 1.0
file IMG_8555.MOV
inpoint 0
outpoint 1
file IMG_8555.MOV
inpoint 4
outpoint 5
...
file IMG_8555.MOV
inpoint 448.86
outpoint 1279.240
then run
ffmpeg -i IMG_8555_trim.ffconcat output.mov
#kesh's method worked for the mentioned problem but it was causing the other overlays (not included in this example) using enable='between(...)' to be off sync, so I couldnt go with that solution.
At the end I managed to still use between and setpts but without using FRAME_RATE constant to calculate new pts values.
Here is an example of my approach, assuming I want to have 3 cuts like that:
[start1, end1]---[start2,end2]---[start3,end3]
ffmpeg -i input.mov \
[0:v] \
select='between(t,start1,end1)+between(t,start2,end2)+between(t,start3,end3)', \
setpts='PTS-STARTPTS-(gt(t,end1)*(start2-end1) + gt(t,end2)*(start3-end2) )/TB'; \
[0:a] \
aselect='between(t,start1,end1)+between(t,start2,end2)+between(t,start3,end3)', \
asetpts='PTS-STARTPTS-(gt(t,end1)*(start2-end1) + gt(t,end2)*(start3-end2) )/TB' \
output.mov
Note that gt(t,100) returns 1 if it is greather than 100 and 0 otherwise. I am using it to shift PTS by the gap between previous cuts (start2-end1). If the current T is less than end1 then the value of gt(t,end1) will be 0. So start2-end1 wont be added (as it is multiplied by zero)

Mute Volume with Minimal Re-encoding

Is it possible to mute a section of a video file (say 5 seconds) without having to re-encode the whole audio stream with ffmpeg? I know it's technically (though probably not easily) possible by reusing the majority of the existing audio stream and only re-encoding the changed section and possibly a short section before and after, but I'm not sure if ffmpeg supports this. If it doesn't, anyone know of any other library that does?
You can do the partial segmented encode, as you suggest, but if the source codec is DCT-based such as AAC/MP3, there will be glitches at the start and end of the re-encoded segment once you stitch it all back together.
You would use the segment muxer and concat demuxer to do this.
ffmpeg -i input -vn -c copy -f segment -segment_time 5 aud_%d.m4a
Re-encode the offending segment, say aud_2.m4a to noaud_2.m4a.
Now create a text file
file aud_0.mp4
file aud_1.mp4
file noaud_2.mp4
file aud_3.mp4
and run
ffmpeg -an -i input -f concat -safe 0 -i list.txt -c copy new.mp4
Download the small sample file.
Here is my plan visualized:
# original video
| video |
| audio |
# cut video into 3 parts. Mute the middle part.
| video | | video | | video |
| audio | | - | | audio |
# concatenate the 3 parts
| video | video | video |
| audio | - | audio |
# mux uncut original video with audio from concatenated video
| video |
| audio | - | audio |
Let's do this.
Store filename:
i="fridayafternext_http.mp4"
To mute the line "What the hell are you doing in my house!?", the silence should start at second 34 with a duration of 2 seconds.
Store all that for your convenience:
mute_starttime=34
mute_duration=2
bash supports simple math so we can automatically calculate the start time where the audio starts again, which is 36 of course:
rest_starttime=$(( $starttime + $duration))
Create all 3 parts. Notice that for the 2nd part we use -an to mute the audio:
ffmpeg -i "$i" -c copy -t $mute_starttime start.mp4 && \
ffmpeg -i "$i" -ss $mute_starttime -c copy -an -t ${mute_duration} muted.mp4 && \
ffmpeg -i "$i" -ss $rest_starttime -c copy rest.mp4
Create concat_videos.txt with the following text:
file 'start.mp4'
file 'muted.mp4'
file 'rest.mp4'
Concat videos with the Concat demuxer:
ffmpeg -f concat -safe 0 -i concat_videos.txt -c copy muted_audio.mp4
Mux original video with new audio
ffmpeg -i "$i" -i "muted_audio.mp4" -map 0:v -map 1:a -c copy "${i}_partly_muted.mp4"
Note:
I've learned from Gyan's answer that you do the last 2 steps in 1 take which is really cool.
ffmpeg -an -i "$i" -f concat -safe 0 -i concat_videos.txt -c copy "${i}_partly_muted.mp4"

insert audio into another audio file (eg a censor bleep)

I need to insert a short beep into another audio file (similar to a censorship bleep) using linux and/or php.
I'm thinking there should be some way to do it with ffmpeg (with some combination of -t, concat, map, async, adelay, itsoffset?) or avconv or mkvmerge - but haven't found anyone doing this. Maybe I need to do it in 2 stages somehow?
For example if I have a 60 second mp3 and want to beep out 2 seconds at 2 places the desired result would be:
0:00-0:15 from original
0:15-0:17 beep (overwrites the 2 secs of original)
0:17-0:40 from original
0:40-0:42 beep
0:42-0:60 from original
I have a 2 second beep.mp3, but can use something else instead like -i "sine=frequency=1000:duration=2"
You can use the concat demuxer.
Create a text file, e.g.
file main.wav
inpoint 0
outpoint 15
file beep.wav
file main.wav
inpoint 17
outpoint 40
file beep.wav
file main.wav
inpoint 40
outpoint 42
and then
ffmpeg -f concat -i list.txt out.mp3
Convert the beep file to have the same sampling rate and channel count as the main audio.
First, you need to have beep.mp3 time equal to 60 seconds or little bit less than your mp3 file time.
Then, you can use ffmpeg code -ss <start_time> -t <duration> -i <your_file>.mp3
ffmpeg -ss 00:00:00 -t 15 -i ./original.mp3 -ss 00:15:00 -t 2 -i ./beep.mp3 -ss 00:17:00 -t 23 -i ./original.mp3 -ss 00:40:00 -t 2 -i ./beep.mp3 -ss 00:42:00 -i ./original.mp3 -filter_complex '[0:0][1:0] concat=n=2:v=0:a=1[out]' -map '[out]' ./output.mp3
at the end you will get output.mp3 file as you needed.

ffmpeg 2 audio files in one video file

lets say I have a video file (video.mp4) and 2 audio files (audio1.mp3 and audio2.mp3.) The video has a length of 60 seconds, every audio file has a length of 30 seconds.
What I am trying to achive is:
the first 20 seconds of the video is with original audio stream, followed by 20 seconds of the first audio file (offset of 5 seconds with a length of 20s) and the same with the second audio file.
ffmpeg -i video.mp4 -ss 5 -t 20 -i audio1.mp3 -ss 5 -t 20 -i audio2.mp3 -vcodec copy -acodec copy -copyinkf -map 0:v:0 -map 1:a:0 -map 2:a:0 -shortest final.mp4
The command above takes the video stream of the first input and the audio stream of the third input. The audio stream of the second input seems to be overwritten. How can I put all audio streams together and how can I define the offset when the audio streams should begin?
I assume that you want the combined audio programme in one stream. Even if you applied timestamp offsets to the other audios, most players won't switch audio streams mid-playback.
So,
ffmpeg -i video.mp4 -ss 5 -t 20 -i audio1.mp3 -ss 5 -t 20 -i audio2.mp3
-filter_complex
"[0]atrim=0:20[a];[1]adelay=20000|20000[b];[2]adelay=40000|40000[c];[a][b][c]amix=3"
-vcodec copy -copyinkf -shortest final.mp4

ffmpeg clip audio interval with starting and end time

I am trying to clip an MP3 between two starting points, like starting at 10 seconds and ending at 16 seconds (time interval of 6 seconds).
I am using this command:
ffmpeg -ss 10 -i input.mp3 -t 6 output.mp3
The resulting output.mp3 contains the 6 seconds that I specified followed by 8 or 9 seconds of empty audio. Is there something wrong with my command?
Edit:
ffmpeg -ss 10 -t 6 -i input.mp3 output.mp3 says -t is not an input option, keeping it for the next output; consider fixing your command line. and gives me a file that's got 8 seconds of audio starting from 10s and then some 9 or 10 seconds of silence.
ffmpeg -ss 10 -to 16 -i input.mp3 output.mp3 produces a file that is twice the length of the original - basically the same audio file repeated again.\
Testing the output:
I used Quicktime and it has silent audio at the end. The description of the output file in finder says like 14 seconds. When I use VLC, it plays for the correct 6 seconds and stops, even though its duration in the file browser in VLC says 14. My MPlayer doesn't work properly. I also did the preview audio in Finder, and it plays the 6 seconds properly and then stops. But the round seeker bar of the MP3 didn't reach the end. And it also says 14 seconds instead of 6.
My goal is to stream this 6 second file through a REST API to the front end. I want the user to be able to download this file properly. Ideally it won't have inconsistent metadata (14 seconds instead of 6).
For me both
ffmpeg -ss 10 -t 6 -i input.mp3 output.mp3
or
ffmpeg -ss 10 -i input.mp3 -t 6 output.mp3
work OK, just 6 seconds of audio. Here's the mplayer output (last line):
A: 5.8 (05.7) of 6.0 (06.0) 0.5%
Also
ffmpeg -ss 10 -to 16 -i input.mp3 output.mp3
work the same way. I use ffmpeg version 1.2.4. I guess your ffmpeg is somehow "broken" or the input file is somehow (report a bug in either case).
You may try the other answer with mp3cut from portforwardpodcast or
sox input.mp3 output.mp3 trim 10 6
ffmpeg - Trim audio file without re-encoding
Use ffmpeg to trim an audio file without re-encoding it.
Trim starting from 10 seconds and end at 16 seconds (total time 6 seconds)
ffmpeg -i input.mp3 -ss 10 -t 6 -acodec copy output.mp3
Trim from 00:02:54.583 to the end of the file
ffmpeg -i input.mp3 -ss 00:02:54.583 -acodec copy output.mp3
Trim from 00:02:54.583 for 5 minutes (300 seconds)
ffmpeg -i input.mp3 -ss 00:02:54.583 -t 300 -acodec copy output.mp3
I've had great success with both CBR and VBR mp3 files using mp3cut.
mp3cut -o output.mp3 -t 00:10-00:16 input.mp3
http://manpages.ubuntu.com/manpages/lucid/man1/mp3cut.1.html

Resources