video = $video; } public function handle() { $video = $this->video; // Get original file path $originalPath = storage_path('app/' . $video->path); if (!file_exists($originalPath)) { Log::error('CompressVideoJob: Original file not found: ' . $originalPath); return; } // Create compressed filename $compressedFilename = 'compressed_' . $video->filename; $compressedPath = storage_path('app/public/videos/' . $compressedFilename); try { $ffmpegConfig = Config::get('ffmpeg'); $ffmpeg = FFMpeg::create([ 'ffmpeg.binaries' => $ffmpegConfig['ffmpeg'] ?? '/usr/bin/ffmpeg', 'ffprobe.binaries' => $ffmpegConfig['ffprobe'] ?? '/usr/bin/ffprobe', 'timeout' => $ffmpegConfig['timeout'] ?? 3600, ]); $ffmpegVideo = $ffmpeg->open($originalPath); $gpuEnabled = Setting::gpuEnabled(); $encoder = Setting::gpuEncoder(); $preset = Setting::gpuPreset(); $device = Setting::gpuDevice(); if ($gpuEnabled) { $videoPasses = [ "-c:v {$encoder}", "-preset {$preset}", '-rc vbr', '-cq 23', '-profile:v high', '-pix_fmt yuv420p', "-gpu {$device}", ]; } else { $videoPasses = [ '-c:v libx264', '-preset fast', '-crf 23', '-profile:v high', '-pix_fmt yuv420p', ]; } $audioPasses = ['-c:a aac', '-b:a 192k']; $format = new X264('aac', $encoder); foreach ($videoPasses as $pass) { $format->addLegacyOption($pass); } foreach ($audioPasses as $pass) { $format->addLegacyOption($pass); } $ffmpegVideo->save($format, $compressedPath); // Check if compressed file was created and is smaller if (file_exists($compressedPath)) { $originalSize = filesize($originalPath); $compressedSize = filesize($compressedPath); // Only use compressed file if it's smaller if ($compressedSize < $originalSize) { // Delete original and rename compressed unlink($originalPath); rename($compressedPath, $originalPath); // Update video record $video->update([ 'size' => $compressedSize, 'filename' => $video->filename, // Keep same filename 'mime_type' => 'video/mp4', ]); Log::info('CompressVideoJob: Video compressed', [ 'video_id' => $video->id, 'original_size' => $originalSize, 'compressed_size' => $compressedSize, 'saved' => round(($originalSize - $compressedSize) / $originalSize * 100) . '%', 'encoder' => $encoder, 'gpu' => $gpuEnabled, ]); } else { // Compressed file is larger, delete it unlink($compressedPath); Log::info('CompressVideoJob: Compression made file larger, keeping original'); } } $video->update(['status' => 'ready']); // Chain to HLS generation for GPU-accelerated adaptive playback \App\Jobs\GenerateHlsJob::dispatch($video); } catch (\Exception $e) { Log::error('CompressVideoJob failed: ' . $e->getMessage()); $video->update(['status' => 'ready']); // Mark as ready anyway } } }