All Products
Search
Document Center

ApsaraVideo VOD:Advanced features

Last Updated:Feb 10, 2026

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.

Important

To try out the demo, download it and follow the instructions in Run the demo to compile and run the project.

Professional Skills Confirmation

Note

Some player features require a Professional Edition license. For more information, see Features. To obtain a license, refer to Obtain a license.

You can 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 advanced features. When you use a related feature, the player verifies the license and returns the result through this callback. If isValid is false, errorMsg contains the reason for the failure.

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.

Procedure

  1. Create a player.

    Create an AliListPlayer instance.

    self.listPlayer = [[AliListPlayer alloc] init];
    [self.listPlayer setTraceID:@"xxxxxx"];  // The TraceID is a unique identifier for a device or user, such as an IMEI or IDFA.

  2. Optional: Set listeners.

    Listeners are optional when you create a list player. If you do not configure listeners, you cannot receive notifications about player-related events, such as playback failures or playback progress. We recommend that you configure listeners.

    The player supports configuring multiple listeners, including onPlayerEvent and onError, which are particularly important. We recommend that you configure them.

    /**
     @brief Error callback.
     @param player The player pointer.
     @param errorModel The player error description. See AliVcPlayerErrorModel.
     */
    - (void)onError:(AliPlayer*)player errorModel:(AVPErrorModel *)errorModel {
        // Display an error message and stop playback.
    }
    /**
     @brief Player event callback.
     @param player The player pointer.
     @param eventType The player event type. See AVPEventType.
     */
    -(void)onPlayerEvent:(AliPlayer*)player eventType:(AVPEventType)eventType {
        switch (eventType) {
            case AVPEventPrepareDone: {
                // The player is prepared.
            }
                break;
            case AVPEventAutoPlayStart:
                // Autoplay starts.
                break;
            case AVPEventFirstRenderedStart:
                // The first frame is rendered.
                break;
            case AVPEventCompletion:
                // Playback is complete.
                break;
            case AVPEventLoadingStart:
                // Buffering starts.
                break;
            case AVPEventLoadingEnd:
                // Buffering is complete.
                break;
            case AVPEventSeekEnd:
                // Seeking is complete.
                break;
            case AVPEventLoopingStart:
                // Loop playback starts.
                break;
            default:
                break;
        }
    }
    /**
     @brief Callback for the current playback position.
     @param player The player pointer.
     @param position The current playback position.
     */
    - (void)onCurrentPositionUpdate:(AliPlayer*)player position:(int64_t)position {
        // Update the progress bar.
    }
    /**
     @brief Callback for the video's buffered position.
     @param player The player pointer.
     @param position The current buffered position.
     */
    - (void)onBufferedPositionUpdate:(AliPlayer*)player position:(int64_t)position {
        // Update the buffer progress.
    }
    /**
     @brief Callback for track information.
     @param player The player pointer.
     @param info An array of track stream information. See AVPTrackInfo.
     */
    - (void)onTrackReady:(AliPlayer*)player info:(NSArray<AVPTrackInfo*>*)info {
        // Get information about multi-bitrate streams.
    }
    /**
     @brief Callback for displaying subtitles.
     @param player The player pointer.
     @param trackIndex The index of the subtitle stream.
     @param subtitleID The subtitle ID.
     @param subtitle The string to be displayed as subtitle.
     */
    - (void)onSubtitleShow:(AliPlayer*)player trackIndex:(int)trackIndex subtitleID:(long)subtitleID subtitle:(NSString *)subtitle {
        // Display the subtitles.
    }
    /**
     @brief Callback for hiding subtitles.
     @param player The player pointer.
     @param trackIndex The index of the subtitle stream.
     @param subtitleID The subtitle ID.
     */
    - (void)onSubtitleHide:(AliPlayer*)player trackIndex:(int)trackIndex subtitleID:(long)subtitleID {
        // Hide the subtitles.
    }
    /**
     @brief Callback for taking a snapshot.
     @param player The player pointer.
     @param image The image.
     */
    - (void)onCaptureScreen:(AliPlayer *)player image:(UIImage *)image {
        // Preview and save the snapshot.
    }
    /**
     @brief Callback for when a track switch is complete.
     @param player The player pointer.
     @param info The information of the new track. See AVPTrackInfo.
     */
    - (void)onTrackChanged:(AliPlayer*)player info:(AVPTrackInfo*)info {
        // Notification for bitrate switching result.
    }
    //...
  3. Set the preload count.

    Setting a reasonable preload count can effectively improve startup speed.

    self.listPlayer.preloadCount = 2;
  4. Add or remove playback sources.

    List playback supports two source types: VidSts and UrlSource. A URL is the playback address of a video. A VID is the audio-video ID (VideoId) of a video-on-demand asset.

    • UrlSource: A playback URL from ApsaraVideo VOD or a third-party service.

      You can obtain a URL for a media asset in ApsaraVideo VOD by calling the GetPlayInfo operation. We recommend integrating the server-side SDK of ApsaraVideo VOD to retrieve playback URLs. This simplifies the process by handling URL signing automatically. For an example, see OpenAPI Explorer.

    • Vid: Audio/video ID. You can obtain this ID from the console (path: Media Asset Library > Audio/Video) or through a server-side API (Search for Media Information) after the upload is complete.

    // Add a VidSts source.
    [self.listPlayer addVidSource:videoId uid:UUIDString];
    // Add a UrlSource.
    [self.listPlayer addUrlSource:URL uid:UUIDString];
    // Remove a source.
    [self.listPlayer removeSource:UUIDString];
    Note
    • The UID is a unique identifier for a video. It distinguishes whether videos are identical. If UIDs match, the videos are considered identical. If videos play out of order, check whether the same UID is set for different videos. UIDs have no format restrictions and can be any string.

  5. Set the display view.

    If the source contains video content, set a view in the player to display it.

    self.listPlayer.playerView = self.simplePlayScrollView.playView;
  6. Play a video source.

    After you add one or more video sources, call moveTo to autoplay a video source. The following example shows how to do this:

    // Use this API for UrlSource playback.
    - (BOOL) moveTo:(NSString*)uid;
    // Use this API for VidSts playback. You must pass the temporary STS credential and temporary AccessKey pair. Get them in advance. For more information, see Create a RAM role and perform STS temporary authorization.
    - (BOOL) moveTo:(NSString*)uid accId:(NSString*)accId accKey:(NSString*)accKey token:(NSString*)token region:(NSString*)region;
  7. Play the previous or next video.

    After calling moveTo to play a video source, call moveToPrev or moveToNext to play the previous or next video, using the video source from moveTo as the anchor point. The following example shows how to:

    Note

    When you use the same view and call moveto or moveToNext to switch video sources, the screen may flicker or briefly turn black. To prevent this, set the clearShowWhenStop field of PlayerConfig to false when you initialize listPlayer and call setConfig to apply the change.

    UrlSource Playback Source

    //Move to the next video.
    - (BOOL) moveToNext;
    //Move to the previous video.
    - (BOOL) moveToPre;

    VidSts Playback Source

    // Play the next video.
    - (BOOL) moveToNext:(NSString*)accId accKey:(NSString*)accKey token:(NSString*)token region:(NSString*)region;
    // Play the previous video.
    - (BOOL) moveToPre:(NSString*)accId accKey:(NSString*)accKey token:(NSString*)token region:(NSString*)region;
