本文还有配套的精品资源,点击获取 menu-r.4af5f7ec.gif

简介:在Android平台上, ffmpegdemo 应用展示了如何利用 ffmpeg 库进行音视频的编解码、播放及流媒体服务。 ffmpeg 作为一个开源项目,提供包括编码、解码、转换和流媒体处理在内的多种音视频处理工具。此应用允许用户播放不同协议的流媒体内容,并涉及构建和集成ffmpeg到Android项目中的一系列步骤。这些步骤包括构建ffmpeg库、添加到Android项目、创建Java/Kotlin接口、执行多媒体操作、处理错误和性能优化、管理权限,以及集成播放器和流媒体支持。

1. Android平台多媒体处理概述

1.1 Android平台的多媒体框架概述

Android作为一个功能丰富的移动操作平台,为开发者提供了一系列多媒体处理工具和服务。从最初的音频播放,到视频录制、编解码处理,再到现在的虚拟现实(VR)和增强现实(AR),Android多媒体框架的能力不断在增强。开发者可以利用这一框架进行音频和视频的捕获、处理、播放以及格式转换等操作。

1.2 Android多媒体处理的重要性

在当今的移动应用市场,能够提供高质量的音视频体验的应用通常更容易获得用户的青睐。多媒体处理能力是现代应用不可缺少的一部分,无论是社交媒体应用、视频会议工具,还是游戏和教育应用。因此,理解并掌握Android平台的多媒体处理技术,对于开发者来说是必须的。

1.3 本章目标与学习路径

本章将概述Android平台上处理多媒体的基本框架与技术栈。通过本章的学习,读者可以对Android如何处理音频和视频有一个初步的了解,并为接下来深入学习如何集成和优化Android平台上的多媒体处理,比如使用ffmpeg库,打下坚实的基础。

2. ffmpeg库的集成与应用

2.1 ffmpeg库的介绍及其优势

2.1.1 了解ffmpeg及其功能

FFmpeg是一个非常强大的开源多媒体框架,它能够实现对音视频数据的录制、转换、流化和处理等多种功能。FFmpeg支持几乎所有的音视频格式,并且提供了丰富而灵活的库和工具。使用FFmpeg,开发者可以在他们的应用程序中轻松实现复杂的多媒体处理功能,比如视频录制、视频转码、音视频合并、音视频转格式、实时视频滤镜等。

2.1.2 评估ffmpeg在Android平台的应用前景

Android作为一个移动操作平台,广泛应用于智能手机、平板电脑等移动设备。移动设备对多媒体处理的需求日益增加,使得高效的多媒体处理工具变得尤为重要。FFmpeg在Android平台上的集成已经成为移动多媒体处理的首选方案。它的跨平台特性和性能优势,使得开发者能够构建出更加丰富和高效的应用程序。此外,随着Android NDK(Native Development Kit)的支持,FFmpeg能被更高效地集成到原生代码中,降低了处理高复杂度多媒体任务时的性能开销。

2.2 ffmpeg库的集成步骤

2.2.1 集成前的准备工作

集成FFmpeg前,需要了解Android开发环境和NDK。开发者应确保已安装了Android Studio和相应的NDK环境,并熟悉C/C++的开发。接着,获取FFmpeg的源码,可以通过下载官方发布的预编译库或者克隆官方仓库并自行编译。准备阶段还需要确认是否已经下载了适用于FFmpeg编译的工具链。

2.2.2 在Android项目中引入ffmpeg库

集成FFmpeg到Android项目中通常有三种方式:使用预编译的库文件、手动编译FFmpeg库并集成到项目、使用Gradle插件自动化集成。手动编译FFmpeg需要一定的技术基础,但能确保库的兼容性和性能优化。而使用预编译库和Gradle插件则能简化集成过程,但可能需要调整编译选项以确保最佳的兼容性和性能。

2.2.3 配置ffmpeg库的编译环境

在配置FFmpeg的编译环境时,首先需要设置NDK路径,并指定编译架构如armeabi-v7a、arm64-v8a、x86等。之后,配置编译选项,包括启用或禁用特定的编解码器、过滤器等模块,以及调整优化参数,如使用特定的CPU指令集来提高性能。编译FFmpeg时,还需指定输出库文件的位置,以便能够被Android项目所引用。

