zoukankan      html  css  js  c++  java
  • 视频切片上传

    视频上传属于大文件上传啊 直接上传很浪费时间 和占内存所以使用切片上传比较好

    前断上传插件 我使用的是zui 自带切片上传

    <div class="layui-form-item">
    <label class="layui-form-label"><span class="red">•</span> 视频文件:</label>
    <div class="layui-input-block">
    <div id="uploaderVideo" class="uploader" style="margin-bottom:0;">
    <div class="file-list" data-drag-placeholder="视频上传只支持mp4格式"></div>
    <button type="button" class="btn btn-primary uploader-btn-browse"><i
    class="icon icon-cloud-upload"></i> 选择文件
    </button>
    </div>
    </div>
    </div>
    <input type="hidden" name="chunk_uuid" id="chunk_uuid" value=""/>
    <input type="hidden" name="video_name_raw" id="video_name_raw" value=""/>
    <input type="hidden" name="video_name" id="video_name" value=""/>
    $('#uploaderVideo').uploader({
    autoUpload: true,
    multi_selection: false,
    chunk_size: '2m',
    url: '/upload/uploadVideoChunk',
    onBeforeUpload: function (file) {
    if ($.trim($('#chunk_uuid').val()).length > 0) {
    redTip('只能上传一个文件');
    this.removeFile(file);
    this.stop();
    }
    },
    onChunkUploaded: function (file, responseObject) {
    var jn = $.parseJSON(responseObject.response);
    console.log('上传进度:' + jn.d.chunk + '/' + jn.d.chunks);
    },
    onFileUploaded: function (file, responseObject) {
    var jn = $.parseJSON(responseObject.response);
    //记录uuid
    $('#chunk_uuid').val(jn.d.chunk_uuid);
    $('#video_name_raw').val(jn.d.name);
    //自动填写视频名称
    var video_name = $.trim($('#video_name').val());
    if (video_name.length < 1) {
    $('#video_name').val(jn.d.name);
    }
    },
    responseHandler: function (responseObject, file) {
    console.log('ok');
    }
    });

    这个是js的使用代码,自带切片功能

    上传的参数
    chunk:表示现在 正在上传第几片切片
    chunks:表示总共切片多少分
    uuid:代表上传的别名,可以作为独一的存储地址
    file:代表上传的文件
    前端是比较简单的 主要是服务端代码
    $now_chunk = $request->post('chunk');
    $now_chunk = intval($now_chunk);
    $chunk_total = $request->post('chunks');
    $chunk_total = intval($chunk_total);
    $name = $request->post('name');
    $uuid = $request->post('uuid');

    if ($now_chunk < 0) {
    return rs(Code::VIDEO_UPLOAD_CHUNK_ERROR, m(Code::VIDEO_UPLOAD_CHUNK_ERROR));
    }
    if ($chunk_total < 1) {
    return rs(Code::VIDEO_UPLOAD_CHUNK_ERROR, m(Code::VIDEO_UPLOAD_CHUNK_ERROR));
    }
    if ($uuid == '') {
    return rs(Code::VIDEO_UPLOAD_UUID_ERROR, m(Code::VIDEO_UPLOAD_UUID_ERROR));
    }

    if (!$request->hasFile('file')) {
    return rs(Code::VIDEO_UPLOAD_FILE_ERROR, m(Code::VIDEO_UPLOAD_FILE_ERROR));
    }

    if (!$request->file('file')->isValid()) {
    return rs(Code::VIDEO_UPLOAD_FILE_ERROR, m(Code::VIDEO_UPLOAD_FILE_ERROR));
    }

    $year = date('Y');

    //上传文件
    $request->file('file')->storePubliclyAs($this->baseDirOfVideoChunk() . '/' . $year . '/' . $uuid, $now_chunk);

    //保存到session中
    $key = 'video_upload_' . $uuid;
    if (session()->exists($key)) {
    $one = session()->get($key);
    $one['chunk_ok'][] = $now_chunk;
    } else {
    $one = [
    'uuid' => $uuid,
    'name' => $name,
    'chunk_total' => $chunk_total,
    'chunk_ok' => [$now_chunk]
    ];
    }
    session()->put($key, $one);
    session()->save();

    $one = session()->get($key);
    if ($one['chunk_total'] === count($one['chunk_ok'])) {
    //上传完毕
    session()->forget($key);
    return rs(Code::OK, m(Code::OK), ['finish' => 'yes', 'name' => $name, 'chunks' => $chunk_total, 'chunk' => ($now_chunk + 1), 'chunk_uuid' => $year . '/' . $uuid]);
    } else {
    //上传未完成
    return rs(Code::OK, m(Code::OK), ['finish' => 'no', 'name' => $name, 'chunks' => $chunk_total, 'chunk' => ($now_chunk + 1), 'chunk_uuid' => $year . '/' . $uuid]);
    }

    这个只是简单的上传代码接受切片文件(因使用laravel框架,所以内置方法都是laravel的内置方法)
    上传结束后 就是合并上传文件

    $video = $this->getVideoData(['cook_st' => Vars::VIDEO_COOK_ST_MERGE_WAIT, 'merge_times_lt' => Vars::MAX_MERGE_AND_CUT_TIMES], '', 1, 1);
    if (empty($video)) {
    return rs(Code::OK, m(Code::OK));
    }
    $video = $video[0];
    $video_id = $video['video_id'];

    VideoModel::getInstance()->incField(array('video_id' => $video_id), 'merge_times', 1);


    //检查chunk文件夹是否存在
    $base_dir = $this->storageAppPublicDir() . '/' . $this->baseDirOfVideoChunk();
    $video_chunk_dir = $base_dir . '/' . $video['chunk_uuid'];
    if (!is_dir($video_chunk_dir)) {
    Storage::disk('video_log')->append(date('Ymd') . '.log', $this->logContent('视频 video_id=' . $video_id . ' 的 chunk 文件夹不存在'));
    return rs(Code::VIDEO_MERGE_ERROR, m(Code::VIDEO_MERGE_ERROR) . '_c');
    }

    //检查chunk文件夹是否有文件
    $files = scandir($video_chunk_dir);
    if ($files < 3) {
    Storage::disk('video_log')->append(date('Ymd') . '.log', $this->logContent('视频 video_id=' . $video_id . ' 的 chunk 文件夹为空'));
    return rs(Code::VIDEO_MERGE_ERROR, m(Code::VIDEO_MERGE_ERROR) . '_d');
    }
    sort($files);

    //保存文件路径 + 文件名
    $video_raw_path = $this->storageAppPublicDir() . '/' . $this->getVideoRawPath($video_id, $video['video_suffix']);

    //创建文件夹
    if (!is_dir(dirname($video_raw_path))) {
    File::makeDirectory(dirname($video_raw_path));
    }

    //删除原来的视频
    if (is_file($video_raw_path)) {
    @unlink($video_raw_path);
    }

    //合并chunk切块
    $errors = [];
    foreach ($files as $chunk) {
    if (in_array($chunk, ['.', '..'])) {
    continue;
    }
    $chunk_fp = fopen($video_chunk_dir . '/' . $chunk, 'rb');
    $data = fread($chunk_fp, filesize($video_chunk_dir . '/' . $chunk));
    $fp = fopen($video_raw_path, 'ab');
    fwrite($fp, $data);
    fclose($fp);
    fclose($chunk_fp);
    }
    if (!empty($errors)) {
    Storage::disk('video_log')->append(date('Ymd') . '.log', $this->logContent('源视频 video_id=' . $video_id . ' 的 ' . implode(' - ', $errors) . ' 文件不存在'));
    return rs(Code::VIDEO_MERGE_ERROR, m(Code::VIDEO_MERGE_ERROR), ['errors' => $errors]);
    }

    //原始文件大小 + 时长
    $file_size_m = filesize($video_raw_path) / (1024 * 1024);
    $video_duration = $this->getVideoDuration($video_raw_path);
    $video_duration = video_time_to_second($video_duration);
    VideoModel::getInstance()->edit(['video_id' => $video_id], ['video_size_m' => round($file_size_m, 2), 'video_duration' => $video_duration]);


    //删除chunk文件
    File::deleteDirectory($video_chunk_dir);

    //更新数据库状态
    $this->setVideoCookSt($video_id, Vars::VIDEO_COOK_ST_SPLIT_WAIT);

    //修改视频ID的课程时长
    $where = array();
    $where['video_id'] = $video_id;
    $up = array();
    $up['video_tot_duration'] = $video_duration;
    LessonModel::getInstance()->edit($where, $up);

    return rs(Code::OK, m(Code::OK));

    合并代码是比较重要的 上面就是合并的代码



  • 相关阅读:
    js 日期
    二级导航 css
    ajax 输出json数据
    三列板块 css效果
    随机18个数 js
    js 表单非空验证
    ajax案例,调用XML文件
    :hover 鼠标悬浮时(基本导航)
    下载html5-boilerplate(通过npm)
    鼠标滚动,导航置顶.纯css3的position: sticky;
  • 原文地址:https://www.cnblogs.com/jhcyzxx/p/12461911.html
Copyright © 2011-2022 走看看