给数字人生成加上界面,基于ER-NeRF/RAD-NeRF/AD-NeRF,Gradio框架构建WEBUI,使用HLS流媒体,实现边推理边播放——之二:将ndarray内存序列图直接转成ts格式视频

前言

  • 前文说到,我们的目标是要实现服务器一边推理一边播放视频的效果,并且知道服务器现在的推理状况
  • 前文链接:http://t.csdnimg.cn/Gy6JU
  • 服务器日志实时在webui中输出前文已经讲解,这里讲解如何边推边播
  • 要实现边推边播,最重要的问题是要选择一种视频播放协议,使浏览器能直接播放没有完整生成的视频文件(不要直播推流那一套,毕竟服务器资源有限),其次要解决视频文件直接从内存中转存的问题
  • 根据我们的要求,hls协议就能满足我们的要求:基于http协议,不需要单独再架设流媒体服务器,使用m3u8索引文件对视频文件进行概括,边播边加载,不会全部加载所有文件…

效果

在这里插入图片描述

实现

首先,我们需要根据hls协议,生成索引m3u8文件。
当前的状态是我们只有一个音频文件,视频文件是完全由机器推理生成的。
所以我们只能根据音频文件,自己拼凑一个m3u8文件:
默认我们每个ts文件是5s钟,那么根据音频文件的长度,就可以拼凑成一个完整的索引文件:

def create_m3u8_by_totalTime(totalTime: int, save_path_name: str):
    '''根据总时长,按每5s一段,创建一个m3u8文件,返回每个ts文件的名字队列
        :param totalTime 总时长,ms
        :param save_path_name m3u8文件要存储的路径及名称,以.m3u8为后缀
        :returns 返回每个ts的名字的队列对象及最后一个ts的时长(ms)
    '''
    dir = os.path.dirname(save_path_name)
    if not os.path.exists(dir):
        os.makedirs(dir)
    segment = int(totalTime / 5000) if totalTime % 5000 == 0 else int(totalTime / 5000) + 1
    tsQueue = queue.Queue(segment)
    with open(save_path_name, 'w') as m3u8:
        m3u8.write('#EXTM3U\n')
        m3u8.write('#EXT-X-VERSION:3\n')
        m3u8.write('#EXT-X-MEDIA-SEQUENCE:0\n')  # 当播放打开M3U8时,以这个标签的值作为参考,播放对应的序列号的切片
        m3u8.write('#EXT-X-ALLOW-CACHE:YES\n')
        m3u8.write('#EXT-X-TARGETDURATION:6\n')  # ts播放的最大时长,s
        lastTime = -1
        for i in range(segment):
            if i + 1 == segment:
                lastTime = totalTime % 5000
            m3u8.write(f'#EXTINF:{5.0 if lastTime < 0 else lastTime / 1000},\n')  # ts时长,注意有个逗号
            m3u8.write(f'{i}.ts\n')
            tsQueue.put(f'{i}.ts')
        m3u8.write('#EXT-X-ENDLIST')
    return tsQueue, lastTime

然后,我们需要将NeRF推理生成的图像帧转存为视频ts文件。
已知我们的视频都是25帧/秒,那5s的视频就应该是125帧,所以我们就按服务器每生成125帧图像的时候,就生成一次ts文件:

def create_ts_with_5sec(save_path:str,frame_ndarray:list,ts_index:int):
    '''创建一个5s时长的ts文件'''
    tmp_file = os.path.join(save_path,f'_tmp_quiet_{ts_index}.ts')
    height,width,c = frame_ndarray[0].shape
    print(f'======>视频width:{width},height:{height}')
    #图像写入ts文件
    process = (
        ffmpeg.input('pipe:', format='rawvideo', pix_fmt='rgb24', s='{}x{}'.format(width, height),framerate=25)
        .output(tmp_file, vcodec='libx264', r=25,output_ts_offset=ts_index * 5,hls_time=5,hls_segment_type='mpegts') #r:帧率,output_ts_offset:ts文件序列
        .global_args('-y')  # 覆盖同名文件
        .run_async(pipe_stdin=True)
    )
    for frame in frame_ndarray:
        process.stdin.write(frame.astype(np.uint8).tobytes())
        time.sleep(0.01)
    process.stdin.close()
    process.wait()

