Fix mediainfo number parsing

This commit is contained in:
Zoe Roux 2023-05-26 01:05:51 +09:00
parent 64d4ee9168
commit dbe85322ea
5 changed files with 25 additions and 18 deletions

View File

@ -11,7 +11,7 @@ COPY src src
RUN cargo install --path . RUN cargo install --path .
FROM alpine FROM alpine
RUN apk add --no-cache ffmpeg RUN apk add --no-cache ffmpeg mediainfo
COPY --from=builder /usr/local/cargo/bin/transcoder ./transcoder COPY --from=builder /usr/local/cargo/bin/transcoder ./transcoder
EXPOSE 7666 EXPOSE 7666

View File

@ -1,5 +1,5 @@
FROM rust:alpine FROM rust:alpine
RUN apk add --no-cache musl-dev ffmpeg RUN apk add --no-cache musl-dev ffmpeg mediainfo
RUN cargo install cargo-watch RUN cargo install cargo-watch
WORKDIR /app WORKDIR /app

View File

@ -1,5 +1,6 @@
use json::JsonValue;
use serde::Serialize; use serde::Serialize;
use std::str; use std::str::{self, FromStr};
use tokio::process::Command; use tokio::process::Command;
use utoipa::ToSchema; use utoipa::ToSchema;
@ -65,20 +66,26 @@ pub async fn identify(path: String) -> Result<MediaInfo, std::io::Error> {
.arg("--Language=raw") .arg("--Language=raw")
.arg(path) .arg(path)
.output() .output()
.await?; .await
.expect("Error running the mediainfo command");
assert!(mediainfo.status.success()); assert!(mediainfo.status.success());
let output = json::parse(str::from_utf8(mediainfo.stdout.as_slice()).unwrap()).unwrap(); let output = json::parse(str::from_utf8(mediainfo.stdout.as_slice()).unwrap()).unwrap();
let general = output["media"]["tracks"] let general = output["media"]["track"]
.members() .members()
.find(|x| x["@type"] == "General") .find(|x| x["@type"] == "General")
.unwrap(); .unwrap();
fn parse<F: FromStr>(v: &JsonValue) -> Option<F> {
v.as_str().and_then(|x| x.parse::<F>().ok())
}
// TODO: Every number is wrapped by "" in mediainfo json's mode so the number parsing is wrong.
Ok(MediaInfo { Ok(MediaInfo {
length: general["Duration"].as_f32().unwrap(), length: parse::<f32>(&general["Duration"]).unwrap(),
container: general["Format"].as_str().unwrap().to_string(), container: general["Format"].as_str().unwrap().to_string(),
video: { video: {
let v = output["media"]["tracks"] let v = output["media"]["track"]
.members() .members()
.find(|x| x["@type"] == "Video") .find(|x| x["@type"] == "Video")
.expect("File without video found. This is not supported"); .expect("File without video found. This is not supported");
@ -86,17 +93,17 @@ pub async fn identify(path: String) -> Result<MediaInfo, std::io::Error> {
// This codec is not in the right format (does not include bitdepth...). // This codec is not in the right format (does not include bitdepth...).
codec: v["Format"].as_str().unwrap().to_string(), codec: v["Format"].as_str().unwrap().to_string(),
language: v["Language"].as_str().map(|x| x.to_string()), language: v["Language"].as_str().map(|x| x.to_string()),
quality: Quality::from_height(v["Height"].as_u32().unwrap()), quality: Quality::from_height(parse::<u32>(&v["Height"]).unwrap()),
width: v["Width"].as_u32().unwrap(), width: parse::<u32>(&v["Width"]).unwrap(),
height: v["Height"].as_u32().unwrap(), height: parse::<u32>(&v["Height"]).unwrap(),
bitrate: v["BitRate"].as_u32().unwrap(), bitrate: parse::<u32>(&v["BitRate"]).unwrap(),
} }
}, },
audios: output["media"]["tracks"] audios: output["media"]["track"]
.members() .members()
.filter(|x| x["@type"] == "Audio") .filter(|x| x["@type"] == "Audio")
.map(|a| Track { .map(|a| Track {
index: a["StreamOrder"].as_u32().unwrap(), index: parse::<u32>(&a["StreamOrder"]).unwrap(),
title: a["Title"].as_str().map(|x| x.to_string()), title: a["Title"].as_str().map(|x| x.to_string()),
language: a["Language"].as_str().map(|x| x.to_string()), language: a["Language"].as_str().map(|x| x.to_string()),
// TODO: format is invalid. Channels count missing... // TODO: format is invalid. Channels count missing...
@ -105,11 +112,11 @@ pub async fn identify(path: String) -> Result<MediaInfo, std::io::Error> {
forced: a["Forced"] == "No", forced: a["Forced"] == "No",
}) })
.collect(), .collect(),
subtitles: output["media"]["tracks"] subtitles: output["media"]["track"]
.members() .members()
.filter(|x| x["@type"] == "Text") .filter(|x| x["@type"] == "Text")
.map(|a| Track { .map(|a| Track {
index: a["StreamOrder"].as_u32().unwrap(), index: parse::<u32>(&a["StreamOrder"]).unwrap(),
title: a["Title"].as_str().map(|x| x.to_string()), title: a["Title"].as_str().map(|x| x.to_string()),
language: a["Language"].as_str().map(|x| x.to_string()), language: a["Language"].as_str().map(|x| x.to_string()),
// TODO: format is invalid. Channels count missing... // TODO: format is invalid. Channels count missing...
@ -119,7 +126,7 @@ pub async fn identify(path: String) -> Result<MediaInfo, std::io::Error> {
}) })
.collect(), .collect(),
fonts: vec![], fonts: vec![],
chapters: output["media"]["tracks"] chapters: output["media"]["track"]
.members() .members()
.find(|x| x["@type"] == "Menu") .find(|x| x["@type"] == "Menu")
.map(|x| { .map(|x| {

View File

@ -94,7 +94,7 @@ async fn identify_resource(
.map_err(|_| ApiError::NotFound)?; .map_err(|_| ApiError::NotFound)?;
identify(path).await.map(|info| Json(info)).map_err(|e| { identify(path).await.map(|info| Json(info)).map_err(|e| {
eprintln!("Unhandled error occured while transcoding: {}", e); eprintln!("Unhandled error occured while identifing the resource: {}", e);
ApiError::InternalError ApiError::InternalError
}) })
} }

View File

@ -98,7 +98,7 @@ impl Quality {
pub fn from_height(height: u32) -> Self { pub fn from_height(height: u32) -> Self {
Self::iter() Self::iter()
.find(|x| x.height() <= height) .find(|x| x.height() >= height)
.unwrap_or(&Quality::P240) .unwrap_or(&Quality::P240)
.clone() .clone()
} }