1use std::collections::HashMap;
4use std::io::{Read, Seek, SeekFrom};
5
6use crate::asf::{AsfFile, AsfPayload, VideoStreamInfo};
7use crate::decoder::{MacroblockDecoder, YuvFrame};
8use crate::error::{DecoderError, Result};
9use crate::wma::{PcmFrameF32, WmaDecoder};
10use crate::wmv2::{Wmv2FrameHeader, Wmv2FrameType, Wmv2Params};
11
12#[derive(Clone)]
14pub struct DecodedFrame {
15 pub pts_ms: u32,
16 pub is_key_frame: bool,
17 pub frame: YuvFrame,
18}
19
20#[derive(Clone)]
22pub struct DecodedAudioFrame {
23 pub pts_ms: u32,
24 pub frame: PcmFrameF32,
25}
26
27pub struct Wmv2Decoder {
31 params: Wmv2Params,
32 mb_dec: MacroblockDecoder,
33 cur: YuvFrame,
34 locked_hdr_off: Option<usize>,
35}
36
37impl Wmv2Decoder {
38 pub fn new(width: u32, height: u32, extradata: &[u8]) -> Self {
42 let params = Wmv2Params::new(width, height);
43 let mut mb_dec = MacroblockDecoder::new(width, height);
44 mb_dec.wmv2_set_extradata(extradata);
45 let cur = YuvFrame::new(width, height);
46 Self {
47 params,
48 mb_dec,
49 cur,
50 locked_hdr_off: None,
51 }
52 }
53
54 pub fn width(&self) -> u32 {
55 self.params.width
56 }
57
58 pub fn height(&self) -> u32 {
59 self.params.height
60 }
61
62 pub fn current_frame(&self) -> &YuvFrame {
66 &self.cur
67 }
68
69
70 pub fn decode_frame(&mut self, payload: &[u8], is_key_frame: bool) -> Result<Option<&YuvFrame>> {
74 if payload.is_empty() {
75 return Ok(None);
76 }
77
78 let mut best_score: i64 = -1;
79 let mut best_off: usize = 0;
80 let mut best_hdr: Option<Wmv2FrameHeader> = None;
81
82 let mut offs: Vec<usize> = Vec::with_capacity(18);
84 if let Some(o) = self.locked_hdr_off {
85 offs.push(o);
86 }
87 for o in 0..=16 {
88 if Some(o) != self.locked_hdr_off {
89 offs.push(o);
90 }
91 }
92
93 for off in offs {
94 if off > payload.len() {
95 continue;
96 }
97 let cands = Wmv2FrameHeader::parse_candidates(&payload[off..], self.mb_dec.width_mb, self.mb_dec.height_mb);
98 if cands.is_empty() {
99 continue;
100 }
101 for h in cands {
102 if is_key_frame && h.frame_type != Wmv2FrameType::I {
104 continue;
105 }
106
107 let mut sc: i64 = if h.frame_skipped {
109 1
110 } else if is_key_frame {
111 2
112 } else {
113 self.mb_dec.probe_wmv2_payload(&payload[off..], &h) as i64
114 };
115
116 if Some(off) == self.locked_hdr_off {
117 sc += 64;
118 }
119
120 if sc > best_score {
121 best_score = sc;
122 best_off = off;
123 best_hdr = Some(h);
124 }
125 }
126 }
127
128 let Some(hdr) = best_hdr else {
129 return Ok(None);
130 };
131
132 if self.locked_hdr_off.is_none() {
133 self.locked_hdr_off = Some(best_off);
134 }
135
136 let frame_data = &payload[best_off..];
137 self.mb_dec.decode_wmv2_frame(frame_data, &hdr, &self.params, &mut self.cur)?;
138 Ok(Some(&self.cur))
139 }
140
141 pub fn decode_frame_owned(&mut self, payload: &[u8], is_key_frame: bool) -> Result<Option<YuvFrame>> {
143 let Some(f) = self.decode_frame(payload, is_key_frame)? else {
144 return Ok(None);
145 };
146 Ok(Some(f.clone()))
147 }
148}
149
150#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
155struct FrameKey {
156 stream_number: u8,
157 object_id: u32,
158}
159
160#[derive(Debug, Clone)]
161struct FrameAssembly {
162 total: usize,
163 pts_ms: u32,
164 is_key: bool,
165 data: Vec<u8>,
166 ranges: Vec<(usize, usize)>,
167}
168
169impl FrameAssembly {
170 fn new(total: usize, pts_ms: u32, is_key: bool) -> Self {
171 Self {
172 total,
173 pts_ms,
174 is_key,
175 data: vec![0u8; total],
176 ranges: Vec::new(),
177 }
178 }
179
180 fn insert(&mut self, offset: usize, frag: &[u8]) {
181 if self.total == 0 || offset >= self.total || frag.is_empty() {
182 return;
183 }
184 let end = (offset + frag.len()).min(self.total);
185 let n = end - offset;
186 self.data[offset..end].copy_from_slice(&frag[..n]);
187 self.add_range(offset, end);
188 }
189
190 fn add_range(&mut self, start: usize, end: usize) {
191 if start >= end {
192 return;
193 }
194 self.ranges.push((start, end));
195 self.ranges.sort_by_key(|r| r.0);
196
197 let mut merged: Vec<(usize, usize)> = Vec::with_capacity(self.ranges.len());
198 for (s, e) in self.ranges.drain(..) {
199 if let Some(last) = merged.last_mut() {
200 if s <= last.1 {
201 last.1 = last.1.max(e);
202 continue;
203 }
204 }
205 merged.push((s, e));
206 }
207 self.ranges = merged;
208 }
209
210 fn covered_len(&self) -> usize {
211 self.ranges.iter().map(|(s, e)| e - s).sum()
212 }
213
214 fn is_complete(&self) -> bool {
215 self.total > 0
216 && self.covered_len() >= self.total
217 && self.ranges.len() == 1
218 && self.ranges[0] == (0, self.total)
219 }
220}
221
222#[derive(Default)]
223struct FrameAssembler {
224 in_flight: HashMap<FrameKey, FrameAssembly>,
225}
226
227impl FrameAssembler {
228 fn push(&mut self, payload: AsfPayload) -> Option<(u32, bool, Vec<u8>)> {
229 if payload.data.is_empty() {
230 return None;
231 }
232
233 let key = FrameKey {
234 stream_number: payload.stream_number,
235 object_id: payload.object_id,
236 };
237
238 if payload.obj_offset == 0 {
240 let osz = payload.obj_size as usize;
241 if osz == 0 || osz == payload.data.len() {
242 return Some((payload.pts_ms, payload.is_key_frame, payload.data));
243 }
244 }
245
246 if payload.obj_size == 0 {
248 return Some((payload.pts_ms, payload.is_key_frame, payload.data));
249 }
250
251 let total = payload.obj_size as usize;
252 let entry = self
253 .in_flight
254 .entry(key)
255 .or_insert_with(|| FrameAssembly::new(total, payload.pts_ms, payload.is_key_frame));
256
257 entry.is_key |= payload.is_key_frame;
259 entry.insert(payload.obj_offset as usize, &payload.data);
260
261 if entry.is_complete() {
262 let assembly = self.in_flight.remove(&key).unwrap();
263 return Some((assembly.pts_ms, assembly.is_key, assembly.data));
264 }
265 None
266 }
267}
268
269pub struct AsfWmv2Decoder<R: Read + Seek> {
274 reader: R,
275 asf: AsfFile,
276 video_info: VideoStreamInfo,
277 assembler: FrameAssembler,
278 decoder: Wmv2Decoder,
279}
280
281pub struct AsfWmaDecoder<R: Read + Seek> {
286 reader: R,
287 asf: AsfFile,
288 audio_stream_number: u8,
289 decoder: WmaDecoder,
290 assembler: FrameAssembler,
291 last_pts_ms: u32,
292 flushed_eof: bool,
293}
294
295impl<R: Read + Seek> AsfWmaDecoder<R> {
296 pub fn open(mut reader: R) -> Result<Self> {
301 let asf = AsfFile::open(&mut reader)?;
302 let mut chosen = None;
303 for a in asf.audio_streams.iter() {
304 if matches!(a.format_tag, 0x0160 | 0x0161) {
305 chosen = Some(a.clone());
306 break;
307 }
308 }
309 let Some(audio_info) = chosen else {
310 return Err(DecoderError::Unsupported(
311 "No supported WMA (0x0160/0x0161) audio stream found".into(),
312 ));
313 };
314
315 reader.seek(SeekFrom::Start(asf.data_offset))?;
316 let decoder = WmaDecoder::new(&audio_info)?;
317
318 Ok(Self {
319 reader,
320 asf,
321 audio_stream_number: audio_info.stream_number,
322 decoder,
323 assembler: FrameAssembler::default(),
324 last_pts_ms: 0,
325 flushed_eof: false,
326 })
327 }
328
329 pub fn sample_rate(&self) -> u32 {
330 self.decoder.sample_rate()
331 }
332
333 pub fn channels(&self) -> u16 {
334 self.decoder.channels()
335 }
336
337 pub fn next_frame(&mut self) -> Result<Option<DecodedAudioFrame>> {
341 loop {
342 let payloads = match self.asf.read_packet(&mut self.reader) {
343 Ok(p) => p,
344 Err(DecoderError::EndOfStream) => {
345 if self.flushed_eof {
346 return Ok(None);
347 }
348 self.flushed_eof = true;
349 if let Some(frame) = self.decoder.decode_packet(&[], self.last_pts_ms)? {
350 return Ok(Some(DecodedAudioFrame {
351 pts_ms: frame.pts_ms,
352 frame,
353 }));
354 }
355 return Ok(None);
356 }
357 Err(e) => return Err(e),
358 };
359
360 for payload in payloads {
361 if payload.stream_number != self.audio_stream_number {
362 continue;
363 }
364 let Some((pts_ms, _is_key, data)) = self.assembler.push(payload) else {
365 continue;
366 };
367 self.last_pts_ms = pts_ms;
368 if let Some(frame) = self.decoder.decode_packet(&data, pts_ms)? {
369 return Ok(Some(DecodedAudioFrame { pts_ms, frame }));
370 }
371 }
372 }
373 }
374}
375
376impl<R: Read + Seek> AsfWmv2Decoder<R> {
377 pub fn open(mut reader: R) -> Result<Self> {
381 let asf = AsfFile::open(&mut reader)?;
382 let mut video_info: Option<VideoStreamInfo> = None;
383 for v in asf.video_streams.iter() {
384 let four_cc = std::str::from_utf8(&v.codec_four_cc)
385 .unwrap_or("")
386 .to_uppercase();
387 if matches!(four_cc.as_str(), "WMV2" | "WMV1") {
388 video_info = Some(v.clone());
389 break;
390 }
391 }
392 let Some(video_info) = video_info else {
393 return Err(DecoderError::Unsupported("No WMV2/WMV1 video stream found".into()));
394 };
395
396 reader.seek(SeekFrom::Start(asf.data_offset))?;
397
398 let decoder = Wmv2Decoder::new(video_info.width, video_info.height, &video_info.extra_data);
399
400 Ok(Self {
401 reader,
402 asf,
403 video_info,
404 assembler: FrameAssembler::default(),
405 decoder,
406 })
407 }
408
409 pub fn video_stream_info(&self) -> &VideoStreamInfo {
411 &self.video_info
412 }
413
414 pub fn next_frame(&mut self) -> Result<Option<DecodedFrame>> {
418 loop {
419 let payloads = match self.asf.read_packet(&mut self.reader) {
420 Ok(p) => p,
421 Err(DecoderError::EndOfStream) => return Ok(None),
422 Err(e) => return Err(e),
423 };
424
425 for payload in payloads {
426 if payload.stream_number != self.video_info.stream_number {
427 continue;
428 }
429 let Some((pts_ms, is_key, data)) = self.assembler.push(payload) else {
430 continue;
431 };
432
433 if let Some(frame) = self.decoder.decode_frame_owned(&data, is_key)? {
434 return Ok(Some(DecodedFrame {
435 pts_ms,
436 is_key_frame: is_key,
437 frame,
438 }));
439 }
440 }
441 }
442 }
443}