You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

iOS15系统播放Azure媒体服务HLS流时播放一段时间后画面拉伸问题求助

问题根因分析与修复方案

高发根因(按出现概率排序)

  • iOS 15.0.x 版本对 CMAF 封装的 HLS 流存在原生兼容性缺陷:码率自适应切换时,若分片未单独携带采样宽高比(SAR)/显示宽高比(DAR)元数据,AVPlayer 会丢失该配置,默认采用 1:1 采样比渲染,导致画面拉伸
  • Azure 媒体服务默认 AdaptiveStreaming 预设生成的多码率变体,可能存在不同分辨率码流宽高比元数据不一致的问题,且默认仅在主播放列表写入宽高比配置,未同步写入每个分片
  • AVPlayerViewController 内部布局逻辑存在偶发异常:码率切换触发 presentationSize 更新时,不会主动重新应用已设置的 videoGravity 属性,导致布局计算错误

修复步骤

1. 优先验证 CMAF 兼容性问题

将 Azure 动态打包的输出格式替换为 iOS 原生兼容性更好的 TS 封装 HLS,流地址后缀修改为 manifest(format=m3u8-aapl),先确认是否为 CMAF 适配问题。
如果必须使用 CMAF 格式,需在 Azure 编码预设中新增配置,强制将 DAR/SAR 元数据写入每一个视频分片,而非仅写入主播放清单。

2. 补充 AVPlayer 配置与状态监听

新增 AVPlayerItem 基础参数配置

初始化 AVPlayerItem 时主动设置分辨率与缓冲区参数:

let playerItem = AVPlayerItem(url: streamURL)
// 按视频实际最大分辨率设置,避免AVPlayer拉取超出需求的高码率流
playerItem.preferredMaximumResolution = CGSize(width: 1920, height: 1080)
// 常规场景默认设为10秒即可,可根据网络情况调整
playerItem.preferredForwardBufferDuration = 10

监听画面尺寸变化,强制刷新布局

修改 VideoPlayerView 实现,新增 KVO 监听 AVPlayerItem 的 presentationSize 属性,变化时强制重新赋值 videoGravity 触发布局刷新:

struct VideoPlayerView: UIViewControllerRepresentable {
    var player: AVPlayer
    @Binding var gravity: AVLayerVideoGravity

    func makeUIViewController(context: Context) -> AVPlayerViewController {
        let controller = AVPlayerViewController()
        controller.player = player
        controller.showsPlaybackControls = false
        controller.videoGravity = gravity
        // 监听当前播放项的画面尺寸变化
        context.coordinator.sizeObserver = player.currentItem?.observe(\.presentationSize, options: [.new]) { [weak controller] _, _ in
            DispatchQueue.main.async {
                controller?.videoGravity = gravity
            }
        }
        return controller
    }

    func updateUIViewController(_ uiViewController: AVPlayerViewController, context: Context) {
        uiViewController.videoGravity = gravity
    }

    static func dismantleUIViewController(_ uiViewController: AVPlayerViewController, coordinator: Coordinator) {
        // 移除监听避免内存泄漏
        coordinator.sizeObserver?.invalidate()
    }

    func makeCoordinator() -> Coordinator {
        Coordinator()
    }

    class Coordinator {
        var sizeObserver: NSKeyValueObservation?
    }
}

3. 验证多码率流元数据一致性

使用 ffprobe 工具检查所有码率变体的宽高比配置是否一致,命令如下:

ffprobe -v error -select_streams v:0 -show_entries stream=width,height,dar,sar -of csv=p=0 [分片地址]

若存在某档码流的 DAR/SAR 与其他码流不一致,需调整 Azure 编码预设,强制所有输出码流使用统一的宽高比参数。

4. 终极规避方案

弃用 AVPlayerViewController,直接使用 AVPlayerLayer 手动渲染视频,完全控制布局逻辑,避免系统组件内部的偶发异常。

内容的提问来源于stack exchange,提问作者Saul Burgos

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.01 01:24:01