如何在浏览器上播放avi文件

How to play avi files on browser

我的团队需要开发一个在网络上播放 avi 文件的系统。这些文件由我们无法访问其固件的硬件记录。我们正试图与制造商协商将文件格式更改为mp4,但到目前为止我们一无所获。

正因为如此,我们正在尝试另一种方式让它发挥作用。我们的第一个尝试是使用 FFMPEG 将文件转换为 mp4(或 webm 或 ogg),但这个过程花费的时间太长,因为我们每天都必须处理大量视频。

我们也尝试使用 FFMPEG 的复制命令(速度要快得多),但视频总是在某些时候崩溃 (主要是当我们需要在其时间轴中导航时) 和我们不知道为什么。

所以现在想定制videojs flash player来重现AVI文件,但是因为我们对视频编程和flash没有太多经验,所以不知道可不可以。是否可以在动作脚本中编写解码器来读取avi文件?

我看到 Youtube 和 Facebook 可以播放 AVI 文件...他们是怎么做到的?我已经看了很多,但没有成功。

编辑 1

复制命令前的avi视频文件:

$ ffmpeg -i video.avi
ffmpeg version N-82324-g872b358 Copyright (c) 2000-2016 the FFmpeg developers
  built with gcc 5.4.0 (GCC)
  configuration: --enable-gpl --enable-version3 --disable-w32threads --enable-dx                                                                                                                                                                                               va2 --enable-libmfx --enable-nvenc --enable-avisynth --enable-bzlib --enable-lib                                                                                                                                                                                               ebur128 --enable-fontconfig --enable-frei0r --enable-gnutls --enable-iconv --ena                                                                                                                                                                                               ble-libass --enable-libbluray --enable-libbs2b --enable-libcaca --enable-libfree                                                                                                                                                                                               type --enable-libgme --enable-libgsm --enable-libilbc --enable-libmodplug --enab                                                                                                                                                                                               le-libmp3lame --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-lib                                                                                                                                                                                               openh264 --enable-libopenjpeg --enable-libopus --enable-librtmp --enable-libschr                                                                                                                                                                                               oedinger --enable-libsnappy --enable-libsoxr --enable-libspeex --enable-libtheor                                                                                                                                                                                               a --enable-libtwolame --enable-libvidstab --enable-libvo-amrwbenc --enable-libvo                                                                                                                                                                                               rbis --enable-libvpx --enable-libwavpack --enable-libwebp --enable-libx264 --ena                                                                                                                                                                                               ble-libx265 --enable-libxavs --enable-libxvid --enable-libzimg --enable-lzma --e                                                                                                                                                                                               nable-decklink --enable-zlib
  libavutil      55. 36.100 / 55. 36.100
  libavcodec     57. 66.101 / 57. 66.101
  libavformat    57. 57.100 / 57. 57.100
  libavdevice    57.  2.100 / 57.  2.100
  libavfilter     6. 66.100 /  6. 66.100
  libswscale      4.  3.100 /  4.  3.100
  libswresample   2.  4.100 /  2.  4.100
  libpostproc    54.  2.100 / 54.  2.100
Input #0, avi, from 'video.avi':
  Metadata:
    encoder         :
  Duration: 00:50:07.67, start: 0.000000, bitrate: 6 kb/s
    Stream #0:0: Video: h264 (Constrained Baseline) (H264 / 0x34363248), yuv420p                                                                                                                                                                                               (progressive), 352x240, 3 fps, 3 tbr, 3 tbn, 6 tbc
At least one output file must be specified

复制命令(没有音频流,因为视频没有):

$ ffmpeg -i video.avi -vcodec copy video.mp4
ffmpeg version N-82324-g872b358 Copyright (c) 2000-2016 the FFmpeg developers
  built with gcc 5.4.0 (GCC)
  configuration: --enable-gpl --enable-version3 --disable-w32threads --enable-dxva2 --enable-libmfx --enable-nvenc --enable-avisynth --enable-bzlib --enable-libebur128 --enable-fontconfig --enable-frei0r --enable-gnutls --enable-iconv --enable-libass --enable-libbluray --enable-libbs2b --enable-libcaca --enable-libfreetype --enable-libgme --enable-libgsm --enable-libilbc --enable-libmodplug --enable-libmp3lame --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-libopenh264 --enable-libopenjpeg --enable-libopus --enable-librtmp --enable-libschroedinger --enable-libsnappy --enable-libsoxr --enable-libspeex --enable-libtheora --enable-libtwolame --enable-libvidstab --enable-libvo-amrwbenc --enable-libvorbis --enable-libvpx --enable-libwavpack --enable-libwebp --enable-libx264 --enable-libx265 --enable-libxavs --enable-libxvid --enable-libzimg --enable-lzma --enable-decklink --enable-zlib
  libavutil      55. 36.100 / 55. 36.100
  libavcodec     57. 66.101 / 57. 66.101
  libavformat    57. 57.100 / 57. 57.100
  libavdevice    57.  2.100 / 57.  2.100
  libavfilter     6. 66.100 /  6. 66.100
  libswscale      4.  3.100 /  4.  3.100
  libswresample   2.  4.100 /  2.  4.100
  libpostproc    54.  2.100 / 54.  2.100