2.3 ffmpeg库在多媒体应用中的实践

2.3.1 音视频格式支持和处理

FFmpeg支持众多音视频格式,开发者可以根据需要选择合适的编解码器处理不同格式的媒体文件。FFmpeg不仅可以处理如AVI、MP4等常见格式,还支持一些专业和不常见的格式。在使用FFmpeg处理媒体文件时,开发者需要了解不同格式的特征、编解码器的特性,以及如何针对不同的使用场景选择合适的编解码技术。

2.3.2 解码器和编码器的选择与应用

解码器用于将编码的音视频数据解码成原始数据,而编码器则用于将原始数据编码成规定的格式。在选择解码器和编码器时,需要考虑目标设备的性能、应用场景的实时性要求以及媒体文件的质量等因素。例如,对于移动设备,可能会选择H.264编码器而不是H.265,因为H.264对硬件要求较低,且兼容性更广泛。开发者需要通过实际测试来确定最适合的编解码器组合,以达到最佳的播放效果和资源利用效率。

2.3.3 音视频数据处理的示例代码

在实际应用中,FFmpeg的API能够帮助开发者实现复杂的功能。例如,以下代码片段展示了如何使用FFmpeg API对视频进行转码操作:

AVFormatContext* input_format_context = NULL;
AVCodecContext* video_codec_context = NULL;
AVCodec* video_codec = NULL;
AVFrame* video_frame = NULL;
AVPacket* video_packet = NULL;
AVFormatContext* output_format_context = NULL;
AVStream* video_stream = NULL;
AVCodecContext* video_codec_context = NULL;
int video_stream_index = -1;

// 打开输入文件
if (avformat_open_input(&input_format_context, input_filename, NULL, NULL) != 0) {
    // Handle error.
}

// 找到视频流
if (avformat_find_stream_info(input_format_context, NULL) < 0) {
    // Handle error.
}

for (unsigned int i = 0; i < input_format_context->nb_streams; i++) {
    if (input_format_context->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
        video_stream_index = i;
        break;
    }
}

if (video_stream_index == -1) {
    // Handle error.
}

video_codec = avcodec_find_decoder(input_format_context->streams[video_stream_index]->codecpar->codec_id);
if (video_codec == NULL) {
    // Handle error.
}

video_codec_context = avcodec_alloc_context3(video_codec);
if (video_codec_context == NULL) {
    // Handle error.
}

if (avcodec_parameters_to_context(video_codec_context, input_format_context->streams[video_stream_index]->codecpar) < 0) {
    // Handle error.
}

if (avcodec_open2(video_codec_context, video_codec, NULL) < 0) {
    // Handle error.
}

// 分配输入帧缓冲区等操作...

// 打开输出文件并写入输出流头信息
// ...

// 循环处理每个视频帧
while (1) {
    if (av_read_frame(input_format_context, video_packet) < 0) {
        break;
    }

    // 编码前的准备操作

    if (video_packet->stream_index == video_stream_index) {
        // 解码视频帧
        if (avcodec_send_packet(video_codec_context, video_packet) < 0) {
            // Handle error.
        }

        while (avcodec_receive_frame(video_codec_context, video_frame) == 0) {
            // 处理解码后的视频帧,如转码操作
        }
    }

    // 清理工作
    av_packet_unref(video_packet);
}

// 清理资源并关闭输入输出文件
// ...

以上代码块仅为示例,展示了如何使用FFmpeg API进行视频的读取和帧的处理。实际开发中,还需要处理编解码器的错误检查、内存管理、多线程等细节问题。此外,开发者还可能需要根据项目需求,使用FFmpeg的过滤器对帧进行特定的处理,如调整大小、裁剪、特效等。在多线程环境中使用FFmpeg时,还需遵循FFmpeg的线程安全要求,避免数据竞争和内存访问错误。

通过上述章节的内容,我们可以看到,ffmpeg库作为Android平台多媒体处理的有力工具,不仅有着强大的功能和广泛的应用前景,而且通过合理的集成步骤和实践操作,能够高效地应用于多种场景,满足开发者对多媒体处理的需求。

3. 音视频编解码与流媒体播放

3.1 音视频编解码技术基础

3.1.1 编解码的概念与重要性

