del: 移除安卓支持

This commit is contained in:
mofeng-git
2026-07-14 21:01:47 +08:00
parent 139064de35
commit 1ded7a8a66
88 changed files with 299 additions and 7107 deletions

View File

@@ -1,122 +0,0 @@
//! Android FFmpeg/MediaCodec encoder glue.
use bytes::Bytes;
use hwcodec::common::{Quality, RateControl};
use hwcodec::ffmpeg::{resolve_pixel_format, AVPixelFormat};
use hwcodec::ffmpeg_ram::encode::{EncodeContext, Encoder as HwEncoder};
use crate::error::{AppError, Result};
use crate::video::format::{PixelFormat, Resolution};
pub struct AndroidMediaCodecH264Encoder {
inner: HwEncoder,
resolution: Resolution,
input_format: PixelFormat,
bitrate_kbps: u32,
}
impl AndroidMediaCodecH264Encoder {
pub fn new(
resolution: Resolution,
input_format: PixelFormat,
fps: u32,
bitrate_kbps: u32,
) -> Result<Self> {
let pixfmt = match input_format {
PixelFormat::Nv12 => resolve_pixel_format("nv12", AVPixelFormat::AV_PIX_FMT_NV12),
PixelFormat::Yuv420 => {
resolve_pixel_format("yuv420p", AVPixelFormat::AV_PIX_FMT_YUV420P)
}
other => {
return Err(AppError::VideoError(format!(
"FFmpeg h264_mediacodec accepts NV12/YUV420P memory frames; {other} requires conversion first"
)))
}
};
let ctx = EncodeContext {
name: "h264_mediacodec".to_string(),
mc_name: None,
width: resolution.width as i32,
height: resolution.height as i32,
pixfmt,
align: 1,
fps: fps.max(1) as i32,
gop: fps.max(1) as i32,
rc: RateControl::RC_CBR,
quality: Quality::Quality_Low,
kbs: bitrate_kbps.max(1) as i32,
q: 23,
thread_count: 1,
};
let inner = HwEncoder::new(ctx).map_err(|_| {
AppError::VideoError("Failed to create FFmpeg h264_mediacodec encoder".to_string())
})?;
Ok(Self {
inner,
resolution,
input_format,
bitrate_kbps: bitrate_kbps.max(1),
})
}
pub fn encode_raw(&mut self, data: &[u8], pts_ms: i64) -> Result<Vec<AndroidH264Packet>> {
let min_len = self
.input_format
.frame_size(self.resolution)
.ok_or_else(|| AppError::VideoError("MediaCodec input must be raw YUV".to_string()))?;
if data.len() < min_len {
return Err(AppError::VideoError(format!(
"MediaCodec {} frame too small: {} < {}",
self.input_format,
data.len(),
min_len
)));
}
let packets = self
.inner
.encode_bytes(data, pts_ms)
.map_err(|err| AppError::VideoError(format!("h264_mediacodec encode failed: {err}")))?;
Ok(packets
.into_iter()
.map(|packet| AndroidH264Packet {
data: packet.data,
pts: packet.pts,
key_frame: packet.key == 1,
})
.collect())
}
pub fn set_bitrate(&mut self, bitrate_kbps: u32) -> Result<()> {
self.inner
.set_bitrate(bitrate_kbps.max(1) as i32)
.map_err(|_| AppError::VideoError("Failed to set MediaCodec bitrate".to_string()))?;
self.bitrate_kbps = bitrate_kbps.max(1);
Ok(())
}
pub fn request_keyframe(&mut self) {
self.inner.request_keyframe();
}
pub fn codec_name(&self) -> &str {
"h264_mediacodec"
}
pub fn input_format(&self) -> PixelFormat {
self.input_format
}
}
unsafe impl Send for AndroidMediaCodecH264Encoder {}
#[derive(Debug, Clone)]
pub struct AndroidH264Packet {
pub data: Bytes,
pub pts: i64,
pub key_frame: bool,
}

View File

