踩坑ffmpeg录制的mp4无法在浏览器上播放

这篇具有很好参考价值的文章主要介绍了踩坑ffmpeg录制的mp4无法在浏览器上播放。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

前言

使用ffmpeg编译好的程序在电脑上进行音视频转换,可以参考这篇:《windows电脑FFmpeg安装教程手把手详解_windows安装ffmpeg》,而我们要做的是在游戏引擎中集成ffmpeg源码用来录制游戏视频。

我们游戏目前只支持录制avi格式的视频,但是近期有个运营需求:在上架商品的时候在游戏内录制一段视频提供给网页端进行播放。

首先简单的了解了一下,ffmpeg是支持录制mp4格式的,于是简短地改了几行代码就实现了录制mp4,然后把录制出来的视频发给网页同学部署测试。

第二天收到反馈我们录制的视频无法在网页上播放,由于我也是第一次接触ffmpeg,不知道为什么mp4无法在浏览器上播放,整个过程就是不断通过chatgpt查阅资料,不断修改代码调试,最终在某个夜晚跑通了。

问题:浏览器上无法播放mp4

我们游戏录制出来的mp4,右键 - 打开方式,选择浏览器,或者直接拖动mp4文件到浏览器里面,让它打开,表现为无法播放

踩坑ffmpeg录制的mp4无法在浏览器上播放

查看视频详细信息

通过ffmpeg工具提供的一些指令用来查看视频的详细信息,有助于调试

ffprobe -v quiet -print_format json -show_format -show_streams 你的文件名

ffprobe -v quiet -print_format json -show_format -show_streams video.mp4

查看视频每一帧的信息:

ffprobe -show_packets -of xml -i video.mp4

使用ffmpeg将mp4转为h264文件

我的第一个验证想法,使用ffmpeg把游戏录制的视频转换看看转换之后的视频是否在浏览器上播放,结果:转换后就可以在浏览器中就可以播放了

指令:ffmpeg -i video.mp4 -vcodec h264 -crf 10 test.mp4

说明:-crf 的数值是0~51,代表压缩等级,值越大画质越差,体积越小

使用h264编码

通过chatgpt查阅资料,了解到需要把mp4使用h264编码,于是就改了这个接口,这样来看格式虽然是h264了,但是仍然无法在网页上播放

avformat_alloc_output_context2(&oc, NULL, NULL, file_name);
//把第三个参数,输出格式强制指定为H264
avformat_alloc_output_context2(&oc, NULL, "h264", file_name);

对比差异

既然通过格式转换是可以播放的,那就对比一下两个视频文件的详细对比差异,差异如下所示:

踩坑ffmpeg录制的mp4无法在浏览器上播放

可以播放的视频 游戏录制的视频
"codec_tag_string": "avc1", "codec_tag_string": "[0][0][0][0]",
"is_avc": "true", "is_avc": "false",

游戏录制的缺少了以下部分字段

"start_pts": 0,
"start_time": "0.000000",
"duration_ts": 45824,
"duration": "3.580000",
"bit_rate": "2161030",
"nb_frames": "179",

手动设置codec_tag

一开始我的重点方向是:codec_tag

在 MP4 文件中,codec_tag 是一个用于标识视频和音频编解码器的标签。它通常是一个四个字母的代码,例如“avc1”表示 H.264 视频编解码器,“mp4a”表示 AAC 音频编解码器。codec_tag 可以帮助播放器确定正确的解码器来解码视频和音频流。在使用 MP4 文件时,确保你的播放器支持所使用的 codec_tag。

然后使用chatgpt查到示例代码加到游戏内但代码编译不通过,原因我们是自己编译的ffmpeg.lib,还需要修改export才能用某些接口,这个问题后面再说

但是手动设置tag之后,问题依赖存在

断点查证

在断点的时候发现调用:avcodec_find_encoder传入的格式并不是h264,而是mpeg4