Note

For an enhanced list playback experience, use our short-form drama solution. For more information, see Client-side development for short-form dramas.

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

MP4 videos with alpha channel support enhance gift effects by providing better animation quality, smaller file sizes, higher compatibility, and improved development efficiency. This allows gift effects to display more effectively to users, thereby improving the user experience.

  1. Better animation quality: MP4 videos preserve original animation details and colors more accurately than other formats.

  2. Smaller file size: Compared to other formats such as APNG or IXD, MP4 video files offer more effective compression, which improves loading speed and reduces network bandwidth consumption.

  3. Higher compatibility: The MP4 format is widely supported across devices and browsers.

  4. Using MP4 videos for gift effects is a simple technical solution that improves development efficiency. Developers do not need to create complex parsing and rendering logic, which allows them to focus on implementing other features.

Sample code

Use the alphaRenderMode property to set the position of the alpha channel in the video material (top, bottom, left, or right). The default value is None.

Note
  • The position of the alpha channel in the video asset must match the alphaRenderMode setting.

  • The size of the view must be proportional to the resolution of the material.

/**
 @brief Alpha rendering mode. Supports alpha at the right, left, top, or bottom. The default value is none.
 @see AVPAlphaRenderMode
 */
/****
 @brief Set a rendering mode. Support alpha at right, left, top and bottom. Default value is none.
 @see AVPAlphaRenderMode
 */
@property(nonatomic) AVPAlphaRenderMode alphaRenderMode;
//--------------View usage-------------
// For the player's view, set a clear background color.
@property (weak, nonatomic) IBOutlet UIView *mediaPlayerView;
[self.aliplayerview setBackgroundColor:UIColor.clearColor];

//-----------AliPlayer usage-----------
// Set the alpha mode.
[self.player setAlphaRenderMode:AVP_RENDERMODE_ALPHA_AT_LEFT];
// Set the material corresponding to the alpha mode.
AVPUrlSource *source = [[AVPUrlSource alloc] urlWithString:@"https://alivc-player.oss-cn-shanghai.aliyuncs.com/video/%E4%B8%9A%E5%8A%A1%E9%9C%80%E6%B1%82%E6%A0%B7%E6%9C%AC/alpha%E9%80%9A%E9%81%93/alpha_left.mp4"];
[self.player setUrlSource:source];

// Optional: Clear the screen after playback completion to prevent visual artifacts.
#pragma mark -- AVPDelegate
- (void)onPlayerEvent:(AliPlayer *)player eventType:(AVPEventType)eventType {
    switch (eventType) {
        case AVPEventCompletion:
        {
            [player clearScreen];
        }
            break;
        //...
    }
}

[self.player setAutoPlay: YES];
[self.player prepare];

Metal rendering

The ApsaraVideo Player SDK for iOS supports video rendering using the Metal framework.

