草庐IT

元宇宙技术教程|如何一键生成虚拟人视频

ZEGO即构开发者 2023-03-28 原文

想拍视频,不想露脸?

虚拟人视频录制

ZEGO Avatar SDK 虚拟形象 SDK 提供了视频录制功能,支持用户随时把 Avatar 虚拟形象录制成视频,同时也可以将麦克风采集的声音录制到虚拟形象视频中。

用户可以把 Avatar虚拟人 的精彩时刻,录制成视频,分享给好友。

实现视频录制的前提条件

在实现“录制视频”功能之前,请确保:

  • 已在项目中集成了 Avatar SDK 虚拟形象 SDK,详情请参考 集成 SDK
  • 已参考 创建虚拟形象,完成基本的虚拟人物形象搭建。

虚拟人视频录制的实现流程

开发者请参考以下步骤,实现 “录制视频” 功能。

1 启动虚拟人视频录制

开始视频录制前,如果要保存到设备上,请先配置 WRITE_EXTERNAL_STORAGE 权限。录制接口只支持传入保存视频文件的绝对路径。

配置方法请参考 设置权限

搭建出基本的虚拟人物形象后,调用 ZegoAvatarViewstartRecord 接口,传入录制视频的配置参数 ZegoRecordConfig,其中 videoPath 指视频保存路径,必填。默认录制视频为 .mp4 格式。

ZegoRecordConfig recordConfig = new ZegoRecordConfig();
// 可选: 默认就是MP4, 除了MP4还能录制Webm, 但是Webm的设备兼容性太差, 且录制出来的视频, 在 iOS 也缺少原生支持, 不建议使用
recordConfig.recordMode = ZegoRecordConfig.MODE_MP4;
// 可选: 把声音也录制上
recordConfig.recordAudio = true; 
// 注意: 华为手机要写入相册, 要在 AndroidManifest.xml 中的 application 增加这个 android:requestLegacyExternalStorage="true", 否则没有权限
// 设置存储路径, 可以存储在相册或者其它位置. 以下示例为相册的存储路径示例, 通知相册的逻辑, 用户自定义即可
mVideoFile = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM).getAbsolutePath() + File.separator + System.currentTimeMillis() + ".mp4";
// 必填: 保存到相册, 需要确保已经在 AndroidManifest.xml 已经申请过 WRITE_EXTERNAL_STORAGE 权限 
recordConfig.setVideoPath(mVideoFile);
// 可选: 视频录制默认是 mAvatarView 的尺寸, 如果觉得录制视频的尺寸太大, 可以通过设置 scaleWidth 来限制最大宽度, 高度则按比例缩小
// 注意: scaleWidth 必须小于 mAvatarView 的宽度
recordConfig.setScaleWidth(mAvatarView.getWidth() / 2);

// 启动录制, 当启动失败返回false(没有权限、创建编码器出错等),由于录制是在子线程进行的, 录制过程中有错误(编码失败等错误), 会通过 callback 回到出来
// 注:mAvatarView 为 ZegoAvatarView 的实例
mAvatarView.startRecord(recordConfig, (errorCode, msg) -> {
    Log.e("ZegoAvatar", "Avatar 形象视频录制出错了: " + msg);
});

启动录制失败时,接口会返回 false(失败原因可能为:没有权限、创建编码器出错等)。之后编码运行在子线程,录制过程中若发生错误,会在 callback 中回调出来,相关错误码请参考 常见错误码

2 停止视频录制

如果想要停止录制,可调用 ZegoAvatarViewstopRecord 接口停止录制,SDK 会把视频内容保存成视频文件,复制到 videoPath 指定的路径中。

// 停止视频录制, 调用后会停止录制, 并把录制的视频文件写到 startRecord 时指定的 videoPath
// 如果过程中发生错误, 会在 callback 中回调出来
mAvatarView.stopRecord((errorCode, msg) -> {
    if (errorCode == 0) {
        Log.i("ZegoAvatar", "Avatar 形象视频录制成功, 保存路径: " + mVideoFile);
    } else {
        Log.i("ZegoAvatar", "Avatar 形象视频录制失败: " + msg);
    }
});

