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:
redzic 2021-11-07 06:20:12 -06:00 committed by GitHub
parent a8812b9900
commit 754c1192fe
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 89 additions and 67 deletions

View file

@ -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
View file

@ -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",

View file

@ -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

View file

@ -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>,

View file

@ -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!(

View file

@ -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);

View 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());
}
}