菜单 学习猿地 - LMONKEY

VIP

开通学习猿地VIP

尊享10项VIP特权 持续新增

知识通关挑战

打卡带练!告别无效练习

接私单赚外块

VIP优先接,累计金额超百万

学习猿地私房课免费学

大厂实战课仅对VIP开放

你的一对一导师

每月可免费咨询大牛30次

领取更多软件工程师实用特权

入驻
0
0

Laravel 服务提供者业务使用实例

原创
05/13 14:22
阅读数 388

开始动工吧

改动之前

在正式开始之前,我觉得有必要稍微花一点点时间看一下改动之前的调用方式,以便可以全面的了解一下,如果不感兴趣的可以直接跳过~

public function transcodeVideo(){
    //这里对参数内容进行了简化,关注流程就好:)
    $url = $this->url;  
    //调用七牛的转码服务
    return FileService::getInstance()->transcodeVideo($url,callback?mid=".$this->id);
}

//调用七牛的转码服务,一开始是考虑直接改这个方法,当然这么做也确实可以。
public function transcodeVideo($video,$callback_url){
    Log::info(__CLASS__.'transcodeVideo param:',compact('video','callback_url'));
    $auth = new Auth(env('QINIU_ACCESSKEY'), env('QINIU_SECRETKEY'));
    $c = new \Qiniu\Processing\PersistentFop($auth);  
    $ret = $c->execute(env('QINIU_BUCKET'),$video,'avthumb/mp4/vcodec/libx264/s/720x720/autoscale/1|saveas/'.\Qiniu\base64_urlSafeEncode(env('QINIU_BUCKET').':'.md5($video).'.mp4'),'video1',$callback_url,true);
    Log::info(__CLASS__.'.transcodeVideo ret:',$ret);
    if(is_array($ret) && count($ret) > 0) {
        return true;
    }else{
        return false;
    }
}

其实有一个问题就是,因为项目肯定不止一个人在用到这个功能,所以调用方也是五花八门的,不全局搜索一下,你都不知道有多少个人在使用这个功能,所以我们做一个统一入口是很有必要的。

改动之后

首先我们注册一个视频转码的服务提供者,具体怎么创建大家可以参考官方文档,有很详细的介绍,这里就不再多说了。

public function register()
{
    //如果要换其他的服务方,直接把匿名函数中的类改一下就好了
    $this->app->singleton(VideoTranscodeService::class, function($app){
        return new \Aliyun\VideoTranscodeService();
    });
}

那么我们看到了,如果要实现这个服务,我们需要构建的基础代码结构:

1. 定义抽象父类: VideoTranscodeService

2. 定义七牛实现: Qiniu\VideoTranscodeService

3. 定义阿里云实现: Aliyun\VideoTranscodeService

下面附上实现代码,有相关业务需求的同学也可以参考一下。

抽象父类:

abstract class VideoTranscodeService{

    protected $sourceUrl = '';
    protected $extra = [];
    protected $scene = '';

    /**
     * 提交转码作业
     * @param string $scene         场景
     * @param string $sourceUrl     源文件地址
     * @param array $extra          额外数据
     * @return mixed
     * @throws BusinessException
     */
    public function videoTranscode($scene, $sourceUrl = '', $extra = [])
    {
        Log::info(__CLASS__.'.videoTranscode param:', compact('scene', 'sourceUrl','extra'));

        if(!$scene) {
            Log::warning(__CLASS__.'.videoTranscode loss scene');
            throw new BusinessException('缺少场景',Error::INVALID_PARAM);
        }

        if(!$sourceUrl) {
            Log::warning(__CLASS__.'.videoTranscode loss sourceUrl');
            throw new BusinessException('缺少源文件地址',Error::INVALID_PARAM);
        }

        $this->scene = $scene;
        $this->sourceUrl = $sourceUrl;
        $this->extra = $extra;

        return call_user_func([$this, $this->scene]);
    }

    /**
     * @param $func
     * @param $arg
     * @throws BusinessException
     */
    public function __call($func = '', $arg = []){
        Log::warning(__CLASS__ . $func . ' function not Exists');
        throw new BusinessException('访问不存在的方法', Error::INVALID_PARAM);
    }

    /**
     * 根据源文件地址,生成转码后地址
     * @param string $sourceUrl
     * @return mixed
     */
    abstract public function makeCompressUrl($sourceUrl);

    /**
     * 根据视频地址,生成封面图地址
     * @param $videoUrl
     * @return mixed
     */
    abstract public function makeCoverImg($videoUrl);

}

七牛转码服务:

class VideoTranscodeService extends  TranscodeService{

    /**
     * 视频转码
     * @param string $sourceUrl
     * @param array $extra
     * @return bool
     * @throws BusinessException
     */
    protected function interaction(){
        Log::info(__CLASS__.'.interaction param:', [$this->sourceUrl, $this->extra]);

        $callbackUrl = $this->makeCallbackUrl($this->extra['id']);

        return $this->submitTranscodeJob($callbackUrl);
    }

    /**
     * 提交转码作业
     * @param $video
     * @param $callbackUrl
     * @return bool
     */
    protected function submitTranscodeJob($callbackUrl = ''){
        //源文件
        $video = basename($this->sourceUrl);

        //认证
        $auth = new Auth(env('QINIU_ACCESSKEY'), env('QINIU_SECRETKEY'));
        $c = new \Qiniu\Processing\PersistentFop($auth);

        //输出(转码)地址
        $output = VideoTranscodeConf::$videoPath[$this->scene]['output'].md5($video).'.mp4';
        $saveAs = \Qiniu\base64_urlSafeEncode(env('QINIU_BUCKET').':'.$output);
        $fops = 'avthumb/mp4/vcodec/libx264/s/720x720/autoscale/1|saveas/'. $saveAs;

        //提交转码作业
        $ret = $c->execute(env('QINIU_BUCKET'),$video,$fops,'video1',$callbackUrl,true);
        Log::info(__CLASS__.'.submitTranscodeJob ret:',$ret);

        if (is_array($ret) && count($ret) > 0) {
            return true;
        }else{
            return false;
        }
    }

    //生成七牛回调地址
    protected function makeCallbackUrl($extra){
        $data = $this->scene.'#'.$extra;
        return route('qiniuCallback',['data' => $data]);
    }

    /**
     * 根据源文件地址,生成转码后地址
     * @param string $sourceUrl
     * @return mixed|string
     * @throws BusinessException
     */
    public function makeCompressUrl($sourceUrl = ''){
        if(!$sourceUrl) {
            Log::warning(__CLASS__.'.makeCompressUrl sourceName Not Exists');
            throw new BusinessException('源文件地址错误',Error::INVALID_PARAM);
        }
        return env('QINIU_HOST')."/".md5(basename($sourceUrl)).".mp4";
    }

    /**
     * 根据视频地址,生成封面图地址
     * @param $videoUrl
     * @return string
     */
    public function makeCoverImg($videoUrl){
        return $videoUrl.'?vframe/jpg/offset/0';
    }
}

阿里云转码服务:

class VideoTranscodeService extends TranscodeService{

    /**
     *
     * VideoTranscodeService constructor.
     * @throws ClientException
     */
    public function __construct(){
        AlibabaCloud::accessKeyClient(AliyunConf::VIDEO_ACCESS_KEY, AliyunConf::VIDEO_ACCESS_KEY_SECRET)
            ->regionId(env('ALIYUN_VIDEO_REGION'))
            ->asGlobalClient();
    }

    /**
     * 视频转码
     * @param string $sourceUrl         输入视频地址 
     * @param array $extra              额外配置参数: id、 width(视频宽度)
     * @return bool                     请求结果,仅代表请求是否成功,不代表最终转码结果
     * @throws BusinessException
     * @throws ClientException
     * @throws ServerException
     */
    protected function interaction(){
        Log::info(__CLASS__.'.interaction param:', [$this->sourceUrl,$this->extra]);

        $ossLocation = env('ALIYUN_VIDEO_BUCKET_LOCATION');
        $ossBucket = env('ALIYUN_VIDEO_BUCKET_NAME');
        $userData = 'interaction#'.$this->extra['id'];
        $templateId = $this->getTemplate($this->extra['width']);

        $input = [
            'Location' => $ossLocation,
            'Bucket' => $ossBucket,
            'Object' => urlencode($this->makeInputObject())
        ];

        $outputs = [[
            'OutputObject' => urlencode($this->makeOutputObject()),
            'Container' => ['Format' => AliyunConf::VIDEO_TRANSCODE_FORMAT],
            'TemplateId' => $templateId,
            'UserData' => $userData
        ]];

        return $this->submitTranscodeJob($input, $outputs, $ossLocation, $ossBucket);
    }

    /**
     * 提交转码作业
     * @param $input
     * @param $outputs
     * @param string $ossLocation
     * @param string $ossBucket
     * @return bool
     * @throws ClientException
     * @throws ServerException
     */
    protected function submitTranscodeJob($input, $outputs, $ossLocation = '', $ossBucket = ''){
        $result = AlibabaCloud::mts()
            ->v20140618()
            ->submitJobs()
            ->setAcceptFormat('JSON')
            ->withInput(json_encode($input))
            ->withOutputs(json_encode($outputs))
            ->withOutputBucket($ossBucket)
            ->withOutputLocation($ossLocation)
            ->withPipelineId(env('ALIYUN_VIDEO_TRANSCODE_PIPELINE'))
            ->request();

        return $result->isSuccess();
    }

    /**
     * 根据源文件名称,生成转码后地址(主要用作于类外直接调用)
     * @param string $sourceUrl     转码前源文件名称  
     * @return string               转码后URL地址    
     * @throws BusinessException
     */
    public function makeCompressUrl($sourceUrl = ''){
        if(!$sourceUrl) {
            Log::warning(__CLASS__.'.makeCompressUrl sourceName Not Exists');
            throw new BusinessException('源文件地址错误',Error::INVALID_PARAM);
        }
        $inputFile = basename($sourceUrl);
        $outputObject = $this->makeOutputObject($inputFile);
        return env('ALIYUN_VIDEO_BUCKET_URL').$outputObject;
    }

    /**
     * 根据视频地址,生成封面图地址
     * @param $videoUrl
     * @return string
     */
    public function makeCoverImg($videoUrl){
        return $videoUrl.'?x-oss-process=video/snapshot,t_0,w_0,h_0,m_fast';
    }

    /**
     * 生成输出文件bucket地址
     * @param $inputFile string 输入文件 -用于类外部直接调用makeCompressUrl时生成的路径
     * @return string
     * @throws BusinessException
     */
    protected function makeOutputObject($inputFile = ''){
        if (isset(VideoTranscodeConf::$videoPath[$this->scene]['output'])) {
            if (!$inputFile) {
                $inputFile = basename($this->sourceUrl);
            }

            return VideoTranscodeConf::$videoPath[$this->scene]['output'].md5($inputFile).'.'. AliyunConf::VIDEO_TRANSCODE_FORMAT;
        }else{
            Log::error(__CLASS__.'.makeOutputObject outputpath not config');
            throw new BusinessException('缺少输出配置文件', Error::INVALID_PARAM);
        }
    }

    /**
     * 生成输入文件bucket地址
     * @return string
     * @throws BusinessException
     */
    protected function makeInputObject(){
        if (isset(VideoTranscodeConf::$videoPath[$this->scene]['input'])) {
            return VideoTranscodeConf::$videoPath[$this->scene]['input'].basename($this->sourceUrl);
        } else {
            Log::error(__CLASS__.'.makeInputObject inputpath not config');
            throw new BusinessException('缺少输入配置文件', Error::INVALID_PARAM);
        }
    }

    /**
     * 根据宽度定义转码模板
     * @param int $width
     * @return string
     */
    protected function getTemplate($width = 0){
        if($width > 1280) {
            $templateId = AliyunConf::VIDEO_TRANSCODE_HD;   //高清
        }else{
            $templateId = AliyunConf::VIDEO_TRANSCODE_SD;   //标清
        }
        return $templateId;
    }
}

这样我们的服务就写好了,在业务代码中只需要调用下面代码即可完成视频的转码,而不需要关注第三方的服务到底是谁。(代码中隐藏了部分参数配置信息,但不影响整体流程)

app(VideoTranscodeService::class)->videoTranscode('interaction', $this->url, $extra);

发表评论

0/200
0 点赞
0 评论
收藏
为你推荐 换一批