All Products
Search
Document Center

ApsaraVideo VOD:Basic features

Last Updated:Nov 20, 2025

This topic describes how to create an iOS player instance and provides examples of how to use basic playback features, such as setting the volume, enabling video seeking, listening for playback states, enabling loop playback, setting the playback speed, and switching audio tracks.

Important

To run the demo, download it, and then compile and run it. For more information, see Run the demo.

Set the playback source (DataSource)

  • The ApsaraVideo Player SDK for iOS supports four playback methods for video-on-demand (VOD): VidAuth (recommended for ApsaraVideo VOD users), VidSts, UrlSource, and encrypted playback.

  • The ApsaraVideo Player SDK for iOS supports two playback methods for live streaming: UrlSource and encrypted playback.

VOD playback

VOD playback using VidAuth (Recommended)

To play a VOD video using VidAuth, set the vid property of the player to the video ID and the playauth property to the playback credential.

  • Video ID: You can obtain the video ID from the ApsaraVideo VOD console (Media Library > Audio/Video) or by calling the SearchMedia API operation after the video is uploaded.

  • Playback credential: You can obtain the playback credential by calling the GetVideoPlayAuth API operation. We recommend that you integrate the ApsaraVideo VOD server-side SDK to obtain playback credentials. This eliminates the need to sign requests. For an example of how to call this API operation, see API Explorer.

We recommend that ApsaraVideo VOD users use this playback method. Compared to the STS method, the PlayAuth method is more secure and easier to use. For a detailed comparison, see Comparison between the credential-based method and the STS-based method.

If you enable HLS encryption parameter pass-through in the ApsaraVideo VOD console, the default parameter name is MtsHlsUriToken. For more information, see HLS encryption parameter pass-through. In this case, set the MtsHlsUriToken value in the VOD source as shown in the following code.

AVPVidAuthSource *authSource = [[AVPVidAuthSource alloc] init];
authSource.vid = @"Vid information"; // Required. The video ID (VideoId).
authSource.playAuth = @"<yourPlayAuth>"; // Required. The playback credential. You must call the GetVideoPlayAuth operation of ApsaraVideo VOD to generate the credential.
authSource.region = @"The region where ApsaraVideo VOD is activated"; // For ApsaraVideo Player SDK V5.5.5.0 and later, this parameter is deprecated. You do not need to set the region because the player automatically parses it. For versions earlier than V5.5.5.0, this parameter is required. The region where ApsaraVideo VOD is activated. Default value: cn-shanghai.
// authSource.authTimeout = 3600; // The validity period of the playback URL in seconds. This value overwrites the validity period of URL signing that you set in the ApsaraVideo VOD console. If you do not specify this parameter, the default value 3600 is used. If you set this parameter, make sure that the validity period is longer than the video duration to prevent the playback URL from expiring before the playback is complete.

// If you enable HLS encryption parameter pass-through in the ApsaraVideo VOD console and the default parameter name is MtsHlsUriToken, you must set the config and pass it to the vid. See the following code.
// If you do not enable HLS encryption parameter pass-through in the ApsaraVideo VOD console, you do not need to integrate the following code.
VidPlayerConfigGenerator* vp = [[VidPlayerConfigGenerator alloc] init];
[vp setHlsUriToken:yourMtsHlsUriToken];
authSource.playConfig = [vp generatePlayerConfig];

[self.player setAuthSource:authSource];

VOD playback using VidSts

To play a VOD video using VidSts, you must use a temporary Security Token Service (STS) credential instead of an ApsaraVideo VOD playback credential. You must obtain an STS token and a temporary AccessKey pair (AccessKeyId and AccessKeySecret) in advance. For more information, see Obtain an STS token.

If you enable HLS encryption parameter pass-through in the ApsaraVideo VOD console, the default parameter name is MtsHlsUriToken. For more information, see HLS encryption parameter pass-through. In this case, set the MtsHlsUriToken value in the VOD source as shown in the following code.