在数字媒体领域,编解码技术是核心的组成部分,它涉及到音频和视频数据的压缩与解压缩。编解码技术的重要性在于它能够在不影响或最小影响媒体质量的前提下,大幅度减小文件大小,从而提高存储效率和传输效率。

编解码通常分为两个步骤:编码(Compression)和解码(Decompression)。编码过程发生在内容制作或分发前,负责将原始的音视频数据转换成更适合存储和传输的格式。解码过程则发生在播放设备端,它将编码后的数据还原成原始的音视频信号。

编码可以通过减少数据的冗余性和去除人类感官不易察觉的信息来实现数据压缩。不同的编解码器基于不同的算法,可以达到不同的压缩比和质量平衡。在Android多媒体处理中,选择合适的编解码器对于应用程序的性能、用户体验和资源占用至关重要。

3.1.2 常见音视频编解码格式解析

在众多的编解码格式中,H.264/AVC和AAC是目前最为流行的视频和音频压缩标准。H.264能够提供较高的压缩比,同时保持较好的图像质量,广泛应用于视频传输和存储。而AAC作为音频编解码格式,其压缩效率高,音质损失小。

除了H.264和AAC,还有其他一些编解码格式也值得关注。例如,HEVC(H.265)作为H.264的继承者,在提供更高压缩效率的同时,也带来了更高的处理要求。AV1作为一个开源、免版税的视频编解码格式,旨在替代H.265,已经在某些应用场景中开始普及。

了解各种编解码格式的特点,开发者可以更好地根据应用场景选择最合适的编解码器,以确保音视频内容的播放品质以及应用程序的流畅运行。

3.2 音视频流媒体播放实现

3.2.1 流媒体播放原理与组件

流媒体播放涉及将音频和视频数据以一种连续的、实时的方式传输到接收端,并且在接收到数据后可以即时播放,无需下载完整文件。这个过程依赖于几个关键组件,包括编码器、服务器、网络协议以及客户端播放器。

编码器负责将原始媒体文件压缩成适合流式传输的格式。服务器则存储这些编码后的媒体文件,并通过网络协议将其传输到客户端。网络协议,如HTTP Live Streaming (HLS)和Dynamic Adaptive Streaming over HTTP (DASH),确保媒体数据可以通过标准的Web服务器进行流式传输。

客户端播放器需要能够解析这些协议,处理来自网络的数据流,并解码数据以供播放。对于Android平台,可以使用Android的MediaCodec API进行解码操作,以及MediaPlayer或者ExoPlayer等框架来管理媒体播放。

3.2.2 实现流媒体播放的关键代码示例

下面是一个使用ExoPlayer进行流媒体播放的基本示例代码。ExoPlayer是Google推出的开源视频播放库,适用于Android应用,它支持多种流媒体协议和编解码器。

// 创建ExoPlayer实例
val exoPlayer = SimpleExoPlayer.Builder(context).build()

// 准备播放器,加载媒体资源
val mediaItem = MediaItem.Builder()
    .setUri("https://your.stream.url")
    .build()
exoPlayer.setMediaItem(mediaItem)

// 准备播放器准备播放
exoPlayer.prepare()

// 开始播放
exoPlayer.play()

// 释放播放器资源
exoPlayer.release()

在上述代码中,首先创建了一个 SimpleExoPlayer 实例,然后创建了一个 MediaItem 对象,指定了流媒体的URL地址,并将这个媒体项设置到播放器中。接下来调用 prepare 方法让播放器准备播放,最后调用 play 方法开始播放。一旦播放结束或不再需要播放器,应调用 release 方法释放播放器资源。

3.3 音视频流媒体的传输与同步

3.3.1 流媒体传输协议概述

流媒体传输协议,如HLS和DASH,允许媒体内容以小块(通常称为分片)的形式进行传输。这种分块传输使得媒体内容可以适应带宽波动,提高播放的流畅性。

HLS将媒体内容分割成小的MPEG-TS文件片段,并通过HTTP协议传输,它支持自适应比特率传输,这意味着如果网络条件改变,播放器可以无缝切换到不同比特率的流版本。

DASH与HLS类似,但提供了更高级的自适应流媒体技术。DASH基于HTTP协议传输媒体内容,并支持对不同的媒体组件(如视频、音频和字幕)使用不同的编码方式和比特率,从而实现更优的带宽利用率。

