1use ::core::ffi::c_void;
4use ::core::ops::{Deref, DerefMut};
5use ::core::{ptr, slice};
6use c_str_macro::c_str;
7use ffmpeg_sys_next::*;
8use libc::c_int;
9use log::*;
10use nalgebra as na;
11use ofps::prelude::v1::{ptrplus::*, Result, *};
12use ofps::utils::*;
13use std::io::*;
14use std::mem::MaybeUninit;
15
16ofps::define_descriptor!(av, Decoder, |input| {
17 let f = open_file(&input)?;
18 AvDecoder::try_new(f).map(|d| Box::new(d) as _)
19});
20
21pub struct AvBuf(&'static mut [u8]);
22
23impl AvBuf {
24 pub fn try_new(size: usize) -> Result<Self> {
25 let buf = unsafe { av_malloc(size) as *mut u8 };
26
27 if buf.is_null() {
28 Err(anyhow!("Failed to allocate buffer"))
29 } else {
30 Ok(Self(unsafe { slice::from_raw_parts_mut(buf, size) }))
31 }
32 }
33}
34
35impl Drop for AvBuf {
36 fn drop(&mut self) {
37 unsafe { av_free(self.0.as_mut_ptr() as *mut _) }
38 }
39}
40
41impl Deref for AvBuf {
42 type Target = [u8];
43
44 fn deref(&self) -> &[u8] {
45 self.0
46 }
47}
48
49impl DerefMut for AvBuf {
50 fn deref_mut(&mut self) -> &mut [u8] {
51 self.0
52 }
53}
54
55pub struct AvContext<T: ?Sized> {
56 #[allow(clippy::redundant_allocation)]
57 _stream: Box<Box<T>>,
58 pub fmt_ctx: &'static mut AVFormatContext,
59 pub avio_ctx: &'static mut AVIOContext,
60}
61
62impl<T: ?Sized> Drop for AvContext<T> {
63 fn drop(&mut self) {
64 unsafe {
67 avformat_close_input(&mut (self.fmt_ctx as *mut _));
68 av_free((*self.avio_ctx).buffer as *mut _);
69 av_free(self.avio_ctx as *mut _ as *mut c_void);
70 }
71 }
72}
73
74impl<T: Read + ?Sized> AvContext<T> {
75 pub fn try_new(stream: Box<T>) -> Result<Self> {
76 let mut buf = AvBuf::try_new(8196)?;
77
78 let mut stream: Box<Box<T>> = stream.into();
79
80 let avio_ctx = unsafe {
83 avio_alloc_context(
84 buf.as_mut_ptr(),
85 buf.len() as _,
86 0,
87 (&mut *stream) as *mut Box<T> as *mut _,
88 Some(Self::read_callback),
89 None,
90 None,
91 )
92 .as_mut()
93 }
94 .ok_or_else(|| anyhow!("Failed to allocate AVIOContext"))?;
95
96 let mut fmt_ctx = unsafe { avformat_alloc_context().as_mut() }.ok_or_else(|| {
97 unsafe { av_free((*avio_ctx).buffer as *mut _) };
98 unsafe { av_free(avio_ctx as *mut AVIOContext as *mut _) };
99 anyhow!("Failed to allocate AVFormatContext")
100 })?;
101
102 fmt_ctx.pb = avio_ctx;
103
104 match unsafe {
105 avformat_open_input(
106 fmt_ctx.as_mut_ptr(),
107 ptr::null(),
108 ptr::null_mut(),
109 ptr::null_mut(),
110 )
111 } {
112 0 => {
113 std::mem::forget(buf);
114 Ok(Self {
115 _stream: stream,
116 fmt_ctx,
117 avio_ctx,
118 })
119 }
120 e => {
121 unsafe { av_free((*avio_ctx).buffer as *mut _) };
122 unsafe { av_free(avio_ctx as *mut AVIOContext as *mut _) };
123 Err(anyhow!("Unable to open input ({:x})", e))
124 }
125 }
126 }
127
128 unsafe extern "C" fn read_callback(
129 opaque: *mut c_void,
130 buf: *mut u8,
131 buf_size: c_int,
132 ) -> c_int {
133 let ret = (*(opaque as *mut Box<T>))
134 .read(slice::from_raw_parts_mut(buf, buf_size as _))
135 .map(|r| r as c_int)
136 .map(|r| {
137 trace!("{}", r);
138 r
139 })
140 .map_err(|e| {
141 error!("{}", e);
142 e
143 })
144 .unwrap_or(-1);
145
146 if ret == 0 && buf_size != 0 {
148 -1
149 } else {
150 ret
151 }
152 }
153
154 pub fn dump_format(&mut self) {
155 unsafe { av_dump_format(self.fmt_ctx, 0, std::ptr::null(), 0) };
156 }
157}
158
159pub struct AvDecoder<T: ?Sized> {
160 pub av_ctx: AvContext<T>,
161 codec_ctx: &'static mut AVCodecContext,
162 av_frame: &'static mut AVFrame,
163 stream_idx: i32,
164 framerate: f64,
165 aspect_ratio: (usize, usize),
166 sws_av_frame: &'static mut AVFrame,
167 sws_ctx: Option<&'static mut SwsContext>,
168}
169
170impl<T: ?Sized> Properties for AvDecoder<T> {}
171
172unsafe impl<T: Send + ?Sized> Send for AvDecoder<T> {}
173unsafe impl<T: Sync + ?Sized> Sync for AvDecoder<T> {}
174
175impl<T: ?Sized> Drop for AvDecoder<T> {
176 fn drop(&mut self) {
177 unsafe {
180 av_frame_free(&mut (self.av_frame as *mut _));
181 avcodec_free_context(&mut (self.codec_ctx as *mut _));
182 av_frame_free(&mut (self.sws_av_frame as *mut _));
183 if let Some(sws_ctx) = self.sws_ctx.take() {
184 sws_freeContext(sws_ctx);
185 }
186 };
187 }
188}
189
190struct RefFrame<'a> {
191 frame: &'a mut AVFrame,
192}
193
194impl<'a> Drop for RefFrame<'a> {
195 fn drop(&mut self) {
196 unsafe { av_frame_unref(self.frame) };
197 }
198}
199
200impl<'a> RefFrame<'a> {
201 fn new(codec_ctx: &mut AVCodecContext, frame: &'a mut AVFrame) -> Result<Option<Self>> {
202 match unsafe { avcodec_receive_frame(codec_ctx, frame) } {
203 -11 => Ok(None),
205 e if e < 0 => return Err(anyhow!("Failed to recv frame ({})", e)),
206 _ => Ok(Some(Self { frame })),
207 }
208 }
209}
210
211impl<'a> Deref for RefFrame<'a> {
212 type Target = AVFrame;
213
214 fn deref(&self) -> &Self::Target {
215 self.frame
216 }
217}
218
219impl<'a> DerefMut for RefFrame<'a> {
220 fn deref_mut(&mut self) -> &mut Self::Target {
221 self.frame
222 }
223}
224
225impl<T: Read + ?Sized> AvDecoder<T> {
226 pub fn try_new(stream: Box<T>) -> Result<Self> {
227 let av_ctx = AvContext::try_new(stream)?;
228
229 let mut decoder: Option<&mut AVCodec> = None;
230
231 let stream_idx = match unsafe {
232 av_find_best_stream(
233 av_ctx.fmt_ctx,
234 AVMediaType::AVMEDIA_TYPE_VIDEO,
235 -1,
236 -1,
237 decoder.as_mut_ptr() as *mut _ as *mut *const AVCodec,
238 0,
239 )
240 } {
241 e if e < 0 => Err(anyhow!("Failed to find a stream ({})", e)),
242 i => Ok(i),
243 }?;
244
245 let mut codec_ctx = unsafe { avcodec_alloc_context3(decoder.as_deref().as_ptr()).as_mut() }
246 .ok_or_else(|| anyhow!("Failed to allocate codec context"))?;
247
248 let stream = unsafe { (*av_ctx.fmt_ctx.streams.offset(stream_idx as _)).as_mut() }
249 .ok_or_else(|| anyhow!("Stream info null"))?;
250
251 debug!("{:?}", stream);
252
253 let framerate = if stream.avg_frame_rate.den != 0 && stream.avg_frame_rate.num != 0 {
254 stream.avg_frame_rate.num as f64 / stream.avg_frame_rate.den as f64
255 } else {
256 stream.time_base.den as f64 / stream.time_base.num as f64
257 };
258
259 match unsafe { avcodec_parameters_to_context(codec_ctx, stream.codecpar) } {
260 e if e < 0 => {
261 unsafe { avcodec_free_context(codec_ctx.as_mut_ptr()) };
262 return Err(anyhow!("Failed to get codec parameters ({})", e));
263 }
264 _ => {}
265 }
266
267 let mut av_opts: Option<&mut AVDictionary> = None;
268
269 unsafe {
270 av_dict_set(
271 av_opts.as_mut_ptr(),
272 c_str!("flags2").as_ptr(),
273 c_str!("+export_mvs").as_ptr(),
274 0,
275 );
276 }
277
278 match unsafe { avcodec_open2(codec_ctx, decoder.as_deref().as_ptr(), av_opts.as_mut_ptr()) }
279 {
280 e if e < 0 => {
281 unsafe { avcodec_free_context(codec_ctx.as_mut_ptr()) };
282 return Err(anyhow!("Failed to open codec ({})", e));
283 }
284 _ => {}
285 }
286
287 let av_frame = unsafe { av_frame_alloc().as_mut() }
288 .ok_or_else(|| anyhow!("Unable to allocate frame"))?;
289
290 let sws_av_frame = unsafe { av_frame_alloc().as_mut() }
291 .ok_or_else(|| anyhow!("Unable to allocate sws frame"))?;
292
293 debug!(
294 "{:x} {:x}",
295 codec_ctx.pix_fmt as usize,
296 AVPixelFormat::AV_PIX_FMT_RGBA as usize
297 );
298 debug!(
299 "{:?} {:?}",
300 unsafe { av_pix_fmt_desc_get(codec_ctx.pix_fmt) },
301 unsafe { av_pix_fmt_desc_get(AVPixelFormat::AV_PIX_FMT_RGBA) }
302 );
303
304 Ok(Self {
305 av_ctx,
306 codec_ctx,
307 av_frame,
308 stream_idx,
309 framerate,
310 aspect_ratio: (0, 0),
311 sws_av_frame,
312 sws_ctx: None,
313 })
314 }
315
316 pub fn extract_mvs(
322 &mut self,
323 packet: &mut AVPacket,
324 mf: &mut MotionVectors,
325 out_frame: Option<(&mut Vec<RGBA>, &mut usize)>,
326 ) -> Result<bool> {
327 match unsafe { avcodec_send_packet(self.codec_ctx, packet) } {
328 e if e < 0 => return Err(anyhow!("Failed to send packet ({})", e)),
329 _ => {}
330 }
331
332 if let Some(frame) = RefFrame::new(self.codec_ctx, self.av_frame)? {
333 self.aspect_ratio = (frame.width as usize, frame.height as usize);
334
335 if let Some((out_frame, out_height)) = out_frame {
336 out_frame.clear();
337
338 let sws_ctx = match self.sws_ctx.take() {
340 Some(ctx) => ctx,
341 None => unsafe {
342 let sws_frame = &mut self.sws_av_frame;
343
344 sws_frame.format = AVPixelFormat::AV_PIX_FMT_RGBA as _;
345 sws_frame.width = frame.width;
346 sws_frame.height = frame.height;
347
348 av_frame_get_buffer(*sws_frame, 32);
349
350 sws_getContext(
351 frame.width,
352 frame.height,
353 std::mem::transmute(frame.format),
354 sws_frame.width,
355 sws_frame.height,
356 std::mem::transmute(sws_frame.format),
357 0,
358 ptr::null_mut(),
359 ptr::null_mut(),
360 ptr::null(),
361 )
362 .as_mut()
363 }
364 .ok_or_else(|| anyhow!("Unable to allocate sws context"))?,
365 };
366
367 let sws_frame = &mut self.sws_av_frame;
368
369 unsafe {
370 sws_scale(
371 sws_ctx,
372 frame.data.as_ptr() as *const *const _,
373 frame.linesize.as_ptr(),
374 0,
375 frame.height,
376 sws_frame.data.as_mut_ptr(),
377 sws_frame.linesize.as_mut_ptr(),
378 )
379 };
380
381 let frame_data = sws_frame.data[0];
382 let linesize = sws_frame.linesize[0] as usize;
383 let width = sws_frame.width as usize;
384 *out_height = sws_frame.height as usize;
385 for y in 0..*out_height {
386 let frame_slice =
387 unsafe { slice::from_raw_parts(frame_data.add(linesize * y), width * 4) };
388 for chunk in frame_slice.chunks_exact(4) {
389 out_frame.push(RGBA::from_rgb_slice(chunk));
390 }
391 }
392
393 self.sws_ctx = Some(sws_ctx);
394 }
395
396 if let Some(side_data) = unsafe {
397 av_frame_get_side_data(&*frame, AVFrameSideDataType::AV_FRAME_DATA_MOTION_VECTORS)
398 .as_ref()
399 } {
400 let size = side_data.size as usize / std::mem::size_of::<AVMotionVector>();
401 let motion_vectors =
402 unsafe { slice::from_raw_parts(side_data.data as *const AVMotionVector, size) };
403
404 let frame_norm =
405 na::Vector2::new(1f32 / frame.width as f32, 1f32 / frame.height as f32);
406
407 for mv in motion_vectors {
409 let pos = na::Vector2::new(mv.src_x as f32, mv.src_y as f32)
410 .component_mul(&frame_norm)
411 .into();
412 let motion = na::Vector2::new(mv.motion_x as f32, mv.motion_y as f32)
413 .component_div(&na::Vector2::new(
414 mv.motion_scale as f32,
415 mv.motion_scale as f32,
416 ))
417 .component_mul(&-frame_norm);
418
419 mf.push((pos, motion));
420 }
421
422 Ok(true)
423 } else {
424 Ok(false)
425 }
426 } else {
427 Ok(false)
428 }
429 }
430}
431
432impl<T: Read + ?Sized> Decoder for AvDecoder<T> {
433 fn process_frame(
434 &mut self,
435 mf: &mut MotionVectors,
436 mut out_frame: Option<(&mut Vec<RGBA>, &mut usize)>,
437 mut skip: usize,
438 ) -> Result<bool> {
439 let mut packet = MaybeUninit::uninit();
440 let mut reached_stream = false;
441 let mut ret = false;
442
443 while !reached_stream || skip > 0 {
444 match unsafe { av_read_frame(self.av_ctx.fmt_ctx, packet.as_mut_ptr()) } {
445 e if e < 0 => return Err(anyhow!("Failed to read frame ({})", e)),
446 _ => {
447 if skip > 0 {
448 skip -= 1;
449 if skip > 20 {
450 continue;
451 }
452 }
453
454 let packet = unsafe { packet.assume_init_mut() };
455
456 trace!("Read packet: {} {}", packet.stream_index, packet.size);
457
458 if packet.stream_index == self.stream_idx {
459 debug!("Reached wanted stream!");
460 reached_stream = true;
461 ret = self.extract_mvs(packet, mf, out_frame.take())?;
462 }
463
464 unsafe { av_packet_unref(packet) };
465 }
466 }
467 }
468
469 Ok(ret)
470 }
471
472 fn get_framerate(&self) -> Option<f64> {
473 Some(self.framerate)
474 }
475
476 fn get_aspect(&self) -> Option<(usize, usize)> {
477 Some(self.aspect_ratio)
478 }
479}