踩坑ffmpeg录制的mp4无法在浏览器上播放

于是手动在上面添加了一 行用来修改编码格式,但是还是一样的结果

其实在这个时候,我还是有些分不清楚codec_tag和codec的关系

查一些正确的示例

所以让chatgpt给我举例一些使用ffmpeg来编码h264的视频,然后对照我们的代码来分析是问题出在那里,后面了解到某位同事对ffmpeg比较懂,已于向他请教,大大加速了查证过程。

视频每一帧的数据中无pts和dst

ffprobe -show_packets -of xml -i video.mp4,使用这个指令来查看视频中每帧的数据,发现录制出来的视频没有pts和dst

<ffprobe>
Input #0, h264, from 'video.mp4':
  Duration: N/A, bitrate: N/A
  Stream #0:0: Video: h264 (Main), yuv420p(progressive), 1904x1002 [SAR 1:1 DAR 952:501], 25 fps, 100 tbr, 1200k tbn
    <packets>
        <packet codec_type="video" stream_index="0" duration="24000" duration_time="0.020000" size="34080" pos="0" flags="K__"/>
        <packet codec_type="video" stream_index="0" duration="24000" duration_time="0.020000" size="4995" pos="34080" flags="___"/>
        <packet codec_type="video" stream_index="0" duration="24000" duration_time="0.020000" size="817" pos="39075" flags="___"/>
        <packet codec_type="video" stream_index="0" duration="24000" duration_time="0.020000" size="428" pos="39892" flags="___"/>
        <packet codec_type="video" stream_index="0" duration="24000" duration_time="0.020000" size="89" pos="40320" flags="___"/>
        <packet codec_type="video" stream_index="0" duration="24000" duration_time="0.020000" size="169" pos="40409" flags="___"/>
        <packet codec_type="video" stream_index="0" duration="24000" duration_time="0.020000" size="75" pos="40578" flags="___"/>
        <packet codec_type="video" stream_index="0" duration="24000" duration_time="0.020000" size="71" pos="40653" flags="___"/>
        <packet codec_type="video" stream_index="0" duration="24000" duration_time="0.020000" size="71" pos="40724" flags="___"/>
        <packet codec_type="video" stream_index="0" duration="24000" duration_time="0.020000" size="672" pos="40795" flags="___"/>
    </packets>
</ffprobe>

正常情况下每帧的视频数据中是有pts和dst的,于是在写入每帧数据时手动给pts和dst赋值

av_packet_rescale_ts(pkt, *time_base, st->time_base);
pkt->stream_index = st->index;
this->video_st.write_size += pkt->size;
int step = 1000 / this->fps;//ptk.pts每帧加的数值=1000/帧率
pkt->pts = step * m_frameNum;
pkt->dts = step * m_frameNum;
/* Write the compressed frame to the media file. */
return av_interleaved_write_frame(fmt_ctx, pkt);

在av_interleaved_write_frame之前写入pts,之后pts的值就无效了

手动计算pts播放起来非常卡

这样改完之后pts的值是有了,但是播放速度不正常,表现会非常卡,原因就是pts计算错误

踩坑ffmpeg录制的mp4无法在浏览器上播放

assert中断

试过强制修改codec_id,但是碰到问题:在结束录制的时候会中多线程的Assert导致录制得到的视频数据是空的,代码:lib\cstdmf\concurrency.hpp void grab() MF_ASSERT(id_ != gid);

让ffmpeg自动选择输出格式

反复阅读代码然后不断尝试,发现在调用avformat_alloc_output_context2接口不指定格式,而只给输出文件的后缀,录制出来的视频是有pts和dts的!!!

这一下就回到最初的地方,在最早的时候我就是没有设置这个选项的。

踩坑ffmpeg录制的mp4无法在浏览器上播放

接口定义和解释如下:

int avformat_alloc_output_context2(AVFormatContext **ctx, AVOutputFormat *oformat, const char *format_name, const char *filename);

ctx:输出格式上下文的指针,函数执行成功后会将创建的上下文赋值给该指针。
oformat:输出格式,可以为 NULL,表示让 FFmpeg 自动选择输出格式。
format_name:输出格式的名称,可以为 NULL,表示让 FFmpeg 自动选择输出格式。
filename:输出文件名,可以为 NULL,表示不需要输出到文件。

pts有了但格式是mpeg4

然后修改接口,再次编译验证,这一次pts在视频帧数据中有了,但为啥视频格式会变成mpeg4???

测试了一下mpeg4在浏览器上也无法播放,但是可以在win10自带的播放上可以播放。

mp4好了但avi坏了

查看代码,确实有一处地方指定了mpeg4,代码:video_codec = avcodec_find_encoder(AV_CODEC_ID_MPEG4);

于是把它改为video_codec = avcodec_find_encoder(AV_CODEC_ID_H264);,这样终于好了。

再来验证一下以前的录制avi格式,结果发现坏了,以前的avi格式录制不了,断点一下,发现中上面提到的assert了。盲猜是avi不能使用h264,于是修改了一下mp4使用h264,其它格式使用mpeg4,再编译验证,这样就好了。

总结一下:

  1. 初始化avformat_alloc_output_context2不要指定格式,让ffmpeg自动调用,但需要输出的文件后缀为mp4
  2. 调用avcodec_find_encoder把mp4设置h246格式,但是对于avi改为AV_CODEC_ID_MPEG4
  3. 指定视频的文件头
  4. 其它地方不要再手动去修改codec_id,否则在结束录制的时候会出错,导致视频为空
  5. 多观察ffmpeg每一个接口的返回值,特别是非成功的情况下要进行处理

这几个接口需要关注返回值是否成功:

  1. avformat_alloc_output_context2 初始化
  2. avcodec_find_encoder 查找编码器的函数
  3. avformat_write_header 写入视频的header
  4. av_interleaved_write_frame 写入视频每一帧的数据
  5. av_write_trailer 结束录制

参考内容

ffmpeg实现将H264裸流封装成.mp4或.avi文件_ffmpeg对裸流封装-CSDN博客

[原]零基础学习视频解码之FFMpeg中比较重要的函数以及数据结构 - 雪夜&流星 - 博客园 (cnblogs.com)

FFmpeg从入门到入魔(3):提取MP4中的H.264和AAC - 掘金 (juejin.cn)

YUV编码为H264 H264封装为MP4 - 知乎 (zhihu.com)

使用工具

MP4封装格式—音视频基础知识 · FFmpeg原理 (xianwaizhiyin.net)

下载 Mp4 Explorer (apponic.com)文章来源地址https://www.toymoban.com/news/detail-776923.html