AVPVidStsSource *source = [[AVPVidStsSource alloc] init];
source.vid = @"Vid information"; // Required. The video ID (VideoId).
source.region = @"The region where ApsaraVideo VOD is activated"; // Required. The region where ApsaraVideo VOD is activated. Default value: cn-shanghai.
source.securityToken = @"<yourSecurityToken>"; // Required. The STS token. You must call the AssumeRole operation of STS to generate the token.
source.accessKeySecret = @"<yourAccessKeySecret>"; // Required. The AccessKey secret of the temporary AccessKey pair. You must call the AssumeRole operation of STS to generate the secret.
source.accessKeyId = @"<yourAccessKeyId>"; // Required. The AccessKey ID of the temporary AccessKey pair. You must call the AssumeRole operation of STS to generate the ID.
// source.authTimeout = 3600; // The validity period of the playback URL in seconds. This value overwrites the validity period of URL signing that you set in the ApsaraVideo VOD console. If you do not specify this parameter, the default value 3600 is used. If you set this parameter, make sure that the validity period is longer than the video duration to prevent the playback URL from expiring before the playback is complete.
// If you enable HLS encryption parameter pass-through in the ApsaraVideo VOD console and the default parameter name is MtsHlsUriToken, you must set the config and pass it to the vid. See the following code.
// If you do not enable HLS encryption parameter pass-through in the ApsaraVideo VOD console, you do not need to integrate the following code.
VidPlayerConfigGenerator* vp = [[VidPlayerConfigGenerator alloc] init];
[vp setHlsUriToken:yourMtsHlsUriToken];
source.playConfig = [vp generatePlayerConfig];
// Set the playback source.
[self.player setStsSource:source]

VOD playback using UrlSource

To play a VOD video using UrlSource, set the source property of the player to the playback URL.

  • Playback URL in ApsaraVideo VOD: You can call the GetPlayInfo API operation to obtain the URL. We recommend that you integrate the ApsaraVideo VOD server-side SDK to obtain playback URLs. This eliminates the need to sign requests. For an example of how to call this API operation, see API Explorer.

  • Local video URL: Ensure that you have the required access permissions. You can call a system API to retrieve the full path of an accessible local video file, such as /sdcard/xxx/xxx/xxx.mp4 or content://xxx/xxx/xx.mp4.

AVPUrlSource *urlSource = [[AVPUrlSource alloc] urlWithString:url]; // Required. The playback URL. The URL can be a third-party VOD URL, a playback URL in ApsaraVideo VOD, or a local video URL.
[self.player setUrlSource:urlSource]; 

Encrypted VOD playback

VOD supports HLS encryption, Alibaba Cloud proprietary cryptography, and DRM encryption. For more information about encrypted playback, see Play encrypted videos on iOS.

Live stream playback

For more information, see Standard live stream playback.

Note
  • UrlSource uses a URL for playback. VidSts and VidAuth use a video ID (VID) for playback.

  • For information about how to set the region, see VOD regions.

Control playback

The ApsaraVideo Player SDK for iOS supports common operations such as starting, pausing, and seeking.

Prepare for playback

Call the prepare interface to prepare for video playback. The following code provides an example:

[self.player prepare];

Start playback

Call the start interface to start video playback. The following code provides an example:

[self.player start];

Start playback from a specific time

Call the seekToTime interface to start playback from a specific time. This is suitable for scenarios where a user drags the progress bar or resumes playback from a specific time. The following code provides an example:

// The position parameter specifies the time. Unit: milliseconds. The seekMode parameter can be set to accurate or inaccurate mode.
// Accurate seek
[self.player seekToTime:position seekMode:AVP_SEEKMODE_ACCURATE];
// Inaccurate seek
[self.player seekToTime:position seekMode:AVP_SEEKMODE_INACCURATE];

Start playback from a specific position. This is suitable for scenarios where a user starts playback from a specific time. For this to take effect, call this interface once before each prepare call. The following code provides an example:

// Set the start time in milliseconds for the next prepare call of the player. This setting is valid only for the immediately following prepare call.
// After prepare is called, this value is automatically cleared. If this method is not called again before the next prepare call, playback starts in the normal way.
// The seekMode can be set to accurate or inaccurate mode.
[self.player setStartTime:time seekMode:seekMode];

Pause playback

Call the pause interface to pause video playback. The following code provides an example:

[self.player pause];

Resume playback

Call the start interface to resume video playback. The following code provides an example:

[self.player start];

Stop playback

Call the stop interface to stop video playback. The following code provides an example:

[self.player stop];

Destroy the player

You can destroy a player instance synchronously or asynchronously. The following code provides an example:

// Synchronous destruction. The stop interface is automatically called internally.
[self.player destroy];
// Asynchronous destruction. The stop interface is automatically called internally.
[self.player destroyAsync];
Note

The synchronous destruction interface returns a response only after all player resources are released. If high interface response speed is required, we recommend that you use the asynchronous destruction interface. Note the following points:

  1. Do not perform any other operations on the player object during asynchronous destruction.

  2. You do not need to manually stop the player before calling the asynchronous destruction interface because the destruction process includes an asynchronous stop procedure.

Listen for player states

The ApsaraVideo Player SDK for iOS lets you set a player listener and listen for playback states.

Set a player listener

The player supports multiple listeners.

  • The onPlayerEvent and onError callbacks are important. We recommend that you set them.

@interface SimplePlayerViewController ()<AVPDelegate>
@end
- (void)viewDidLoad {
    self.player = [[AliPlayer alloc] init];
    self.player.playerView = self.avpPlayerView.playerView;
    self.player.delegate = self;
    //...
}
/**
 @brief Callback for errors.
 @param player The player pointer.
 @param errorModel The error description. For more information, see AliVcPlayerErrorModel.
 */
- (void)onError:(AliPlayer*)player errorModel:(AVPErrorModel *)errorModel {
    // Reports an error and stops the playback.
}
/**
 @brief Callback for player events.
 @param player The player pointer.
 @param eventType The event type. For more information, see AVPEventType.
 */
