diff --git a/objects/Format.php b/objects/Format.php index 215ae148..b1abaeab 100644 --- a/objects/Format.php +++ b/objects/Format.php @@ -1,5 +1,7 @@ getId())) {/* dequeued */ _error_log("id=(" . $encoder_queue_id . ") dequeued"); } else { - - if (empty($try) && self::fixFile($pathFileName, $encoder_queue_id)) { + //if (empty($try) && self::fixFile($pathFileName, $encoder_queue_id)) { + if (empty($try)) { self::exec($format_id, $pathFileName, $destinationFile, $encoder_queue_id, $try + 1); } else { $msg = json_encode($output); diff --git a/objects/HLSProcessor.php b/objects/HLSProcessor.php new file mode 100644 index 00000000..25d914d0 --- /dev/null +++ b/objects/HLSProcessor.php @@ -0,0 +1,172 @@ + $track) { + $language = isset($track->language) ? $track->language : "lang" . ($track->index + 1); // Assign language name, customize as needed + + $langDir = preg_replace('/[^a-z0-9_-]/i', '', $language); + + mkdir("{$destinationFile}audio_tracks/{$langDir}"); + + $audioFile = "{$destinationFile}audio_tracks/{$langDir}/audio.m3u8"; + $audioTsPattern = "{$destinationFile}audio_tracks/{$langDir}/audio_%03d.ts"; // Pattern for audio .ts segments + + // Correctly map the audio track and add VOD parameters + $audioCommand = get_ffmpeg() . " -i {$pathFileName} -map 0:a:{$track->index} -c:a aac -b:a 128k " . + "-movflags +faststart -f hls -hls_time 6 -hls_playlist_type vod " . + "-hls_segment_filename \"{$audioTsPattern}\" {$audioFile}"; + + $audioCommand = removeUserAgentIfNotURL($audioCommand); + _error_log("Executing audio FFmpeg command: {$audioCommand}"); + exec($audioCommand, $output, $result_code); // Execute FFmpeg command + + if (!file_exists($audioFile)) { + _error_log("audioFile error: {$audioCommand} " . json_encode(array($output))); + rmdir("{$destinationFile}audio_tracks/{$langDir}"); + unset($audioTracks[$key]); + } else { + // Add audio track entry to the master playlist + $default = ($track->index == 0) ? "YES" : "NO"; // Set first audio track as default + $masterPlaylist .= "#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID=\"audio_group\",NAME=\"{$track->title}\",LANGUAGE=\"{$language}\",DEFAULT={$default},AUTOSELECT=YES,URI=\"audio_tracks/{$langDir}/audio.m3u8\"\n"; + } + } + + $ffmpegCommand = ''; + $resolutionsFound = 0; + // Generate HLS files for each resolution + foreach ($resolutions as $key => $value) { + if ($resolution >= $value) { + $encodingSettings = Format::ENCODING_SETTINGS[$value]; + $rate = $encodingSettings['maxrate']; // Use the maxrate from ENCODING_SETTINGS + $framerate = isset($videoFramerate[$key]) && $videoFramerate[$key] > 0 ? $videoFramerate[$key] : 30; + $dir = $destinationFile . "res{$value}/"; + mkdir($dir); + $outputFile = "{$dir}index.m3u8"; + + // Add resolution playlist entry to the master playlist + $masterPlaylist .= "#EXT-X-STREAM-INF:BANDWIDTH=" . ($rate * 1000) . ",RESOLUTION=-2x{$value},AUDIO=\"audio_group\"\n"; + $masterPlaylist .= "res{$value}/index.m3u8 \n"; + + // Append FFmpeg command for this resolution + $ffmpegCommand .= self::getFFmpegCommandForResolution($pathFileName, $value, $rate, $framerate, $audioTracks, $keyInfoFile, $outputFile); + + $resolutionsFound++; + } else { + _error_log("HLSProcessor: Skipped resolution {$value} for {$pathFileName} (video height is {$resolution})"); + } + } + + if(empty($resolutionsFound)){ + // did not find any resolution, process the default one + $encodingSettings = Format::ENCODING_SETTINGS[480]; + $rate = $encodingSettings['maxrate']; // Use the maxrate from ENCODING_SETTINGS + $framerate = isset($videoFramerate[$key]) && $videoFramerate[$key] > 0 ? $videoFramerate[$key] : 30; + $dir = $destinationFile . "res{$resolution}/"; + mkdir($dir); + $outputFile = "{$dir}index.m3u8"; + + // Add resolution playlist entry to the master playlist + $masterPlaylist .= "#EXT-X-STREAM-INF:BANDWIDTH=" . ($rate * 1000) . ",RESOLUTION=-2x{$resolution},AUDIO=\"audio_group\"\n"; + $masterPlaylist .= "res{$resolution}/index.m3u8 \n"; + + // Append FFmpeg command for this resolution + $ffmpegCommand .= self::getFFmpegCommandForResolution($pathFileName, $resolution, $rate, $framerate, $audioTracks, $keyInfoFile, $outputFile); + + $resolutionsFound++; + } + + $ffmpegCommand = get_ffmpeg() . " -i {$pathFileName} " . $ffmpegCommand; + $ffmpegCommand = removeUserAgentIfNotURL($ffmpegCommand); + + // Write the master playlist to the destination file + file_put_contents($destinationFile . "index.m3u8", $masterPlaylist); + _error_log("Master playlist written to: {$destinationFile}index.m3u8"); + + return array($destinationFile, $ffmpegCommand); + } + + // FFmpeg Command Generation for HLS with Audio Tracks for a Specific Resolution + private static function getFFmpegCommandForResolution($inputFile, $resolution, $bitrate, $framerate, $audioTracks, $keyInfoFile, $outputFile) + { + $command = " -vf scale=-2:{$resolution} -b:v {$bitrate}k -r {$framerate} " . + "-movflags +faststart -hls_time 6 -hls_key_info_file {$keyInfoFile} -hls_playlist_type vod " . + "-map 0:v -c:v h264 -f hls {$outputFile}"; + + return $command; + } + + // Function to get video resolution + private static function getResolution($pathFileName) + { + $command = get_ffprobe() . " -v error -select_streams v:0 -show_entries stream=height -of csv=p=0 {$pathFileName}"; + return (int) shell_exec($command); + } + + // Function to detect audio tracks and their metadata + private static function getAudioTracks($pathFileName) + { + $command = get_ffprobe() . " -v error -select_streams a -show_entries stream=index:stream_tags=language,title -of json {$pathFileName}"; + $output = shell_exec($command); + $audioInfo = json_decode($output, true); + + $tracks = []; + foreach ($audioInfo['streams'] as $index => $stream) { + $track = new stdClass(); + $track->index = $index; + $track->language = isset($stream['tags']['language']) ? $stream['tags']['language'] : 'Default'; + $track->title = isset($stream['tags']['title']) ? $stream['tags']['title'] : $track->language; + + if($track->language == 'und'){ + $track->language = 'Default'; + } + if($track->title == 'und'){ + $track->title = 'Default'; + } + $tracks[] = $track; + } + + return $tracks; + } +} diff --git a/objects/Object.php b/objects/Object.php index 18e4dc00..2fe9a61e 100644 --- a/objects/Object.php +++ b/objects/Object.php @@ -196,7 +196,7 @@ public function save() { } return $id; } else { - error_log($sql . ' Error : (' . $global['mysqli']->errno . ') ' . $global['mysqli']->error); + error_log($sql . ' Error : (' . $global['mysqli']->errno . ') ' . $global['mysqli']->error.' '.$sql); return false; } }