LinkVisual视频Media SDK

更新时间:2019-07-31 18:58:07

概述

本节主要为Link Visual iOS版本的音视频模块使用说明,包含视频播放、语音对讲的功能。

依赖SDK 概述
API 通道 提供API通道能力
长连通道 P2P需要长连接通道

初始化

在初始化 SDK 前,需要正确的配置安全图片,请参见:集成安全图片

工程配置

方式一: CocoaPods
podfile中添加阿里源

source 'https://github.com/aliyun/aliyun-specs.git'

添加库依赖

pod 'CocoaAsyncSocket', '7.4.2'
pod 'IMSLinkVisualMedia', '1.0.0'

执行pod update、则库安装完毕

方式二: 本地库项目引入(如果拿到的是本地包请使用该方式集成)
如为podspec,在podfile中添加本地路径

pod 'IMSLinkVisualMedia', :path => 'LocalPods/IMSLinkVisualMedia.podspec'

sdk文件拷贝以下文件至项目内LocalPods目录如下图方式
image.png

podspec拷贝以下文件至项目内LocalPods目录

IMSLinkVisualMedia.podspec
IMSLinkVisualMedia//文件夹 IMSLinkVisualMedia文件夹内包含以下framework

IMSLinkVisualMedia.framework
LibRtmp.framework
LinkVisualClientSDK.framework
FFmpeg.framework

执行pod update则库安装完毕

使用说明

视频播放器

播放器按功能分为三种,提供了以下功能:

直播播放器

  • 用于RTMP直播源,具有时延低的特点.

  • 支持P2P(需使用接入LinkVisual设备端SDK的摄像头).

点播播放器

  • 用于设备录像回放的播放,可调整播放进度.

HLS播放器

  • 用于云端录像回放的播放

FFmpeg使用版本为n4.0.1.
音频编码支持AAC_LC和G711a.
视频编码支持H264/H265.
iOS SDK封装AVPlayer作为HLS的播放器.

功能列表:

功能 直播播放器 设备录像播放器 HLS播放器
视频播放
音频播放
暂停/恢复 x
跳至指定位置播放 X
总时长 x
当前播放进度 x
播放器状态变更通知
静音
变速播放 x x x
循环播放 x x x
画面缩放模式设置 x x x
播放器截图
边播边录 x

使用指南

//框架引入
#import <IMSLinkVisualMedia/IMSLinkVisualMedia.h>
直播播放器
    //创建播放器
    IMSLinkVisualPlayerViewController *player = [[IMSLinkVisualPlayerViewController alloc] init];
    [self addChildViewController:player];
    //打开播放器日志  默认为 IMSLinkVisualMediaLogInfo 
    player.playerLog = IMSLinkVisualMediaLogInfo;
    //设置播放器frame
    player.view.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
    player.view.frame = self.view.bounds;
    //添加播放器view到指定位置
    [self.view insertSubview:player.view atIndex:0];
    //播放器代理
    player.delegate = self;
    //设置播放器参数
    [player setDataSource:self.iotId streamType:IMSLinkVisualPlayerLiveStreamTypeMain encryptType:0 needForceIFrame:true];
    //开始播放
    [player start];
    //停止播放 ,释放播放器,
    [player stop];

点播播放器

    //创建播放器
    IMSLinkVisualPlayerViewController *player = [[IMSLinkVisualPlayerViewController alloc] init];
    [self addChildViewController:player];
    //设置播放器frame
    player.view.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
    player.view.frame = self.view.bounds;
    //添加播放器view到指定位置
    [self.view insertSubview:player.view atIndex:0];
    //播放器代理
    player.replayDelegate = self;
    player.delegate = self;
    //设置播放器参数 vodStartTime为当天0点时间戳,vodEndTime为当天24点-1秒时间戳 seekTime为本次播放的起始时间(秒)
    [player setDataSource:iotId vodStartTime:timestamp vodEndTime:timestamp + dayOfSecond encryptType:0 seekTime:time];
    //开始播放
    [player start];
    //录像时间跳转 seekTime 为本天需要跳转的秒数
    [player seekToDuration:seekTime];
    //暂停播放
    [player pause];
    //暂停之后恢复播放
    [player restore];
    //停止播放 ,释放播放器,
    [player stop];

