Can we confirm that as of iOS 16.3.1, key frames for MPEGTS via HLS are mandatory now?
I've been trying to figure out why https://chaney-field3.click2stream.com/ shows "Playback Error" across Safari, Chrome, Firefox, etc.. I ran the diagnostics against one of the m3u8 files that is generated via Developer Tools (e.g. mediastreamvalidator "https://e1-na7.angelcam.com/cameras/102610/streams/hls/playlist.m3u8?token=" and then hlsreport validation_data.json) and see this particular error:
Video segments MUST start with an IDR frame
Variant #1, IDR missing on 3 of 3
Does Safari and iOS devices explicitly block playback when it doesn't find one? From what I understand AngelCam simply acts as a passthrough for the video/audio packets and does no transcoding but converts the RTSP packets into HLS for web browsers But IP cameras are constantly streaming their data and a user connecting to the site may be receiving the video between key frames, so it would likely violate this expectation.
From my investigation it also seems like this problem also started happening in iOS 16.3? I'm seeing similar reports for other IP cameras here:
https://ipcamtalk.com/threads/blue-iris-ui3.23528/page-194#post-754082
https://www.reddit.com/r/BlueIris/comments/1255d78/ios_164_breaks_ui3_video_decode/
For what it's worth, when I re-encoded the MPEG ts files (e.g. ffmpeg-i /tmp/streaming-master-m4-na3.bad/segment-375.ts -c:v h264 /tmp/segment-375.ts) it strips the non key frames in the beginning and then playback works properly if I host the same images on a static site and have the iOS device connect to it.
It seems like Chrome, Firefox, VLC, and ffmpeg are much more forgiving on missing key frames. I'm wondering what the reason for enforcing this requirement? And can I confirm it's been a recent change?
Streaming
RSS for tagDeep dive into the technical specifications that influence seamless playback for streaming services, including bitrates, codecs, and caching mechanisms.
Post
Replies
Boosts
Views
Activity
We're experimenting with a stream that has a large (10 minutes) clear portion in front of the protected section w/Fairplay.
We're noticing that AVPlayer/Safari trigger calls to fetch the license key even while it's playing the clear part, and once we provide the key, playback fails with:
name = AVPlayerItemFailedToPlayToEndTimeNotification, object = Optional(<AVPlayerItem: 0x281ff2800> I/NMU [No ID]), userInfo = Optional([AnyHashable("AVPlayerItemFailedToPlayToEndTimeErrorKey"): Error Domain=CoreMediaErrorDomain Code=-12894 "(null)"])
- name : "AVPlayerItemFailedToPlayToEndTimeNotification"
- object : <AVPlayerItem: 0x281ff2800> I/NMU [No ID]
▿ userInfo : 1 element
▿ 0 : 2 elements
▿ key : AnyHashable("AVPlayerItemFailedToPlayToEndTimeErrorKey")
- value : "AVPlayerItemFailedToPlayToEndTimeErrorKey"
- value : Error Domain=CoreMediaErrorDomain Code=-12894 "(null)"
It seems like AVPlayer is trying to decrypt the clear portion of the stream...and I'm wondering if it's because we've set up our manifest incorrectly.
Here it is:
#EXTM3U
#EXT-X-VERSION:8
#EXT-X-TARGETDURATION:20
#EXT-X-MEDIA-SEQUENCE:0
#EXT-X-INDEPENDENT-SEGMENTS
#EXT-X-PLAYLIST-TYPE:VOD
#EXT-X-MAP:URI="clear-asset.mp4",BYTERANGE="885@0"
#EXT-X-DEFINE:NAME="path0",VALUE="clear-asset.mp4"
#EXTINF:9.98458,
#EXT-X-BYTERANGE:81088@885
{$path0}
#EXTINF:19.96916,
#EXT-X-BYTERANGE:159892@81973
{$path0}
#EXTINF:19.96916,
#EXT-X-BYTERANGE:160245@241865
{$path0}
#EXT-X-DISCONTINUITY
#EXT-X-MAP:URI="secure-asset.mp4",BYTERANGE="788@0"
#EXT-X-DEFINE:NAME="path1",VALUE="secure-asset.mp4"
#EXT-X-KEY:METHOD=SAMPLE-AES,URI="skd://guid",KEYFORMAT="com.apple.streamingkeydelivery",KEYFORMATVERSIONS="1"
#EXTINF:19.96916,
#EXT-X-BYTERANGE:159928@5196150
{$path1}
#EXT-X-ENDLIST
Dear Apple Engineers,
First of all, thank you for this wonderful and very necessary native solution.
Question: Is it possible to use this API when processing HLS?
Thank you.
Hi Team,
Offline playback with AES-128 encryption
I'm downloading HLS content that is AES-128 encrypted and using the AVAssetResourceLoaderDelegate method shouldWaitForLoadingOfRequestedResource to parse the manifest to fetch the AES key URL. After fetching the key URL, I'll download and save the AES key locally. I will use the locally saved key to start the offline playback.
Since AVContentKeySession has been there for quite some time, is it okay to use the resource loader delegate method to parse and download the AES key?
Is there any chance that Apple will deprecate the downloading keys through the resource loader delegate?
Thanks,
Deepak.N
I'm using mediafilesegmenter with input as a fragmented mp4 hvc1 file and got this error:
Nov 23 2023 17:48:25.948: Fragmented MP4 is the only supported container format for the segmentation of HEVC content
Nov 23 2023 17:48:25.948: Unsupported media type 'hvc1' in track 0
Nov 23 2023 17:48:25.948: Unable to find any valid tracks to segment.
Segmenting failed (-12780).
Hello,
I'm having an issue where my app is in TestFlight, and some of my testers are reporting that FairPlay protected videos are not playing back in iOS 17.
It's been working fine in iOS 16 (my app's initial target).
I can see from the debug logs that for an online stream request -
contentKeySession(_ session: AVContentKeySession, didProvide keyRequest: AVContentKeyRequest)
is never called.
Whereas, a download for offline playback request, the function is called.
I've used much of the sample code in "HLS Catalog With FPS" as part of the FPS developer package.
All of my m3u8 files are version 5 and contain encryption instructions like below:
#EXT-X-KEY:METHOD=SAMPLE-AES,URI="skd://some-uuid",KEYFORMAT="com.apple.streamingkeydelivery",KEYFORMATVERSIONS="1"
Here's a short excerpt of the code being run:
let values = HTTPCookie.requestHeaderFields(with: cookies)
let cookieOptions = ["AVURLAssetHTTPHeaderFieldsKey": values]
assetUrl = "del\(assetUrl)"
clip!.assetUrl = AVURLAsset(url: URL(string: assetUrl)!, options: cookieOptions)
clip!.assetUrl!.resourceLoader.setDelegate(self, queue: DispatchQueue.global(qos: .default))
ContentKeyManager.shared.contentKeySession.addContentKeyRecipient(clip!.assetUrl!)
urlAssetObserver = self.observe(\.isPlayable, options: [.new, .initial]) { [weak self] (assetUrl, _) in
guard let strongSelf = self else { return }
strongSelf.playerItem = AVPlayerItem(asset: (self!.clip!.assetUrl)!)
strongSelf.player.replaceCurrentItem(with: strongSelf.playerItem)
}
The error thrown is:
Task .<8> finished with error [18,446,744,073,709,550,614] Error Domain=NSURLErrorDomain Code=-1002 "unsupported URL" UserInfo={NSLocalizedDescription=unsupported URL, NSErrorFailingURLStringKey=skd://some-uuid, NSErrorFailingURLKey=skd://some-uuid, _NSURLErrorRelatedURLSessionTaskErrorKey=(
"LocalDataTask .<8>"
), _NSURLErrorFailingURLSessionTaskErrorKey=LocalDataTask .<8>, NSUnderlyingError=0x2839a7450 {Error Domain=kCFErrorDomainCFNetwork Code=-1002 "(null)"}}
Which I believe is being thrown from AVPlayerItem.
Without the delegate, it appears to playback fine. However, I need the delegate (I think), since I'm appending some query params to each request for the segments.
I have an observer on the playerItem, per the example project which is changing the status to .failed once he -1002 error is thrown.
Please let me know if anything rings to mind to try, or if I can provide any additional info.
Thanks in advance!