1use core::num::NonZero;
2
3use crate::codec::DecoderCodec;
4use crate::error::{FfmpegError, FfmpegErrorCode};
5use crate::ffi::*;
6use crate::frame::{AudioFrame, GenericFrame, VideoFrame};
7use crate::packet::Packet;
8use crate::rational::Rational;
9use crate::smart_object::SmartPtr;
10use crate::stream::Stream;
11use crate::{AVCodecID, AVMediaType, AVPixelFormat, AVSampleFormat};
12
13#[derive(Debug)]
17pub enum Decoder {
18 Video(VideoDecoder),
20 Audio(AudioDecoder),
22}
23
24pub struct GenericDecoder {
26 decoder: SmartPtr<AVCodecContext>,
27}
28
29unsafe impl Send for GenericDecoder {}
31
32impl std::fmt::Debug for GenericDecoder {
33 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
34 f.debug_struct("Decoder")
35 .field("time_base", &self.time_base())
36 .field("codec_type", &self.codec_type())
37 .finish()
38 }
39}
40
41pub struct VideoDecoder(GenericDecoder);
43
44impl std::fmt::Debug for VideoDecoder {
45 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
46 f.debug_struct("VideoDecoder")
47 .field("time_base", &self.time_base())
48 .field("width", &self.width())
49 .field("height", &self.height())
50 .field("pixel_format", &self.pixel_format())
51 .field("frame_rate", &self.frame_rate())
52 .field("sample_aspect_ratio", &self.sample_aspect_ratio())
53 .finish()
54 }
55}
56
57pub struct AudioDecoder(GenericDecoder);
59
60impl std::fmt::Debug for AudioDecoder {
61 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
62 f.debug_struct("AudioDecoder")
63 .field("time_base", &self.time_base())
64 .field("sample_rate", &self.sample_rate())
65 .field("channels", &self.channels())
66 .field("sample_fmt", &self.sample_format())
67 .finish()
68 }
69}
70
71pub struct DecoderOptions {
73 pub codec: Option<DecoderCodec>,
75 pub thread_count: i32,
77}
78
79impl Default for DecoderOptions {
81 fn default() -> Self {
82 Self {
83 codec: None,
84 thread_count: 1,
85 }
86 }
87}
88
89impl Decoder {
90 pub fn new(ist: &Stream) -> Result<Self, FfmpegError> {
92 Self::with_options(ist, Default::default())
93 }
94
95 pub fn with_options(ist: &Stream, options: DecoderOptions) -> Result<Self, FfmpegError> {
97 let Some(codec_params) = ist.codec_parameters() else {
98 return Err(FfmpegError::NoDecoder);
99 };
100
101 let codec = options
102 .codec
103 .or_else(|| DecoderCodec::new(AVCodecID(codec_params.codec_id as _)))
104 .ok_or(FfmpegError::NoDecoder)?;
105
106 if codec.is_empty() {
107 return Err(FfmpegError::NoDecoder);
108 }
109
110 let decoder = unsafe { avcodec_alloc_context3(codec.as_ptr()) };
112
113 let destructor = |ptr: &mut *mut AVCodecContext| {
114 unsafe { avcodec_free_context(ptr) };
116 };
117
118 let mut decoder = unsafe { SmartPtr::wrap_non_null(decoder, destructor) }.ok_or(FfmpegError::Alloc)?;
120
121 FfmpegErrorCode(unsafe { avcodec_parameters_to_context(decoder.as_mut_ptr(), codec_params) }).result()?;
123
124 let decoder_mut = decoder.as_deref_mut_except();
125
126 decoder_mut.pkt_timebase = ist.time_base().into();
127 decoder_mut.time_base = ist.time_base().into();
128 decoder_mut.thread_count = options.thread_count;
129
130 if AVMediaType(decoder_mut.codec_type) == AVMediaType::Video {
131 let format_context = unsafe { ist.format_context() };
137
138 decoder_mut.framerate =
139 unsafe { av_guess_frame_rate(format_context, ist.as_ptr() as *mut AVStream, std::ptr::null_mut()) };
141 }
142
143 if matches!(AVMediaType(decoder_mut.codec_type), AVMediaType::Video | AVMediaType::Audio) {
144 FfmpegErrorCode(unsafe { avcodec_open2(decoder_mut, codec.as_ptr(), std::ptr::null_mut()) }).result()?;
146 }
147
148 Ok(match AVMediaType(decoder_mut.codec_type) {
149 AVMediaType::Video => Self::Video(VideoDecoder(GenericDecoder { decoder })),
150 AVMediaType::Audio => Self::Audio(AudioDecoder(GenericDecoder { decoder })),
151 _ => Err(FfmpegError::NoDecoder)?,
152 })
153 }
154
155 pub fn video(self) -> Result<VideoDecoder, Self> {
157 match self {
158 Self::Video(video) => Ok(video),
159 _ => Err(self),
160 }
161 }
162
163 pub fn audio(self) -> Result<AudioDecoder, Self> {
165 match self {
166 Self::Audio(audio) => Ok(audio),
167 _ => Err(self),
168 }
169 }
170}
171
172impl GenericDecoder {
173 pub const fn codec_type(&self) -> AVMediaType {
175 AVMediaType(self.decoder.as_deref_except().codec_type)
176 }
177
178 pub const fn time_base(&self) -> Option<Rational> {
180 let time_base = self.decoder.as_deref_except().time_base;
181 match NonZero::new(time_base.den) {
182 Some(den) => Some(Rational::new(time_base.num, den)),
183 None => None,
184 }
185 }
186
187 pub fn send_packet(&mut self, packet: &Packet) -> Result<(), FfmpegError> {
189 FfmpegErrorCode(unsafe { avcodec_send_packet(self.decoder.as_mut_ptr(), packet.as_ptr()) }).result()?;
191 Ok(())
192 }
193
194 pub fn send_eof(&mut self) -> Result<(), FfmpegError> {
196 FfmpegErrorCode(unsafe { avcodec_send_packet(self.decoder.as_mut_ptr(), std::ptr::null()) }).result()?;
198 Ok(())
199 }
200
201 pub fn receive_frame(&mut self) -> Result<Option<GenericFrame>, FfmpegError> {
203 let mut frame = GenericFrame::new()?;
204
205 let ret = FfmpegErrorCode(unsafe { avcodec_receive_frame(self.decoder.as_mut_ptr(), frame.as_mut_ptr()) });
207
208 match ret {
209 FfmpegErrorCode::Eagain | FfmpegErrorCode::Eof => Ok(None),
210 code if code.is_success() => {
211 frame.set_time_base(self.decoder.as_deref_except().time_base);
212 Ok(Some(frame))
213 }
214 code => Err(FfmpegError::Code(code)),
215 }
216 }
217}
218
219impl VideoDecoder {
220 pub const fn width(&self) -> i32 {
222 self.0.decoder.as_deref_except().width
223 }
224
225 pub const fn height(&self) -> i32 {
227 self.0.decoder.as_deref_except().height
228 }
229
230 pub const fn pixel_format(&self) -> AVPixelFormat {
232 AVPixelFormat(self.0.decoder.as_deref_except().pix_fmt)
233 }
234
235 pub fn frame_rate(&self) -> Rational {
237 self.0.decoder.as_deref_except().framerate.into()
238 }
239
240 pub fn sample_aspect_ratio(&self) -> Rational {
242 self.0.decoder.as_deref_except().sample_aspect_ratio.into()
243 }
244
245 pub fn receive_frame(&mut self) -> Result<Option<VideoFrame>, FfmpegError> {
247 Ok(self.0.receive_frame()?.map(|frame| frame.video()))
248 }
249}
250
251impl std::ops::Deref for VideoDecoder {
252 type Target = GenericDecoder;
253
254 fn deref(&self) -> &Self::Target {
255 &self.0
256 }
257}
258
259impl std::ops::DerefMut for VideoDecoder {
260 fn deref_mut(&mut self) -> &mut Self::Target {
261 &mut self.0
262 }
263}
264
265impl AudioDecoder {
266 pub const fn sample_rate(&self) -> i32 {
268 self.0.decoder.as_deref_except().sample_rate
269 }
270
271 pub const fn channels(&self) -> i32 {
273 self.0.decoder.as_deref_except().ch_layout.nb_channels
274 }
275
276 pub const fn sample_format(&self) -> AVSampleFormat {
278 AVSampleFormat(self.0.decoder.as_deref_except().sample_fmt)
279 }
280
281 pub fn receive_frame(&mut self) -> Result<Option<AudioFrame>, FfmpegError> {
283 Ok(self.0.receive_frame()?.map(|frame| frame.audio()))
284 }
285}
286
287impl std::ops::Deref for AudioDecoder {
288 type Target = GenericDecoder;
289
290 fn deref(&self) -> &Self::Target {
291 &self.0
292 }
293}
294
295impl std::ops::DerefMut for AudioDecoder {
296 fn deref_mut(&mut self) -> &mut Self::Target {
297 &mut self.0
298 }
299}
300
301#[cfg(test)]
302#[cfg_attr(all(test, coverage_nightly), coverage(off))]
303mod tests {
304 use std::num::NonZero;
305
306 use crate::codec::DecoderCodec;
307 use crate::decoder::{Decoder, DecoderOptions};
308 use crate::io::Input;
309 use crate::{AVCodecID, AVMediaType, file_path};
310
311 #[test]
312 fn test_generic_decoder_debug() {
313 let input = Input::open(file_path("avc_aac_large.mp4")).expect("Failed to open valid file");
314 let streams = input.streams();
315 let stream = streams
316 .iter()
317 .find(|s| {
318 s.codec_parameters()
319 .map(|p| AVMediaType(p.codec_type) == AVMediaType::Video)
320 .unwrap_or(false)
321 })
322 .expect("No video stream found");
323 let codec_params = stream.codec_parameters().expect("Missing codec parameters");
324 assert_eq!(
325 AVMediaType(codec_params.codec_type),
326 AVMediaType::Video,
327 "Expected the stream to be a video stream"
328 );
329 let decoder_options = DecoderOptions {
330 codec: Some(DecoderCodec::new(AVCodecID::H264).expect("Failed to find H264 codec")),
331 thread_count: 2,
332 };
333 let decoder = Decoder::with_options(&stream, decoder_options).expect("Failed to create Decoder");
334 let generic_decoder = match decoder {
335 Decoder::Video(video_decoder) => video_decoder.0,
336 Decoder::Audio(audio_decoder) => audio_decoder.0,
337 };
338
339 insta::assert_debug_snapshot!(generic_decoder, @r"
340 Decoder {
341 time_base: Some(
342 Rational {
343 numerator: 1,
344 denominator: 15360,
345 },
346 ),
347 codec_type: AVMediaType::Video,
348 }
349 ");
350 }
351
352 #[test]
353 fn test_video_decoder_debug() {
354 let input = Input::open(file_path("avc_aac_large.mp4")).expect("Failed to open valid file");
355 let streams = input.streams();
356 let stream = streams
357 .iter()
358 .find(|s| {
359 s.codec_parameters()
360 .map(|p| AVMediaType(p.codec_type) == AVMediaType::Video)
361 .unwrap_or(false)
362 })
363 .expect("No video stream found");
364 let codec_params = stream.codec_parameters().expect("Missing codec parameters");
365 assert_eq!(
366 AVMediaType(codec_params.codec_type),
367 AVMediaType::Video,
368 "Expected the stream to be a video stream"
369 );
370
371 let decoder_options = DecoderOptions {
372 codec: Some(DecoderCodec::new(AVCodecID::H264).expect("Failed to find H264 codec")),
373 thread_count: 2,
374 };
375 let decoder = Decoder::with_options(&stream, decoder_options).expect("Failed to create Decoder");
376
377 let generic_decoder = match decoder {
378 Decoder::Video(video_decoder) => video_decoder,
379 _ => panic!("Expected a video decoder, got something else"),
380 };
381
382 insta::assert_debug_snapshot!(generic_decoder, @r"
383 VideoDecoder {
384 time_base: Some(
385 Rational {
386 numerator: 1,
387 denominator: 15360,
388 },
389 ),
390 width: 3840,
391 height: 2160,
392 pixel_format: AVPixelFormat::Yuv420p,
393 frame_rate: Rational {
394 numerator: 60,
395 denominator: 1,
396 },
397 sample_aspect_ratio: Rational {
398 numerator: 1,
399 denominator: 1,
400 },
401 }
402 ");
403 }
404
405 #[test]
406 fn test_audio_decoder_debug() {
407 let input = Input::open(file_path("avc_aac_large.mp4")).expect("Failed to open valid file");
408 let streams = input.streams();
409 let stream = streams
410 .iter()
411 .find(|s| {
412 s.codec_parameters()
413 .map(|p| AVMediaType(p.codec_type) == AVMediaType::Audio)
414 .unwrap_or(false)
415 })
416 .expect("No audio stream found");
417 let codec_params = stream.codec_parameters().expect("Missing codec parameters");
418 assert_eq!(
419 AVMediaType(codec_params.codec_type),
420 AVMediaType::Audio,
421 "Expected the stream to be an audio stream"
422 );
423 let decoder_options = DecoderOptions {
424 codec: Some(DecoderCodec::new(AVCodecID::Aac).expect("Failed to find AAC codec")),
425 thread_count: 2,
426 };
427 let decoder = Decoder::with_options(&stream, decoder_options).expect("Failed to create Decoder");
428 let audio_decoder = match decoder {
429 Decoder::Audio(audio_decoder) => audio_decoder,
430 _ => panic!("Expected an audio decoder, got something else"),
431 };
432
433 insta::assert_debug_snapshot!(audio_decoder, @r"
434 AudioDecoder {
435 time_base: Some(
436 Rational {
437 numerator: 1,
438 denominator: 48000,
439 },
440 ),
441 sample_rate: 48000,
442 channels: 2,
443 sample_fmt: AVSampleFormat::Fltp,
444 }
445 ");
446 }
447
448 #[test]
449 fn test_decoder_options_default() {
450 let default_options = DecoderOptions::default();
451
452 assert!(default_options.codec.is_none(), "Expected default codec to be None");
453 assert_eq!(default_options.thread_count, 1, "Expected default thread_count to be 1");
454 }
455
456 #[test]
457 fn test_decoder_new() {
458 let input = Input::open(file_path("avc_aac_large.mp4")).expect("Failed to open valid file");
459 let streams = input.streams();
460 let stream = streams
461 .iter()
462 .find(|s| {
463 s.codec_parameters()
464 .map(|p| AVMediaType(p.codec_type) == AVMediaType::Video)
465 .unwrap_or(false)
466 })
467 .expect("No video stream found");
468
469 let decoder_result = Decoder::new(&stream);
470 assert!(decoder_result.is_ok(), "Expected Decoder::new to succeed, but it failed");
471
472 let decoder = decoder_result.unwrap();
473 if let Decoder::Video(video_decoder) = decoder {
474 assert_eq!(video_decoder.width(), 3840, "Expected valid width for video stream");
475 assert_eq!(video_decoder.height(), 2160, "Expected valid height for video stream");
476 } else {
477 panic!("Expected a video decoder, but got a different type");
478 }
479 }
480
481 #[test]
482 fn test_decoder_with_options_missing_codec_parameters() {
483 let mut input = Input::open(file_path("avc_aac_large.mp4")).expect("Failed to open valid file");
484 let mut streams = input.streams_mut();
485 let mut stream = streams.get(0).expect("Expected a valid stream");
486 let codecpar = unsafe { (*stream.as_mut_ptr()).codecpar };
488 unsafe {
490 (*stream.as_mut_ptr()).codecpar = std::ptr::null_mut();
491 }
492 let decoder_result = Decoder::with_options(&stream, DecoderOptions::default());
493 unsafe {
495 (*stream.as_mut_ptr()).codecpar = codecpar;
496 }
497
498 assert!(decoder_result.is_err(), "Expected Decoder creation to fail");
499 if let Err(err) = decoder_result {
500 match err {
501 crate::error::FfmpegError::NoDecoder => (),
502 _ => panic!("Unexpected error type: {err:?}"),
503 }
504 }
505 }
506
507 #[test]
508 fn test_decoder_with_options_non_video_audio_codec_type() {
509 let mut input = Input::open(file_path("avc_aac_large.mp4")).expect("Failed to open valid file");
510 let mut streams = input.streams_mut();
511 let mut stream = streams.get(0).expect("Expected a valid stream");
512 let codecpar = unsafe { (*stream.as_mut_ptr()).codecpar };
514 unsafe {
516 (*codecpar).codec_type = AVMediaType::Subtitle.into();
517 }
518 let decoder_result = Decoder::with_options(&stream, DecoderOptions::default());
519
520 assert!(
521 decoder_result.is_err(),
522 "Expected Decoder creation to fail for non-video/audio codec type"
523 );
524 if let Err(err) = decoder_result {
525 match err {
526 crate::error::FfmpegError::NoDecoder => (),
527 _ => panic!("Unexpected error type: {err:?}"),
528 }
529 }
530 }
531
532 #[test]
533 fn test_video_decoder_deref_mut_safe() {
534 let input = Input::open(file_path("avc_aac_large.mp4")).expect("Failed to open valid file");
535 let streams = input.streams();
536 let stream = streams
537 .iter()
538 .find(|s| {
539 s.codec_parameters()
540 .map(|p| AVMediaType(p.codec_type) == AVMediaType::Video)
541 .unwrap_or(false)
542 })
543 .expect("No video stream found");
544 let decoder_options = DecoderOptions {
545 codec: None,
546 thread_count: 2,
547 };
548 let decoder = Decoder::with_options(&stream, decoder_options).expect("Failed to create Decoder");
549 let mut video_decoder = match decoder {
550 Decoder::Video(video_decoder) => video_decoder,
551 _ => panic!("Expected a VideoDecoder, got something else"),
552 };
553 {
554 let generic_decoder = &mut *video_decoder;
555 let mut time_base = generic_decoder.time_base().expect("Failed to get time base of decoder");
556 time_base.numerator = 1000;
557 time_base.denominator = NonZero::new(1).unwrap();
558 generic_decoder.decoder.as_deref_mut_except().time_base = time_base.into();
559 }
560 let generic_decoder = &*video_decoder;
561 let time_base = generic_decoder.decoder.as_deref_except().time_base;
562
563 assert_eq!(time_base.num, 1000, "Expected time_base.num to be updated via DerefMut");
564 assert_eq!(time_base.den, 1, "Expected time_base.den to be updated via DerefMut");
565 }
566
567 #[test]
568 fn test_audio_decoder_deref_mut() {
569 let input = Input::open(file_path("avc_aac_large.mp4")).expect("Failed to open valid file");
570 let streams = input.streams();
571 let stream = streams
572 .iter()
573 .find(|s| {
574 s.codec_parameters()
575 .map(|p| AVMediaType(p.codec_type) == AVMediaType::Audio)
576 .unwrap_or(false)
577 })
578 .expect("No audio stream found");
579 let decoder_options = DecoderOptions {
580 codec: None,
581 thread_count: 2,
582 };
583 let decoder = Decoder::with_options(&stream, decoder_options).expect("Failed to create Decoder");
584 let mut audio_decoder = match decoder {
585 Decoder::Audio(audio_decoder) => audio_decoder,
586 _ => panic!("Expected an AudioDecoder, got something else"),
587 };
588 {
589 let generic_decoder = &mut *audio_decoder;
590 let mut time_base = generic_decoder.time_base().expect("Failed to get time base of decoder");
591 time_base.numerator = 48000;
592 time_base.denominator = NonZero::new(1).unwrap();
593 generic_decoder.decoder.as_deref_mut_except().time_base = time_base.into();
594 }
595 let generic_decoder = &*audio_decoder;
596 let time_base = generic_decoder.decoder.as_deref_except().time_base;
597
598 assert_eq!(time_base.num, 48000, "Expected time_base.num to be updated via DerefMut");
599 assert_eq!(time_base.den, 1, "Expected time_base.den to be updated via DerefMut");
600 }
601
602 #[test]
603 fn test_decoder_video() {
604 let mut input = Input::open(file_path("avc_aac_large.mp4")).expect("Failed to open valid file");
605 let streams = input.streams();
606 let video_stream = streams.best(AVMediaType::Video).expect("No video stream found");
607 let audio_stream = streams.best(AVMediaType::Audio).expect("No audio stream found");
608 let mut video_decoder = Decoder::new(&video_stream)
609 .expect("Failed to create decoder")
610 .video()
611 .expect("Failed to get video decoder");
612 let mut audio_decoder = Decoder::new(&audio_stream)
613 .expect("Failed to create decoder")
614 .audio()
615 .expect("Failed to get audio decoder");
616 let mut video_frames = Vec::new();
617 let mut audio_frames = Vec::new();
618
619 let video_stream_index = video_stream.index();
620 let audio_stream_index = audio_stream.index();
621
622 while let Some(packet) = input.receive_packet().expect("Failed to receive packet") {
623 if packet.stream_index() == video_stream_index {
624 video_decoder.send_packet(&packet).expect("Failed to send packet");
625 while let Some(frame) = video_decoder.receive_frame().expect("Failed to receive frame") {
626 video_frames.push(frame);
627 }
628 } else if packet.stream_index() == audio_stream_index {
629 audio_decoder.send_packet(&packet).expect("Failed to send packet");
630 while let Some(frame) = audio_decoder.receive_frame().expect("Failed to receive frame") {
631 audio_frames.push(frame);
632 }
633 }
634 }
635
636 video_decoder.send_eof().expect("Failed to send eof");
637 while let Some(frame) = video_decoder.receive_frame().expect("Failed to receive frame") {
638 video_frames.push(frame);
639 }
640
641 audio_decoder.send_eof().expect("Failed to send eof");
642 while let Some(frame) = audio_decoder.receive_frame().expect("Failed to receive frame") {
643 audio_frames.push(frame);
644 }
645
646 insta::assert_debug_snapshot!("test_decoder_video", video_frames);
647 insta::assert_debug_snapshot!("test_decoder_audio", audio_frames);
648 }
649}