HLS播放器

    //创建播放器
    hlsPlayer = [IMSLinkVisualHLSPlayer new];
    //设置播放器frame
    hlsPlayer.frame = self.view.bounds;
    hlsPlayer.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
     //添加播放器view到指定位置
    [self.view insertSubview:hlsPlayer atIndex:0];
    //播放器代理
    hlsPlayer.delegate = self;
   //设置播放器参数 file.fileName 为云端录像返回参数
   [hlsPlayer playWithFileName:file.fileName iotId:iotId];
    //开始播放
    [hlsPlayer play];
    //录像时间跳转 seekTime 为本段视频需要跳转的秒数
    [hlsPlayer seekToTime:CMTimeMake(seekTime, 1)];
    //暂停播放
    [hlsPlayer pause];
    //停止播放 ,释放播放器,
    [hlsPlayer stop];

直播与点播的播放器状态

/// 播放器状态
typedef NS_ENUM(NSUInteger,IMSLinkVisualPlayerState){
    /// 空闲(播放器未开启,stop,释放)
    IMSLinkVisualPlayerStateIdle,
    /// 缓冲中(播放器start之后未开始播放前的状态)
    IMSLinkVisualPlayerStateBuffering,
    /// 开始播放(播放已经缓冲完毕,正在播放,未暂停)
    IMSLinkVisualPlayerStateStartPlay,
    /// 暂停播放(播放器正在暂停)
    IMSLinkVisualPlayerStatePausePlay
};

HLS的播放器状态

typedef NS_ENUM(NSInteger, IMSLinkVisualHLSPlayerStatus) {
    /// 空闲
    IMSLinkVisualHLSPlayerIdle,
    /// 加载中
    IMSLinkVisualHLSPlayerLoading,
    /// 加载完毕
    IMSLinkVisualHLSPlayerReady,
    /// 播放中
    IMSLinkVisualHLSPlayerPlaying,
    /// 暂停
    IMSLinkVisualHLSPlayerPause,
    /// 播放结束
    IMSLinkVisualHLSPlayerFinished,
};

接口说明

设置数据源(URL)
/**
 设置RTMP数据源、默认不加密

 @see IMSLinkVisualPlayerSourceType
 @param rtmpUrl RTMP格式的url
 @param sourceType 播放器类型
 @return 数据源是否设置成功
 */

- (BOOL)setDataSource:(NSString *_Nullable)rtmpUrl
           sourceType:(IMSLinkVisualPlayerSourceType)sourceType;
设置数据源(直播业务)

视频播放器业务依赖于账号和用户 SDK 的初始化。

/**
     * 设置IPC直播数据源.
     *
     * @param iotId                    IPC设备的iotId
     * @param streamType               流的类型: 0-主码流,1-辅码流
     * @param encryptType             云转加密类型: 0-AES128
     * @param needForceIFrame          是否需要强制I帧
     */
[self.player setDataSource:self.iotId streamType:IMSLinkVisualPlayerLiveStreamTypeMain];

- (BOOL)setDataSource:(NSString *)iotId
           streamType:(IMSLinkVisualPlayerLiveStreamType)streamType
          encryptType:(NSInteger)encryptType
      needForceIFrame:(BOOL)needForceIFrame;
设置数据源(录播业务)

视频播放器业务依赖于账号和用户 SDK 的初始化。

/**
     * 设置播放源为IPC录像(按录像文件名)
     *
     * @param iotId                         IPC设备的iotId
     * @param vodFileName           请求录像的文件名称
     */