3 自定义音频采集

如果设置了 ZegoRecordConfig 对象的 recordAudio 为 true,SDK 会使用内置的麦克风采集模块采集声音。内置的采集模块在设备兼容性上有所欠缺,ZEGO 推荐开发者使用 Express SDK 进行音频采集,请参考 自定义音频采集与渲染

  1. 开发者需要调用 setCustomAudioDelegate 接口,设置自定义音频数据采集代理(需要继承 AudioDataDelegate 实现 onStartonStop 方法)。
  2. 采集到音频数据后,调用 sendAudioData 接口,发送数据。
  • 如果录制视频的同时,也开起了“语音驱动”,且语音驱动也已开启“自定义音频采集”,则 setCustomAudioDelegate 接口只需设置一次即可,SDK 会进行复用,无需重复设置。
  • 开发者如果使用 Express SDK 做音频采集,可以参考示例源码中的 “im/zego/zegoavatarexample/express/ZegoExpressAudioCaptureDelegate.java” 文件,其代码已实现通过 Express SDK 的自定义音频前处理,把音频数据提供给 Avatar 做视频录制的逻辑。
public class CustomAudioDataDelegate extends AudioDataDelegate {
    private Boolean isRunning = false;
    @Override
    public void onStart() {
        // 启动音频采集
        isRunning = true;
        // 配置 Express ,启动自定义音频前处理等等
    }

    @Override
    public void onStop() {
       // 停止音频采集
        isRunning = false;
    }
    
    // 这个是 Express 的声音前处理回调, 这里直接把Express 采集的数据给到 Avatar SDK即可。
    public void onProcessCapturedAudioData(ByteBuffer data, int dataLength, ZegoAudioFrameParam param) {
        if(isRunning){
            // 填充声音数据
            // data: pcm的原始数据
            // length: data的长度
            // dataType: data采集的位数  0表示16位,1表示8位
            // timeStamp: 时间戳, 从启动采集到当前经过的时间, 单位毫秒。
            super.sendAudioData(data, dataLength, 1/*rtc 给的数据是 8位的, 填 1*/, super.getDurationMs()/*这是个父类方法,直接调用即可。*/);
        }
    }
}

4 获取Avatar SDK更多帮助

获取本文 Avatar SDK的开发文档、技术支持,访问即构文档中心开发文档页

