首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >下载前获取AVAssetDownloadTask大小

下载前获取AVAssetDownloadTask大小
EN

Stack Overflow用户
提问于 2016-09-19 10:59:13
回答 3查看 1.7K关注 0票数 7

我目前正在用FairPlay流实现离线流。为此,我使用AVAssetDownloadTask下载流。

我想给用户关于开始下载的大小的反馈:

您确定要下载此流吗?下载将需要2.4GB,您目前还剩下14 of的空间

我已经检查了像countOfBytesReceivedcountOfBytesExpectedToReceive这样的属性,但是这些属性不会返回正确的值。

代码语言:javascript
复制
let headRequest = NSMutableURLRequest(URL: asset.streamURL)
headRequest.HTTPMethod = "HEAD"
let sizeTask = NSURLSession.sharedSession().dataTaskWithRequest(headRequest) { (data, response, error) in
    print("Expected size is \(response?.expectedContentLength)")
}.resume()

打印一个大小为2464,其中最后的大小是3GB。

在下载过程中,我记录了上面的属性:

代码语言:javascript
复制
func URLSession(session: NSURLSession, assetDownloadTask: AVAssetDownloadTask, didLoadTimeRange timeRange: CMTimeRange, totalTimeRangesLoaded loadedTimeRanges: [NSValue], timeRangeExpectedToLoad: CMTimeRange) {
    print("Downloaded \( convertFileSizeToMegabyte(Float(assetDownloadTask.countOfBytesReceived)))/\(convertFileSizeToMegabyte(Float(assetDownloadTask.countOfBytesExpectedToReceive))) MB")
}

但这些都停留在零:

下载0.0/0.0 MB

EN

回答 3

Stack Overflow用户

发布于 2016-10-04 18:43:20

HLS流实际上是称为清单和传输流的文件的集合。清单通常包含子清单的文本列表(每个子清单对应不同的比特率),而这些子清单包含包含实际电影数据的传输流列表。

在您的代码中,当您下载HLS URL时,您实际上只下载了主清单,这通常是几千字节。如果要复制整个流,则需要解析所有清单,复制原始流的文件夹结构,并获取传输段(这些片段通常在10秒内,因此可能有数百个这样的片段)。如果清单也使用绝对URL指定,则可能需要重写URL。

要计算每个流的大小,可以将比特率(在主清单中列出)乘以流的持续时间;对于下载而言,这可能是一个足够好的估计。

在这里,更好的答案是实现AVAssetDownloadTask,因为您在离线FairPlay的上下文中使用AVAssetDownloadDelegate。该协议中的一种方法为您提供了您想要的进展:

URLSession:assetDownloadTask:didLoadTimeRange:totalTimeRangesLoaded:timeRangeExpectedToLoad:

下面是显示此委托的WWDC 2016会议504

有很多与FairPlay的离线播放有关的细节,所以非常仔细地浏览这个视频是个好主意。

票数 2
EN

Stack Overflow用户

发布于 2016-09-20 05:05:07

我没有亲自使用过这个API,但我至少对HTTP流有点熟悉。有了这些知识,我想我知道为什么你不能得到你想要的信息。

HLS协议旨在处理实时流和固定长度资产流.它可以通过将媒体切入大约10秒的块IIRC,并在特定URL的播放列表文件中列出这些块的URL。

如果播放列表没有改变,那么您可以下载播放列表,计算文件数量,获取第一个文件的长度,并将其乘以文件数,您将得到一个粗略的近似,当您开始检索最后一个块时,可以用确切的值替换它。

但是,并不能保证播放列表不会改变。使用HLS的,通过删除最老段(或不删除)并在末尾添加新段,播放列表可能每10秒更改一次。通过这种方式,HLS支持没有结束的直播流。在这种情况下,下载有一个大小的概念是荒谬的。

更糟糕的是,2464可能是播放列表文件的大小,而不是其中第一个资产的大小,也就是说,除非子类的didReceiveResponse:方法工作,否则它不会告诉您任何信息,在这种情况下,您可以通过读取Content-Length头来获取每个片段的长度。即使它正常工作,您可能仍然无法从这个API中获得段数(而且也不能保证所有段的长度完全相同,尽管它们应该非常接近)。

我怀疑,要获得你想要的信息,即使是对于一个非真实资产,你可能需要获取播放列表,自己解析它,并为其中列出的每个媒体段URL执行一系列的头请求。

幸运的是,HLS规范是一个可公开使用的标准,因此,如果您想沿着这条道路走下去,可以阅读一些RFCs来了解播放列表文件的结构。而且AFAIK,播放列表本身不使用任何DRM或任何东西加密,所以应该可以这样做,即使API的实际解密部分不是公开的(AFAIK)。

票数 0
EN

Stack Overflow用户

发布于 2017-10-31 15:21:30

这是我的C#/Xamarin代码,用来计算最终的下载大小。它很可能是不完美的,特别是在iOS11支持的新的编解码器中,但是您应该有这样的想法。

代码语言:javascript
复制
private static async Task<long> GetFullVideoBitrate(string manifestUrl)
{
    string bandwidthPattern = "#EXT-X-STREAM-INF:.*(BANDWIDTH=(?<bitrate>\\d+)).*";
    string videoPattern = "^" + bandwidthPattern + "(RESOLUTION=(?<width>\\d+)x(?<height>\\d+)).*CODECS=\".*avc1.*\".*$";
    string audioPattern = "^(?!.*RESOLUTION)" + bandwidthPattern + "CODECS=\".*mp4a.*\".*$";

    HttpClient manifestClient = new HttpClient();
    Regex videoInfoRegex = new Regex(videoPattern, RegexOptions.Multiline);
    Regex audioInfoRegex = new Regex(audioPattern, RegexOptions.Multiline);
    string manifestData = await manifestClient.GetStringAsync(manifestUrl);
    MatchCollection videoMatches = videoInfoRegex.Matches(manifestData);
    MatchCollection audioMatches = audioInfoRegex.Matches(manifestData);
    List<long> videoBitrates = new List<long>();
    List<long> audioBitrates = new List<long>();

    foreach (Match match in videoMatches)
    {
        long bitrate;

        if (long.TryParse(match.Groups["bitrate"]
                               .Value,
                          out bitrate))
        {
            videoBitrates.Add(bitrate);
        }
    }

    foreach (Match match in audioMatches)
    {
        long bitrate;

        if (long.TryParse(match.Groups["bitrate"]
                               .Value,
                          out bitrate))
        {
            audioBitrates.Add(bitrate);
        }
    }

    if (videoBitrates.Any() && audioBitrates.Any())
    {
        IEnumerable<long> availableBitrate = videoBitrates.Where(b => b >= Settings.VideoQuality.ToBitRate());
        long videoBitrateSelected = availableBitrate.Any() ? availableBitrate.First() : videoBitrates.Max();
        long totalAudioBitrate = audioBitrates.Sum();

        return videoBitrateSelected + totalAudioBitrate;
    }

    return 0;
}
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/39571523

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档