@@ -1,137 +0,0 @@
//! Android FFmpeg/MediaCodec MJPEG decoder glue.
use hwcodec::ffmpeg::AVPixelFormat;
use hwcodec::ffmpeg_ram::decode::{DecodeContext, Decoder};
use tracing::{info, warn};
use crate::error::{AppError, Result};
use crate::video::codec::convert::Nv12Converter;
use crate::video::format::{PixelFormat, Resolution};
pub struct AndroidMediaCodecMjpegDecoder {
decoder: Decoder,
resolution: Resolution,
nv12_converter: Option<Nv12Converter>,
last_output_format: Option<PixelFormat>,
pending_frames: u32,
}
impl AndroidMediaCodecMjpegDecoder {
pub fn new(resolution: Resolution) -> Result<Self> {
let ctx = DecodeContext {
name: "mjpeg_mediacodec".to_string(),
width: resolution.width as i32,
height: resolution.height as i32,
sw_pixfmt: AVPixelFormat::AV_PIX_FMT_NV12,
thread_count: 1,
};
let decoder = Decoder::new(ctx).map_err(|_| {
AppError::VideoError("Failed to create FFmpeg mjpeg_mediacodec decoder".to_string())
})?;
Ok(Self {
decoder,
resolution,
nv12_converter: None,
last_output_format: None,
pending_frames: 0,
})
}
pub fn decode_to_nv12(&mut self, mjpeg: &[u8]) -> Result<Vec<u8>> {
let frames = match self.decoder.decode(mjpeg) {
Ok(frames) => frames,
Err(err) if err == -11 => {
self.pending_frames += 1;
if self.pending_frames <= 3 {
return Err(AppError::VideoError(
"mjpeg_mediacodec decode needs more input".to_string(),
));
}
return Err(AppError::VideoError(
"mjpeg_mediacodec decoder did not output after 3 frames".to_string(),
));
}
Err(err) => {
return Err(AppError::VideoError(format!(
"mjpeg_mediacodec decode failed: {err}"
)));
}
};
if frames.is_empty() {
self.pending_frames += 1;
if self.pending_frames <= 3 {
return Err(AppError::VideoError(
"mjpeg_mediacodec decode needs more input".to_string(),
));
}
return Err(AppError::VideoError(
"mjpeg_mediacodec decoder did not output after 3 frames".to_string(),
));
}
self.pending_frames = 0;
if frames.len() > 1 {
warn!(
"mjpeg_mediacodec decode returned {} frames, using last",
frames.len()
);
}
let frame = frames.pop().ok_or_else(|| {
AppError::VideoError("mjpeg_mediacodec decode returned empty".to_string())
})?;
if frame.width as u32 != self.resolution.width
|| frame.height as u32 != self.resolution.height
{
warn!(
"mjpeg_mediacodec output size {}x{} differs from expected {}x{}",
frame.width, frame.height, self.resolution.width, self.resolution.height
);
}
let output_format = pixel_format_from_av(frame.pixfmt).ok_or_else(|| {
AppError::VideoError(format!(
"mjpeg_mediacodec output pixfmt {:?} is not supported",
frame.pixfmt
))
})?;
if self.last_output_format != Some(output_format) {
info!("mjpeg_mediacodec output format: {}", output_format);
self.last_output_format = Some(output_format);
}
match output_format {
PixelFormat::Nv12 => Ok(frame.data),
PixelFormat::Nv21 => {
let converter = self
.nv12_converter
.get_or_insert_with(|| Nv12Converter::nv21_to_nv12(self.resolution));
Ok(converter.convert(&frame.data)?.to_vec())
}
PixelFormat::Yuv420 => {
let converter = self
.nv12_converter
.get_or_insert_with(|| Nv12Converter::yuv420_to_nv12(self.resolution));
Ok(converter.convert(&frame.data)?.to_vec())
}
other => Err(AppError::VideoError(format!(
"mjpeg_mediacodec output {} cannot be converted to NV12",
other
))),
}
}
}
fn pixel_format_from_av(format: AVPixelFormat) -> Option<PixelFormat> {
match format {
AVPixelFormat::AV_PIX_FMT_NV12 => Some(PixelFormat::Nv12),
AVPixelFormat::AV_PIX_FMT_NV21 => Some(PixelFormat::Nv21),
AVPixelFormat::AV_PIX_FMT_YUV420P | AVPixelFormat::AV_PIX_FMT_YUVJ420P => {
Some(PixelFormat::Yuv420)
}
_ => None,
}
}
unsafe impl Send for AndroidMediaCodecMjpegDecoder {}

View File

