mirror of
https://github.com/levogevo/ffmpeg-builder.git
synced 2026-03-16 19:20:11 +00:00
Compare commits
6 Commits
73bb7338f4
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 852d7e3795 | |||
| 18815854f5 | |||
| 5261b67a18 | |||
| c2be0112fb | |||
| f1b2a0d534 | |||
| 64c7f358fc |
@@ -13,7 +13,7 @@ Tested on:
|
|||||||
With these scripts you can:
|
With these scripts you can:
|
||||||
1. install required dependencies using `./scripts/install_deps.sh`
|
1. install required dependencies using `./scripts/install_deps.sh`
|
||||||
2. build ffmpeg with the desired configuration using `./scripts/build.sh`
|
2. build ffmpeg with the desired configuration using `./scripts/build.sh`
|
||||||
3. encode a file using libsvtav1_psy and libopus using `./scripts/encode.sh`
|
3. encode a file using libsvtav1 and libopus using `./scripts/encode.sh`
|
||||||
4. estimate the film grain of a given file using `./scripts/efg.sh`
|
4. estimate the film grain of a given file using `./scripts/efg.sh`
|
||||||
|
|
||||||
# Building
|
# Building
|
||||||
@@ -24,7 +24,7 @@ Configuration is done through environment variables.
|
|||||||
By default, this project will build a static `ffmpeg` binary in `./gitignore/sysroot/bin/ffmpeg`.
|
By default, this project will build a static `ffmpeg` binary in `./gitignore/sysroot/bin/ffmpeg`.
|
||||||
|
|
||||||
The user-overridable compile options are:
|
The user-overridable compile options are:
|
||||||
- `ENABLE`: configure what ffmpeg enables (default: libaom libass libvpx libxml2 libvmaf libx264 libx265 libwebp libopus librav1e libdav1d libvorbis libmp3lame libfribidi libfreetype libharfbuzz libsvtav1_psy libfontconfig )
|
- `ENABLE`: configure what ffmpeg enables (default: libaom libass libvpx libxml2 libvmaf libx264 libx265 libwebp libopus librav1e libdav1d libvorbis libmp3lame libfribidi libfreetype libharfbuzz libopenjpeg libsvtav1_hdr libfontconfig )
|
||||||
- `PREFIX`: prefix to install to, default is local install in ./gitignore/sysroot (default: local)
|
- `PREFIX`: prefix to install to, default is local install in ./gitignore/sysroot (default: local)
|
||||||
- `STATIC`: static or shared build (default: ON)
|
- `STATIC`: static or shared build (default: ON)
|
||||||
- `LTO`: enable link time optimization (default: ON)
|
- `LTO`: enable link time optimization (default: ON)
|
||||||
@@ -78,6 +78,7 @@ encode -i input [options] output
|
|||||||
- Skips re-encoding av1/opus streams.
|
- Skips re-encoding av1/opus streams.
|
||||||
- Only maps audio streams that match the video stream language if the video stream has a defined language.
|
- Only maps audio streams that match the video stream language if the video stream has a defined language.
|
||||||
- Only maps english subtitle streams.
|
- Only maps english subtitle streams.
|
||||||
|
- Crop PGS subtitles to match video dimensions.
|
||||||
- Adds track statistics to the output mkv file and embeds the encoder versions to the output metadata. For example:
|
- Adds track statistics to the output mkv file and embeds the encoder versions to the output metadata. For example:
|
||||||
```
|
```
|
||||||
ENCODE : aa4d7e6
|
ENCODE : aa4d7e6
|
||||||
|
|||||||
@@ -533,3 +533,10 @@ benchmark_command() {
|
|||||||
}
|
}
|
||||||
' "${trace}" | sort -rn | head -n 20
|
' "${trace}" | sort -rn | head -n 20
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# make sure supmover is built
|
||||||
|
# and set SUPMOVER
|
||||||
|
check_for_supmover() {
|
||||||
|
SUPMOVER="${LOCAL_PREFIX}/bin/supmover"
|
||||||
|
test -f "${SUPMOVER}" || do_build supmover || return 1
|
||||||
|
}
|
||||||
|
|||||||
58
lib/build.sh
58
lib/build.sh
@@ -324,6 +324,7 @@ fi' >"${compilerDir}/which"
|
|||||||
|
|
||||||
get_build_conf() {
|
get_build_conf() {
|
||||||
local getBuild="${1}"
|
local getBuild="${1}"
|
||||||
|
local getBuildValue="${2:-}"
|
||||||
|
|
||||||
local longestBuild=0
|
local longestBuild=0
|
||||||
local longestVer=0
|
local longestVer=0
|
||||||
@@ -335,12 +336,13 @@ get_build_conf() {
|
|||||||
local BUILDS_CONF='
|
local BUILDS_CONF='
|
||||||
ffmpeg 8.0.1 tar.gz https://github.com/FFmpeg/FFmpeg/archive/refs/tags/n${ver}.${ext}
|
ffmpeg 8.0.1 tar.gz https://github.com/FFmpeg/FFmpeg/archive/refs/tags/n${ver}.${ext}
|
||||||
|
|
||||||
|
libsvtav1_hdr 4.0.1 tar.gz https://github.com/juliobbv-p/svt-av1-hdr/archive/refs/tags/v${ver}.${ext} dovi_tool,hdr10plus_tool,cpuinfo
|
||||||
libsvtav1_psy 3.0.2-B tar.gz https://github.com/BlueSwordM/svt-av1-psyex/archive/refs/tags/v${ver}.${ext} dovi_tool,hdr10plus_tool,cpuinfo
|
libsvtav1_psy 3.0.2-B tar.gz https://github.com/BlueSwordM/svt-av1-psyex/archive/refs/tags/v${ver}.${ext} dovi_tool,hdr10plus_tool,cpuinfo
|
||||||
hdr10plus_tool 1.7.2 tar.gz https://github.com/quietvoid/hdr10plus_tool/archive/refs/tags/${ver}.${ext}
|
hdr10plus_tool 1.7.2 tar.gz https://github.com/quietvoid/hdr10plus_tool/archive/refs/tags/${ver}.${ext}
|
||||||
dovi_tool 2.3.1 tar.gz https://github.com/quietvoid/dovi_tool/archive/refs/tags/${ver}.${ext}
|
dovi_tool 2.3.1 tar.gz https://github.com/quietvoid/dovi_tool/archive/refs/tags/${ver}.${ext}
|
||||||
cpuinfo latest git https://github.com/pytorch/cpuinfo/
|
cpuinfo latest git https://github.com/pytorch/cpuinfo/
|
||||||
|
|
||||||
libsvtav1 3.1.2 tar.gz https://gitlab.com/AOMediaCodec/SVT-AV1/-/archive/v${ver}/SVT-AV1-v${ver}.${ext}
|
libsvtav1 4.0.1 tar.gz https://gitlab.com/AOMediaCodec/SVT-AV1/-/archive/v${ver}/SVT-AV1-v${ver}.${ext}
|
||||||
librav1e 0.8.1 tar.gz https://github.com/xiph/rav1e/archive/refs/tags/v${ver}.${ext}
|
librav1e 0.8.1 tar.gz https://github.com/xiph/rav1e/archive/refs/tags/v${ver}.${ext}
|
||||||
libaom 3.13.1 tar.gz https://storage.googleapis.com/aom-releases/libaom-${ver}.${ext}
|
libaom 3.13.1 tar.gz https://storage.googleapis.com/aom-releases/libaom-${ver}.${ext}
|
||||||
libvmaf 3.0.0 tar.gz https://github.com/Netflix/vmaf/archive/refs/tags/v${ver}.${ext}
|
libvmaf 3.0.0 tar.gz https://github.com/Netflix/vmaf/archive/refs/tags/v${ver}.${ext}
|
||||||
@@ -454,6 +456,11 @@ supmover 2.4.3 tar.gz https://github.com/MonoS/SupMover/archi
|
|||||||
extractedDir="${BUILD_DIR}/${build}-v${ver}"
|
extractedDir="${BUILD_DIR}/${build}-v${ver}"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if [[ -n ${getBuildValue} ]]; then
|
||||||
|
declare -n value=${getBuildValue}
|
||||||
|
echo "${value}"
|
||||||
|
fi
|
||||||
|
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -514,7 +521,7 @@ download_release() {
|
|||||||
else
|
else
|
||||||
# for git downloads
|
# for git downloads
|
||||||
test -d "${download}" ||
|
test -d "${download}" ||
|
||||||
git clone --recursive "${url}" "${download}" || return 1
|
git clone --depth 1 --recursive "${url}" "${download}" || return 1
|
||||||
(
|
(
|
||||||
cd "${download}" || exit 1
|
cd "${download}" || exit 1
|
||||||
local localHEAD remoteHEAD
|
local localHEAD remoteHEAD
|
||||||
@@ -605,7 +612,7 @@ do_build() {
|
|||||||
echo "LOCAL_PREFIX: ${LOCAL_PREFIX}"
|
echo "LOCAL_PREFIX: ${LOCAL_PREFIX}"
|
||||||
for patch in "${PATCHES_DIR}/${build}"/*.patch; do
|
for patch in "${PATCHES_DIR}/${build}"/*.patch; do
|
||||||
test -f "${patch}" || continue
|
test -f "${patch}" || continue
|
||||||
echo -e "patch:${patch}\n$(<"${patch}")" >>"${newMetadataFile}"
|
echo -e "patch:${patch}\n$(<"${patch}")"
|
||||||
done
|
done
|
||||||
COLOR=OFF SHOW_SINGLE=true dump_arr "${BUILD_ENV_NAMES[@]}"
|
COLOR=OFF SHOW_SINGLE=true dump_arr "${BUILD_ENV_NAMES[@]}"
|
||||||
} >"${newMetadataFile}"
|
} >"${newMetadataFile}"
|
||||||
@@ -839,19 +846,21 @@ build_cpuinfo() {
|
|||||||
sanitize_sysroot_libs libcpuinfo || return 1
|
sanitize_sysroot_libs libcpuinfo || return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
build_libsvtav1() {
|
build_libsvtav1_hdr() {
|
||||||
meta_cmake_build \
|
build_libsvtav1_psy
|
||||||
-DENABLE_AVX512=ON \
|
|
||||||
-DCOVERAGE=OFF || return 1
|
|
||||||
sanitize_sysroot_libs libSvtAv1Enc || return 1
|
|
||||||
}
|
}
|
||||||
|
|
||||||
build_libsvtav1_psy() {
|
build_libsvtav1_psy() {
|
||||||
meta_cmake_build \
|
build_libsvtav1 \
|
||||||
-DENABLE_AVX512=ON \
|
|
||||||
-DCOVERAGE=OFF \
|
|
||||||
-DLIBDOVI_FOUND=1 \
|
-DLIBDOVI_FOUND=1 \
|
||||||
-DLIBHDR10PLUS_RS_FOUND=1 || return 1
|
-DLIBHDR10PLUS_RS_FOUND=1
|
||||||
|
}
|
||||||
|
|
||||||
|
build_libsvtav1() {
|
||||||
|
meta_cmake_build \
|
||||||
|
-DSVT_AV1_LTO=OFF \
|
||||||
|
-DENABLE_AVX512=ON \
|
||||||
|
-DCOVERAGE=OFF "$@" || return 1
|
||||||
sanitize_sysroot_libs libSvtAv1Enc || return 1
|
sanitize_sysroot_libs libSvtAv1Enc || return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -985,6 +994,13 @@ build_cmake3() (
|
|||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if is_android; then
|
||||||
|
CMAKE_FLAGS+=(
|
||||||
|
"-DCMAKE_USE_SYSTEM_LIBUV=ON"
|
||||||
|
"-DCMAKE_USE_SYSTEM_LIBARCHIVE=ON"
|
||||||
|
)
|
||||||
|
fi
|
||||||
|
|
||||||
CMAKE_FLAGS+=(
|
CMAKE_FLAGS+=(
|
||||||
"-DCMAKE_PREFIX_PATH=${LOCAL_PREFIX}"
|
"-DCMAKE_PREFIX_PATH=${LOCAL_PREFIX}"
|
||||||
"-DCMAKE_INSTALL_PREFIX=${LOCAL_PREFIX}"
|
"-DCMAKE_INSTALL_PREFIX=${LOCAL_PREFIX}"
|
||||||
@@ -1261,14 +1277,11 @@ add_project_versioning_to_ffmpeg() {
|
|||||||
'' # pad with empty line
|
'' # pad with empty line
|
||||||
"ffmpeg-builder=$(git -C "${REPO_DIR}" rev-parse HEAD)"
|
"ffmpeg-builder=$(git -C "${REPO_DIR}" rev-parse HEAD)"
|
||||||
)
|
)
|
||||||
for build in ${ENABLE}; do
|
for build in ${ENABLE} ffmpeg; do
|
||||||
get_build_conf "${build}" || return 1
|
get_build_conf "${build}" || return 1
|
||||||
# add build configuration info
|
# add build configuration info
|
||||||
FFMPEG_BUILDER_INFO+=("${build}=${ver}")
|
FFMPEG_BUILDER_INFO+=("${build}=${ver}")
|
||||||
done
|
done
|
||||||
# and finally for ffmpeg itself
|
|
||||||
get_build_conf ffmpeg || return 1
|
|
||||||
FFMPEG_BUILDER_INFO+=("${build}=${ver}")
|
|
||||||
|
|
||||||
local fname='opt_common.c'
|
local fname='opt_common.c'
|
||||||
local optFile="fftools/${fname}"
|
local optFile="fftools/${fname}"
|
||||||
@@ -1286,9 +1299,18 @@ add_project_versioning_to_ffmpeg() {
|
|||||||
build_ffmpeg() {
|
build_ffmpeg() {
|
||||||
add_project_versioning_to_ffmpeg || return 1
|
add_project_versioning_to_ffmpeg || return 1
|
||||||
|
|
||||||
# libsvtav1_psy real name is libsvtav1
|
# libsvtav1_* patch and enable name change
|
||||||
for enable in ${ENABLE}; do
|
for enable in ${ENABLE}; do
|
||||||
test "${enable}" == 'libsvtav1_psy' && enable='libsvtav1'
|
if line_starts_with "${enable}" libsvtav1; then
|
||||||
|
# libsvtav1 v4 is breaking API
|
||||||
|
if [[ "$(get_build_conf "${enable}" ver)" == '4'* ]]; then
|
||||||
|
replace_line \
|
||||||
|
libavcodec/libsvtav1.c \
|
||||||
|
'param->enable_adaptive_quantization = 0;' \
|
||||||
|
'param->aq_mode = 0;' || return 1
|
||||||
|
fi
|
||||||
|
enable=libsvtav1
|
||||||
|
fi
|
||||||
CONFIGURE_FLAGS+=("--enable-${enable}")
|
CONFIGURE_FLAGS+=("--enable-${enable}")
|
||||||
done
|
done
|
||||||
|
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ libfribidi \
|
|||||||
libfreetype \
|
libfreetype \
|
||||||
libharfbuzz \
|
libharfbuzz \
|
||||||
libopenjpeg \
|
libopenjpeg \
|
||||||
libsvtav1_psy \
|
libsvtav1_hdr \
|
||||||
libfontconfig \
|
libfontconfig \
|
||||||
"
|
"
|
||||||
|
|
||||||
|
|||||||
375
lib/encode.sh
375
lib/encode.sh
@@ -1,25 +1,27 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
# sets unmapStreams
|
DESIRED_SUB_LANG=eng
|
||||||
|
|
||||||
|
# sets UNMAP_STREAMS
|
||||||
set_unmap_streams() {
|
set_unmap_streams() {
|
||||||
local file="$1"
|
local file="$1"
|
||||||
local unmapFilter='bin_data|jpeg|png'
|
local unmapFilter='bin_data|jpeg|png'
|
||||||
local streamsStr
|
local streamsStr
|
||||||
unmapStreams=()
|
UNMAP_STREAMS=()
|
||||||
streamsStr="$(get_num_streams "${file}")" || return 1
|
streamsStr="$(get_num_streams "${file}")" || return 1
|
||||||
mapfile -t streams <<<"${streamsStr}" || return 1
|
mapfile -t streams <<<"${streamsStr}" || return 1
|
||||||
for stream in "${streams[@]}"; do
|
for stream in "${streams[@]}"; do
|
||||||
if [[ "$(get_stream_codec "${file}" "${stream}")" =~ ${unmapFilter} ]]; then
|
if [[ "$(get_stream_codec "${file}" "${stream}")" =~ ${unmapFilter} ]]; then
|
||||||
unmapStreams+=("-map" "-0:${stream}")
|
UNMAP_STREAMS+=("-map" "-0:${stream}")
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
}
|
}
|
||||||
|
|
||||||
# sets audioParams
|
# sets AUDIO_PARAMS
|
||||||
set_audio_params() {
|
set_audio_params() {
|
||||||
local file="$1"
|
local file="$1"
|
||||||
local videoLang
|
local videoLang
|
||||||
audioParams=()
|
AUDIO_PARAMS=()
|
||||||
videoLang="$(get_stream_lang "${file}" 'v:0')" || return 1
|
videoLang="$(get_stream_lang "${file}" 'v:0')" || return 1
|
||||||
for stream in $(get_num_streams "${file}" 'a'); do
|
for stream in $(get_num_streams "${file}" 'a'); do
|
||||||
local numChannels codec lang
|
local numChannels codec lang
|
||||||
@@ -32,18 +34,18 @@ set_audio_params() {
|
|||||||
codec="$(get_stream_codec "${file}" "${stream}")" || return 1
|
codec="$(get_stream_codec "${file}" "${stream}")" || return 1
|
||||||
lang="$(get_stream_lang "${file}" "${stream}")" || return 1
|
lang="$(get_stream_lang "${file}" "${stream}")" || return 1
|
||||||
if [[ ${videoLang} != '' && ${videoLang} != "${lang}" ]]; then
|
if [[ ${videoLang} != '' && ${videoLang} != "${lang}" ]]; then
|
||||||
audioParams+=(
|
AUDIO_PARAMS+=(
|
||||||
'-map'
|
'-map'
|
||||||
"-0:${stream}"
|
"-0:${stream}"
|
||||||
)
|
)
|
||||||
elif [[ ${codec} == 'opus' ]]; then
|
elif [[ ${codec} == 'opus' ]]; then
|
||||||
audioParams+=(
|
AUDIO_PARAMS+=(
|
||||||
"-c:${OUTPUT_INDEX}"
|
"-c:${OUTPUT_INDEX}"
|
||||||
"copy"
|
"copy"
|
||||||
)
|
)
|
||||||
OUTPUT_INDEX=$((OUTPUT_INDEX + 1))
|
OUTPUT_INDEX=$((OUTPUT_INDEX + 1))
|
||||||
else
|
else
|
||||||
audioParams+=(
|
AUDIO_PARAMS+=(
|
||||||
"-filter:${OUTPUT_INDEX}"
|
"-filter:${OUTPUT_INDEX}"
|
||||||
"aformat=channel_layouts=7.1|5.1|stereo|mono"
|
"aformat=channel_layouts=7.1|5.1|stereo|mono"
|
||||||
"-c:${OUTPUT_INDEX}"
|
"-c:${OUTPUT_INDEX}"
|
||||||
@@ -56,11 +58,10 @@ set_audio_params() {
|
|||||||
done
|
done
|
||||||
}
|
}
|
||||||
|
|
||||||
# sets subtitleParams
|
# sets SUBTITLE_PARAMS
|
||||||
set_subtitle_params() {
|
set_subtitle_params() {
|
||||||
local file="$1"
|
local file="$1"
|
||||||
local convertCodec='eia_608'
|
local convertCodec='eia_608'
|
||||||
local keepLang='eng'
|
|
||||||
|
|
||||||
local defaultTextCodec
|
local defaultTextCodec
|
||||||
if [[ ${SAME_CONTAINER} == false && ${FILE_EXT} == 'mkv' ]]; then
|
if [[ ${SAME_CONTAINER} == false && ${FILE_EXT} == 'mkv' ]]; then
|
||||||
@@ -71,18 +72,27 @@ set_subtitle_params() {
|
|||||||
convertCodec+='|srt'
|
convertCodec+='|srt'
|
||||||
fi
|
fi
|
||||||
|
|
||||||
subtitleParams=()
|
SUBTITLE_PARAMS=()
|
||||||
for stream in $(get_num_streams "${file}" 's'); do
|
for stream in $(get_num_streams "${file}" 's'); do
|
||||||
local codec lang
|
local codec lang
|
||||||
codec="$(get_stream_codec "${file}" "${stream}")" || return 1
|
codec="$(get_stream_codec "${file}" "${stream}")" || return 1
|
||||||
lang="$(get_stream_lang "${file}" "${stream}")" || return 1
|
lang="$(get_stream_lang "${file}" "${stream}")" || return 1
|
||||||
if [[ ${lang} != '' && ${keepLang} != "${lang}" ]]; then
|
if [[ ${lang} != '' && ${DESIRED_SUB_LANG} != "${lang}" ]]; then
|
||||||
subtitleParams+=(
|
SUBTITLE_PARAMS+=(
|
||||||
'-map'
|
'-map'
|
||||||
"-0:${stream}"
|
"-0:${stream}"
|
||||||
)
|
)
|
||||||
elif [[ ${codec} =~ ${convertCodec} ]]; then
|
elif [[ ${codec} =~ ${convertCodec} ]]; then
|
||||||
subtitleParams+=("-c:${OUTPUT_INDEX}" "${defaultTextCodec}")
|
SUBTITLE_PARAMS+=("-c:${OUTPUT_INDEX}" "${defaultTextCodec}")
|
||||||
|
OUTPUT_INDEX=$((OUTPUT_INDEX + 1))
|
||||||
|
elif [[ ${codec} == 'hdmv_pgs_subtitle' ]]; then
|
||||||
|
PGS_SUB_STREAMS+=("${stream}")
|
||||||
|
SUBTITLE_PARAMS+=(
|
||||||
|
'-map'
|
||||||
|
"-0:${stream}"
|
||||||
|
)
|
||||||
|
else
|
||||||
|
# map -0 covers the stream but still want to increment the index
|
||||||
OUTPUT_INDEX=$((OUTPUT_INDEX + 1))
|
OUTPUT_INDEX=$((OUTPUT_INDEX + 1))
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
@@ -91,59 +101,228 @@ set_subtitle_params() {
|
|||||||
get_encode_versions() {
|
get_encode_versions() {
|
||||||
action="${1:-}"
|
action="${1:-}"
|
||||||
|
|
||||||
encodeVersion="encode=$(git -C "${REPO_DIR}" rev-parse --short HEAD)"
|
ENCODE_VERSION="encode=$(git -C "${REPO_DIR}" rev-parse --short HEAD)"
|
||||||
ffmpegVersion=''
|
FFMPEG_VERSION=''
|
||||||
videoEncVersion=''
|
VIDEO_ENC_VERSION=''
|
||||||
audioEncVersion=''
|
AUDIO_ENC_VERSION=''
|
||||||
|
|
||||||
# shellcheck disable=SC2155
|
# shellcheck disable=SC2155
|
||||||
local output="$(ffmpeg -version 2>&1)"
|
local output="$(ffmpeg -version 2>&1)"
|
||||||
while read -r line; do
|
while read -r line; do
|
||||||
if line_starts_with "${line}" 'ffmpeg='; then
|
if line_starts_with "${line}" 'ffmpeg='; then
|
||||||
ffmpegVersion="${line}"
|
FFMPEG_VERSION="${line}"
|
||||||
elif line_starts_with "${line}" 'libsvtav1'; then
|
elif line_starts_with "${line}" 'libsvtav1'; then
|
||||||
videoEncVersion="${line}"
|
VIDEO_ENC_VERSION="${line}"
|
||||||
elif line_starts_with "${line}" 'libopus='; then
|
elif line_starts_with "${line}" 'libopus='; then
|
||||||
audioEncVersion="${line}"
|
AUDIO_ENC_VERSION="${line}"
|
||||||
fi
|
fi
|
||||||
done <<<"${output}"
|
done <<<"${output}"
|
||||||
|
|
||||||
local version
|
local version
|
||||||
if [[ ${ffmpegVersion} == '' ]]; then
|
if [[ ${FFMPEG_VERSION} == '' ]]; then
|
||||||
while read -r line; do
|
while read -r line; do
|
||||||
if line_starts_with "${line}" 'ffmpeg version '; then
|
if line_starts_with "${line}" 'ffmpeg version '; then
|
||||||
read -r _ _ version _ <<<"${line}"
|
read -r _ _ version _ <<<"${line}"
|
||||||
ffmpegVersion="ffmpeg=${version}"
|
FFMPEG_VERSION="ffmpeg=${version}"
|
||||||
break
|
break
|
||||||
fi
|
fi
|
||||||
done <<<"${output}"
|
done <<<"${output}"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ ${videoEncVersion} == '' ]]; then
|
if [[ ${VIDEO_ENC_VERSION} == '' ]]; then
|
||||||
version="$(get_pkgconfig_version SvtAv1Enc)"
|
version="$(get_pkgconfig_version SvtAv1Enc)"
|
||||||
test "${version}" == '' && return 1
|
test "${version}" == '' && return 1
|
||||||
videoEncVersion="libsvtav1=${version}"
|
VIDEO_ENC_VERSION="libsvtav1=${version}"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ ${audioEncVersion} == '' ]]; then
|
if [[ ${AUDIO_ENC_VERSION} == '' ]]; then
|
||||||
version="$(get_pkgconfig_version opus)"
|
version="$(get_pkgconfig_version opus)"
|
||||||
test "${version}" == '' && return 1
|
test "${version}" == '' && return 1
|
||||||
audioEncVersion="libopus=${version}"
|
AUDIO_ENC_VERSION="libopus=${version}"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
test "${ffmpegVersion}" == '' && return 1
|
test "${FFMPEG_VERSION}" == '' && return 1
|
||||||
test "${videoEncVersion}" == '' && return 1
|
test "${VIDEO_ENC_VERSION}" == '' && return 1
|
||||||
test "${audioEncVersion}" == '' && return 1
|
test "${AUDIO_ENC_VERSION}" == '' && return 1
|
||||||
|
|
||||||
if [[ ${action} == 'print' ]]; then
|
if [[ ${action} == 'print' ]]; then
|
||||||
echo "${encodeVersion}"
|
echo "${ENCODE_VERSION}"
|
||||||
echo "${ffmpegVersion}"
|
echo "${FFMPEG_VERSION}"
|
||||||
echo "${videoEncVersion}"
|
echo "${VIDEO_ENC_VERSION}"
|
||||||
echo "${audioEncVersion}"
|
echo "${AUDIO_ENC_VERSION}"
|
||||||
fi
|
fi
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# given an input mkv/sup file,
|
||||||
|
# output a new mkv file with
|
||||||
|
# input metadata preserved
|
||||||
|
replace_mkv_sup() {
|
||||||
|
local mkvIn="$1"
|
||||||
|
local supIn="$2"
|
||||||
|
local mkvOut="$3"
|
||||||
|
local stream="${4:-0}"
|
||||||
|
|
||||||
|
local json
|
||||||
|
json="$(get_stream_json "${mkvIn}" "${stream}")" || return 1
|
||||||
|
|
||||||
|
# x:y
|
||||||
|
# x = stream json variable name
|
||||||
|
# y = mkvmerge option name
|
||||||
|
local optionMap=(
|
||||||
|
disposition.default:--default-track-flag
|
||||||
|
disposition.original:--original-flag
|
||||||
|
disposition.comment:--commentary-flag
|
||||||
|
disposition.forced:--forced-display-flag
|
||||||
|
disposition.hearing_impaired:--hearing-impaired-flag
|
||||||
|
tags.language:--language
|
||||||
|
tags.title:--track-name
|
||||||
|
)
|
||||||
|
|
||||||
|
# start building mkvmerge command
|
||||||
|
local mergeCmd=(
|
||||||
|
mkvmerge
|
||||||
|
-o "${mkvOut}"
|
||||||
|
)
|
||||||
|
for line in "${optionMap[@]}"; do
|
||||||
|
IFS=: read -r key option <<<"${line}"
|
||||||
|
local val
|
||||||
|
val="$(jq -r ".streams[].${key}" <<<"${json}")" || return 1
|
||||||
|
# skip undefined values
|
||||||
|
test "${val}" == null && continue
|
||||||
|
# always track 0 for single track
|
||||||
|
mergeCmd+=("${option}" "0:${val}")
|
||||||
|
done
|
||||||
|
mergeCmd+=("${supIn}")
|
||||||
|
|
||||||
|
"${mergeCmd[@]}"
|
||||||
|
}
|
||||||
|
|
||||||
|
crop_sup() {
|
||||||
|
local inSup="$1"
|
||||||
|
local outSup="$2"
|
||||||
|
local left="$3"
|
||||||
|
local top="$4"
|
||||||
|
local right="$5"
|
||||||
|
local bottom="$6"
|
||||||
|
local warnMsg='Window is outside new screen area'
|
||||||
|
local maxAcceptableWarn=5
|
||||||
|
local offset=5
|
||||||
|
|
||||||
|
# skip cropping if not needed
|
||||||
|
if [[ "${left}${top}${right}${bottom}" == "0000" ]]; then
|
||||||
|
cp "${inSup}" "${outSup}" || return 1
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
for ((try = 0; try < 30; try++)); do
|
||||||
|
echo_info "cropping sup with ${left} ${top} ${right} ${bottom}"
|
||||||
|
"${SUPMOVER}" \
|
||||||
|
"${inSup}" \
|
||||||
|
"${outSup}" \
|
||||||
|
--crop \
|
||||||
|
"${left}" "${top}" "${right}" "${bottom}" &>"${outSup}.out" || return 1
|
||||||
|
# supmover does not error for out-of-bounds subtitles
|
||||||
|
# so adjust crop value until there is most certainly no issue
|
||||||
|
if [[ "$(grep -c "${warnMsg}" "${cropSup}.out")" -gt ${maxAcceptableWarn} ]]; then
|
||||||
|
echo_warn "${warnMsg}, retrying... (try ${try})"
|
||||||
|
test "${left}" -gt ${offset} && left=$((left - offset))
|
||||||
|
test "${top}" -gt ${offset} && top=$((top - offset))
|
||||||
|
test "${right}" -gt ${offset} && right=$((right - offset))
|
||||||
|
test "${bottom}" -gt ${offset} && bottom=$((bottom - offset))
|
||||||
|
else
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
# if we got here, all tries were had, so indicate failure
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# extract PGS_SUB_STREAMS from INPUT
|
||||||
|
# and crop using CROP_VALUE
|
||||||
|
setup_pgs_mkv() {
|
||||||
|
local pgsMkvOut="$1"
|
||||||
|
|
||||||
|
if [[ ${#PGS_SUB_STREAMS[@]} -eq 0 ]]; then
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
check_for_supmover || return 1
|
||||||
|
|
||||||
|
# setup tempdir
|
||||||
|
local ogSup cropSup cropMkv tmpdir
|
||||||
|
tmpdir="${pgsMkvOut}-dir"
|
||||||
|
recreate_dir "${tmpdir}" || return 1
|
||||||
|
|
||||||
|
# get video resolution
|
||||||
|
local vidRes vidWidth vidHeight
|
||||||
|
vidRes="$(get_resolution "${INPUT}")"
|
||||||
|
IFS=x read -r vidWidth vidHeight <<<"${vidRes}"
|
||||||
|
|
||||||
|
for stream in "${PGS_SUB_STREAMS[@]}"; do
|
||||||
|
# extract sup from input
|
||||||
|
ogSup="${tmpdir}/${stream}.sup"
|
||||||
|
cropSup="${tmpdir}/${stream}-cropped.sup"
|
||||||
|
cropMkv="${tmpdir}/${stream}.mkv"
|
||||||
|
mkvextract "${INPUT}" tracks "${stream}:${ogSup}" || return 1
|
||||||
|
|
||||||
|
# check sup resolution
|
||||||
|
local supRes
|
||||||
|
supRes="$(get_sup_resolution "${ogSup}")" || return 1
|
||||||
|
local supWidth supHeight
|
||||||
|
IFS=x read -r supWidth supHeight <<<"${supRes}"
|
||||||
|
local left top right bottom
|
||||||
|
# determine crop values
|
||||||
|
# if the supfile is smaller than the video stream
|
||||||
|
# crop using aspect ratio instead of resolution
|
||||||
|
if [[ ${vidWidth} -gt ${supWidth} || ${vidHeight} -gt ${supHeight} ]]; then
|
||||||
|
echo_warn "PGS sup (stream=${stream}) is somehow smaller than initial video stream"
|
||||||
|
echo_warn "cropping based off of aspect ratio instead of resolution"
|
||||||
|
left=0
|
||||||
|
# (supHeight - ((vidHeight/vidWidth) * supWidth)) / 2
|
||||||
|
top="$(awk '{ print int(($1 - ($2 / $3 * $4)) / 2) }' <<<"${supHeight} ${vidHeight} ${vidWidth} ${supWidth}")"
|
||||||
|
right=${left}
|
||||||
|
bottom=${top}
|
||||||
|
# otherwise crop using the crop value
|
||||||
|
elif [[ ${CROP_VALUE} != '' ]]; then
|
||||||
|
# determine supmover crop based off of crop
|
||||||
|
local res w h x y
|
||||||
|
# extract ffmpeg crop value ("crop=w:h:x:y")
|
||||||
|
IFS='=' read -r _ res <<<"${CROP_VALUE}"
|
||||||
|
IFS=':' read -r w h x y <<<"${res}"
|
||||||
|
|
||||||
|
# ffmpeg crop value
|
||||||
|
# is different than supmover crop inputs
|
||||||
|
left=${x}
|
||||||
|
top=${y}
|
||||||
|
right=$((supWidth - w - left))
|
||||||
|
bottom=$((supHeight - h - top))
|
||||||
|
# fallback to just the video resolution
|
||||||
|
else
|
||||||
|
left=$(((supWidth - vidWidth) / 2))
|
||||||
|
top=$(((supHeight - vidHeight) / 2))
|
||||||
|
right=${left}
|
||||||
|
bottom=${top}
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! crop_sup "${ogSup}" "${cropSup}" "${left}" "${top}" "${right}" "${bottom}"; then
|
||||||
|
rm -r "${tmpdir}" || return 1
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! replace_mkv_sup "${INPUT}" "${cropSup}" "${cropMkv}" "${stream}"; then
|
||||||
|
echo_fail "could not replace mkv sup for ${stream}"
|
||||||
|
rm -r "${tmpdir}" || return 1
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
# merge all single mkv into one
|
||||||
|
mkvmerge -o "${pgsMkvOut}" "${tmpdir}/"*.mkv
|
||||||
|
local mergeRet=$?
|
||||||
|
rm -r "${tmpdir}" || return 1
|
||||||
|
return ${mergeRet}
|
||||||
|
}
|
||||||
|
|
||||||
encode_usage() {
|
encode_usage() {
|
||||||
echo "encode -i input [options] output"
|
echo "encode -i input [options] output"
|
||||||
echo -e "\t[-P NUM] set preset (default: ${PRESET})"
|
echo -e "\t[-P NUM] set preset (default: ${PRESET})"
|
||||||
@@ -238,7 +417,7 @@ set_encode_opts() {
|
|||||||
encode_usage
|
encode_usage
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
GRAIN="film-grain=${OPTARG}:film-grain-denoise=1:"
|
GRAIN="film-grain=${OPTARG}:film-grain-denoise=1:adaptive-film-grain=1:"
|
||||||
optsUsed=$((optsUsed + 2))
|
optsUsed=$((optsUsed + 2))
|
||||||
;;
|
;;
|
||||||
P)
|
P)
|
||||||
@@ -312,7 +491,13 @@ set_encode_opts() {
|
|||||||
# shellcheck disable=SC2155
|
# shellcheck disable=SC2155
|
||||||
# shellcheck disable=SC2016
|
# shellcheck disable=SC2016
|
||||||
gen_encode_script() {
|
gen_encode_script() {
|
||||||
local genScript="${TMP_DIR}/$(bash_basename "${OUTPUT}").sh"
|
if missing_cmd mkvpropedit; then
|
||||||
|
echo_fail "use: ${REPO_DIR}/scripts/install_deps.sh"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
local outputBasename="$(bash_basename "${OUTPUT}")"
|
||||||
|
local genScript="${TMP_DIR}/${outputBasename}.sh"
|
||||||
|
|
||||||
# global output index number to increment
|
# global output index number to increment
|
||||||
OUTPUT_INDEX=0
|
OUTPUT_INDEX=0
|
||||||
@@ -323,17 +508,15 @@ gen_encode_script() {
|
|||||||
OUTPUT
|
OUTPUT
|
||||||
PRESET
|
PRESET
|
||||||
CRF
|
CRF
|
||||||
crop
|
CROP_VALUE
|
||||||
encodeVersion
|
ENCODE_VERSION
|
||||||
ffmpegVersion
|
FFMPEG_VERSION
|
||||||
videoEncVersion
|
VIDEO_ENC_VERSION
|
||||||
audioEncVersion
|
AUDIO_ENC_VERSION
|
||||||
svtAv1Params
|
svtAv1Params
|
||||||
|
pgsMkv
|
||||||
|
muxxedPgsMkv
|
||||||
)
|
)
|
||||||
local crop=''
|
|
||||||
if [[ $CROP == "true" ]]; then
|
|
||||||
crop="$(get_crop "${INPUT}")" || return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
svtAv1ParamsArr=(
|
svtAv1ParamsArr=(
|
||||||
"tune=0"
|
"tune=0"
|
||||||
@@ -357,15 +540,18 @@ gen_encode_script() {
|
|||||||
|
|
||||||
# arrays
|
# arrays
|
||||||
local arrays=(
|
local arrays=(
|
||||||
unmapStreams
|
UNMAP_STREAMS
|
||||||
audioParams
|
AUDIO_PARAMS
|
||||||
|
SUBTITLE_PARAMS
|
||||||
videoParams
|
videoParams
|
||||||
metadata
|
metadata
|
||||||
subtitleParams
|
|
||||||
ffmpegParams
|
ffmpegParams
|
||||||
|
PGS_SUB_STREAMS
|
||||||
)
|
)
|
||||||
|
local "${arrays[@]}"
|
||||||
|
|
||||||
local videoParams=(
|
local videoParams=(
|
||||||
"-crf" '${CRF}' "-preset" '${PRESET}' "-g" "240"
|
"-crf" '${CRF}' "-preset" '${PRESET}'
|
||||||
)
|
)
|
||||||
local ffmpegParams=(
|
local ffmpegParams=(
|
||||||
'-hide_banner'
|
'-hide_banner'
|
||||||
@@ -376,51 +562,72 @@ gen_encode_script() {
|
|||||||
)
|
)
|
||||||
|
|
||||||
# set video params
|
# set video params
|
||||||
|
get_encode_versions || return 1
|
||||||
local inputVideoCodec="$(get_stream_codec "${INPUT}" 'v:0')"
|
local inputVideoCodec="$(get_stream_codec "${INPUT}" 'v:0')"
|
||||||
if [[ ${inputVideoCodec} == 'av1' ]]; then
|
if [[ ${inputVideoCodec} == 'av1' ]]; then
|
||||||
ffmpegParams+=(
|
ffmpegParams+=(
|
||||||
"-c:v:${OUTPUT_INDEX}" 'copy'
|
"-c:v:${OUTPUT_INDEX}" 'copy'
|
||||||
)
|
)
|
||||||
|
# can't crop if copying codec
|
||||||
|
CROP=false
|
||||||
else
|
else
|
||||||
ffmpegParams+=(
|
ffmpegParams+=(
|
||||||
'-pix_fmt' 'yuv420p10le'
|
'-pix_fmt' 'yuv420p10le'
|
||||||
"-c:v:${OUTPUT_INDEX}" 'libsvtav1' '${videoParams[@]}'
|
"-c:v:${OUTPUT_INDEX}" 'libsvtav1' '${videoParams[@]}'
|
||||||
'-svtav1-params' '${svtAv1Params}'
|
'-svtav1-params' '${svtAv1Params}'
|
||||||
)
|
)
|
||||||
|
metadata+=(
|
||||||
|
'-metadata' '${VIDEO_ENC_VERSION}'
|
||||||
|
'-metadata' 'svtav1_params=${svtAv1Params}'
|
||||||
|
'-metadata' 'video_params=${videoParams[*]}'
|
||||||
|
)
|
||||||
fi
|
fi
|
||||||
OUTPUT_INDEX=$((OUTPUT_INDEX + 1))
|
OUTPUT_INDEX=$((OUTPUT_INDEX + 1))
|
||||||
|
|
||||||
# these values may be empty
|
# these values may be empty
|
||||||
local unmapStr audioParamsStr subtitleParamsStr
|
|
||||||
set_unmap_streams "${INPUT}" || return 1
|
set_unmap_streams "${INPUT}" || return 1
|
||||||
set_audio_params "${INPUT}" || return 1
|
set_audio_params "${INPUT}" || return 1
|
||||||
set_subtitle_params "${INPUT}" || return 1
|
set_subtitle_params "${INPUT}" || return 1
|
||||||
|
|
||||||
if [[ ${unmapStreams[*]} != '' ]]; then
|
if [[ ${UNMAP_STREAMS[*]} != '' ]]; then
|
||||||
ffmpegParams+=('${unmapStreams[@]}')
|
ffmpegParams+=('${UNMAP_STREAMS[@]}')
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ ${audioParams[*]} != '' ]]; then
|
if [[ ${AUDIO_PARAMS[*]} != '' ]]; then
|
||||||
ffmpegParams+=('${audioParams[@]}')
|
ffmpegParams+=('${AUDIO_PARAMS[@]}')
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ ${subtitleParams[*]} != '' ]]; then
|
if [[ ${SUBTITLE_PARAMS[*]} != '' ]]; then
|
||||||
ffmpegParams+=('${subtitleParams[@]}')
|
ffmpegParams+=('${SUBTITLE_PARAMS[@]}')
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ ${crop} != '' ]]; then
|
metadata+=(
|
||||||
ffmpegParams+=('-vf' '${crop}')
|
'-metadata' '${ENCODE_VERSION}'
|
||||||
fi
|
'-metadata' '${FFMPEG_VERSION}'
|
||||||
|
|
||||||
get_encode_versions || return 1
|
|
||||||
local metadata=(
|
|
||||||
'-metadata' '${encodeVersion}'
|
|
||||||
'-metadata' '${ffmpegVersion}'
|
|
||||||
'-metadata' '${videoEncVersion}'
|
|
||||||
'-metadata' '${audioEncVersion}'
|
|
||||||
'-metadata' 'svtav1_params=${svtAv1Params}'
|
|
||||||
'-metadata' 'video_params=${videoParams[*]}'
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# in the case all audio streams are copied,
|
||||||
|
# don't add libopus metadata
|
||||||
|
if line_contains "${AUDIO_PARAMS[*]}" 'libopus'; then
|
||||||
|
metadata+=(
|
||||||
|
'-metadata' '${AUDIO_ENC_VERSION}')
|
||||||
|
fi
|
||||||
|
|
||||||
|
local CROP_VALUE
|
||||||
|
if [[ ${CROP} == true ]]; then
|
||||||
|
CROP_VALUE="$(get_crop "${INPUT}")" || return 1
|
||||||
|
ffmpegParams+=('-vf' '${CROP_VALUE}')
|
||||||
|
metadata+=(
|
||||||
|
'-metadata' '${CROP_VALUE}'
|
||||||
|
'-metadata' "og_res=$(get_resolution "${INPUT}")"
|
||||||
|
)
|
||||||
|
fi
|
||||||
|
|
||||||
|
# separate processing step for pkg subs
|
||||||
|
local pgsMkv="${TMP_DIR}/pgs-${outputBasename// /.}.mkv"
|
||||||
|
local muxxedPgsMkv='${OUTPUT}.muxxed'
|
||||||
|
setup_pgs_mkv "${pgsMkv}" 1>&2 || return 1
|
||||||
|
|
||||||
ffmpegParams+=('${metadata[@]}')
|
ffmpegParams+=('${metadata[@]}')
|
||||||
|
|
||||||
{
|
{
|
||||||
@@ -451,27 +658,17 @@ gen_encode_script() {
|
|||||||
echo 'ffmpeg "${ffmpegParams[@]}" -dolbyvision 0 "${OUTPUT}" || exit 1'
|
echo 'ffmpeg "${ffmpegParams[@]}" -dolbyvision 0 "${OUTPUT}" || exit 1'
|
||||||
|
|
||||||
# track-stats and clear title
|
# track-stats and clear title
|
||||||
if [[ ${FILE_EXT} == 'mkv' ]] && has_cmd mkvmerge && has_cmd mkvpropedit; then
|
if [[ ${FILE_EXT} == 'mkv' ]]; then
|
||||||
{
|
{
|
||||||
# ffmpeg does not reliably copy PGS subtitles without breaking
|
# ffmpeg does not copy PGS subtitles without breaking them
|
||||||
# them when cropped, so just use mkvmerge to make sure they get
|
# use mkvmerge to extract and supmover to crop
|
||||||
# copied correctly
|
if [[ ${#PGS_SUB_STREAMS[@]} -gt 0 ]]; then
|
||||||
local muxxed='"${OUTPUT}.muxxed"'
|
echo
|
||||||
local mergeCmd=(
|
echo 'mkvmerge -o "${muxxedPgsMkv}" "${pgsMkv}" "${OUTPUT}" || exit 1'
|
||||||
mkvmerge
|
echo 'rm "${pgsMkv}" || exit 1'
|
||||||
-o "${muxxed}"
|
echo 'mv "${muxxedPgsMkv}" "${OUTPUT}" || exit 1'
|
||||||
--no-subtitles '"${OUTPUT}"'
|
fi
|
||||||
--no-video
|
|
||||||
--no-audio
|
|
||||||
--no-chapters
|
|
||||||
--no-attachments
|
|
||||||
--no-global-tags
|
|
||||||
--subtitle-tracks eng
|
|
||||||
'"${INPUT}"'
|
|
||||||
)
|
|
||||||
echo
|
|
||||||
echo "${mergeCmd[*]} || exit 1"
|
|
||||||
echo "mv ${muxxed}" '"${OUTPUT}" || exit 1'
|
|
||||||
echo 'mkvpropedit "${OUTPUT}" --add-track-statistics-tags || exit 1'
|
echo 'mkvpropedit "${OUTPUT}" --add-track-statistics-tags || exit 1'
|
||||||
echo 'mkvpropedit "${OUTPUT}" --edit info --set "title=" || exit 1'
|
echo 'mkvpropedit "${OUTPUT}" --edit info --set "title=" || exit 1'
|
||||||
}
|
}
|
||||||
@@ -491,7 +688,7 @@ gen_encode_script() {
|
|||||||
|
|
||||||
FB_FUNC_NAMES+=('encode')
|
FB_FUNC_NAMES+=('encode')
|
||||||
# shellcheck disable=SC2034
|
# shellcheck disable=SC2034
|
||||||
FB_FUNC_DESCS['encode']='encode a file using libsvtav1_psy and libopus'
|
FB_FUNC_DESCS['encode']='encode a file using libsvtav1 and libopus'
|
||||||
encode() {
|
encode() {
|
||||||
set_encode_opts "$@"
|
set_encode_opts "$@"
|
||||||
local ret=$?
|
local ret=$?
|
||||||
|
|||||||
@@ -1,8 +1,17 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
_ffprobe_wrapper() {
|
||||||
|
local stderr="${TMP_DIR}/ffprobe-stderr"
|
||||||
|
if ! ffprobe "$@" 2>"${TMP_DIR}/ffprobe-stderr"; then
|
||||||
|
cat "${stderr}"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
get_duration() {
|
get_duration() {
|
||||||
local file="$1"
|
local file="$1"
|
||||||
ffprobe \
|
_ffprobe_wrapper \
|
||||||
-v error \
|
-v error \
|
||||||
-show_entries format=duration \
|
-show_entries format=duration \
|
||||||
-of default=noprint_wrappers=1:nokey=1 \
|
-of default=noprint_wrappers=1:nokey=1 \
|
||||||
@@ -11,7 +20,7 @@ get_duration() {
|
|||||||
|
|
||||||
get_avg_bitrate() {
|
get_avg_bitrate() {
|
||||||
local file="$1"
|
local file="$1"
|
||||||
ffprobe \
|
_ffprobe_wrapper \
|
||||||
-v error \
|
-v error \
|
||||||
-select_streams v:0 \
|
-select_streams v:0 \
|
||||||
-show_entries format=bit_rate \
|
-show_entries format=bit_rate \
|
||||||
@@ -43,7 +52,7 @@ get_crop() {
|
|||||||
# don't care about decimal points
|
# don't care about decimal points
|
||||||
IFS='.' read -r duration _ <<<"${duration}"
|
IFS='.' read -r duration _ <<<"${duration}"
|
||||||
# get crop value for first half of input
|
# get crop value for first half of input
|
||||||
local timeEnc=$((duration / 2))
|
local timeEnc=$((duration / 20))
|
||||||
ffmpeg \
|
ffmpeg \
|
||||||
-y \
|
-y \
|
||||||
-hide_banner \
|
-hide_banner \
|
||||||
@@ -55,7 +64,7 @@ get_crop() {
|
|||||||
-filter:v:0 'cropdetect=limit=100:round=16:skip=2:reset_count=0' \
|
-filter:v:0 'cropdetect=limit=100:round=16:skip=2:reset_count=0' \
|
||||||
-codec:v 'wrapped_avframe' \
|
-codec:v 'wrapped_avframe' \
|
||||||
-f 'null' '/dev/null' 2>&1 |
|
-f 'null' '/dev/null' 2>&1 |
|
||||||
grep -o crop=.* |
|
grep -o 'crop=.*' |
|
||||||
sort -bh |
|
sort -bh |
|
||||||
uniq -c |
|
uniq -c |
|
||||||
sort -bh |
|
sort -bh |
|
||||||
@@ -63,10 +72,31 @@ get_crop() {
|
|||||||
grep -o "crop=.*"
|
grep -o "crop=.*"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# output '1920x1080'
|
||||||
|
get_resolution() {
|
||||||
|
local file="$1"
|
||||||
|
get_stream_json "${file}" 0 |
|
||||||
|
jq -r '.streams[0] | "\(.width)x\(.height)"'
|
||||||
|
}
|
||||||
|
|
||||||
|
# same as get_resolution
|
||||||
|
get_sup_resolution() {
|
||||||
|
local supfile="$1"
|
||||||
|
check_for_supmover || return 1
|
||||||
|
if [[ "$(get_file_format "${supfile}")" != 'sup' ]]; then
|
||||||
|
echo_fail "${supfile} is not a sup file"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
local trace res
|
||||||
|
trace="$("${SUPMOVER}" "${supfile}" --trace)" || return 1
|
||||||
|
res="$(grep 'Video size' <<<"${trace}" | sort -u | awk '{print $NF}')" || return 1
|
||||||
|
echo "${res}"
|
||||||
|
}
|
||||||
|
|
||||||
get_stream_codec() {
|
get_stream_codec() {
|
||||||
local file="$1"
|
local file="$1"
|
||||||
local stream="$2"
|
local stream="$2"
|
||||||
ffprobe \
|
_ffprobe_wrapper \
|
||||||
-v error \
|
-v error \
|
||||||
-select_streams "${stream}" \
|
-select_streams "${stream}" \
|
||||||
-show_entries stream=codec_name \
|
-show_entries stream=codec_name \
|
||||||
@@ -74,18 +104,31 @@ get_stream_codec() {
|
|||||||
"${file}"
|
"${file}"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get_stream_json() {
|
||||||
|
local file="$1"
|
||||||
|
local stream="$2"
|
||||||
|
_ffprobe_wrapper \
|
||||||
|
-v error \
|
||||||
|
-select_streams "${stream}" \
|
||||||
|
-show_entries stream \
|
||||||
|
-of json \
|
||||||
|
"${file}"
|
||||||
|
}
|
||||||
|
|
||||||
get_file_format() {
|
get_file_format() {
|
||||||
local file="$1"
|
local file="$1"
|
||||||
local probe
|
local probe
|
||||||
probe="$(ffprobe \
|
probe="$(_ffprobe_wrapper \
|
||||||
-v error \
|
-v error \
|
||||||
-show_entries format=format_name \
|
-show_entries format=format_name \
|
||||||
-of default=noprint_wrappers=1:nokey=1 \
|
-of default=noprint_wrappers=1:nokey=1 \
|
||||||
"${file}")" || return 1
|
"${file}")" || return 1
|
||||||
if line_contains "${probe}" 'matroska'; then
|
if line_contains "${probe}" 'matroska'; then
|
||||||
echo mkv
|
echo mkv
|
||||||
else
|
elif line_contains "${probe}" 'mp4'; then
|
||||||
echo mp4
|
echo mp4
|
||||||
|
else
|
||||||
|
echo "${probe}"
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -98,7 +141,7 @@ get_num_streams() {
|
|||||||
select=("-select_streams" "${type}")
|
select=("-select_streams" "${type}")
|
||||||
fi
|
fi
|
||||||
|
|
||||||
ffprobe \
|
_ffprobe_wrapper \
|
||||||
-v error "${select[@]}" \
|
-v error "${select[@]}" \
|
||||||
-show_entries stream=index \
|
-show_entries stream=index \
|
||||||
-of default=noprint_wrappers=1:nokey=1 \
|
-of default=noprint_wrappers=1:nokey=1 \
|
||||||
@@ -108,7 +151,7 @@ get_num_streams() {
|
|||||||
get_num_audio_channels() {
|
get_num_audio_channels() {
|
||||||
local file="$1"
|
local file="$1"
|
||||||
local stream="$2"
|
local stream="$2"
|
||||||
ffprobe \
|
_ffprobe_wrapper \
|
||||||
-v error \
|
-v error \
|
||||||
-select_streams "${stream}" \
|
-select_streams "${stream}" \
|
||||||
-show_entries stream=channels \
|
-show_entries stream=channels \
|
||||||
@@ -119,7 +162,7 @@ get_num_audio_channels() {
|
|||||||
get_stream_lang() {
|
get_stream_lang() {
|
||||||
local file="$1"
|
local file="$1"
|
||||||
local stream="$2"
|
local stream="$2"
|
||||||
ffprobe \
|
_ffprobe_wrapper \
|
||||||
-v error \
|
-v error \
|
||||||
-select_streams "${stream}" \
|
-select_streams "${stream}" \
|
||||||
-show_entries stream_tags=language \
|
-show_entries stream_tags=language \
|
||||||
|
|||||||
@@ -98,6 +98,7 @@ print_req_pkgs() {
|
|||||||
libandroid-posix-semaphore-static
|
libandroid-posix-semaphore-static
|
||||||
libandroid-shmem
|
libandroid-shmem
|
||||||
libandroid-shmem-static
|
libandroid-shmem-static
|
||||||
|
cargo-c
|
||||||
)
|
)
|
||||||
# shellcheck disable=SC2034
|
# shellcheck disable=SC2034
|
||||||
local msys_ucrt_pkgs=(
|
local msys_ucrt_pkgs=(
|
||||||
|
|||||||
@@ -79,6 +79,7 @@ $(encode)
|
|||||||
- Skips re-encoding av1/opus streams.
|
- Skips re-encoding av1/opus streams.
|
||||||
- Only maps audio streams that match the video stream language if the video stream has a defined language.
|
- Only maps audio streams that match the video stream language if the video stream has a defined language.
|
||||||
- Only maps english subtitle streams.
|
- Only maps english subtitle streams.
|
||||||
|
- Crop PGS subtitles to match video dimensions.
|
||||||
- Adds track statistics to the output mkv file and embeds the encoder versions to the output metadata. For example:
|
- Adds track statistics to the output mkv file and embeds the encoder versions to the output metadata. For example:
|
||||||
\`\`\`
|
\`\`\`
|
||||||
ENCODE : aa4d7e6
|
ENCODE : aa4d7e6
|
||||||
|
|||||||
3
main.sh
3
main.sh
@@ -88,6 +88,9 @@ $cmd "$@"' >"${ENTRY_SCRIPT}"
|
|||||||
}
|
}
|
||||||
gen_links || return 1
|
gen_links || return 1
|
||||||
|
|
||||||
|
# allow calling entry.sh with arguments as execution
|
||||||
|
entry() { "$@" ; }
|
||||||
|
|
||||||
set_completions() {
|
set_completions() {
|
||||||
for funcName in "${FB_FUNC_NAMES[@]}"; do
|
for funcName in "${FB_FUNC_NAMES[@]}"; do
|
||||||
complete -W "${FB_FUNC_COMPLETION[${funcName}]}" "${funcName}"
|
complete -W "${FB_FUNC_COMPLETION[${funcName}]}" "${funcName}"
|
||||||
|
|||||||
Reference in New Issue
Block a user