通过ffmpeg-python包的api,指定输入为一个管道pipe,指定输出为mpegts,帧率为25,注意output_ts_offset要为一个正序增长的数。
通过process.stdin.write(frame.astype(np.uint8).tobytes())将内存中的每张图像都写入ffmepg管道中。
但这仅仅是写入了视频,还需要加上声音。
加声音这里有两种方式,一种是图像转视频输出的时候,不写入磁盘,直接就写入一个输出管道中,然后将管道中的数据再进行合并声音操作。
另一种是output的时候就存为一个临时文件,合并声音的时候再读取文件合并,最后输出一个正式文件。
目前第一种方案暂时未研究成功,这里记录第二种方案:
注意:这里音频读取的范围段是一个固定5s时长的范围

def seconds_to_time(seconds):
    hours = seconds // 3600
    minutes = (seconds % 3600) // 60
    seconds = seconds % 60
    return f"{hours:02d}:{minutes:02d}:{seconds:02d}"

tmp_ts = ffmpeg.input(tmp_file)
    audio = ffmpeg.input(audio_path_name, ss=seconds_to_time(ts_index * 5),t='5') #顺序读取5s的音频时长内容
    joined = ffmpeg.concat(tmp_ts.video, audio, v=1, a=1).node
    out = ffmpeg.output(joined[0], joined[1],tmp_file.replace('_tmp_quiet_',''),vcodec='libx264', r=25,output_ts_offset=ts_index * 5,hls_time=5,hls_segment_type='mpegts').global_args('-y')  # 覆盖同名文件
    out.run()
    print('=====>ts生成完成!')

最终生成完成!
通过日志输出的方式,通知客户端m3u8文件的位置,让客户端加载m3u8文件,进行视频播放。

另外,数字人的图像推理,大多集中使用GPU,此处图像转存为ts格式视频文件,使用CPU,那这两个步骤可以并行执行。
思路就是通过一个队列,推理了一帧图像之后,就将图像的ndarray数组存入队列中,然后开启一个读取队列值的子线程,在子线程中取出图像数组,执行上面的生成ts文件的操作,就可以达到边推理边生成视频文件的效果。
相关代码我已放到gitee,有问题私信。

下一篇文章我们讲一下gradio怎么实时获取m3u8索引文件并实时播放

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
基于ER-NeRF自训练AI数字人-马鹤宁的方法主要包括三个步骤:数据收集、模型训练和模型评估。 首先,我们需要收集马鹤宁的相关数据。这些数据可以包括他的文字、音频、视频等各种形式的信息。我们可以从他的历史记录、社交媒体、公开演讲等渠道获取数据。收集到的数据应该尽可能全面和多样化,以便更好地了解马鹤宁的思维方式和个性特点。 接下来,我们使用ER-NeRF(Neural Radiance Fields with Extended Multimodal Inputs)模型对马鹤宁的数据进行训练。ER-NeRF是一种基于神经辐射场的模型,可以处理多模态输入。它能够将不同模态的数据,如文字、音频和视频,统一表示为一个连续的隐变量表达。这样可以更好地捕捉到马鹤宁的多模态特征。 在模型训练过程中,我们需要设计一个恰当的损失函数来指导模型学习。这个损失函数可以包括多个方面的考虑,如文本生的准确性、语音合的自然度以及图像重建的真实感等。通过不断迭代训练,使得模型能够逐渐准确地模拟出马鹤宁的行为和语言特点。 最后,我们需要对训练好的模型进行评估。评估的目标是判断生数字人是否与真实的马鹤宁表现一致。我们可以通过与真实数据进行对比、与他人对话以及进行用户调研等方式来验证模型的有效性和可信度。同时,还需要对模型进行不断的优化和调整,以提高生数字人的质量和逼真度。 以上是基于ER-NeRF自训练AI数字人-马鹤宁的主要步骤。通过数据收集、模型训练和模型评估,我们可以逐渐建立一个可以模拟并与真实马鹤宁类似的数字人。这样的AI数字人可以用于虚拟现实、人机交互等领域,为用户提供更为真实和丰富的体验。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值