Note

Currently supports only background color, scaling mode, and the Picture-in-Picture (PiP) feature.

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 Example

AVPConfig *config = [self.player getConfig];
// Enable Metal rendering.
config.videoRenderType = 1;
[self.player setConfig:config];
[self.player prepare];

External subtitles

Note

For a detailed code example, see the ExternalSubtitle module in the API-Example project. This project is an Objective-C-based iOS sample project for the ApsaraVideo Player SDK that helps developers quickly master core SDK integration.

The ApsaraVideo Player SDK for iOS supports adding and switching external subtitles in SRT, SSA, ASS, and VTT formats.

Examples:

  1. 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];
  2. 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];
    }
  3. Add a subtitle track.

    [self.player addExtSubtitle:URL];
  4. Switch a subtitle track.

    [self.player selectExtSubtitle:trackIndexenable:YES];

External subtitles (custom rendering using rendering components)

Full support for WebVTT external subtitles is implemented using AliVttSubtitleView and AliVttRenderImpl, enabling flexible customization of font size, color, and specific fonts.

Note

Use cases:

  • Customize WebVTT subtitle styles, including font, color, and size.

  • Integrate ApsaraVideo Player SDK V7.11.0 and use AliVttSubtitleView.

  • Support multilingual subtitles (such as Arabic, Chinese, Japanese, and Korean) and auto-match corresponding fonts.

Important

Prerequisites:

  • Font files (.ttf) are added to the Xcode project.

  • Subtitle listeners are added and WebVTT content can be retrieved.

  • The loadFontFromBundle method is called and fonts load successfully.

Steps to customize subtitle styles

  1. 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
  2. (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);
        }
    }
  3. 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 fonts.
        [impl loadCustomFontFromBundle:@"LongCang-Regular"];
        
        return impl;
    }];
    
    // Associate with player.
    [player setExternalSubtitleView:subtitleView];
  4. 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

You can 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 the enableHardwareDecoder toggle. By default, hardware decoding is enabled. If hardware decoding fails to initialize, software decoding is automatically used to ensure normal playback. The following example shows how to enable hardware decoding:

// Enable hardware decoding. It is enabled by default.
self.player.enableHardwareDecoder = YES;

If automatic failover occurs from hardware decoding to software decoding, the onPlayerEvent callback is triggered. The following example shows how to handle this event:

-(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 on 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.

Note
  • This feature is available only after you enable the cloud-native adaptive decoding 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

Note

The ApsaraVideo Player SDK for iOS supports adaptive bitrate streaming of HTTP Live Streaming (HLS) video streams and Dynamic Adaptive Streaming over HTTP (DASH) video streams. After prepare completes successfully, you can retrieve information about each bitrate stream by calling getMediaInfo, which returns TrackInfo. The following sample code shows how to query media information:

AVPMediaInfo *info = [self.player getMediaInfo];
NSArray<AVPTrackInfo*>* tracks = info.tracks;

During playback, you can call the player's selectTrack method to switch the bitrate stream. When the value is set to SELECT_AVPTRACK_TYPE_VIDEO_AUTO, adaptive bitrate streaming is enabled. For example:

// Switch to a specific bitrate.
[self.player selectTrack:track.trackIndex];
// Enable adaptive bitrate switching.
[self.player selectTrack:SELECT_AVPTRACK_TYPE_VIDEO_AUTO];

The switch triggers the onTrackChanged callback. The following example shows how to handle track changes.

- (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 enable adaptive bitrate streaming, you can set an upper limit for the definition of adaptive bitrate (ABR) switching through config to prevent automatic switching to an unintended bitrate. The following example shows how to do this: (We recommend calling this code before the player calls the prepare method or the playlist 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 capture feature for the current video playback, which is implemented by the snapShot interface. The captured raw data is converted to a bitmap and returned. The callback interface is onCaptureScreen. The following sample code shows how to capture a snapshot of the current video playback.

// Snapshot callback.
- (void)onCaptureScreen:(AliPlayer *)player image:(UIImage *)image {
    // Process the snapshot.
}
// Take a snapshot of the current frame.
[self.player snapShot];
Note

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 for video-on-demand) playback. For configuration instructions, see Preview videos.

After you configure the video preview feature, use the VidPlayerConfigGen interface's setPreviewTime method to set the player's preview duration. For example, if you use VidSts-based playback, the following sample code demonstrates this:

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.

Note

VidPlayerConfigGen supports setting various server-side request parameters. See Request parameter descriptions.

Set the Referer

The iOS player SDK supports setting the Referer. You can control access permissions using the Referer blacklists and whitelists in the console and setting the request Referer through the AVPConfig method. The following sample code provides an example:

// 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 header. After you specify the User-Agent header, the player includes the user agent information in its requests. The following sample code shows how to...

// 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 sample code provides 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];
Note
  • 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 onError event is triggered, and AVPErrorModel.code is set to ERROR_LOADING_TIMEOUT.

  • If networkRetryCount is set to 0, a network retry timeout triggers the onPlayerEvent callback, and the eventWithString parameter is set to EVENT_PLAYER_NETWORK_RETRY. You can then call the player's reload method to reload the stream or perform other actions.

Configure cache and latency control

Buffer control is important for a player. You can decrease the startup loading duration and improve playback smoothness using proper configurations. The iOS Player SDK provides the AVPConfig interface to configure buffer and latency. The following example shows how to configure buffer and latency settings:

// 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];
Important
  • 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. The following sample code shows how to:

// 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

Note

For detailed code examples, see the PictureInPicture module in the API-Example project. This project is an Objective-C-based iOS sample project for the ApsaraVideo Player SDK that helps developers quickly master core SDK integration.

Note
  • PiP requires iOS 15 or later and ApsaraVideo Player SDK for iOS 5.4.9.0 or later.

  • For versions of 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 the picture-in-picture (PiP) feature is enabled, the video is played in a floating window when the application is switched to the background. When the application is switched to the foreground, the video is played in the application window. The PiP feature is controlled by the setPictureInPictureEnable setting. To enable the PiP feature, you must configure it in the AVPEventPrepareDone state. The following sample code provides an example:

- (void)onPlayerEvent:(AliPlayer *)player eventType:(AVPEventType)eventType {
    switch (eventType) {
        case AVPEventPrepareDone:
        {
            [self.player setPictureInPictureEnable:YES];
        }
            break;
        default:
            break;
    }
}
Note

When the player calls stop to stop playback, the Picture-in-Picture window is no longer needed, so you must first disable Picture-in-Picture by calling setPictureInPictureEnable before calling stop.

Set the PiP delegate

The following code examples demonstrate common interactive operations between Picture-in-Picture (PiP) windows and player windows, such as displaying the Pause, Play, Fast Forward, Fast Backward, and Replay buttons in PiP mode. For details about the corresponding delegate methods, see the Player SDK Demo, specifically the AliPlayerPictureInPictureDelegate.h header file in the AliyunPlayer.framework folder.

  1. Set the PiP delegate.

    /**
    * @brief Set the PiP delegate.
    */
    -(void) setPictureinPictureDelegate:(id<AliPlayerPictureInPictureDelegate>)delegate;
    
    
    // Set the PiP delegate.
    [self.player setPictureinPictureDelegate:self];
  2. Add variables and implement the delegate interface.

    1. You can add a global variable to control the player's state changes.

      #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;
      
      @end
      Note

      You 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.

    2. 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];
         }
      }
    3. Update the status of the PiP controller when you listen for the onPlayerEvent event.

      - (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];
          }
        }
      }
    4. 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);
            }
        }
      • This callback monitors the Picture-in-Picture (PiP) playback state (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;
        }
        Note

        This 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

