| 22 | #[allow(unused_variables)] |
| 23 | #[allow(unused_labels)] |
| 24 | pub fn decode_video( |
| 25 | id: u64, |
| 26 | path: impl AsRef<Path>, |
| 27 | sender: &Sender, |
| 28 | ) -> Result<(), ffmpeg_next::Error> { |
| 29 | ONCE_INIT.call_once(|| { |
| 30 | ffmpeg_next::init().unwrap(); |
| 31 | }); |
| 32 | |
| 33 | let mut ictx = input(&path)?; |
| 34 | |
| 35 | let input = ictx |
| 36 | .streams() |
| 37 | .best(Type::Video) |
| 38 | .ok_or(ffmpeg_next::Error::StreamNotFound)?; |
| 39 | |
| 40 | let video_stream_index = input.index(); |
| 41 | |
| 42 | let mut decoder = input.codec().decoder().video()?; |
| 43 | |
| 44 | let mut scaler = Context::get( |
| 45 | decoder.format(), |
| 46 | decoder.width(), |
| 47 | decoder.height(), |
| 48 | Pixel::BGR24, |
| 49 | decoder.width(), |
| 50 | decoder.height(), |
| 51 | Flags::BILINEAR, |
| 52 | )?; |
| 53 | |
| 54 | let mut fid = 0; |
| 55 | |
| 56 | 'main: for (stream, packet) in ictx.packets() { |
| 57 | if stream.index() == video_stream_index { |
| 58 | decoder.send_packet(&packet)?; |
| 59 | |
| 60 | let mut decoded = Video::empty(); |
| 61 | |
| 62 | while decoder.receive_frame(&mut decoded).is_ok() { |
| 63 | let mut bgr_frame = Video::empty(); |
| 64 | scaler.run(&decoded, &mut bgr_frame)?; |
| 65 | |
| 66 | #[cfg(feature = "python")] |
| 67 | { |
| 68 | use numpy::ToPyArray; |
| 69 | use pyo3::prelude::*; |
| 70 | use pyo3::types::IntoPyDict; |
| 71 | let ndarray = Python::with_gil(|py| -> PyResult<_> { |
| 72 | let data = bgr_frame.data(0); |
| 73 | let ndarray = data.to_pyarray(py).reshape([ |
| 74 | bgr_frame.height() as usize, |
| 75 | bgr_frame.stride(0) / 3, |
| 76 | 3, |
| 77 | ])?; |
| 78 | |
| 79 | Ok([("data", ndarray.to_object(py))] |
| 80 | .into_py_dict(py) |
| 81 | .to_object(py)) |