Axiom icon indicating copy to clipboard operation
Axiom copied to clipboard

Convert files to HLS (.m3u8)

Open Thiagobhmg opened this issue 4 years ago • 8 comments

It would be great to be able to output files in HLS. It would be possible? Could anyone help?

Thiagobhmg avatar May 31 '20 00:05 Thiagobhmg

I managed to run a batch to generate the .m3u8 file, you could add the conversion to this format in the list too, with more options.

"F:\convertvideos\Axiom.FFmpeg\ffmpeg\bin\ffmpeg.exe"

-i "F:\test\test.mp4"

-profile:v baseline -level 3.0 -s 1920x1080 -start_number 0 -hls_time 10 -hls_list_size 0

-f hls index.m3u8

Thiagobhmg avatar May 31 '20 01:05 Thiagobhmg

I return to congratulate the work that is being developed in this program. I think they should really think about adding the output in HLS (m3u8). In none of the other systems there is the possibility of making this conversion. I managed to adapt the script but it would be great to have this option to select.

Thiagobhmg avatar May 31 '20 02:05 Thiagobhmg

@Thiagobhmg

I will take a look at adding it.

What is the conversion doing? It converts the .mp4 to a .ts file and creates an .m3u8 playlist for it?

Do you have more information on these 3 options?:

  • -start_number 0
  • -hls_time 10
  • -hls_list_size 0

MattMcManis avatar May 31 '20 06:05 MattMcManis

I am testing various combinations. I will try to describe what each thing in HLS does as I understand it.

The best combination so far has been this one. Because it ran with the CUDA of the video card (I was very happy with the possibility) because it improved the conversion speed of the files by 6x. I didn't understand why you don't use all the processing power of the board, is it possible to configure this?

"F:\convertvideos\Axiom.FFmpeg\ffmpeg\bin\ffmpeg.exe" 

-y 

-hwaccel cuda 

-i "F:\test\test.mp4"

-vf scale=w=1280:h=720:force_original_aspect_ratio=decrease 
-c:a aac
-ar 44100 
-b:a 128k 
-c:v h264_nvenc
-profile:v main 
-crf 20
-g 48 
-keyint_min 48 
-sc_threshold 0
-b:v 2500k
-maxrate 2675k 
-bufsize 3750k 
-hls_time 4 
-hls_playlist_type vod 
-hls_segment_filename test/720p_%03d.ts test/720p.m3u8

-hls_time

is every few seconds the file will be broken into .TS the default is 2 seconds, but it can be configured as the person wants. As I understand it when advancing through the time line he always starts the video .Ts closest to where he clicked on the player's timeline.

-hls_segment_filename

is how it saves the name of the .Ts segments and the .m3u8 file (which generates the playlist with the .Ts segments)

The ideal here would be to be able to configure variables such as output-directory / date-time-name-of-the-original-file.

-vf scale

Here is for the person to scale the video. I found it best to use in this configuration. But people should be able to choose the format they want.

Resolution Playlist

Another thing that would be important to implement is the generation of one of the playlist for loading the video in the player according to the desired resolutions of the video.

For example: 360p, 540p, 720p or 1080p.

I found this script that can help: would it be possible to run this script on Windows?

Sorry for the questions, I'm not a developer. I understand only the basics of programming.

Thiagobhmg avatar Jun 01 '20 15:06 Thiagobhmg

I found this script that can help:

would it be possible to run this script on Windows?

Sorry for the questions, I'm not a developer. I understand only the basics of programming.

Developed by @mrbar42

File to be converted to HLS

bash create-vod-hls.sh beach.mkv

#!/usr/bin/env bash

set -e

# Usage create-vod-hls.sh SOURCE_FILE [OUTPUT_NAME]
[[ ! "${1}" ]] && echo "Usage: create-vod-hls.sh SOURCE_FILE [OUTPUT_NAME]" && exit 1

# comment/add lines here to control which renditions would be created
renditions=(
# resolution  bitrate  audio-rate
#  "426x240    400k    64k"
  "640x360    800k     96k"
  "842x480    1400k    128k"
  "1280x720   2800k    128k"
  "1920x1080  5000k    192k"
)

segment_target_duration=4       # try to create a new segment every X seconds
max_bitrate_ratio=1.07          # maximum accepted bitrate fluctuations
rate_monitor_buffer_ratio=1.5   # maximum buffer size between bitrate conformance checks

#########################################################################

source="${1}"
target="${2}"
if [[ ! "${target}" ]]; then
  target="${source##*/}" # leave only last component of path
  target="${target%.*}"  # strip extension
fi
mkdir -p ${target}


key_frames_interval="$(echo `ffprobe ${source} 2>&1 | grep -oE '[[:digit:]]+(.[[:digit:]]+)? fps' | grep -oE '[[:digit:]]+(.[[:digit:]]+)?'`*2 | bc || echo '')"
key_frames_interval=${key_frames_interval:-50}
key_frames_interval=$(echo `printf "%.1f\n" $(bc -l <<<"$key_frames_interval/10")`*10 | bc) # round
key_frames_interval=${key_frames_interval%.*} # truncate to integer

# static parameters that are similar for all renditions
static_params="-c:a aac -ar 48000 -c:v h264 -profile:v main -crf 20 -sc_threshold 0"
static_params+=" -g ${key_frames_interval} -keyint_min ${key_frames_interval} -hls_time ${segment_target_duration}"
static_params+=" -hls_playlist_type vod"

# misc params
misc_params="-hide_banner -y"

