1use std::collections::btree_map::Entry;
8use std::collections::BTreeMap;
9use std::collections::BTreeSet;
10use std::collections::VecDeque;
11
12pub use backend::DecoderBackend;
13use backend::*;
14use base::error;
15use base::AsRawDescriptor;
16use base::Descriptor;
17use base::SafeDescriptor;
18use base::Tube;
19use base::WaitContext;
20use vm_memory::GuestMemory;
21
22use crate::virtio::video::async_cmd_desc_map::AsyncCmdDescMap;
23use crate::virtio::video::command::QueueType;
24use crate::virtio::video::command::VideoCmd;
25use crate::virtio::video::control::CtrlType;
26use crate::virtio::video::control::CtrlVal;
27use crate::virtio::video::control::QueryCtrlType;
28use crate::virtio::video::device::*;
29use crate::virtio::video::error::*;
30use crate::virtio::video::event::*;
31use crate::virtio::video::format::*;
32use crate::virtio::video::params::Params;
33use crate::virtio::video::protocol;
34use crate::virtio::video::resource::*;
35use crate::virtio::video::response::CmdResponse;
36
37pub mod backend;
38pub mod capability;
39
40use capability::*;
41
42type StreamId = u32;
43type ResourceId = u32;
44
45type InputResourceId = u32;
47type OutputResourceId = u32;
48
49type FrameBufferId = i32;
55
56enum QueueOutputResourceResult {
58 UsingAsEos, Reused(FrameBufferId), Registered(FrameBufferId), }
62
63struct InputResource {
64 resource: GuestResource,
66 offset: u32,
68}
69
70type InputResources = BTreeMap<InputResourceId, InputResource>;
72
73#[derive(Default)]
74struct OutputResources {
75 res_id_to_frame_buf_id: BTreeMap<OutputResourceId, FrameBufferId>,
77 frame_buf_id_to_res_id: BTreeMap<FrameBufferId, OutputResourceId>,
78
79 queued_res_ids: BTreeSet<OutputResourceId>,
81
82 eos_resource_id: Option<OutputResourceId>,
87
88 output_params_set: bool,
95
96 res_id_to_res_handle: BTreeMap<OutputResourceId, GuestResource>,
98
99 res_id_to_descriptor: BTreeMap<OutputResourceId, SafeDescriptor>,
102}
103
104impl OutputResources {
105 fn queue_resource(
106 &mut self,
107 resource_id: OutputResourceId,
108 ) -> VideoResult<QueueOutputResourceResult> {
109 if !self.queued_res_ids.insert(resource_id) {
110 error!("resource_id {} is already queued", resource_id);
111 return Err(VideoError::InvalidParameter);
112 }
113
114 if *self.eos_resource_id.get_or_insert(resource_id) == resource_id {
120 return Ok(QueueOutputResourceResult::UsingAsEos);
121 }
122
123 Ok(match self.res_id_to_frame_buf_id.entry(resource_id) {
124 Entry::Occupied(e) => QueueOutputResourceResult::Reused(*e.get()),
125 Entry::Vacant(_) => {
126 let buffer_id = self.res_id_to_frame_buf_id.len() as FrameBufferId;
127 self.res_id_to_frame_buf_id.insert(resource_id, buffer_id);
128 self.frame_buf_id_to_res_id.insert(buffer_id, resource_id);
129 QueueOutputResourceResult::Registered(buffer_id)
130 }
131 })
132 }
133
134 fn dequeue_frame_buffer(
135 &mut self,
136 buffer_id: FrameBufferId,
137 stream_id: StreamId,
138 ) -> Option<ResourceId> {
139 let resource_id = match self.frame_buf_id_to_res_id.get(&buffer_id) {
140 Some(id) => *id,
141 None => {
142 error!(
143 "unknown frame buffer id {} for stream {}",
144 buffer_id, stream_id
145 );
146 return None;
147 }
148 };
149
150 self.queued_res_ids.take(&resource_id).or_else(|| {
151 error!(
152 "resource_id {} is not enqueued for stream {}",
153 resource_id, stream_id
154 );
155 None
156 })
157 }
158
159 fn dequeue_eos_resource_id(&mut self) -> Option<OutputResourceId> {
160 self.queued_res_ids.take(&self.eos_resource_id?)
161 }
162
163 fn output_params_set(&mut self) -> bool {
164 if !self.output_params_set {
165 self.output_params_set = true;
166 return true;
167 }
168 false
169 }
170}
171
172enum PendingResponse {
173 PictureReady {
174 picture_buffer_id: i32,
175 timestamp: u64,
176 },
177 FlushCompleted,
178 BufferBarrier(Descriptor),
180 PollingBufferBarrier(Descriptor),
182}
183
184struct Context<S: DecoderSession> {
187 stream_id: StreamId,
188
189 in_params: Params,
190 out_params: Params,
191
192 in_res: InputResources,
193 out_res: OutputResources,
194
195 is_resetting: bool,
197
198 pending_responses: VecDeque<PendingResponse>,
199
200 session: Option<S>,
201}
202
203impl<S: DecoderSession> Context<S> {
204 fn new(
205 stream_id: StreamId,
206 format: Format,
207 in_resource_type: ResourceType,
208 out_resource_type: ResourceType,
209 ) -> Self {
210 const DEFAULT_WIDTH: u32 = 640;
211 const DEFAULT_HEIGHT: u32 = 480;
212 const DEFAULT_INPUT_BUFFER_SIZE: u32 = 1024 * 1024;
213
214 let out_plane_formats =
215 PlaneFormat::get_plane_layout(Format::NV12, DEFAULT_WIDTH, DEFAULT_HEIGHT).unwrap();
216
217 Context {
218 stream_id,
219 in_params: Params {
220 format: Some(format),
221 frame_width: DEFAULT_WIDTH,
222 frame_height: DEFAULT_HEIGHT,
223 resource_type: in_resource_type,
224 min_buffers: 1,
225 max_buffers: 32,
226 plane_formats: vec![PlaneFormat {
227 plane_size: DEFAULT_INPUT_BUFFER_SIZE,
228 ..Default::default()
229 }],
230 ..Default::default()
231 },
232 out_params: Params {
233 format: Some(Format::NV12),
234 frame_width: DEFAULT_WIDTH,
235 frame_height: DEFAULT_HEIGHT,
236 resource_type: out_resource_type,
237 plane_formats: out_plane_formats,
238 ..Default::default()
239 },
240 in_res: Default::default(),
241 out_res: Default::default(),
242 is_resetting: false,
243 pending_responses: Default::default(),
244 session: None,
245 }
246 }
247
248 fn output_pending_responses(
249 &mut self,
250 wait_ctx: &WaitContext<Token>,
251 ) -> Vec<VideoEvtResponseType> {
252 let mut event_responses = vec![];
253 while let Some(mut responses) = self.output_pending_response() {
254 event_responses.append(&mut responses);
255 }
256
257 if let Some(PendingResponse::BufferBarrier(desc)) = self.pending_responses.front() {
259 let desc = Descriptor(desc.as_raw_descriptor());
260 self.pending_responses.pop_front();
261 match wait_ctx.add(&desc, Token::BufferBarrier { id: self.stream_id }) {
262 Ok(()) => self
263 .pending_responses
264 .push_front(PendingResponse::PollingBufferBarrier(desc)),
265 Err(e) => {
266 error!("failed to add buffer FD to wait context, returning uncompleted buffer: {:#}", e)
267 }
268 }
269 }
270
271 event_responses
272 }
273
274 fn output_pending_response(&mut self) -> Option<Vec<VideoEvtResponseType>> {
275 let responses = match self.pending_responses.front()? {
276 PendingResponse::BufferBarrier(_) | PendingResponse::PollingBufferBarrier(_) => {
277 return None
278 }
279 PendingResponse::PictureReady {
280 picture_buffer_id,
281 timestamp,
282 } => {
283 let resource_id = self
284 .out_res
285 .dequeue_frame_buffer(*picture_buffer_id, self.stream_id)?;
286
287 vec![VideoEvtResponseType::AsyncCmd(
288 AsyncCmdResponse::from_response(
289 AsyncCmdTag::Queue {
290 stream_id: self.stream_id,
291 queue_type: QueueType::Output,
292 resource_id,
293 },
294 CmdResponse::ResourceQueue {
295 timestamp: *timestamp,
296 flags: 0,
298 size: 0,
300 },
301 ),
302 )]
303 }
304 PendingResponse::FlushCompleted => {
305 let eos_resource_id = self.out_res.dequeue_eos_resource_id()?;
306 let eos_tag = AsyncCmdTag::Queue {
307 stream_id: self.stream_id,
308 queue_type: QueueType::Output,
309 resource_id: eos_resource_id,
310 };
311 let eos_response = CmdResponse::ResourceQueue {
312 timestamp: 0,
313 flags: protocol::VIRTIO_VIDEO_BUFFER_FLAG_EOS,
314 size: 0,
315 };
316 vec![
317 VideoEvtResponseType::AsyncCmd(AsyncCmdResponse::from_response(
318 eos_tag,
319 eos_response,
320 )),
321 VideoEvtResponseType::AsyncCmd(AsyncCmdResponse::from_response(
322 AsyncCmdTag::Drain {
323 stream_id: self.stream_id,
324 },
325 CmdResponse::NoData,
326 )),
327 ]
328 }
329 };
330 self.pending_responses.pop_front().unwrap();
331
332 Some(responses)
333 }
334
335 fn register_resource(
336 &mut self,
337 queue_type: QueueType,
338 resource_id: u32,
339 resource: GuestResource,
340 offset: u32,
341 ) {
342 match queue_type {
343 QueueType::Input => {
344 self.in_res
345 .insert(resource_id, InputResource { resource, offset });
346 }
347 QueueType::Output => {
348 self.out_res
349 .res_id_to_res_handle
350 .insert(resource_id, resource);
351 }
352 };
353 }
354
355 fn handle_provide_picture_buffers(
360 &mut self,
361 min_num_buffers: u32,
362 width: i32,
363 height: i32,
364 visible_rect: Rect,
365 ) {
366 let format = Some(Format::NV12);
368
369 let plane_formats =
370 PlaneFormat::get_plane_layout(Format::NV12, width as u32, height as u32).unwrap();
371
372 self.in_params.frame_width = width as u32;
373 self.in_params.frame_height = height as u32;
374
375 self.out_params = Params {
376 format,
377 resource_type: self.out_params.resource_type,
379 frame_width: width as u32,
381 frame_height: height as u32,
382 min_buffers: min_num_buffers + 1,
384 max_buffers: 32,
385 crop: Crop {
386 left: visible_rect.left as u32,
387 top: visible_rect.top as u32,
388 width: (visible_rect.right - visible_rect.left) as u32,
389 height: (visible_rect.bottom - visible_rect.top) as u32,
390 },
391 plane_formats,
392 ..Default::default()
394 };
395 }
396}
397
398struct ContextMap<S: DecoderSession> {
400 map: BTreeMap<StreamId, Context<S>>,
401}
402
403impl<S: DecoderSession> ContextMap<S> {
404 fn insert(&mut self, ctx: Context<S>) -> VideoResult<()> {
405 match self.map.entry(ctx.stream_id) {
406 Entry::Vacant(e) => {
407 e.insert(ctx);
408 Ok(())
409 }
410 Entry::Occupied(_) => {
411 error!("session {} already exists", ctx.stream_id);
412 Err(VideoError::InvalidStreamId(ctx.stream_id))
413 }
414 }
415 }
416
417 fn get(&self, stream_id: &StreamId) -> VideoResult<&Context<S>> {
418 self.map.get(stream_id).ok_or_else(|| {
419 error!("failed to get context of stream {}", *stream_id);
420 VideoError::InvalidStreamId(*stream_id)
421 })
422 }
423
424 fn get_mut(&mut self, stream_id: &StreamId) -> VideoResult<&mut Context<S>> {
425 self.map.get_mut(stream_id).ok_or_else(|| {
426 error!("failed to get context of stream {}", *stream_id);
427 VideoError::InvalidStreamId(*stream_id)
428 })
429 }
430}
431
432impl<S: DecoderSession> Default for ContextMap<S> {
433 fn default() -> Self {
434 Self {
435 map: Default::default(),
436 }
437 }
438}
439
440pub struct Decoder<D: DecoderBackend> {
442 decoder: D,
443 capability: Capability,
444 contexts: ContextMap<D::Session>,
445 resource_bridge: Tube,
446 mem: GuestMemory,
447}
448
449impl<D: DecoderBackend> Decoder<D> {
450 pub fn new(backend: D, resource_bridge: Tube, mem: GuestMemory) -> Self {
452 let capability = backend.get_capabilities();
453
454 Self {
455 decoder: backend,
456 capability,
457 contexts: Default::default(),
458 resource_bridge,
459 mem,
460 }
461 }
462
463 fn query_capabilities(&self, queue_type: QueueType) -> CmdResponse {
468 let descs = match queue_type {
469 QueueType::Input => self.capability.input_formats().clone(),
470 QueueType::Output => self.capability.output_formats().clone(),
471 };
472
473 CmdResponse::QueryCapability(descs)
474 }
475
476 fn create_stream(
477 &mut self,
478 stream_id: StreamId,
479 coded_format: Format,
480 input_resource_type: ResourceType,
481 output_resource_type: ResourceType,
482 ) -> VideoResult<VideoCmdResponseType> {
483 self.contexts.insert(Context::new(
488 stream_id,
489 coded_format,
490 input_resource_type,
491 output_resource_type,
492 ))?;
493 Ok(VideoCmdResponseType::Sync(CmdResponse::NoData))
494 }
495
496 fn destroy_stream(&mut self, stream_id: StreamId) {
497 if self.contexts.map.remove(&stream_id).is_none() {
498 error!("Tried to destroy an invalid stream context {}", stream_id);
499 }
500 }
501
502 fn create_session(
503 decoder: &mut D,
504 wait_ctx: &WaitContext<Token>,
505 ctx: &Context<D::Session>,
506 stream_id: StreamId,
507 ) -> VideoResult<D::Session> {
508 let format = match ctx.in_params.format {
509 Some(f) => f,
510 None => {
511 error!("bitstream format is not specified");
512 return Err(VideoError::InvalidParameter);
513 }
514 };
515
516 let session = decoder.new_session(format)?;
517
518 wait_ctx
519 .add(session.event_pipe(), Token::Event { id: stream_id })
520 .map_err(|e| {
521 error!(
522 "failed to add FD to poll context for session {}: {}",
523 stream_id, e
524 );
525 VideoError::InvalidOperation
526 })?;
527
528 Ok(session)
529 }
530
531 fn create_resource(
532 &mut self,
533 wait_ctx: &WaitContext<Token>,
534 stream_id: StreamId,
535 queue_type: QueueType,
536 resource_id: ResourceId,
537 plane_offsets: Vec<u32>,
538 plane_entries: Vec<Vec<UnresolvedResourceEntry>>,
539 ) -> VideoResult<VideoCmdResponseType> {
540 let ctx = self.contexts.get_mut(&stream_id)?;
541
542 if ctx.session.is_none() {
545 ctx.session = Some(Self::create_session(
546 &mut self.decoder,
547 wait_ctx,
548 ctx,
549 stream_id,
550 )?);
551 }
552
553 let entries = if plane_entries.len() != 1 {
555 return Err(VideoError::InvalidArgument);
556 } else {
557 plane_entries.first().unwrap()
559 };
560
561 let (resource_type, params) = match queue_type {
563 QueueType::Input => (ctx.in_params.resource_type, &ctx.in_params),
564 QueueType::Output => (ctx.out_params.resource_type, &ctx.out_params),
565 };
566
567 let resource = match resource_type {
568 ResourceType::VirtioObject => {
569 if entries.len() != 1 {
571 return Err(VideoError::InvalidArgument);
572 }
573 GuestResource::from_virtio_object_entry(
574 entries.first().unwrap().object(),
579 &self.resource_bridge,
580 params,
581 )
582 .map_err(|_| VideoError::InvalidArgument)?
583 }
584 ResourceType::GuestPages => GuestResource::from_virtio_guest_mem_entry(
585 unsafe {
588 std::slice::from_raw_parts(
589 entries.as_ptr() as *const protocol::virtio_video_mem_entry,
590 entries.len(),
591 )
592 },
593 &self.mem,
594 params,
595 )
596 .map_err(|_| VideoError::InvalidArgument)?,
597 };
598
599 let offset = plane_offsets.first().copied().unwrap_or(0);
600 ctx.register_resource(queue_type, resource_id, resource, offset);
601
602 if queue_type == QueueType::Input {
603 return Ok(VideoCmdResponseType::Sync(CmdResponse::NoData));
604 };
605
606 if let Some(frame_buf_id) = ctx.out_res.res_id_to_frame_buf_id.get(&resource_id) {
612 error!(
613 "resource {} has already been imported to Chrome as a frame buffer {}",
614 resource_id, frame_buf_id
615 );
616 return Err(VideoError::InvalidOperation);
617 }
618
619 Ok(VideoCmdResponseType::Sync(CmdResponse::NoData))
620 }
621
622 fn destroy_all_resources(
623 &mut self,
624 stream_id: StreamId,
625 queue_type: QueueType,
626 ) -> VideoResult<VideoCmdResponseType> {
627 let ctx = self.contexts.get_mut(&stream_id)?;
628
629 match queue_type {
631 QueueType::Input => {
632 ctx.in_res = Default::default();
633 }
634 QueueType::Output => {
635 ctx.out_res = Default::default();
636 }
637 }
638 Ok(VideoCmdResponseType::Sync(CmdResponse::NoData))
639 }
640
641 fn queue_input_resource(
642 &mut self,
643 stream_id: StreamId,
644 resource_id: ResourceId,
645 timestamp: u64,
646 data_sizes: Vec<u32>,
647 ) -> VideoResult<VideoCmdResponseType> {
648 let ctx = self.contexts.get_mut(&stream_id)?;
649
650 if data_sizes.len() != 1 {
651 error!("num_data_sizes must be 1 but {}", data_sizes.len());
652 return Err(VideoError::InvalidOperation);
653 }
654
655 let session = ctx.session.as_mut().ok_or(VideoError::InvalidOperation)?;
656
657 let InputResource { resource, offset } =
658 ctx.in_res
659 .get(&resource_id)
660 .ok_or(VideoError::InvalidResourceId {
661 stream_id,
662 resource_id,
663 })?;
664
665 session.decode(
666 resource_id,
667 timestamp,
668 resource
669 .handle
670 .try_clone()
671 .map_err(|_| VideoError::InvalidParameter)?,
672 *offset,
673 data_sizes[0], )?;
675
676 Ok(VideoCmdResponseType::Async(AsyncCmdTag::Queue {
677 stream_id,
678 queue_type: QueueType::Input,
679 resource_id,
680 }))
681 }
682
683 fn queue_output_resource(
684 &mut self,
685 stream_id: StreamId,
686 resource_id: ResourceId,
687 ) -> VideoResult<VideoCmdResponseType> {
688 let ctx = self.contexts.get_mut(&stream_id)?;
689
690 match ctx.out_params.format {
692 Some(Format::NV12) => (), Some(f) => {
694 error!(
695 "video decoder only supports NV12 as a frame format, got {}",
696 f
697 );
698 return Err(VideoError::InvalidOperation);
699 }
700 None => {
701 error!("output format is not set");
702 return Err(VideoError::InvalidOperation);
703 }
704 };
705
706 match ctx.out_res.queue_resource(resource_id)? {
707 QueueOutputResourceResult::UsingAsEos => {
708 Ok(())
710 }
711 QueueOutputResourceResult::Reused(buffer_id) => {
712 let res = ctx.pending_responses.iter()
713 .find(|&res| {
714 matches!(res, PendingResponse::PictureReady { picture_buffer_id, .. } if *picture_buffer_id == buffer_id)
715 });
716
717 if res.is_some() {
718 Ok(())
719 } else {
720 ctx.session
721 .as_mut()
722 .ok_or(VideoError::InvalidOperation)?
723 .reuse_output_buffer(buffer_id)
724 }
725 }
726 QueueOutputResourceResult::Registered(buffer_id) => {
727 let resource = ctx
730 .out_res
731 .res_id_to_res_handle
732 .remove(&resource_id)
733 .ok_or(VideoError::InvalidResourceId {
734 stream_id,
735 resource_id,
736 })?;
737
738 let session = ctx.session.as_mut().ok_or(VideoError::InvalidOperation)?;
739
740 ctx.out_res.res_id_to_descriptor.remove(&resource_id);
741 if resource.guest_cpu_mappable {
742 if let GuestResourceHandle::VirtioObject(VirtioObjectHandle { desc, .. }) =
743 &resource.handle
744 {
745 let desc = desc.try_clone().map_err(|e| {
746 VideoError::BackendFailure(anyhow::anyhow!(e).context(
747 "failed to clone buffer descriptor for completion barrier",
748 ))
749 })?;
750 ctx.out_res.res_id_to_descriptor.insert(resource_id, desc);
751 }
752 }
753
754 if ctx.out_res.output_params_set() {
756 const OUTPUT_BUFFER_COUNT: usize = 32;
757
758 session.set_output_parameters(OUTPUT_BUFFER_COUNT, Format::NV12)?;
763 }
764
765 session.use_output_buffer(buffer_id, resource)
766 }
767 }?;
768 Ok(VideoCmdResponseType::Async(AsyncCmdTag::Queue {
769 stream_id,
770 queue_type: QueueType::Output,
771 resource_id,
772 }))
773 }
774
775 fn get_params(
776 &self,
777 stream_id: StreamId,
778 queue_type: QueueType,
779 is_ext: bool,
780 ) -> VideoResult<VideoCmdResponseType> {
781 let ctx = self.contexts.get(&stream_id)?;
782 let params = match queue_type {
783 QueueType::Input => ctx.in_params.clone(),
784 QueueType::Output => ctx.out_params.clone(),
785 };
786 Ok(VideoCmdResponseType::Sync(CmdResponse::GetParams {
787 queue_type,
788 params,
789 is_ext,
790 }))
791 }
792
793 fn set_params(
794 &mut self,
795 stream_id: StreamId,
796 queue_type: QueueType,
797 params: Params,
798 is_ext: bool,
799 ) -> VideoResult<VideoCmdResponseType> {
800 let ctx = self.contexts.get_mut(&stream_id)?;
801 match queue_type {
802 QueueType::Input => {
803 if ctx.session.is_some() {
804 error!("parameter for input cannot be changed once decoding started");
805 return Err(VideoError::InvalidParameter);
806 }
807
808 ctx.in_params.format = params.format;
810 ctx.in_params.plane_formats = params.plane_formats;
811 if is_ext {
813 ctx.in_params.resource_type = params.resource_type;
814 }
815 }
816 QueueType::Output => {
817 if ctx.out_res.output_params_set {
820 error!("parameter for output cannot be changed once resources are imported");
821 return Err(VideoError::InvalidParameter);
822 }
823 if is_ext {
824 ctx.out_params.resource_type = params.resource_type;
825 }
826 }
827 };
828 Ok(VideoCmdResponseType::Sync(CmdResponse::NoData))
829 }
830
831 fn query_control(&self, ctrl_type: QueryCtrlType) -> VideoResult<VideoCmdResponseType> {
832 match self.capability.query_control(&ctrl_type) {
833 Some(resp) => Ok(VideoCmdResponseType::Sync(CmdResponse::QueryControl(resp))),
834 None => {
835 error!("querying an unsupported control: {:?}", ctrl_type);
836 Err(VideoError::InvalidArgument)
837 }
838 }
839 }
840
841 fn get_control(
842 &self,
843 stream_id: StreamId,
844 ctrl_type: CtrlType,
845 ) -> VideoResult<VideoCmdResponseType> {
846 let ctx = self.contexts.get(&stream_id)?;
847 match ctrl_type {
848 CtrlType::Profile => {
849 let profile = match ctx.in_params.format {
850 Some(Format::VP8) => Profile::VP8Profile0,
851 Some(Format::VP9) => Profile::VP9Profile0,
852 Some(Format::H264) => Profile::H264Baseline,
853 Some(Format::Hevc) => Profile::HevcMain,
854 Some(f) => {
855 error!("specified format is invalid: {}", f);
856 return Err(VideoError::InvalidArgument);
857 }
858 None => {
859 error!("bitstream format is not set");
860 return Err(VideoError::InvalidArgument);
861 }
862 };
863
864 Ok(CtrlVal::Profile(profile))
865 }
866 CtrlType::Level => {
867 let level = match ctx.in_params.format {
868 Some(Format::H264) => Level::H264_1_0,
869 Some(f) => {
870 error!("specified format has no level: {}", f);
871 return Err(VideoError::InvalidArgument);
872 }
873 None => {
874 error!("bitstream format is not set");
875 return Err(VideoError::InvalidArgument);
876 }
877 };
878
879 Ok(CtrlVal::Level(level))
880 }
881 t => {
882 error!("cannot get a control value: {:?}", t);
883 Err(VideoError::InvalidArgument)
884 }
885 }
886 .map(|ctrl_val| VideoCmdResponseType::Sync(CmdResponse::GetControl(ctrl_val)))
887 }
888
889 fn drain_stream(&mut self, stream_id: StreamId) -> VideoResult<VideoCmdResponseType> {
890 self.contexts
891 .get_mut(&stream_id)?
892 .session
893 .as_mut()
894 .ok_or(VideoError::InvalidOperation)?
895 .flush()?;
896 Ok(VideoCmdResponseType::Async(AsyncCmdTag::Drain {
897 stream_id,
898 }))
899 }
900
901 fn clear_queue(
902 &mut self,
903 stream_id: StreamId,
904 queue_type: QueueType,
905 wait_ctx: &WaitContext<Token>,
906 ) -> VideoResult<VideoCmdResponseType> {
907 let ctx = self.contexts.get_mut(&stream_id)?;
908
909 match queue_type {
917 QueueType::Input => {
918 if let Some(session) = ctx.session.as_mut() {
919 session.reset()?;
920 ctx.is_resetting = true;
921 for polled_barrier in ctx.pending_responses.iter_mut().filter_map(|r| {
923 if let PendingResponse::PollingBufferBarrier(desc) = r {
924 Some(desc)
925 } else {
926 None
927 }
928 }) {
929 wait_ctx.delete(polled_barrier).unwrap_or_else(|e| {
930 base::warn!(
931 "failed to remove buffer barrier from wait context: {:#}",
932 e
933 )
934 });
935 }
936 ctx.pending_responses.clear();
937 Ok(VideoCmdResponseType::Async(AsyncCmdTag::Clear {
938 stream_id,
939 queue_type: QueueType::Input,
940 }))
941 } else {
942 Ok(VideoCmdResponseType::Sync(CmdResponse::NoData))
943 }
944 }
945 QueueType::Output => {
946 if let Some(session) = ctx.session.as_mut() {
947 session.clear_output_buffers()?;
948 ctx.out_res.queued_res_ids.clear();
949 }
950 Ok(VideoCmdResponseType::Sync(CmdResponse::NoData))
951 }
952 }
953 }
954}
955
956impl<D: DecoderBackend> Device for Decoder<D> {
957 fn process_cmd(
958 &mut self,
959 cmd: VideoCmd,
960 wait_ctx: &WaitContext<Token>,
961 ) -> (
962 VideoCmdResponseType,
963 Option<(u32, Vec<VideoEvtResponseType>)>,
964 ) {
965 use VideoCmd::*;
966 use VideoCmdResponseType::Sync;
967
968 let mut event_ret = None;
969 let cmd_response = match cmd {
970 QueryCapability { queue_type } => Ok(Sync(self.query_capabilities(queue_type))),
971 StreamCreate {
972 stream_id,
973 coded_format,
974 input_resource_type,
975 output_resource_type,
976 } => self.create_stream(
977 stream_id,
978 coded_format,
979 input_resource_type,
980 output_resource_type,
981 ),
982 StreamDestroy { stream_id } => {
983 self.destroy_stream(stream_id);
984 Ok(Sync(CmdResponse::NoData))
985 }
986 ResourceCreate {
987 stream_id,
988 queue_type,
989 resource_id,
990 plane_offsets,
991 plane_entries,
992 } => self.create_resource(
993 wait_ctx,
994 stream_id,
995 queue_type,
996 resource_id,
997 plane_offsets,
998 plane_entries,
999 ),
1000 ResourceDestroyAll {
1001 stream_id,
1002 queue_type,
1003 } => self.destroy_all_resources(stream_id, queue_type),
1004 ResourceQueue {
1005 stream_id,
1006 queue_type: QueueType::Input,
1007 resource_id,
1008 timestamp,
1009 data_sizes,
1010 } => self.queue_input_resource(stream_id, resource_id, timestamp, data_sizes),
1011 ResourceQueue {
1012 stream_id,
1013 queue_type: QueueType::Output,
1014 resource_id,
1015 ..
1016 } => {
1017 let resp = self.queue_output_resource(stream_id, resource_id);
1018 if resp.is_ok() {
1019 if let Ok(ctx) = self.contexts.get_mut(&stream_id) {
1020 event_ret = Some((stream_id, ctx.output_pending_responses(wait_ctx)));
1021 }
1022 }
1023 resp
1024 }
1025 GetParams {
1026 stream_id,
1027 queue_type,
1028 is_ext,
1029 } => self.get_params(stream_id, queue_type, is_ext),
1030 SetParams {
1031 stream_id,
1032 queue_type,
1033 params,
1034 is_ext,
1035 } => self.set_params(stream_id, queue_type, params, is_ext),
1036 QueryControl { query_ctrl_type } => self.query_control(query_ctrl_type),
1037 GetControl {
1038 stream_id,
1039 ctrl_type,
1040 } => self.get_control(stream_id, ctrl_type),
1041 SetControl { .. } => {
1042 error!("SET_CONTROL is not allowed for decoder");
1043 Err(VideoError::InvalidOperation)
1044 }
1045 StreamDrain { stream_id } => self.drain_stream(stream_id),
1046 QueueClear {
1047 stream_id,
1048 queue_type,
1049 } => self.clear_queue(stream_id, queue_type, wait_ctx),
1050 };
1051
1052 let cmd_ret = match cmd_response {
1053 Ok(r) => r,
1054 Err(e) => {
1055 error!("returning error response: {}", &e);
1056 Sync(e.into())
1057 }
1058 };
1059 (cmd_ret, event_ret)
1060 }
1061
1062 fn process_event(
1063 &mut self,
1064 desc_map: &mut AsyncCmdDescMap,
1065 stream_id: u32,
1066 wait_ctx: &WaitContext<Token>,
1067 ) -> Option<Vec<VideoEvtResponseType>> {
1068 use crate::virtio::video::device::VideoEvtResponseType::*;
1072
1073 let ctx = match self.contexts.get_mut(&stream_id) {
1074 Ok(ctx) => ctx,
1075 Err(e) => {
1076 error!("failed to get a context for session {}: {}", stream_id, e);
1077 return None;
1078 }
1079 };
1080
1081 let session = match ctx.session.as_mut() {
1082 Some(s) => s,
1083 None => {
1084 error!("session not yet created for context {}", stream_id);
1085 return None;
1086 }
1087 };
1088
1089 let event = match session.read_event() {
1090 Ok(event) => event,
1091 Err(e) => {
1092 error!("failed to read an event from session {}: {}", stream_id, e);
1093 return None;
1094 }
1095 };
1096
1097 let event_responses = match event {
1098 DecoderEvent::ProvidePictureBuffers {
1099 min_num_buffers,
1100 width,
1101 height,
1102 visible_rect,
1103 } => {
1104 ctx.handle_provide_picture_buffers(min_num_buffers, width, height, visible_rect);
1105 vec![Event(VideoEvt {
1106 typ: EvtType::DecResChanged,
1107 stream_id,
1108 })]
1109 }
1110 DecoderEvent::PictureReady {
1111 picture_buffer_id,
1112 timestamp,
1113 ..
1114 } => {
1115 if ctx.is_resetting {
1116 vec![]
1117 } else {
1118 if let Some(desc) = ctx
1121 .out_res
1122 .frame_buf_id_to_res_id
1123 .get(&picture_buffer_id)
1124 .and_then(|res_id| ctx.out_res.res_id_to_descriptor.get(res_id))
1125 {
1126 let desc = Descriptor(desc.as_raw_descriptor());
1127 ctx.pending_responses
1128 .push_back(PendingResponse::BufferBarrier(desc));
1129 }
1130 ctx.pending_responses
1131 .push_back(PendingResponse::PictureReady {
1132 picture_buffer_id,
1133 timestamp,
1134 });
1135 ctx.output_pending_responses(wait_ctx)
1136 }
1137 }
1138 DecoderEvent::NotifyEndOfBitstreamBuffer(resource_id) => {
1139 let async_response = AsyncCmdResponse::from_response(
1140 AsyncCmdTag::Queue {
1141 stream_id,
1142 queue_type: QueueType::Input,
1143 resource_id,
1144 },
1145 CmdResponse::ResourceQueue {
1146 timestamp: 0, flags: 0, size: 0, },
1150 );
1151 vec![AsyncCmd(async_response)]
1152 }
1153 DecoderEvent::FlushCompleted(flush_result) => {
1154 match flush_result {
1155 Ok(()) => {
1156 ctx.pending_responses
1157 .push_back(PendingResponse::FlushCompleted);
1158 ctx.output_pending_responses(wait_ctx)
1159 }
1160 Err(error) => {
1161 error!(
1164 "failed to 'Flush' in VDA (stream id {}): {:?}",
1165 stream_id, error
1166 );
1167 vec![AsyncCmd(AsyncCmdResponse::from_error(
1168 AsyncCmdTag::Drain { stream_id },
1169 error,
1170 ))]
1171 }
1172 }
1173 }
1174 DecoderEvent::ResetCompleted(reset_result) => {
1175 ctx.is_resetting = false;
1176 let tag = AsyncCmdTag::Clear {
1177 stream_id,
1178 queue_type: QueueType::Input,
1179 };
1180 match reset_result {
1181 Ok(()) => {
1182 let mut responses: Vec<_> = desc_map
1183 .create_cancellation_responses(
1184 &stream_id,
1185 Some(QueueType::Input),
1186 Some(tag),
1187 )
1188 .into_iter()
1189 .map(AsyncCmd)
1190 .collect();
1191 responses.push(AsyncCmd(AsyncCmdResponse::from_response(
1192 tag,
1193 CmdResponse::NoData,
1194 )));
1195 responses
1196 }
1197 Err(error) => {
1198 error!(
1199 "failed to 'Reset' in VDA (stream id {}): {:?}",
1200 stream_id, error
1201 );
1202 vec![AsyncCmd(AsyncCmdResponse::from_error(tag, error))]
1203 }
1204 }
1205 }
1206 DecoderEvent::NotifyError(error) => {
1207 error!("an error is notified by VDA: {}", error);
1208 vec![Event(VideoEvt {
1209 typ: EvtType::Error,
1210 stream_id,
1211 })]
1212 }
1213 };
1214
1215 Some(event_responses)
1216 }
1217
1218 fn process_buffer_barrier(
1219 &mut self,
1220 stream_id: u32,
1221 wait_ctx: &WaitContext<Token>,
1222 ) -> Option<Vec<VideoEvtResponseType>> {
1223 let ctx = match self.contexts.get_mut(&stream_id) {
1224 Ok(ctx) => ctx,
1225 Err(e) => {
1226 error!("failed to get a context for session {}: {}", stream_id, e);
1227 return None;
1228 }
1229 };
1230
1231 match ctx.pending_responses.front() {
1232 Some(PendingResponse::PollingBufferBarrier(desc)) => {
1233 let _ = wait_ctx.delete(&Descriptor(desc.as_raw_descriptor()));
1236 ctx.pending_responses.pop_front();
1237 }
1238 _ => {
1239 error!("expected a buffer barrier, but found none");
1240 }
1241 }
1242
1243 Some(ctx.output_pending_responses(wait_ctx))
1244 }
1245}