3.3.2 音视频同步技术与实践

在流媒体播放中,音视频同步是一项关键任务,它确保声音和图像能够以正确的时序进行播放。音频和视频流可能由于网络延迟、设备性能、编解码处理等因素而导致延迟差异,因此需要同步技术来调整这种差异。

在Android平台上,ExoPlayer提供了强大的同步支持。它不仅可以处理本地媒体文件,还可以处理网络流媒体中的时间戳差异。以下是一个简单的代码示例,展示了如何配置ExoPlayer以使用时间戳同步:

// 配置同步
val defaultRenderersFactory = DefaultRenderersFactory(context)
defaultRenderersFactory.setAudioVideoBecomingNoisyManager(object : AudioVideoBecomingNoisyManager {
    override fun onBecomingNoisy() {
        // 处理耳机拔出事件
    }
})
exoPlayer.setRenderersFactory(defaultRenderersFactory)
exoPlayer.setAudioAttributes(AudioAttributes.Builder()
    .setUsage(Cusage.VOICE_COMMUNICATION)
    .setContentType(CcontentType.MUSIC)
    .build(), true)
exoPlayer.setHandleAudioBecomingNoisy(true)

在上述代码中,通过 DefaultRenderersFactory 配置了ExoPlayer的渲染器,设置音频和视频成为嘈杂时的管理器,设置了音频属性,并启用了音频嘈杂时的处理。这样可以使得音频在耳机被拔出时自动降低音量,而视频仍然可以继续播放。

通过以上技术和实践的应用,开发者可以在Android项目中实现高质量的音视频流媒体播放和同步。这不仅提升了用户体验,也对实现复杂的流媒体服务提供了基础支持。

4. Android项目中ffmpeg的构建和编译

4.1 ffmpeg的构建过程详解

4.1.1 构建前的环境准备

在开始构建ffmpeg之前,确保你的开发环境已经配置妥当。首先,需要安装Ndk(Native Development Kit),它为Android提供了C和C++的开发环境。对于ffmpeg的构建,你还需要安装一些必备的工具,比如autoconf、automake、libtool、yasm和pkg-config等。这些可以使用你的包管理器进行安装,例如在Ubuntu系统中使用apt-get:

sudo apt-get install autoconf automake libtool yasm nasm pkg-config

还需要确保你的gcc编译器是可用的,如果构建过程中遇到问题,确认一下gcc的版本是否满足ffmpeg的编译要求。此外,下载最新版本的ffmpeg源码,构建时可能需要网络连接,确保网络的稳定性。

4.1.2 编译ffmpeg源码的详细步骤

一旦环境搭建完毕,接下来是构建ffmpeg的源码,这包括一系列的配置、编译和安装步骤。

首先,解压下载的源码压缩包:

tar xvf ffmpeg-x.x.tar.bz2

然后,进入解压后的目录:

cd ffmpeg-x.x

配置编译选项是构建过程中的关键一步,你可以在源码目录内找到一个名为 configure 的脚本,使用此脚本可以设置不同的编译选项,以适应不同的需求。例如,如果你希望编译出针对Android平台的ffmpeg二进制文件,你可以使用NDK的交叉编译工具链:

./configure --prefix=/path/to/install/dir \
--target-os=android --arch=arm --enable-shared \
--disable-static --extra-cflags="-mfpu=neon" \
--extra-ldflags="-llog" \
CC=arm-linux-androideabi-gcc

这里做了以下几件事: - 指定了输出路径为 /path/to/install/dir 。 - 设置目标操作系统为Android,架构为ARM。 - 启用共享库,禁用静态库。 - 添加了特定的CPU标志以启用NEON指令集,提高性能。 - 连接了Android的日志库。 - 指定了交叉编译器 arm-linux-androideabi-gcc 。

配置完成后,编译源码:

make

最后,安装编译好的库文件到之前指定的目录:

make install

4.2 ffmpeg构建后的集成测试

4.2.1 测试环境的搭建

为了验证ffmpeg库的构建是否成功并且功能正常,你需要搭建一个测试环境。在Android项目中集成构建好的ffmpeg库,并创建一些测试用例来验证库文件的功能。

