1use crate::error::NativeErrorExt;
52use crate::formats::yuv2rgb::{write_rgb8_f32x8, write_rgb8_scalar, write_rgba8_f32x8, write_rgba8_scalar};
53use crate::formats::{YUVSlices, YUVSource};
55use crate::{Error, OpenH264API, Timestamp};
56use openh264_sys2::{
57 API, DECODER_OPTION, DECODER_OPTION_ERROR_CON_IDC, DECODER_OPTION_NUM_OF_FRAMES_REMAINING_IN_BUFFER,
58 DECODER_OPTION_NUM_OF_THREADS, DECODER_OPTION_TRACE_LEVEL, DECODING_STATE, ISVCDecoder, ISVCDecoderVtbl, SBufferInfo,
59 SDecodingParam, SParserBsInfo, SSysMEMBuffer, SVideoProperty, TagBufferInfo, WELS_LOG_DETAIL, WELS_LOG_QUIET,
60 videoFormatI420,
61};
62use std::os::raw::{c_int, c_long, c_uchar, c_void};
63use std::ptr::{addr_of_mut, from_mut, null, null_mut};
64
65#[rustfmt::skip]
69#[allow(non_snake_case)]
70pub struct DecoderRawAPI {
71 api: OpenH264API,
72 decoder_ptr: *mut *const ISVCDecoderVtbl,
73 initialize: unsafe extern "C" fn(arg1: *mut ISVCDecoder, pParam: *const SDecodingParam) -> c_long,
74 uninitialize: unsafe extern "C" fn(arg1: *mut ISVCDecoder) -> c_long,
75 decode_frame: unsafe extern "C" fn(arg1: *mut ISVCDecoder, pSrc: *const c_uchar, iSrcLen: c_int, ppDst: *mut *mut c_uchar, pStride: *mut c_int, iWidth: *mut c_int, iHeight: *mut c_int) -> DECODING_STATE,
76 decode_frame_no_delay: unsafe extern "C" fn(arg1: *mut ISVCDecoder, pSrc: *const c_uchar, iSrcLen: c_int, ppDst: *mut *mut c_uchar, pDstInfo: *mut SBufferInfo) -> DECODING_STATE,
77 decode_frame2: unsafe extern "C" fn(arg1: *mut ISVCDecoder, pSrc: *const c_uchar, iSrcLen: c_int, ppDst: *mut *mut c_uchar, pDstInfo: *mut SBufferInfo) -> DECODING_STATE,
78 flush_frame: unsafe extern "C" fn(arg1: *mut ISVCDecoder, ppDst: *mut *mut c_uchar, pDstInfo: *mut SBufferInfo) -> DECODING_STATE,
79 decode_parser: unsafe extern "C" fn(arg1: *mut ISVCDecoder, pSrc: *const c_uchar, iSrcLen: c_int, pDstInfo: *mut SParserBsInfo) -> DECODING_STATE,
80 decode_frame_ex: unsafe extern "C" fn(arg1: *mut ISVCDecoder, pSrc: *const c_uchar, iSrcLen: c_int, pDst: *mut c_uchar, iDstStride: c_int, iDstLen: *mut c_int, iWidth: *mut c_int, iHeight: *mut c_int, iColorFormat: *mut c_int) -> DECODING_STATE,
81 set_option: unsafe extern "C" fn(arg1: *mut ISVCDecoder, eOptionId: DECODER_OPTION, pOption: *mut c_void) -> c_long,
82 get_option: unsafe extern "C" fn(arg1: *mut ISVCDecoder, eOptionId: DECODER_OPTION, pOption: *mut c_void) -> c_long,
83}
84
85#[rustfmt::skip]
86#[allow(clippy::too_many_arguments)]
87#[allow(clippy::missing_safety_doc)]
88#[allow(non_snake_case, unused, missing_docs)]
89impl DecoderRawAPI {
90 fn new(api: OpenH264API) -> Result<Self, Error> {
91 unsafe {
92 let mut decoder_ptr = null::<ISVCDecoderVtbl>() as *mut *const ISVCDecoderVtbl;
93
94 api.WelsCreateDecoder(from_mut(&mut decoder_ptr)).ok()?;
95
96 let e = || {
97 Error::msg("VTable missing function.")
98 };
99
100 Ok(Self {
101 api,
102 decoder_ptr,
103 initialize: (*(*decoder_ptr)).Initialize.ok_or_else(e)?,
104 uninitialize: (*(*decoder_ptr)).Uninitialize.ok_or_else(e)?,
105 decode_frame: (*(*decoder_ptr)).DecodeFrame.ok_or_else(e)?,
106 decode_frame_no_delay: (*(*decoder_ptr)).DecodeFrameNoDelay.ok_or_else(e)?,
107 decode_frame2: (*(*decoder_ptr)).DecodeFrame2.ok_or_else(e)?,
108 flush_frame: (*(*decoder_ptr)).FlushFrame.ok_or_else(e)?,
109 decode_parser: (*(*decoder_ptr)).DecodeParser.ok_or_else(e)?,
110 decode_frame_ex: (*(*decoder_ptr)).DecodeFrameEx.ok_or_else(e)?,
111 set_option: (*(*decoder_ptr)).SetOption.ok_or_else(e)?,
112 get_option: (*(*decoder_ptr)).GetOption.ok_or_else(e)?,
113 })
114 }
115 }
116
117 unsafe fn initialize(&self, pParam: *const SDecodingParam) -> c_long { unsafe { (self.initialize)(self.decoder_ptr, pParam) }}
119 unsafe fn uninitialize(&self, ) -> c_long { unsafe { (self.uninitialize)(self.decoder_ptr) }}
120
121 pub unsafe fn decode_frame(&self, Src: *const c_uchar, iSrcLen: c_int, ppDst: *mut *mut c_uchar, pStride: *mut c_int, iWidth: *mut c_int, iHeight: *mut c_int) -> DECODING_STATE { unsafe { (self.decode_frame)(self.decoder_ptr, Src, iSrcLen, ppDst, pStride, iWidth, iHeight) }}
122 pub unsafe fn decode_frame_no_delay(&self, pSrc: *const c_uchar, iSrcLen: c_int, ppDst: *mut *mut c_uchar, pDstInfo: *mut SBufferInfo) -> DECODING_STATE { unsafe { (self.decode_frame_no_delay)(self.decoder_ptr, pSrc, iSrcLen, ppDst, pDstInfo) }}
123 pub unsafe fn decode_frame2(&self, pSrc: *const c_uchar, iSrcLen: c_int, ppDst: *mut *mut c_uchar, pDstInfo: *mut SBufferInfo) -> DECODING_STATE { unsafe { (self.decode_frame2)(self.decoder_ptr, pSrc, iSrcLen, ppDst, pDstInfo) }}
124 pub unsafe fn flush_frame(&self, ppDst: *mut *mut c_uchar, pDstInfo: *mut SBufferInfo) -> DECODING_STATE { unsafe { (self.flush_frame)(self.decoder_ptr, ppDst, pDstInfo) }}
125 pub unsafe fn decode_parser(&self, pSrc: *const c_uchar, iSrcLen: c_int, pDstInfo: *mut SParserBsInfo) -> DECODING_STATE { unsafe { (self.decode_parser)(self.decoder_ptr, pSrc, iSrcLen, pDstInfo) }}
126 pub unsafe fn decode_frame_ex(&self, pSrc: *const c_uchar, iSrcLen: c_int, pDst: *mut c_uchar, iDstStride: c_int, iDstLen: *mut c_int, iWidth: *mut c_int, iHeight: *mut c_int, iColorFormat: *mut c_int) -> DECODING_STATE { unsafe { (self.decode_frame_ex)(self.decoder_ptr, pSrc, iSrcLen, pDst, iDstStride, iDstLen, iWidth, iHeight, iColorFormat) }}
127 pub unsafe fn set_option(&self, eOptionId: DECODER_OPTION, pOption: *mut c_void) -> c_long { unsafe { (self.set_option)(self.decoder_ptr, eOptionId, pOption) }}
128 pub unsafe fn get_option(&self, eOptionId: DECODER_OPTION, pOption: *mut c_void) -> c_long { unsafe { (self.get_option)(self.decoder_ptr, eOptionId, pOption) }}
129}
130
131impl Drop for DecoderRawAPI {
132 fn drop(&mut self) {
133 unsafe {
135 self.api.WelsDestroyDecoder(self.decoder_ptr);
136 }
137 }
138}
139
140unsafe impl Send for DecoderRawAPI {}
141unsafe impl Sync for DecoderRawAPI {}
142
143#[derive(Default, Copy, Clone, Debug, Eq, PartialEq)]
152pub enum Flush {
153 #[default]
155 Auto,
156 Flush,
158 NoFlush,
160}
161
162impl Flush {
163 #[allow(clippy::match_same_arms)]
166 #[allow(clippy::needless_pass_by_value)]
167 const fn should_flush(self, decoder_options: DecodeOptions) -> bool {
168 match (self, decoder_options.flush_after_decode) {
169 (Self::Auto, Self::Auto) => true,
170 (Self::NoFlush, Self::Auto) => false,
171 (Self::Flush, Self::Auto) => true,
172 (_, Self::NoFlush) => false,
173 (_, Self::Flush) => true,
174 }
175 }
176}
177
178#[derive(Default, Copy, Clone, Debug)]
182#[must_use]
183pub struct DecoderConfig {
184 params: SDecodingParam,
185 num_threads: DECODER_OPTION,
186 debug: DECODER_OPTION,
187 error_concealment: DECODER_OPTION,
188 flush_after_decode: Flush,
189}
190
191unsafe impl Send for DecoderConfig {}
192unsafe impl Sync for DecoderConfig {}
193
194impl DecoderConfig {
195 pub const fn new() -> Self {
197 Self {
198 params: SDecodingParam {
199 pFileNameRestructed: null_mut(),
200 uiCpuLoad: 0,
201 uiTargetDqLayer: 0,
202 eEcActiveIdc: 0,
203 bParseOnly: false,
204 sVideoProperty: SVideoProperty {
205 size: 0,
206 eVideoBsType: 0,
207 },
208 },
209 num_threads: 0,
210 debug: WELS_LOG_QUIET,
211 error_concealment: 0,
212 flush_after_decode: Flush::Flush,
213 }
214 }
215
216 pub const unsafe fn num_threads(mut self, num_threads: u32) -> Self {
227 self.num_threads = num_threads as i32;
228 self
229 }
230
231 pub const fn debug(mut self, value: bool) -> Self {
233 self.debug = if value { WELS_LOG_DETAIL } else { WELS_LOG_QUIET };
234 self
235 }
236
237 pub const fn flush_after_decode(mut self, flush_behavior: Flush) -> Self {
239 self.flush_after_decode = flush_behavior;
240 self
241 }
242}
243
244#[derive(Default, Clone, Debug, Eq, PartialEq)]
246pub struct DecodeOptions {
247 flush_after_decode: Flush,
248}
249
250impl DecodeOptions {
251 #[must_use]
253 pub const fn new() -> Self {
254 Self {
255 flush_after_decode: Flush::Auto,
256 }
257 }
258
259 #[must_use]
261 pub const fn flush_after_decode(mut self, value: Flush) -> Self {
262 self.flush_after_decode = value;
263 self
264 }
265}
266
267pub struct Decoder {
269 raw_api: DecoderRawAPI,
270 config: DecoderConfig,
271}
272
273impl Decoder {
274 #[cfg(feature = "source")]
283 pub fn new() -> Result<Self, Error> {
284 let api = OpenH264API::from_source();
285 Self::with_api_config(api, DecoderConfig::new())
286 }
287
288 pub fn with_api_config(api: OpenH264API, mut config: DecoderConfig) -> Result<Self, Error> {
294 let raw_api = DecoderRawAPI::new(api)?;
295
296 #[rustfmt::skip]
299 unsafe {
300 raw_api.initialize(&raw const config.params).ok()?;
301 raw_api.set_option(DECODER_OPTION_TRACE_LEVEL, addr_of_mut!(config.debug).cast()).ok()?;
302 raw_api.set_option(DECODER_OPTION_NUM_OF_THREADS, addr_of_mut!(config.num_threads).cast()).ok()?;
303 raw_api.set_option(DECODER_OPTION_ERROR_CON_IDC, addr_of_mut!(config.error_concealment).cast()).ok()?;
304 };
305
306 Ok(Self { raw_api, config })
307 }
308
309 pub fn decode(&mut self, packet: &[u8]) -> Result<Option<DecodedYUV<'_>>, Error> {
317 self.decode_with_options(packet, DecodeOptions::default())
318 }
319
320 pub fn decode_with_options(&mut self, packet: &[u8], options: DecodeOptions) -> Result<Option<DecodedYUV<'_>>, Error> {
342 let mut dst = [null_mut::<u8>(); 3];
343 let mut buffer_info = SBufferInfo::default();
344 let flush = self.config.flush_after_decode.should_flush(options);
345
346 unsafe {
347 self.raw_api
348 .decode_frame_no_delay(
349 packet.as_ptr(),
350 packet.len() as i32,
351 from_mut(&mut dst).cast(),
352 &raw mut buffer_info,
353 )
354 .ok()?;
355 }
356
357 match (buffer_info.iBufferStatus, flush) {
358 (0, true) if self.num_frames_in_buffer()? > 0 => {
360 let (dst, buffer_info) = self.flush_single_frame_raw()?;
361
362 if buffer_info.iBufferStatus == 0 {
363 return Err(Error::msg(
364 "Buffer status invalid, we have outstanding frames but failed to flush them.",
365 ));
366 }
367
368 unsafe { Ok(DecodedYUV::from_raw_open264_ptrs(&dst, &buffer_info)) }
369 }
370 (0, _) => Ok(None),
372 _ => unsafe { Ok(DecodedYUV::from_raw_open264_ptrs(&dst, &buffer_info)) },
374 }
375 }
376
377 pub fn flush_remaining(&'_ mut self) -> Result<Vec<DecodedYUV<'_>>, Error> {
385 let mut frames = Vec::new();
386
387 for _ in 0..self.num_frames_in_buffer()? {
388 let (dst, buffer_info) = self.flush_single_frame_raw()?;
389
390 if let Some(image) = unsafe { DecodedYUV::from_raw_open264_ptrs(&dst, &buffer_info) } {
391 frames.push(image);
392 }
393 }
394
395 Ok(frames)
396 }
397
398 pub const unsafe fn raw_api(&mut self) -> &mut DecoderRawAPI {
425 &mut self.raw_api
426 }
427
428 fn num_frames_in_buffer(&mut self) -> Result<usize, Error> {
430 let mut num_frames: DECODER_OPTION = 0;
431 unsafe {
432 self.raw_api()
433 .get_option(
434 DECODER_OPTION_NUM_OF_FRAMES_REMAINING_IN_BUFFER,
435 addr_of_mut!(num_frames).cast(),
436 )
437 .ok()?;
438 }
439
440 Ok(num_frames as usize)
441 }
442
443 fn flush_single_frame_raw(&mut self) -> Result<([*mut u8; 3], TagBufferInfo), Error> {
445 let mut dst = [null_mut::<u8>(); 3];
446 let mut buffer_info = SBufferInfo::default();
447
448 unsafe {
449 self.raw_api()
450 .flush_frame(from_mut(&mut dst).cast(), &raw mut buffer_info)
451 .ok()?;
452 Ok((dst, buffer_info))
453 }
454 }
455}
456
457impl Drop for Decoder {
458 fn drop(&mut self) {
459 unsafe {
461 self.raw_api.uninitialize();
462 }
463 }
464}
465
466#[derive(Debug)]
468pub struct DecodedYUV<'a> {
469 info: SSysMEMBuffer,
470 timestamp: Timestamp,
471
472 y: &'a [u8],
473 u: &'a [u8],
474 v: &'a [u8],
475}
476
477impl DecodedYUV<'_> {
478 const unsafe fn from_raw_open264_ptrs(dst: &[*mut u8; 3], buffer_info: &TagBufferInfo) -> Option<Self> {
483 unsafe {
484 let info = buffer_info.UsrData.sSystemBuffer;
485 let timestamp = Timestamp::from_millis(buffer_info.uiInBsTimeStamp); if dst[0].is_null() || dst[1].is_null() || dst[2].is_null() {
490 None
491 } else {
492 let y = std::slice::from_raw_parts(dst[0], (info.iHeight * info.iStride[0]) as usize);
494 let u = std::slice::from_raw_parts(dst[1], (info.iHeight * info.iStride[1] / 2) as usize);
495 let v = std::slice::from_raw_parts(dst[2], (info.iHeight * info.iStride[1] / 2) as usize);
496
497 Some(Self {
498 info,
499 timestamp,
500 y,
501 u,
502 v,
503 })
504 }
505 }
506 }
507
508 #[must_use]
512 pub const fn dimensions_uv(&self) -> (usize, usize) {
513 (self.info.iWidth as usize / 2, self.info.iHeight as usize / 2)
514 }
515
516 #[must_use]
518 pub const fn timestamp(&self) -> Timestamp {
519 self.timestamp
520 }
521
522 pub fn split<const N: usize>(&'_ self) -> [YUVSlices<'_>; N] {
526 if N == 1 {
527 return [YUVSlices::new((self.y, self.u, self.v), self.dimensions(), self.strides()); N];
528 }
529
530 let y_chunks: Vec<&[u8]> = self.y.chunks(self.y.len() / N).collect();
531 let u_chunks: Vec<&[u8]> = self.u.chunks(self.u.len() / N).collect();
532 let v_chunks: Vec<&[u8]> = self.v.chunks(self.v.len() / N).collect();
533
534 let mut parts = [YUVSlices::new((self.y, self.u, self.v), self.dimensions(), self.strides()); N];
535 for i in 0..N {
536 parts[i] = YUVSlices::new(
537 (y_chunks[i], u_chunks[i], v_chunks[i]),
538 (self.dimensions().0, self.info.iHeight as usize / N),
539 self.strides(),
540 );
541 }
542
543 parts
544 }
545
546 #[allow(clippy::unnecessary_cast)]
553 pub fn write_rgb8(&self, target: &mut [u8]) {
554 let dim = self.dimensions();
555 let strides = self.strides();
556 let wanted = dim.0 * dim.1 * 3;
557
558 assert_eq!(self.info.iFormat, videoFormatI420 as i32);
560 assert_eq!(
561 target.len(),
562 wanted,
563 "Target RGB8 array does not match image dimensions. Wanted: {} * {} * 3 = {}, got {}",
564 dim.0,
565 dim.1,
566 wanted,
567 target.len()
568 );
569
570 if dim.0 % 8 == 0 && dim.1 >= 2 {
574 write_rgb8_f32x8(self.y, self.u, self.v, dim, strides, target);
575 } else {
576 write_rgb8_scalar(self.y, self.u, self.v, dim, strides, target);
577 }
578 }
579
580 #[allow(clippy::unnecessary_cast)]
587 pub fn write_rgba8(&self, target: &mut [u8]) {
588 let dim = self.dimensions();
589 let strides = self.strides();
590 let wanted = dim.0 * dim.1 * 4;
591
592 assert_eq!(self.info.iFormat, videoFormatI420 as i32);
594 assert_eq!(
595 target.len(),
596 wanted,
597 "Target RGBA8 array does not match image dimensions. Wanted: {} * {} * 4 = {}, got {}",
598 dim.0,
599 dim.1,
600 wanted,
601 target.len()
602 );
603 if dim.0 % 8 == 0 && dim.1 >= 2 {
607 write_rgba8_f32x8(self.y, self.u, self.v, dim, strides, target);
608 } else {
609 write_rgba8_scalar(self.y, self.u, self.v, dim, strides, target);
610 }
611 }
612}
613
614impl YUVSource for DecodedYUV<'_> {
615 fn dimensions_i32(&self) -> (i32, i32) {
616 (self.info.iWidth, self.info.iHeight)
617 }
618
619 fn dimensions(&self) -> (usize, usize) {
620 (self.info.iWidth as usize, self.info.iHeight as usize)
621 }
622
623 fn strides(&self) -> (usize, usize, usize) {
624 (
626 self.info.iStride[0] as usize,
627 self.info.iStride[1] as usize,
628 self.info.iStride[1] as usize,
629 )
630 }
631
632 fn strides_i32(&self) -> (i32, i32, i32) {
633 (self.info.iStride[0], self.info.iStride[1], self.info.iStride[1])
635 }
636
637 fn y(&self) -> &[u8] {
638 self.y
639 }
640
641 fn u(&self) -> &[u8] {
642 self.u
643 }
644
645 fn v(&self) -> &[u8] {
646 self.v
647 }
648}
649
650#[cfg(test)]
651mod test {
652 use openh264_sys2::SSysMEMBuffer;
653
654 use crate::{
655 Timestamp,
656 formats::{YUVSlices, YUVSource},
657 };
658
659 use super::DecodedYUV;
660
661 macro_rules! yuv420_planes {
665 (y_stride: $y_stride:literal, height: $height:literal) => {{
666 let numbers = (0..u32::MAX).map(|i| (i % 256) as u8);
668
669 let y_plane_len = ($y_stride * $height) as usize;
670 let y = numbers.clone().take(y_plane_len).collect::<Vec<_>>();
671
672 let uv_plane_len = ($y_stride * $height / 4) as usize;
674 let u = numbers.clone().take(uv_plane_len).collect::<Vec<_>>();
675 let v = numbers.clone().take(uv_plane_len).collect::<Vec<_>>();
676
677 (y, u, v)
678 }};
679 }
680
681 macro_rules! decoded_yuv420 {
685 (y_stride: $y_stride:literal, dim: ($width:literal, $height:literal), $y:expr, $u:expr, $v:expr) => {
686 DecodedYUV {
687 info: SSysMEMBuffer {
688 iWidth: $width,
689 iHeight: $height,
690 iFormat: 23,
692 iStride: [$y_stride as i32, $y_stride / 2 as i32],
693 },
694 timestamp: Timestamp::ZERO,
695 y: $y,
696 u: $u,
697 v: $v,
698 }
699 };
700 }
701
702 #[test]
703 fn test_split_01() {
704 let (y, u, v) = yuv420_planes!(y_stride: 4, height: 4);
706 let buf = decoded_yuv420!(y_stride: 4, dim: (4, 4), &y, &u, &v);
707
708 let parts: [YUVSlices; 1] = buf.split();
709 assert_eq!(1, parts.len());
710 assert_eq!(parts[0].y(), y.as_slice());
711 assert_eq!(parts[0].u(), u.as_slice());
712 assert_eq!(parts[0].v(), v.as_slice());
713 }
714
715 #[test]
716 fn test_split_02() {
717 let (y, u, v) = yuv420_planes!(y_stride: 132, height: 128);
718 let buf = decoded_yuv420!(y_stride: 132, dim: (128, 128), &y, &u, &v);
719
720 let parts: [YUVSlices; 4] = buf.split();
721
722 let (mut y_plane, mut u_plane, mut v_plane) = (vec![], vec![], vec![]);
723 for slice in parts {
724 y_plane.extend_from_slice(slice.y());
725 u_plane.extend_from_slice(slice.u());
726 v_plane.extend_from_slice(slice.v());
727 }
728
729 assert_eq!(buf.y().len(), y_plane.len());
730 assert_eq!(buf.y(), y_plane);
731 assert_eq!(buf.u().len(), u_plane.len());
732 assert_eq!(buf.u(), u_plane);
733 assert_eq!(buf.v().len(), v_plane.len());
734 assert_eq!(buf.v(), v_plane);
735 }
736}