I want to create 'm3u8' file from the list of ts files. How can I do it?
I did search in google & read documentation of ffmpeg but I didn't find anything.
It's not clear which of the following cases you're asking about, so here's a quick answer for both:
If you're starting with a single file that contains your content
This is the most common case. In general, there are three steps to creating a playable HlS stream from source material.
for each desired output level (let’s say Bitrate for simplicity), you need to create a collection of segmented .ts files.
For each output level you need a playlist manifest (m3u8) that contains the list of segment files making up the content.
For the whole stream you need a single master manifest (another m3u8) that lists the playlists.
FFMpeg can do all three of these.
If you're starting with a collection of .ts files
If you really are starting with a collection of .ts files, you could either hand-build an m3u8 file as described in the previous answer, or you could write a script to do it.
In either case, there are some considerations for the .ts files:
If the segment files do not belong to an uninterrupted sequence (as they would if they were transcoded from a single source clip for use in HLS), you’ll need to insert EXT-X-DISCONTINUITY tags between segments that don’t have the same encoding characteristics or that don’t have monotonically increasing PTS (presentation timestamp) values.
While the segments don't need to all be the same length, the longest one must not exceed the (integer) number of seconds specified in the EXT-X-TARGETDURATION tag.
"For VOD content, the average segment bit rate MUST be within 10% of the AVERAGE-BANDWIDTH attribute"
When you've built your m3u8 file, it helps to run it through a validator to find any problems.This is a lot easier than scratching your head wondering why an HLS stream plays poorly or inconsistently across players/browsers.
mediaStreamValidator on macOS is very good https://developer.apple.com/documentation/http_live_streaming/about_apple_s_http_live_streaming_tools
Also consider the online tool at Theo: http://inspectstream.theoplayer.com/
You probably want a HLS structure. There's a lot of documentation at Apple (IIRC it was invented by Apple and then got adopted widely), e.g. a draft RFC and a page with example streams.
HLS consists of two levels: a master M3U8 which references other M3U8 which in turn reference the .ts files. You can omit the master M3U8 and just provide the "second level".
As a starting point, it may look something like this:
#EXTM3U
#EXT-X-TARGETDURATION:10
#EXT-X-MEDIA-SEQUENCE:1
#EXTINF:10, no desc
media-000001.ts
#EXTINF:10, no desc
media-000002.ts
#EXTINF:10, no desc
media-000003.ts
The EXT-X-TARGETDURATION specifies how long each .ts file is (they must all be of the same length). It may either be a relative or absolute path.
Can be done with a bash script:
#!/usr/bin/env bash
file="hls.m3u8"
echo "#EXTM3U" > $file
echo "#EXT-X-VERSION:3" >> $file
echo "#EXT-X-MEDIA-SEQUENCE:24" >> $file
echo "#EXT-X-TARGETDURATION:10" >> $file
for i in `find *.ts -type f | sort -g`; do
l=$(ffprobe -v error -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 $i)
echo "#EXTINF:$l," >> $file
echo "$i" >> $file
done
echo "#EXT-X-ENDLIST" >> $file
Related
I'm trying to segment a video and name the cropped files in a specific way. Right now I'm using
ffmpeg -i input.mp3 -f segment -segment_time 59 output_%03d.wav
and looping over created files, parsing their filenames and renaming them accordingly.
I have an array which contains
array=[1650027545, 1650027300, 1650026502, ...]
and want the output files to be in;
output_1650027545.wav
output_1650027300.wav
output_1650026502.wav
format. Since there's no loop, I can't figure out how to implement such a naming scheme. Any help is appreciated!
Here's how my camera operates:
When taking a video recording, the camera will automatically segment into a new file chapter once it has reached a certain size. These files when put together with editing software will play seamlessly as if they were never chaptered, and when played back from the camera directly will also play through as one continuation.
Which results in the video being split into three video files:
$ ls -1
GH010119.MP4
GH020119.MP4
GH030119.MP4
Which may be placed in a directory alongside segments from another video. For example:
$ ls -1
GH010119.MP4
GH010120.MP4
GH010126.MP4
GH010127.MP4
GH020119.MP4
GH020126.MP4
GH020127.MP4
GH030119.MP4
In order to use ffmpeg to concatenate the same continuous segments, I need to write a file listing the filenames of the videos I want to concatenate. So I'm finding the files with the same last four characters:
find . -name "*0119*" -execdir echo '{}' ';' | xargs -n1 echo file > concat_list.txt
But is there a way to figure out, from the videos' data or metadata, which of these files are segments of the same video?
Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
This question does not appear to be about a specific programming problem, a software algorithm, or software tools primarily used by programmers. If you believe the question would be on-topic on another Stack Exchange site, you can leave a comment to explain where the question may be able to be answered.
Closed 2 years ago.
The community reviewed whether to reopen this question 16 days ago and left it closed:
Original close reason(s) were not resolved
Improve this question
I'm trying to write a batch file using ffmpeg to automate the redundant daily task of taking footage from work that's recorded in 4gb blocks (which is standard in most DSLR cameras & GoPro's), and split the clips into 2gb files for streaming purposes. The idea is to have the script check external drive FOOTAGE's folder #import and split files after 2gb (since the max size is 4gb, this will alleviate the need for more than one split).
I'm also trying to amend the filenames of the split files, so FILE1 is 4gb, it splits into FILE1_1 and FILE1_2 which are 2gb each, respectively. Everything I've tried has just copied the original file into two new, identical files - no split or anything.
After doing some Googling and reading some of the answers here, I found this post, but it's based on duration, not size (recording video footage at varying levels of quality makes this pointless): Split into equal parts and convert many mp4 videos using ffmpeg
Can someone help me with this? I haven't come across any usable solutions utilizing what I understand to be the method, using -fs limit_size, and I really want to understand how this works.
UPDATE: Also found this, but it hasn't been updated in four years and I don't see anything in there regarding splitting that will prove helpful:
https://github.com/kcm1700/VideoSplitter/blob/master/
I just had the same problem, and after I didn't find a solution here, I wrote a quick bash script for that job.
Features:
Use ffmpeg's -fs-flag to limit filesize
Check length of resulting video part and calculate where to start next part
Enumerate video parts
proceed with as many parts as needed to contain the whole source file.
Allow for custom ffmpeg arguments to also reduce resolution and quality in one pass.
It takes only three arguments: The source filename, the desired filesize of each part and the desired arguments for ffmpeg.
Example call to split a file into 64MB parts:
./split-video.sh huge-video.mov 64000000 "-c:v libx264 -crf 23 -c:a copy -vf scale=960:-1"
Finally, the source code of the script:
#!/bin/bash
# Short script to split videos by filesize using ffmpeg by LukeLR
if [ $# -ne 3 ]; then
echo 'Illegal number of parameters. Needs 3 parameters:'
echo 'Usage:'
echo './split-video.sh FILE SIZELIMIT "FFMPEG_ARGS'
echo
echo 'Parameters:'
echo ' - FILE: Name of the video file to split'
echo ' - SIZELIMIT: Maximum file size of each part (in bytes)'
echo ' - FFMPEG_ARGS: Additional arguments to pass to each ffmpeg-call'
echo ' (video format and quality options etc.)'
exit 1
fi
FILE="$1"
SIZELIMIT="$2"
FFMPEG_ARGS="$3"
# Duration of the source video
DURATION=$(ffprobe -i "$FILE" -show_entries format=duration -v quiet -of default=noprint_wrappers=1:nokey=1|cut -d. -f1)
# Duration that has been encoded so far
CUR_DURATION=0
# Filename of the source video (without extension)
BASENAME="${FILE%.*}"
# Extension for the video parts
#EXTENSION="${FILE##*.}"
EXTENSION="mp4"
# Number of the current video part
i=1
# Filename of the next video part
NEXTFILENAME="$BASENAME-$i.$EXTENSION"
echo "Duration of source video: $DURATION"
# Until the duration of all partial videos has reached the duration of the source video
while [[ $CUR_DURATION -lt $DURATION ]]; do
# Encode next part
echo ffmpeg -i "$FILE" -ss "$CUR_DURATION" -fs "$SIZELIMIT" $FFMPEG_ARGS "$NEXTFILENAME"
ffmpeg -ss "$CUR_DURATION" -i "$FILE" -fs "$SIZELIMIT" $FFMPEG_ARGS "$NEXTFILENAME"
# Duration of the new part
NEW_DURATION=$(ffprobe -i "$NEXTFILENAME" -show_entries format=duration -v quiet -of default=noprint_wrappers=1:nokey=1|cut -d. -f1)
# Total duration encoded so far
CUR_DURATION=$((CUR_DURATION + NEW_DURATION))
i=$((i + 1))
echo "Duration of $NEXTFILENAME: $NEW_DURATION"
echo "Part No. $i starts at $CUR_DURATION"
NEXTFILENAME="$BASENAME-$i.$EXTENSION"
done
Hope, that helps :)
You can do this in one command using mp4box.
mp4box -splits 2000000 filename.mp4
where splits argument takes value in kilobytes. Due to presence of keyframes, segments won't be exactly 2GB.
One idea would be to use ffmpeg with the option -fs. This wil limit the file size. The size of the output file is slightly more than the requested file size.
This will only create one file. But you can build a loop until the whole file is split.
First create a part of the file, then check how long it is with:
ffprobe -i input.file -show_format -v quiet | sed -n 's/duration=//p'
Then start another file with the offset by using -ss
After that do another round of encoding until the whole file is split. You can also use a stream copy for audio and video
I have a camera taking time-lapse shots every 2–3 seconds, and I keep a rolling record of a few days' worth. Because that's a lot of files, I keep them in subdirectories by day and hour:
images/
2015-05-02/
00/
2015-05-02-0000-02
2015-05-02-0000-05
2015-05-02-0000-07
01/
(etc.)
2015-05-03/
I'm writing a script to automatically upload a timelapse of the sunrise to YouTube each day. I can get the sunrise time from the web in advance, then go back after the sunrise and get a list of the files that were taken in that period using find:
touch -d "$SUNRISE_START" sunrise-start.txt
touch -d "$SUNRISE_END" sunrise-end.txt
find images/"$TODAY" -type f -anewer sunrise-start.txt ! -anewer sunrise-end.txt
Now I want to convert those files to a video with ffmpeg. Ideally I'd like to do this without making a copy of all the files (because we're talking ~3.5 GB per hour of images), and I'd prefer not to rename them to something like image000n.jpg because other users may want to access the images. Copying the images is my fallback.
But I'm getting stuck sending the results of find to ffmpeg. I understand that ffmpeg can expand wildcards internally, but I'm not sure that this is going to work where the files aren't all in one directory. I also see a few people using find's --exec option with ffmpeg to do batch conversions, but I'm not sure if this is going to work with image sequence input (as opposed to, say, converting 1000 images into 1000 single-frame videos).
Any ideas on how I can connect the two—or, failing that, a better way to get files in a date range across several subdirectories into ffmpeg as an image sequence?
Use the concat demuxer with a list of files. The list format is:
file '/path/to/file1'
file '/path/to/file2'
file '/path/to/file3'
Basic ffmpeg usage:
`ffmpeg -f concat -i mylist.txt ... <output>`
Concatenate [FFmpeg wiki]
use pattern_type glob for this
ffmpeg -f image2 -r 25 -pattern_type glob -i '*.jpg' -an -c:v libx264 -r 25 timelapse.mp4
ffmpeg probably uses the same file name globbing facility as the shell, so all valid file name globbing patterns should work. Specifically in your case, a pattern of images/201?-??-??/??/201?-??-??-????-?? will expand to all files in question e.g.
ls -l images/201?-??-??/??/201?-??-??-????-??
ffmpeg ... 'images/201?-??-??/??/201?-??-??-????-??' ...
Note the quotes around the pattern in the ffmpeg invocation: you want to pass the pattern verbatim to ffmpeg to expand the pattern into file names, not have the shell do the expansion.
I'm trying to cross-fade several audio files together with a 3 second cross-fade and join them together in to one file with sox.
I can join several files together by the command below but not sure how to cross fade between each one:
sox $(ls /tmp/a*.wav | sort -n) /tmp/out/out.wav
I can cross fade two files with the commands below but not sure how to combine the first line that joins several files together with the second line that splices / cross fades
sox 100hz.wav 440hz.wav out.wav splice $(soxi -D 100hz.wav),3
I found this question but the answer doesn't work for me.
crossfading a group of audio files with sox splice
I don't know if you are aware of the crossfade_cat.sh script offered by sox. You could just use it successively:
./crossfade_cat.sh 1 440.wav 660.wav auto auto && ./crossfade_cat.sh 1 mix.wav 880.wav auto auto
Or if you want to crossfade a high number of wav files, to use all files in a directory you could use a shell loop, something like this:
crossfade_dur=1
i=0
for file in *.wav
do
i=$((i+1))
if [ $i -eq 1 ]
then
cp $file mix.wav
else
crossfade_cat.sh $crossfade_dur mix.wav $file auto auto
fi
done