七牛云上传视频并转码

时间:2024-04-16 21:40:33

概述:

很多用户使用七牛的云存储服务,存放很多mp4文件到七牛的存储空间,但是通过复制外链,然后在浏览器中播放,经常会遇到“只有音频,没有视频”的情况;
其实这个不是七牛的存储有问题,而是视频的编码方式,浏览器不支持,如:MPEG-4 在googel Chrome 、IE这些浏览器中都是不支持视频播放的,但通过苹果的Safari浏览器是能正常播放的;

思路:
1.上传一个视频到七牛的空间,然后再进行转码操作;
2,上传的同时指定预处理操作,进行转码处理后,上传;
3.查看七牛的avthumb接口说明和支持的编码说明,链接如下:
http://developer.qiniu.com/code/v6/api/dora-api/av/avthumb.html
https://support.qiniu.com/hc/kb/article/182142/?from=draft

第一种方法,代码示例如下:

package com.qiniu.dora;

import com.qiniu.base.AccountMgr;
import com.qiniu.common.QiniuException;
import com.qiniu.common.Zone;
import com.qiniu.processing.OperationManager;
import com.qiniu.storage.Configuration;
import com.qiniu.util.Auth;
import com.qiniu.util.StringMap;
import com.qiniu.util.UrlSafeBase64;

/**
 * 很多浏览器不支持 MPEG-4编码的视频,所以上传到七牛,用类似google 这样的浏览器是不能正常播放的,只有音频,没有视频
 * 所以可以使用七牛的转码接口
 * 
 * @author xuhuanchao
 *
 */
public class AVthumbForMpeg4 {

    //获取授权对象
    Auth auth = Auth.create(AccountMgr.ACCESS_KEY, AccountMgr.SECRET_KEY);
    //执行操作的管理对象
    OperationManager operationMgr = new OperationManager(auth, new Configuration(Zone.zone0()));
    /**
     * Test Method
     * @param args
     */
    public static void main(String[] args) {
        new AVthumbForMpeg4().transcoding();
    }
    /**
     * 转码
     */
    void transcoding() {
        String bucket = "java-bucket";          //存储空间名称
        String key = "mpeg_4_type.mp4";         //存储空间中视频的文件名称
        String newKey = "H264_type.mp4";        //转码后,另存的文件名称
        String pipeline = "admin_merge_radio";  //处理队列

        String saveAs = UrlSafeBase64.encodeToString(bucket + ":" + newKey);        //saveas接口 参数
        String fops = "avthumb/mp4/vcodec/libx264|saveas/" + saveAs;                //处理命令 avthumb 和 saveas 通过管道符 |  进行连接

        try {
            //执行转码和另存 操作
            String persistentId = operationMgr.pfop(bucket, key, fops, new StringMap().put("persistentPipeline", pipeline));
            System.out.println(persistentId);
        } catch (QiniuException e) {
            String errorCode = String.valueOf(e.response.statusCode);
            System.out.println(errorCode);
            e.printStackTrace();
        }
    }  
}

第二种方法,代码示例如下:

import com.qiniu.util.Auth;
import com.qiniu.util.StringMap;
import com.qiniu.util.UrlSafeBase64;

import java.io.IOException;

import com.qiniu.common.QiniuException;
import com.qiniu.http.Response;
import com.qiniu.storage.UploadManager;

public class UploadDemo {
  //设置好账号的ACCESS_KEY和SECRET_KEY
  String ACCESS_KEY = "Access_Key";
  String SECRET_KEY = "Secret_Key";
  //要上传的空间
  String bucketname = "Bucket_Name";
  //上传到七牛后保存的文件名
  String key = "my-java.png";
  //上传文件的路径
  String FilePath = "/.../...";

  //设置转码操作参数
  String fops = "avthumb/mp4/s/640x360/vb/1.25m";
  //设置转码的队列
  String pipeline = "yourpipelinename";

  //可以对转码后的文件进行使用saveas参数自定义命名,当然也可以不指定文件会默认命名并保存在当前空间。
  String urlbase64 = UrlSafeBase64.encodeToString("目标Bucket_Name:自定义文件key");
  String pfops = fops +"|saveas/"+ urlbase64;

  //密钥配置
  Auth auth = Auth.create(ACCESS_KEY, SECRET_KEY);
  //创建上传对象
  UploadManager uploadManager = new UploadManager();

  //上传策略中设置persistentOps字段和persistentPipeline字段
  public String getUpToken(){
      return auth.uploadToken(bucketname,null,3600,new StringMap()
          .putNotEmpty("persistentOps", pfops)
          .putNotEmpty("persistentPipeline", pipeline), true);
  }

