使用 FFmpeg 在 iOS 上编写时将 fMP4 转码为 HLS

Posted

技术标签:

【中文标题】使用 FFmpeg 在 iOS 上编写时将 fMP4 转码为 HLS【英文标题】:Transcoding fMP4 to HLS while writing on iOS using FFmpeg 【发布时间】:2016-11-08 16:47:23 【问题描述】:

TL;DR

我想将 fMP4 片段转换为 TS 片段(用于 HLS),因为片段是在 ios 设备上使用 FFmpeg 编写的。

为什么?

我正在尝试在 iOS 上实现实时上传,同时在本地保持无缝的高清副本。

我尝试过的

    滚动AVAssetWriters,每个写入 8 秒,然后通过 FFmpeg 将 MP4 连接在一起。

    出了什么问题 - 音频和视频有时会出现中断。我已经确定了 3 个原因。

    1) AAC 编码器写入的音频启动帧会产生间隙。

    2) 由于视频帧长为 33.33 毫秒,音频帧长为 0.022 毫秒,因此它们可能不会在文件末尾对齐。

    3) Mac OS 上缺少帧精确编码,但不适用于 iOS Details Here

    FFmpeg 将带有原始音频的大型纯视频 MP4 文件混合到 TS 段中。该作品基于Kickflip SDK

    出了什么问题 - 每隔一段时间就会上传一个只有音频的文件,没有任何视频。永远无法在内部重现它,但是当我们的用户没有记录他们认为自己做了什么时,这让他们非常沮丧。最终片段的准确搜索也存在问题,几乎就像 TS 片段的时间戳不正确一样。

我现在在想什么

Apple 在今年(2016 年)的 WWDC 上推出了 fMP4,在此之前我根本没有仔细研究过它。由于可以读取 fMP4 文件并在写入时播放,因此我认为 FFmpeg 也可以在文件写入时对其进行转码,只要我们推迟发送字节到 FFmpeg,直到文件中的每个片段完成。

但是,我对 FFmpeg C API 不够熟悉,我只是在尝试 #2 中短暂使用过它。

我需要你什么

    这是一个可行的解决方案吗?是否有人对 fMP4 足够熟悉,知道我是否真的可以做到这一点? 我怎么知道AVFoundation 已在文件中完成了一个片段的写入,以便我可以将其通过管道传输到 FFmpeg? 如何从磁盘上的文件中获取数据,一次分块,将其传递到 FFmpeg 并让它输出 TS 段?

【问题讨论】:

这个问题应该有助于如何提问。写得很好的问题。 我已经放弃了这种方法,转而使用VideoToolbox(文档记录很差)来转换内存中的帧,而不是使用AVAssetWriter 中间人。代码基于此示例 github.com/twinenginelabs/kickflip-ios-sdk 【参考方案1】:

如果fmp4包含h264+aac,严格来说不需要转码,只需将样本数据重新打包成TS即可。 (使用ffmpeg -codec copy 或gpac)

写。对齐 (1.2) 我想这一切都取决于您的编码器设置(帧速率、采样率和 GOP 大小)。当然可以确保音频和视频在片段边界处完全对齐(例如:this table)。如果您的目标是 iOS,我建议您使用 HLS protocol 版本 3(或 4),以便更准确地表示时间。这还允许您单独流式传输音频和视频(非多路复用)。

我相信 ffmpeg 应该能够推送实时 fmp4 流(即使用长时间运行的 HTTP POST),但播放需要 origin software 来做一些有意义的事情(即流到 HLS)。

【讨论】:

以上是关于使用 FFmpeg 在 iOS 上编写时将 fMP4 转码为 HLS的主要内容,如果未能解决你的问题,请参考以下文章

ios 怎么配置编译ffmpeg

ffmpeg安装之linux编译安装

ffmpeg 存流为hls文件

在 Mac OS 上编译 FFmpeg

161ffmpeg 5 的用法总结

如何在 Windows 上编译 64 位版本的 ffmpeg?