Note

For a detailed code example, see the RtsLiveStream module in the API-Example project. This project is an Objective-C-based iOS sample project for the ApsaraVideo Player SDK that helps developers quickly master core SDK integration.

For more information, see RTS live playback.

Switch between left and right audio channels

The iOS Player SDK uses the outputAudioChannel property to set the output audio channel. If the input source is stereo, you can switch to the left or right channel. If the input source is mono, this setting has no effect.

Note

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

Set the background color of the player's rendering view.

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 the vid. For a list of supported parameters, see GetPlayInfo. The following content describes how to specify a domain name for vidAuth-based playback and provides sample code:

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

  1. Use Player or all-in-one SDK V7.6.0 or later.

  2. The Professional Edition license has been authorized. For more information, see Obtain the Player SDK License.

  3. ApsaraVideo Player with the H.266 decoding plug-in supports only H.266 videos encoded by ApsaraVideo Transcoding.

Integrate the plugin

Player SDK

CocoaPods Integration (Recommended)

Add the dependency to your Podfile.

Note

For the latest version of the iOS SDK, see Release notes.

// x.x.x must be the same as the version number of ApsaraVideo Player SDK.
pod 'AliPlayerSDK_iOS_VVC_CODEC_PLUGIN', 'x.x.x'

Local integration

Download the latest version of the iOS Player SDK. Add vvcCodecPlugin.framwork to Frameworks, Libraries, and Embedded Content, set Embed to Embed & Sign, and configure the Framework Search Paths. For more information, see Local integration.

All-in-one SDK

CocoaPods (recommended)

Add the dependency to your Podfile.

// x.x.x must be the same as the version number of the integrated SDK you are using.
pod 'AliVCSDK_Standard/AliPlayerSDK_iOS_VVC_CODEC', 'x.x.x'

Local integration

Download the latest version of the iOS all-in-one package. Extract the package and add plugins/vvcCodecPlugin.framework to Frameworks, Libraries, and Embedded Content, set Embed to Embed & Sign, and configure the Framework Search Paths. For more information, see Local integration.

Activate the plugin

Note

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 smooth, uninterrupted playback.

Prerequisites

  1. Use Player or all-in-one SDK V7.9.0 or later.

  2. Use VidAuth sources for playback or configure URL signing in your business.

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 playback.

 @param callback The callback block triggered when the VidAuth source expires.
 You can return a valid `VidAuth` object via this callback 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

Function composition