[self.player setDataSource:self.iotId vodFileName:record.fileName];
/**
     * 设置播放地址为已接入飞燕的IPC设备指定录像时间段的本地录像文件地址.
     *
     * @param iotId                         IPC设备的iotId
     * @param vodStartTime          录像开始时间,1970年1月1日开始的秒数
     * @param vodEndTime         录像结束时间,1970年1月1日开始的秒数
     * @param encrypted             是否流需要加密, 强烈建议开启,对于出海产品,务必保持开启
     * @param encryptType         云转加密类型: 目前只支持0(AES-128)加密
     * @param seekTime              相对于beginTime的起始播放偏移量,单位为秒
     */
[player  setDataSource:iotId
               vodStartTime:self.record.beginTime
                  vodEndTime:self.record.endTime
                  needEncrypt:NO
                  encryptType:0
                       seekTime:seekTime];
设置播放器缓存
#import <IMSLinkVisualMedia/IMSLinkVisualMedia.h>
/**
 //设置播放器缓存 缓存越大,延迟越高 一帧缓存延迟40ms 默认为5帧
 @param buffer 缓存大小 0 -- 16
 */
[self.player setDisplyBuffer:10];
开始播放
#import <IMSLinkVisualMedia/IMSLinkVisualMedia.h>

// 开始播放
[self.player start];
停止播放
#import <IMSLinkVisualMedia/IMSLinkVisualMedia.h>

// 停止播放,结束播放器
[self.player stop];
暂停播放(仅录播)
#import <IMSLinkVisualMedia/IMSLinkVisualMedia.h>

// 暂停播放
[self.player pause];
恢复播放(仅录播)
#import <IMSLinkVisualMedia/IMSLinkVisualMedia.h>

// 恢复播放
[self.player restore];
监听播放器状态(代理)
#pragma mark - IMSLinkVisualDelegate
#pragma mark 播放器建立连接

-(void)linkVisual:(IMSLinkVisualPlayerViewController *_Nullable)client didConnect:(IMSLinkVisualPlayerError)status {
    if (IMSLinkVisualPlayerSuccess == status) {
    }else{
    }
}


#pragma mark 播放器播放成功

-(void)linkVisual:(IMSLinkVisualPlayerViewController *_Nullable)client didCompletePaly:(BOOL)success {
    if (success) {
    }else{
    }
}
#pragma mark 播放器停止

- (void)linkVisual:(IMSLinkVisualPlayerViewController *)client didStop:(BOOL)success{
    if (success) {
    }
}
#pragma mark 播放器回到前台,reStart 重新自动播放

- (void)linkVisual:(IMSLinkVisualPlayerViewController *)client becomeActive:(BOOL)reStart{
    if (reStart) {
    }
}
#pragma mark 播放器状态变更

- (void)linkVisual:(IMSLinkVisualPlayerViewController * _Nullable)client newStatus:(IMSLinkVisualPlayerState)newStatus oldStatus:(IMSLinkVisualPlayerState)oldStatus {

}
#pragma mark 播放器错误回调

- (void)linkVisual:(IMSLinkVisualPlayerViewController * _Nullable)client clientError:(NSError*)error {

}
监听录像播放器状态(代理)(录像播放器同样拥有播放器回调)
#pragma mark - IMSLinkVisualReplayDelegate
#pragma mark 播放器时间回调

- (void)linkVisualReplay:(IMSLinkVisualPlayerViewController *)player currentTime:(NSInteger)currentTime{
}
#pragma mark 播放器seek完毕

- (void)linkVisualReplaySeekComplete:(IMSLinkVisualPlayerViewController *)player{
}
#pragma mark 播放器播放完毕

- (void)linkVisualReplayOver:(IMSLinkVisualPlayerViewController * _Nullable)player { 
}
设置播放地址为IPC云存录像(按文件名)(hls)
#import <IMSLinkVisualMedia/IMSLinkVisualMedia.h>

