1
0
mirror of https://github.com/osmarks/meme-search-engine.git synced 2024-11-10 22:09:54 +00:00

video parsing basics

This commit is contained in:
osmarks 2024-05-28 22:28:41 +01:00
parent 129b769a56
commit 5eae8674ce
4 changed files with 178 additions and 3 deletions

99
Cargo.lock generated
View File

@ -258,6 +258,26 @@ version = "1.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b"
[[package]]
name = "bindgen"
version = "0.69.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a00dc851838a2120612785d195287475a3ac45514741da670b735818822129a0"
dependencies = [
"bitflags 2.5.0",
"cexpr",
"clang-sys",
"itertools",
"lazy_static",
"lazycell",
"proc-macro2",
"quote",
"regex",
"rustc-hash",
"shlex",
"syn 2.0.65",
]
[[package]]
name = "bit_field"
version = "0.10.2"
@ -356,6 +376,15 @@ dependencies = [
"once_cell",
]
[[package]]
name = "cexpr"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766"
dependencies = [
"nom",
]
[[package]]
name = "cfg-expr"
version = "0.15.8"
@ -386,6 +415,17 @@ dependencies = [
"windows-targets 0.52.5",
]
[[package]]
name = "clang-sys"
version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a483f3cbf7cec2e153d424d0e92329d816becc6421389bd494375c6065921b9b"
dependencies = [
"glob",
"libc",
"libloading",
]
[[package]]
name = "color_quant"
version = "1.1.0"
@ -688,6 +728,30 @@ dependencies = [
"simd-adler32",
]
[[package]]
name = "ffmpeg-sys-the-third"
version = "2.0.0+ffmpeg-7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a82bfdb0a7925996707f0a7dc37b2f3251ff5a15d26e78c586adb60c240dedc5"
dependencies = [
"bindgen",
"cc",
"libc",
"pkg-config",
"vcpkg",
]
[[package]]
name = "ffmpeg-the-third"
version = "2.0.1+ffmpeg-7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c4aa99eb55979d5c1db3b0b7a807a5e50dda07f5f6c2dbc6e9b50c205f611646"
dependencies = [
"bitflags 2.5.0",
"ffmpeg-sys-the-third",
"libc",
]
[[package]]
name = "finl_unicode"
version = "1.2.0"
@ -866,6 +930,12 @@ version = "0.28.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253"
[[package]]
name = "glob"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b"
[[package]]
name = "h2"
version = "0.4.5"
@ -1266,6 +1336,12 @@ dependencies = [
"spin 0.5.2",
]
[[package]]
name = "lazycell"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
[[package]]
name = "lebe"
version = "0.5.2"
@ -1289,6 +1365,16 @@ dependencies = [
"once_cell",
]
[[package]]
name = "libloading"
version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0c2a198fb6b0eada2a8df47933734e6d35d350665a33a3593d7164fa52c75c19"
dependencies = [
"cfg-if",
"windows-targets 0.52.5",
]
[[package]]
name = "libm"
version = "0.2.8"
@ -1399,6 +1485,7 @@ dependencies = [
"chrono",
"faiss",
"fastrand",
"ffmpeg-the-third",
"fnv",
"futures-util",
"half",
@ -2217,6 +2304,12 @@ version = "0.1.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f"
[[package]]
name = "rustc-hash"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
[[package]]
name = "rustix"
version = "0.38.34"
@ -2399,6 +2492,12 @@ dependencies = [
"digest",
]
[[package]]
name = "shlex"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
[[package]]
name = "signal-hook-registry"
version = "1.4.2"

View File

@ -39,10 +39,15 @@ url = "2"
fastrand = "2"
mimalloc = "0.1"
sonic-rs = "0.3"
ffmpeg-the-third = "2.0"
[patch.crates-io]
image = { git = "https://github.com/fintelia/image/", branch = "upgrade-zune-jpeg" }
[[bin]]
name = "reddit-dump"
path = "src/reddit_dump.rs"
path = "src/reddit_dump.rs"
[[bin]]
name = "video-reader"
path = "src/video_reader.rs"

View File

@ -6,7 +6,7 @@ use anyhow::{Result, Context};
use axum::body::Body;
use axum::response::Response;
use axum::{
extract::Json,
extract::{Json, DefaultBodyLimit},
response::IntoResponse,
routing::{get, post},
Router,
@ -860,7 +860,7 @@ async fn main() -> Result<()> {
let client = client.clone();
QUERIES_COUNTER.inc();
handle_request(config, client.clone(), &index, req).await.map_err(|e| format!("{:?}", e))
}))
}).layer(DefaultBodyLimit::max(2<<24)))
.route("/", get(|_req: ()| async move {
Json(FrontendInit {
n_total: index_.read().await.vectors.ntotal(),

71
src/video_reader.rs Normal file
View File

@ -0,0 +1,71 @@
extern crate ffmpeg_the_third as ffmpeg;
use anyhow::{Result, Context};
use image::RgbImage;
use std::env;
use ffmpeg::{codec, filter, format::{self, Pixel}, media::Type, software::scaling, util::frame::video::Video};
fn main() -> Result<()> {
let mut ictx = format::input(&env::args().nth(1).unwrap()).context("parsing video")?;
let video = ictx.streams().best(Type::Video).context("no video stream")?;
let video_index = video.index();
let context_decoder = codec::Context::from_parameters(video.parameters()).context("initializing decoder context")?;
let mut decoder = context_decoder.decoder().video().context("initializing decoder")?;
let mut graph = filter::Graph::new();
let afr = video.avg_frame_rate();
let afr = (((afr.0 as f32) / (afr.1 as f32)).round() as i64).max(1);
// passing in the actual timebase breaks something, and the thumbnail filter should not need it
graph.add(&filter::find("buffer").unwrap(), "in",
&format!("video_size={}x{}:pix_fmt={}:time_base={}/{}:pixel_aspect={}/{}", decoder.width(), decoder.height(), decoder.format().descriptor().unwrap().name(), video.time_base().0, video.time_base().1, decoder.aspect_ratio().0, decoder.aspect_ratio().1))?;
graph.add(&filter::find("buffersink").unwrap(), "out", "")?;
graph.output("in", 0)?.input("out", 0)?.parse(&format!("[in] thumbnail=n={} [thumbs]; [thumbs] select='gt(scene,0.05)+eq(n,0)' [out]", afr)).context("filtergraph parse failed")?;
let mut out = graph.get("out").unwrap();
out.set_pixel_format(decoder.format());
graph.validate().context("filtergraph build failed")?;
let mut scaler = scaling::Context::get(
decoder.format(),
decoder.width(),
decoder.height(),
Pixel::RGB24,
384,
384,
scaling::Flags::LANCZOS,
)?;
let mut count = 0;
let mut receive_and_process_decoded_frames = |decoder: &mut ffmpeg::decoder::Video, filter_graph: &mut filter::Graph| -> Result<()> {
let mut decoded = Video::empty();
let mut filtered = Video::empty();
let mut rgb_frame = Video::empty();
loop {
if !decoder.receive_frame(&mut decoded).is_ok() { break }
let mut in_ctx = filter_graph.get("in").unwrap();
let mut src = in_ctx.source();
src.add(&decoded).context("add frame")?;
while filter_graph.get("out").unwrap().sink().frame(&mut filtered).is_ok() {
scaler.run(&filtered, &mut rgb_frame).context("scaler")?;
println!("frame gotten {}x{} {:?} {}", rgb_frame.width(), rgb_frame.height(), rgb_frame.data(0).len(), count);
let image = RgbImage::from_vec(rgb_frame.width(), rgb_frame.height(), rgb_frame.data(0).to_vec()).unwrap(); // unfortunately, we have to copy
image.save(format!("/tmp/output-{}.png", count))?;
count += 1;
}
}
Ok(())
};
for (stream, packet) in ictx.packets().filter_map(Result::ok) {
if stream.index() == video_index {
decoder.send_packet(&packet).context("decoder")?;
receive_and_process_decoded_frames(&mut decoder, &mut graph).context("processing")?;
}
}
decoder.send_eof()?;
receive_and_process_decoded_frames(&mut decoder, &mut graph)?;
Ok(())
}