Input #0, avi, from 'video.avi':
  Metadata:
encoder         :
  Duration: 00:50:07.67, start: 0.000000, bitrate: 6 kb/s
Stream #0:0: Video: h264 (Constrained Baseline) (H264 / 0x34363248), yuv420p(progressive), 352x240, 3 fps, 3 tbr, 3 tbn, 6 tbc
Output #0, mp4, to 'video.mp4':
  Metadata:
encoder         : Lavf57.57.100
Stream #0:0: Video: h264 (Constrained Baseline) ([33][0][0][0] / 0x0021), yuv420p(progressive), 352x240, q=2-31, 3 fps, 3 tbr, 12288 tbn, 3 tbc
Stream mapping:
  Stream #0:0 -> #0:0 (copy)
Press [q] to stop, [?] for help
[mp4 @ 0000000002513fc0] Timestamps are unset in a packet for stream 0. This is deprecated and will stop working in the future. Fix your code to set the timestamps properly
[NULL @ 0000000002524020] missing picture in access unit with size 16
Last message repeated 300 times
frame= 9324 fps=0.0 q=-1.0 Lsize=    1388kB time=01:38:27.66 bitrate=   1.9kbits/s speed=3.32e+004x
video:1354kB audio:0kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: 2.493988%

复制命令后的mp4视频文件:

$ ffmpeg -i video.mp4
ffmpeg version N-82324-g872b358 Copyright (c) 2000-2016 the FFmpeg developers
  built with gcc 5.4.0 (GCC)
  configuration: --enable-gpl --enable-version3 --disable-w32threads --enable-dx                                                                                                                                                                                               va2 --enable-libmfx --enable-nvenc --enable-avisynth --enable-bzlib --enable-lib                                                                                                                                                                                               ebur128 --enable-fontconfig --enable-frei0r --enable-gnutls --enable-iconv --ena                                                                                                                                                                                               ble-libass --enable-libbluray --enable-libbs2b --enable-libcaca --enable-libfree                                                                                                                                                                                               type --enable-libgme --enable-libgsm --enable-libilbc --enable-libmodplug --enab                                                                                                                                                                                               le-libmp3lame --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-lib                                                                                                                                                                                               openh264 --enable-libopenjpeg --enable-libopus --enable-librtmp --enable-libschr                                                                                                                                                                                               oedinger --enable-libsnappy --enable-libsoxr --enable-libspeex --enable-libtheor                                                                                                                                                                                               a --enable-libtwolame --enable-libvidstab --enable-libvo-amrwbenc --enable-libvo                                                                                                                                                                                               rbis --enable-libvpx --enable-libwavpack --enable-libwebp --enable-libx264 --ena                                                                                                                                                                                               ble-libx265 --enable-libxavs --enable-libxvid --enable-libzimg --enable-lzma --e                                                                                                                                                                                               nable-decklink --enable-zlib
  libavutil      55. 36.100 / 55. 36.100
  libavcodec     57. 66.101 / 57. 66.101
  libavformat    57. 57.100 / 57. 57.100
  libavdevice    57.  2.100 / 57.  2.100
  libavfilter     6. 66.100 /  6. 66.100
  libswscale      4.  3.100 /  4.  3.100
  libswresample   2.  4.100 /  2.  4.100
  libpostproc    54.  2.100 / 54.  2.100
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'video.mp4':
  Metadata:
major_brand     : isom
minor_version   : 512
compatible_brands: isomiso2avc1mp41
encoder         : Lavf57.57.100
  Duration: 01:38:28.00, start: 0.000000, bitrate: 1 kb/s
Stream #0:0(und): Video: h264 (Constrained Baseline) (avc1 / 0x31637661), yu                                                                                                                                                                                               v420p, 352x240, 1 kb/s, 1.58 fps, 3 tbr, 12288 tbn, 24576 tbc (default)
Metadata:
  handler_name    : VideoHandler
At least one output file must be specified

编辑 2

如果有人想测试,我上传了两个小样本:

We also tried to use FFMPEG's copy command (which is much faster), but the video always crashes at some point (mainly when we need to navigate in its timeline) and we don't know why.

这是给你的 re-fixed MP4 的 link。正在寻找。
我手动检查了字节,正如我所怀疑的那样,时间戳是错误的。