  public void upload() throws IOException{
    try {
      //调用put方法上传
      Response res = uploadManager.put(FilePath, null, getUpToken());
      //打印返回的信息
      System.out.println(res.bodyString()); 
      } catch (QiniuException e) {
          Response r = e.response;
          // 请求失败时打印的异常的信息
          System.out.println(r.toString());
          try {
              //响应的文本信息
            System.out.println(r.bodyString());
          } catch (QiniuException e1) {
              //ignore
          }
      }       
  }

  public static void main(String args[]) throws IOException{  
    new UploadDemo().upload();
  }

}


注:上面的Demo只是针对视频转码,如果需要别的功能比如音视频切片、视频截图、视频拼接只需要修改下上面的fops后面的参数就可以了,
eg: fops = "vframe/jpg/offset/1/w/480/h/360/rotate/90"就表示视频截图了。
下面给出一些常见的数据处理功能,可以根据需要进行选择:
//------------------图片缩放-------------------
fops ="imageView/2/w/200/h/200";

//------------------视频转码-------------------
// fops ="avthumb/flv/vb/229k/vcodec/libx264/noDomain/1";

//------------------图片水印-------------------
String pictureurl = UrlSafeBase64.encodeToString("http://developer.qiniu.com/resource/logo-2.jpg");
fops = "watermark/1/image/" + pictureurl;

//------------------视频切片-------------------
fops = "avthumb/m3u8";
//切片与加密参数
fops = "avthumb/m3u8/vb/640k/hlsKey/MDEyMzQ1Njc4OTEyMzQ1Ng==/hlsKeyUrl/aHR0cDovLzd4bGVrYi5jb20yLnowLmdsYi5xaW5pdWNkbi5jb20vcWluaXV0ZXN0LmtleQ==";

//------------------文档转换-------------------
fops = "yifangyun_preview";

//------------------视频截图-------------------
fops = "vframe/jpg/offset/1/w/480/h/360/rotate/90";

//------------------视频拼接-------------------
//拼接视频片段时要保证所有源的画面长宽值一致
//除去作为数据处理对象的源文件以外,还可以指定最多5个源文件(即总计6个片段)
//所有源文件必须属于同一存储空间
//格式:avconcat/<Mode>/format/<Format>/<encodedUrl0>/<encodedUrl1>/<encodedUrl2>/...
String encodedUrl1 = UrlSafeBase64.encodeToString("http://7xl4c9.com1.z0.glb.clouddn.com/pingjie2.flv");
String encodedUrl2 = UrlSafeBase64.encodeToString("http://7xl4c9.com1.z0.glb.clouddn.com/pingjie3.avi");
fops = "avconcat/2/format/mp4/"+encodedUrl1+encodedUrl2;

//------------------多文件压缩-------------------
//可将若干七牛空间中的资源文件,在七牛服务端压缩后存储
//格式:mkzip/<mode>/url/<Base64EncodedURL>/alias/<Base64EncodedAlias>/url/<Base64EncodedURL>
String encodedfile1 = UrlSafeBase64.encodeToString("http://7xl4c9.com1.z0.glb.clouddn.com/photo1.jpg");
String encodedfile2 = UrlSafeBase64.encodeToString("http://7xl4c9.com1.z0.glb.clouddn.com/vedio1.mp4");
String encodedfile3 = UrlSafeBase64.encodeToString("http://7xl4c9.com1.z0.glb.clouddn.com/audio1.mp3");
fops = "mkzip/2/url/"+encodedfile1+"url/"+encodedfile2+"url/"+encodedfile3;

补充说明案例:

页面ajax

 <input type="file" class="form-control" name="file" id="filedata" placeholder="upload"
      style="margin-bottom:5px;">
 <button onclick="uploadfile(this);">上传视频文件</button>
 <input type="hidden" class="form-control" name="videoUrl" id="urlId" placeholder="请输入视频链接"
        style="margin-bottom:5px;">
 <span id="isfile"></span>
 <div id="successAlertFile" class="alert alert-success"
      style="display:none;">
     <span id="successAlertFile_msg"></span>
 </div>
                