创建一个新的Android项目,或者在现有的项目中,添加对刚刚构建好的ffmpeg库的依赖。确保Android项目中有对应的NDK环境配置,并且可以找到库文件。

4.2.2 集成后的功能验证与性能评估

在项目中集成好ffmpeg后,需要创建测试用例来验证解码、编码、转码等基本功能是否正常。你可以编写一个简单的界面,通过用户输入来选择不同的多媒体处理任务,并展示处理结果。

性能评估是另一个重要的环节,需要在不同的设备上测试,记录处理同一段多媒体数据的时间,内存消耗和CPU占用等参数。可以使用Android的性能监控工具,比如Android Profiler,来收集运行时数据。

4.3 构建ffmpeg库的高级选项

4.3.1 配置项的介绍与选择

ffmpeg的构建选项非常丰富,可以根据具体需求进行定制。这些选项可以在运行 ./configure 脚本时通过参数进行传递。例如,可以指定支持的编解码器:

--enable-libx264 --enable-libmp3lame --enable-libvpx

还可以根据具体的应用场景开启或关闭某些特性:

--disable-network

这些高级选项允许开发者在功能与性能之间取得平衡,例如减少功能支持可以降低最终应用的大小,但这可能会限制可用的格式和功能。

4.3.2 定制化构建与性能优化

为了进一步优化应用的性能,定制化构建ffmpeg时,可以对一些核心的库进行优化配置,例如使用更高效的编解码器或调整库的大小。了解每个编译选项对性能的影响,并根据应用需求进行选择,是提升应用响应速度和减少资源消耗的重要手段。

此外,你还可以根据项目的目标设备进行定制化优化。比如,对于只支持ARM架构的设备,可以去掉x86架构的编译支持,或者根据目标设备的CPU特性启用特定的硬件加速选项,从而提高编码或解码的速度。

--enable-neon --enable-mipsdspr2

综上所述,通过选择合适的构建选项和进行性能优化,可以使得ffmpeg在Android项目中的表现更贴合应用需求,满足从低功耗到高性能的各类场景。

5. 音视频操作的深度应用与优化

在移动设备上实现音视频操作涉及许多技术细节,尤其是在保证性能和用户体验的同时。在这一章节中,我们将深入探讨在Android平台上进行音视频解码、播放、编码和转码的高级实践,并提供错误处理和性能优化的实用技巧。我们还将讨论与Android权限管理以及流媒体协议支持相关的技术。

5.1 音视频解码、播放、编码、转码实践

音视频的解码、播放、编码和转码是多媒体处理的核心功能。正确地实现这些功能不仅要求开发者掌握相应的技术知识,还要对性能优化有所了解。

5.1.1 音视频解码操作流程

音视频解码是多媒体处理的基础,它涉及将压缩的数据转换为原始的音视频数据。在Android平台上,解码操作通常由 MediaCodec API完成。以下是一个音视频解码的基本流程:

  1. 创建解码器实例并配置输入输出格式。
  2. 提供编码数据给解码器,可以是通过 MediaExtractor 获取的数据。
  3. 同步地获取解码输出,处理解码后的数据。
// 省略了实例化和配置MediaCodec代码
// 输入和输出缓冲区
MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
int inIndex = mediaCodec.dequeueInputBuffer(TIMEOUT_USEC);
if (inIndex >= 0) {
    ByteBuffer buffer = mediaCodec.getInputBuffer(inIndex);
    // 填充数据到buffer...
    mediaCodec.queueInputBuffer(inIndex, 0, bufferInfo.size, bufferInfo.presentationTimeUs, 0);
}

// 获取解码后的数据
int outIndex = mediaCodec.dequeueOutputBuffer(bufferInfo, TIMEOUT_USEC);
while (outIndex >= 0) {
    // 处理解码后的数据...
    mediaCodec.releaseOutputBuffer(outIndex, false);
    outIndex = mediaCodec.dequeueOutputBuffer(bufferInfo, TIMEOUT_USEC);
}

5.1.2 音视频播放技术细节

播放音视频文件涉及多个步骤,包括文件解码、数据处理以及将原始数据渲染到屏幕上。对于视频播放,你需要正确处理不同分辨率和帧率的视频,而对于音频播放,你需要考虑如何处理不同采样率和声道配置的音频数据。

