1use std::collections::BTreeMap;
19use std::collections::VecDeque;
20use std::sync::Arc;
21use std::sync::Weak;
22
23use ::ffmpeg::avcodec::*;
24use ::ffmpeg::swscale::*;
25use ::ffmpeg::*;
26use anyhow::anyhow;
27use anyhow::Context;
28use base::error;
29use base::info;
30use base::warn;
31use base::MappedRegion;
32use base::MemoryMappingArena;
33use thiserror::Error as ThisError;
34
35use crate::virtio::video::decoder::backend::*;
36use crate::virtio::video::ffmpeg::GuestResourceToAvFrameError;
37use crate::virtio::video::ffmpeg::MemoryMappingAvBufferSource;
38use crate::virtio::video::ffmpeg::TryAsAvFrameExt;
39use crate::virtio::video::format::FormatDesc;
40use crate::virtio::video::format::FormatRange;
41use crate::virtio::video::format::FrameFormat;
42use crate::virtio::video::format::Level;
43use crate::virtio::video::format::Profile;
44use crate::virtio::video::resource::BufferHandle;
45use crate::virtio::video::resource::GuestResource;
46use crate::virtio::video::resource::GuestResourceHandle;
47use crate::virtio::video::utils::EventQueue;
48use crate::virtio::video::utils::OutputQueue;
49use crate::virtio::video::utils::SyncEventQueue;
50
51struct InputBuffer {
54 mapping: MemoryMappingArena,
56 resource_id: u32,
58 event_queue: Weak<SyncEventQueue<DecoderEvent>>,
61}
62
63impl Drop for InputBuffer {
64 fn drop(&mut self) {
65 match self.event_queue.upgrade() {
66 None => (),
67 Some(event_queue) => event_queue
69 .queue_event(DecoderEvent::NotifyEndOfBitstreamBuffer(self.resource_id))
70 .unwrap_or_else(|e| {
71 error!("cannot send end of input buffer notification: {:#}", e)
72 }),
73 }
74 }
75}
76
77impl AvBufferSource for InputBuffer {
78 fn as_ptr(&self) -> *const u8 {
79 self.mapping.as_ptr()
80 }
81
82 fn len(&self) -> usize {
83 self.mapping.size()
84 }
85
86 fn is_empty(&self) -> bool {
87 self.len() == 0
88 }
89}
90
91enum CodecJob {
93 Packet(AvPacket<'static>),
94 Flush,
95}
96
97enum SessionState {
101 AwaitingInitialResolution,
103 AwaitingBufferCount,
105 Decoding {
107 output_queue: OutputQueue,
108 format_converter: SwConverter,
109 },
110 Drc,
113}
114
115pub struct FfmpegDecoderSession {
117 event_queue: Arc<SyncEventQueue<DecoderEvent>>,
119
120 codec_jobs: VecDeque<CodecJob>,
122 is_flushing: bool,
124
125 state: SessionState,
127 current_visible_res: (usize, usize),
129
130 context: AvCodecContext,
132 avframe: Option<AvFrame>,
135}
136
137#[derive(Debug, ThisError)]
138enum TrySendFrameError {
139 #[error("error while converting frame: {0}")]
140 CannotConvertFrame(#[from] ConversionError),
141 #[error("error while constructing AvFrame: {0}")]
142 IntoAvFrame(#[from] GuestResourceToAvFrameError),
143 #[error("error while sending picture ready event: {0}")]
144 BrokenPipe(#[from] base::Error),
145}
146
147#[derive(Debug, ThisError)]
148enum TryReceiveFrameError {
149 #[error("error creating AvFrame: {0}")]
150 CreateAvFrame(#[from] AvFrameError),
151 #[error("error queueing flush completed event: {0}")]
152 CannotQueueFlushEvent(#[from] base::Error),
153 #[error("error while changing resolution: {0}")]
154 ChangeResolutionError(#[from] ChangeResolutionError),
155}
156
157#[derive(Debug, ThisError)]
158enum TrySendPacketError {
159 #[error("error while sending input packet to libavcodec: {0}")]
160 AvError(#[from] AvError),
161}
162
163#[derive(Debug, ThisError)]
164enum TryDecodeError {
165 #[error("error while sending packet: {0}")]
166 SendPacket(#[from] TrySendPacketError),
167 #[error("error while trying to send decoded frame: {0}")]
168 SendFrameError(#[from] TrySendFrameError),
169 #[error("error while receiving frame: {0}")]
170 ReceiveFrame(#[from] TryReceiveFrameError),
171}
172
173#[derive(Debug, ThisError)]
174enum ChangeResolutionError {
175 #[error("error queueing event: {0}")]
176 QueueEventFailed(#[from] base::Error),
177 #[error("unexpected state during resolution change")]
178 UnexpectedState,
179}
180
181impl FfmpegDecoderSession {
182 fn queue_event(&mut self, event: DecoderEvent) -> base::Result<()> {
184 self.event_queue.queue_event(event)
185 }
186
187 fn change_resolution(
189 &mut self,
190 new_visible_res: (usize, usize),
191 ) -> Result<(), ChangeResolutionError> {
192 info!("resolution changed to {:?}", new_visible_res);
193
194 self.queue_event(DecoderEvent::ProvidePictureBuffers {
196 min_num_buffers: std::cmp::max(self.context.as_ref().refs, 0) as u32 + 1,
197 width: new_visible_res.0 as i32,
198 height: new_visible_res.1 as i32,
199 visible_rect: Rect {
200 left: 0,
201 top: 0,
202 right: new_visible_res.0 as i32,
203 bottom: new_visible_res.1 as i32,
204 },
205 })?;
206
207 self.current_visible_res = new_visible_res;
208
209 self.state = match self.state {
211 SessionState::AwaitingInitialResolution => SessionState::AwaitingBufferCount,
212 SessionState::Decoding { .. } => SessionState::Drc,
213 _ => return Err(ChangeResolutionError::UnexpectedState),
214 };
215
216 Ok(())
217 }
218
219 fn try_send_packet(
225 &mut self,
226 input_packet: &AvPacket<'static>,
227 ) -> Result<bool, TrySendPacketError> {
228 match self.context.try_send_packet(input_packet) {
229 Ok(true) => Ok(true),
230 Ok(false) => Ok(false),
233 Err(AvError(AVERROR_EOF)) => Ok(false),
235 Err(AvError(AVERROR_INVALIDDATA)) => {
237 warn!("Invalid data in stream, ignoring...");
238 Ok(true)
239 }
240 Err(e) => Err(e.into()),
241 }
242 }
243
244 fn try_send_input_job(&mut self) -> Result<bool, TrySendPacketError> {
250 if self.is_flushing {
252 return Ok(false);
253 }
254
255 let mut next_job = match self.codec_jobs.pop_front() {
256 None => return Ok(false),
258 Some(job) => job,
259 };
260
261 match &mut next_job {
262 CodecJob::Packet(input_packet) => {
263 let res = self.try_send_packet(input_packet)?;
264 match res {
265 true => drop(next_job),
267 false => self.codec_jobs.push_front(next_job),
269 }
270
271 Ok(res)
272 }
273 CodecJob::Flush => {
274 self.is_flushing = true;
279
280 Ok(true)
281 }
282 }
283 }
284
285 fn try_receive_frame(&mut self) -> Result<bool, TryReceiveFrameError> {
292 let mut avframe = match self.avframe {
293 Some(_) => return Ok(false),
295 None => AvFrame::new()?,
296 };
297
298 match self.context.try_receive_frame(&mut avframe) {
299 Ok(TryReceiveResult::Received) => {
300 let new_visible_res = (avframe.width as usize, avframe.height as usize);
302 if new_visible_res != self.current_visible_res {
303 self.change_resolution(new_visible_res)?;
304 }
305
306 self.avframe = Some(avframe);
307
308 Ok(true)
309 }
310 Ok(TryReceiveResult::TryAgain) => {
311 if self.is_flushing {
312 match self.context.flush_decoder() {
316 Ok(()) => self.try_receive_frame(),
318 Err(err) => {
319 self.is_flushing = false;
320 self.queue_event(DecoderEvent::FlushCompleted(Err(
321 VideoError::BackendFailure(err.into()),
322 )))?;
323 Ok(false)
324 }
325 }
326 } else {
327 Ok(false)
329 }
330 }
331 Ok(TryReceiveResult::FlushCompleted) => {
332 self.is_flushing = false;
333 self.queue_event(DecoderEvent::FlushCompleted(Ok(())))?;
334 self.context.reset();
335 Ok(false)
336 }
337 Err(AvError(AVERROR_INVALIDDATA)) => {
339 warn!("Invalid data in stream, ignoring...");
340 Ok(false)
341 }
342 Err(av_err) => {
343 if let Err(e) = self.event_queue.queue_event(DecoderEvent::NotifyError(
346 VideoError::BackendFailure(av_err.into()),
347 )) {
348 error!("failed to notify error: {}", e);
349 }
350 Ok(false)
351 }
352 }
353 }
354
355 fn try_send_frame(&mut self) -> Result<bool, TrySendFrameError> {
364 let (output_queue, format_converter) = match &mut self.state {
365 SessionState::Decoding {
366 output_queue,
367 format_converter,
368 } => (output_queue, format_converter),
369 _ => return Ok(false),
371 };
372
373 let avframe = match self.avframe.take() {
374 None => return Ok(false),
376 Some(avframe) => avframe,
377 };
378
379 let (picture_buffer_id, target_buffer) = match output_queue.try_get_ready_buffer() {
380 None => {
381 self.avframe = Some(avframe);
383 return Ok(false);
384 }
385 Some(buffer) => buffer,
386 };
387
388 let picture_ready_event = DecoderEvent::PictureReady {
391 picture_buffer_id: picture_buffer_id as i32,
392 timestamp: avframe.pts as u64,
393 };
394
395 format_converter.convert(
397 &avframe,
398 &mut target_buffer.try_as_av_frame(MemoryMappingAvBufferSource::from)?,
399 )?;
400 self.event_queue.queue_event(picture_ready_event)?;
401
402 Ok(true)
403 }
404
405 fn try_decode(&mut self) -> Result<(), TryDecodeError> {
411 while self.try_send_frame()? || self.try_receive_frame()? || self.try_send_input_job()? {}
413
414 Ok(())
415 }
416}
417
418impl DecoderSession for FfmpegDecoderSession {
419 fn set_output_parameters(&mut self, buffer_count: usize, format: Format) -> VideoResult<()> {
420 match self.state {
421 SessionState::AwaitingInitialResolution => Ok(()),
424 SessionState::AwaitingBufferCount | SessionState::Drc => {
425 let avcontext = self.context.as_ref();
426
427 let dst_pix_format: AvPixelFormat =
428 format.try_into().map_err(|_| VideoError::InvalidFormat)?;
429
430 self.state = SessionState::Decoding {
431 output_queue: OutputQueue::new(buffer_count),
432 format_converter: SwConverter::new(
433 avcontext.width as usize,
434 avcontext.height as usize,
435 avcontext.pix_fmt,
436 dst_pix_format.pix_fmt(),
437 )
438 .context("while setting output parameters")
439 .map_err(VideoError::BackendFailure)?,
440 };
441 Ok(())
442 }
443 _ => Err(VideoError::BackendFailure(anyhow!(
444 "invalid state while calling set_output_parameters"
445 ))),
446 }
447 }
448
449 fn decode(
450 &mut self,
451 resource_id: u32,
452 timestamp: u64,
453 resource: GuestResourceHandle,
454 offset: u32,
455 bytes_used: u32,
456 ) -> VideoResult<()> {
457 let input_buffer = InputBuffer {
458 mapping: resource
459 .get_mapping(offset as usize, bytes_used as usize)
460 .context("while mapping input buffer")
461 .map_err(VideoError::BackendFailure)?,
462 resource_id,
463 event_queue: Arc::downgrade(&self.event_queue),
464 };
465
466 let avbuffer = AvBuffer::new(input_buffer)
467 .context("while creating AvPacket")
468 .map_err(VideoError::BackendFailure)?;
469
470 let avpacket = AvPacket::new_owned(timestamp as i64, avbuffer);
471
472 self.codec_jobs.push_back(CodecJob::Packet(avpacket));
473
474 self.try_decode()
475 .context("while decoding")
476 .map_err(VideoError::BackendFailure)
477 }
478
479 fn flush(&mut self) -> VideoResult<()> {
480 if self.is_flushing {
481 Err(VideoError::BackendFailure(anyhow!(
482 "flush is already in progress"
483 )))
484 } else {
485 self.codec_jobs.push_back(CodecJob::Flush);
486 self.try_decode()
487 .context("while flushing")
488 .map_err(VideoError::BackendFailure)
489 }
490 }
491
492 fn reset(&mut self) -> VideoResult<()> {
493 self.context.reset();
495
496 self.codec_jobs.clear();
498
499 self.clear_output_buffers()?;
501
502 self.queue_event(DecoderEvent::ResetCompleted(Ok(())))
503 .context("while resetting")
504 .map_err(VideoError::BackendFailure)
505 }
506
507 fn clear_output_buffers(&mut self) -> VideoResult<()> {
508 self.is_flushing = false;
510
511 if let SessionState::Decoding { output_queue, .. } = &mut self.state {
513 output_queue.clear_ready_buffers();
514 }
515
516 self.avframe = None;
518
519 self.event_queue.retain(|event| {
521 !matches!(
522 event,
523 DecoderEvent::PictureReady { .. } | DecoderEvent::FlushCompleted(_)
524 )
525 });
526
527 Ok(())
528 }
529
530 fn event_pipe(&self) -> &dyn AsRawDescriptor {
531 self.event_queue.as_ref()
532 }
533
534 fn use_output_buffer(
535 &mut self,
536 picture_buffer_id: i32,
537 resource: GuestResource,
538 ) -> VideoResult<()> {
539 let output_queue = match &mut self.state {
540 SessionState::AwaitingInitialResolution => return Ok(()),
543 SessionState::Decoding { output_queue, .. } => output_queue,
544 SessionState::Drc => return Ok(()),
546 _ => {
547 error!("use_output_buffer: invalid state");
548 return Ok(());
549 }
550 };
551
552 output_queue
553 .import_buffer(picture_buffer_id as u32, resource)
554 .context("while importing output buffer")
555 .map_err(VideoError::BackendFailure)?;
556 self.try_decode()
557 .context("while decoding output buffer")
558 .map_err(VideoError::BackendFailure)
559 }
560
561 fn reuse_output_buffer(&mut self, picture_buffer_id: i32) -> VideoResult<()> {
562 let output_queue = match &mut self.state {
563 SessionState::AwaitingInitialResolution => return Ok(()),
566 SessionState::Decoding { output_queue, .. } => output_queue,
567 SessionState::Drc => return Ok(()),
569 _ => {
570 return Err(VideoError::BackendFailure(anyhow!(
571 "invalid state while calling reuse_output_buffer"
572 )))
573 }
574 };
575
576 output_queue
577 .reuse_buffer(picture_buffer_id as u32)
578 .context("while reusing output buffer")
579 .map_err(VideoError::BackendFailure)?;
580 self.try_decode()
581 .context("while reusing output buffer")
582 .map_err(VideoError::BackendFailure)
583 }
584
585 fn read_event(&mut self) -> VideoResult<DecoderEvent> {
586 self.event_queue
587 .dequeue_event()
588 .context("while reading decoder event")
589 .map_err(VideoError::BackendFailure)
590 }
591}
592
593pub struct FfmpegDecoder {
594 codecs: BTreeMap<Format, AvCodec>,
595}
596
597impl FfmpegDecoder {
598 pub fn new() -> Self {
600 let codecs = AvCodecIterator::new()
602 .filter_map(|codec| {
603 if !codec.is_decoder() {
604 return None;
605 }
606
607 let codec_name = codec.name();
608
609 let format = match codec_name {
613 "h264" => Format::H264,
614 "vp8" => Format::VP8,
615 "vp9" => Format::VP9,
616 "hevc" => Format::Hevc,
617 _ => return None,
618 };
619
620 if codec.capabilities() & AV_CODEC_CAP_DR1 == 0 {
623 warn!(
624 "Skipping codec {} due to lack of DR1 capability.",
625 codec_name
626 );
627 return None;
628 }
629
630 Some((format, codec))
631 })
632 .collect();
633
634 Self { codecs }
635 }
636}
637
638impl DecoderBackend for FfmpegDecoder {
639 type Session = FfmpegDecoderSession;
640
641 fn get_capabilities(&self) -> Capability {
642 const SUPPORTED_OUTPUT_FORMATS: [Format; 1] = [Format::NV12];
644
645 let mut in_formats = vec![];
646 let mut profiles_map: BTreeMap<Format, Vec<Profile>> = Default::default();
647 let mut levels: BTreeMap<Format, Vec<Level>> = Default::default();
648 for (&format, codec) in &self.codecs {
649 let profile_iter = codec.profile_iter();
650 let profiles = match format {
651 Format::H264 => {
652 levels.insert(format, vec![Level::H264_1_0]);
655
656 profile_iter
657 .filter_map(|p| {
658 match p.profile() {
659 FF_PROFILE_H264_BASELINE => Some(Profile::H264Baseline),
660 FF_PROFILE_H264_MAIN => Some(Profile::H264Main),
661 FF_PROFILE_H264_EXTENDED => Some(Profile::H264Extended),
662 FF_PROFILE_H264_HIGH => Some(Profile::H264High),
663 FF_PROFILE_H264_HIGH_10 => Some(Profile::H264High10),
664 FF_PROFILE_H264_HIGH_422 => Some(Profile::H264High422),
665 FF_PROFILE_H264_HIGH_444_PREDICTIVE => {
666 Some(Profile::H264High444PredictiveProfile)
667 }
668 FF_PROFILE_H264_STEREO_HIGH => Some(Profile::H264StereoHigh),
669 FF_PROFILE_H264_MULTIVIEW_HIGH => Some(Profile::H264MultiviewHigh),
670 _ => None,
673 }
674 })
675 .collect()
676 }
677 Format::VP8 => {
678 vec![
680 Profile::VP8Profile0,
681 Profile::VP8Profile1,
682 Profile::VP8Profile2,
683 Profile::VP8Profile3,
684 ]
685 }
686 Format::VP9 => profile_iter
687 .filter_map(|p| match p.profile() {
688 FF_PROFILE_VP9_0 => Some(Profile::VP9Profile0),
689 FF_PROFILE_VP9_1 => Some(Profile::VP9Profile1),
690 FF_PROFILE_VP9_2 => Some(Profile::VP9Profile2),
691 FF_PROFILE_VP9_3 => Some(Profile::VP9Profile3),
692 _ => None,
693 })
694 .collect(),
695 Format::Hevc => profile_iter
696 .filter_map(|p| match p.profile() {
697 FF_PROFILE_HEVC_MAIN => Some(Profile::HevcMain),
698 FF_PROFILE_HEVC_MAIN_10 => Some(Profile::HevcMain10),
699 FF_PROFILE_HEVC_MAIN_STILL_PICTURE => Some(Profile::HevcMainStillPicture),
700 _ => None,
701 })
702 .collect(),
703 _ => unreachable!("Unhandled format {:?}", format),
704 };
705
706 profiles_map.insert(format, profiles);
707
708 in_formats.push(FormatDesc {
709 mask: !(u64::MAX << SUPPORTED_OUTPUT_FORMATS.len()),
710 format,
711 frame_formats: vec![FrameFormat {
712 width: FormatRange {
716 min: 64,
717 max: 16384,
718 step: 1,
719 },
720 height: FormatRange {
721 min: 64,
722 max: 16384,
723 step: 1,
724 },
725 bitrates: Default::default(),
726 }],
727 plane_align: max_buffer_alignment() as u32,
728 });
729 }
730
731 let out_formats = SUPPORTED_OUTPUT_FORMATS
733 .iter()
734 .map(|&format| FormatDesc {
735 mask: !(u64::MAX << in_formats.len()),
736 format,
737 frame_formats: vec![FrameFormat {
738 width: FormatRange {
742 min: 64,
743 max: 16384,
744 step: 1,
745 },
746 height: FormatRange {
747 min: 64,
748 max: 16384,
749 step: 1,
750 },
751 bitrates: Default::default(),
752 }],
753 plane_align: max_buffer_alignment() as u32,
754 })
755 .collect::<Vec<_>>();
756
757 Capability::new(in_formats, out_formats, profiles_map, levels)
758 }
759
760 fn new_session(&mut self, format: Format) -> VideoResult<Self::Session> {
761 let codec = self.codecs.get(&format).ok_or(VideoError::InvalidFormat)?;
762 let context = codec
763 .build_decoder()
767 .and_then(|b| b.build())
768 .context("while creating new session")
769 .map_err(VideoError::BackendFailure)?;
770 Ok(FfmpegDecoderSession {
771 codec_jobs: Default::default(),
772 is_flushing: false,
773 state: SessionState::AwaitingInitialResolution,
774 event_queue: Arc::new(
775 EventQueue::new()
776 .context("while creating decoder session")
777 .map_err(VideoError::BackendFailure)?
778 .into(),
779 ),
780 context,
781 current_visible_res: (0, 0),
782 avframe: None,
783 })
784 }
785}
786
787#[cfg(test)]
788mod tests {
789 use super::super::tests::*;
790 use super::*;
791
792 #[test]
793 fn test_get_capabilities() {
794 let decoder = FfmpegDecoder::new();
795 let caps = decoder.get_capabilities();
796 assert!(!caps.input_formats().is_empty());
797 assert!(!caps.output_formats().is_empty());
798 }
799
800 #[test]
801 fn test_decode_h264_guestmem_to_guestmem() {
802 decode_h264_generic(
803 &mut FfmpegDecoder::new(),
804 build_guest_mem_handle,
805 build_guest_mem_handle,
806 );
807 }
808
809 #[test]
811 fn test_decode_h264_guestmem_to_object() {
812 decode_h264_generic(
813 &mut FfmpegDecoder::new(),
814 build_guest_mem_handle,
815 build_object_handle,
816 );
817 }
818
819 #[test]
821 fn test_decode_h264_object_to_guestmem() {
822 decode_h264_generic(
823 &mut FfmpegDecoder::new(),
824 build_object_handle,
825 build_guest_mem_handle,
826 );
827 }
828
829 #[test]
831 fn test_decode_h264_object_to_object() {
832 decode_h264_generic(
833 &mut FfmpegDecoder::new(),
834 build_object_handle,
835 build_object_handle,
836 );
837 }
838}