/**
 @protocol AVPSourceRefreshCallback
 @brief A protocol for handling playback source refresh results, which developers need to implement.

 This protocol notifies developers when the player requests playback source refresh, such as when a resource
 has expired or needs updating. The methods in this protocol are called to provide the refresh results to the developer,
 including success or failure.

 @note This protocol applies to URL source, VidAuth source, and similar scenarios requiring refresh logic.
 */
 /****
 @brief A protocol for handling playback source refresh results, which developers need to implement.

 This protocol notifies developers when the player requests playback source refresh, such as when a resource
 has expired or needs updating. The methods in this protocol are called to provide the refresh results to the developer,
 including success or failure.

 @note This protocol applies to URL source, VidAuth source, and similar scenarios requiring refresh logic.
 */
@protocol AVPSourceRefreshCallback <NSObject>

/**
 @brief Called by the player when the refresh operation succeeds.
 @param newSource The new playback source object containing the updated information.

 This method indicates that the refresh operation has been successfully completed. Developers need to pass
 the updated `newSource` back to the player so that it can load the latest resource.
 */
 /****
 @brief Called by the player when the refresh operation succeeds.
 
 @param newSource The new playback source object containing the updated information.

 This method indicates that the refresh operation has been successfully completed. Developers need to pass
 the updated `newSource` back to the player so that it can load the latest resource.
 */
- (void)onSuccess:(id)newSource;

/**
 @brief Called by the player when the refresh operation fails.
 @param errorMsg A string describing the reason for the failure.

 This method indicates that the refresh operation has failed. Developers can use `errorMsg` to capture failure
 details and handle subsequent processing accordingly.
 */
 /****
 @brief Called by the player when the refresh operation fails.
 
 @param errorMsg A string describing the reason for the failure.

 This method indicates that the refresh operation has failed. Developers can use `errorMsg` to capture failure
 details and handle subsequent processing accordingly.
 */
- (void)onError:(NSString *)errorMsg;

@end

Usage

You can obtain audio-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 begins -------------------
        // 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 call `callback` to return the new URL source, ensuring uninterrupted 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 return a valid `URLSource` object via this callback 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

Function composition

/**
 @protocol AVPSourceRefreshCallback
 @brief A protocol for handling playback source refresh results, which developers need to implement.

 This protocol notifies developers when the player requests playback source refresh, such as when a resource
 has expired or needs updating. The methods in this protocol are called to provide the refresh results to the developer,
 including success or failure.

 @note This protocol applies to URL source, VidAuth source, and similar scenarios requiring refresh logic.
 */
 /****
 @brief A protocol for handling playback source refresh results, which developers need to implement.

 This protocol notifies developers when the player requests playback source refresh, such as when a resource
 has expired or needs updating. The methods in this protocol are called to provide the refresh results to the developer,
 including success or failure.

 @note This protocol applies to URL source, VidAuth source, and similar scenarios requiring refresh logic.
 */
@protocol AVPSourceRefreshCallback <NSObject>

/**
 @brief Called by the player when the refresh operation succeeds.
 @param newSource The new playback source object containing the updated information.

 This method indicates that the refresh operation has been successfully completed. Developers need to pass
 the updated `newSource` back to the player so that it can load the latest resource.
 */
 /****
 @brief Called by the player when the refresh operation succeeds.
 
 @param newSource The new playback source object containing the updated information.

 This method indicates that the refresh operation has been successfully completed. Developers need to pass
 the updated `newSource` back to the player so that it can load the latest resource.
 */
- (void)onSuccess:(id)newSource;

/**
 @brief Called by the player when the refresh operation fails.
 @param errorMsg A string describing the reason for the failure.

 This method indicates that the refresh operation has failed. Developers can use `errorMsg` to capture failure
 details and handle subsequent processing accordingly.
 */
 /****
 @brief Called by the player when the refresh operation fails.
 
 @param errorMsg A string describing the reason for the failure.

 This method indicates that the refresh operation has failed. Developers can use `errorMsg` to capture failure
 details and handle subsequent processing accordingly.
 */
- (void)onError:(NSString *)errorMsg;

@end

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, treat 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 it
        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 it. 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. Handle callback
        if (newAuthUrl) {
            [callback onSuccess:resultSource];
        } else {
            [callback onError:@"REFRESH_ERROR:refresh fail"];
        }
    }
}];

Utility functions

Example using Signing method A.

Utility functions

#import "CdnAuthUtil.h"
#import <CommonCrypto/CommonDigest.h>

@implementation CdnAuthUtil

#pragma mark - Auth Method A
+ (NSString *)aAuthWithUri:(NSString *)uri key:(NSString *)key exp:(NSTimeInterval)exp {
    NSDictionary *components = [self matchUri:uri];
    if (!components) return nil;

    NSString *scheme = components[@"scheme"];
    NSString *host = components[@"host"];
    NSString *path = components[@"path"];
    NSString *args = components[@"args"];

    NSString *rand = @"0";
    NSString *uid = @"0";

    NSString *sstring = [NSString stringWithFormat:@"%@-%lld-%@-%@-%@", path, (long long)exp, rand, uid, key];
    NSString *hashvalue = [self md5sum:sstring];
    NSString *authKey = [NSString stringWithFormat:@"%lld-%@-%@-%@", (long long)exp, rand, uid, hashvalue];

    if (args.length > 0) {
        return [NSString stringWithFormat:@"%@%@%@%@&auth_key=%@", scheme, host, path, args, authKey];
    } else {
        return [NSString stringWithFormat:@"%@%@%@%@?auth_key=%@", scheme, host, path, args, authKey];
    }
}