FFprobe(使用 ffprobe video.avi)表示 AVI 持续时间为 5.88 秒。 MPC-HC 还显示持续时间为 6 秒(四舍五入)。现在我们稍后期望 MP4 在使用 copy 命令时也具有相同的 5.88 持续时间。但是在 copy 之后,输出的 MP4 有一个新的 10 秒持续时间???

MP4 将持续时间放在 3 个位置。每个软件都有自己的规则来检查哪个条目,所以为了每个人的缘故,最好编辑所有 3 个地方。元数据分为 "atoms" 所以我们编辑 3 个原子。

这些称为 mvhdtkhdelst 的原子的持续时间都具有字节值 00 00 28 87,等于 10375 毫秒(或 10.375 秒)。 这是错误的,因为我们想要 5880 毫秒(或 5.88 秒)。我手动将它们全部从 00 00 28 87 更改为 00 00 16 F8,这给出了 5880 毫秒。现在 MPC-HC 认为 mp4 是 5 秒(呸!!)但是 Chrome 一直说它仍然是 10 秒(该死的!!)。

作为最后的手段,我检查了一个名为 stts 的原子。这有 3 个项目用于总共 136 帧的计时(注意 FFprobe 说 AVI 实际上有 141 帧)。无论如何,第一项表示前 128 帧的显示时间为 512 毫秒(持续时间为 128 * 512 = 65536 ms)。这是错误的。

长话短说。我编辑 stts 说...

  • 而不是 03 只有 01 显示时间条目(但其他条目字节未被删除)。
  • 而不是00 00 00 80 = 128,实际上是00 00 00 8D = 141帧
  • 我仍然保留这些(现在 141 帧)的原始显示时间 00 00 02 00 = 512 毫秒
  • 我将剩余的两个条目字节全部更改为零(因为我们不需要使用它们)。

正如在 Chrome 浏览器中测试的那样,这就是您的 MP4 成为工作的可搜索文件的方式。

结论:

要修复您自己的文件,我怀疑仅编辑 MP4 元数据中 stts 部分的第一个条目就足够了。你告诉它 "I have X-amount of frames, each frame displays for X interval, no extras!!"。然后只需在 mvhdtkhdelst 中编辑持续时间。在这里你必须知道如何使用字节。

编写一个桌面程序(如果您团队中有人可以做到)...

  • 从 AVI 获取 "duration" 和 "total frames"(我推荐 ExifTool 而不是 FFprobe,因为它可以正确显示这两个细节)。您的程序通过 std in/out.

  • 读取此信息
  • 一旦知道,搜索原子名称作为 UTF 文本以找到它们在字节中的 beginning 位置。

  • 当你有每个起始位置时......你现在将把数字编辑为 4 字节整数(以十六进制表示法编写)

    • 找到“mvhd”的开始位置,然后跳过 20 个字节以找到持续时间。
    • 查找“tkhd”的开始位置,然后跳过 24 个字节以查找持续时间。
    • 找到“elst”的开始位置,然后跳过 24 个字节以找到持续时间。
  • 最后找到“stts”的起始位置,然后跳过 8 个字节找到总条目(4 个字节)。接下来的 4 个字节是 "total frames" 数字(你用实数修复),然后接下来的 4 个字节是帧的时间但保持不变...

其他查询: ...

Is it possible to write a decoder in action script to read avi files? I saw that Youtube and Facebook can play AVI files... How do they do this?

是的!!由于您的 AVI 具有 Mpeg (H.264) 视频,Flash 具有接受 MPEG a/v 字节的解码器,因此如果您从 AVI 中提取帧字节并将它们提供给解码器,它将显示。

这个旧的 demo app 是一个例子,我将 Mpeg 的 AAC 音频字节提供给解码器。 AVI 的原理相同。我与 Flash 一起工作,但我会告诉你......最好修复文件,而不是世界上只有一个定制的应用程序可以播放它们的情况。固定文件适用于 Flash、HTML5 浏览器和其他任何地方。

PS : Facebook 和 Youtube 正在重新编码您的文件。它不是直接文件副本。

我们终于解决了这个问题。

虽然@VC.One的解决方案似乎可行,但我们没有成功,因为我们认为有更好的方法可以解决它而不必进行字节操作(一旦我们没有有很多经验)...

经过多次尝试,我们意识到我们的 AVI 文件格式不正确,所以我们使用了一个名为 Mencoder 的程序,该程序具有函数 forceidx:

Force index rebuilding. Useful for files with broken index (A/V desync, etc). This will enable seeking in files where seeking was not possible. You can fix the index permanently with MEncoder (see the documentation). NOTE: This option only works if the underlying media supports seeking (i.e. not with stdin, pipe, etc).

在运行这个命令之后,我们使用FFMPEG的复制命令"convert"将(现在格式正确的)AVI文件转为mp4。瞧!奇迹发生了!

非常感谢你们!

谢谢,@VC.One 到此为止!