// 设置播放路径为云端获得fileName, 设备iotId
 [self.player playWithFileName:file.fileName iotId:iotId];
设置播放url路径(hls)
#import <IMSLinkVisualMedia/IMSLinkVisualMedia.h>

// 设置播放路径为获得url地址
 [self.player playWithRequestUrl:requestUrl];
开始播放(hls)
#import <IMSLinkVisualMedia/IMSLinkVisualMedia.h>

// 播放
[self.player play];
暂停播放(hls)
#import <IMSLinkVisualMedia/IMSLinkVisualMedia.h>

// 暂停播放
[self.player pause];
监听HLS播放器状态(代理)
#pragma mark - IMSLinkVisualHLSPlayerDelegate

#pragma mark 播放器时间回调

- (void)linkVisualHLSPlayer:(IMSLinkVisualHLSPlayer*)player currentTime:(NSTimeInterval)currentTime {

}
#pragma mark 播放器加载失败

- (void)linkVisualHLSPlayerFailed:(IMSLinkVisualHLSPlayer *)player {
}
#pragma mark 播放器播放完毕

- (void)linkVisualHLSPlayerFinished:(IMSLinkVisualHLSPlayer *)player {
}
#pragma mark 播放器加载完成

- (void)linkVisualHLSPlayerReadyToPlay:(IMSLinkVisualHLSPlayer *)player {

}
#pragma mark 播放器seek完毕


- (void)linkVisualHLSPlayerSeek:(IMSLinkVisualHLSPlayer *)player completion:(BOOL)finished {

}
监听播放器状态(通知)
#import <IMSLinkVisualMedia/IMSLinkVisualMedia.h>

//监听播放器状态变更
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(playerStateChangeNotification:) name:IMSLinkVisualPlayerStateChangeNotification object:nil];

//监听播放器错误
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(playerErrorNotification:) name:IMSLinkVisualPlayerErrorNotification object:nil];

//监听播放器结束通知
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(playerStateEndNotification:) name:IMSLinkVisualPlayerStateEndNotification object:nil];

//播放器状态变更回调

- (void)playerStateChangeNotification:(NSNotification *)notification {
    if (notification.object != self.player) {
        return;
    }

    IMSLinkVisualPlayerState newState = [notification.userInfo[IMSLinkVisualPlayerNewStateKey] unsignedIntegerValue];

    switch (newState) {
        // 空闲
        case IMSLinkVisualPlayerStateIdle:
        // 缓冲中
        case IMSLinkVisualPlayerStateBuffering:
        // 开始播放
        case IMSLinkVisualPlayerStateStartPlay:
        // 暂停播放
        case IMSLinkVisualPlayerStatePausePlay:
    }    
}

//播放器错误通知回调

- (void)playerErrorNotification:(NSNotification *)notification {
    if (notification.object != self.player) {
        return;
    }
    // 错误内容
    NSError *error = notification.userInfo[IMSLinkVisualPlayerErrorKey];
    // 错误代码
    IMSLinkVisualPlayerError errorCode = error.code;

}

//播放器播放结束通知回调

- (void)playerStateEndNotification:(NSNotification *)notification {
    if (notification.object != self.player) {
        return;
    }
}
视频截图
#import <IMSLinkVisualMedia/IMSLinkVisualMedia.h>

//获取视频截图
UIImage *image = [self.player videoSnapshot];
边录边播
#import <IMSLinkVisualMedia/IMSLinkVisualMedia.h>

- (IBAction)recordVideoButtonClick:(UIButton *)sender {
    sender.selected = !sender.selected;
    NSString *tmpPath = [NSTemporaryDirectory() stringByAppendingPathComponent:@"tmp.mp4"];

    if (sender.selected) {
        [self.player startRecordVideoWithfilePath:tmpPath];
    } else {
        [self.player stopRecordVideo];
    }
}

播放器错误列表

