|
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