Skip to content
This repository has been archived by the owner on Feb 2, 2023. It is now read-only.

[ASVideoNode] Initializing Streaming-based Video PlayerItems using URL instead of AVAsset #1954

Merged
merged 9 commits into from
Jul 21, 2016

Conversation

Xinchi
Copy link
Contributor

@Xinchi Xinchi commented Jul 19, 2016

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

Xinchi and others added 3 commits June 14, 2016 10:15
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.
@Xinchi
Copy link
Contributor Author

Xinchi commented Jul 20, 2016

@chourobin Regarding your comment in #1600,

hey @gazreese, I'd just like to add that after further investigation, I believe it's no longer required to build the AVPlayerItem from the URL (for HLS). Hence, the check for tracks should no longer be needed.

Apparently the AVFoundation guide was out of date. In this release note -- under Enhancements for HTTP Live Streaming -- it states that all assets (HLS and non-HLS) may be constructed from an AVURLAsset. We just have to call -loadValuesAsynchronouslyForKeys:completionHandler: first before assigning it to a player item. I've been doing this outside of ASVideoNode for now but I would be happy to submit a PR to bring this async asset loading into ASVideoNode by default. I wanted to check in and see what you guys think.

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.

@Xinchi
Copy link
Contributor Author

Xinchi commented Jul 20, 2016

@gazreese Mind taking a look at this PR to see if it addressed the internal / public asset inconsistency issue you raised in #1600 ?

@Xinchi
Copy link
Contributor Author

Xinchi commented Jul 20, 2016

@ejensen Mind taking a look at this PR to see if it addressed the asynchronous loading of track key that you mentioned in #1748 ?

@Xinchi
Copy link
Contributor Author

Xinchi commented Jul 20, 2016

@gazreese @chourobin @ejensen @Eke
Do you think it's better for ASDK to tell if the AVUrlAsset specified by the client a HLS vs non-HLS asset by checking the track property, or is it better to provide a separate API for the client to specify which to construct the playeritem with, asset or url?

@ghost ghost added the CLA Signed label Jul 20, 2016
- (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;
Copy link
Contributor

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?

Copy link
Contributor Author

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?

@ghost ghost added the CLA Signed label Jul 20, 2016
@gazreese
Copy link
Contributor

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.

@ghost ghost added the CLA Signed label Jul 20, 2016
@@ -41,6 +41,7 @@ NS_ASSUME_NONNULL_BEGIN
- (BOOL)isPlaying;

@property (nullable, nonatomic, strong, readwrite) AVAsset *asset;
@property (nullable, atomic, strong, readwrite) NSURL *assetURL;
Copy link
Contributor

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?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch! fixing..

@ghost ghost added the CLA Signed label Jul 20, 2016
@levi
Copy link
Contributor

levi commented Jul 21, 2016

@Xinchi strong direction. Looks good to me!

@ghost ghost added the CLA Signed label Jul 21, 2016
@maicki
Copy link
Contributor

maicki commented Jul 21, 2016

@Xinchi Looks good to me!!

giphy

@ghost ghost added the CLA Signed label Jul 21, 2016
_asset = [AVURLAsset assetWithURL:assetURL];

[self setNeedsDataFetch];
}
Copy link
Contributor

@Adlai-Holler Adlai-Holler Jul 21, 2016

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?

@Xinchi Xinchi mentioned this pull request Jul 21, 2016
@Adlai-Holler Adlai-Holler merged commit 5723f60 into facebookarchive:master Jul 21, 2016
Adlai-Holler pushed a commit that referenced this pull request Jul 21, 2016
playerItem.audioMix = _audioMix;
return playerItem;
AVPlayerItem *playerItem = nil;
if (self.assetURL != nil) {
Copy link
Contributor

@appleguy appleguy Jul 21, 2016

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?

Copy link
Contributor Author

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:

  1. fetch data is called from parent node
  2. fetch data is called from setting the AssetURL
  3. 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.

@Xinchi Xinchi changed the title Hls issue [ASVideoNode] Initializing Streaming-based Video PlayerItems using URL instead of AVAsset Jul 21, 2016
- (void)setAssetURL:(NSURL *)assetURL
{
if (!ASObjectIsEqual(assetURL, self.assetURL)) {
self.asset = [AVURLAsset assetWithURL:assetURL];
Copy link
Contributor

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?

Copy link
Contributor Author

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.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants