|
1 | 1 | use core::slice; |
| 2 | +use std::collections::BinaryHeap; |
2 | 3 | use std::ffi::{c_int, c_uchar}; |
3 | 4 | use std::fmt::Display; |
4 | 5 | use std::fs::File; |
@@ -192,13 +193,42 @@ impl OpenH264Codec { |
192 | 193 | } |
193 | 194 | } |
194 | 195 |
|
| 196 | +struct EnqueuedFrame { |
| 197 | + composition_time: i32, |
| 198 | + frame: DecodedFrame, |
| 199 | +} |
| 200 | + |
| 201 | +impl PartialEq for EnqueuedFrame { |
| 202 | + fn eq(&self, other: &Self) -> bool { |
| 203 | + self.composition_time == other.composition_time |
| 204 | + } |
| 205 | +} |
| 206 | + |
| 207 | +impl Eq for EnqueuedFrame {} |
| 208 | + |
| 209 | +impl Ord for EnqueuedFrame { |
| 210 | + fn cmp(&self, other: &Self) -> std::cmp::Ordering { |
| 211 | + // Note the reversal: BinaryHeap is a max-heap, but we always |
| 212 | + // want to pop the frame with the lowest timestamp. |
| 213 | + self.composition_time.cmp(&other.composition_time).reverse() |
| 214 | + } |
| 215 | +} |
| 216 | + |
| 217 | +impl PartialOrd for EnqueuedFrame { |
| 218 | + fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> { |
| 219 | + Some(self.cmp(other)) |
| 220 | + } |
| 221 | +} |
| 222 | + |
195 | 223 | /// H264 video decoder. |
196 | 224 | pub struct H264Decoder { |
197 | 225 | /// How many bytes are used to store the length of the NALU (1, 2, 3, or 4). |
198 | 226 | length_size: u8, |
199 | 227 |
|
200 | 228 | openh264: Arc<OpenH264>, |
201 | 229 | decoder: *mut ISVCDecoder, |
| 230 | + |
| 231 | + frame_reorder_queue: BinaryHeap<EnqueuedFrame>, |
202 | 232 | } |
203 | 233 |
|
204 | 234 | struct OpenH264Data { |
@@ -227,6 +257,7 @@ impl H264Decoder { |
227 | 257 | length_size: 0, |
228 | 258 | openh264, |
229 | 259 | decoder, |
| 260 | + frame_reorder_queue: BinaryHeap::new(), |
230 | 261 | } |
231 | 262 | } |
232 | 263 | } |
@@ -366,55 +397,77 @@ impl VideoDecoder for H264Decoder { |
366 | 397 | )); |
367 | 398 | } |
368 | 399 | if dest_buf_info.iBufferStatus != 1 { |
369 | | - return Err(Error::DecoderError( |
370 | | - "No output frame produced by the decoder".into(), |
371 | | - )); |
372 | | - } |
373 | | - let buffer_info = dest_buf_info.UsrData.sSystemBuffer; |
374 | | - if buffer_info.iFormat != videoFormatI420 as c_int { |
375 | | - return Err(Error::DecoderError( |
376 | | - format!("Unexpected output format: {}", buffer_info.iFormat).into(), |
377 | | - )); |
| 400 | + let ret = decoder_vtbl.FlushFrame.unwrap()( |
| 401 | + self.decoder, |
| 402 | + output.as_mut_ptr(), |
| 403 | + &mut dest_buf_info as *mut openh264_sys::SBufferInfo, |
| 404 | + ); |
| 405 | + |
| 406 | + if ret != 0 { |
| 407 | + return Err(Error::DecoderError( |
| 408 | + format!("Flushing failed with status code: {}", ret).into(), |
| 409 | + )); |
| 410 | + } |
378 | 411 | } |
379 | 412 |
|
380 | | - let mut yuv: Vec<u8> = Vec::with_capacity( |
381 | | - buffer_info.iWidth as usize * buffer_info.iHeight as usize * 3 / 2, |
382 | | - ); |
| 413 | + if dest_buf_info.iBufferStatus == 1 { |
| 414 | + let buffer_info = dest_buf_info.UsrData.sSystemBuffer; |
| 415 | + if buffer_info.iFormat != videoFormatI420 as c_int { |
| 416 | + return Err(Error::DecoderError( |
| 417 | + format!("Unexpected output format: {}", buffer_info.iFormat).into(), |
| 418 | + )); |
| 419 | + } |
383 | 420 |
|
384 | | - // Copying Y |
385 | | - for i in 0..buffer_info.iHeight { |
386 | | - yuv.extend_from_slice(slice::from_raw_parts( |
387 | | - output[0].offset((i * buffer_info.iStride[0]) as isize), |
388 | | - buffer_info.iWidth as usize, |
389 | | - )); |
390 | | - } |
| 421 | + let mut yuv: Vec<u8> = Vec::with_capacity( |
| 422 | + buffer_info.iWidth as usize * buffer_info.iHeight as usize * 3 / 2, |
| 423 | + ); |
391 | 424 |
|
392 | | - // Copying U |
393 | | - for i in 0..buffer_info.iHeight / 2 { |
394 | | - yuv.extend_from_slice(slice::from_raw_parts( |
395 | | - output[1].offset((i * buffer_info.iStride[1]) as isize), |
396 | | - buffer_info.iWidth as usize / 2, |
397 | | - )); |
398 | | - } |
| 425 | + // Copying Y |
| 426 | + for i in 0..buffer_info.iHeight { |
| 427 | + yuv.extend_from_slice(slice::from_raw_parts( |
| 428 | + output[0].offset((i * buffer_info.iStride[0]) as isize), |
| 429 | + buffer_info.iWidth as usize, |
| 430 | + )); |
| 431 | + } |
399 | 432 |
|
400 | | - // Copying V |
401 | | - for i in 0..buffer_info.iHeight / 2 { |
402 | | - yuv.extend_from_slice(slice::from_raw_parts( |
403 | | - output[2].offset((i * buffer_info.iStride[1]) as isize), |
404 | | - buffer_info.iWidth as usize / 2, |
405 | | - )); |
| 433 | + // Copying U |
| 434 | + for i in 0..buffer_info.iHeight / 2 { |
| 435 | + yuv.extend_from_slice(slice::from_raw_parts( |
| 436 | + output[1].offset((i * buffer_info.iStride[1]) as isize), |
| 437 | + buffer_info.iWidth as usize / 2, |
| 438 | + )); |
| 439 | + } |
| 440 | + |
| 441 | + // Copying V |
| 442 | + for i in 0..buffer_info.iHeight / 2 { |
| 443 | + yuv.extend_from_slice(slice::from_raw_parts( |
| 444 | + output[2].offset((i * buffer_info.iStride[1]) as isize), |
| 445 | + buffer_info.iWidth as usize / 2, |
| 446 | + )); |
| 447 | + } |
| 448 | + |
| 449 | + // TODO: Check whether frames are being squished/stretched, or cropped, |
| 450 | + // when encoded image size doesn't match declared video tag size. |
| 451 | + // NOTE: This will always use the BT.601 coefficients, which may or may |
| 452 | + // not be correct. So far I haven't seen anything to the contrary in FP. |
| 453 | + self.frame_reorder_queue.push(EnqueuedFrame { |
| 454 | + composition_time: encoded_frame |
| 455 | + .composition_time |
| 456 | + .ok_or(Error::DecoderError("No composition time provided".into()))?, |
| 457 | + frame: DecodedFrame::new( |
| 458 | + buffer_info.iWidth as u32, |
| 459 | + buffer_info.iHeight as u32, |
| 460 | + BitmapFormat::Yuv420p, |
| 461 | + yuv, |
| 462 | + ), |
| 463 | + }); |
406 | 464 | } |
407 | 465 |
|
408 | | - // TODO: Check whether frames are being squished/stretched, or cropped, |
409 | | - // when encoded image size doesn't match declared video tag size. |
410 | | - // NOTE: This will always use the BT.601 coefficients, which may or may |
411 | | - // not be correct. So far I haven't seen anything to the contrary in FP. |
412 | | - Ok(DecodedFrame::new( |
413 | | - buffer_info.iWidth as u32, |
414 | | - buffer_info.iHeight as u32, |
415 | | - BitmapFormat::Yuv420p, |
416 | | - yuv, |
417 | | - )) |
| 466 | + if self.frame_reorder_queue.len() >= 3 { |
| 467 | + Ok(self.frame_reorder_queue.pop().unwrap().frame) |
| 468 | + } else { |
| 469 | + Err(Error::DecoderError("Not enough frames decoded yet".into())) |
| 470 | + } |
418 | 471 | } |
419 | 472 | } |
420 | 473 | } |
0 commit comments