因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公共参数
            SortedDictionary config = 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)
        {
            SortedDictionary config = 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; }
    }