#pragma mark - Private Helper: MD5
+ (NSString *)md5sum:(NSString *)src {
    const char *cStr = [src UTF8String];
    unsigned char result[CC_MD5_DIGEST_LENGTH];
    CC_MD5(cStr, (unsigned int)strlen(cStr), result);

    NSMutableString *hexString = [NSMutableString string];
    for (int i = 0; i < CC_MD5_DIGEST_LENGTH; i++) {
        [hexString appendFormat:@"%02x", result[i]];
    }
    return hexString.copy;
}

#pragma mark - Private Helper: Regex Match
+ (NSDictionary *)matchUri:(NSString *)uri {
    NSError *error = nil;
    NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"^(https?://)?([^/?]+)(/[^?]*)?(\\?.*)?$"
                                  options:0
                                  error:&error];
    if (error) {
        NSLog(@"Regex error: %@", error.localizedDescription);
        return nil;
    }

    NSTextCheckingResult *match = [regex firstMatchInString:uri
                                   options:0
                                   range:NSMakeRange(0, uri.length)];
    if (!match) return nil;

    __block NSString *scheme = nil, *host = nil, *path = nil, *args = nil;

    void (^setStringFromRange)(NSInteger, NSString**) = ^(NSInteger idx, NSString **outStr) {
        NSRange range = [match rangeAtIndex:idx];
        if (range.location != NSNotFound && range.length > 0) {
            *outStr = [uri substringWithRange:range];
        } else {
            *outStr = nil;
        }
    };

    setStringFromRange(1, &scheme);
    setStringFromRange(2, &host);
    setStringFromRange(3, &path);
    setStringFromRange(4, &args);

    // Default value handling
    if (!scheme) scheme = @"http://";
    if (!path) path = @"/";

    return @{
        @"scheme": scheme,
        @"host": host,
        @"path": path,
        @"args": args ?: @""
        };
}
@end

Performance

Set the playback scene

Setting the playback scene automatically configures optimal parameters (including buffer settings and feature toggles) for that scene. Custom parameters set via the setConfig interface remain effective (custom settings take precedence).

Note
  • After setting the playback scene, use the getConfig interface to view the configuration.

API example

/**
 @brief Set player scene.
 @param scene Player scene.
 @see AVPScene
 */
/****
 @brief Set player scene.
 @param scene Player scene.
 @see AVPScene
 */
-(void) setPlayerScene:(AVPScene)scene;

Playback scenes

typedef enum _AVPScene {
    /**
     * Scene: None
     */
    /****
     * scene none
     */
    SceneNone,
    /**
     * Long video scene: Applies to videos longer than 30 minutes
     */
    /****
     * long scene: apply to more than 30min
     */
    SceneLong,
    /**
     * Medium video scene: Applies to videos 5–30 minutes long
     */
    /****
     * middle scene: apply to 5min-30min
     */
    SceneMedium,
    /**
     * Short video scene: Applies to videos up to 5 minutes long
     */
    /****
     * short scene: apply to 0s-5min
     */
    SceneShort,
    /**
     * Live streaming scene
     */
    /****
     * live scene
     */
    SceneLive,
    /**
     * Ultra-low-latency live streaming scene
     */
    /****
     * RTS live scene
     */
    SceneRTSLive
} AVPScene;

Usage

// Set short video scene.
[self.player setPlayerScene:SceneShort];

// Set medium video scene.
[self.player setPlayerScene:SceneMedium]; 

// Set long video scene.
[self.player setPlayerScene:SceneLong];  

// Set live streaming scene.
[self.player setPlayerScene:SceneLive];   

Pre-rendering

iOS Player SDK supports quick first-frame rendering before playback starts, improving startup speed.

Note
  1. This feature is disabled by default.

  2. When enabled, it changes the trigger order of the ready and first-frame-rendered events: Without it, ready fires first, then first-frame-rendered. With it, first-frame-rendered may fire before ready, depending on decode/render speed. This does not affect playback.

Example:

[self.player setOption:ALLOW_PRE_RENDER valueInt:1];

Local cache

Note

For detailed code examples, see the PreloadUrl module in the API-Example project. This project is an Objective-C-based iOS sample project for the ApsaraVideo Player SDK that helps developers quickly master core SDK integration.

iOS Player SDK provides local caching to improve startup speed, seek speed, and reduce stuttering for repeated video playback. It also saves bandwidth.

Enable local cache

By default, the local caching feature is disabled. To use this feature, you must manually enable it. You can control it using AliPlayerGlobalSettings and the enableLocalCache parameter. Example:

/**
 * Enable local cache. After enabling, it caches to local files.
 * @param enable: Local cache toggle. true: enable, false: disable. Default is disable.
 * @param maxBufferMemoryKB: Deprecated since V5.4.7.1. No effect.
 * @param localCacheDir: Required. 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];
Note
  • If video URLs contain authentication parameters that change during caching/playback, improve cache hit rate by removing auth parameters before calculating hash via setCacheUrlHashCallback (e.g., MD5). Example: For URL http://****.mp4?aaa, calculate hash using http://****.mp4. However, for encrypted m3u8 videos, removing auth parameters from keyURLs causes different videos to share the same key, leading to playback failure. Solution: In setCacheUrlHashCallback, only remove auth parameters from playback domains (http(s)://xxxxx.m3u8?aaaa) but not keyURL domains (http(s)://yyyyy?bbbb).进阶功能-本地缓存.png

  • If the server supports both HTTP and HTTPS protocols, but the media files pointed to by different protocols are the same, you can remove or unify the request headers before you calculate the MD5 value. For example:

    • If the video playback URLs are https://****.mp4 and http://****.mp4, use ****.mp4 to calculate the MD5 value.

    • If the video playback URL is https://****.mp4, unify it to http://****.mp4 before you calculate the MD5 value.

  • For Player SDK version 5.5.4.0 and later, if the video playback URL contains authentication parameters and the playback protocol is HLS, you can select different authentication modes by setting the AVPConfig.enableStrictAuthMode field (the default value is false in versions earlier than 7.13.0; the default value is true in version 7.13.0 and later):

    • Non-strict authentication (false): Authentication is cached. If only part of the media was cached last time, the player uses the cached authentication to make a request when playing the non-cached part next time. If the URL authentication validity period is very short, or playback resumes long after pausing, authentication may expire. To resolve this, integrate the auto-refresh playback sources feature.

    • Strict authentication (true): Authentication is not cached. Authentication is performed every time playback starts. This causes startup failure without a network.

Enable or disable local cache for a single URL

You can disable the local caching feature for a single URL by configuring a setting in the player config. The following example shows how to do this:

// Get the configuration first.
AVPConfig *config = [self.player getConfig];
// Whether to enable local cache for the playback URL. The default value is true. When the local cache in AliPlayerGlobalSettings is enabled, and the local cache here is also enabled (set to true), the local cache for this URL will take effect. If it is set to false here, the 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 it as follows using AliPlayerGlobalSettings.

[AliPlayerGlobalSettings enableLocalCache:true];

Preloading

iOS Player SDK provides preloading, an upgrade to local caching that downloads part of a video into the cache before playback begins, further improving startup speed.

The limits of the preloading feature are as follows:

  • Preloading supports single media files such as MP4, MP3, FLV, and HLS.

Note

iOS Player SDK schedules preload network requests by default to reduce interference 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];
  1. Enable the local cache feature as described in Local cache.

  2. You can 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];
  3. Set task parameters.

    Note

    This applies only to multi-bitrate videos. You can choose any one of setDefaultBandWidth, setDefaultResolution, or setDefaultQuality.

    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];
  4. Add a task listener.

    Expand to view the code

    @interface YourViewController () <OnPreloadListener>
    
    @property(nonatomic,strong) AliMediaLoaderV2* vodMedialoader; // Preloader
    @property(nonatomic,strong) AVPVidAuthSource* vidSource; // vidAuth data source
    @property(nonatomic,strong) AVPUrlSource* urlSource; // url data source
    @property(nonatomic,strong) AVPVidStsSource* vidStsSource; // vidSts data source
    
    @end
    
    @implementation YourViewController
    
    - (void)onCompleted:(NSString *)taskId urlOrVid:(NSString *)urlOrVid {
        NSLog(@"Current task (%@) completed:%@", taskId,urlOrVid);
    }
    
    - (void)onError:(NSString *)taskId urlOrVid:(NSString *)urlOrVid errorModel:(AVPErrorModel *)errorModel {
        NSLog(@"An exception occurred:%@", urlOrVid);
    }
    
    - (void)onCanceled:(NSString *)taskId urlOrVid:(NSString *)urlOrVid {
        NSLog(@"Task canceled:%@", urlOrVid);
    }
    
    @end
  5. Build the task, add it to the MediaLoaderV2 instance, 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];
  6. 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.
  7. 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.

Expand to view the code

// Enable recommended configuration and dynamic preloading
[self.listPlayer setScene:AVP_SHORT_VIDEO];

// Configure baseline preload duration
// Set preload duration to 1000ms
AVPPreloadConfig *config = [[AVPPreloadConfig alloc] init];
config.preloadDuration = 1000;
[self.listPlayer updatePreloadConfig:config];

// Configure preload count, supports bidirectional
// 1 for previous preload count, 3 for next preload count
[self.listPlayer setPreloadCount:1 nextCount:3];

// Configure the decrementing offset for dynamic preloading
[self.listPlayer enableStrategy:AVP_STRATEGY_DYNAMIC_PRELOAD enable:true];
[self.listPlayer setStrategyParam:AVP_STRATEGY_DYNAMIC_PRELOAD strategyParam:@"{\"algorithm\": \"sub\",\"offset\": \"200\"}"];

Preload multi-bitrate HLS videos

In listPlayer multi-bitrate HLS video playback scenarios, you can preload a stream that matches the current playback definition and choose a preload mode as needed.

Expand to view supported preloading modes

typedef enum AVPMultiBitratesMode : NSUInteger {
    /**
     * Default configuration. Play and preload the default bitrate.
     */
    /****
     * default mode, play and preload default bitrate of a stream
     */
    AVPMultiBitratesMode_Default = 0,
    /**
     * First frame priority configuration. The video starts playing at the bitrate that has finished preloading.
     */
    /****
     * First frame cost (FC) priority, decrease first frame cost. only play bitrate of the hls stream which has been preloaded.
     */
    AVPMultiBitratesMode_FCPrio = 1,
    /**
     * Balances first frame and smooth playback. The video bitrate is consistent before and after switching (moveToNext), and first frame performance is also considered.
     */
    /****
     * First frame and play smooth, play the same bitrate before and after moveToNext
     */
    AVPMultiBitratesMode_FC_AND_SMOOTH = 2,
    /**
     * Smooth playback priority configuration. The video starts playing at the bitrate of the previous video.
     */
    /****
     * Play Smooth priority, play the same bitrate before and after moveToNext.
     */
    AVPMultiBitratesMode_SmoothPrio = 3,
} AVPMultiBitratesMode;