有关元宇宙技术教程|如何一键生成虚拟人视频的更多相关文章

  1. ruby - 如何使用 Nokogiri 的 xpath 和 at_xpath 方法 - 2

    我正在学习如何使用Nokogiri,根据这段代码我遇到了一些问题:require'rubygems'require'mechanize'post_agent=WWW::Mechanize.newpost_page=post_agent.get('http://www.vbulletin.org/forum/showthread.php?t=230708')puts"\nabsolutepathwithtbodygivesnil"putspost_page.parser.xpath('/html/body/div/div/div/div/div/table/tbody/tr/td/div

  2. ruby - 如何从 ruby​​ 中的字符串运行任意对象方法? - 2

    总的来说,我对ruby​​还比较陌生,我正在为我正在创建的对象编写一些rspec测试用例。许多测试用例都非常基础,我只是想确保正确填充和返回值。我想知道是否有办法使用循环结构来执行此操作。不必为我要测试的每个方法都设置一个assertEquals。例如:describeitem,"TestingtheItem"doit"willhaveanullvaluetostart"doitem=Item.new#HereIcoulddotheitem.name.shouldbe_nil#thenIcoulddoitem.category.shouldbe_nilendend但我想要一些方法来使用

  3. ruby - 使用 RubyZip 生成 ZIP 文件时设置压缩级别 - 2

    我有一个Ruby程序,它使用rubyzip压缩XML文件的目录树。gem。我的问题是文件开始变得很重,我想提高压缩级别,因为压缩时间不是问题。我在rubyzipdocumentation中找不到一种为创建的ZIP文件指定压缩级别的方法。有人知道如何更改此设置吗?是否有另一个允许指定压缩级别的Ruby库? 最佳答案 这是我通过查看ruby​​zip内部创建的代码。level=Zlib::BEST_COMPRESSIONZip::ZipOutputStream.open(zip_file)do|zip|Dir.glob("**/*")d

  4. python - 如何使用 Ruby 或 Python 创建一系列高音调和低音调的蜂鸣声? - 2

    关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。

  5. ruby-on-rails - 如何验证 update_all 是否实际在 Rails 中更新 - 2

    给定这段代码defcreate@upgrades=User.update_all(["role=?","upgraded"],:id=>params[:upgrade])redirect_toadmin_upgrades_path,:notice=>"Successfullyupgradeduser."end我如何在该操作中实际验证它们是否已保存或未重定向到适当的页面和消息? 最佳答案 在Rails3中,update_all不返回任何有意义的信息,除了已更新的记录数(这可能取决于您的DBMS是否返回该信息)。http://ar.ru

  6. ruby-on-rails - 'compass watch' 是如何工作的/它是如何与 rails 一起使用的 - 2

    我在我的项目目录中完成了compasscreate.和compassinitrails。几个问题:我已将我的.sass文件放在public/stylesheets中。这是放置它们的正确位置吗?当我运行compasswatch时,它不会自动编译这些.sass文件。我必须手动指定文件:compasswatchpublic/stylesheets/myfile.sass等。如何让它自动运行?文件ie.css、print.css和screen.css已放在stylesheets/compiled。如何在编译后不让它们重新出现的情况下删除它们?我自己编译的.sass文件编译成compiled/t

  7. ruby - 如何将脚本文件的末尾读取为数据文件(Perl 或任何其他语言) - 2

    我正在寻找执行以下操作的正确语法(在Perl、Shell或Ruby中):#variabletoaccessthedatalinesappendedasafileEND_OF_SCRIPT_MARKERrawdatastartshereanditcontinues. 最佳答案 Perl用__DATA__做这个:#!/usr/bin/perlusestrict;usewarnings;while(){print;}__DATA__Texttoprintgoeshere 关于ruby-如何将脚

  8. ruby - 如何指定 Rack 处理程序 - 2

    Rackup通过Rack的默认处理程序成功运行任何Rack应用程序。例如:classRackAppdefcall(environment)['200',{'Content-Type'=>'text/html'},["Helloworld"]]endendrunRackApp.new但是当最后一行更改为使用Rack的内置CGI处理程序时,rackup给出“NoMethodErrorat/undefinedmethod`call'fornil:NilClass”:Rack::Handler::CGI.runRackApp.newRack的其他内置处理程序也提出了同样的反对意见。例如Rack

  9. ruby - 如何每月在 Heroku 运行一次 Scheduler 插件? - 2

    在选择我想要运行操作的频率时,唯一的选项是“每天”、“每小时”和“每10分钟”。谢谢!我想为我的Rails3.1应用程序运行调度程序。 最佳答案 这不是一个优雅的解决方案,但您可以安排它每天运行,并在实际开始工作之前检查日期是否为当月的第一天。 关于ruby-如何每月在Heroku运行一次Scheduler插件?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/8692687/

  10. ruby-on-rails - 如何从 format.xml 中删除 <hash></hash> - 2

    我有一个对象has_many应呈现为xml的子对象。这不是问题。我的问题是我创建了一个Hash包含此数据,就像解析器需要它一样。但是rails自动将整个文件包含在.........我需要摆脱type="array"和我该如何处理?我没有在文档中找到任何内容。 最佳答案 我遇到了同样的问题;这是我的XML:我在用这个:entries.to_xml将散列数据转换为XML,但这会将条目的数据包装到中所以我修改了:entries.to_xml(root:"Contacts")但这仍然将转换后的XML包装在“联系人”中,将我的XML代码修改为

随机推荐