错误主码(PlayerMainError) 描述 子码(解析userInfo中subCode来获取) 描述
ErrorSource 数据源相关错误 IMSLinkVisualPlayerErrorConnect (1005) 与数据源建立连接失败
IMSLinkVisualPlayerErrorEncrypt(1006) 无效的解密密钥
IMSLinkVisualPlayerErrorUrl (1007) 无效的播放地址
IMSLinkVisualPlayerErrorDataSource(1008) 数据源错误或未设置
IMSLinkVisualPlayerErrorStart (1009) 请求播放地址失败
ErrorRender 渲染相关错误渲染相关错误 IMSLinkVisualPlayerErrorDecode(1000) 解码错误
ErrorUnexpected 不符合预期错误 IMSLinkVisualPlayerErrorStream(1100) 拉流失败,8S未拉取到流或连接被异常断开

hls播放器错误列表

hls播放器错误码 描述
IMSLinkVisualPlayerErrorUrl (_1007)_ 无效的播放地址
IMSLinkVisualPlayerErrorStart (_1009)_ 请求播放地址失败
IMSLinkVisualPlayerErrorDataSource (_1008)_ 数据源错误或未设置
IMSLinkVisualPlayerErrorConnect (_1005)_ 拉流失败,未拉取到流或连接被异常断开
IMSLinkVisualPlayerErrorStream(_1100)_ 流连接失败(一段时间内(比如20秒)没收到流)

语音对讲

提供App和IPC设备之间端到端的双向实时音频传输能力.

语音对讲支持双工模式. App端需要做: 发起开始语音对讲请求->交换音频参数->音频采集-> 音频编码(可选)-> 上传/接收 -> 音频解码(可选) -> 音频播放->停止语音对讲 这些流程.

音频格式支持情况:

编码 解码
PCM - -
AAC_LC
G711A
G711U

使用指南

1、创建语音对讲编码参数

参数为录制语音数据的参数,用来与设备端对齐

    IMSLinkVisualAudioParams *intercomEncodeParams = [[IMSLinkVisualAudioParams alloc] init];
    intercomEncodeParams.sampleRate = 8000;
    intercomEncodeParams.channel = 1;
    intercomEncodeParams.bitsPerSample = 16;
    intercomEncodeParams.format = IMSLinkVisualAudioFormatG711a;
2、设置语音对讲参数

创建编码器用于编码语音数据

//     player 为播放器实例 IMSLinkVisualPlayerViewController
    player.intercomEncodeParams = intercomEncodeParams;
3、设置语音对讲回调代理

用于语音对讲开始与结束流程的消息回调代理,开始对讲前,先增加语音对讲状态回调方法

 player.intercomDelegate = self;
4、开语音对讲

设置播放器为对讲模式并开启对讲功能

[player startIntercom:IMSLinkVisualIntercomAudioModeIntercom];
5、停止语音对讲
    [player stopIntercom];
语音对讲状态回调方法与触发规则

#pragma mark - IMSLinkVisualIntercomDelegate
#pragma mark 语音对讲连接服务器
//语音对讲与设备端建立连接时触发

- (void)linkVisualIntercomDidConnect:(IMSLinkVisualPlayerViewController *)player {
    //语音对讲连接服务器成功
}
#pragma mark 语音对讲ready
//当对讲连接于服务端连接建立后,若对端已就绪,会告知本端事件talk ready. 此时向对端发送音频数据都会被对端收到并处理.

- (void)linkVisualIntercomDidReady:(IMSLinkVisualPlayerViewController *_Nullable)player
                             error:(NSError *_Nullable)error{
}

#pragma mark 语音对讲停止
//语音对讲结束时触发

- (void)linkVisualIntercomDidStop:(IMSLinkVisualPlayerViewController *)player
                            error:(NSError *)error {
    //语音对讲结束
    if (error) {
    //关闭对讲发生错误
    }
}

#pragma mark 语音对讲出错
//在语音对讲通道建立以及对讲中时都可能发生错误,需要处理,错误类型详见错误列表.

