-
Notifications
You must be signed in to change notification settings - Fork 2.2k
[ASVideoNode] Initializing Streaming-based Video PlayerItems using URL instead of AVAsset #1954
Conversation
Apple claims in the AVFoundationProgramming Guide that HLS videos can be constructed only through URL, but later with iOS 4.3 release notes it claimed to bring updates to how the HLS videos should be initialized, which works with asset too. I’ve tested with both, and it looks like initializing with asset is buggy.
Apple claims in the AVFoundationProgramming Guide that HLS videos can be constructed only through URL, but later with iOS 4.3 release notes it claimed to bring updates to how the HLS videos should be initialized, which works with asset too. I’ve tested with both, and it looks like initializing with asset is buggy.
… it doesn't block the main thread
@chourobin Regarding your comment in #1600,
Seems it's not entirely true that this issue has gone away in the AVFoundation, as @gazreese and I have observed the issue with HLS loading. So this is what this PR is for. |
@gazreese @chourobin @ejensen @Eke |
- (BOOL)hasURLAsset | ||
{ | ||
// The array of AVAssetTrack objects available via the tracks property of an URL asset is typically empty for streaming-based media | ||
return _asset.tracks.count == 0; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Xinchi Below, it looks like there is use of the safe / "correct" API to asynchronously load this value. Can we instead use that form of request / completion handler to restructure how we construct the player item, so the player item is created "as quickly as possible" even if it first goes through a call to loadValues...completionBlock: and the bulk of the work is in the completion block?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The constructPlayerItem method is called once the requestedKeys are loaded in the prepareToPlayAsset: withKeys: method.. not sure how we can make it faster than that?
Hi @Xinchi. Regarding construction I'm keener on having the explicit construction using either the asset or the URL if I'm honest. This is reflected in ASVideoPlayerNode as well as the standard iOS APIs. As for giving this a try, I've raised it up on my internal tracker and will have a look at it when I've finished what I'm working on. |
@@ -41,6 +41,7 @@ NS_ASSUME_NONNULL_BEGIN | |||
- (BOOL)isPlaying; | |||
|
|||
@property (nullable, nonatomic, strong, readwrite) AVAsset *asset; | |||
@property (nullable, atomic, strong, readwrite) NSURL *assetURL; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Xinchi Any reason why this property is atomic?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch! fixing..
@Xinchi strong direction. Looks good to me! |
@Xinchi Looks good to me!! |
_asset = [AVURLAsset assetWithURL:assetURL]; | ||
|
||
[self setNeedsDataFetch]; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems that -assetURL
and -setAssetURL:
are just convenience accessors for setting and retrieving the asset BY url. So couldn't we simplify with e.g.:
- (void)setAssetURL:(NSURL *)assetURL
{
if (!ASObjectIsEqual(assetURL, self.assetURL) {
self.asset = [AVURLAsset assetWithURL:assetURL];
}
}
etc?
playerItem.audioMix = _audioMix; | ||
return playerItem; | ||
AVPlayerItem *playerItem = nil; | ||
if (self.assetURL != nil) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Xinchi I'm not sure this is correct - what if we already have an _asset, which was created from this assetURL?
This should probably still be if _asset == nil, create the asset from the assetURL (if available). Then as a separate if condition, if we have a non-nil _asset, create the playerItem?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In this case you described, the method won't be invoked because this method is invoked in 3 cases:
- fetch data is called from parent node
- fetch data is called from setting the AssetURL
- fetch data is called from setting the asset.
In #1, It shouldn't load the video asset more than once.
In #2, if we already have an _asset, which was created from this assetURL, the setter will be returned without setting the Asset and invoking the player item construction.
In #3, It's very unlikely that the application will set the assetURL first and then set the Asset. @maicki and I have discussed how we can prevent users from setting both the asset and url, and @maicki suggested we should add clear documentation for our users.
- (void)setAssetURL:(NSURL *)assetURL | ||
{ | ||
if (!ASObjectIsEqual(assetURL, self.assetURL)) { | ||
self.asset = [AVURLAsset assetWithURL:assetURL]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What if the player item has been created already? Does the clearFetchedData / fetch data pass cause this to be updated correctly?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes - setting the asset will invoke [self clearFetchedData] and [self setNeedsDataFetch]; cc @Adlai-Holler who proposed this approach.
Closing #1748 and opening this Pull Request, as the base in #1748 was still the old commit and after rebasing, it leads to the longest PR.
@gazreese @ejensen @hannahmbanana @levi @maicki