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};
310
311 #[test]
312 fn test_generic_decoder_debug() {
313 let valid_file_path = "../../assets/avc_aac_large.mp4";
314 let input = Input::open(valid_file_path).expect("Failed to open valid file");
315 let streams = input.streams();
316 let stream = streams
317 .iter()
318 .find(|s| {
319 s.codec_parameters()
320 .map(|p| AVMediaType(p.codec_type) == AVMediaType::Video)
321 .unwrap_or(false)
322 })
323 .expect("No video stream found");
324 let codec_params = stream.codec_parameters().expect("Missing codec parameters");
325 assert_eq!(
326 AVMediaType(codec_params.codec_type),
327 AVMediaType::Video,
328 "Expected the stream to be a video stream"
329 );
330 let decoder_options = DecoderOptions {
331 codec: Some(DecoderCodec::new(AVCodecID::H264).expect("Failed to find H264 codec")),
332 thread_count: 2,
333 };
334 let decoder = Decoder::with_options(&stream, decoder_options).expect("Failed to create Decoder");
335 let generic_decoder = match decoder {
336 Decoder::Video(video_decoder) => video_decoder.0,
337 Decoder::Audio(audio_decoder) => audio_decoder.0,
338 };
339
340 insta::assert_debug_snapshot!(generic_decoder, @r"
341 Decoder {
342 time_base: Some(
343 Rational {
344 numerator: 1,
345 denominator: 15360,
346 },
347 ),
348 codec_type: AVMediaType::Video,
349 }
350 ");
351 }
352
353 #[test]
354 fn test_video_decoder_debug() {
355 let valid_file_path = "../../assets/avc_aac_large.mp4";
356 let input = Input::open(valid_file_path).expect("Failed to open valid file");
357 let streams = input.streams();
358 let stream = streams
359 .iter()
360 .find(|s| {
361 s.codec_parameters()
362 .map(|p| AVMediaType(p.codec_type) == AVMediaType::Video)
363 .unwrap_or(false)
364 })
365 .expect("No video stream found");
366 let codec_params = stream.codec_parameters().expect("Missing codec parameters");
367 assert_eq!(
368 AVMediaType(codec_params.codec_type),
369 AVMediaType::Video,
370 "Expected the stream to be a video stream"
371 );
372
373 let decoder_options = DecoderOptions {
374 codec: Some(DecoderCodec::new(AVCodecID::H264).expect("Failed to find H264 codec")),
375 thread_count: 2,
376 };
377 let decoder = Decoder::with_options(&stream, decoder_options).expect("Failed to create Decoder");
378
379 let generic_decoder = match decoder {
380 Decoder::Video(video_decoder) => video_decoder,
381 _ => panic!("Expected a video decoder, got something else"),
382 };
383
384 insta::assert_debug_snapshot!(generic_decoder, @r"
385 VideoDecoder {
386 time_base: Some(
387 Rational {
388 numerator: 1,
389 denominator: 15360,
390 },
391 ),
392 width: 3840,
393 height: 2160,
394 pixel_format: AVPixelFormat::Yuv420p,
395 frame_rate: Rational {
396 numerator: 60,
397 denominator: 1,
398 },
399 sample_aspect_ratio: Rational {
400 numerator: 1,
401 denominator: 1,
402 },
403 }
404 ");
405 }
406
407 #[test]
408 fn test_audio_decoder_debug() {
409 let valid_file_path = "../../assets/avc_aac_large.mp4";
410 let input = Input::open(valid_file_path).expect("Failed to open valid file");
411 let streams = input.streams();
412 let stream = streams
413 .iter()
414 .find(|s| {
415 s.codec_parameters()
416 .map(|p| AVMediaType(p.codec_type) == AVMediaType::Audio)
417 .unwrap_or(false)
418 })
419 .expect("No audio stream found");
420 let codec_params = stream.codec_parameters().expect("Missing codec parameters");
421 assert_eq!(
422 AVMediaType(codec_params.codec_type),
423 AVMediaType::Audio,
424 "Expected the stream to be an audio stream"
425 );
426 let decoder_options = DecoderOptions {
427 codec: Some(DecoderCodec::new(AVCodecID::Aac).expect("Failed to find AAC codec")),
428 thread_count: 2,
429 };
430 let decoder = Decoder::with_options(&stream, decoder_options).expect("Failed to create Decoder");
431 let audio_decoder = match decoder {
432 Decoder::Audio(audio_decoder) => audio_decoder,
433 _ => panic!("Expected an audio decoder, got something else"),
434 };
435
436 insta::assert_debug_snapshot!(audio_decoder, @r"
437 AudioDecoder {
438 time_base: Some(
439 Rational {
440 numerator: 1,
441 denominator: 48000,
442 },
443 ),
444 sample_rate: 48000,
445 channels: 2,
446 sample_fmt: AVSampleFormat::Fltp,
447 }
448 ");
449 }
450
451 #[test]
452 fn test_decoder_options_default() {
453 let default_options = DecoderOptions::default();
454
455 assert!(default_options.codec.is_none(), "Expected default codec to be None");
456 assert_eq!(default_options.thread_count, 1, "Expected default thread_count to be 1");
457 }
458
459 #[test]
460 fn test_decoder_new() {
461 let valid_file_path = "../../assets/avc_aac_large.mp4";
462 let input = Input::open(valid_file_path).expect("Failed to open valid file");
463 let streams = input.streams();
464 let stream = streams
465 .iter()
466 .find(|s| {
467 s.codec_parameters()
468 .map(|p| AVMediaType(p.codec_type) == AVMediaType::Video)
469 .unwrap_or(false)
470 })
471 .expect("No video stream found");
472
473 let decoder_result = Decoder::new(&stream);
474 assert!(decoder_result.is_ok(), "Expected Decoder::new to succeed, but it failed");
475
476 let decoder = decoder_result.unwrap();
477 if let Decoder::Video(video_decoder) = decoder {
478 assert_eq!(video_decoder.width(), 3840, "Expected valid width for video stream");
479 assert_eq!(video_decoder.height(), 2160, "Expected valid height for video stream");
480 } else {
481 panic!("Expected a video decoder, but got a different type");
482 }
483 }
484
485 #[test]
486 fn test_decoder_with_options_missing_codec_parameters() {
487 let valid_file_path = "../../assets/avc_aac_large.mp4";
488 let mut input = Input::open(valid_file_path).expect("Failed to open valid file");
489 let mut streams = input.streams_mut();
490 let mut stream = streams.get(0).expect("Expected a valid stream");
491 let codecpar = unsafe { (*stream.as_mut_ptr()).codecpar };
493 unsafe {
495 (*stream.as_mut_ptr()).codecpar = std::ptr::null_mut();
496 }
497 let decoder_result = Decoder::with_options(&stream, DecoderOptions::default());
498 unsafe {
500 (*stream.as_mut_ptr()).codecpar = codecpar;
501 }
502
503 assert!(decoder_result.is_err(), "Expected Decoder creation to fail");
504 if let Err(err) = decoder_result {
505 match err {
506 crate::error::FfmpegError::NoDecoder => (),
507 _ => panic!("Unexpected error type: {err:?}"),
508 }
509 }
510 }
511
512 #[test]
513 fn test_decoder_with_options_non_video_audio_codec_type() {
514 let valid_file_path = "../../assets/avc_aac_large.mp4";
515 let mut input = Input::open(valid_file_path).expect("Failed to open valid file");
516 let mut streams = input.streams_mut();
517 let mut stream = streams.get(0).expect("Expected a valid stream");
518 let codecpar = unsafe { (*stream.as_mut_ptr()).codecpar };
520 unsafe {
522 (*codecpar).codec_type = AVMediaType::Subtitle.into();
523 }
524 let decoder_result = Decoder::with_options(&stream, DecoderOptions::default());
525
526 assert!(
527 decoder_result.is_err(),
528 "Expected Decoder creation to fail for non-video/audio codec type"
529 );
530 if let Err(err) = decoder_result {
531 match err {
532 crate::error::FfmpegError::NoDecoder => (),
533 _ => panic!("Unexpected error type: {err:?}"),
534 }
535 }
536 }
537
538 #[test]
539 fn test_video_decoder_deref_mut_safe() {
540 let valid_file_path = "../../assets/avc_aac_large.mp4";
541 let input = Input::open(valid_file_path).expect("Failed to open valid file");
542 let streams = input.streams();
543 let stream = streams
544 .iter()
545 .find(|s| {
546 s.codec_parameters()
547 .map(|p| AVMediaType(p.codec_type) == AVMediaType::Video)
548 .unwrap_or(false)
549 })
550 .expect("No video stream found");
551 let decoder_options = DecoderOptions {
552 codec: None,
553 thread_count: 2,
554 };
555 let decoder = Decoder::with_options(&stream, decoder_options).expect("Failed to create Decoder");
556 let mut video_decoder = match decoder {
557 Decoder::Video(video_decoder) => video_decoder,
558 _ => panic!("Expected a VideoDecoder, got something else"),
559 };
560 {
561 let generic_decoder = &mut *video_decoder;
562 let mut time_base = generic_decoder.time_base().expect("Failed to get time base of decoder");
563 time_base.numerator = 1000;
564 time_base.denominator = NonZero::new(1).unwrap();
565 generic_decoder.decoder.as_deref_mut_except().time_base = time_base.into();
566 }
567 let generic_decoder = &*video_decoder;
568 let time_base = generic_decoder.decoder.as_deref_except().time_base;
569
570 assert_eq!(time_base.num, 1000, "Expected time_base.num to be updated via DerefMut");
571 assert_eq!(time_base.den, 1, "Expected time_base.den to be updated via DerefMut");
572 }
573
574 #[test]
575 fn test_audio_decoder_deref_mut() {
576 let valid_file_path = "../../assets/avc_aac_large.mp4";
577 let input = Input::open(valid_file_path).expect("Failed to open valid file");
578 let streams = input.streams();
579 let stream = streams
580 .iter()
581 .find(|s| {
582 s.codec_parameters()
583 .map(|p| AVMediaType(p.codec_type) == AVMediaType::Audio)
584 .unwrap_or(false)
585 })
586 .expect("No audio stream found");
587 let decoder_options = DecoderOptions {
588 codec: None,
589 thread_count: 2,
590 };
591 let decoder = Decoder::with_options(&stream, decoder_options).expect("Failed to create Decoder");
592 let mut audio_decoder = match decoder {
593 Decoder::Audio(audio_decoder) => audio_decoder,
594 _ => panic!("Expected an AudioDecoder, got something else"),
595 };
596 {
597 let generic_decoder = &mut *audio_decoder;
598 let mut time_base = generic_decoder.time_base().expect("Failed to get time base of decoder");
599 time_base.numerator = 48000;
600 time_base.denominator = NonZero::new(1).unwrap();
601 generic_decoder.decoder.as_deref_mut_except().time_base = time_base.into();
602 }
603 let generic_decoder = &*audio_decoder;
604 let time_base = generic_decoder.decoder.as_deref_except().time_base;
605
606 assert_eq!(time_base.num, 48000, "Expected time_base.num to be updated via DerefMut");
607 assert_eq!(time_base.den, 1, "Expected time_base.den to be updated via DerefMut");
608 }
609
610 #[test]
611 fn test_decoder_video() {
612 let valid_file_path = "../../assets/avc_aac_large.mp4";
613 let mut input = Input::open(valid_file_path).expect("Failed to open valid file");
614 let streams = input.streams();
615 let video_stream = streams.best(AVMediaType::Video).expect("No video stream found");
616 let audio_stream = streams.best(AVMediaType::Audio).expect("No audio stream found");
617 let mut video_decoder = Decoder::new(&video_stream)
618 .expect("Failed to create decoder")
619 .video()
620 .expect("Failed to get video decoder");
621 let mut audio_decoder = Decoder::new(&audio_stream)
622 .expect("Failed to create decoder")
623 .audio()
624 .expect("Failed to get audio decoder");
625 let mut video_frames = Vec::new();
626 let mut audio_frames = Vec::new();
627
628 let video_stream_index = video_stream.index();
629 let audio_stream_index = audio_stream.index();
630
631 while let Some(packet) = input.receive_packet().expect("Failed to receive packet") {
632 if packet.stream_index() == video_stream_index {
633 video_decoder.send_packet(&packet).expect("Failed to send packet");
634 while let Some(frame) = video_decoder.receive_frame().expect("Failed to receive frame") {
635 video_frames.push(frame);
636 }
637 } else if packet.stream_index() == audio_stream_index {
638 audio_decoder.send_packet(&packet).expect("Failed to send packet");
639 while let Some(frame) = audio_decoder.receive_frame().expect("Failed to receive frame") {
640 audio_frames.push(frame);
641 }
642 }
643 }
644
645 video_decoder.send_eof().expect("Failed to send eof");
646 while let Some(frame) = video_decoder.receive_frame().expect("Failed to receive frame") {
647 video_frames.push(frame);
648 }
649
650 audio_decoder.send_eof().expect("Failed to send eof");
651 while let Some(frame) = audio_decoder.receive_frame().expect("Failed to receive frame") {
652 audio_frames.push(frame);
653 }
654
655 insta::assert_debug_snapshot!("test_decoder_video", video_frames);
656 insta::assert_debug_snapshot!("test_decoder_audio", audio_frames);
657 }
658}