大多数浏览器和
Developer App 均支持流媒体播放。
-
探索 AVFoundation 中的 HLS 变体
了解如何使用 AVFoundation API 来凸显 app 中内容的不同变体。我们将展示如何使用这些 API 针对不同的视频特征检查 HLS 内容,包括 SDR/HDR、FPS 等属性。我们将探索代表流化和离线内容的 AVAssetVarient。
资源
相关视频
WWDC21
WWDC20
-
下载
♪播放重低音音乐♪ 嗨 欢迎来到WWDC开发者大会 我是尼尚 是位工程师 AVFoundation小队的一员 今天我们会来看 HTTP实时流媒体变量 首先 我们会先看你要如何查看 HTTP实时流媒体变量 用AVFoundation的API 接着 我们会看要如何在下载的情况下 使用HTTP实时流媒体变量 那我们就先从变量查看开始 你们一定很熟悉 典型的主播放列表长怎样 来看这个例子 在这特定的播放列表 我们有两个变量 其中一个变量是有着立体声的 软件定义无线电变量 另一个是杜比视界变量 有着杜比全景声 这特定播放列表的涵盖数据 可能会用这个方式 呈现在你的app上 看仔细一点 你可以看到它有4K影像 杜比视界和杜比全景声标记 在以前的版本 你必须从外面取得这个信息 现在在iOS 15 你可以直接查看HTTP实时流媒体 播放列表来推测它们 首先 你先把一个AVURLAsset 指向主播放列表的位置 接着 你可以得到 HTTP实时流媒体播放列表 经由变量的性质 我们看到的这个AVAsset变量 代表一个从主播放列表来的 HTTP实时流媒体变量 所以它有多个性质 代表不同媒体属性 有些属性 像是媒体比特率 可以直接被取得 另一些属性 像是那些跟影片和音频翻译有关的 会被组成群组并分到各自的子类 分别叫做影片属性 和音频属性 你可以看到 它们两个各自有相应的性质 你可以用它们来了解你的涵盖数据 现在你知道要如何在AVFoundation 查看HTTP实时流媒体变量了 现在我们来看要如何 在下载的情况下使用它们 我们从2016年就开始支持 下载HTTP实时流媒体内容 来使用线下回放 如果你还不熟悉 下载HTTP实时流媒体的API 建议你看看在2020年的 WWDC开发者大会里 针对这个主题的相关讲座 从iOS 15开始 我们会把 下载HTTP实时流媒体的API 功能变得更强大 正常来说 你会想要改变 HTTP实时流媒体变量 被选起来要下载的那些 这可能是因为工作需求 或你只是想要把更多选择 提供给你的用户 以前 你可以这样改变 用downloadTask的选项 我们有一个高动态范围的选项 无损音频的选项 和一些其他的属性 从iOS 15开始 我们扩张了变量的选择 用NSPredicates 你可能已经从Core Data 熟悉怎么用谓词了 如果没有 不用担心 你今天会学到它们 在开始前 我先来介绍变量副标目界面 这个界面让你能够指定变量偏好 给AVFoundation 就像我说的 它们可以被建立起来 用NSPredicates 我们来用几个例子了解一下 这里我们有一个 可以让NSPredicates表示出 少于五个兆位的高峰比特率 你可以用这个来建立你的变量副标目 它可以命令AVFoundation 选出少于五个兆位的变量 简单吧? 我们来看另外一个例子 这里我们建立了一个NSPredicates 给高动态范围的影片范围 跟之前很像 你可以为它建立变量副标目 你也可以合并多个谓词 来建立复合谓词 然后用它们建立你的变量副标目 所有变量的性质都可以 用来针对性质建立一个谓词 有些性质 像音频频道计数 没办法很容易地被 用谓词格式字符串表示 我们有自定的构建器 你可以在标头文件查询它们 是专门解释变量副标目的 当你有了你的变量副标目 你可以用它建立一个 叫内容配置的东西 每个内容配置代表一套影片 音频和字幕翻译 好 我们来举个例 这里是一个变量副标目 它合并了两个我们先前看到的谓词 对 这有点复杂 他告诉AVFoundation 要选择高动态范围变量 少于五个兆位的 我们也有一套媒体的选择 代表英文和法文音频 和英文字幕翻译 这两个都可以用来 建立一个内容配置对象 你可以建立多个像这样的内容配置 然后把它提供给downloadTask 这些多个内容配置会 被下载配置界面绑在一起 这是支持所有东西的根本 它是用AVURLAsset建立的 而且需要一个涵盖数据名称 或是一个影像 这些涵盖数据名称和影像会呈现在 “设置”app 里 这让你的用户 可以管理他们所有的下载资料 在同一个地方 在“设置”app 当然 downloadTask可以被配置 用多个内容配置 仔细看 其中一个内容配置 会被指定为主要的 剩下的会是辅助的 两个的差别是 你通常会想要 下载主要的一套影片、音频 和字幕翻译 然后再加上 额外的音频或字幕翻译做辅助 要指定你额外的翻译 当作辅助的内容配置 你可以命令AVFoundation 来优化 和避免重复下载多个影片翻译 我们看一个例子就会更清楚了解了 这里是个完整的例子 首先 我们先建立一个下载配置 包含AVURLAsset和一个标题 主要的内容配置 跟我们刚刚看到的一样 它被配置来下载少于五个兆位的 高动态范围变量 含英文及法文音频 和英文字幕翻译 在这特定的例子中 我们会想要帮它外加 一个辅助的内容配置 来以无损格式下载英文音频 现在我们有两个内容建置 是我们想要下载的 要记得确定把 优化的辅助内容配置设定为真 对了 它原本预设就是真了 它可以让AVFoundation 选择无损变量 让无损变量的影片翻译 可以跟主要的内容配置一样 如果设定成假 可能会造成无损变量 被独立评估 造成重复下载影片翻译 这可能会增加你的下载大小 是我们不想要的 好 当你有下载配置时 你可以用它来建立downloadTask 恢复downloadTask来开始下载 从iOS 15开始 你可以观看downloadTask的进度 用NSProgress界面 NSProgress对象 是可以用KVO观察的 你可以用它来更新你的用户界面 接下来 我们知道可能有些人 需要商业逻辑 来选择变量 可能会比较难用谓词来表示 在这个情况下 你也可以选择 明确地选择你想下载的变量 举个例子 我们已经选出主要的和辅助的变量 和相对应的媒体选择 我们可以命令AVFoundation 去照现状下载它们 直接用变量建立副标目 要小心选择变量 它们要可以在下载的装置上播放 今天的介绍就到这里了 总结一下 我们介绍了要如何查看 HTTP实时流媒体变量 和如何用它们配置downloadTask 过程中 我们用到不同界面 来配置downloadTask 第一个是变量副标目 这是用来表示你的变量偏好 然后我们看到内容配置界面 内容配置会把 你的变量偏好 和你的媒体选择绑在一起 再来 我们看到下载配置 下载配置是最根本的界面 它会把所有东西绑在一起 最后我们也学到 你可以用NSProgress 监测你的downloadTask 想知道更多信息 请看我们提供的相关文档 它们都讲得非常详细 谢谢观看 再见 ♪
-
-
0:40 - HLS Master Playlist
#EXTM3U #EXT-X-VERSION:7 #EXT-X-INDEPENDENT-SEGMENTS #EXT-X-MEDIA:TYPE=AUDIO,NAME="English",GROUP-ID="stereo",LANGUAGE="en",DEFAULT=YES, AUTOSELECT=YES,CHANNELS="2",URI="en_stereo.m3u8" #EXT-X-MEDIA:TYPE=AUDIO,NAME="French",GROUP-ID="stereo",LANGUAGE="fr",DEFAULT=NO, AUTOSELECT=YES,CHANNELS="2",URI="fr_stereo.m3u8" #EXT-X-MEDIA:TYPE=AUDIO,NAME="English",GROUP-ID="atmos",LANGUAGE="en",DEFAULT=YES, AUTOSELECT=YES,CHANNELS="16/JOC",URI="en_atmos.m3u8" #EXT-X-MEDIA:TYPE=AUDIO,NAME="French",GROUP-ID="atmos",LANGUAGE="fr",DEFAULT=NO, AUTOSELECT=YES,CHANNELS="16/JOC",URI="fr_atmos.m3u8" #EXT-X-STREAM-INF:BANDWIDTH=14516883,VIDEO-RANGE=SDR,CODECS="avc1.64001f,mp4a.40.5", AUDIO="stereo",FRAME-RATE=23.976,RESOLUTION=1920x1080 sdr_variant.m3u8 #EXT-X-STREAM-INF:BANDWIDTH=34516883,VIDEO-RANGE=PQ,CODECS="dvh1.05.06,ec-3", AUDIO="atmos",FRAME-RATE=23.976,RESOLUTION=3840x1920 dovi_variant.m3u8
-
3:38 - Peak bitrate cap predicate
let peakBitRateCap = NSPredicate(format: "peakBitRate < 5000000") let peakBitRateCapQualifier = AVAssetVariantQualifier(predicate: peakBitRateCap)
-
3:55 - HDR predicate
let hdrOnlyPredicate = NSPredicate(format: "videoAttributes.videoRange == %@", argumentArray: [AVVideoRange.pq]) let hdrOnlyQualifier = AVAssetVariantQualifier(predicate: hdrOnlyPredicate)
-
4:46 - Content configuration
let variantPref = AVAssetVariantQualifier(predicate: NSPredicate(format: "videoAttributes.videoRange == %@ && peakBitRate < 5000000", argumentArray: [AVVideoRange.pq])) let myMediaSelections : [AVMediaSelection] = [enAudioMS, frAudioMS, enLegibleMS] //English, French audio and English subtitle renditions let contentConfig = AVAssetDownloadContentConfiguration() contentConfig.variantQualifiers = [variantPref] contentConfig.mediaSelections = myMediaSelections
-
6:29 - Download configuration
let asset = AVURLAsset(url: URL(string: "http://example.com/master.m3u8")!) let dwConfig = AVAssetDownloadConfiguration(asset: asset, title: "my-title") /* Primary content config */ let varPref = NSPredicate(format: "videoAttributes.videoRange == %@ && peakBitRate < 5000000", argumentArray: [AVVideoRange.pq]) let varQf = AVAssetVariantQualifier(predicate: varPref) dwConfig.primaryContentConfiguration.variantQualifiers = [varQf] dwConfig.primaryContentConfiguration.mediaSelections = [enAudioMS, frAudioMS, enLegibleMS] //English, French audio and English subtitle renditions /* Aux content config */ let auxVarPref = NSPredicate(format: "%d IN audioAttributes.formatIDs", argumentArray: [kAudioFormatAppleLossless]) let auxVarQf = AVAssetVariantQualifier(predicate: auxVarPref) let auxContentConfig = AVAssetDownloadContentConfiguration() auxContentConfig.variantQualifiers = [auxVarQf] auxContentConfig.mediaSelections = [enAudioMS] //english audio dwConfig.auxiliaryContentConfigurations = [auxContentConfig] dwConfig.optimizesAuxiliaryContentConfigurations = true
-
7:42 - Download task
let myAssetDownloadDelegate = MyDownloadDelegate() let avurlsession = AVAssetDownloadURLSession(configuration: URLSessionConfiguration.background(withIdentifier: "my-background-session"), assetDownloadDelegate: myAssetDownloadDelegate, delegateQueue: OperationQueue.main) let asset = AVURLAsset(url: URL(string: "http://example.com/master.m3u8")!) let dwConfig = AVAssetDownloadConfiguration(asset: asset, title: “my-title”) ... let downloadTask = avurlsession.makeAssetDownloadTask(downloadConfiguration: dwConfig) downloadTask.resume() let progress = downloadTask.progress
-
8:10 - Direct variant selection
/* Example for direct variant selection */ let asset = AVURLAsset(url: URL(string: "http://example.com/master.m3u8")!) let dwConfig = AVAssetDownloadConfiguration(asset: asset, title: "my-title") /* Primary content config */ let myVariant : AVAssetVariant = ... let myMediaSelections : [AVMediaSelection] = ... let variantQf = AVAssetVariantQualifier(variant: myVariant) dwConfig.primaryContentConfiguration.variantQualifiers = [variantQf] dwConfig.primaryContentConfiguration.mediaSelections = myMediaSelections /* Aux content config */ let myAuxVariant : AVAssetVariant = ... let myAuxMediaSelections : [AVMediaSelection] = ... let auxVariantQf = AVAssetVariantQualifier(variant: myAuxVariant) let auxContentConfig = AVAssetDownloadContentConfiguration() auxContentConfig.variantQualifiers = [auxVariantQf] auxContentConfig.mediaSelections = myAuxMediaSelections dwConfig.auxiliaryContentConfigurations = [auxContentConfig]
-
-
正在查找特定内容?在上方输入一个主题,就能直接跳转到相应的精彩内容。
提交你查询的内容时出现错误。请检查互联网连接,然后再试一次。