master_playlist="#EXTM3U
#EXT-X-VERSION:3
"
cmd=""
for rendition in "${renditions[@]}"; do
  # drop extraneous spaces
  rendition="${rendition/[[:space:]]+/ }"

  # rendition fields
  resolution="$(echo ${rendition} | cut -d ' ' -f 1)"
  bitrate="$(echo ${rendition} | cut -d ' ' -f 2)"
  audiorate="$(echo ${rendition} | cut -d ' ' -f 3)"

  # calculated fields
  width="$(echo ${resolution} | grep -oE '^[[:digit:]]+')"
  height="$(echo ${resolution} | grep -oE '[[:digit:]]+$')"
  maxrate="$(echo "`echo ${bitrate} | grep -oE '[[:digit:]]+'`*${max_bitrate_ratio}" | bc)"
  bufsize="$(echo "`echo ${bitrate} | grep -oE '[[:digit:]]+'`*${rate_monitor_buffer_ratio}" | bc)"
  bandwidth="$(echo ${bitrate} | grep -oE '[[:digit:]]+')000"
  name="${height}p"
  
  cmd+=" ${static_params} -vf scale=w=${width}:h=${height}:force_original_aspect_ratio=decrease"
  cmd+=" -b:v ${bitrate} -maxrate ${maxrate%.*}k -bufsize ${bufsize%.*}k -b:a ${audiorate}"
  cmd+=" -hls_segment_filename ${target}/${name}_%03d.ts ${target}/${name}.m3u8"
  
  # add rendition entry in the master playlist
  master_playlist+="#EXT-X-STREAM-INF:BANDWIDTH=${bandwidth},RESOLUTION=${resolution}\n${name}.m3u8\n"
done

# start conversion
echo -e "Executing command:\nffmpeg ${misc_params} -i ${source} ${cmd}"
ffmpeg ${misc_params} -i ${source} ${cmd}

# create master playlist file
echo -e "${master_playlist}" > ${target}/playlist.m3u8

echo "Done - encoded HLS is at ${target}/"

Thiagobhmg avatar Jun 02 '20 03:06 Thiagobhmg

-vf "scale=w=1280:h=720:force_original_aspect_ratio=decrease" - scale video to maximum possible within 1280x720 while preserving aspect ratio

-c:a aac -ar 48000 -b:a 128k - set audio codec to AAC with sampling of 48kHz and bitrate of 128k

-c:v h264 - set video codec to be H264 which is the standard codec of HLS segments

-profile:v main - set H264 profile to main - this means support in modern devices read more

-crf 20 - Constant Rate Factor, high level factor for overall quality

-g 48 -keyint_min 48 - IMPORTANT create key frame (I-frame) every 48 frames (~2 seconds) - will later affect correct slicing of segments and alignment of renditions

-sc_threshold 0 - don't create key frames on scene change - only according to -g

-b:v 2500k -maxrate 2675k -bufsize 3750k - limit video bitrate, these are rendition specific and depends on your content type - read more

-hls_time 4 - segment target duration in seconds - the actual length is constrained by key frames

-hls_playlist_type vod - adds the #EXT-X-PLAYLIST-TYPE:VOD tag and keeps all segments in the playlist

-hls_segment_filename test/720p_%03d.ts - explicitly define segments files names test/720p.m3u8 - path of the playlist file - also tells ffmpeg to output HLS (.m3u8)

Thiagobhmg avatar Jun 02 '20 03:06 Thiagobhmg

@Thiagobhmg

I will look over all this soon, I had to spend a few days finishing another feature.

MattMcManis avatar Jun 08 '20 22:06 MattMcManis

updating the conversion script I was able to use.

With this script the youtube video will be downloaded, converted to .mkv and then the file in m3u8 will be converted to VOD, generating the Playlist.

cd /d "F:\test\" 

&& 

for /f "delims=" %f in (' 

@"F:\Axiom.FFmpeg\youtube-dl\youtube-dl.exe" 
--get-filename -o "%(title)s" "https://www.youtube.com/watch?v=Cr8GwDXuOLg" 
') 

do ( 

@"F:\Axiom.FFmpeg\youtube-dl\youtube-dl.exe" 

-f bestvideo[ext=mp4]+bestaudio[ext=m4a]/bestvideo+bestaudio/best 

"https://www.youtube.com/watch?v=Cr8GwDXuOLg" 
-o "F:\test\%f.mkv" 

 --ffmpeg-location "F:\Axiom.FFmpeg\ffmpeg\bin\ffmpeg.exe" 

--merge-output-format mkv

&& 

"F:\Axiom.FFmpeg\ffmpeg\bin\ffmpeg.exe" 

-y 

-hwaccel cuda

-i "F:\test\%f.mkv"

-vf scale=w=1280:h=720:force_original_aspect_ratio=decrease
-pix_fmt nv21
-preset slow
-g 48 
-sc_threshold 0
-map 0:0 -map 0:1 -map 0:0 -map 0:1
-s:v:0 640x360 -c:v:0 libx264 -b:v:0 365k
-s:v:1 960x540 -c:v:1 libx264 -b:v:1 2000k
-c:v h264_nvenc
-var_stream_map "v:0,a:0 v:1,a:1"
-master_pl_name master.m3u8
-f hls -hls_time 2 -hls_list_size 0
-hls_segment_filename "v%v/fileSequence%d.ts"
v%v/prog_index.m3u8

&& 

del "F:\test\%f.mkv" 
)

Thiagobhmg avatar Sep 25 '20 19:09 Thiagobhmg