低延迟直播
  • 平台类型
  • 框架 / 引擎
  • iOS
  • Android
  • macOS
  • Windows
  • Linux
  • Web
  • 小程序

媒体播放器

更新时间:2021-05-12 10:42

1 功能简介

媒体播放器组件提供播放音视频媒体文件的能力,并且支持将播放的媒体文件的音画数据推流出去。

1.1 应用场景

  • 播放测试音频:可以使用媒体播放器播放测试音频,验证音频播放设备是否工作正常。
  • 播放背景音乐:使用媒体播放器播放音乐并混在流中推送出去,让远端听到背景音乐。
  • 播放视频文件:结合自定义视频采集将媒体资源的视频数据推送出去,远端可拉流观看。

1.2 支持格式

媒体播放器支持 MP3、MP4、FLV、WAV、AAC、M3U8、CAF 等格式文件,并支持播放 iOS 媒体库中的音乐(“ipod-library://”)。

媒体播放器默认支持格式为:MP3、MP4、FLV、WAV、AAC。如需支持其它格式,请联系 ZEGO 技术支持。

1.3 支持协议

支持 HTTP 和 HTTPS 协议。

2 示例源码下载

请参考 下载示例源码 获取源码。

相关源码请查看 “/ZegoExpressExample/Topics/MediaPlayer” 目录下的文件。

3 前提条件

在实现媒体播放器功能之前,请确保:

4 使用步骤

4.1 创建媒体播放器

调用 “ZegoExpressEngine” 的 createMediaPlayer 接口以创建媒体播放器实例。一个媒体播放器实例只能播放一个音视频,引擎同一时间最多支持创建 4 个播放器实例,以达到同时播放多个媒体资源的效果。若当前已存在 4 个播放器实例,再次调用创建播放器接口将返回 nil

  • 接口原型

    /// 创建媒体播放器实例对象
    ///
    /// 目前最多支持创建 4 个实例,超过后将返回 nil
    /// @return 媒体播放器实例,超过最大数量限制后将返回 nil
    - (nullable ZegoMediaPlayer *)createMediaPlayer;
  • 调用示例

    ZegoMediaPlayer *mediaPlayer = [[ZegoExpressEngine sharedEngine] createMediaPlayer];
    
    if (mediaPlayer) {
        self.player = mediaPlayer;
    } else {
        NSLog(@"创建播放器失败");
    }

4.2 (可选)为播放器设置事件回调

播放器事件回调设置

调用媒体播放器的 setEventHandler 接口为播放器设置事件回调,以接收“播放器状态改变”、“播放进度改变”、“播放器网络状态更新”等通知。

  • 接口原型

    @interface ZegoMediaPlayer : NSObject
    ......
    /// 设置媒体播放器的事件回调 handler
    ///
    /// 开发者可以根据媒体播放器的相关事件回调进行播放器 UI 界面的变化
    /// @param handler 媒体播放器的事件回调对象
    - (void)setEventHandler:(nullable id<ZegoMediaPlayerEventHandler>)handler;
    ......
    @end
    @protocol ZegoMediaPlayerEventHandler <NSObject>
    
    @optional
    
    /// 播放器播放状态回调
    ///
    /// @param mediaPlayer 回调的播放器实例
    /// @param state 播放器状态
    /// @param errorCode 错误码,详情请参考常用错误码文档
    - (void)mediaPlayer:(ZegoMediaPlayer *)mediaPlayer stateUpdate:(ZegoMediaPlayerState)state errorCode:(int)errorCode;
    
    /// 播放器网络状态事件回调
    ///
    /// @param mediaPlayer 回调的播放器实例
    /// @param networkEvent 网络状态事件
    - (void)mediaPlayer:(ZegoMediaPlayer *)mediaPlayer networkEvent:(ZegoMediaPlayerNetworkEvent)networkEvent;
    
    /// 播放器播放进度回调
    ///
    /// @param mediaPlayer 回调的播放器实例
    /// @param millisecond 进度,单位为毫秒
    - (void)mediaPlayer:(ZegoMediaPlayer *)mediaPlayer playingProgress:(unsigned long long)millisecond;
    
    @end
  • 调用示例

    // 此处示例 self 实现了 `ZegoMediaPlayerEventHandler` 协议并调用播放器的 set 接口
    [self.player setEventHandler:self];
    - (void)mediaPlayer:(ZegoMediaPlayer *)mediaPlayer stateUpdate:(ZegoMediaPlayerState)state errorCode:(int)errorCode {
        switch (state) {
            case ZegoMediaPlayerStateNoPlay:
                // 播放停止状态
                break;
            case ZegoMediaPlayerStatePlaying:
                // 正在播放状态
                break;
            case ZegoMediaPlayerStatePausing:
                // 暂停状态
                break;
            case ZegoMediaPlayerStatePlayEnded:
                // 当前曲目播放完成,可执行播放下一首等操作
                break;
        }
    }
    
    - (void)mediaPlayer:(ZegoMediaPlayer *)mediaPlayer networkEvent:(ZegoMediaPlayerNetworkEvent)networkEvent {
        if (networkEvent == ZegoMediaPlayerNetworkEventBufferBegin) {
            // 展示 Loading UI
        } else if (networkEvent == ZegoMediaPlayerNetworkEventBufferEnded) {
            // 关闭 Loading UI
        }
    }
    
    - (void)mediaPlayer:(ZegoMediaPlayer *)mediaPlayer playingProgress:(unsigned long long)millisecond {
        // 更新进度条
    }

4.3 加载媒体资源

调用媒体播放器的 loadResource 指定要播放的媒体资源,可以是本地资源的绝对路径,也可以是网络资源的 URL,如 “http://your.domain.com/your-movie.mp4”。用户可通过传入回调参数的方式获取加载文件的结果。

  • 接口原型

    /// 加载资源,可传本地资源的绝对路径或者网络资源的 URL
    - (void)loadResource:(NSString *)path callback:(nullable ZegoMediaPlayerLoadResourceCallback)callback;
  • 调用示例

    // 此处示例获取 App 包内的 sample.mp4 文件绝对路径
    NSString *fileURL = [[NSBundle mainBundle] pathForResource:@"sample" ofType:@"mp4"];
    
    [self.player loadResource:fileURL callback:^(int errorCode) {
        // 可执行更新 UI 等逻辑
    }];

4.4 播放控制

4.4.1 播放状态控制

调用 startpauseresumestop 来启停播放。一旦播放器的内部状态改变,mediaPlayer 回调将会被触发。

用户也可通过调用 currentState 随时获取播放器的当前状态。

如果 enableRepeat 设置为 “YES”,则播放器会在播放完文件后自动重播。

@interface ZegoMediaPlayer : NSObject

......

/// 开始播放(播放前需要先加载资源)
- (void)start;

/// 停止播放
- (void)stop;

/// 暂停播放
- (void)pause;

/// 恢复播放
- (void)resume;

/// 设置是否重复播放
- (void)enableRepeat:(BOOL)enable;

......

@end

4.4.2 播放进度控制

播放文件的进度会通过 mediaPlayer 方法回调,默认触发回调的间隔是 1000 ms,可通过 setProgressInterval 更改此间隔。

用户也可通过 currentProgress 来获取当前播放进度。

通过 seekTo 接口可以调整播放进度进度。

  • 接口原型

    @interface ZegoMediaPlayer : NSObject
    
    /// 整个文件的播放时长,毫秒
    @property (nonatomic, assign, readonly) unsigned long long totalDuration;
    
    /// 当前播放进度,毫秒
    @property (nonatomic, assign, readonly) unsigned long long currentProgress;
    
    ......
    
    /// 设置指定播放进度,毫秒
    - (void)seekTo:(unsigned long long)millisecond callback:(nullable ZegoMediaPlayerSeekToCallback)callback;
    
    ......
    
    /// 设置播放进度回调间隔
    - (void)setProgressInterval:(unsigned long long)millisecond;
    
    ......
    
    @end
  • 调用示例

    [self.player setProgressInterval:1000];
    
    unsigned long long totalDuration = self.player.totalDuration;
    
    [self.player seekTo:totalDuration/2 callback:^(int errorCode) {
        NSLog(@"errorCode: %d", errorCode);
    }];
    
    unsigned long long progress = self.player.currentProgress;
    
    NSLog(@"process: %llu", progress);

4.4.3 播放器音频控制

通过 playVolumesetPlayVolume 获取和控制播放音量。

通过 publishVolumesetPublishVolume 获取和控制推流音量。

调用 enableAux 可以将文件的声音混入正在推的流中。

调用 muteLocal 可以使本地静默播放但能正常将声音混入流。

// 获取播放器当前播放音量
int playVolume = self.player.playVolume;

// 设置播放器音量为原先的一半
[self.player setPlayVolume:playVolume/2];

// 开启将资源的声音混入正在推的流中
[self.player enableAux:YES];

// 开启本地静默播放
[self.player muteLocal:YES];

如果想获取文件的音频数据,可通过 setAudioHandler 来设置音频帧回调。

  • 接口原型

    @interface ZegoMediaPlayer : NSObject
    ......
    /// 设置播放器音频数据回调
    - (void)setAudioHandler:(nullable id<ZegoMediaPlayerAudioHandler>)handler;
    ......
    @end
    @protocol ZegoMediaPlayerAudioHandler <NSObject>
    
    @optional
    
    /// 播放器音频帧数据回调
    /// @param mediaPlayer 回调的播放器实例
    /// @param data 音频帧的裸数据
    /// @param dataLength 数据的长度
    /// @param param 音频帧参数
    - (void)mediaPlayer:(ZegoMediaPlayer *)mediaPlayer audioFrameData:(const unsigned char *)data dataLength:(unsigned int)dataLength param:(ZegoAudioFrameParam *)param;
    
    @end
  • 调用示例

    // 此处示例 self 实现了 `ZegoMediaPlayerAudioHandler` 协议并调用播放器的 set 接口
    [self.player setAudioHandler:self];
    - (void)mediaPlayer:(ZegoMediaPlayer *)mediaPlayer audioFrameData:(const unsigned char *)data dataLength:(unsigned int)dataLength param:(ZegoAudioFrameParam *)param {
        // 收到媒体播放器音频数据回调
    }

4.4.4 播放器视频控制

当播放视频资源时,用 setPlayerCanvas 来设置视频的显示视图。

  • 接口原型

    /// 设置播放器视图
    - (void)setPlayerCanvas:(nullable ZegoCanvas *)canvas;
  • 调用示例

    [self.player setPlayerCanvas:[ZegoCanvas canvasWithView:self.playerView]];

如果想获取文件的视频数据,可通过 setVideoHandler 来设置视频帧回调。

  • 接口原型

    /// 设置播放器视频数据回调,希望接收的视频帧数据格式以及数据类型
    - (void)setVideoHandler:(nullable id<ZegoMediaPlayerVideoHandler>)handler format:(ZegoVideoFrameFormat)format type:(ZegoVideoBufferType)type;
    @protocol ZegoMediaPlayerVideoHandler <NSObject>
    
    @optional
    
    /// 播放器视频帧裸数据回调
    /// @param mediaPlayer 回调的播放器实例
    /// @param data 视频帧的裸数据(例:RGBA 只需考虑 data[0],I420 需考虑 data[0,1,2])
    /// @param dataLength 数据的长度(例:RGBA 只需考虑 dataLength[0],I420 需考虑 dataLength[0,1,2])
    /// @param param 视频帧参数
    - (void)mediaPlayer:(ZegoMediaPlayer *)mediaPlayer videoFrameRawData:(const unsigned char * _Nonnull * _Nonnull)data dataLength:(unsigned int *)dataLength param:(ZegoVideoFrameParam *)param;
    
    /// 播放器视频帧 CVPixerBuffer 数据回调
    /// @param mediaPlayer 回调的播放器实例
    /// @param buffer 封装为 CVPixerBuffer 的视频帧数据
    /// @param param 视频帧参数
    - (void)mediaPlayer:(ZegoMediaPlayer *)mediaPlayer videoFramePixelBuffer:(CVPixelBufferRef)buffer param:(ZegoVideoFrameParam *)param;
    
    @end
  • 调用示例

    // 设置视频数据格式为 NV12,数据类型为 CVPixelBuffer
    [self.player setVideoHandler:self format:ZegoVideoFrameFormatNV12 type:ZegoVideoBufferTypeCVPixelBuffer];
    /// When video frame type is set to `ZegoVideoFrameTypeCVPixelBuffer`, video frame CVPixelBuffer data will be called back from this function
    /// @note Need to switch threads before processing video frames
    - (void)mediaPlayer:(ZegoMediaPlayer *)mediaPlayer videoFramePixelBuffer:(CVPixelBufferRef)buffer param:(ZegoVideoFrameParam *)param {
        // NSLog(@"pixel buffer video frame callback. format:%d, width:%f, height:%f", (int)param.format, param.size.width, param.size.height);
    }

当数据类型 “type” 设为 “ZegoVideoBufferTypeCVPixelBuffer” 时,数据格式 “format” 仅支持设为 “ZegoVideoFrameFormatI420”、“ZegoVideoFrameFormatNV12”、“ZegoVideoFrameFormatBGRA32”、“ZegoVideoFrameFormatARGB32”;设为其他不支持的格式后续将不会回调视频帧数据。

4.4.5 将播放器播放的视频推流出去

  1. 将播放器的视频推流出去前,需要先通过 setVideoHandler 设置视频帧回调监听,用于获取 onVideoFrame 抛出的视频帧数据。

  2. 使用自定义方式采集视频,并将获取到的视频数据混入推流数据中,详细操作请参考 视频进阶 - 自定义视频采集

自定义采集数据时,建议开发者自行定义一个 “flag” 标记位:

  • 当触发 onStart 回调时将 “flag” 标记设置为 “True”,表示可以开始将自定义采集的视频数据发送给 SDK。
  • 当触发 onStop 回调时将 “flag” 标记设置为 “False”,表示需要停止发送采集的视频数据给 SDK。
  1. 开发者需要在 onVideoFrame 中添加对 “flag” 的判断逻辑,当 “flag” 设置为 “True” 时(即触发了 onStart 回调),调用 sendCustomVideoCaptureRawData 方法向 SDK 发送已获取的视频数据。

  2. 调用 startPublishingStream 开始推流,请参考 快速开始 - 实现流程 的 “2.3 推流”。

4.4.6 变声

处理类似于 KTV 中对伴奏升降调等场景时,可以调用媒体播放器的 setVoiceChangerParam 接口来实现变声功能。开发者可通过 ZegoVoiceChangerParam 对象中的音高参数 “pitch” 设置变声效果,该参数取值范围为 [-8.0, 8.0],值越大声音越尖锐,默认值为 “0.0”(即关闭变声器)。

ZegoVoiceChangerParam *param = [[ZegoVoiceChangerParam alloc] init];
param.pitch = 8.0f;     /** 男声变童声 */
param.pitch = 4.0f;     /** 男声变女声 */
param.pitch = 6.0f;     /** 女声变童声 */
param.pitch = -3.0f;    /** 女声变男声 */
[self.player setVoiceChangerParam:param audioChannel:ZegoMediaPlayerAudioChannelAll];

4.5 销毁媒体播放器

使用完播放器之后,需要及时置空播放器实例变量以销毁媒体播放器,释放占用的资源。调用示例如下:

self.player = nil;

当该媒体播放器实例对象的引用计数为 0 时将销毁该播放器实例并释放其占用的资源。

5 API 参考列表

方法 描述
createMediaPlayer 创建媒体播放器
destroyMediaPlayer 销毁媒体播放器
setVoiceChangerParam 设置变声参数

6 常见问题

  1. 如何在播放中途切换播放资源?

    先调用播放器的 stop 接口,然后重新调用 loadResource 接口加载新资源。