@@ -48,8 +48,6 @@ pub enum H264EncoderType {
Rkmpp,
/// V4L2 M2M (ARM generic) - requires hwcodec extension
V4l2M2m,
/// Android MediaCodec via FFmpeg
MediaCodec,
/// Software encoding (libx264/openh264)
Software,
/// No encoder available
@@ -66,7 +64,6 @@ impl std::fmt::Display for H264EncoderType {
H264EncoderType::Vaapi => write!(f, "VAAPI"),
H264EncoderType::Rkmpp => write!(f, "RKMPP"),
H264EncoderType::V4l2M2m => write!(f, "V4L2 M2M"),
H264EncoderType::MediaCodec => write!(f, "MediaCodec"),
H264EncoderType::Software => write!(f, "Software"),
H264EncoderType::None => write!(f, "None"),
}
@@ -83,7 +80,6 @@ impl From<EncoderBackend> for H264EncoderType {
EncoderBackend::Vaapi => H264EncoderType::Vaapi,
EncoderBackend::Rkmpp => H264EncoderType::Rkmpp,
EncoderBackend::V4l2m2m => H264EncoderType::V4l2M2m,
EncoderBackend::MediaCodec => H264EncoderType::MediaCodec,
EncoderBackend::Software => H264EncoderType::Software,
}
}
@@ -196,7 +192,6 @@ pub fn get_available_encoders(width: u32, height: u32) -> Vec<CodecInfo> {
let ctx = EncodeContext {
name: String::new(),
mc_name: None,
width: width as i32,
height: height as i32,
pixfmt: resolve_pixel_format("yuv420p", AVPixelFormat::AV_PIX_FMT_YUV420P),
@@ -296,7 +291,6 @@ impl H264Encoder {
let ctx = EncodeContext {
name: codec_name.to_string(),
mc_name: None,
width: width as i32,
height: height as i32,
pixfmt,

View File

@@ -45,8 +45,6 @@ pub enum H265EncoderType {
Rkmpp,
/// V4L2 M2M (ARM generic)
V4l2M2m,
/// Android MediaCodec via FFmpeg
MediaCodec,
/// Software encoder (libx265)
Software,
/// No encoder available
@@ -63,7 +61,6 @@ impl std::fmt::Display for H265EncoderType {
H265EncoderType::Vaapi => write!(f, "VAAPI"),
H265EncoderType::Rkmpp => write!(f, "RKMPP"),
H265EncoderType::V4l2M2m => write!(f, "V4L2 M2M"),
H265EncoderType::MediaCodec => write!(f, "MediaCodec"),
H265EncoderType::Software => write!(f, "Software"),
H265EncoderType::None => write!(f, "None"),
}
@@ -79,7 +76,6 @@ impl From<EncoderBackend> for H265EncoderType {
EncoderBackend::Vaapi => H265EncoderType::Vaapi,
EncoderBackend::Rkmpp => H265EncoderType::Rkmpp,
EncoderBackend::V4l2m2m => H265EncoderType::V4l2M2m,
EncoderBackend::MediaCodec => H265EncoderType::MediaCodec,
EncoderBackend::Software => H265EncoderType::Software,
}
}
@@ -199,7 +195,6 @@ pub fn get_available_h265_encoders(width: u32, height: u32) -> Vec<CodecInfo> {
let ctx = EncodeContext {
name: String::new(),
mc_name: None,
width: width as i32,
height: height as i32,
pixfmt: resolve_pixel_format("nv12", AVPixelFormat::AV_PIX_FMT_NV12),
@@ -373,7 +368,6 @@ impl H265Encoder {
let ctx = EncodeContext {
name: codec_name.to_string(),
mc_name: None,
width: width as i32,
height: height as i32,
pixfmt,

View File

@@ -3,10 +3,6 @@
use hwcodec::common::DataFormat;
use hwcodec::ffmpeg_ram::CodecInfo;
#[cfg(feature = "android-mediacodec")]
pub mod android_mediacodec;
#[cfg(feature = "android-mediacodec")]
pub mod android_mjpeg;
pub mod convert;
pub mod h264;
@@ -23,10 +19,6 @@ pub mod vp9;
#[cfg(all(feature = "desktop", any(target_arch = "aarch64", target_arch = "arm")))]
pub mod mjpeg_rkmpp;
#[cfg(feature = "android-mediacodec")]
pub use android_mediacodec::{AndroidH264Packet, AndroidMediaCodecH264Encoder};
#[cfg(feature = "android-mediacodec")]
pub use android_mjpeg::AndroidMediaCodecMjpegDecoder;
pub use convert::{MjpegToNv12Decoder, PixelConverter, Yuv420pBuffer};
pub use h264::{H264Config, H264Encoder, H264EncoderType, H264InputFormat};
pub use h265::{H265Config, H265Encoder, H265EncoderType, H265InputFormat};

View File

@@ -96,8 +96,6 @@ pub enum EncoderBackend {
Rkmpp,
/// V4L2 Memory-to-Memory (ARM)
V4l2m2m,
/// Android MediaCodec via FFmpeg
MediaCodec,
/// Software encoding (libx264, libx265, libvpx)
Software,
}
@@ -117,8 +115,6 @@ impl EncoderBackend {
EncoderBackend::Rkmpp
} else if name.contains("v4l2m2m") {
EncoderBackend::V4l2m2m
} else if name.contains("mediacodec") {
EncoderBackend::MediaCodec
} else {
EncoderBackend::Software
}
@@ -138,7 +134,6 @@ impl EncoderBackend {
EncoderBackend::Amf => "AMF",
EncoderBackend::Rkmpp => "RKMPP",
EncoderBackend::V4l2m2m => "V4L2 M2M",
EncoderBackend::MediaCodec => "MediaCodec",
EncoderBackend::Software => "Software",
}
}
@@ -153,7 +148,6 @@ impl EncoderBackend {
"amf" => Some(EncoderBackend::Amf),
"rkmpp" => Some(EncoderBackend::Rkmpp),
"v4l2m2m" | "v4l2" => Some(EncoderBackend::V4l2m2m),
"mediacodec" | "android-mediacodec" => Some(EncoderBackend::MediaCodec),
"software" | "cpu" => Some(EncoderBackend::Software),
_ => None,
}
@@ -261,8 +255,8 @@ impl EncoderRegistry {
let codec_name = match format {
VideoEncoderType::H264 => "libx264",
VideoEncoderType::H265 => "libx265",
VideoEncoderType::VP8 => "libvpx",
VideoEncoderType::VP9 => "libvpx-vp9",
VideoEncoderType::VP8 => "libvpx_vp8",
VideoEncoderType::VP9 => "libvpx_vp9",
};
encoders.push(AvailableEncoder {
@@ -309,10 +303,9 @@ impl EncoderRegistry {
self.encoders.clear();
self.detection_resolution = (width, height);
// Create test context for encoder detection
// Create test context for encoder detection.
let ctx = EncodeContext {
name: String::new(),
mc_name: None,
width: width as i32,
height: height as i32,
pixfmt: resolve_pixel_format("nv12", AVPixelFormat::AV_PIX_FMT_NV12),
@@ -332,7 +325,6 @@ impl EncoderRegistry {
ctx.clone(),
Duration::from_millis(DETECT_TIMEOUT_MS),
);
info!("Found {} encoders from hwcodec", all_encoders.len());
for codec_info in &all_encoders {

View File

@@ -2,8 +2,6 @@ use serde::Serialize;
use std::sync::mpsc;
use std::time::{Duration, Instant};
#[cfg(feature = "android-mediacodec")]
use super::AndroidMediaCodecH264Encoder;
use super::{
EncoderRegistry, H264Config, H264Encoder, H265Config, H265Encoder, VP8Config, VP8Encoder,
VP9Config, VP9Encoder, VideoEncoderType,
@@ -237,32 +235,6 @@ fn run_smoke_test(
}
fn run_h264_smoke_test(resolution: Resolution, codec_name_ffmpeg: &str) -> Result<()> {
#[cfg(feature = "android-mediacodec")]
if codec_name_ffmpeg == "h264_mediacodec" {
let mut encoder = AndroidMediaCodecH264Encoder::new(
resolution,
PixelFormat::Nv12,
30,
bitrate_kbps_for_resolution(resolution),
)?;
encoder.request_keyframe();
let frame = build_nv12_test_frame(
resolution,
PixelFormat::Nv12.frame_size(resolution).unwrap_or(0),
);
for sequence in 0..SELF_CHECK_FRAME_ATTEMPTS {
let frames = encoder.encode_raw(&frame, pts_ms(sequence))?;
if frames.iter().any(|frame| !frame.data.is_empty()) {
return Ok(());
}
}
return Err(AppError::VideoError(
"Encoder produced no output after multiple frames".to_string(),
));
}
let mut encoder = H264Encoder::with_codec(
H264Config::low_latency(resolution, bitrate_kbps_for_resolution(resolution)),
codec_name_ffmpeg,

View File

@@ -130,7 +130,6 @@ pub fn get_available_vp8_encoders(width: u32, height: u32) -> Vec<CodecInfo> {
let ctx = EncodeContext {
name: String::new(),
mc_name: None,
width: width as i32,
height: height as i32,
pixfmt: resolve_pixel_format("nv12", AVPixelFormat::AV_PIX_FMT_NV12),
@@ -271,7 +270,6 @@ impl VP8Encoder {
let ctx = EncodeContext {
name: codec_name.to_string(),
mc_name: None,
width: width as i32,
height: height as i32,
pixfmt,

View File

@@ -130,7 +130,6 @@ pub fn get_available_vp9_encoders(width: u32, height: u32) -> Vec<CodecInfo> {
let ctx = EncodeContext {
name: String::new(),
mc_name: None,
width: width as i32,
height: height as i32,
pixfmt: resolve_pixel_format("nv12", AVPixelFormat::AV_PIX_FMT_NV12),
@@ -271,7 +270,6 @@ impl VP9Encoder {
let ctx = EncodeContext {
name: codec_name.to_string(),
mc_name: None,
width: width as i32,
height: height as i32,
pixfmt,