// 示例:使用MediaPlayer类播放视频
MediaPlayer mediaPlayer = new MediaPlayer();
mediaPlayer.setDataSource("file:///path/to/video.mp4");
mediaPlayer.prepare();
mediaPlayer.start();

5.1.3 音视频编码与转码的应用

编码和转码用于将原始的音视频数据转换为不同的格式,以便在不同的设备或网络上使用。 MediaCodec API同样可以用于编码操作,但处理方式与解码不同。转码时,需要考虑源视频和目标视频的编码格式、分辨率、帧率和比特率等因素,确保视频质量与文件大小之间的平衡。

5.2 错误处理和性能优化实践

在音视频处理中,错误处理和性能优化是不可忽视的重要环节。合理的错误处理机制可以确保应用的稳定运行,而性能优化则可提升用户体验。

5.2.1 常见音视频处理错误分析

音视频处理过程中的常见错误可能包括但不限于:数据同步问题、内存泄漏、解码器兼容性问题、以及性能瓶颈导致的播放卡顿。针对这些错误,需要在应用中进行详尽的测试,并实现相应的异常处理机制和日志记录。

try {
    // 音视频处理相关代码
} catch (MediaCodec.CodecException e) {
    // 编解码异常处理
} catch (IllegalArgumentException e) {
    // 参数错误异常处理
} catch (IllegalStateException e) {
    // 状态错误异常处理
}

5.2.2 音视频处理的性能优化技巧

性能优化包括但不限于CPU和GPU的合理使用、内存管理、缓存优化和多线程处理。例如,在解码操作中,可以使用 dequeueInputBuffer 方法的超时参数来控制解码器的处理频率,避免资源竞争和CPU过度使用。

int TIMEOUT_USEC = 10000; // 设置超时时间
int inIndex = mediaCodec.dequeueInputBuffer(TIMEOUT_USEC);
if (inIndex >= 0) {
    // 处理输入数据...
}

5.3 Android权限管理与流媒体协议支持

Android平台对于音视频应用中的权限管理和流媒体协议的支持有着明确的规定和要求。

5.3.1 Android平台权限管理策略

在Android应用中处理音视频数据通常需要请求一些特定的权限,例如存储权限、网络权限以及硬件控制权限。在开发过程中,应遵循最小权限原则,仅请求应用运行所必需的权限,以保证用户隐私和应用安全。

<!-- 示例:AndroidManifest.xml中的权限声明 -->
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

5.3.2 流媒体协议的支持与实现

对于流媒体应用,支持多种流媒体协议是关键。这可能包括HTTP Live Streaming (HLS), Dynamic Adaptive Streaming over HTTP (DASH), Real-time Messaging Protocol (RTMP)等。在Android上,可以通过ffmpeg库来实现对多种流媒体协议的支持。

// 示例:使用ffmpeg命令行工具实现HLS流媒体播放
Process process = Runtime.getRuntime().exec("ffmpeg -i http://example.com/stream.m3u8 -c:v libx264 -c:a aac -f mp4 -");

在本章中,我们探讨了音视频操作在Android平台上的深度应用与优化策略。我们从基本的解码、播放、编码、转码实践开始,深入到错误处理和性能优化技巧。此外,我们还讨论了Android权限管理和流媒体协议的支持,这两者在开发音视频应用时同样至关重要。在下一章中,我们将进一步探讨跨平台音视频处理的策略和方法,以及如何将这些技术应用到实际项目中去。

本文还有配套的精品资源,点击获取 menu-r.4af5f7ec.gif

简介:在Android平台上, ffmpegdemo 应用展示了如何利用 ffmpeg 库进行音视频的编解码、播放及流媒体服务。 ffmpeg 作为一个开源项目,提供包括编码、解码、转换和流媒体处理在内的多种音视频处理工具。此应用允许用户播放不同协议的流媒体内容,并涉及构建和集成ffmpeg到Android项目中的一系列步骤。这些步骤包括构建ffmpeg库、添加到Android项目、创建Java/Kotlin接口、执行多媒体操作、处理错误和性能优化、管理权限,以及集成播放器和流媒体支持。

本文还有配套的精品资源,点击获取 menu-r.4af5f7ec.gif

Logo

北京人形旗下天工造物具身智能开源社区,聚焦具身天工与慧思开物两大平台

更多推荐