到了这里,关于踩坑ffmpeg录制的mp4无法在浏览器上播放的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • ffmpeg把RTSP流分段录制成MP4,如果能把ffmpeg.exe改成ffmpeg.dll用,那音视频开发的难度直接就降一个维度啊

    比如,原来我们要用ffmpeg录一段RTSP视频流转成MP4,我们有两种方案: 方案一:可以使用以下命令将rtsp流分段存储为mp4文件 ffmpeg -i rtsp://example.com/stream -vcodec copy -acodec aac -f segment -segment_time 3600 -reset_timestamps 1 -strftime 1 output_%Y-%m-%d_%H-%M-%S.mp4 方案二:可以直接调用ffmpeg库avcode

    2024年02月10日
    浏览(55)
  • jmeter录制谷歌浏览器脚本配置

    新建测试计划; 添加线程组; 添加非测试元件—http代理服务器; 默认端口8888,如被占用可以修改;目标控制器,录制时捕获的请求放在哪个分组下,可以选择之前新增好的线程组; 排除模式添加 ​​. .(js|css|PNG|jpg|png|gif). ​​,过滤掉​​js、css、png、jpg​​等信息,录

    2024年02月02日
    浏览(37)
  • 如何使用Selenium IDE浏览器插件轻松完成脚本录制,轻松搞定自动化测试!

    Selenium IDE可以用来调式Selenium脚本,支持将浏览器的Web网页操作导出为不同编程语言的脚本。 创建项目之后可以录制或回放已录制的网页操作情况,特别是对一些开发测试人员提供了相当大的便利。 目前,该Selenium IDE插件可以支持Edge/火狐以及谷歌浏览器的使用,其他浏览器

    2024年02月02日
    浏览(54)
  • 部分浏览器 set-cookie 不成功踩坑记录

    事件起因: 公司正在做一个sso的单点登录的项目,做完之后,在测试阶段,不同的终端的兼容测试时候,好几个不同的浏览器出现了不同的问题,有登录之后自动退出,有登陆不成功等问题。 在 pc 端只有 uc 浏览器不成功,移动端有 safari、360浏览器、qq浏览器、uc浏览器等。

    2024年02月09日
    浏览(52)
  • Win10 python环境测试selenium加IE浏览器自动化-踩坑实录

    【背景】 需要访问某个旧网址,仅支持IE浏览器访问。为了实现自动化,被迫采用python加selenium、加IE浏览器来做。 【实录】 selenium采用IE浏览器方式的资料不多,网上可供参考范例不多。以下实时记录整个过程,实现调通一个基本访问实例。 【第一步】安装正确版本的sele

    2024年01月21日
    浏览(95)
  • MacOS浏览器无法上网

    记一个Mac在安装ClashX后出现的问题 Mac 在安装 ClashX或者ClashX Pro后有可能会出现浏览器(谷歌,Safari,火狐)都无法正常上网,但是其他地方网络是正常的,在启动小猫咪后可能更改了系统的配置文件. 在网上搜的解决办法大部分都是在网络中设置WiFi,但是无法解决这问题. 解决办法: 找

    2024年02月14日
    浏览(36)
  • 华为自带浏览器无法使用

    一、首先确认其他浏览器是否正常使用 1.Microsoft Edge 页面截图  2、谷歌页面截图 问题所在:Microsoft Edge浏览器版本 111.0.1661.43 (正式版本64 位)兼容性问题。 二、处理方法 1、将Microsoft Edge浏览器卸载,且将C:Program Files (x86)MicrosoftEdge对应残留文件夹目录删除。 2、删除完去华

    2024年02月04日
    浏览(177)
  • 浏览器无法连接网络问题

    电脑其他程序都能正常联网,但是所有的浏览器都无法联网,同时外部网站都能ping通 查看电脑Internet连接的问题报告显示: 该设备或资源(Web 代理)未设置为接受端口\\\"7890\\\"上的连接 。 经过检查发现不是IP地址设置和防火墙设置的问题,最终 采用重置网络设置解决了问题 。 重

    2024年02月13日
    浏览(39)
  • selenium无法打开浏览器问题

    想利用这个例子简单测试一下安装是否成功? from selenium import wbdriver driver = weddriver.Chrom() driver.get(‘http://www.baidu.com’) 前提是:浏览器版本和浏览器驱动版本是一致的,具体怎么看版本是否是一致的,下期再给大家补充 结果报如下错误: 在安装浏览器的时候浏览器的名字都

    2024年02月11日
    浏览(62)
  • edge浏览器无法登录账号!Microsoft 帐户无法登录!

    种种原因,将笔记本重置了,重新下载装了系统,但是麻烦也来了, Microsoft 帐户无法登录!edge浏览器无法登录账号 ,之前的保存的密码,加星的书签页同步不过去,这不完犊子了!干啥都要忘记密码,找回密码,重新设置密码,新密码不能与原密码重复……!忘记账号,重

    2024年02月08日
    浏览(55)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包