Skip to main content

视频解码功能实现教程

1. 概述

Mobile SDK内部已实现从相机获取视频码流的功能,开发者可以根据Mobile SDK提供的开启相机码流、添加码流观察者来获取视频码流数据,然后自行实现数据解码和视频播放功能。也可以选择使用Autel_UX_SDK demo提供的VideoStreamPlayManager、VideoOpenGLView进行视频解码播放。本教程旨在帮助您基本了解 Mobile SDK 上述两种视频解码方式的实现.

2. 视频解码流程图

以下为UI层、视频播放业务、Mobile SDK之间的调用流程

视频解码流程

3. 视频解码API介绍

Mobile SDK视频解码功能主要集中在AUTELVideoFeed和AUTELVideoDataPacket两个类中.

AUTELVideoFeed主要提供开启、关闭码流功能,以及对码流添加或移除观察者。Mobile SDK会将每一帧码流数据分发给已添加的观察者.

3.1 开启监测相机码流

+ (void)openVideoFeed;

3.2 关闭监测相机码流

+ (void)closeVideoFeed

3.3 添加视频码流观察者

当Mobile SDK接收到视频码流后,分发给这些观察者.queue:Mobile SDK准备好码流数据包后,分发码流所在线程队列

+ (void)addVideoFeedListener:(id<AUTELVideoFeedListener>)listener withQueue:(dispatch_queue_t)queue;

3.4 移除视频码流观察者

移除后,不再分发视频码流给此观察者.

+ (void)removeVideoFeedListener:(id<AUTELVideoFeedListener>)listener;

3.5 码流数据回调

通过2.2.3 添加视频码流观察者后,需要在观察者所在类中实现码流回调API。以下为码流数据回调的API介绍

码流数据包更新回调

- (void)videoFeed:(AUTELVideoFeed *)feed didUpdateVideoData:(AUTELVideoDataPacket *)packet;

相机连接状态更新回调

由于所有视频码流数据来源于相机,所以相机断开连接后,就没有视频码流了。因此,我们需要监测相机的连接状态

- (void)videoFeed:(AUTELVideoFeed *)feed didUpdateConnecteState:(BOOL)state;

通过码流数据包回调方法,可以获取到视频码流数据AUTELVideoDataPacket以及相机的连接状态。开发者在获取到AUTELVideoDataPacket后进行解码和播放。

3.6 视频码流数据

AUTELVideoDataPacket是通过添加码流观察者后,Mobile SDK向上层回调的码流数据类,以下是对AUTELVideoDataPacket的属性说明。

@property (nonatomic, assign, readonly)uint8_t *data;// 获取当前帧的码流数据

@property (nonatomic, assign, readonly)size_t size; // 码流数据size大小

@property (nonatomic, assign, readonly)int64_t pts; // 获取当前帧的码流数据帧率

@property (nonatomic, assign, readonly)int32_t width; // 获取当前帧的码流数据(视频图片)宽

@property (nonatomic, assign, readonly)int32_t height; // 获取当前帧的码流数据(视频图片)高

@property (nonatomic, assign, readonly)int32_t keyFrame; // 是否是关键帧

@property (nonatomic, assign, readonly)AutelVideoEncodeFormat videoFormat; //H264编码格式、H265编码格式

- (instancetype)initWithData:(uint8_t *)data withSize:(size_t)size withPts:(int64_t)pts;
//为了支持H265增加,codeType定义见AutelVideoEncodeFormat
- (instancetype)initWithData:(uint8_t *)data withSize:(size_t)size withPts:(int64_t)pts encodeType: (int)codeType;
//为了支持H265增加,codeType定义见AutelVideoEncodeFormat
- (instancetype)initWithData: (uint8_t *)data
withwidth: (int32_t)width
withheight: (int32_t)height
withKeyFrame: (int32_t)keyFrame
withSize: (size_t)size
withPts: (int64_t)pts
encodeType: (int)codeType;

- (instancetype)initWithData:(uint8_t *)data;
//为了支持H265增加,codeType定义见AutelVideoEncodeFormat
- (instancetype)initWithData:(uint8_t *)data encodeType: (int)codeType;

通过上面的介绍,可以获取视频数据。如果开发者希望自己实现视频解码和播放,那么到这里就已经能达成目的。

4. 视频解码功能实现

下面以Autel_UX_SDK demo为例讲解如何进行视频解码和播放的功能开发。

在本例中,为方便视频解码功能开发,我们对底层Mobile SDK视频码流做了二次封装,主要涉及的类有VideoStreamPlayManagerVideoOpenGLView

  • VideoStreamPlayManager:开启码流、码流解码、视频帧播放功能的管理类。开发者只需要进行简单调用就能达到视频播放的效果。
  • VideoOpenGLView:支持openGL渲染的视频播放视图,只需要通过正常的系统创建并设置好布局即可。

上述类封装在AUTELWidget.framework动态库。

4.1 创建视频播放视图

lazy var videoPlayView : VideoOpenGLView = {
let view = VideoOpenGLView.init()
return view
}()
view.addSubview(videoPlayView)
videoPlayView.snp.makeConstraints { (make) in
make.edges.equalToSuperview()
}

4.2 开启视频播放

func startPlay() {
guard !self.isPlaySetup else {
return
}
self.isPlaySetup = true
print("VideoStreamPlayManager startPlay called")
VideoStreamPlayManager.sharedInstance().setPlayView(to: videoPlayView)
}

4.3 结束视频播放

func stopPlay() {
print("VideoStreamPlayManager stopPlay called")
VideoStreamPlayManager.sharedInstance().stopPlayAndRemoveView()
self.isPlaySetup = false
}

4.4 其他功能

  • 开启过爆提示

    视频画面过度曝光部分会被标识出来,显示在实时视频画面上

    VideoStreamPlayManager.sharedInstance().showOverExpose = true
  • 设置视频宽高比(变化)回调

    VideoStreamPlayManager.sharedInstance().ratioHandle = { [weak self] ratio in
    GCDUtils.main {
    self?.updatePlayerView(ratio)
    }
    }
  • 获取视频宽高size

    VideoStreamPlayManager.sharedInstance().renderAspectRatio