function uploadfile(el) {
        var formData = new FormData();
        var file = $(el).siblings().filter(\'#filedata\').prop(\'files\')[0];
        formData.append("file", $(el).siblings().filter(\'#filedata\').prop(\'files\')[0]);
        if(file != null && file != \'\'){
            if (file.size < 104857600) {
                $.ajax({
                    url: \'${s.base}/video/upload.html\',
                    type: \'POST\',
                    data: formData,
                    processData: false, // 不要对data参数进行序列化处理,默认为true
                    contentType: false, // 不要设置Content-Type请求头,因为文件数据是以 multipart/form-data 来编码
                    xhr: function () {
                        myXhr = $.ajaxSettings.xhr();
                        if (myXhr.upload) {
                            myXhr.upload.addEventListener(\'progress\', function (e) {
                                if (e.lengthComputable) {
                                    var percent = Math.floor(e.loaded / e.total * 100);
                                    $(el).siblings().filter(\'#isfile\').html(percent.toString() + \'%\');
                                    if (percent == 100) {
                                        $(el).siblings().filter(\'#isfile\').html("正在上传:" + "<img src=\'${s.base}/res/i/loading.gif\'/>");
                                    }
                                }
                            }, false);
                        }
                        return myXhr;
                    },
                    success: function (respText) {
                        var resp = $.parseJSON(respText);
                        if (resp.errcode == 0) {
                            console.log(resp,"---success----");
                            $(el).siblings().filter(\'#isfile\').html(\'\');
                            $(el).siblings().filter(\'#successAlertFile\').show().fadeOut(3000);//显示模态框
                            $(el).siblings().filter(\'#successAlertFile\').children().css(\'color\', \'green\').html(\'上传成功!\');
                            $(el).siblings().filter(\'#urlId\').val(resp.data.path);
                        } else {
                            $(el).siblings().filter(\'#successAlertFile\').show().fadeOut(3000);
                            $(el).siblings().filter(\'#successAlertFile\').children().css(\'color\', \'red\').html(\'文件名称重复,请重新上传!\');
                            $(el).siblings().filter(\'#isfile\').html(\'\');
                        }
                    },
                    error: function (res) {
                        // 请求失败
                        console.log(res);
                        $(el).siblings().filter(\'#successAlertFile\').show().fadeOut(3000);
                        $(el).siblings().filter(\'#successAlertFile\').children().css(\'color\', \'red\').html(\'上传失败,请重新上传!\');
                        $(el).siblings().filter(\'#isfile\').html(\'\');
                    }
                });
            } else {
                $(el).siblings().filter(\'#successAlertFile\').show().fadeOut(3000);
                $(el).siblings().filter(\'#successAlertFile\').children().css(\'color\', \'red\').html(\'上传视频不能大于100MB!\');
            }
        } else {
            $(el).siblings().filter(\'#successAlertFile\').show().fadeOut(3000);
            $(el).siblings().filter(\'#successAlertFile\').children().css(\'color\', \'red\').html(\'上传视频不能为空!\');
        }
        /* var demo =  $(el).siblings().filter(\'#urlId\').val()
         console.log(demo,"----demo---")*/
    }

controller

  package com.online.college.opt.controller;

import com.online.college.common.storage.QiniuStorage;
import com.online.college.common.web.JsonView;
import com.online.college.core.consts.domain.CollegeClassTeacher;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.commons.CommonsMultipartFile;
import org.springframework.web.servlet.ModelAndView;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

/**
 * @Author: LBX
 * @Date: 2018/12/24 14:07
 */
@Controller
@RequestMapping("/video")
public class UploadFileController {

    @RequestMapping("/upload")
    @ResponseBody
    public String upload(@RequestParam("file") CommonsMultipartFile picture){
        Map<String,Object> map = new HashMap<>();
        if (null != picture && picture.getBytes().length > 0) {
            String key = QiniuStorage.uploadVideo(picture);
            map.put("key",key);
        }
        return JsonView.render(map);
    }
}

service

	 /**
	 * 上传视频
	 * @param picture
	 */
	public static String uploadVideo(CommonsMultipartFile picture){
		String key = QiniuKeyGenerator.generateKey();
		key = QiniuWrapper.uploadVideo(picture, key);
		return key;
	}

serviceimpl

  /**
     * 上传视频
     *
     * @return
     */
    public static String uploadVideo(CommonsMultipartFile picture, String key) {
        DiskFileItem diskFileItem = (DiskFileItem) picture.getFileItem();
        File file = diskFileItem.getStoreLocation();
        try {
            String fileName = picture.getOriginalFilename();
            //设置转码操作参数
            String fops = "avthumb/mp4/vcodec/libx264";
            //可以对转码后的文件进行使用saveas参数自定义命名,当然也可以不指定文件会默认命名并保存在当前空间。
            String urlbase64 = UrlSafeBase64.encodeToString(bucketName + ":" + fileName + ".mp4");
            String pfops = fops + "|saveas/" + urlbase64;
            String upToken = auth.uploadToken(bucketName, null, 3600, new StringMap().putNotEmpty("persistentOps", pfops));
            key = key + ".mp4";
            //调用put方法上传
            Response response = uploadManager.put(file, key, upToken);
            //打印返回的信息
            System.out.println("-----success---" + response.bodyString());
            DefaultPutRet ret = response.jsonToObject(DefaultPutRet.class);
            return ret.key;
        } catch (QiniuException e) {
            logger.error("upload file to qiniu cloud storage failed", e);
        }
        return null;
    }