Expand to view the integration code

// Select multi-bitrate loading mode.
[self.listPlayer->SetMultiBitratesMode(preLoadMode)];

// (Optional) Select startup bitrate.
[self.listPlayer setDefaultBandWidth:defaultBandWidth];

// (Optional) In the preparedone callback, select ABR mode.
-(void)onPlayerEvent:(AliPlayer*)player eventType:(AVPEventType)eventType {
    switch (eventType) {
        case AVPEventPrepareDone: {
            [self.listPlayer selectTrack:-1];
        }
            break;
        case AVPEventFirstRenderedStart: {
        }
            break;
        default:
            break;
    }
}

Get the download speed

Get 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

HTTPDNS sends domain resolution requests to specific HTTPDNS servers via DNS resolution technology for faster, more stable results and reduced DNS hijacking risk.

The ApsaraVideo Player SDK provides enhanced HTTPDNS exclusively for Alibaba Cloud CDN domains, supporting precise CDN scheduling and real-time resolution for improved network performance.

Enhanced HTTPDNS usage example

Enhanced HTTPDNS only works for Alibaba Cloud CDN domains. Ensure your domain is a configured Alibaba Cloud CDN domain. For adding/configuring CDN domains in VOD, see Add accelerated domain. For more CDN domain info, see Alibaba Cloud CDN.

// Enable enhanced HTTPDNS.
[AliPlayerGlobalSettings enableEnhancedHttpDns:YES];
// Optional. Add a domain name for HTTPDNS pre-resolution.
[[AliDomainProcessor shareInstance] addPreResolveDomain:@"player.***alicdn.com"];

HTTP/2

Note

iOS Player SDK enables HTTP/2 by default starting from V5.5.0.0.

iOS Player SDK supports HTTP/2, which uses multiplexing to avoid head-of-line blocking and improve playback performance.

[AliPlayerGlobalSettings setUseHttp2:true];

Pre-establishing TCP connections for HTTP

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 domain names 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

Note

For detailed code examples, see the Download module in the API-Example project. This project is an Objective-C-based iOS sample project for the ApsaraVideo Player SDK that helps developers quickly master core SDK integration.

iOS Player SDK 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

  • Only the VidSts and VidAuth methods enable the video download feature.

  • Enable and configure the download mode in the ApsaraVideo VOD console. For more information, see Offline Download.

  • The SDK supports resumable downloads.

Procedure

  1. Optional: Configure the encryption verification file for secure download. Only required for secure download. Not required for standard download.

    Note

    Ensure the encryption verification file matches the 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.

    We recommend configuring the key file once in the Application.

    NSString *encrptyFilePath = [[NSBundle mainBundle] pathForResource:@"encryptedApp" ofType:@"dat"];
    [AliPrivateService initKey:encrptyFilePath];
  2. Create and set up the downloader.

    Example:

    AliMediaDownloader *downloader = [[AliMediaDownloader alloc] init];
    [downloader setSaveDirectory:self.downLoadPath];
    [downloader setDelegate:self];
  3. Set event listeners.

    The downloader 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.
    }
  4. Prepare the download source.

    Call the prepare method to prepare a download source. This method supports VidStsSource and VidAuthSource.

    • 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];
    Note

    If 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.

  5. Select a download item after preparation succeeds.

    After the download source is prepared, the onPrepared method is called. The TrackInfo parameter provides information about video streams, such as their definitions. You can select a track to download. The following sample code provides 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];
    }
  6. 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];
  7. Release the downloader after download success or failure.

    After the download succeeds, call destroy to release the downloader.

    [self.downloader destroy];
    self.downloader = nil;

Encrypted playback

ApsaraVideo VOD supports HLS standard encryption, Alibaba Cloud proprietary encryption, and DRM encryption. Live streaming supports only 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 stream pulling on iOS.

References