fufesou 77c4a14845 flutter texture render, mid commit
Signed-off-by: fufesou <shuanglongchen@yeah.net>
2023-02-23 17:06:51 +08:00

171 lines
6.0 KiB
Rust

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::ImageFormat;
use crate::{
codec::{EncoderApi, EncoderCfg},
I420ToABGR, 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<MediaCodecDecoder>,
pub h265: Option<MediaCodecDecoder>,
}
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], fmt: ImageFormat, raw: &mut Vec<u8>) -> ResultType<bool> {
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;
raw.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 {
match fmt {
ImageFormat::ARGB => {
I420ToARGB(
y_ptr,
stride,
u_ptr,
stride / 2,
v_ptr,
stride / 2,
raw.as_mut_ptr(),
(w * bps) as _,
w as _,
h as _,
);
}
ImageFormat::ARGB => {
I420ToABGR(
y_ptr,
stride,
u_ptr,
stride / 2,
v_ptr,
stride / 2,
raw.as_mut_ptr(),
(w * bps) as _,
w as _,
h as _,
);
}
_ => {
bail!("Unsupported image format");
}
}
}
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<MediaCodecDecoder> {
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
});
}