use hbb_common::anyhow::Error; use hbb_common::{bail, ResultType}; use ndk::media::media_codec::{MediaCodec, MediaCodecDirection, MediaFormat}; use std::ops::Deref; use std::{ io::Write, sync::atomic::{AtomicBool, Ordering}, time::Duration, }; use crate::{ codec::{EncoderApi, EncoderCfg}, I420ToARGB, }; /// MediaCodec mime type name const H264_MIME_TYPE: &str = "video/avc"; const H265_MIME_TYPE: &str = "video/hevc"; // const VP8_MIME_TYPE: &str = "video/x-vnd.on2.vp8"; // const VP9_MIME_TYPE: &str = "video/x-vnd.on2.vp9"; // TODO MediaCodecEncoder pub static H264_DECODER_SUPPORT: AtomicBool = AtomicBool::new(false); pub static H265_DECODER_SUPPORT: AtomicBool = AtomicBool::new(false); pub struct MediaCodecDecoder { decoder: MediaCodec, name: String, } impl Deref for MediaCodecDecoder { type Target = MediaCodec; fn deref(&self) -> &Self::Target { &self.decoder } } #[derive(Default)] pub struct MediaCodecDecoders { pub h264: Option, pub h265: Option, } impl MediaCodecDecoder { pub fn new_decoders() -> MediaCodecDecoders { let h264 = create_media_codec(H264_MIME_TYPE, MediaCodecDirection::Decoder); let h265 = create_media_codec(H265_MIME_TYPE, MediaCodecDirection::Decoder); MediaCodecDecoders { h264, h265 } } pub fn decode(&mut self, data: &[u8], rgb: &mut Vec) -> ResultType { match self.dequeue_input_buffer(Duration::from_millis(10))? { Some(mut input_buffer) => { let mut buf = input_buffer.buffer_mut(); if data.len() > buf.len() { log::error!("Failed to decode, the input data size is bigger than input buf"); bail!("The input data size is bigger than input buf"); } buf.write_all(&data)?; self.queue_input_buffer(input_buffer, 0, data.len(), 0, 0)?; } None => { log::debug!("Failed to dequeue_input_buffer: No available input_buffer"); } }; return match self.dequeue_output_buffer(Duration::from_millis(100))? { Some(output_buffer) => { let res_format = self.output_format(); let w = res_format .i32("width") .ok_or(Error::msg("Failed to dequeue_output_buffer, width is None"))? as usize; let h = res_format.i32("height").ok_or(Error::msg( "Failed to dequeue_output_buffer, height is None", ))? as usize; let stride = res_format.i32("stride").ok_or(Error::msg( "Failed to dequeue_output_buffer, stride is None", ))?; let buf = output_buffer.buffer(); let bps = 4; let u = buf.len() * 2 / 3; let v = buf.len() * 5 / 6; rgb.resize(h * w * bps, 0); let y_ptr = buf.as_ptr(); let u_ptr = buf[u..].as_ptr(); let v_ptr = buf[v..].as_ptr(); unsafe { I420ToARGB( y_ptr, stride, u_ptr, stride / 2, v_ptr, stride / 2, rgb.as_mut_ptr(), (w * bps) as _, w as _, h as _, ); } self.release_output_buffer(output_buffer, false)?; Ok(true) } None => { log::debug!("Failed to dequeue_output: No available dequeue_output"); Ok(false) } }; } } fn create_media_codec(name: &str, direction: MediaCodecDirection) -> Option { let codec = MediaCodec::from_decoder_type(name)?; let media_format = MediaFormat::new(); media_format.set_str("mime", name); media_format.set_i32("width", 0); media_format.set_i32("height", 0); media_format.set_i32("color-format", 19); // COLOR_FormatYUV420Planar if let Err(e) = codec.configure(&media_format, None, direction) { log::error!("Failed to init decoder:{:?}", e); return None; }; log::error!("decoder init success"); if let Err(e) = codec.start() { log::error!("Failed to start decoder:{:?}", e); return None; }; log::debug!("Init decoder successed!: {:?}", name); return Some(MediaCodecDecoder { decoder: codec, name: name.to_owned(), }); } pub fn check_mediacodec() { std::thread::spawn(move || { // check decoders let decoders = MediaCodecDecoder::new_decoders(); H264_DECODER_SUPPORT.swap(decoders.h264.is_some(), Ordering::SeqCst); H265_DECODER_SUPPORT.swap(decoders.h265.is_some(), Ordering::SeqCst); decoders.h264.map(|d| d.stop()); decoders.h265.map(|d| d.stop()); // TODO encoders }); }