This topic describes how to use the advanced features of the ApsaraVideo Player SDK for iOS. For a complete description of all features, see API reference.
To try out the demo, download it and follow the instructions in Run the demo to compile and run the project.
Professional skill confirmation
Some player features require a Professional Edition license. For more information, see Features. To obtain a license, refer to Obtain a license.
Set the listener when your application starts or before you call any player API operations.
void premiumVeryfyCallback(AVPPremiumBizType biztype, bool isValid, NSString* errorMsg) {
NSLog(@"onPremiumLicenseVerifyCallback: %d, isValid: %d, errorMsg: %@", biztype, isValid, errorMsg);
}
[AliPrivateService setOnPremiumLicenseVerifyCallback:premiumVeryfyCallback];Here, AVPPremiumBizType is an enumeration of professional capabilities. When you use a related feature, the player verifies the capability and returns the verification result through this callback. If isValid is false, errorMsg contains the specific reason.
Playback
List playback
The ApsaraVideo Player SDK for iOS provides a full-featured list playback capability. The SDK uses mechanisms such as preloading to minimize the time-to-first-frame (TTTF) for short videos.
For an enhanced list playback experience, use our short-form drama solution. For more information, see Mini-Drama Client Development.
Play videos with an alpha channel
Overview
The ApsaraVideo Player SDK supports rendering an alpha channel to create dynamic effects, such as animated gifts. During live streaming, you can play animated gifts without obscuring the main content, enhancing the user experience.
Limits
Alpha channel rendering is supported in the all-in-one SDK V6.8.0 and later, or the ApsaraVideo Player SDK V6.9.0 and later.
Benefits
Using MP4 videos with transparency for gift effects delivers better animation quality, smaller file sizes, higher compatibility, and greater development efficiency. This enables gift effects to be displayed more effectively to users, enhancing the user experience.
Better animation quality: MP4 videos preserve original animation details and colors more accurately than other formats.
Smaller file size: MP4 video files compress more effectively than other formats, such as APNG or IXD, which results in faster load times and lower network bandwidth consumption.
Higher compatibility: The MP4 format is widely supported across devices and browsers.
Using MP4 videos for gift effects improves development efficiency. This technical solution is straightforward, freeing developers from researching and implementing complex parsing and rendering logic so they can focus on other features.
Metal rendering
The ApsaraVideo Player SDK for iOS supports video rendering using the Metal framework.
Currently, only setting the background color, scaling mode, and Picture-in-Picture (PiP) are supported with Metal rendering.
Configuration
/**
@brief Video render type, 0 means default render; 1 means mixed render. Default is 0.
*/
/****
@brief video render type, 0 means default render; 1 means mixed render.
*/
@property(nonatomic, assign) int videoRenderType;Usage examples
AVPConfig *config = [self.player getConfig];
// Enable Metal rendering.
config.videoRenderType = 1;
[self.player setConfig:config];
[self.player prepare];External subtitles
For a detailed code example, see the ExternalSubtitle module in the API-Example project. This project is based on Objective-C and demonstrates core SDK integration for the ApsaraVideo Player SDK for iOS.
The ApsaraVideo Player SDK for iOS supports adding and switching external subtitles in SRT, SSA, ASS, and VTT formats.
Examples:
Create a view to display subtitles.
Create different views for different formats.
// Initialize a custom subTitleLabel. UILabel *subTitleLabel = [[UILabel alloc] initWithFrame:frame]; // Add the subtitle label to a custom superView. The superView is a parent view that exists in the custom interface. [superView addSubview:subTitleLabel];Set subtitle-related listeners.
// External subtitle added. - (void)onSubtitleExtAdded:(AliPlayer*)player trackIndex:(int)trackIndex URL:(NSString *)URL {} // Subtitle header information callback. - (void)onSubtitleHeader:(AliPlayer *)player trackIndex:(int)trackIndex Header:(NSString *)header{} // Subtitle display callback. - (void)onSubtitleShow:(AliPlayer*)player trackIndex:(int)trackIndex subtitleID:(long)subtitleID subtitle:(NSString *)subtitle { subTitleLabel.text =subtitle; subTitleLabel.tag =subtitleID; } // Subtitle hide callback. - (void)onSubtitleHide:(AliPlayer*)player trackIndex:(int)trackIndex subtitleID:(long)subtitleID{ [subTitleLabel removeFromSuperview]; }Add a subtitle track.
[self.player addExtSubtitle:URL];Switch a subtitle track.
[self.player selectExtSubtitle:trackIndexenable:YES];
External subtitles (custom rendering with rendering components)
Full support for WebVTT external subtitles is implemented using AliVttSubtitleView and AliVttRenderImpl, enabling flexible customization of font size, color, and specific fonts.
Use cases:
Customize WebVTT subtitle styles such as font, color, and size.
Integrate ApsaraVideo Player SDK 7.11.0 and use AliVttSubtitleView.
Support multilingual subtitles (such as Arabic, Chinese, Japanese, and Korean) with automatic font matching.
Prerequisites:
Font files (.ttf) are added to the Xcode project.
Subtitle listeners are added and WebVTT content can be retrieved.
The loadFontFromBundle method successfully loads fonts.
Steps to customize subtitle styles
Create a custom rendering implementation class (AliVttRenderImpl).
// CustomFontVttRenderImpl.h @interface CustomFontVttRenderImpl : AliVttRenderImpl @end // CustomFontVttRenderImpl.m @implementation CustomFontVttRenderImpl // Optional: Override font generation logic - (UIFont *)customizeFont:(UIFont *)originalFont contentAttribute:(VttContentAttribute *)contentAttribute contentText:(NSString *)text { // Example: Automatically select font based on content if ([self containsArabicCharacters:text]) { return [UIFont fontWithName:@"NotoSansArabic-Regular" size:originalFont.pointSize]; } if ([self containsCJKCharacters:text]) { return [UIFont fontWithName:@"NotoSansCJKsc-Regular" size:originalFont.pointSize]; } return originalFont; } // Optional: Force color change - (void)applyColorStyle:(NSMutableDictionary *)attrs contentAttribute:(VttContentAttribute *)contentAttribute { // Force red color attrs[NSForegroundColorAttributeName] = [UIColor redColor]; } // Optional: Enlarge font - (void)applyFontStyle:(NSMutableDictionary *)attrs contentAttribute:(VttContentAttribute *)contentAttribute context:(RenderContext *)context { CGFloat originalSize = contentAttribute.fontSizePx / context.contentsScale; CGFloat newSize = originalSize * 2.0; // Double the size UIFont *font = [self generateFontWithName:contentAttribute.fontName fontSize:newSize isBold:contentAttribute.mBold isItalic:contentAttribute.mItalic]; attrs[NSFontAttributeName] = font; } // Helper method: Detect Arabic characters - (BOOL)containsArabicCharacters:(NSString *)text { for (NSUInteger i = 0; i < text.length; i++) { unichar c = [text characterAtIndex:i]; if ((c >= 0x0600 && c <= 0x06FF) || (c >= 0x0750 && c <= 0x077F)) { return YES; } } return NO; } // Helper method: Detect CJK characters - (BOOL)containsCJKCharacters:(NSString *)text { for (NSUInteger i = 0; i < text.length; i++) { unichar c = [text characterAtIndex:i]; if ((c >= 0x4E00 && c <= 0x9FFF) || // Chinese (c >= 0x3040 && c <= 0x309F) || // Japanese hiragana (c >= 0xAC00 && c <= 0xD7AF)) { // Korean return YES; } } return NO; } @end(Optional) Dynamically load custom fonts.
- (void)loadCustomFontFromBundle:(NSString *)fontName { NSString *path = [[NSBundle mainBundle] pathForResource:fontName ofType:@"ttf"]; if (path) { NSData *fontData = [NSData dataWithContentsOfFile:path]; CGDataProviderRef provider = CGDataProviderCreateWithCFData((__bridge CFDataRef)fontData); CGFontRef fontRef = CGFontCreateWithDataProvider(provider); if (CTFontManagerRegisterGraphicsFont(fontRef, NULL)) { NSLog(@"Font registration succeeded: %@", fontName); } else { NSLog(@"Font registration failed: %@", fontName); } CGFontRelease(fontRef); CGDataProviderRelease(provider); } }Initialize the subtitle view and bind the custom renderer.
// Create subtitle view AliVttSubtitleView *subtitleView = [[AliVttSubtitleView alloc] init]; // Set custom renderer factory [subtitleView setRenderImplFactory:^AliVttRenderImpl*() { CustomFontVttRenderImpl *impl = [[CustomFontVttRenderImpl alloc] init]; // Optional: Preload font [impl loadCustomFontFromBundle:@"LongCang-Regular"]; return impl; }]; // Associate with player [player setExternalSubtitleView:subtitleView];Handle player subtitle callbacks.
Implement the following methods in AVPDelegate:
// Subtitle header (includes style and region definitions) - (void)onSubtitleHeader:(AliPlayer *)player trackIndex:(int)trackIndex Header:(NSString *)header { [self.subtitleView setVttHeader:player trackIndex:trackIndex Header:header]; } // Show subtitle - (void)onSubtitleShow:(AliPlayer *)player trackIndex:(int)trackIndex subtitleID:(long)subtitleID subtitle:(NSString *)subtitle { [self.subtitleView show:player trackIndex:trackIndex subtitleID:subtitleID subtitle:subtitle]; } // Hide subtitle - (void)onSubtitleHide:(AliPlayer *)player trackIndex:(int)trackIndex subtitleID:(long)subtitleID { [self.subtitleView hide:player trackIndex:trackIndex subtitleID:subtitleID]; } // Subtitle added (used to enable track) - (void)onSubtitleExtAdded:(AliPlayer *)player trackIndex:(int)trackIndex URL:(NSString *)URL { [player selectExtSubtitle:trackIndex enable:YES]; }
Audio-only playback
Disable video playback to play only the audio track. Configure this setting before calling prepare.
AVPConfig *config = [self.player getConfig];
config.disableVideo = YES;
[self.player setConfig:config];Switch between software and hardware decoding
The iOS player SDK provides hardware decoding capability for H.264 and H.265, and includes a toggle: enableHardwareDecoder. This toggle is enabled by default, and the SDK automatically switches to software decoding if hardware decoding initialization fails, ensuring normal video playback. The following example shows this configuration:
// Enable hardware decoding. It is enabled by default.
self.player.enableHardwareDecoder = YES;If the player automatically switches from hardware decoding to software decoding, a notification is sent through the onPlayerEvent callback. The following is an example:
-(void)onPlayerEvent:(AliPlayer*)player eventWithString:(AVPEventWithString)eventWithString description:(NSString *)description {
if (eventWithString == EVENT_SWITCH_TO_SOFTWARE_DECODER) {
// Switched to software decoding.
}
}H.265 adaptive playback
An adaptive fallback is triggered when the current device model is in the cloud-based H.265 blacklist or if H.265 hardware decoding fails. If an H.264 backup stream is configured, it will be played. Otherwise, the player falls back to H.265 software decoding.
This feature is enabled only after you activate the cloud-native adaptive decoding value-added service. You need to submit a Yida form to request license authorization.
The cloud-native adaptive decoding value-added service includes dynamic delivery of hardware decoding compatibility data and adaptive fallback from H.265 to H.264 streams.
The SDK still automatically switches to software decoding upon hardware decoding failure, even if this value-added service is not enabled.
Example of configuring a backup stream:
// The application layer maintains a map of original URLs to backup URLs.
NSString* getBackupUrlCallback(AVPBizScene scene, AVPCodecType codecType, NSString* oriurl){
NSMutableDictionary *globalMap = [AliPlayerViewController getGlobalBackupUrlMap];
NSString *backupUrl = globalMap[oriurl];
return backupUrl;
}
[AliPlayerGlobalSettings setAdaptiveDecoderGetBackupURLCallback:getBackupUrlCallback];Switch video definition based on network conditions
Generate multi-bitrate HLS streams using a video packaging template in ApsaraVideo VOD. For instructions, see Adaptive bitrate streaming configuration for video on demand.
Adaptive streams generated by ApsaraVideo VOD transcoding require you to specify the default playback definition list as
AUTOwhen using Vid playback to play adaptive video streams. Otherwise, the system selects a lower-definition video stream according to the default logic. For the default playback order of definitions, see Which definition does the player SDK play by default when multiple definitions are generated by video transcoding?. For example, when using VidAuth playback, the following shows how to specify the definition list:AVPVidAuthSource *authSource = [[AVPVidAuthSource alloc] init]; authSource.definitions = @"AUTO";
The iOS Player SDK supports adaptive bitrate HLS and DASH video streams. After the prepare method completes successfully, you can retrieve information for each bitrate stream by calling getMediaInfo, which retrieves TrackInfo objects. The following example shows how to do this:
AVPMediaInfo *info = [self.player getMediaInfo];
NSArray<AVPTrackInfo*>* tracks = info.tracks;During playback, you can switch the playing stream by calling the player's selectTrack method. When the value is SELECT_AVPTRACK_TYPE_VIDEO_AUTO, adaptive bitrate streaming is enabled. The following example shows this:
// Switch to a specific bitrate.
[self.player selectTrack:track.trackIndex];
// Enable adaptive bitrate switching.
[self.player selectTrack:SELECT_AVPTRACK_TYPE_VIDEO_AUTO];The result of the switch is returned in the onTrackChanged callback. The following is an example:
- (void)onTrackChanged:(AliPlayer*)player info:(AVPTrackInfo*)info {
if (info.trackType == AVPTRACK_TYPE_VIDEO) {
// Rendition changed.
}
// etc
}Optional: Before calling the player's selectTrack method to switch the playback stream to adaptive bitrate streaming, you can set an upper limit for the definition in adaptive bitrate (ABR) switching through config to prevent automatic switching to an unexpectedly high bitrate. Example: (We recommend calling the following code before the player calls the prepare method or the list player calls the moveTo method so that the configuration takes effect.)
AVPConfig *config = [self.player getConfig];
config.maxAllowedAbrVideoPixelNumber = 921600;// Set the maximum allowed pixel count for ABR to 1280x720. The player will only switch to definitions with a pixel count less than or equal to this value.
[self.player setConfig:config];Take a snapshot
The iOS Player SDK provides the snapShot method to take a screenshot of the current video. This method captures the raw data and returns it as a bitmap. The callback method is onCaptureScreen. The following is an example:
// Snapshot callback.
- (void)onCaptureScreen:(AliPlayer *)player image:(UIImage *)image {
// Process the snapshot.
}
// Take a snapshot of the current frame.
[self.player snapShot];The snapshot does not include the UI.
Preview
In combination with ApsaraVideo VOD configurations, you can implement a preview feature. This is supported for both VidSts and VidAuth (recommended) playback. For configuration instructions, see Preview videos.
After you configure the preview feature, use the setPreviewTime method of the VidPlayerConfigGen interface to set the preview duration. The following example uses the VidSts playback method:
AVPVidStsSource *source = [[AVPVidStsSource alloc] init];
....
VidPlayerConfigGenerator* vp = [[VidPlayerConfigGenerator alloc] init];
[vp setPreviewTime:20];// 20-second preview
source.playConfig = [vp generatePlayerConfig];// Set for the playback source
...When a preview duration is set, the server returns only the content for that time period.
VidPlayerConfigGen supports setting various server-side request parameters. See Request parameter descriptions.
Set the Referer
The iOS Player SDK supports setting the Referer. When used together with the Referer blacklists and whitelists in the console, it can control access permissions. You can set the Referer of the request using the AVPConfig method. The following is an example of iOS Player SDK configuration:
// Get the configuration first.
AVPConfig *config = [self.player getConfig];
// Set the Referer.
config.referer = referer;
....// Other settings
// Set the configuration for the player.
[self.player setConfig:config];Set the User-Agent
The iOS player SDK provides AVPConfig to set the User-Agent (UA) header. After you set this header, the player includes the UA header in its HTTP requests. The following example demonstrates this:
// Get the configuration first.
AVPConfig *config = [self.player getConfig];
// Set the User-Agent.
config.userAgent = userAgent;
....// Other settings
// Set the configuration for the player.
[self.player setConfig:config];Configure network retry count and timeout
You can set the network timeout duration and the number of retries for the iOS player SDK using the AVPConfig method. The following is an example:
// Get the current configuration.
AVPConfig *config = [self.player getConfig];
// Specify the network timeout period. Unit: milliseconds.
config.networkTimeout = 5000;
// Specify the maximum number of retries upon a network timeout. The retry interval is the value of the networkTimeout parameter. A value of 0 indicates that no retry is performed. The application determines the retry policy. The default value is 2.
config.networkRetryCount = 2;
....// Configure other settings.
// Configure the settings for the player.
[self.player setConfig:config];If networkRetryCount is greater than 0, the player retries networkRetryCount times when a network problem occurs, with an interval of networkTimeout between retries.
If the loading state persists after all retries, the
onErrorevent is triggered withAVPErrorModel.codeset toERROR_LOADING_TIMEOUT.If you set
networkRetryCountto 0, the player triggers theonPlayerEventcallback witheventWithStringset toEVENT_PLAYER_NETWORK_RETRYwhen a network retry times out. You can then call the player’sreloadmethod to reload the network or perform other actions.
Configure cache and latency control
For a player, cache control is critical. Proper configuration can effectively improve startup speed and reduce stuttering. The iOS player SDK provides a control interface for configuring cache and latency through AVPConfig. The following example shows how to do this:
// Retrieve the configuration.
AVPConfig *config = [self.player getConfig];
// Specify the maximum latency. Note: This parameter is valid for only live streaming. If the latency is high, Player SDK synchronizes frames to ensure that the latency is within the specified limit.
config.maxDelayTime = 5000;
// Specify the maximum buffer duration. Unit: milliseconds. This parameter specifies the maximum duration of data that the player can buffer at a time.
config.maxBufferDuration = 50000;
// Specify the peak buffer duration. Unit: milliseconds. When the player loads data due to poor network conditions, the player stops loading after the duration of the buffered data reaches this value.
config.highBufferDuration = 3000;
// Specify the startup buffer duration. Unit: milliseconds. A smaller value indicates a shorter startup loading duration. However, the player may enter the loading status soon after the playback starts.
config.startBufferDuration = 500;
// Configure other settings.
// Apply the configuration to the player.
[self.player setConfig:config];The buffer durations must satisfy: startBufferDuration ≤ highBufferDuration ≤ maxBufferDuration.
When the maximum buffer duration (maxBufferDuration) is greater than 5 minutes, the system defaults to a 5-minute duration to prevent excessive memory usage.
Set HTTP headers
You can use the AVPConfig method to add HTTP header parameters to requests in the player. For example:
// Retrieve the configuration.
AVPConfig *config = [self.player getConfig];
// Define the headers.
NSMutableArray *httpHeaders = [[NSMutableArray alloc] init];
// For example, configure a host when you use HTTPDNS.
[httpHeaders addObject:@"Host:example.com"];
// Configure the headers.
config.httpHeaders = httpHeaders;
....// Configure other settings.
// Configure the settings for the player.
[self.player setConfig:config];Picture-in-Picture
For detailed code examples, see the PictureInPicture module in the API-Example project. This project is based on Objective-C and demonstrates core SDK integration for the ApsaraVideo Player SDK for iOS.
PiP requires iOS 15 or later and the ApsaraVideo Player SDK for iOS 5.4.9.0 or later.
For versions of the ApsaraVideo Player SDK for iOS earlier than 5.5.2.0, the PiP feature provides only methods to enable and disable PiP and to display the PiP window when the app is in the background. Starting from version 5.5.2.0, the SDK supports setting the PiP delegate from the outside, which allows for more personalized PiP feature development.
To use PiP, ensure it is enabled in your device's settings (Settings > General > Picture in Picture).
Enable PiP
After you enable the Picture-in-Picture (PiP) feature, the video continues to play in a small window when the application is moved to the background. When the application is brought back to the foreground, the video resumes its original playback format and continues to play. The PiP feature is controlled by the setPictureInPictureEnable switch and must be enabled when the player is in the AVPEventPrepareDone state. The following example shows how to enable the PiP feature:
- (void)onPlayerEvent:(AliPlayer *)player eventType:(AVPEventType)eventType {
switch (eventType) {
case AVPEventPrepareDone:
{
[self.player setPictureInPictureEnable:YES];
}
break;
default:
break;
}
}When you call stop to stop playback, you must first disable Picture-in-Picture (PiP) by calling setPictureInPictureEnable, and then call stop.
Set the PiP delegate
This section provides common code examples for interaction between Picture-in-Picture (PiP) windows and player windows. These examples include the logic for displaying PiP's pause, playback, fast forward, fast backward, and replay buttons. For details about the delegate methods, see the Player SDK Demo, specifically the AliPlayerPictureInPictureDelegate.h header file in the AliyunPlayer.framework folder.
Set the PiP delegate.
/** * @brief Set the PiP delegate. */ -(void) setPictureinPictureDelegate:(id<AliPlayerPictureInPictureDelegate>)delegate; // Set the PiP delegate. [self.player setPictureinPictureDelegate:self];Add variables and implement the delegate interface.
Add global variables to manage the player and PiP state.
#import "YourUIViewController.h" #import <AliyunPlayer/AliyunPlayer.h> @interface YourUIViewController () <AVPDelegate, AliPlayerPictureInPictureDelegate> // Player instance. @property (nonatomic, strong) AliPlayer *player; // Player view container. @property (nonatomic, strong) UIView *playerView; // Listen for whether PiP is currently paused. @property (nonatomic, assign) BOOL isPipPaused; // Listen for the current playback status of the player. Set it through the newStatus callback of the playback event status change listener. @property (nonatomic, assign) AVPStatus currentPlayerStatus; // Set the PiP controller. Set it in the callback method for when PiP is about to start. You need to actively set it to nil when the page is about to be destroyed. We recommend setting it. @property (nonatomic, weak) AVPictureInPictureController *pipController; // Listen for the current playback progress of the player. Set currentPosition to the value of the position parameter in the callback for the current video playback position. @property (nonatomic, assign) int64_t currentPosition; @endNoteYou must use the weak or assign modifier for pipController. If you use the assign modifier, make sure that you set the correct variables to null.
Update the status of the PiP controller when you listen for the onPlayerStatusChanged event.
- (void)onPlayerStatusChanged:(AliPlayer*)player oldStatus:(AVPStatus)oldStatus newStatus:(AVPStatus)newStatus { self.currentPlayerStatus = newStatus; if (_pipController) { [self.pipController invalidatePlaybackState]; } }When you listen for playback event callbacks, call the following method to update the Picture-in-Picture (PiP) controller's status.
- (void)onPlayerEvent:(AliPlayer*)player eventType:(AVPEventType)eventType { if (eventType == AVPEventCompletion) { if (_pipController) { self.isPipPaused = YES; // After playback ends, change the PiP status to paused. [self.pipController invalidatePlaybackState]; } } else if (eventType == AVPEventSeekEnd) { // Seeking is complete. if (_pipController) { [self.pipController invalidatePlaybackState]; } } }Set listeners.
Listen for the callback when PiP is about to start.
/** @brief Picture-in-Picture is about to start. @param pictureInPictureController The Picture-in-Picture controller. */ - (void)pictureInPictureControllerWillStartPictureInPicture:(AVPictureInPictureController *)pictureInPictureController { if (!_pipController) { self.pipController = pictureInPictureController; } self.isPipPaused = !(self.currentPlayerStatus == AVPStatusStarted); [pictureInPictureController invalidatePlaybackState]; }Listen for the callback when PiP is preparing to stop.
/** @brief Picture-in-Picture is preparing to stop. @param pictureInPictureController The Picture-in-Picture controller. */ - (void)pictureInPictureControllerWillStopPictureInPicture:(AVPictureInPictureController *)pictureInPictureController { self.isPipPaused = NO; [pictureInPictureController invalidatePlaybackState]; }Listen for the callback that instructs the delegate to restore the user interface before PiP stops.
/** @brief Tells the delegate to restore the user interface before Picture-in-Picture stops. @param pictureInPictureController The Picture-in-Picture controller. @param completionHandler Call and pass YES to allow the system to finish restoring the player user interface. */ - (void)pictureInPictureController:(AVPictureInPictureController *)pictureInPictureController restoreUserInterfaceForPictureInPictureStopWithCompletionHandler:(void (^)(BOOL restored))completionHandler { if (_pipController) { _pipController = nil; } completionHandler(YES); }Listen for the callback that sets the current playable time range for PiP.
/** @brief Notifies the Picture-in-Picture controller of the current playable time range. @param pictureInPictureController The Picture-in-Picture controller. @return The current playable time range. */ - (CMTimeRange)pictureInPictureControllerTimeRangeForPlayback:(nonnull AVPictureInPictureController *)pictureInPictureController layerTime:(CMTime)layerTime{ Float64 current64 = CMTimeGetSeconds(layerTime); Float64 start; Float64 end; if (currentPosition <= self.player.duration) { double curPostion = self.currentPosition / 1000.0; double duration = self.player.duration / 1000.0; double interval = duration - curPostion; start = current64 - curPostion; end = current64 + interval; CMTime t1 = CMTimeMakeWithSeconds(start, layerTime.timescale); CMTime t2 = CMTimeMakeWithSeconds(end, layerTime.timescale); return CMTimeRangeFromTimeToTime(t1, t2); } else { return CMTimeRangeMake(kCMTimeNegativeInfinity, kCMTimePositiveInfinity); } }Callback for monitoring whether Picture-in-Picture (PiP) is paused or playing.
/** @brief Reflects the paused or playing state on the UI. @param pictureInPictureController The Picture-in-Picture controller. @return Paused or playing. */ - (BOOL)pictureInPictureControllerIsPlaybackPaused:(nonnull AVPictureInPictureController *)pictureInPictureController{ return self.isPipPaused; }NoteThis callback is triggered before PiP starts. Make sure that the return value of this callback is false at this time. Otherwise, PiP cannot be activated.
Listen for the callback when the user skips forward or backward to synchronize the playback progress to the player.
/** @brief The fast forward or fast backward button is clicked. @param pictureInPictureController The Picture-in-Picture controller. @param skipInterval The time interval for fast forwarding or fast backwarding. @param completionHandler A closure that must be called to indicate that the seek operation is complete. */ - (void)pictureInPictureController:(nonnull AVPictureInPictureController *)pictureInPictureController skipByInterval:(CMTime)skipInterval completionHandler:(nonnull void (^)(void))completionHandler { int64_t skipTime = skipInterval.value / skipInterval.timescale; int64_t skipPosition = self.currentPosition + skipTime * 1000; if (skipPosition < 0) { skipPosition = 0; } else if (skipPosition > self.player.duration) { skipPosition = self.player.duration; } [self.player seekToTime:skipPosition seekMode:AVP_SEEKMODE_INACCURATE]; [pictureInPictureController invalidatePlaybackState]; }Listen for the callback when the pause or play button is clicked in PiP, and perform the required operations.
/** @brief The pause button in Picture-in-Picture is clicked. @param pictureInPictureController The Picture-in-Picture controller. @param playing Whether it is playing. */ - (void)pictureInPictureController:(nonnull AVPictureInPictureController *)pictureInPictureController setPlaying:(BOOL)playing { if (!playing){ [self.player pause]; self.isPipPaused = YES; } else { // Recommendation: If PiP playback is complete and needs to be replayed, you can additionally execute the code in the following if statement. if (self.currentPlayerStatus == AVPStatusCompletion) { [self.player seekToTime:0 seekMode:AVP_SEEKMODE_ACCURATE]; } [self.player start]; self.isPipPaused = NO; } [pictureInPictureController invalidatePlaybackState]; }
In-app Picture-in-Picture
By default, PiP activates when the app moves to the background. To implement in-app PiP, you can manually control its activation. First, determine if PiP has been started.
/**
@brief Whether PiP is started.
@param pictureInPictureController The PiP controller.
@param isEnable Whether PiP is started.
*/
/****
@brief pictureInPicture is enable or not
@param pictureInPictureController picture in picture controller
@param isEnable is enable or not
*/
- (void)pictureInPictureControllerIsPictureInPictureEnable:(nullable AVPictureInPictureController *)pictureInPictureController isEnable:(BOOL)isEnable;When PiP is enabled, disable automatic activation and control it manually.
- (void) pictureInPictureControllerIsPictureInPictureEnable:(nullable AVPictureInPictureController *) pictureInPictureController isEnable:(BOOL) isEnable
{
if (isEnable && pictureInPictureController) {
_pipController = pictureInPictureController;
// close pip auto start
if (@available(iOS 15.0, *)) {
_pipController.canStartPictureInPictureAutomaticallyFromInline = false;
}
} else {
_pipController = NULL;
}
}
- (void) switchPip:(bool) enable {
if (_pipController == nil) {
return;
}
if (enable) {
// start pip
[_pipController startPictureInPicture];
} else {
// close pip
[_pipController stopPictureInPicture];
}
}Live RTS fallback
For a detailed code example, see the RtsLiveStream module in the API-Example project. This project is based on Objective-C and demonstrates core SDK integration for the ApsaraVideo Player SDK for iOS.
For more information, see RTS live playback.
Switch left and right sound channels
In the iOS player SDK, you can use the outputAudioChannel property to set the output audio channel. If the input source is stereo, you can use the methods described below to switch to the left or right audio channel. This setting has no effect if the input source is mono.
The output audio channel setting affects both audio rendering and PCM data callbacks.
// Set the AVPOutputAudioChannel enumeration value to switch channels.
// AVP_AUDIO_CHANNEL_NONE: Do not specify a channel. Play with the input source's audio channel. This is the default value.
// AVP_AUDIO_CHANNEL_LEFT: Switch to the left audio channel for playback.
// AVP_AUDIO_CHANNEL_RIGHT: Switch to the right audio channel for playback.
self.player.outputAudioChannel = AVP_AUDIO_CHANNEL_NONE;Set the video background color
You can use the Player SDK for iOS to set the background color for rendering. The API and its usage are as follows:
API example
/**
@brief Set the background color of the video.
@param color the color
*/
/****
@brief Set video background color
@param color the color
*/
-(void) setVideoBackgroundColor:(UIColor *)color;Usage
// The parameter is an 8-digit hexadecimal value. The 8 digits are grouped into pairs, representing A (alpha/transparency), R (red), G (green), and B (blue) in order.
// For example, 0x0000ff00 represents green.
[self.player setVideoBackgroundColor:0x0000ff00]Specify a playback domain for VidAuth
With the VidAuth method, you can specify parameters such as the playback domain. For a list of supported fields, see GetPlayInfo. The interface and usage instructions are as follows:
API example
/**
@brief Play using the vid+playauth method. See https://www.alibabacloud.com/help/zh/vod/user-guide/use-playback-credentials-to-play-videos
@param source The input type of AVPVidAuthSource.
@see AVPVidAuthSource
*/
- (void)setAuthSource:(AVPVidAuthSource*)source;Usage
Add the playDomain field through the VidPlayerConfigGenerator interface.
VidPlayerConfigGenerator* gen = [[VidPlayerConfigGenerator alloc]init];
// Add the playDomain field. For the fields that can be added, see
// https://www.alibabacloud.com/help/zh/vod/developer-reference/api-vod-2017-03-21-getplayinfo
[gen addVidPlayerConfigByStringValue:@"playDomain" value: @"com.xxx.xxx"];
[source setPlayConfig:[gen generatePlayerConfig]];
[self.player setAuthSource:source]:Background decoding
Starting from version 6.12.0, the SDK supports background decoding. When enabled, the player can continue to decode and play video streams when the app is in the background.
// A value of 1 enables background decoding. A value of 0 disables background decoding. The default value is 0.
[self.player setOption:ALLOW_DECODE_BACKGROUND valueInt:1];H.266 decoding plugin
H.266, also known as Versatile Video Coding (VVC), is a next-generation video coding standard that offers significantly lower bitrates at the same quality. The H.266 decoding capability is provided as a separate plug-in for on-demand integration.
Prerequisites
Use the Player or all-in-one SDK V7.6.0 or later.
You have completed authorization of your Professional Edition license. For more information, see Obtaining a Player SDK License.
ApsaraVideo Player with the H.266 decoding plug-in supports only H.266 videos encoded by ApsaraVideo Transcoding.
Integrate the plugin
Activate the plugin
Starting from v7.7.0, the plug-in is enabled by default and does not need manual activation.
[AliPlayerGlobalSettings enableCodecPlugin:@"vvc" valid:true];Related error codes
For error codes related to the H.266 plug-in, see General FAQ for players on different platforms.
Auto-refresh playback sources
Enabling auto-refresh prevents playback interruptions caused by expired authentication. When a source expires, the player triggers a listener to fetch a new URL, ensuring continuous and smooth playback.
Prerequisites
Use the Player or all-in-one SDK V7.9.0 or later.
Use VidAuth sources or configure URL signing.
VidAuth source
API example
/**
@brief Set the callback for VidAuth source expiration notification.
When the player detects that the current VidAuth source has expired, this callback is triggered. VidAuth source expiration includes PlayAuth expiration and playback URL expiration.
You can refresh the VidAuth source in the callback and submit the new VidAuth source object via `callback` to ensure stable and smooth video playback.
@param callback The callback block triggered when the VidAuth source expires.
You can use this callback to return a valid `VidAuth` object to update the player.
*/
/****
@brief Set the callback for VidAuth source expiration notification.
This method is triggered when the player detects that the current VidAuth source has expired.
You can refresh the VidAuth source within the callback and use the `callback` to return the updated VidAuth source,
ensuring uninterrupted and smooth video playback.
@param callback The callback block triggered when the VidAuth source expires.
Use this callback to provide a valid `VidAuth` object to update the player.
*/
-(void)setOnVidAuthExpiredCallback:(void (^)(id expiredSource, id<AVPSourceRefreshCallback> callback))callback;Function composition
Usage
You can retrieve video playback credentials by calling the GetVideoPlayAuth operation. We recommend integrating the ApsaraVideo VOD server-side SDK to get credentials and avoid self-signing. For more information, see OpenAPI Explorer.
[self.player setOnVidAuthExpiredCallback:^(id expiredSource, id<AVPSourceRefreshCallback> callback) {
// Get AVPVidAuthSource
if ([expiredSource isKindOfClass:[AVPVidAuthSource class]]) {
// ------------------- User implementation starts -------------------
// Call your own function to get a new PlayAuth from your app server.
// clinetGetPlayAuthFunction is a sample function name. Replace it with your own implementation.
[self clinetGetPlayAuthFunction:vid success:^(NSString* newPlayAuth){
// 1. Callback for successful retrieval of new credentials
[vidAuth setPlayAuth:newPlayAuth];
// 2. Return the updated object to the player via the SDK callback
[callback onSuccess:vidAuth];
} failure:^(NSString* errorMsg) {
// Callback for failed credential retrieval.
// errorMsg contains detailed error information.
[callback onError:errorMsg];
}];
// ------------------- User implementation ends -------------------
}
}];URL source
API example
/**
@brief Set the callback for URL source expiration notification.
When the player detects that the current URL source has expired, this callback is triggered.
You can refresh the URL source in the callback and use `callback` to return the new URL source, ensuring uninterrupted video playback.
@note For information about configuring URL signing, see the Alibaba Cloud documentation:
https://www.alibabacloud.com/help/zh/vod/user-guide/configure-url-signing?spm=a2c4g.11186623.0.0.560c4140fGh8MW
@param callback The callback block triggered when the URL source expires.
You can use this callback to provide a valid `URLSource` object to update the player.
*/
/****
@brief Set the callback for URL source expiration notification.
This method is triggered when the player detects that the current URL source has expired.
You can refresh the URL source within the callback and use the `callback` to return the updated URL source,
ensuring uninterrupted video playback.
@param callback The callback block triggered when the URL source expires.
Use this callback to provide a valid `URLSource` object to update the player.
*/
-(void)setOnURLSourceExpiredCallback:(void (^)(id expiredSource, id<AVPSourceRefreshCallback> callback))callback;Function composition
Usage
[self.player setOnURLSourceExpiredCallback:^(id expiredSource, id<AVPSourceRefreshCallback> callback) {
// Get AVPUrlSource
if ([expiredSource isKindOfClass:[AVPUrlSource class]]) {
AVPUrlSource *expiredUrlSource = (AVPUrlSource *)expiredSource;
NSString *expiredUrl = [expiredUrlSource.playerUrl absoluteString];
// Check if auth_key is included
if (![expiredUrl containsString:@"auth_key="]) {
return;
}
// 1. Extract the original URL from the expired URL
NSRange authKeyQuestionRange = [expiredUrl rangeOfString:@"?auth_key="];
NSRange authKeyAmpersandRange = [expiredUrl rangeOfString:@"&auth_key="];
NSInteger authKeyIndex = NSNotFound;
if (authKeyQuestionRange.location != NSNotFound) {
authKeyIndex = authKeyQuestionRange.location;
} else if (authKeyAmpersandRange.location != NSNotFound) {
authKeyIndex = authKeyAmpersandRange.location;
}
NSString *originalUrl = nil;
if (authKeyIndex != NSNotFound) {
originalUrl = [expiredUrl substringToIndex:authKeyIndex];
} else {
// If auth_key is not found, consider the entire URL as the original URL
originalUrl = expiredUrl;
}
// 2. Prepare new authentication parameters: authKey and expiration time
// If the class member authKey is valid, use authKey
NSString *key = (self.authKey.length > 0) ? self.authKey : @"";
if (!NOT_EMPTY(key)) {
[callback onError:@"REFRESH_ERROR:key fail"];
return;
}
// If the class member validTime is valid, use validTime; otherwise, use the default value
NSTimeInterval validTime = (self.validTime > 0) ? self.validTime : 3600; // Default 3600 seconds
NSTimeInterval newExpireTime = [[NSDate date] timeIntervalSince1970] + validTime;
// 3. Generate a new authenticated URL using CdnAuthUtil (Method A)
NSString *newAuthUrl = [CdnAuthUtil aAuthWithUri:originalUrl key:key exp:newExpireTime];
AVPUrlSource *resultSource = [[AVPUrlSource alloc] urlWithString:newAuthUrl];
// 4. Callback handling
if (newAuthUrl) {
[callback onSuccess:resultSource];
} else {
[callback onError:@"REFRESH_ERROR:refresh fail"];
}
}
}];Utility functions
For example, using signing method A.
Performance
Set the playback scenario
Setting the playback scenario automatically configures optimal parameters (including buffer settings and feature toggles) while preserving custom settings made via the setConfig interface (custom settings take precedence).
After setting the playback scenario, use the
getConfiginterface to view the parameter configuration.
API example
/**
@brief Set player scenario.
@param scene Player scenario.
@see AVPScenario
*/
/****
@brief Set player scene.
@param scene Player scene.
@see AVPScene
*/
-(void) setPlayerScene:(AVPScene)scene;Playback scenarios
typedef enum _AVPScene {
/**
* Scenario: None
*/
/****
* scene none
*/
SceneNone,
/**
* Long-video scenario: Applies to videos longer than 30 minutes
*/
/****
* long scene: apply to more than 30min
*/
SceneLong,
/**
* Medium-video scenario: Applies to videos 5–30 minutes long
*/
/****
* middle scene: apply to 5min-30min
*/
SceneMedium,
/**
* Short-video scenario: Applies to videos up to 5 minutes long
*/
/****
* short scene: apply to 0s-5min
*/
SceneShort,
/**
* Live-streaming scenario
*/
/****
* live scene
*/
SceneLive,
/**
* Ultra-low-latency live-streaming scenario
*/
/****
* RTS live scene
*/
SceneRTSLive
} AVPScene;Usage
// Set short-video scenario
[self.player setPlayerScene:SceneShort];
// Set medium-video scenario
[self.player setPlayerScene:SceneMedium];
// Set long-video scenario
[self.player setPlayerScene:SceneLong];
// Set live-streaming scenario
[self.player setPlayerScene:SceneLive]; Pre-rendering
The ApsaraVideo Player SDK for iOS supports quickly rendering the first frame before playback starts, improving startup speed.
This feature is disabled by default.
You must set the
Viewbefore callingPrepareto ensure the frame is ready for rendering on theView.When enabled, this feature changes the order of the preparation success and first-frame rendering events: Without it, preparation success fires first, then first-frame rendering. With it, first-frame rendering may fire before preparation success, depending on decoding and rendering speed. This does not affect playback.
Example:
[self.player setOption:ALLOW_PRE_RENDER valueInt:1];Local cache
For detailed code examples, see the PreloadUrl module in the API-Example project. This project is based on Objective-C and demonstrates core SDK integration for the ApsaraVideo Player SDK for iOS.
The ApsaraVideo Player SDK for iOS provides local caching to improve startup speed, seek speed, and reduce stuttering for repeated video playback. It also saves bandwidth.
Enable local cache
The local caching feature is disabled by default. To use this feature, you must enable it manually. You can control this feature in AliPlayerGlobalSettings using enableLocalCache. The following is an example:
/**
* Enable local cache. After enabling, it will cache to local files.
* @param enable: Local cache feature switch. true: enable, false: disable. Default is disable.
* @param maxBufferMemoryKB: Deprecated since V5.4.7.1. No effect.
* @param localCacheDir: Must be set. The directory for local cache files. Must be an absolute path.
*/
[AliPlayerGlobalSettings enableLocalCache:true maxBufferMemoryKB:1024 localCacheDir:@""];
/**
@brief Settings for automatic clearing of local cache files.
@param expireMin: Deprecated since V5.4.7.1. No effect.
@param maxCapacityMB: Maximum cache capacity in megabytes. Default is 20 GB. During cleanup, if the total cache capacity exceeds this size, the oldest cache files will be deleted one by one, sorted by the last cache time of the cacheItem, until the capacity is less than or equal to the maximum cache capacity.
@param freeStorageMB: Minimum free disk space in megabytes. Default is 0. During cleanup, similar to the maximum cache capacity, if the current disk space is less than this value, cache files will also be deleted one by one according to the rules until freeStorage is greater than or equal to this value or all caches are cleared.
*/
[AliPlayerGlobalSettings setCacheFileClearConfig:0 maxCapacityMB:0 freeStorageMB:0];
/**
* Callback to get the hash value of the loaded URL. Used as a unique ID for the URL. You must ensure that each URL is different.
*/
// You need to implement this function yourself and pass the function pointer to setCacheUrlHashCallback.
static NSString *CaheUrlHashHandle(NSString *url) {
return @"xxx";
}
[AliPlayerGlobalSettings setCacheUrlHashCallback:&CaheUrlHashHandle];If the playback URL of a video file contains authentication parameters, the values of the authentication parameters change during the local caching and playback of the video file. You can call the
setCacheUrlHashCallbackoperation to calculate the MD5 hash value after you remove the authentication parameters. For example,http://****.mp4?aaais the playback URL of a video file that contains authentication parameters. In this case, the URLhttp://****.mp4is used to calculate the MD5 hash value when the video file is loaded. However, if you calculate the MD5 hash value after you remove the authentication parameters in the key URL of an encrypted M3U8 video, the playback fails because different videos are hit by the same key URL. Solution: Remove the authentication parameters only from the playback URLhttp(s)://xxxxx.m3u8?aaaabut not the key URLhttp(s)://yyyyy?bbbbin thesetCacheUrlHashCallbackcallback.
If the server supports both HTTP and HTTPS protocols but points to the same media file, remove or unify the request headers before computing the MD5 value. For example:
If the video playback URLs are
https://****.mp4andhttp://****.mp4, use****.mp4to calculate the MD5 value.If the video playback URL is
https://****.mp4, unify it tohttp://****.mp4before you calculate the MD5 value.
For Player SDK 5.5.4.0 and later, if the video playback URL contains authentication parameters and the playback protocol is HLS, you can set the
AVPConfig.enableStrictAuthModefield to select a different authentication mode (The default value is false for earlier versions. The default value is true for 7.13.0 and later.):Non-strict authentication (false): Authentication is cached. If only part of the media was cached previously, the player uses the cached authentication to request non-cached parts. If the URL authentication validity period is short, or playback resumes long after pausing, authentication may expire. Combine with the auto-refresh playback sources feature to handle expired authentication during resume.
Strict authentication (true): Authentication is not cached. Authentication occurs on every startup, causing startup failure without network connectivity.
Enable or disable local cache for a single URL
If you want to disable the local cache feature for a single URL, you can set this in the player config. The following is an example:
// Get the configuration first.
AVPConfig *config = [self.player getConfig];
// Whether to enable local cache for the playback URL. Default is true. When local cache is enabled in AliPlayerGlobalSettings and also enabled here (set to true), the local cache for this URL takes effect. If set to false here, local cache for this URL is disabled.
config.enableLocalCache = false;
....// Other settings
// Set the configuration for the player.
[self.player setConfig:config];Use the default cache path
If you want to use the default path for caching, you can configure AliPlayerGlobalSettings as follows.
[AliPlayerGlobalSettings enableLocalCache:true];Preloading
The ApsaraVideo Player SDK for iOS provides preloading, an upgrade to local caching that improves startup speed by downloading part of a video into the cache before playback begins.
Preloading limits:
Supports single media files such as MP4, MP3, FLV, and HLS.
By default, the SDK schedules preload network requests to avoid interfering with the currently playing video. The preload request is sent only after the buffered content reaches a specific threshold. To disable this and manage requests in real-time, use the following:
[AliPlayerGlobalSettings enableNetworkBalance:false];Enable local cache as described in Local cache.
Set the data source.
VidAuth (recommended)
AVPVidAuthSource* vidAuthSource = [[AVPVidAuthSource alloc] init]; [vidAuthSource setVid:@"Vid information"]; // Required. The video ID (VideoId). [vidAuthSource setPlayAuth:@"<yourPlayAuth>"]; // Required. The playback credential. You need to call the GetVideoPlayAuth operation of ApsaraVideo VOD to generate it. [vidAuthSource setRegion:@"Access region"]; // For player SDK V5.5.5.0 and later, this parameter is deprecated. You do not need to set the region. The player will automatically parse the region. For player SDK versions earlier than 5.5.5.0, this parameter is required. The access region of ApsaraVideo VOD. The default is cn-shanghai. [vidAuthSource setQuality:@"Selected definition"]; //"AUTO" represents adaptive bitrate.VidSts
AVPVidStsSource* vidStsSource = [[AVPVidStsSource alloc] init]; [vidStsSource setVid: @"Vid information"]; // Required. The video ID (VideoId). [vidStsSource setRegion:@"Access region"]; // Required. The access region of ApsaraVideo VOD. The default is cn-shanghai. [vidStsSource setSecurityToken: @"<yourSecurityToken>"]; // Required. The STS security token. You need to call the AssumeRole operation of STS to generate it. [vidStsSource setAccessKeySecret: @"<yourAccessKeySecret>"]; // Required. The AccessKey secret of the temporary STS AccessKey pair. You need to call the AssumeRole operation of STS to generate it. [vidStsSource setAccessKeyId: @"<yourAccessKeyId>"]; // Required. The AccessKey ID of the temporary STS AccessKey pair. You need to call the AssumeRole operation of STS to generate it. [vidStsSource setQuality:@"Selected definition"]; //"AUTO" represents adaptive bitrate.UrlSource
NSString* url = @"Playback URL"; // Required. The playback URL. It can be a third-party VOD URL or a playback URL from ApsaraVideo VOD. AVPUrlSource* urlSource = [[AVPUrlSource alloc]urlWithString:url];Set task parameters.
NoteThis applies only to multi-bitrate videos. You can choose any one of
setDefaultBandWidth,setDefaultResolution, orsetDefaultQuality.AVPPreloadConfig *config = [[AVPPreloadConfig alloc]init]; // Set the preload bitrate for a multi-bitrate stream. [config setDefaultBandWidth:400000]; // Set the preload resolution for a multi-bitrate stream. [config setDefaultResolution:640 * 480]; // Set the preload quality for a multi-bitrate stream. [config setDefaultQuality:@"FD"]; // Set the preload duration. [config setDuration:1000];Add a task listener.
Build the task, add it to the
MediaLoaderV2instance, and start preloading.VidAuth (recommended)
// Build the preload task. AVPPreloadTask* mPreloadTask = [[AVPPreloadTask alloc]initWithVidAuthSource:vidAuthSource preloadConfig:config]; // Get the MediaLoaderV2 instance. AliMediaLoaderV2* vodMedialoader = [AliMediaLoaderV2 shareInstance]; // Add the task and start preloading. NSString* taskId = [vodMedialoader addTask:mPreloadTask listener:self];VidSts
// Build the preload task. AVPPreloadTask* mPreloadTask = [[AVPPreloadTask alloc]initWithVidStsSource:vidStsSource preloadConfig:config]; // Get the MediaLoaderV2 instance. AliMediaLoaderV2* vodMedialoader = [[AliMediaLoaderV2 alloc]init]; // Add the task and start preloading. NSString* taskId = [vodMedialoader addTask:mPreloadTask listener:self];UrlSource
// Build the preload task. AVPPreloadTask* mPreloadTask = [[AVPPreloadTask alloc]initWithUrlSource:urlSource preloadConfig:config]; // Get the MediaLoaderV2 instance. AliMediaLoaderV2* vodMedialoader = [[AliMediaLoaderV2 alloc]init]; // Add the task and start preloading. NSString* taskId = [vodMedialoader addTask:mPreloadTask listener:self];Optional: Manage tasks.
[vodMedialoader cancelTask:taskId];// Cancel the preload task with the specified task ID. [vodMedialoader pauseTask:taskId];// Pause the preload task with the specified task ID. [vodMedialoader resumeTask:taskId];// Resume the preload task with the specified task ID.Optional: Delete loaded files.
You can delete loaded files as needed to save space. The SDK does not provide a delete interface. You need to delete the files in the loading directory in the app.
Dynamic preloading
The dynamic preloading policy lets you balance playback experience and cost by controlling the cache of the current video and the number of preloaded items.
Preload multi-bitrate HLS videos
For multi-bitrate HLS videos in listPlayer, you can preload a stream that matches the current playback definition and select a preload mode.
Get the download speed
Retrieve the download speed of the currently playing video in the onCurrentDownloadSpeed callback.
- (void)onCurrentDownloadSpeed:(AliPlayer *)player speed:(int64_t)speed{
intspeed_=speed;
}Network features
HTTPDNS
The HTTPDNS feature uses DNS resolution technology to send domain name resolution requests to a specific HTTPDNS server and obtain resolution results quickly and stably. This prevents DNS hijacking.
ApsaraVideo Player SDK provides HTTPDNS services for domain names accelerated by Alibaba Cloud CDN. You can use the enhanced HTTPDNS feature to implement precise scheduling and ensure that real-time domain resolution results immediately take effect. This improves network performance.
Enhanced HTTPDNS usage example
You can use the enhanced HTTPDNS feature only for accelerated domain names. Before you use the feature, make sure that an accelerated domain name is added and configured. For more information about how to add and configure a domain name for CDN in ApsaraVideo VOD, see Add an accelerated domain name. For more information about accelerated domain names, see What is Alibaba Cloud CDN?.
// Enable enhanced HTTPDNS.
[AliPlayerGlobalSettings enableEnhancedHttpDns:YES];
// Optional. Add a domain for HTTPDNS pre-resolution.
[[AliDomainProcessor shareInstance] addPreResolveDomain:@"player.***alicdn.com"];HTTP/2
The ApsaraVideo Player SDK for iOS enables HTTP/2 by default starting from V5.5.0.0.
The ApsaraVideo Player SDK for iOS supports HTTP/2. This protocol uses multiplexing to avoid head-of-line blocking and improve playback performance.
[AliPlayerGlobalSettings setUseHttp2:true];HTTP pre-established TCP connections
For HTTP (not HTTPS) video playback requests, pre-establishing TCP connections significantly improves user experience, reduces connection time, ensures playback immediacy and continuity, and optimizes network and system resource usage.
// Domain format is host[:port]. Port is optional. Multiple domains are separated by semicolons (;).
// Global setting.
// Each time the full interface is set, the current string is used (add for more, delete for less). An empty string stops pre-connection.
[AliPlayerGlobalSettings setOption:SET_PRE_CONNECT_DOMAIN value: @"domain1;domain2"];Video download
For detailed code examples, see the Download module in the API-Example project. This project is based on Objective-C and demonstrates core SDK integration for the ApsaraVideo Player SDK for iOS.
The ApsaraVideo Player SDK for iOS provides a video download feature for ApsaraVideo VOD content, with standard and secure modes.
Standard download: The downloaded video is not encrypted and can be played by third-party players.
Secure download: The downloaded video is encrypted and can only be played by the ApsaraVideo Player.
Usage notes
This feature is only for VidSts and VidAuth sources.
Enable and configure the download mode in the ApsaraVideo VOD console. For more information, see Offline download.
You can resume video downloads from a breakpoint.
Procedure
Optional: Configure the encryption verification file for secure download. Configure this file only for secure download. Standard download does not require it.
NoteEnsure the encryption verification file matches your app information. Otherwise, the video download fails.
If you use secure download, configure the key file generated in the ApsaraVideo VOD console in the Player SDK. The key file is used to decrypt and verify the video for download and playback. For more information about generating the key file, see Enable secure download.
You need to configure this only once in the application. The following is an example:
NSString *encrptyFilePath = [[NSBundle mainBundle] pathForResource:@"encryptedApp" ofType:@"dat"]; [AliPrivateService initKey:encrptyFilePath];Create and set up the downloader.
Example:
AliMediaDownloader *downloader = [[AliMediaDownloader alloc] init]; [downloader setSaveDirectory:self.downLoadPath]; [downloader setDelegate:self];Set event listeners.
The download object provides multiple listeners.
-(void)onPrepared:(AliMediaDownloader *)downloader mediaInfo:(AVPMediaInfo *)info { // The download item is successfully prepared. } -(void)onError:(AliMediaDownloader *)downloader errorModel:(AVPErrorModel *)errorModel { // A download error occurred. } -(void)onDownloadingProgress:(AliMediaDownloader *)downloader percentage:(int)percent { // Download progress percentage. } -(void)onProcessingProgress:(AliMediaDownloader *)downloader percentage:(int)percent { // Processing progress percentage. } -(void)onCompletion:(AliMediaDownloader *)downloader { // The download is successful. }Prepare the download source.
Call the
preparemethod to prepare a download source. Supported source types include VidStsSource and VidAuthSource. Examples follow:VidSts
// Create VidSts. AVPVidStsSource* stsSource = [[AVPVidStsSource alloc] init]; stsSource.region = @"Access region"; // The access region of ApsaraVideo VOD. The default is cn-shanghai. stsSource.vid = @"Vid information"; // The video ID (VideoId). stsSource.securityToken = @"<yourSecurityToken>"; // The STS security token. You need to call the AssumeRole operation of STS to generate it. stsSource.accessKeySecret = @"<yourAccessKeySecret>"; // The AccessKey secret of the temporary STS AccessKey pair. You need to call the AssumeRole operation of STS to generate it. stsSource.accessKeyId = @"<yourAccessKeyId>"; // The AccessKey ID of the temporary STS AccessKey pair. You need to call the AssumeRole operation of STS to generate it. // If you have enabled HLS standard encryption parameter pass-through in the VOD console, and the default parameter name is MtsHlsUriToken, you need to set the config and pass it into the vid. See below. // If you have not enabled HLS standard encryption parameter pass-through in the VOD console, you do not need to integrate the following code. VidPlayerConfigGenerator* vp = [[VidPlayerConfigGenerator alloc] init]; [vp setHlsUriToken:yourMtsHlsUriToken]; stsSource.playConfig = [vp generatePlayerConfig]; // Prepare the download source. [downloader prepareWithVid:stsSource];VidAuth
// Create VidAuth. AVPVidAuthSource *authSource = [[AVPVidAuthSource alloc] init]; authSource.vid = @"Vid information"; // The video ID (VideoId). authSource.playAuth = @"<yourPlayAuth>"; // The playback credential. You need to call the GetVideoPlayAuth operation of ApsaraVideo VOD to generate it. authSource.region = @"Access region"; // For player SDK V5.5.5.0 and later, this parameter is deprecated. You do not need to set the region. The player will automatically parse the region. For player SDK versions earlier than 5.5.5.0, this parameter is required. The access region of ApsaraVideo VOD. The default is cn-shanghai. // If you have enabled HLS standard encryption parameter pass-through in the VOD console, and the default parameter name is MtsHlsUriToken, you need to set the config and pass it into the vid. See below. // If you have not enabled HLS standard encryption parameter pass-through in the VOD console, you do not need to integrate the following code. VidPlayerConfigGenerator* vp = [[VidPlayerConfigGenerator alloc] init]; [vp setHlsUriToken:yourMtsHlsUriToken]; authSource.playConfig = [vp generatePlayerConfig]; // Prepare the download source. [downloader prepareWithVid:authSource];
NoteIf you enable parameter pass-through for HLS encryption in the ApsaraVideo VOD console, the default parameter is MtsHIsUriToken. For more information, see Parameter pass-through for HLS encryption. Then, set the MtsHIsUriToken value to the ApsaraVideo VOD source by following the preceding code.
Select a download item.
After preparation succeeds, the
onPreparedmethod is called. The returned TrackInfo includes information such as the definition of each video stream. Select a track to download. The following is an example:-(void)onPrepared:(AliMediaDownloader *)downloader mediaInfo:(AVPMediaInfo *)info { NSArray<AVPTrackInfo*>* tracks = info.tracks; // For example, download the first TrackInfo. [downloader selectTrack:[tracks objectAtIndex:0].trackIndex]; }Update the download source and start the download.
VidSts or VidAuth may expire before the download. Therefore, we recommend updating the download source before you start the download.
// Update the download source. [downloader updateWithVid:vidSource] // Start the download. [downloader start];After the download succeeds or fails, release the downloader.
After the download succeeds, invoke
destroyto release the downloader.[self.downloader destroy]; self.downloader = nil;
Encrypted playback
ApsaraVideo VOD supports HLS standard encryption, Alibaba Cloud proprietary encryption, and DRM encryption. For instructions, see Play an encrypted video.
Native RTS playback
The SDK integrates the Native RTS SDK to implement low-latency live streaming. For more information, see Implement RTS-based stream pulling on iOS.