DJI SDK 文件相关操作的 API 简析

用大疆无人机拍摄完后,怎么少得了去查看一下自己的作品是否满意呢?这时候一个文件回看和管理的功能就至关重要了。本文主要就开发 DJIFileManger 中所涉及 DJI-SDK-iOS 的相关 API 进行简要的说明和分析。

1. 操作流程概览

首先我们要明确做一个文件回看和管理的功能有什么基本要素:

  • 缩略图
  • 预览图
  • 查看文件各种属性值
  • 下载原图或者原视频
  • 删除

明确了这几点后,我们就可以去 DJI-SDK API 文档 中查找相关的 API 了,也可以通过官方的一个 Demo 来窥探部分相关 API 的操作。这里我们根据相关的 API 可以得出这样的一个操作流程:

<div id="qa8kqf" data-type="puml" data-display="block" data-align="left" data-src="https://cdn.nlark.com/__puml/c842bda738e79bb90cda06010bc0af57.svg" data-width="429" data-height="470" data-text="%40startuml%0A%0Ausecase+(%E7%9B%B8%E6%9C%BA%E5%88%87%E6%8D%A2%E6%A8%A1%E5%BC%8F%E4%B8%BA+%5Cn+mediaDownload)+as+camera%0Ausecase+(%E8%8E%B7%E5%8F%96%E6%96%87%E4%BB%B6%E5%AD%98%E5%82%A8%E8%B7%AF%E5%BE%84)+as+storage%0Ausecase+%E5%88%B7%E6%96%B0%E6%96%87%E4%BB%B6%E5%88%97%E8%A1%A8+as+refresh%0Ausecase+(%E8%8E%B7%E5%8F%96%E6%96%87%E4%BB%B6%E5%88%97%E8%A1%A8%E5%BF%AB%E7%85%A7+%5Cn%EF%BC%88%E5%8D%B3+DJIMediaFile+%E7%9A%84%E6%95%B0%E7%BB%84%EF%BC%89)as+mediaFile%0Ausecase+(%E8%8E%B7%E5%8F%96%E6%96%87%E4%BB%B6%E7%BC%A9%E7%95%A5%E5%9B%BE+%5Cn+%E6%88%96%E9%A2%84%E8%A7%88%E5%9B%BE)+as+content%0Ausecase+(%E4%B8%8B%E8%BD%BD%E5%8E%9F%E6%96%87%E4%BB%B6)+as+download%0Ausecase+(%E5%88%A0%E9%99%A4%E5%8E%9F%E6%96%87%E4%BB%B6)+as+delete%0A%0Acamera+-down-%3E+storage%0Astorage+-down-%3E+refresh%0Arefresh+-down-%3E+mediaFile%0AmediaFile+-down-%3E+(content)%0AmediaFile+-down-%3E+(download)%0AmediaFile+-down-%3E+(delete)%0A%0A%40enduml"><img src="https://cdn.nlark.com/__puml/c842bda738e79bb90cda06010bc0af57.svg" width="429"/><div style="display:none">
<!-- source puml code:



usecase (相机切换模式为 \n mediaDownload) as camera
usecase (获取文件存储路径) as storage
usecase 刷新文件列表 as refresh
usecase (获取文件列表快照 \n(即 DJIMediaFile 的数组))as mediaFile
usecase (获取文件缩略图 \n 或预览图) as content
usecase (下载原文件) as download
usecase (删除原文件) as delete

camera -down-> storage
storage -down-> refresh
refresh -down-> mediaFile
mediaFile -down-> (content)
mediaFile -down-> (download)
mediaFile -down-> (delete)

-->
</div></div>

下面我会根据这个基本的流程来进行讲解。

2. 文件操作前置准备

2-1. 相机模式切换及文件存储路径

我们需要把相机的模式切换为 MediaDownload ,在此模式下我们才可以进行文件相关的操作。

// 获取相机
let camera = DJISDKManager.product()?.camera

// 切换相机模式
camera?.setMode(.mediaDownload) { error in
    // handle error
}

接着我们需要获取文件存储的路径,这里文件的存储路径有两种:SD卡和飞机内部存储。这里获取存储路径用到的 API 是 DJICamera 下的这个方法:

getStorageLocation(completion:  (DJICameraStorageLocation, Error?) -> Void)

它会返回一个 DJICameraStorageLocation 的枚举。接下来我们就可以利用这个存储路径去刷新文件列表,以及获取文件列表的快照了。

2-2. 刷新文件列表及获取文件列表快照

首先我们需要刷新在存储空间上的文件,以获得最新的文件列表,这里用到的 API 是 DJIMediaManager 下的这个方法:

func refreshFileList(of storageLocation: DJICameraStorageLocation, withCompletion completion: DJICompletionBlock? = nil)

