You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用tus.js与tus-php上传视频后,播放器无法流式加载求助

解决tus.js + tus-php上传视频后无法流式播放的问题

问题根源

无法流式播放通常源于两个核心问题:

  • 服务器未支持HTTP Range请求(播放器需要分段加载视频的能力)
  • 视频文件的moov atom(元数据块)位于文件末尾,播放器必须加载完整文件才能解析播放信息

解决方案

1. 配置服务器支持HTTP Range请求

Nginx配置示例

如果使用Nginx托管静态视频文件,在对应server块中添加:

location ~* \.(mp4|m4v)$ {
    mp4;
    mp4_buffer_size 1m;
    mp4_max_buffer_size 5m;
    add_header Accept-Ranges bytes;
    add_header Content-Type video/mp4;
}

这段配置开启Nginx的mp4模块,支持Range请求并返回正确响应头。

Apache配置示例

启用mod_headers和mod_expires模块后,在.htaccess或虚拟主机配置中添加:

<FilesMatch "\.(mp4|m4v)$">
    Header set Accept-Ranges bytes
    Header set Content-Type video/mp4
</FilesMatch>

2. 前置视频的moov atom

很多视频的元数据(moov)在文件末尾,导致播放器必须加载完整个文件才能开始播放。可在上传完成后用ffmpeg自动处理:

在tus上传完成的回调中(比如Laravel路由处理逻辑里)执行:

// 假设上传后的视频路径为$videoPath
$outputPath = str_replace('.mp4', '_stream.mp4', $videoPath);
exec("ffmpeg -i {$videoPath} -movflags faststart {$outputPath}");

// 替换原文件或更新数据库路径
rename($outputPath, $videoPath);

-movflags faststart参数会把moov atom移到文件开头,让播放器快速解析播放信息。

3. 在Laravel中处理视频请求的Range逻辑

如果通过Laravel路由返回视频(而非直接静态托管),需手动处理Range请求:

Route::get('/storage/videos/{filename}', function ($filename) {
    $path = public_path('storage/videos/' . $filename);
    
    if (!file_exists($path)) {
        abort(404);
    }

    $filesize = filesize($path);
    $mime = mime_content_type($path);

    $range = request()->header('Range');
    
    if ($range) {
        list($start, $end) = explode('-', substr($range, 6));
        $start = (int)$start;
        $end = $end ? (int)$end : $filesize - 1;
        $length = $end - $start + 1;

        $file = fopen($path, 'rb');
        fseek($file, $start);
        $content = fread($file, $length);
        fclose($file);

        return response($content, 206)
            ->header('Content-Type', $mime)
            ->header('Content-Length', $length)
            ->header('Content-Range', "bytes {$start}-{$end}/{$filesize}")
            ->header('Accept-Ranges', 'bytes');
    }

    return response()->file($path, [
        'Accept-Ranges' => 'bytes',
        'Content-Type' => $mime,
    ]);
});

这段代码会处理客户端的Range请求,返回分段视频数据,实现流式播放。

4. 调整tus-php的上传完成处理

在Laravel路由中处理tus请求时,添加上传完成回调触发视频处理:

Route::any('/tus', function () {
    $server = app('tus-server');
    
    // 监听上传完成事件
    $server->on('finish', function ($file) {
        $videoPath = public_path('storage/videos/' . $file->getName());
        // 调用ffmpeg处理逻辑
        $outputPath = str_replace('.mp4', '_stream.mp4', $videoPath);
        exec("ffmpeg -i {$videoPath} -movflags faststart {$outputPath}");
        rename($outputPath, $videoPath);
    });

    $server->serve();
    return response()->json();
});

内容的提问来源于stack exchange,提问作者islam öçelik

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.18 13:43:09