Always copy subtitles and all audio tracks (#400)
* Always copy subtitles and all audio tracks Require mkvmerge for x265 * cargo update * Fix concat if audio file does not exist * Use stable rustc in Docker, do not compile VVC * Use old Docker image for now which works with vapoursynth * Fix tests.yml * Use mkvmerge for tests * Add mkvtoolnix as a dependency in tests.yml
This commit is contained in:
parent
a8812b9900
commit
754c1192fe
6
.github/workflows/tests.yml
vendored
6
.github/workflows/tests.yml
vendored
|
@ -12,14 +12,14 @@ on:
|
|||
- "*.md"
|
||||
|
||||
env:
|
||||
deps: tree llvm clang
|
||||
deps: tree llvm clang mkvtoolnix
|
||||
DEBIAN_FRONTEND: noninteractive
|
||||
|
||||
jobs:
|
||||
validate:
|
||||
name: ${{ matrix.name }} ${{ matrix.enc }}
|
||||
runs-on: ubuntu-latest
|
||||
container: luigi311/encoders-docker:latest
|
||||
container: luigi311/encoders-docker:20210901
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
|
@ -105,7 +105,7 @@ jobs:
|
|||
|
||||
- name: Testing ${{ matrix.name }}
|
||||
run: |
|
||||
target/release/av1an -i bus_cif.y4m -e ${{ matrix.enc }} -l log_av1an --keep -o "bus_cif.mkv" ${{ matrix.flags }}
|
||||
target/release/av1an -i bus_cif.y4m -e ${{ matrix.enc }} -l log_av1an -c mkvmerge --keep -o "bus_cif.mkv" ${{ matrix.flags }}
|
||||
du -h bus_cif.mkv
|
||||
tree -a
|
||||
|
||||
|
|
44
Cargo.lock
generated
44
Cargo.lock
generated
|
@ -4,9 +4,9 @@ version = 3
|
|||
|
||||
[[package]]
|
||||
name = "addr2line"
|
||||
version = "0.16.0"
|
||||
version = "0.17.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3e61f2b7f93d2c7d2b08263acaa4a363b3e276806c68af6134c44f523bf1aacd"
|
||||
checksum = "b9ecd88a8c8378ca913a680cd98f0f13ac67383d35993f86c90a70e3f137816b"
|
||||
dependencies = [
|
||||
"gimli",
|
||||
]
|
||||
|
@ -46,9 +46,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.44"
|
||||
version = "1.0.45"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "61604a8f862e1d5c3229fdd78f8b02c68dcf73a4c4b05fd636d12240aaa242c1"
|
||||
checksum = "ee10e43ae4a853c0a3591d4e2ada1719e553be18199d9da9d4a83f5927c2f5c7"
|
||||
|
||||
[[package]]
|
||||
name = "arbitrary"
|
||||
|
@ -186,7 +186,7 @@ dependencies = [
|
|||
"shlex 1.1.0",
|
||||
"structopt",
|
||||
"thiserror",
|
||||
"vergen 5.1.16",
|
||||
"vergen 5.1.17",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -228,9 +228,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "backtrace"
|
||||
version = "0.3.62"
|
||||
version = "0.3.63"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "091bcdf2da9950f96aa522681ce805e6857f6ca8df73833d35736ab2dc78e152"
|
||||
checksum = "321629d8ba6513061f26707241fa9bc89524ff1cd7a915a97ef0c62c666ce1b6"
|
||||
dependencies = [
|
||||
"addr2line",
|
||||
"cc",
|
||||
|
@ -351,7 +351,7 @@ dependencies = [
|
|||
"libc",
|
||||
"num-integer",
|
||||
"num-traits",
|
||||
"time",
|
||||
"time 0.1.44",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
|
@ -560,19 +560,19 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "flexi_logger"
|
||||
version = "0.19.5"
|
||||
version = "0.19.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "eb300b5c59fc4894ea567328a30a3ee3c5a63fb59e17c34b2327ac230455eb79"
|
||||
checksum = "9b329d8ed052ce3f1e7c9109659d4d999b8f7b1bd2e9d2cecc703cb5a98c8b46"
|
||||
dependencies = [
|
||||
"ansi_term 0.12.1",
|
||||
"atty",
|
||||
"chrono",
|
||||
"glob",
|
||||
"lazy_static",
|
||||
"log",
|
||||
"regex",
|
||||
"rustversion",
|
||||
"thiserror",
|
||||
"time 0.3.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -616,9 +616,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "gimli"
|
||||
version = "0.25.0"
|
||||
version = "0.26.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f0a01e0497841a3b2db4f8afa483cce65f7e96a3498bd6c541734792aeac8fe7"
|
||||
checksum = "78cc372d058dcf6d5ecd98510e7fbc9e5aec4d21de70f65fea8fecebcd881bd4"
|
||||
|
||||
[[package]]
|
||||
name = "git2"
|
||||
|
@ -1335,9 +1335,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.68"
|
||||
version = "1.0.69"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0f690853975602e1bfe1ccbf50504d67174e3bcf340f23b5ea9992e0587a52d8"
|
||||
checksum = "e466864e431129c7e0d3476b92f20458e5879919a0596c6472738d9fa2d342f8"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"ryu",
|
||||
|
@ -1612,6 +1612,16 @@ dependencies = [
|
|||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "time"
|
||||
version = "0.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "99beeb0daeac2bd1e86ac2c21caddecb244b39a093594da1a661ec2060c7aedd"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tinyvec"
|
||||
version = "1.5.0"
|
||||
|
@ -1768,9 +1778,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "vergen"
|
||||
version = "5.1.16"
|
||||
version = "5.1.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7b62d4fc8fc9c81d139c8106b9f4e583e7c1eb36e320dc28d5c03aab86729495"
|
||||
checksum = "6cf88d94e969e7956d924ba70741316796177fa0c79a2c9f4ab04998d96e966e"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"cfg-if 1.0.0",
|
||||
|
|
12
Dockerfile
12
Dockerfile
|
@ -1,4 +1,4 @@
|
|||
FROM luigi311/encoders-docker:latest
|
||||
FROM luigi311/encoders-docker:20210901
|
||||
|
||||
ENV MPLCONFIGDIR="/home/app_user/"
|
||||
ARG DEBIAN_FRONTEND=noninteractive
|
||||
|
@ -11,20 +11,12 @@ RUN apt-get update && \
|
|||
apt-get clean && \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Install VTM
|
||||
RUN git clone https://vcgit.hhi.fraunhofer.de/jvet/VVCSoftware_VTM.git /VTM && \
|
||||
mkdir -p /VTM/build
|
||||
WORKDIR /VTM/build
|
||||
RUN cmake .. -DCMAKE_BUILD_TYPE=Release && \
|
||||
make -j"$(nproc)" && \
|
||||
ln -s ../bin/EncoderAppStatic /usr/local/bin/vvc_encoder
|
||||
|
||||
# Create user
|
||||
RUN useradd -ms /bin/bash app_user
|
||||
USER app_user
|
||||
|
||||
# Install rust
|
||||
RUN curl https://sh.rustup.rs -sSf | bash -s -- -y --default-toolchain nightly
|
||||
RUN curl https://sh.rustup.rs -sSf | bash -s -- -y --default-toolchain stable
|
||||
ENV PATH="/home/app_user/.cargo/bin:$PATH"
|
||||
|
||||
# Copy av1an and build av1an
|
||||
|
|
|
@ -179,9 +179,21 @@ pub struct CliOpts {
|
|||
#[structopt(short = "f", long = "ffmpeg")]
|
||||
pub ffmpeg_filter_args: Option<String>,
|
||||
|
||||
/// Audio encoding parameters. If not specified, "-c:a copy" is used
|
||||
/// Audio encoding parameters. If not specified, "-c:a copy" is used.
|
||||
/// Do not use FFmpeg's `-map` syntax with this option. Instead, use the
|
||||
/// colon syntax with each parameter you specify.
|
||||
///
|
||||
/// Example to encode the audio with libopus: -a="-c:a libopus -b:a 128k -ac 2"
|
||||
/// Subtitles are always copied by default.
|
||||
///
|
||||
/// Example to encode all audio tracks with libopus at 128k:
|
||||
///
|
||||
/// -a="-c:a libopus -b:a 128k"
|
||||
///
|
||||
/// Example to encode the first audio track with libopus at 128k, and the
|
||||
/// second audio track with aac at 24k, where only the second track is
|
||||
/// downmixed to a single channel:
|
||||
///
|
||||
/// -a="-c:a:0 libopus -b:a:0 128k -c:a:1 aac -ac:a:1 1 -b:a:1 24k"
|
||||
#[structopt(short, long)]
|
||||
pub audio_params: Option<String>,
|
||||
|
||||
|
|
|
@ -16,8 +16,6 @@ use std::{
|
|||
sync::Arc,
|
||||
};
|
||||
|
||||
use crate::encoder::Encoder;
|
||||
|
||||
#[derive(
|
||||
PartialEq, Eq, Copy, Clone, Serialize, Deserialize, Debug, strum::EnumString, strum::IntoStaticStr,
|
||||
)]
|
||||
|
@ -228,8 +226,8 @@ pub fn mkvmerge(encode_folder: &Path, output: &Path) -> anyhow::Result<()> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
/// Concatenates using ffmpeg
|
||||
pub fn ffmpeg(temp: &Path, output: &Path, encoder: Encoder) {
|
||||
/// Concatenates using ffmpeg (does not work with x265)
|
||||
pub fn ffmpeg(temp: &Path, output: &Path) {
|
||||
fn write_concat_file(temp_folder: &Path) {
|
||||
let concat_file = &temp_folder.join("concat");
|
||||
let encode_folder = &temp_folder.join("encode");
|
||||
|
@ -240,7 +238,7 @@ pub fn ffmpeg(temp: &Path, output: &Path, encoder: Encoder) {
|
|||
|
||||
files.sort_by_key(DirEntry::path);
|
||||
|
||||
let mut contents = String::new();
|
||||
let mut contents = String::with_capacity(24 * files.len());
|
||||
|
||||
for i in files {
|
||||
if cfg!(windows) {
|
||||
|
@ -262,12 +260,13 @@ pub fn ffmpeg(temp: &Path, output: &Path, encoder: Encoder) {
|
|||
|
||||
write_concat_file(temp);
|
||||
|
||||
let audio_file = temp.join("audio.mkv");
|
||||
|
||||
let audio_args = if audio_file.exists() && audio_file.metadata().unwrap().len() > 1000 {
|
||||
vec!["-i", audio_file.to_str().unwrap(), "-c", "copy"]
|
||||
} else {
|
||||
Vec::with_capacity(0)
|
||||
let audio_file = {
|
||||
let file = temp.join("audio.mkv");
|
||||
if file.exists() && file.metadata().unwrap().len() > 1000 {
|
||||
Some(file)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
};
|
||||
|
||||
let mut cmd = Command::new("ffmpeg");
|
||||
|
@ -275,12 +274,10 @@ pub fn ffmpeg(temp: &Path, output: &Path, encoder: Encoder) {
|
|||
cmd.stdout(Stdio::piped());
|
||||
cmd.stderr(Stdio::piped());
|
||||
|
||||
match encoder {
|
||||
Encoder::x265 => cmd
|
||||
.args(&[
|
||||
if let Some(file) = audio_file {
|
||||
cmd
|
||||
.args([
|
||||
"-y",
|
||||
"-fflags",
|
||||
"+genpts",
|
||||
"-hide_banner",
|
||||
"-loglevel",
|
||||
"error",
|
||||
|
@ -290,20 +287,13 @@ pub fn ffmpeg(temp: &Path, output: &Path, encoder: Encoder) {
|
|||
"0",
|
||||
"-i",
|
||||
concat_file,
|
||||
"-i",
|
||||
])
|
||||
.args(audio_args)
|
||||
.args(&[
|
||||
"-c",
|
||||
"copy",
|
||||
"-movflags",
|
||||
"frag_keyframe+empty_moov",
|
||||
"-map",
|
||||
"0",
|
||||
"-f",
|
||||
"mp4",
|
||||
])
|
||||
.arg(output),
|
||||
_ => cmd
|
||||
.arg(file)
|
||||
.args(["-map", "0", "-map", "1", "-c", "copy"])
|
||||
.arg(output);
|
||||
} else {
|
||||
cmd
|
||||
.args([
|
||||
"-y",
|
||||
"-hide_banner",
|
||||
|
@ -316,10 +306,10 @@ pub fn ffmpeg(temp: &Path, output: &Path, encoder: Encoder) {
|
|||
"-i",
|
||||
concat_file,
|
||||
])
|
||||
.args(audio_args)
|
||||
.args(["-c", "copy"])
|
||||
.arg(output),
|
||||
};
|
||||
.args(["-map", "0", "-c", "copy"])
|
||||
.arg(output);
|
||||
}
|
||||
|
||||
let out = cmd.output().unwrap();
|
||||
|
||||
assert!(
|
||||
|
|
|
@ -121,7 +121,20 @@ pub fn encode_audio<S: AsRef<OsStr>>(
|
|||
|
||||
encode_audio.args(["-y", "-hide_banner", "-loglevel", "error", "-i"]);
|
||||
encode_audio.arg(input);
|
||||
encode_audio.args(["-map_metadata", "0", "-dn", "-vn", "-sn"]);
|
||||
|
||||
encode_audio.args([
|
||||
"-map_metadata",
|
||||
"0",
|
||||
"-vn",
|
||||
"-map",
|
||||
"0",
|
||||
"-map",
|
||||
"-0:a",
|
||||
"-c",
|
||||
"copy",
|
||||
"-map",
|
||||
"0:a",
|
||||
]);
|
||||
|
||||
encode_audio.args(audio_params);
|
||||
encode_audio.arg(audio_file);
|
||||
|
|
|
@ -404,6 +404,11 @@ impl EncodeArgs {
|
|||
bail!("mkvmerge not found, but `--concat mkvmerge` was specified. Is it installed in system path?");
|
||||
}
|
||||
|
||||
if self.encoder == Encoder::x265 && self.concat != ConcatMethod::MKVMerge {
|
||||
bail!("mkvmerge is required for concatenating x265, as x265 outputs raw HEVC bitstream files without the timestamps correctly set, which FFmpeg cannot concatenate \
|
||||
properly into a mkv file. Specify mkvmerge as the concatenation method by setting `--concat mkvmerge`.");
|
||||
}
|
||||
|
||||
if let Some(vmaf_path) = &self.vmaf_path {
|
||||
ensure!(vmaf_path.exists());
|
||||
}
|
||||
|
@ -890,7 +895,7 @@ impl EncodeArgs {
|
|||
concat::mkvmerge(self.temp.as_ref(), self.output_file.as_ref())?;
|
||||
}
|
||||
ConcatMethod::FFmpeg => {
|
||||
concat::ffmpeg(self.temp.as_ref(), self.output_file.as_ref(), self.encoder);
|
||||
concat::ffmpeg(self.temp.as_ref(), self.output_file.as_ref());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue