View in English

  • 打开菜单 关闭菜单
  • Apple Developer
搜索
关闭搜索
  • Apple Developer
  • 新闻
  • 探索
  • 设计
  • 开发
  • 分发
  • 支持
  • 账户
在“”范围内搜索。

快捷链接

5 快捷链接

视频

打开菜单 关闭菜单
  • 专题
  • 相关主题
  • 所有视频
  • 关于

更多视频

大多数浏览器和
Developer App 均支持流媒体播放。

  • 简介
  • 转写文稿
  • 代码
  • 使用 AVAssetWriter 创作 片段 MPEG-4 内容

    转换你的音频和视频内容至分段式 MPEG-4 文件,从而获得更快、更流畅的 HLS 流媒体体验。了解如何使用分段式 MPEG-4 格式,如何从电影中获得分段式内容以及如何设置 AVAssetWriter,从而创建用于 HLS 输出的片段。

    资源

    • Writing Fragmented MPEG-4 Files for HTTP Live Streaming
      • 高清视频
      • 标清视频
  • 搜索此视频…

    (你好 WWDC 2020) 你好 欢迎来到 WWDC

    (使用 AVAssetWriter 创作 片段 MPEG-4 内容) 你好 我叫 Takayuki Mizuno 我是 Apple 公司的 CoreMedia 工程师 本次讲座主要关于 AVFoundation 的新功能 可用于为 HLS 编写片段 MP4 文件 下列图表显示出 HLS 的典型工作流 有一个来源材料 可以是视频点播素材 也可以是直播素材 有一部分对媒体数据进行编码 其中 假设视频样本被编码到 HEVC 而音频样本被编码到 AAC (工作流) 这里有一个分段器

    它以特定格式分段媒体数据

    分段器还创建了播放列表 能同时列出这些片段

    最后 还有一个承载内容的 web 服务器 AVFoundation 提供的新功能 主要是用于分段器之中

    AVFoundation 具有 AVAssetWriter 允许媒体创作 app 以便将媒体数据编写指定容器类型 如 MP4 的新文件 我们对它进一步增强 使其能够以 片段 MP4 格式输出用于 HLS 的媒体数据

    Apple HLS 可支持其他格式 如 MPEG-2 传输流 ADTS 和 MPEG 音频 但这个新特性主要用于片段 MP4 来看看其中一个用例 (用例) 我以视频点播素材的来源为例

    AVFoundation 具有 AVAssetReader 它是从媒体文件读取示例数据的 对象

    你可以从源电影中读取示例数据 然后将示例推送到 AVAssetWriter 接着编写片段 MP4 分段文件

    再比如 来源是直播材料

    AVFoundation 具有 AVCaptureVideoDataOutput 和 AVCaptureAudioDataOutput 它们可以为你提供从连接设备捕获的 样本数据的对象

    你从设备接收示例数据 将示例推送到 AVAssetWriter 并编写片段 MP4 分段文件 片段 MP4 是一种流媒体格式 基于 ISO 基本媒体文件格式 Apple HTTP Live Streaming 自 2016 年开始就支持片段 MP4 下面是一个标准 MP4 文件的基本图 它以文件类型框开始 该框指示此文件符合哪种文件格式 (格式结构) 有一个电影框正在组织 关于所有示例数据的信息 然后有一个媒体数据框包含了 所有示例数据 电影框包含与整个示例相关的信息 例如音频和视频编解码器

    它还包含对示例数据的引用 例如示例数据的位置 那些框的顺序大多是任意排序的

    必须先显示“文件类型”框 然后其他框就可以任意排序 如果你使用过 AVAssetWriter 就会知道 AVAssetWriter 具有 movieFragmentInterval 属性 这指定了电影片段的编写频率

    由此产生的电影就是所谓的片段电影 这里是一个片段电影文件的基本图

    在这个电影中有电影片段框 它引用了跟在后面的媒体数据框中保存的 所有示例数据

    这种格式结构很有用 比如在实时捕获中 即使编写是因为崩溃而意外中断 或者诸如此类 部分编写的数据仍然可以访问和播放

    请注意 这个片段电影场景 如果编写成功完成 AVAssetWriter 就将作为最后一步 对文件进行片段整理 这就最终形成了标准的电影文件

    这里是片段 MP4 文件的基本图 首先显示“文件类型”框 接着在文件类型框之后的是电影框 然后是电影片段框 跟在后面的是媒体数据框 然后是两个电影片段框 以及媒体数据框 那些框的顺序理应如下 片段电影与片段 MP4 的主要区别 在于片段 MP4 电影框 不包含对示例数据的引用 它只包含与整个样本相关的信息 而电影片段框和媒体数据框的顺序 则是倒转过来

    现在我将讨论如何使用 AVAssetWriter 这里展示了如何创建 AVAssetWriter 的实例 你不需要提供输出 URL 因为 AVAssetWriter 不编写文件而是输出数据 你只需指定输出内容类型 片段 MP4 符合 MP4 系列 因此 你应该始终指定 UTType 与 AVFileType MP4 创建 AVAssetWriterInput 在本例中 以作为代码字典的压缩设置 来对媒体样本进行编码 或者 可以将输出设置设置为”空值“ 这称为”通过“模式 在通过模式下 AVAssetWriter 只按给定的方式编写示例 然后将输入添加到 AVAssetWriter 下面讲述了如何配置 AVAssetWriter 你必须指定 outputFileTypeProfile (配置 AVASSETWRITER) 你应该指定 Apple HLS 或 CMAF 兼容配置文件 以片段 MP4 格式输出媒体数据

    你需要指定 preferredOutputSegmentInterval

    AVAssetWriter 以该间隔输出媒体数据 该间隔时间可以是合理的时间 但是 HLS 的目标片段持续时间 必须是以秒为单位的整数 因此这里不使用更高的精度 因为这对 HLS 来说是正确的选择 你还可以指定初始段开始时间

    这是间隔的起点

    然后指定实现指定协议的委托对象

    我稍后会再讲述协议 在此之后 继续进行与正常文件 编写相同的过程

    开始编写 然后使用 AVAssetWriterInput 追加示例

    我不打算在这次讲座上再谈这个了 但你可以查看 2011 年 WWDC 讲座 “在 AV Foundation 中与媒体合作” 那就能看到如何执行那些过程了 你可以在 Apple 的开发者网站上 找到讲座视频 下面是委托方法的协议 有两种方法 这两种委托方法都能传递 片段媒体数据的 NS 数据 (委托方法) 它们还能传递 AVAssetSegmentType

    可指示分段媒体数据的类型

    以其中一种方法实现即可 不同之处在于 第二种方法 传递 AVAssetSegmentReport 对象 该对象包含有关片段媒体数据的信息 如果你不需要这些信息 就要实现第一种

    AVAssetSegmentType 有两种类型 初始化和可分离 具有初始化类型的分段媒体数据 包含“文件类型”框和“电影”框 具有可分离类型的片段媒体数据 分别包含电影片段框和媒体数据框

    你将成功地接收具有可分离类型的数据

    (编写文件) 你将接收到的媒体数据打包成所谓的片段 然后编写该文件片段

    一对文件类型框和电影框

    应该是初始化段

    还有那对电影片段框和媒体数据框

    可以是一个片段

    对于 HLS 来说 包含所有这些片段的单个文件 可用于流式传输

    或者可以将每个片段划分为多个片段文件

    此外 多对电影片段框 和媒体数据框可以是一个片段 并存储在一个片段文件中 HLS 使用播放列表 播放列表是客户端发现片段的主要途径 (播放列表) 这里有一个播放列表的例子 有几个标记指示有关片段的信息 例如 URL 和持续时间 AVAssetWriter 不编写播放列表 而是该由你来编写播放列表 这就是为什么其中一个委托方法 要交付 AVAssetSegmentReport 你可以基于 AVAssetSegmentReport 提供的信息 创建播放列表和 I-frame 播放列表

    只要看到我们的示例代码 fmp4Writer 你就能看到如何创建播放列表 此外 关于播放列表的文档 可以在这里的开发者流页面找到 在通过模式中 即不对样本进行编码的模式 AVAssetWriter 输出的媒体数据包括 在达到或超过优选 输出段间隔之后的 下一个同步样本之前的所有样本 (片段间隔) 这里的同步样本 是一个不依赖于其他样本的样本 这是因为 CMAF 要求每个数据段 以同步样本开始 而 Apple HLS 也更喜欢这样 此规则不仅适用于视频 而且还适用于具有示例依赖项的音频 如 USAC 音频 因此 对于通过模式 只能添加一个 AVAssetWriterInput 如果同步样本不在间隔附近布局 则媒体数据可能在 远超过指定持续时间的时间内输出 因此 它将不适合 HLS 解决方案之一是同时对视频样本进行编码 正如我前面提到的 如果你在 AVAssetWriterInput 中 为压缩指定输出设置 则示例将被编码 在编码模式下 刚刚到达 或超过首选输出段间隔的视频样本 将强制编码为同步样本

    换句话说 同步样本是自动生成的 使得分段媒体数据 将以指定的间隔 或非常接近指定的间隔输出 如果同时编码音频和视频 可以为每个媒体添加一个 AVAssetWriterInput 我在前面说过 对于通过模式 只能添加一个 AVAssetWriterInput 但你可以使用主播放列表 将视频和音频作为单独的流传送 你不仅可以传送一对音频和视频流 还可以传送各种比特率或不同语言的流

    你需要创建 AVAssetWriter 的 多个实例 才能创建多个流 同样 关于主播放列表的文档 和 HLS 编码视频和音频的建议 可在这里的开发者流页面中找到

    这是一个高级用例 但如果你需要有别于 preferredOutputSegmentInterval 的 其他分段 你可以自己来实践一下 例如 你可能希望不是在达到间隔之后 而是在达到间隔之前以同步采样 输出媒体数据 下面是我前面展示的代码 它设置了 AVAssetWriter 的属性 要发出自定义分段的信号 请将 preferredOutputSegment- Interval 设置为 CMTime indefinite 不需要设置 initialSegmentStartTime 因为没有间隔 其他设置 与 preferredOutputSegment- Interval 的设置相同 这只用于通过 不能使用自定义分段进行编码 所以当你创建 AVAssetWriterInput 时

    你必须将输出设置设置为“空值”

    调用 flushSegment方法输出媒体数据

    FlushSegment 输出媒体数据 它包括自上次调用后追加的所有示例

    必须在同步示例之前调用 flushSegment 这样下一个分段媒体数据 就可以从同步示例开始

    否则将出现错误 提示说 出现以非同步样本开始的片段媒体数据

    在此模式下 你可以多路复用音频和视频 但如果音频和视频都具有示例依赖项 那么将很难均匀地对齐这两种媒体 在这种情况下 你应该考虑 将视频和音频打包为单独的流 (音频具有依赖性) AVAssetTrack 现在有了一个新属性 能指示出音轨是否具有样本依赖项

    你可以使用此属性预先检查曲目是否具有 示例依赖项 我之前提到过 你应该指定 Apple HLS 或 CMAF 兼容配置文件 以片段 MP4 格式输出媒体数据 (通用媒体应用格式 即CMAF) CMAF是一组关于 如何构造片段 MP4 分段的约束

    它是使用片段 MP4 进行流式传输的标准

    它得到了包括 Apple HLS 在内的 众多播放机的支持 如果你只想应用于 Apple HLS 则不需要某些约束 但如果你希望媒体库有更广泛的受众 那么就可以考虑 CMAF

    现在我将谈谈 HLS 是如何处理音频启动的 此图表示 AAC 音频的音频波形 (音频启动) AAC 音频编解码器需要源 PCM 音频样本以外的数据 来正确编码和解码音频样本 全因编码算法的性质 因此 编码器在第一个真实音频样本之前 添加静音

    这叫做启动 AAC 最常见的启动是 2112 个音频样本 大约是 48 毫秒 假定采样速率为 44100 的情况下

    当音频和视频作为单独的流 编写入单独的文件时 媒体数据是这样布局的

    假定两种媒体都从时间零点开始 你可能已经注意到了 如果音频和视频同时开始

    音频将被启动延迟 这样音频和视频就会稍微不匹配 CMAF 在音轨中采用编辑列表框 来弥补这个问题 启动被剪辑掉了

    使得音频和视频开始时间匹配

    从前面来看 Apple HLS 并没有使用编辑列表 所以如果指定 Apple HLS 配置文件 编辑列表框就不会用于与旧播放机兼容 相反 音频媒体 baseMediaDecodeTime 将启动量向后移动

    然而 baseMediaDecodeTime 不能早于零 因为它被定义为无符号整数

    一种解决方案是将音频和视频向前移动 相同的时间偏移 这样 音频媒体的 baseMediaDecodeTime 可以向后移动启动量

    即使开始时间不为零 在 HLS 中 回放从视频样本的最早呈现时间开始

    因此回放立即开始 而无需等待时间偏移

    这不仅对精确的视频和音频同步 非常重要 而且对于具有不同启动持续时间的 音频变体之间的时间戳精确匹配 也非常重要 因此我们建议你通过向所有样本 添加一定量的时间来转移媒体时间 若是要指定 Apple HLS 配置文件的话

    初始段开始时间也应偏移 相同的时间偏移

    正如我前面所说的 最常见的启动时间不到一秒 所以几秒钟的时间偏移就足够了 而 Media File Segmenter 是 Apple 的分段器工具 具有 10 秒的偏移 这样就可以选择同样的 10 秒 我们的示例代码展示了 如何为所有示例添加时间偏移 在本次演示中 我将使用示例命令行 app 来创建片段 MP4 分段文件和播放列表

    然后我将使用 Safari 播放结果内容

    此演示场景预先设置为本地服务器 以便托管内容

    我在终端 app 中输入了命令行 app

    此命令行 app 从预先制作的源电影中 读取媒体数据 并对视频和音频进行编码 这就是源电影 长度只有 30 秒 此命令行 app 使用 6 秒钟 作为首选输出片段间隔 片段文件和播放列表将在此目录中创建 我们开始吧 源电影的视频帧率为每秒 30 帧 你可以看到有五个片段文件 并创建了一个播放列表 我打开播放列表

    每个片段的持续时间为 6 秒

    我输入本地主机作为 URL 然后使用 Safari 播放它

    我们开始吧

    HLS 有几个要求 它也有几个建议来改善用户的体验 我们建议你使用 AVAssetWriter 验证 你所编写的片段文件和播放列表 从而确保这些文件符合要求和建议 2016 年 WWDC 讲座 “验证 HTTP Live Streams” 是实现这一目标的优秀来源 你可以在 Apple 的开发者站点 中找到相应的讲座视频

    AVAssetWriter 现在为 HLS 输出分段 MP4 格式的媒体数据 感谢你参加本次讲座

    • 5:36 - Instantiate AVAssetWriter and input

      // Instantiate asset writer
      let assetWriter = AVAssetWriter(contentType: UTType(AVFileType.mp4.rawValue)!)
      
      // Add inputs
      let videoInput = AVAssetWriterInput(mediaType: .video, outputSettings: compressionSettings)
      			
      assetWriter.add(videoInput)
    • 6:28 - Configure AVAssetWriter

      assetWriter.outputFileTypeProfile = .mpeg4AppleHLS
      
      assetWriter.preferredOutputSegmentInterval = CMTime(seconds: 6.0, preferredTimescale: 1)
      
      assetWriter.initialSegmentStartTime = myInitialSegmentStartTime
      
      assetWriter.delegate = myDelegateObject
    • 8:00 - Delegate methods

      optional func assetWriter(_ writer: AVAssetWriter, didOutputSegmentData segmentData: Data, segmentType: AVAssetSegmentType)
      
      
      optional func assetWriter(_ writer: AVAssetWriter, didOutputSegmentData segmentData: Data, segmentType: AVAssetSegmentType, segmentReport: AVAssetSegmentReport?)
    • 8:37 - AVAssetSegmentType

      public enum AVAssetSegmentType : Int {
          case initialization = 1 
          case separable = 2
      }
    • 13:45 - Custom segmentation

      // Set properties
      assetWriter.outputFileTypeProfile = .mpeg4AppleHLS
      
      assetWriter.preferredOutputSegmentInterval = .indefinite
      
      assetWriter.delegate = myDelegateObject
      
      // Passthrough
      let videoInput = AVAssetWriterInput(mediaType: .video, outputSettings: nil)
    • 15:17 - Audio has dependencies

      extension AVAssetTrack {
             /* indicates whether this audio track has dependencies (e.g. kAudioFormatMPEGD_USAC) */
          open var hasAudioSampleDependencies: Bool { get }
      }

Developer Footer

  • 视频
  • WWDC20
  • 使用 AVAssetWriter 创作 片段 MPEG-4 内容
  • 打开菜单 关闭菜单
    • iOS
    • iPadOS
    • macOS
    • Apple tvOS
    • visionOS
    • watchOS
    打开菜单 关闭菜单
    • Swift
    • SwiftUI
    • Swift Playground
    • TestFlight
    • Xcode
    • Xcode Cloud
    • SF Symbols
    打开菜单 关闭菜单
    • 辅助功能
    • 配件
    • App 扩展
    • App Store
    • 音频与视频 (英文)
    • 增强现实
    • 设计
    • 分发
    • 教育
    • 字体 (英文)
    • 游戏
    • 健康与健身
    • App 内购买项目
    • 本地化
    • 地图与位置
    • 机器学习
    • 开源资源 (英文)
    • 安全性
    • Safari 浏览器与网页 (英文)
    打开菜单 关闭菜单
    • 完整文档 (英文)
    • 部分主题文档 (简体中文)
    • 教程
    • 下载 (英文)
    • 论坛 (英文)
    • 视频
    打开菜单 关闭菜单
    • 支持文档
    • 联系我们
    • 错误报告
    • 系统状态 (英文)
    打开菜单 关闭菜单
    • Apple 开发者
    • App Store Connect
    • 证书、标识符和描述文件 (英文)
    • 反馈助理
    打开菜单 关闭菜单
    • Apple Developer Program
    • Apple Developer Enterprise Program
    • App Store Small Business Program
    • MFi Program (英文)
    • News Partner Program (英文)
    • Video Partner Program (英文)
    • 安全赏金计划 (英文)
    • Security Research Device Program (英文)
    打开菜单 关闭菜单
    • 与 Apple 会面交流
    • Apple Developer Center
    • App Store 大奖 (英文)
    • Apple 设计大奖
    • Apple Developer Academies (英文)
    • WWDC
    获取 Apple Developer App。
    版权所有 © 2025 Apple Inc. 保留所有权利。
    使用条款 隐私政策 协议和准则