-(void)onPlayerEvent:(AliPlayer*)player eventType:(AVPEventType)eventType{
    switch(eventType){
        case AVPEventPrepareDone:{
            // The player is prepared.
        }
            break;
        case AVPEventAutoPlayStart:
            // The autoplay starts.
            break;
        case AVPEventFirstRenderedStart:
            // The first frame is rendered.
            break;
        case AVPEventCompletion:
            // The 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 {
    // Updates the progress bar.
}
/**
 @brief Callback for the buffered position.
 @param player The player pointer.
 @param position The current buffered position.
 */
- (void)onBufferedPositionUpdate:(AliPlayer*)player position:(int64_t)position {
    // Updates the buffering progress.
}
/**
 @brief Callback for track information.
 @param player The player pointer.
 @param info An array of track information. For more information, see AVPTrackInfo.
 */
- (void)onTrackReady:(AliPlayer*)player info:(NSArray<AVPTrackInfo*>*)info {
    // Obtains information about multiple bitrates.
}
/**
 @brief Callback for displaying captions.
 @param player The player pointer.
 @param index The index of the displayed caption.
 @param subtitle The string of the displayed caption.
 */
- (void)onSubtitleShow:(AliPlayer*)player index:(int)index subtitle:(NSString *)subtitle {
    // Obtains and displays the captions.
}
/**
 @brief Callback for hiding captions.
 @param player The player pointer.
 @param index The index of the displayed caption.
 */
- (void)onSubtitleHide:(AliPlayer*)player index:(int)index {
    // Hides the captions.
}
/**
 @brief Callback for snapshots.
 @param player The player pointer.
 @param image The image.
 */
- (void)onCaptureScreen:(AliPlayer *)player image:(UIImage *)image {
    // Previews and saves the snapshot.
}
/**
 @brief Callback for track switching completion.
 @param player The player pointer.
 @param info The information after switching. For more information, see AVPTrackInfo.
 */
- (void)onTrackChanged:(AliPlayer*)player info:(AVPTrackInfo*)info {
    // Notification for the result of bitrate switching.
}

Listen for playback states

You can listen for the state of the player. The onPlayerStatusChanged callback provides the current state of the player. The following code provides an example:

- (void)onPlayerStatusChanged:(AliPlayer*)player oldStatus:(AVPStatus)oldStatus newStatus:(AVPStatus)newStatus {
    switch (newStatus) {
    case AVPStatusIdle:{
           // Idle.
        }
 break;
        case AVPStatusInitialzed:{
           // Initialized.
        }
 break;
        case AVPStatusPrepared:{
           // Prepared.
        }
 break;
        case AVPStatusStarted:{
           // Playing.
        }
 break;
case AVPStatusPaused:{
           // Paused.
        }
 break;
case AVPStatusStopped:{
           // Stopped.
        }
 break;
case AVPStatusCompletion:{
           // Playback is complete.
        }
 break;
case AVPStatusError:{
           // Error.
        }
 break;
        default:
            break;
    }
}

Set the display mode

The ApsaraVideo Player SDK for iOS supports display settings such as fill, rotate, and mirror.

Fill

You can set one of the following three fill modes: aspect fit, aspect fill, and stretch to fill. Call the scalingMode interface to set the fill mode. The following code provides an example:

// Sets the aspect ratio to fit. The video is scaled down to fit within the view without distortion.
self.player.scalingMode = AVP_SCALINGMODE_SCALEASPECTFIT;
// Sets the aspect ratio to fill. The video is scaled up to fill the view without distortion.
self.player.scalingMode = AVP_SCALINGMODE_SCALEASPECTFILL;
// Sets the mode to stretch and fill. If the aspect ratio of the video is different from that of the view, the video may be distorted.
self.player.scalingMode = AVP_SCALINGMODE_SCALETOFILL;
Note

The fill mode setting does not take effect for Picture-in-Picture (PiP).

Rotate

Call the rotateMode interface to rotate the video by a specified angle. The following code provides an example:

// Rotates the video 0 degrees clockwise.
self.player.rotateMode = AVP_ROTATE_0;
// Rotates the video 90 degrees clockwise.
self.player.rotateMode = AVP_ROTATE_90;
// Rotates the video 180 degrees clockwise.
self.player.rotateMode = AVP_ROTATE_180;
// Rotates the video 270 degrees clockwise.
self.player.rotateMode = AVP_ROTATE_270;

Mirror

You can enable horizontal mirroring, vertical mirroring, or no mirroring. Call the mirrorMode interface to set the mirror mode. The following code provides an example:

// Disables mirroring.
self.player.mirrorMode = AVP_MIRRORMODE_NONE;
// Enables horizontal mirroring.
self.player.mirrorMode = AVP_MIRRORMODE_HORIZONTAL;
// Enables vertical mirroring.
self.player.mirrorMode = AVP_MIRRORMODE_VERTICAL;

Obtain playback information

The ApsaraVideo Player SDK for iOS lets you obtain the current playback progress, playback duration, and buffering progress.

Obtain the current playback progress

You can obtain the current playback time. The position is returned in the onCurrentPositionUpdate callback. The following code provides an example:

- (void)onCurrentPositionUpdate:(AliPlayer*)player position:(int64_t)position {
// The position parameter indicates the current playback progress in milliseconds.
NSString *position = [NSString stringWithFormat:@"%lld, position"];
}

Obtain the playback duration

You can obtain the total duration of the video. You can retrieve the duration only after the video is loaded, for example, after the onPrepared callback is invoked. Unit: milliseconds. The following code provides an example:

-(void)onPlayerEvent:(AliPlayer*)player eventType:(AVPEventType)eventType {
  switch (eventType) {
    case AVPEventPrepareDone: {
      if (self.player.duration >= 0) {
       NSString *duration  = self.player.duration;
      }
    }
      break;
    default:
      break;
  }
}

Obtain the actual playback duration

You can obtain the actual playback duration in real time. The retrieved duration does not include the time spent on pauses or stuttering during playback. The following code provides an example:

 NSString *duration = [player getPlayedDuration];

Obtain the buffering progress

You can obtain the current buffering progress of the video. The position is returned in the onBufferedPositionUpdate callback. The following code provides an example:

- (void)onBufferedPositionUpdate:(AliPlayer*)player position:(int64_t)position {
    NSString *bufferPosition = position;
}

Obtain the real-time rendering frame rate, audio and video bitrates, and network download bitrate

The following code provides an example:

// Obtains the current rendering frame rate. Data type: Float.
[self.player getOption:AVP_OPTION_RENDER_FPS]
// Obtains the bitrate of the video being played. Data type: Float. Unit: bps.
[self.player getOption:AVP_OPTION_VIDEO_BITRATE]
// Obtains the bitrate of the audio being played. Data type: Float. Unit: bps.
[self.player getOption:AVP_OPTION_AUDIO_BITRATE]
// Obtains the current network download bitrate. Data type: Float. Unit: bps.
[self.player getOption:AVP_OPTION_DOWNLOAD_BITRATE]

Set the volume

You can adjust the volume and mute the video.

Adjust the volume

You can adjust the volume. The valid range is 0 to 2. If the volume is set to a value greater than 1, noise may occur. We recommend that you do not set the volume to a value greater than 1. Call the volume interface to adjust the volume. After you set the volume, you can also retrieve the volume information. The following code provides an example:

// The value of volume is a real number from 0 to 2.
self.player.volume = 1.0f;
// Obtains the volume information.
self.player.volume

Mute the video

Call the muted interface to mute the video. The following code provides an example:

self.player.muted = YES;

Set the playback speed

The ApsaraVideo Player SDK for iOS lets you set the playback speed. Using the rate method, you can play the video at a speed from 0.5× to 5× the original speed without changing the pitch. The following code provides an example:

// Sets the playback speed. You can set the playback speed to a value from 0.5 to 5. We recommend that you set the value to a multiple of 0.5, such as 0.5, 1, or 1.5.
self.player.rate = 1.0f;

Configure multiple definitions

Note

For detailed code examples, see the MultiResolution module in API-Example. This project is an Objective-C-based demo for the ApsaraVideo Player SDK for iOS. This project helps developers quickly integrate the core features of the SDK.

Live streaming with UrlSource

For more information, see Standard live stream playback.

VOD playback using Vid (VidAuth or VidSts)

If you use the Vid method (VidAuth or VidSts) for playback, no extra configuration is required. The ApsaraVideo Player SDK for iOS retrieves the definition list from ApsaraVideo VOD. The ApsaraVideo Player SDK for iOS lets you obtain and switch the definition. The UrlSource method does not support this setting.

Obtain the definition

After the video is loaded, you can retrieve the video definition. The onTrackReady listener returns the info object in the callback. You can then retrieve the trackBitrate of the definition from this object.

- (void)onTrackReady:(AliPlayer*)player info:(NSArray<AVPTrackInfo*>*)info {
    for (int i=0; i<info.count; i++) {
        AVPTrackInfo* track = [info objectAtIndex:i];
        switch (track.trackType) {
            case AVPTRACK_TYPE_VIDEO: {
                int trackBitrate = track.trackBitrate;
            }
                break;
        }
    }
}

Switch the definition

To switch the definition, call the selectTrack method and pass the index of the corresponding TrackInfo.

[self.player selectTrack:index];

Notification for definition switching

The onTrackChanged callback is invoked after the definition is switched.

- (void)onTrackChanged:(AliPlayer*)player info:(AVPTrackInfo*)info {
 // The definition is switched.
}

Quick switching

After you enable quick switching mode, you receive a quick response every time you manually call selectTrack.

AVPConfig *config = [self.player getConfig];
config.selectTrackBufferMode = 1;
[self.player setConfig:config];

Loop playback

The ApsaraVideo Player SDK for iOS supports loop playback. You can set the loop property to enable this feature. After playback is complete, the video automatically restarts from the beginning. For example:

self.player.loop = YES;

The AVPEventLoopingStart callback is returned at the start of a loop. The following code provides an example:

- (void)onPlayerEvent:(AliPlayer*)player eventType:(AVPEventType)eventType {
    switch (eventType) {
        case AVPEventLoopingStart:
            break;
    }
}

Switch audio tracks

The ApsaraVideo Player SDK for iOS provides a feature to switch audio tracks. This feature is suitable for scenarios in which users can switch the audio language when watching videos with multi-language audio.

Usage notes

You can switch audio tracks in streams that are not used for list playback such as MP4 streams, single-bitrate mixed HLS streams, audio tracks in single-bitrate HLS streams, and substreams in multi-bitrate mixed HLS streams. The following table describes different types of video streams.

Type

Video stream suffix

Bitrate quantity

M3U8 file quantity

Substream type

Description

Non-list stream (such as MP4 stream)

.mp4

1

-

A stream that contains a video track, multiple audio tracks, and multiple subtitle tracks.

You can switch between audio tracks.

Single-bitrate mixed HLS stream

.m3u8

1

1

A stream that contains a video track, multiple audio tracks, and multiple subtitle tracks.

You can switch between audio tracks.

Single-bitrate HLS stream

.m3u8

1

n

An M3U8 stream that contains only video tracks, audio tracks, or subtitle tracks.

You can switch between audio tracks.

Multi-bitrate mixed HLS stream

.m3u8

n

n

An M3U8 stream that contains a video track, multiple audio tracks, and multiple subtitle tracks. The bitrate of the substreams are different.

You can switch between different substreams. You cannot switch between the audio tracks of a substream.

Examples

  1. Set a callback.

      // The onSubTrackReady callback usually occurs before the prepare callback.
    - (void)onSubTrackReady:(AliPlayer*)player info:(NSArray<AVPTrackInfo*>*)info {
        // Call getSubMediaInfo to obtain the MediaInfo information. You can call this method only after you receive the onSubTrackReady callback. Otherwise, the value is empty.
        AVPMediaInfo* subMediaInfo = [player getSubMediaInfo];
        // Traverse.
        for (int i=0; i<subMediaInfo.tracks.count; i++) {
        	AVPTrackInfo* track = [mediaInfo.tracks objectAtIndex:i];
            // Obtains the corresponding track.
        }
    }
  2. Switch the audio track.

    [self.player selectTrack:myTrack.trackIndex accurate:YES]

Use thumbnails

Note

For detailed code examples, see the Thumbnail module in API-Example. This project is an Objective-C-based demo for the ApsaraVideo Player SDK for iOS. This project helps developers quickly integrate the core features of the SDK.

Before you use thumbnails in the ApsaraVideo Player SDK, ensure that you have configured thumbnails for the video. This means that a sprite has been generated for the video. To do this, you must create a sprite screenshot template in the ApsaraVideo VOD console and use a workflow to process the video with the template. For more information, see Video screenshots. The following code shows how to use thumbnails in the ApsaraVideo Player SDK:

/**
 Specifies whether the current track has a thumbnail. If not, the thumbnail is not displayed.
 */
@property (nonatomic,assign)BOOL trackHasThumbnai;

/**
 Creates a custom view to display the thumbnail.
 */
@property (nonatomic,strong)UIImageView *thumbnaiView;

/**
 @brief: Callback for track information.
 @param player: The player pointer.
 @param info: An array of track information. For more information, see AVPTrackInfo.
 */
- (void)onTrackReady:(AliPlayer*)player info:(NSArray<AVPTrackInfo*>*)info {
    AVPMediaInfo* mediaInfo = [player getMediaInfo];
    if ((nil != mediaInfo.thumbnails) && (0 < [mediaInfo.thumbnails count])) {
        [self.player setThumbnailUrl:[mediaInfo.thumbnails objectAtIndex:0].URL];
        self.trackHasThumbnai = YES;
    }else {
        self.trackHasThumbnai = NO;
    }
}

/**
 Callback for progress bar changes.
 @param playerView playerView
 @param value: The progress value.
 */
- (void)AVPPlayerView:(AVPPlayerView *)playerView progressSliderValueChanged:(CGFloat)value {
    if (self.trackHasThumbnai) {
        [self.player getThumbnail:self.player.duration*value];
    }
}

/**
 @brief: Callback for successful thumbnail retrieval.
 @param positionMs: The specified thumbnail position.
 @param fromPos: The start position of the thumbnail.
 @param toPos: The end position of the thumbnail.
 @param image: The thumbnail image pointer. For macOS, it is an NSImage pointer. For iOS, it is a UIImage pointer.
 */
- (void)onGetThumbnailSuc:(int64_t)positionMs fromPos:(int64_t)fromPos toPos:(int64_t)toPos image:(id)image {
    self.thumbnaiView.hidden = NO;
    [self.thumbnaiView setImage:(UIImage *)image];
}

/**
 @brief: Callback for failed thumbnail retrieval.
 @param positionMs: The specified thumbnail position.
 */
- (void)onGetThumbnailFailed:(int64_t)positionMs {
    self.thumbnaiView.hidden = YES;
}

Note: If you use URL-based playback, the preceding code cannot directly display thumbnails because the onTrackReady callback does not support MediaInfo for URL-based playback. In this case, we recommend that you specify the thumbnail URL directly.

/**
 Specifies whether the current track has a thumbnail. If not, the thumbnail is not displayed.
 */
@property (nonatomic,assign)BOOL trackHasThumbnai;

/**
 Creates a custom view to display the thumbnail.
 */
@property (nonatomic,strong)UIImageView *thumbnaiView;

/**
  onPrepare
 */
- (void)onPlayerStatusChanged:(AliPlayer*)player oldStatus:(AVPStatus)oldStatus newStatus:(AVPStatus)newStatus {
  if(newStatus == AVPStatusPrepared){
       [self.player setThumbnailUrl:[URL];// Generate a specific thumbnail URL based on the console API.
       self.trackHasThumbnai = YES;
  }
}
/**
 Callback for progress bar changes.
 @param playerView playerView
 @param value: The progress value.
 */
- (void)AVPPlayerView:(AVPPlayerView *)playerView progressSliderValueChanged:(CGFloat)value {
    if (self.trackHasThumbnai) {
        [self.player getThumbnail:self.player.duration*value];
    }
}

/**
 @brief: Callback for successful thumbnail retrieval.
 @param positionMs: The specified thumbnail position.
 @param fromPos: The start position of the thumbnail.
 @param toPos: The end position of the thumbnail.
 @param image: The thumbnail image pointer. For macOS, it is an NSImage pointer. For iOS, it is a UIImage pointer.
 */
- (void)onGetThumbnailSuc:(int64_t)positionMs fromPos:(int64_t)fromPos toPos:(int64_t)toPos image:(id)image {
    self.thumbnaiView.hidden = NO;
    [self.thumbnaiView setImage:(UIImage *)image];
}

/**
 @brief: Callback for failed thumbnail retrieval.
 @param positionMs: The specified thumbnail position.
 */
- (void)onGetThumbnailFailed:(int64_t)positionMs {
    self.thumbnaiView.hidden = YES;
}

Obtain SDK logs

While the ApsaraVideo Player SDK is running, it generates detailed log information that includes the status of network requests, the results of system calls, and the status of permission requests. Developers can view these logs to debug code or troubleshoot issues and improve development efficiency.

Method 1: Obtain SDK logs from the console of the development tool

This method is suitable for scenarios in which you can reproduce the issue and capture logs on your local machine.

  1. Enable logging and set the log level.

    // Enables logging.
    [AliPlayer setEnableLog:YES];
    // Sets the log level. Default value: LOG_LEVEL_INFO. To troubleshoot issues, set the level to LOG_LEVEL_TRACE.
    [AliPlayer setLogCallbackInfo:LOG_LEVEL_INFO callbackBlock:nil];
  2. Set frame-level logging.

    // Sets frame-level log printing.
    // A value of 0 disables the feature. A value of 1 enables the feature.
    [AliPlayer setLogOption:FRAME_LEVEL_LOGGING_ENABLED value:value];
    Note

    The frame-level logging feature is mainly used for troubleshooting.

  3. Collect logs.

    1. Method 1: View logs in the console

      After you reproduce the issue, you can retrieve the logs from the console of your development tool, such as Xcode.

    2. Method 2: Output logs to a file in a custom path

      1. After you enable logging, specify a custom path for the log file in the sandbox path before you create a player instance.

        NSArray *paths =NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask, YES);
        NSString *documentDirectory = [paths objectAtIndex:0];
        // The logFilePath is an example path. You can create a custom file, such as an xxxx.log file, in the sandbox path.
        NSString *logFilePath = [documentDirectory stringByAppendingPathComponent:@"xxxx.log"];
      2. Inject log information into the custom file.

        freopen([logFilePath cStringUsingEncoding:NSASCIIStringEncoding],"a+", stdout);
        freopen([logFilePath cStringUsingEncoding:NSASCIIStringEncoding],"a+", stderr);
      3. After you reproduce the issue, you can retrieve the generated .log file from the custom path.

Method 2: Listen for SDK output logs through LogCallback

This method is suitable for scenarios in which the issue occurs on the user side and you cannot reproduce it and capture logs on your local machine. You can listen for SDK output logs through LogCallback and automatically output them to your app's log channel.

  1. Enable logging and set the log level.

    // Enables logging.
    [AliPlayer setEnableLog:YES];
    // Sets the log level. Default value: LOG_LEVEL_INFO. To troubleshoot issues, set the level to LOG_LEVEL_TRACE.
    [AliPlayer setLogCallbackInfo:LOG_LEVEL_INFO callbackBlock:^(AVPLogLevel logLevel, NSString *strLog) {
     NSLog(@"strLog:%@", strLog);
    }];
  2. Collect logs.

    After you reproduce the issue, the logs are automatically output to your app's log file through your app's log channel.