- (void)linkVisualIntercom:(IMSLinkVisualPlayerViewController *)player
                 errorOccurred:(NSError *)error {
    //语音对讲出错
    if (error) {
        //code错误码分析错误发生原因
    }
}

#pragma mark 对讲接收到设备端音频参数
//当语音对讲通道建立后,若对端支持录音,会先收到对端发送过来的音频参数信息,
//后续对端发送的音频数据按照此音频参数来做解码. 该事件是语音对讲通道建立成功的标志. 
//可以在此时构建音频播放器实例用于对端采集音频的实时播放.

- (void)linkVisualIntercom:(IMSLinkVisualPlayerViewController *)player
     didReceiveAudioParams:(IMSLinkVisualAudioParams *)params {
}

#pragma mark 对讲接收到设备端音频数据
//若对端支持录音,语音对讲中会持续不断的收到对端发送过来的音频数据.

- (void)linkVisualIntercom:(IMSLinkVisualPlayerViewController *)intercom didReceiveData:(NSData *)data {
    if (data) {
        //playBuffers为自定义可变数组收集数据
        [self.playBuffers addObject:data];
    }
}

#pragma mark 录音数据完成回调
//语音对讲开始后,会收集不断收到mic采集的数据,根据对讲的状态开始发送的数据

- (void)linkVisualIntercom:(IMSLinkVisualPlayerViewController *)intercom didRecordData:(NSData *)data{
    if (data) {
        //发送录音数据 audioBuffers为自定义可变数组收集数据
        [player sendAudioData:audioData];
    }
}

错误列表

语音对讲错误状态码 描述
IMSLinkVisualIntercomErrorParams 对讲参数错误
IMSLinkVisualIntercomErrorStart 启动对讲失败
IMSLinkVisualIntercomErrorConnect 语音流建立失败
IMSLinkVisualIntercomErrorSendData 发送语音数据失败
IMSLinkVisualIntercomErrorReceiveData 接收语音数据失败

ChangeLog

1.1.0(2019.7.1):

  • 修复语音对讲采集声音破音问题

  • 修复保存的Mp4文件声音快放问题

  • 修复H265源保存的Mp4文件在MacOS和iOS上不能播放的问题

  • 新增语音对讲的(void)rtmpClient:(IMSLinkVisualLiveClient)client didIntercomReady:(NSError )error 方法,用于接收对讲对端就绪事件

  • 改善P2P效果

  • 优化视频解码性能,支持低性能设备

  • 细化错误码,补充子码描

  • 修复若干稳定性问题

1.1.1(2019.7.18):

  • 修复H265流播放花屏问题

  • 修复直播时录屏丢失头部帧的问题

  • IMSLinkVisualHLSPlayer播放器废弃playWithUrl,增加playWithFileName和playWithRequestUrl接口,状态IMSLinkVisualHLSPlayerFree重命名为IMSLinkVisualHLSPlayerIdle

  • 增加设置日志级别接口

  • 增加设置播放器缓存接口

版权信息

LinkVisual视频Media SDK使用了librtmp和FFmpeg开源软件,相关版权声明如下。

librtmp

Copyright (C) 2005-2008 Team XBMC
       http://www.xbmc.org
       Copyright (C) 2008-2009 Andrej Stepanchuk
       Copyright (C) 2009-2010 Howard Chu

 librtmp is free software; you can redistribute it and/or modify
 it under the terms of the GNU Lesser General Public License as
 published by the Free Software Foundation; either version 2.1,
 or (at your option) any later version.

 librtmp is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 GNU General Public License for more details.

 You should have received a copy of the GNU Lesser General Public License
 along with librtmp see the file COPYING.  If not, write to
 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 Boston, MA  02110-1301, USA.
 http://www.gnu.org/copyleft/lgpl.html

FFmpeg

FFmpeg is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.

FFmpeg is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with FFmpeg; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA

results matching ""

    No results matching ""