该方法所需要的一个参数 storageLocation 就是上一节获取的存储路径。在这个方法的回调中,即刷新列表成功后,我们就可以获取到文件列表的快照(FileListSnapshot)了,注意应该根据文件存储位置的不同而选择调用 DJIMediaManager 的下面这两个方法:

sdCardFileListSnapshot()
internalStoragefileListSnapshot()

这两个方法从命名上可以看出返回的是一个文件列表的快照(FileListSnapshot),而实际上它们返回的都是一个 DJIMediaFile 的数组, DJIMediaFile 这个类定义了文件相关的各种信息,有了 DJIMediaFile 我们就可以获取文件的缩略图、预览图还有原图等等数据了。

3. 文件操作

3-1. 获取缩略图和预览图

对于相机拍摄的每一个文件, DJISDK 提供了四种类型数据:

  • 缩略图 thumbnail
  • 预览图 preview
  • 自定义信息 custom data
  • 原始数据 data

这些数据我们都可以通过上面获得的 DJIMediaFile 调用相关 API 来获取。

// 缩略图
fetchThumbnail(completion: DJICompletionBlock?)
// 预览图
fetchPreview(completion: DJICompletionBlock?)
// 自定义信息
fetchCustomInformation(completion: DJICompletionBlock?)
// 原始数据
fetchData(withOffset: UInt, update: DispatchQueue, update: (Data?, Bool, Error?) -> Void)

DJISDK 还提供了一个叫 DJIFetchMediaTaskSchedule 的东西来获取文件数据

注意: DJIFetchMediaTaskSchedule 并不能获取原始数据,要想获取原始数据必须用 DJIMediaFilefetchFileDataWithOffset:updateQueue:updateBlock 方法。

guard let mediaTaskScheduler = camera?.mediaManager.taskScheduler else { return }
// 设置为 fasle,当执行过程中出错时,mediaTaskScheduler 不会暂停,而继续执行队列里面的任务。
mediaTaskScheduler.suspendAfterSingleFetchTaskFailure = false
mediaTaskScheduler.resume(completion: nil)
let fetchTask = DJIFetchMediaTask(file: mediaFile, content: .thumbnail) {
    (mediaFile, fetchMediaTaskContent, error) in
    //... 
}
// moveTaskToEnd: 将任务放到队列末尾;moveTaskToNext:将任务放到队列开头
mediaTaskScheduler.moveTask(toEnd: fetchTask)

上面代码中的 .thumbnailDJIFetchMediaTaskContent 的枚举,它包含了缩略图,预览图和自定义信息,传入相应的枚举值就可以获取相应的数据。

3-2. 下载和删除文件

  • 下载原文件

下载原始文件,只有 DJIMeidaFilefetchFileDataWithOffset:updateQueue:updateBlock 方法。

var fileData = Data()
var previousDataOffset: UInt = 0
mediaFile.fetchData(withOffset: 0, update: DispatchQueue.main) { (data, isFinish, error) in
    if let error = error {
        print("fetch media error: " + error.localizedDescription)
    } else {
        if let data = data {
            fileData.append(data)
            previousDataOffset = previousDataOffset + UInt(data.count)
        }
        if previousDataOffset == UInt(mediaFile.fileSizeInBytes) && isFinish {
            completion(fileData)
        }
    }
}

updateQueue 指定了 updateBlock 在哪个队列中执行,updateBlock 会在执行过程中多次调用,在 updateBlock 中我们就可以做一些诸如前台显示下载进度的操作:

let progress = CGFloat(previousOffset) / CGFloat(mediaFile.fileSizeInBytes) 

DJIMediaFilefileSizeInBytes 属性可以获取源文件以字节为单位的大小,上面做一个除法就可以得到下载的进度值了。

当然,你也可以调用 DJIMediaFile 的下面这个方法来停止当前下载原文件的操作 :

stopFetchingFileData(completion: DJICompletionBlock?)
  • 删除文件

要想删除文件,只需要调用 DJIMediaManager 的这个方法:

delete(_ files: [DJIMediaFile], withCompletion completion: (([DJIMediaFile], Error?) -> Void)? = nil)

这个方法传入的参数是一个 DJIMediaFile 的数组。

3-3. 获取文件属性值

文件的相关属性值,都可以直接从 DJIMediaFile 上获取相关的属性,下面列出一些常用的属性:

fileName 文件名称
mediaType 文件类型(视频还是图片等等具体类型)
fileSizeInBytes 文件大小
timeCreated 文件创建时间
durationInSeconds 视频文件的时长
frameRate 帧率
resolution 分辨率

至此,一个基本的文件管理所需要的相关 API 就介绍完了,更详细的内容还请多查看 DJI-SDK API 文档 。由于笔者能力有限,文中如有错误还请各位读者不吝赐教。

© 著作权归作者所有
这个作品真棒,我要支持一下!
奇志技术团队博客 http://meshtech.co/
0条评论
top Created with Sketch.