Skip to content

Commit

Permalink
Fixes errors with .mkv container format (issue #3)
Browse files Browse the repository at this point in the history
  • Loading branch information
kaegi committed Aug 15, 2019
1 parent 5fbcb35 commit f73f600
Show file tree
Hide file tree
Showing 2 changed files with 35 additions and 16 deletions.
2 changes: 1 addition & 1 deletion MakefileWindows64
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ package_windows64:
rm target/alass-windows64/ffmpeg/bin/ffplay.exe
cargo build --release --target x86_64-pc-windows-gnu
cp target/x86_64-pc-windows-gnu/release/alass-cli.exe target/alass-windows64/bin
echo -ne '@echo off\r\nset ALASS_FFMPEG_PATH=.\\ffmpeg\\bin\\ffmpeg.exe\r\nset ALASS_FFPROBE_PATH=.\\ffmpeg\\bin\\ffprobe.exe\r\n.\\bin\\alass-cli.exe %*\r\n' > target/alass-windows64/alass.bat
echo -ne '@echo off\r\nset ALASS_FFMPEG_PATH=%~dp0ffmpeg\\bin\\ffmpeg.exe\r\nset ALASS_FFPROBE_PATH=%~dp0ffmpeg\\bin\\ffprobe.exe\r\n"%~dp0bin\\alass-cli.exe" %*\r\n' > target/alass-windows64/alass.bat
( cd target; zip -J -r alass-windows64.zip alass-windows64 )


Expand Down
49 changes: 34 additions & 15 deletions alass-cli/src/video_decoder/ffmpeg_binary.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,14 +38,21 @@ struct Stream {
pub index: usize,
pub codec_long_name: String,
pub channels: Option<usize>,
pub duration: String,
/// `.mkv` does not store the duration in the streams; we have to use `format -> duration` instead
pub duration: Option<String>,
pub codec_type: CodecType,
}

#[derive(Debug, Deserialize)]
struct Format {
pub duration: Option<String>,
}

/// Metadata associated with a video.
#[derive(Debug, Deserialize)]
struct Metadata {
streams: Vec<Stream>,
format: Option<Format>,
}

define_error!(DecoderError, DecoderErrorKind);
Expand Down Expand Up @@ -88,6 +95,7 @@ pub(crate) enum DecoderErrorKind {
s: String,
},
AudioSegmentProcessingFailed,
NoDurationInformation,
}

fn format_cmd(cmd_path: &PathBuf, args: &[OsString]) -> String {
Expand Down Expand Up @@ -146,6 +154,7 @@ impl fmt::Display for DecoderErrorKind {
write!(f, "failed to parse duration string '{}' from metadata", s)
}
DecoderErrorKind::AudioSegmentProcessingFailed => write!(f, "processing audio segment failed"),
DecoderErrorKind::NoDurationInformation => write!(f, "no audio duration information found"),
}
}
}
Expand Down Expand Up @@ -175,7 +184,8 @@ impl VideoDecoderFFmpegBinary {
let args = vec![
OsString::from("-v"),
OsString::from("error"),
OsString::from("-show_streams"),
OsString::from("-show_entries"),
OsString::from("format=duration:stream=index,codec_long_name,channels,duration,codec_type"),
OsString::from("-of"),
OsString::from("json"),
OsString::from(file_path.as_ref()),
Expand All @@ -185,12 +195,16 @@ impl VideoDecoderFFmpegBinary {
.unwrap_or(OsString::from("ffprobe"))
.into();

let best_stream_opt: Option<Stream> = Self::get_metadata(file_path_buf.clone(), ffprobe_path.clone(), &args)
.with_context(|_| DecoderErrorKind::ExtractingMetadataFailed {
file_path: file_path_buf.clone(),
cmd_path: ffprobe_path.clone(),
args: args,
})?
let metadata: Metadata =
Self::get_metadata(file_path_buf.clone(), ffprobe_path.clone(), &args).with_context(|_| {
DecoderErrorKind::ExtractingMetadataFailed {
file_path: file_path_buf.clone(),
cmd_path: ffprobe_path.clone(),
args: args,
}
})?;

let best_stream_opt: Option<Stream> = metadata
.streams
.into_iter()
.filter(|s| s.codec_type == CodecType::Audio && s.channels.is_some())
Expand Down Expand Up @@ -238,13 +252,18 @@ impl VideoDecoderFFmpegBinary {
OsString::from("-"),
];

let duration =
best_stream
.duration
.parse::<f64>()
.with_context(|_| DecoderErrorKind::FailedToParseDuration {
s: best_stream.duration,
})?;
let format_opt: Option<Format> = metadata.format;

// `.mkv` containers do not store duration info in streams, only the format information does contain it
let duration_str = best_stream
.duration
.or_else(|| format_opt.and_then(|format| format.duration))
.ok_or_else(|| DecoderError::from(DecoderErrorKind::NoDurationInformation))?;

let duration = duration_str
.parse::<f64>()
.with_context(|_| DecoderErrorKind::FailedToParseDuration { s: duration_str })?;

let num_samples: i64 = (duration * 8000.0) as i64 / PROGRESS_PRESCALER;

progress_handler.init(num_samples);
Expand Down

0 comments on commit f73f600

Please sign in to comment.