Fix match-video playback: HEVC → H.264 transcode + correct HLS URL
- CompressVideoJob: rewrite to exec ffmpeg directly. php-ffmpeg's X264 format class validates the codec name and only accepts libx264, so every job dispatched with h264_nvenc had been throwing within ~1s and leaving the source untouched. The job now honours the GPU encoder settings, and always replaces the source when the codec is HEVC/H.265 so downloads and the MP4 fallback stay playable. - VideoController + video-player component: point HLS URLs at playlist.m3u8 (the actual master file GenerateHlsJob writes) instead of the non-existent master.m3u8, which was 404-ing and forcing the player back to the raw MP4. - VideoController@store: on the NAS-success branch, flip status to 'ready' and populate duration/is_shorts before dispatching GenerateHlsJob, so the job no longer silently no-ops. - Upload chooser: render as a bottom sheet on mobile, and forward the picked type to /videos/create?type= so the create page pre-selects it. Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
This commit is contained in:
1 parent
e0aa6e4817
commit
76f5ef0c84
5 files changed
+170
-68
No files matched your search
@@ -479,8 +479,29 @@ class VideoController extends Controller
|
||||
}
|
||||
|
||||
if ($nasUploadSucceeded) {
|
||||
// For non-audio: HLS generation still runs (downloads from NAS, keeps HLS local)
|
||||
// For non-audio: HLS generation still runs (downloads from NAS, keeps HLS local).
|
||||
// GenerateHlsJob no-ops unless status === 'ready', and on the NAS branch the
|
||||
// upload IS the "done" state (there's no local CompressVideoJob to flip it).
|
||||
if (! $isAudioUpload) {
|
||||
$duration = 0;
|
||||
try {
|
||||
$ffprobeBin = config('ffmpeg.ffprobe.binaries', '/usr/bin/ffprobe');
|
||||
$localCopy = app(\App\Services\NasSyncService::class)->ensureLocalCopy($video->fresh());
|
||||
if ($localCopy && file_exists($localCopy)) {
|
||||
$out = [];
|
||||
exec("{$ffprobeBin} -v error -show_entries format=duration -of csv=p=0 " . escapeshellarg($localCopy), $out);
|
||||
$duration = (int) round((float) ($out[0] ?? 0));
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
\Log::warning('store: ffprobe duration failed: ' . $e->getMessage());
|
||||
}
|
||||
|
||||
$video->update([
|
||||
'status' => 'ready',
|
||||
'duration' => $duration ?: $video->duration,
|
||||
'is_shorts' => ($duration ?: $video->duration) <= 60 && $orientation === 'portrait',
|
||||
]);
|
||||
|
||||
\App\Jobs\GenerateHlsJob::dispatch($video->fresh())
|
||||
->onQueue('video-processing')
|
||||
->onConnection('database');
|
||||
@@ -831,7 +852,7 @@ class VideoController extends Controller
|
||||
'key' => $video->getRouteKey(),
|
||||
'type' => $video->type,
|
||||
'has_hls' => (bool) $video->has_hls,
|
||||
'hls_url' => $video->has_hls ? route('videos.hls', ['video' => $video, 'file' => 'master.m3u8']) : null,
|
||||
'hls_url' => $video->has_hls ? route('videos.hls', ['video' => $video, 'file' => 'playlist.m3u8']) : null,
|
||||
'stream_url' => route('videos.stream', $video) . '?v=' . $video->updated_at->timestamp,
|
||||
// When a specific language track is requested (playlist row pin,
|
||||
// shared link with ?track=), expose it separately. The player uses
|
||||
|
||||
Reference in new issue
Block a user