因APP项目的的需求,需要用上腾讯视频的上传服务,其中需要用到官方提供的点播服务端SDK QCloudAPI
根据文档的说明,上传视频到点播服务需要三个步骤
上图为服务端上传流程示意图,主要有3个参与对象,分别是:
APP 服务器
腾讯云点播系统 VOD
腾讯云存储系统 COS。
官方文档
第一步:
APP 服务器向 VOD 发起上传
APP服务器将文件上传到 COS 前,需要知道目标 COS Bucket、路径等信息。
服务端向 VOD 发起上传,获取上传 COS 所需的信息。VOD 校验服务端的请求通过后为其分配上传信息。
服务端请求上传信息时,可以选择只上传视频(只请求视频文件的上传信息),或者同时上传视频和封面(同时请求视频文件和封面文件的上传信息)。
这一步主要是为了获取 bucketName , storagePath(用于发起上传) 以及 vodSessionKey(用于确认上传)
//发起上传 QCloudAPI qc = new QCloudAPI(); string vodresult = qc.Upload(localPath); //localPath为视频的本地地址 如"D:\video\hello.mp4" VODResultModel VODResultModel = JsonToModel(vodresult); string bucketName = VODResultModel.storageBucket; string storagePath = VODResultModel.video.storagePath;
QCloudAPI Upload方法
//发起上传 public string Upload(string fileName) { //COMMON_PARAMS公共参数 SortedDictionaryconfig = new SortedDictionary (StringComparer.Ordinal); config["SecretId"] = "SecretId"; config["SecretKey"] = "SecretKey"; config["RequestMethod"] = "GET"; config["DefaultRegion"] = "gzp"; //UploadCdnEntity SortedDictionary requestParams = new SortedDictionary (StringComparer.Ordinal); requestParams["videoName"] = fileName; requestParams["videoType"] = "mp4"; requestParams["procedure"] = "QCVB_SimpleProcessFile(0, 0, 10, 10)";//因为需求原因,需要做预处理,这里是获取视频每10%时间的十张截图 QCloudAPIModuleCenter module2 = new QCloudAPIModuleCenter(new Vod(), config); string result = module2.Call("ApplyUpload", requestParams); return result; }
第二步:APP 服务器向 COS 上传文件
APP 服务器根据之前发起上传时获取的上传信息,调用 COS 的上传接口完成文件上传。
//上传文件 CosDemo cd = new CosDemo(); string result = cd.CosUpload(localPath, storagePath, bucketName);
第三步:APP 服务器向 VOD 确认上传
APP 服务器成功上传文件到 COS 后,需要向 VOD 发起确认请求。收到确认上传的请求后,VOD 将返回视频的 fileId、视频播放地址、封面图片地址(如果有)等信息,
并按照用户的要求对上传后的视频进行转码、打水印、截图等操作
//确认上传 string vodSessionKet = VODResultModel.vodSessionKey; string commitresult = qc.CommitUpload(vodSessionKet); //commitresult包含了视频的 fileId、视频播放地址、封面图片地址(如果有)等信息,这里为了方便取值,转为了对象 CommitUploadModel CommitUploadModel = JsonToModel(commitresult);
CommitUpload方法
public string CommitUpload(string vodSessionKey) { SortedDictionaryconfig = new SortedDictionary (StringComparer.Ordinal); config["SecretId"] = "SecretId"; config["SecretKey"] = "SecretKey"; config["RequestMethod"] = "GET"; config["DefaultRegion"] = "gzp"; //CommitUpload SortedDictionary requestParams = new SortedDictionary (StringComparer.Ordinal); requestParams["vodSessionKey"] = vodSessionKey; //QCloudAPIModuleCenter module = new QCloudAPIModuleCenter(new Cdn(), config); QCloudAPIModuleCenter module2 = new QCloudAPIModuleCenter(new Vod(), config); string result = module2.Call("CommitUpload", requestParams); return result; }
至此,我们的视频成功的上传到了腾讯的视频服务了
如果需要获取我们之前预处理的截图,可以这样,这个时候我们需要上面返回给我们的 fileId 了
//获取视频信息/封面图 public string GetVideoInfo(string fileId ) { string videoinfo = ""; QCloudAPI qc = new QCloudAPI(); videoinfo = qc.GetVideoInfo(fileId); FileIdVideoInfoModel FileIdVideoInfoModel = JsonToModel(videoinfo); ; string cover = FileIdVideoInfoModel.sampleSnapshotInfo.sampleSnapshotList[0].imageUrls[1];//获取第二张截图 return cover; }
不过由于转码时间的原因,有时候截取的视频图片无法同步(短时间内)返回给我们,这个时候为了能百分百获取到截图,
我们可以在腾讯点播控制台设置一个上传完成后的一个回调地址(可设置指定回调事件),让腾讯主动告知我们。
不过其中 eventType=NewFileUpload 这个肯定会回调一次,这个是告知我们上传视频成功并返回视频信息,内容大概是这样(返回数据做了马赛克处理)
{ "version":"4.0", "eventType":"NewFileUpload", "data":{"status":0,"message":"","vodTaskId":"","fileId":"031868223255074086","fileUrl":"http://253935602.vod2.myqcloud.com/399e9e23vodgzp1253935602/db580b649031868223255074086/guaII6vn13oA.mp4","continued":0,"author":"","streamId":"","sourceType":"ServerUpload","sourceContext":""}}
我们是为了获取预处理后的截图,所以eventType=ProcedureStateChanged ,其中就包括了我们所需要截图信息,内容大概是这样(返回数据做了马赛克处理)
{ "version":"4.0", "eventType":"ProcedureStateChanged", "data": {"vodTaskId":"253935602-Procedure-c77ecebb964cc9bc51cdf8f434bac103","status":"FINISH","errCode":0,"fileId":"031868223273389931","metaData":{"height":272,"width":480,"bitrate":238702,"size":36268695,"container":"mov,mp4,m4a,3gp,3g2,mj2","md5":"","duration":1208,"videoStreamList":[{"bitrate":206648,"height":272,"width":480,"codec":"h264","fps":15}],"audioStreamList":[{"samplingRate":48000,"bitrate":32054,"codec":"aac"}]},"processTaskList":[{"taskType":"SampleSnapshot","status":"SUCCESS","message":"SUCCESS","errCode":0,"input":{"definition":10},"output":{"imageUrls":["http://253935602.vod2.myqcloud.com/edc640cbvodtransgzp1253935602/20fbb18c9031868223273389931/snapshot/1506425134_2310883639.100_0.jpg", "http://253935602.vod2.myqcloud.com/edc640cbvodtransgzp1253935602/20fbb18c9031868223273389931/snapshot/1506425134_2310883639.100_120800.jpg", "http://253935602.vod2.myqcloud.com/edc640cbvodtransgzp1253935602/20fbb18c9031868223273389931/snapshot/1506425134_2310883639.100_241600.jpg", "http://253935602.vod2.myqcloud.com/edc640cbvodtransgzp1253935602/20fbb18c9031868223273389931/snapshot/1506425134_2310883639.100_362400.jpg", "http://253935602.vod2.myqcloud.com/edc640cbvodtransgzp1253935602/20fbb18c9031868223273389931/snapshot/1506425134_2310883639.100_483200.jpg", "http://253935602.vod2.myqcloud.com/edc640cbvodtransgzp1253935602/20fbb18c9031868223273389931/snapshot/1506425134_2310883639.100_604000.jpg", "http://253935602.vod2.myqcloud.com/edc640cbvodtransgzp1253935602/20fbb18c9031868223273389931/snapshot/1506425134_2310883639.100_724800.jpg", "http://253935602.vod2.myqcloud.com/edc640cbvodtransgzp1253935602/20fbb18c9031868223273389931/snapshot/1506425134_2310883639.100_845600.jpg", "http://253935602.vod2.myqcloud.com/edc640cbvodtransgzp1253935602/20fbb18c9031868223273389931/snapshot/1506425134_2310883639.100_966400.jpg", "http://253935602.vod2.myqcloud.com/edc640cbvodtransgzp1253935602/20fbb18c9031868223273389931/snapshot/1506425134_2310883639.100_1087200.jpg"]}}, {"taskType":"CoverBySnapshot", "status":"SUCCESS", "message":"SUCCESS", "errCode":0, "input":{"definition":10,"positionType":"Time","position":0}, "output":{"imageUrl":"http://253935602.vod2.myqcloud.com/edc640cbvodtransgzp1253935602/20fbb18c9031868223273389931/coverBySnapshot/1506425134_3617383195.100_0.jpg"}}]}}
其中CallBack方法
[HttpPost] public string CallBack() { Stream postData = Request.InputStream; StreamReader sRead = new StreamReader(postData); string postContent = sRead.ReadToEnd(); sRead.Close(); CallBackModel CallBackModel = JsonToModel(postContent); if (CallBackModel != null && CallBackModel.eventType == "ProcedureStateChanged" { Platform_SpiderContentModel model = Platform_SpiderContentService.GetModelByWhere("FileId='" + CallBackModel.data.fileId+"'"); model.Cover = CallBackModel.data.processTaskList[0].output.imageUrls[1].Replace(" ",""); } return "ok"; }
CommitUploadModel实体类
public class CommitUploadModel { public int code { get; set; } public string message { get; set; } public string codeDesc { get; set; } public MyVideo video { get; set; } public string fileId { get; set; } } public class MyVideo { //视频地址 public string url { get; set; } public string verify_content { get; set; } }