1#[cfg(target_os = "uefi")]
4use std::collections::hash_map::DefaultHasher;
5use std::collections::{HashMap, VecDeque};
6#[cfg(target_os = "uefi")]
7use std::hash::BuildHasherDefault;
8use std::io::{Read, Seek, SeekFrom};
9
10use crate::asf::{AsfFile, AsfPayload, VideoStreamInfo};
11use crate::decoder::{MacroblockDecoder, YuvFrame};
12use crate::error::{DecoderError, Result};
13use crate::vc1::{PictureHeader, SequenceHeader, vc1_unescape_buffer};
14#[cfg(feature = "audio")]
15use crate::wma::{PcmFrameF32, WmaDecoder, WmaProDecoder};
16use crate::wmv2::{Wmv2FrameHeader, Wmv2FrameType, Wmv2Params};
17
18#[derive(Clone)]
20pub struct DecodedFrame {
21 pub pts_ms: u32,
22 pub is_key_frame: bool,
23 pub frame: YuvFrame,
24}
25
26#[cfg(feature = "audio")]
28#[derive(Clone)]
29pub struct DecodedAudioFrame {
30 pub pts_ms: u32,
31 pub frame: PcmFrameF32,
32}
33
34pub struct Wmv2Decoder {
38 params: Wmv2Params,
39 mb_dec: MacroblockDecoder,
40 cur: YuvFrame,
41 locked_hdr_off: Option<usize>,
42}
43
44impl Wmv2Decoder {
45 pub fn new(width: u32, height: u32, extradata: &[u8]) -> Self {
49 let params = Wmv2Params::new(width, height);
50 let mut mb_dec = MacroblockDecoder::new(width, height);
51 mb_dec.wmv2_set_extradata(extradata);
52 let cur = YuvFrame::new(width, height);
53 Self {
54 params,
55 mb_dec,
56 cur,
57 locked_hdr_off: None,
58 }
59 }
60
61 pub fn width(&self) -> u32 {
62 self.params.width
63 }
64
65 pub fn height(&self) -> u32 {
66 self.params.height
67 }
68
69 pub fn current_frame(&self) -> &YuvFrame {
73 &self.cur
74 }
75
76 pub fn decode_frame(
80 &mut self,
81 payload: &[u8],
82 is_key_frame: bool,
83 ) -> Result<Option<&YuvFrame>> {
84 if payload.is_empty() {
85 return Ok(None);
86 }
87
88 let mut best_score: i64 = -1;
89 let mut best_off: usize = 0;
90 let mut best_hdr: Option<Wmv2FrameHeader> = None;
91
92 let mut offs: Vec<usize> = Vec::with_capacity(18);
94 if let Some(o) = self.locked_hdr_off {
95 offs.push(o);
96 }
97 for o in 0..=16 {
98 if Some(o) != self.locked_hdr_off {
99 offs.push(o);
100 }
101 }
102
103 for off in offs {
104 if off > payload.len() {
105 continue;
106 }
107 let cands = Wmv2FrameHeader::parse_candidates(
108 &payload[off..],
109 self.mb_dec.width_mb,
110 self.mb_dec.height_mb,
111 );
112 if cands.is_empty() {
113 continue;
114 }
115 for h in cands {
116 if is_key_frame && h.frame_type != Wmv2FrameType::I {
118 continue;
119 }
120
121 let mut sc: i64 = if h.frame_skipped {
123 1
124 } else if is_key_frame {
125 2
126 } else {
127 self.mb_dec.probe_wmv2_payload(&payload[off..], &h) as i64
128 };
129
130 if Some(off) == self.locked_hdr_off {
131 sc += 64;
132 }
133
134 if sc > best_score {
135 best_score = sc;
136 best_off = off;
137 best_hdr = Some(h);
138 }
139 }
140 }
141
142 let Some(hdr) = best_hdr else {
143 return Ok(None);
144 };
145
146 if self.locked_hdr_off.is_none() {
147 self.locked_hdr_off = Some(best_off);
148 }
149
150 let frame_data = &payload[best_off..];
151 self.mb_dec
152 .decode_wmv2_frame(frame_data, &hdr, &self.params, &mut self.cur)?;
153 Ok(Some(&self.cur))
154 }
155
156 pub fn decode_frame_owned(
158 &mut self,
159 payload: &[u8],
160 is_key_frame: bool,
161 ) -> Result<Option<YuvFrame>> {
162 let Some(f) = self.decode_frame(payload, is_key_frame)? else {
163 return Ok(None);
164 };
165 Ok(Some(f.clone()))
166 }
167}
168
169pub struct Wmv3Decoder {
171 seq: SequenceHeader,
172 mb_dec: MacroblockDecoder,
173 cur: YuvFrame,
174}
175
176impl Wmv3Decoder {
177 pub fn new(width: u32, height: u32, extradata: &[u8]) -> Result<Self> {
178 let mut seq = SequenceHeader::parse(extradata)?;
179 seq.width = width;
180 seq.height = height;
181 seq.display_width = width;
182 seq.display_height = height;
183
184 let coded_width = width
192 .checked_add(15)
193 .ok_or_else(|| DecoderError::InvalidData("WMV3 width overflow".into()))?
194 / 16
195 * 16;
196 let coded_height = height
197 .checked_add(15)
198 .ok_or_else(|| DecoderError::InvalidData("WMV3 height overflow".into()))?
199 / 16
200 * 16;
201
202 Ok(Self {
203 seq,
204 mb_dec: MacroblockDecoder::new(coded_width, coded_height),
205 cur: YuvFrame::new(coded_width, coded_height),
206 })
207 }
208
209 pub fn width(&self) -> u32 {
210 self.seq.width
211 }
212 pub fn height(&self) -> u32 {
213 self.seq.height
214 }
215
216 fn visible_frame(&self) -> YuvFrame {
217 let width = self.seq.width as usize;
218 let height = self.seq.height as usize;
219 let src_width = self.cur.width as usize;
220 let src_height = self.cur.height as usize;
221 debug_assert!(width <= src_width && height <= src_height);
222
223 let mut out = YuvFrame::new(self.seq.width, self.seq.height);
224 for y in 0..height {
225 let src = y * src_width;
226 let dst = y * width;
227 out.y[dst..dst + width].copy_from_slice(&self.cur.y[src..src + width]);
228 }
229
230 let cw = width / 2;
231 let ch = height / 2;
232 let src_cw = src_width / 2;
233 for y in 0..ch {
234 let src = y * src_cw;
235 let dst = y * cw;
236 out.cb[dst..dst + cw].copy_from_slice(&self.cur.cb[src..src + cw]);
237 out.cr[dst..dst + cw].copy_from_slice(&self.cur.cr[src..src + cw]);
238 }
239 out
240 }
241
242 pub fn decode_frame_owned(
243 &mut self,
244 payload: &[u8],
245 is_key_frame: bool,
246 pts_ms: u32,
247 ) -> Result<Option<YuvFrame>> {
248 if payload.is_empty() {
249 return Ok(None);
250 }
251 let mb_w = self.seq.width.div_ceil(16) as usize;
252 let mb_h = self.seq.height.div_ceil(16) as usize;
253 let hdr = PictureHeader::parse(payload, &self.seq, pts_ms, mb_w, mb_h)?;
254 if is_key_frame
255 && !matches!(
256 hdr.frame_type,
257 crate::vc1::FrameType::I | crate::vc1::FrameType::BI
258 )
259 {
260 log::debug!(
261 "ASF key-frame flag disagrees with WMV3 PTYPE: {:?}",
262 hdr.frame_type
263 );
264 }
265 self.mb_dec
266 .decode_frame(payload, &hdr, &self.seq, &mut self.cur)?;
267 Ok(Some(self.visible_frame()))
270 }
271}
272
273pub struct Wvc1Decoder {
279 seq: SequenceHeader,
280 mb_dec: MacroblockDecoder,
281 cur: YuvFrame,
282}
283
284impl Wvc1Decoder {
285 pub fn new(asf_width: u32, asf_height: u32, extradata: &[u8]) -> Result<Self> {
286 let mut seq = SequenceHeader::parse_wvc1(extradata)?;
287 if seq.interlace {
288 return Err(DecoderError::Unsupported(
289 "VC-1 Advanced interlaced pictures are not implemented by the native decoder"
290 .into(),
291 ));
292 }
293 if seq.range_mapy.is_some() || seq.range_mapuv.is_some() {
294 return Err(DecoderError::Unsupported(
295 "VC-1 Advanced range mapping is not implemented by the native decoder".into(),
296 ));
297 }
298
299 if asf_width != 0 && asf_width > seq.width {
304 return Err(DecoderError::InvalidData(format!(
305 "WVC1 ASF width {asf_width} exceeds coded width {}",
306 seq.width
307 )));
308 }
309 if asf_height != 0 && asf_height > seq.height {
310 return Err(DecoderError::InvalidData(format!(
311 "WVC1 ASF height {asf_height} exceeds coded height {}",
312 seq.height
313 )));
314 }
315 if asf_width != 0 {
316 seq.display_width = asf_width;
317 }
318 if asf_height != 0 {
319 seq.display_height = asf_height;
320 }
321
322 let coded_width = seq
323 .width
324 .checked_add(15)
325 .ok_or_else(|| DecoderError::InvalidData("WVC1 width overflow".into()))?
326 / 16
327 * 16;
328 let coded_height = seq
329 .height
330 .checked_add(15)
331 .ok_or_else(|| DecoderError::InvalidData("WVC1 height overflow".into()))?
332 / 16
333 * 16;
334
335 Ok(Self {
336 seq,
337 mb_dec: MacroblockDecoder::new(coded_width, coded_height),
338 cur: YuvFrame::new(coded_width, coded_height),
339 })
340 }
341
342 pub fn width(&self) -> u32 {
343 self.seq.display_width.min(self.seq.width)
344 }
345
346 pub fn height(&self) -> u32 {
347 self.seq.display_height.min(self.seq.height)
348 }
349
350 fn visible_frame(&self) -> YuvFrame {
351 let width = self.seq.display_width.min(self.seq.width) as usize;
352 let height = self.seq.display_height.min(self.seq.height) as usize;
353 let src_width = self.cur.width as usize;
354 let mut out = YuvFrame::new(width as u32, height as u32);
355
356 for y in 0..height {
357 let src = y * src_width;
358 let dst = y * width;
359 out.y[dst..dst + width].copy_from_slice(&self.cur.y[src..src + width]);
360 }
361
362 let cw = width / 2;
363 let ch = height / 2;
364 let src_cw = src_width / 2;
365 for y in 0..ch {
366 let src = y * src_cw;
367 let dst = y * cw;
368 out.cb[dst..dst + cw].copy_from_slice(&self.cur.cb[src..src + cw]);
369 out.cr[dst..dst + cw].copy_from_slice(&self.cur.cr[src..src + cw]);
370 }
371 out
372 }
373
374 fn marker_at(data: &[u8], from: usize) -> Option<usize> {
375 if data.len() < 4 || from > data.len().saturating_sub(4) {
376 return None;
377 }
378 (from..=data.len() - 4).find(|&i| data[i] == 0 && data[i + 1] == 0 && data[i + 2] == 1)
379 }
380
381 fn prepare_picture_payload(&mut self, payload: &[u8]) -> Result<Vec<u8>> {
387 let Some(first) = Self::marker_at(payload, 0) else {
388 return Ok(vc1_unescape_buffer(payload));
389 };
390
391 let mut pos = first;
394 let mut frame: Option<Vec<u8>> = None;
395 while let Some(start) = Self::marker_at(payload, pos) {
396 let marker = payload[start + 3];
397 let next = Self::marker_at(payload, start + 4).unwrap_or(payload.len());
398 let body = &payload[start + 4..next];
399 match marker {
400 0x0d => {
401 frame = Some(vc1_unescape_buffer(body));
402 }
403 0x0e => {
404 let entry = vc1_unescape_buffer(body);
405 let old_width = self.seq.width;
406 let old_height = self.seq.height;
407 self.seq.apply_wvc1_entry_point(&entry)?;
408 if self.seq.width != old_width || self.seq.height != old_height {
409 return Err(DecoderError::Unsupported(format!(
410 "in-band WVC1 coded-size change {}x{} -> {}x{} requires decoder reinitialization",
411 old_width, old_height, self.seq.width, self.seq.height
412 )));
413 }
414 if self.seq.interlace {
415 return Err(DecoderError::Unsupported(
416 "VC-1 Advanced interlaced pictures are not implemented by the native decoder"
417 .into(),
418 ));
419 }
420 if self.seq.range_mapy.is_some() || self.seq.range_mapuv.is_some() {
421 return Err(DecoderError::Unsupported(
422 "VC-1 Advanced range mapping is not implemented by the native decoder"
423 .into(),
424 ));
425 }
426 }
427 0x0b => {
428 return Err(DecoderError::Unsupported(
429 "VC-1 Advanced slice start codes are not implemented by the native decoder"
430 .into(),
431 ));
432 }
433 0x0c => {
434 return Err(DecoderError::Unsupported(
435 "VC-1 Advanced field start codes require interlaced decoding".into(),
436 ));
437 }
438 0x0f => {
439 return Err(DecoderError::Unsupported(
445 "in-band VC-1 Advanced sequence changes are not supported".into(),
446 ));
447 }
448 0x0a | 0x00..=0x09 => {}
449 _ => {}
450 }
451 if next >= payload.len() {
452 break;
453 }
454 pos = next;
455 }
456
457 frame.ok_or_else(|| {
458 DecoderError::InvalidData("WVC1 access unit has no VC-1 frame start code".into())
459 })
460 }
461
462 pub fn decode_frame_owned(
463 &mut self,
464 payload: &[u8],
465 is_key_frame: bool,
466 pts_ms: u32,
467 ) -> Result<Option<YuvFrame>> {
468 if payload.is_empty() {
469 return Ok(None);
470 }
471 let frame_payload = self.prepare_picture_payload(payload)?;
472 if frame_payload.is_empty() {
473 return Ok(None);
474 }
475 let mb_w = self.seq.width.div_ceil(16) as usize;
476 let mb_h = self.seq.height.div_ceil(16) as usize;
477 let hdr = PictureHeader::parse(&frame_payload, &self.seq, pts_ms, mb_w, mb_h)?;
478 if is_key_frame
479 && !matches!(
480 hdr.frame_type,
481 crate::vc1::FrameType::I | crate::vc1::FrameType::BI
482 )
483 {
484 log::debug!(
485 "ASF key-frame flag disagrees with WVC1 PTYPE: {:?}",
486 hdr.frame_type
487 );
488 }
489 self.mb_dec
490 .decode_frame(&frame_payload, &hdr, &self.seq, &mut self.cur)?;
491 Ok(Some(self.visible_frame()))
492 }
493}
494
495enum VideoCodecDecoder {
496 Wmv12(Wmv2Decoder),
497 Wmv3(Wmv3Decoder),
498 Wvc1(Wvc1Decoder),
499}
500
501impl VideoCodecDecoder {
502 fn decode_frame_owned(
503 &mut self,
504 payload: &[u8],
505 is_key: bool,
506 pts_ms: u32,
507 ) -> Result<Option<YuvFrame>> {
508 match self {
509 Self::Wmv12(d) => d.decode_frame_owned(payload, is_key),
510 Self::Wmv3(d) => d.decode_frame_owned(payload, is_key, pts_ms),
511 Self::Wvc1(d) => d.decode_frame_owned(payload, is_key, pts_ms),
512 }
513 }
514}
515
516#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
521struct FrameKey {
522 stream_number: u8,
523 object_id: u32,
524}
525
526#[derive(Debug, Clone)]
527struct FrameAssembly {
528 total: usize,
529 pts_ms: u32,
530 is_key: bool,
531 data: Vec<u8>,
532 ranges: Vec<(usize, usize)>,
533}
534
535impl FrameAssembly {
536 fn new(total: usize, pts_ms: u32, is_key: bool) -> Self {
537 Self {
538 total,
539 pts_ms,
540 is_key,
541 data: vec![0u8; total],
542 ranges: Vec::new(),
543 }
544 }
545
546 fn insert(&mut self, offset: usize, frag: &[u8]) {
547 if self.total == 0 || offset >= self.total || frag.is_empty() {
548 return;
549 }
550 let end = (offset + frag.len()).min(self.total);
551 let n = end - offset;
552 self.data[offset..end].copy_from_slice(&frag[..n]);
553 self.add_range(offset, end);
554 }
555
556 fn add_range(&mut self, start: usize, end: usize) {
557 if start >= end {
558 return;
559 }
560 self.ranges.push((start, end));
561 self.ranges.sort_by_key(|r| r.0);
562
563 let mut merged: Vec<(usize, usize)> = Vec::with_capacity(self.ranges.len());
564 for (s, e) in self.ranges.drain(..) {
565 if let Some(last) = merged.last_mut()
566 && s <= last.1
567 {
568 last.1 = last.1.max(e);
569 continue;
570 }
571 merged.push((s, e));
572 }
573 self.ranges = merged;
574 }
575
576 fn covered_len(&self) -> usize {
577 self.ranges.iter().map(|(s, e)| e - s).sum()
578 }
579
580 fn is_complete(&self) -> bool {
581 self.total > 0
582 && self.covered_len() >= self.total
583 && self.ranges.len() == 1
584 && self.ranges[0] == (0, self.total)
585 }
586}
587
588#[cfg(target_os = "uefi")]
589type InFlightMap = HashMap<FrameKey, FrameAssembly, BuildHasherDefault<DefaultHasher>>;
590#[cfg(not(target_os = "uefi"))]
591type InFlightMap = HashMap<FrameKey, FrameAssembly>;
592
593#[derive(Default)]
594struct FrameAssembler {
595 in_flight: InFlightMap,
596}
597
598impl FrameAssembler {
599 fn push(&mut self, payload: AsfPayload) -> Option<(u32, bool, Vec<u8>)> {
600 if payload.data.is_empty() {
601 return None;
602 }
603
604 let key = FrameKey {
605 stream_number: payload.stream_number,
606 object_id: payload.object_id,
607 };
608
609 if payload.obj_offset == 0 {
611 let osz = payload.obj_size as usize;
612 if osz == 0 || osz == payload.data.len() {
613 return Some((payload.pts_ms, payload.is_key_frame, payload.data));
614 }
615 }
616
617 if payload.obj_size == 0 {
619 return Some((payload.pts_ms, payload.is_key_frame, payload.data));
620 }
621
622 let total = payload.obj_size as usize;
623 let entry = self
624 .in_flight
625 .entry(key)
626 .or_insert_with(|| FrameAssembly::new(total, payload.pts_ms, payload.is_key_frame));
627
628 entry.is_key |= payload.is_key_frame;
630 entry.insert(payload.obj_offset as usize, &payload.data);
631
632 if entry.is_complete() {
633 let assembly = self.in_flight.remove(&key).unwrap();
634 return Some((assembly.pts_ms, assembly.is_key, assembly.data));
635 }
636 None
637 }
638}
639
640pub struct AsfWmv2Decoder<R: Read + Seek> {
645 reader: R,
646 asf: AsfFile,
647 video_info: VideoStreamInfo,
648 assembler: FrameAssembler,
649 pending_payloads: VecDeque<AsfPayload>,
654 decoder: VideoCodecDecoder,
655}
656
657#[cfg(feature = "audio")]
662enum AudioCodecDecoder {
663 Wma12(Box<WmaDecoder>),
664 WmaPro(Box<WmaProDecoder>),
665}
666
667#[cfg(feature = "audio")]
668impl AudioCodecDecoder {
669 fn sample_rate(&self) -> u32 {
670 match self {
671 Self::Wma12(d) => d.sample_rate(),
672 Self::WmaPro(d) => d.sample_rate(),
673 }
674 }
675
676 fn channels(&self) -> u16 {
677 match self {
678 Self::Wma12(d) => d.channels(),
679 Self::WmaPro(d) => d.channels(),
680 }
681 }
682
683 fn decode_packet(&mut self, packet: &[u8], pts_ms: u32) -> Result<Option<PcmFrameF32>> {
684 match self {
685 Self::Wma12(d) => d.decode_packet(packet, pts_ms),
686 Self::WmaPro(d) => d.decode_packet(packet, pts_ms),
687 }
688 }
689}
690
691#[cfg(feature = "audio")]
692pub struct AsfWmaDecoder<R: Read + Seek> {
693 reader: R,
694 asf: AsfFile,
695 audio_stream_number: u8,
696 audio_format_tag: u16,
697 audio_block_align: u16,
698 decoder: AudioCodecDecoder,
699 assembler: FrameAssembler,
700 pending_payloads: VecDeque<AsfPayload>,
706 last_pts_ms: u32,
707 flushed_eof: bool,
708}
709
710#[cfg(feature = "audio")]
711impl<R: Read + Seek> AsfWmaDecoder<R> {
712 pub fn open(mut reader: R) -> Result<Self> {
717 let asf = AsfFile::open(&mut reader)?;
718 let mut chosen = None;
719 for a in asf.audio_streams.iter() {
720 if matches!(a.format_tag, 0x0160..=0x0162) {
721 chosen = Some(a.clone());
722 break;
723 }
724 }
725 let Some(audio_info) = chosen else {
726 return Err(DecoderError::Unsupported(
727 "No supported WMA (0x0160/0x0161/0x0162) audio stream found".into(),
728 ));
729 };
730
731 reader.seek(SeekFrom::Start(asf.data_offset))?;
732 let decoder = match audio_info.format_tag {
733 0x0162 => AudioCodecDecoder::WmaPro(Box::new(WmaProDecoder::new(&audio_info)?)),
734 _ => AudioCodecDecoder::Wma12(Box::new(WmaDecoder::new(&audio_info)?)),
735 };
736
737 Ok(Self {
738 reader,
739 asf,
740 audio_stream_number: audio_info.stream_number,
741 audio_format_tag: audio_info.format_tag,
742 audio_block_align: audio_info.block_align,
743 decoder,
744 assembler: FrameAssembler::default(),
745 pending_payloads: VecDeque::new(),
746 last_pts_ms: 0,
747 flushed_eof: false,
748 })
749 }
750
751 pub fn sample_rate(&self) -> u32 {
752 self.decoder.sample_rate()
753 }
754
755 pub fn channels(&self) -> u16 {
756 self.decoder.channels()
757 }
758
759 pub fn duration_ms(&self) -> Option<u64> {
760 self.asf.play_duration_ms
761 }
762
763 pub fn next_frame(&mut self) -> Result<Option<DecodedAudioFrame>> {
767 loop {
768 let payload = if let Some(payload) = self.pending_payloads.pop_front() {
775 payload
776 } else {
777 let payloads = match self.asf.read_packet(&mut self.reader) {
778 Ok(p) => p,
779 Err(DecoderError::EndOfStream) => {
780 if self.flushed_eof {
781 return Ok(None);
782 }
783 self.flushed_eof = true;
784 if let Some(frame) = self.decoder.decode_packet(&[], self.last_pts_ms)? {
785 return Ok(Some(DecodedAudioFrame {
786 pts_ms: frame.pts_ms,
787 frame,
788 }));
789 }
790 return Ok(None);
791 }
792 Err(e) => return Err(e),
793 };
794 self.pending_payloads.extend(
795 payloads
796 .into_iter()
797 .filter(|payload| payload.stream_number == self.audio_stream_number),
798 );
799 let Some(payload) = self.pending_payloads.pop_front() else {
800 continue;
801 };
802 payload
803 };
804
805 let Some((pts_ms, _is_key, data)) = self.assembler.push(payload) else {
806 continue;
807 };
808 self.last_pts_ms = pts_ms;
809 let audio_format_tag = self.audio_format_tag;
810 let audio_block_align = self.audio_block_align;
811 let media_object_len = data.len();
812 let frame = self.decoder.decode_packet(&data, pts_ms).map_err(|err| {
813 let context = format!(
814 "WMA tag=0x{audio_format_tag:04x} block_align={audio_block_align} media_object_len={media_object_len} pts_ms={pts_ms}",
815 );
816 match err {
817 DecoderError::InvalidData(message) => {
818 DecoderError::InvalidData(format!("{context}: {message}"))
819 }
820 DecoderError::Unsupported(message) => {
821 DecoderError::Unsupported(format!("{context}: {message}"))
822 }
823 other => other,
824 }
825 })?;
826 if let Some(frame) = frame {
827 return Ok(Some(DecodedAudioFrame { pts_ms, frame }));
828 }
829 }
830 }
831}
832
833impl<R: Read + Seek> AsfWmv2Decoder<R> {
834 pub fn open(mut reader: R) -> Result<Self> {
838 let asf = AsfFile::open(&mut reader)?;
839 let mut video_info: Option<VideoStreamInfo> = None;
840 for v in asf.video_streams.iter() {
841 let four_cc = std::str::from_utf8(&v.codec_four_cc)
842 .unwrap_or("")
843 .to_uppercase();
844 if matches!(four_cc.as_str(), "WMV3" | "WMV2" | "WMV1" | "WVC1") {
845 video_info = Some(v.clone());
846 break;
847 }
848 }
849 let Some(video_info) = video_info else {
850 return Err(DecoderError::Unsupported(
851 "No supported WMV1/WMV2/WMV3/WVC1 video stream found".into(),
852 ));
853 };
854
855 reader.seek(SeekFrom::Start(asf.data_offset))?;
856
857 let four_cc = std::str::from_utf8(&video_info.codec_four_cc)
858 .unwrap_or("")
859 .to_uppercase();
860 let decoder = if four_cc == "WMV3" {
861 VideoCodecDecoder::Wmv3(Wmv3Decoder::new(
862 video_info.width,
863 video_info.height,
864 &video_info.extra_data,
865 )?)
866 } else if four_cc == "WVC1" {
867 VideoCodecDecoder::Wvc1(Wvc1Decoder::new(
868 video_info.width,
869 video_info.height,
870 &video_info.extra_data,
871 )?)
872 } else {
873 VideoCodecDecoder::Wmv12(Wmv2Decoder::new(
874 video_info.width,
875 video_info.height,
876 &video_info.extra_data,
877 ))
878 };
879
880 Ok(Self {
881 reader,
882 asf,
883 video_info,
884 assembler: FrameAssembler::default(),
885 pending_payloads: VecDeque::new(),
886 decoder,
887 })
888 }
889
890 pub fn video_stream_info(&self) -> &VideoStreamInfo {
892 &self.video_info
893 }
894
895 pub fn duration_ms(&self) -> Option<u64> {
896 self.asf.play_duration_ms
897 }
898
899 pub fn next_frame(&mut self) -> Result<Option<DecodedFrame>> {
903 loop {
904 let payload = if let Some(payload) = self.pending_payloads.pop_front() {
916 payload
917 } else {
918 let payloads = match self.asf.read_packet(&mut self.reader) {
919 Ok(p) => p,
920 Err(DecoderError::EndOfStream) => return Ok(None),
921 Err(e) => return Err(e),
922 };
923 self.pending_payloads.extend(
924 payloads
925 .into_iter()
926 .filter(|payload| payload.stream_number == self.video_info.stream_number),
927 );
928 let Some(payload) = self.pending_payloads.pop_front() else {
929 continue;
930 };
931 payload
932 };
933
934 let Some((pts_ms, is_key, data)) = self.assembler.push(payload) else {
935 continue;
936 };
937
938 if let Some(frame) = self.decoder.decode_frame_owned(&data, is_key, pts_ms)? {
939 return Ok(Some(DecodedFrame {
940 pts_ms,
941 is_key_frame: is_key,
942 frame,
943 }));
944 }
945 }
946 }
947}