Showing
2 changed files
with
253 additions
and
58 deletions
... | @@ -46,45 +46,143 @@ class DevFFmpeg extends Command | ... | @@ -46,45 +46,143 @@ class DevFFmpeg extends Command |
46 | */ | 46 | */ |
47 | public function handle() | 47 | public function handle() |
48 | { | 48 | { |
49 | + $path = '/Users/lishuai/Desktop/test/'; | ||
50 | + $file = $path . 'qinghuaci.mp4'; | ||
51 | +// $file = $path . 'lingdang.mov'; | ||
52 | + $is_bgm = false; | ||
53 | + $bgm = $path . 'bgm.aac'; | ||
54 | + | ||
55 | + // 1.getmediainfo 记录时长,音频视频取最长。 | ||
56 | + $cmd = $this->ffprobe . ' -v quiet -print_format json -show_format -show_streams ' . escapeshellarg($file); | ||
57 | + $output = $this->execmd($cmd); | ||
58 | + $media_info = json_decode($output, true); | ||
59 | + if (json_last_error() === JSON_ERROR_UTF8) { | ||
60 | + $output = mb_convert_encoding($output, "UTF-8"); | ||
61 | + $media_info = json_decode($output, true); | ||
62 | + } | ||
63 | + | ||
64 | + /** 记录媒体信息时长*/ | ||
65 | + $media_file_time_length = isset($media_info['format']['duration']) ? $media_info['format']['duration'] : 0; | ||
66 | + $media_file_size = $media_info['format']['size']; | ||
67 | + if ($media_info['streams'][0]['codec_type'] !== 'video') { | ||
68 | + return 0; | ||
69 | + } | ||
70 | + | ||
71 | + | ||
72 | + // 2. 判断是否有视频原音,没有原音用背景音,没有背景音则混入anullsrc | ||
73 | + | ||
74 | + if ( $media_info['format']['nb_streams'] >= 2 ){ /** 音频视频轨都有 */ | ||
75 | + if ($is_bgm){ | ||
76 | + // 有背景音 融合 | ||
77 | + $audio = $this->getTempPath('.mp3'); | ||
78 | + | ||
79 | + $cmd = $this->ffmpeg. | ||
80 | + ' -y -i ' . escapeshellarg($file). | ||
81 | + ' -y -i ' . escapeshellarg($bgm). | ||
82 | + ' -filter_complex amix=inputs=2:duration=first:dropout_transition=2 ' . | ||
83 | + '-ar 48000 -ab 64k ' . escapeshellarg($audio); | ||
84 | + if (!$this->execmd($cmd)) return 0; | ||
85 | + | ||
86 | + $audio_input = ' -i ' . escapeshellarg($audio); | ||
87 | + $audio_filter = '[3:a]'; | ||
88 | + }else{ | ||
89 | + // 没有背景音 | ||
90 | + $audio_input = ''; | ||
91 | + $audio_filter = '[0:1]'; | ||
92 | + | ||
93 | + } | ||
94 | + | ||
95 | + }elseif ( $media_info['format']['nb_streams'] == 1 ){ | ||
96 | + | ||
97 | + $audio = $this->getTempPath('.mp3'); | ||
98 | + $cmd = $this->ffmpeg . | ||
99 | + ' -y -f lavfi -i aevalsrc=0:duration='. escapeshellarg($media_file_time_length) . | ||
100 | + ' -ar 48000 -ab 64k ' . escapeshellarg($audio); | ||
101 | + if (!$this->execmd($cmd)) return 0; | ||
102 | + | ||
103 | + if ($is_bgm){ | ||
104 | + $audio_empty = $audio; | ||
105 | + $audio = $this->getTempPath('.mp3'); | ||
106 | + $cmd = $this->ffmpeg. | ||
107 | + ' -y -i ' . escapeshellarg($audio_empty). | ||
108 | + ' -y -i ' . escapeshellarg($bgm). | ||
109 | + ' -filter_complex amix=inputs=2:duration=first:dropout_transition=2 ' . | ||
110 | + '-ar 48000 -ab 64k ' . escapeshellarg($audio); | ||
111 | + if (!$this->execmd($cmd)) return 0; | ||
112 | + } | ||
113 | + | ||
114 | + $audio_input = ' -i ' . escapeshellarg($audio); | ||
115 | + $audio_filter = '[3:a]'; | ||
116 | + | ||
117 | + }else{ /** 音频视频轨都没有 */ | ||
118 | + return 0; | ||
119 | + } | ||
120 | + | ||
121 | + $end_wallpaper = Storage::disk('public')->path('ffmpeg') . "/end_wallpaper.png"; | ||
122 | + $thumbnail = Storage::disk('public')->path('ffmpeg') . "/thumbnail.png"; | ||
123 | + $font = Storage::disk('public')->path('ffmpeg') . "/arialuni.ttf"; | ||
124 | + $signature = "一言 username"; | ||
125 | + | ||
126 | + // 生成贴纸和签名 | ||
127 | + $end_wallpaper = $this->wallpaperWithSignature($end_wallpaper, $thumbnail, $signature, $font); | ||
128 | + | ||
129 | + // 截取最后一帧 | ||
130 | + $last_frame_video = $this->getTempPath(); | ||
131 | + $width = $media_info['streams'][0]['width']; | ||
132 | + $height = $media_info['streams'][0]['height']; | ||
133 | + $size = $width . 'x' . $height; | ||
134 | + $time_length = 0.7; | ||
135 | + $r = 24; | ||
136 | + $frame_n = $media_info['streams'][0]['nb_frames'] - 2; | ||
137 | + $cmd = $this->ffmpeg . ' -y -i ' . escapeshellarg($file) . | ||
138 | + " -f lavfi -i nullsrc=s={$size}:d={$time_length}:r={$r} -f lavfi -i aevalsrc=0:duration={$time_length}" . | ||
139 | + " -filter_complex \"[0:v]select='eq(n,{$frame_n})',setpts=PTS-STARTPTS[lastframe];[1:v][lastframe]overlay[v]\"" . | ||
140 | + ' -map [v] -map 2:a ' . escapeshellarg($last_frame_video); | ||
141 | + if (!$this->execmd($cmd)) return 0; | ||
142 | + | ||
143 | + | ||
144 | + $signature_x = 0; | ||
145 | + $signature_y = -20; | ||
146 | + $animate = $this->makeAnimate($last_frame_video, $end_wallpaper, '', $signature_x, $signature_y, $font); | ||
147 | + | ||
148 | + $font_size = ceil($width / 14); | ||
49 | $content = '题破山寺后禅院' . "\t" . ' -- 常建' . PHP_EOL . | 149 | $content = '题破山寺后禅院' . "\t" . ' -- 常建' . PHP_EOL . |
50 | '清晨入古寺,初日照高林。' . PHP_EOL . | 150 | '清晨入古寺,初日照高林。' . PHP_EOL . |
51 | '曲径通幽处,禅房花木深。' . PHP_EOL . | 151 | '曲径通幽处,禅房花木深。' . PHP_EOL . |
52 | '山光悦鸟性,潭影空人心。' . PHP_EOL . | 152 | '山光悦鸟性,潭影空人心。' . PHP_EOL . |
53 | '万籁此都寂,但余钟磬音。' . PHP_EOL ; | 153 | '万籁此都寂,但余钟磬音。' . PHP_EOL ; |
54 | - $path = '/Users/lishuai/Desktop/test/'; | ||
55 | 154 | ||
56 | $cmd = $this->ffmpeg . ' -y '. | 155 | $cmd = $this->ffmpeg . ' -y '. |
57 | - ' -i ' . escapeshellarg($path . 'qinghuaci.mp4'). | 156 | + ' -i ' . escapeshellarg($file). |
58 | - ' -i ' . escapeshellarg($path . 'suffiix.mp4'). | 157 | + ' -i ' . escapeshellarg($animate). |
59 | ' -i ' . escapeshellarg($path . 'logo.png'). | 158 | ' -i ' . escapeshellarg($path . 'logo.png'). |
60 | - | 159 | + $audio_input. |
61 | ' -filter_complex "[0:0] ' . | 160 | ' -filter_complex "[0:0] ' . |
62 | 'drawtext="'. | 161 | 'drawtext="'. |
63 | 'fontfile=' . escapeshellarg($path . 'arialuni.ttf') . ':' . | 162 | 'fontfile=' . escapeshellarg($path . 'arialuni.ttf') . ':' . |
64 | 'text=' . escapeshellarg($content) . ':'. | 163 | 'text=' . escapeshellarg($content) . ':'. |
65 | - 'fontsize=43:'. | 164 | + 'fontsize='.$font_size.':'. |
66 | 'fontcolor=white@1.0:'. | 165 | 'fontcolor=white@1.0:'. |
67 | - 'x=main_w/2' . '-260' . ':'. | 166 | + 'x=' . escapeshellarg('(w-text_w)/2') . ':' . |
68 | - 'y=main_h/2' . '-20' . ':'. | 167 | + 'y=' . escapeshellarg('(h-text_h)/2') . ':' . |
69 | 'box=1:boxcolor=0xd0cdcc@0.5'. | 168 | 'box=1:boxcolor=0xd0cdcc@0.5'. |
70 | '" [text];'. | 169 | '" [text];'. |
71 | - '[text] [2:v]overlay=20:20[water];[water][0:1][1:0][1:1] concat=n=2:v=1:a=1[v][a]" '. | 170 | + '[text] [2:v]overlay=20:20[water];[water]'.$audio_filter.'[1:0][1:1] concat=n=2:v=1:a=1[v][a]" '. |
72 | ' -map [v] -map [a]'. | 171 | ' -map [v] -map [a]'. |
73 | ' -c:v libx264 -bt 256k -r 25' . | 172 | ' -c:v libx264 -bt 256k -r 25' . |
74 | -// ' -c:v:thumb png -disposition:v:thumb attached_pic' . | ||
75 | ' -ar 44100 -ac 2 -qmin 30 -qmax 60 -profile:v baseline -preset fast ' . | 173 | ' -ar 44100 -ac 2 -qmin 30 -qmax 60 -profile:v baseline -preset fast ' . |
76 | escapeshellarg($path . 'out.mp4'); | 174 | escapeshellarg($path . 'out.mp4'); |
77 | 175 | ||
78 | $this->execmd($cmd); | 176 | $this->execmd($cmd); |
79 | 177 | ||
80 | 178 | ||
81 | - $cmd = $this->ffmpeg. ' -y'. | 179 | +// $cmd = $this->ffmpeg. ' -y'. |
82 | - ' -i ' . escapeshellarg($path . 'out.mp4'). | 180 | +// ' -i ' . escapeshellarg($path . 'out.mp4'). |
83 | - ' -i ' . escapeshellarg($path . 'thumbnail.png'). | 181 | +// ' -i ' . escapeshellarg($path . 'thumbnail.png'). |
84 | - ' -map 1 -map 0 -c copy -disposition:0 attached_pic '. | 182 | +// ' -map 1 -map 0 -c copy -disposition:0 attached_pic '. |
85 | - escapeshellarg($path . 'out2.mp4'); | 183 | +// escapeshellarg($path . 'out2.mp4'); |
86 | - | 184 | +// |
87 | - $this->execmd($cmd); | 185 | +// $this->execmd($cmd); |
88 | 186 | ||
89 | return 0; | 187 | return 0; |
90 | 188 | ||
... | @@ -385,8 +483,22 @@ class DevFFmpeg extends Command | ... | @@ -385,8 +483,22 @@ class DevFFmpeg extends Command |
385 | * 获取输出临时文件名 | 483 | * 获取输出临时文件名 |
386 | * @return string | 484 | * @return string |
387 | */ | 485 | */ |
388 | - public function getTempPath() { | 486 | + public function getTempPath($ext = '.mp4') |
389 | - return Storage::disk('public')->path('ffmpeg') . "/output_" . time() . rand(0, 10000) . ".mp4"; | 487 | + { |
488 | + $filename = "/output_" . time() . rand(0, 10000); | ||
489 | + | ||
490 | + $hash_hex = md5($filename); | ||
491 | + // 16进制表示的字符串一共32字节,表示16个二进制字节。 | ||
492 | + // 前16个字符用来第一级求摸,后16个用做第二级 | ||
493 | + $hash_hex_l1 = substr($hash_hex, 0, 8); | ||
494 | + $hash_hex_l2 = substr($hash_hex, 8, 8); | ||
495 | + $dir_l1 = hexdec($hash_hex_l1) % 256; | ||
496 | + $dir_l2 = hexdec($hash_hex_l2) % 512; | ||
497 | + $dir = 'temp/'. $dir_l1. '/' . $dir_l2; | ||
498 | + | ||
499 | + if( !Storage::disk('public')->exists($dir)) Storage::disk('public')->makeDirectory($dir); | ||
500 | + | ||
501 | + return Storage::disk('public')->path($dir . $filename . $ext); | ||
390 | } | 502 | } |
391 | 503 | ||
392 | /** | 504 | /** | ... | ... |
... | @@ -47,60 +47,127 @@ class MakeVideo implements ShouldQueue | ... | @@ -47,60 +47,127 @@ class MakeVideo implements ShouldQueue |
47 | public function handle() | 47 | public function handle() |
48 | { | 48 | { |
49 | $adminMakeVideo = $this->adminMakeVideo; | 49 | $adminMakeVideo = $this->adminMakeVideo; |
50 | - $adminMakeVideo->video_url = Storage::disk('public')->path($adminMakeVideo->video_url); | 50 | + $file = Storage::disk('public')->path($adminMakeVideo->video_url); |
51 | - $adminMakeVideo->poem; | 51 | + $is_bgm = $adminMakeVideo->bg_music; |
52 | - $adminMakeVideo->temp->components; | 52 | + $bgm = Storage::disk('public')->path($adminMakeVideo->bgm_url); |
53 | + | ||
54 | + // 1.getmediainfo 记录时长,音频视频取最长。 | ||
55 | + $cmd = $this->ffprobe . ' -v quiet -print_format json -show_format -show_streams ' . escapeshellarg($file); | ||
56 | + $output = $this->execmd($cmd); | ||
57 | + $media_info = json_decode($output, true); | ||
58 | + if (json_last_error() === JSON_ERROR_UTF8) { | ||
59 | + $output = mb_convert_encoding($output, "UTF-8"); | ||
60 | + $media_info = json_decode($output, true); | ||
61 | + } | ||
62 | + | ||
63 | + /** 记录媒体信息时长*/ | ||
64 | + $media_file_time_length = isset($media_info['format']['duration']) ? $media_info['format']['duration'] : 0; | ||
65 | + if ($media_info['streams'][0]['codec_type'] !== 'video') { | ||
66 | + Log::channel('daily')->error('视频没有video track'); | ||
67 | + return; | ||
68 | + } | ||
69 | + | ||
70 | + // 2. 判断是否有视频原音,没有原音用背景音,没有背景音则混入anullsrc | ||
71 | + if ( $media_info['format']['nb_streams'] >= 2 ){ /** 音频视频轨都有 */ | ||
72 | + if ($is_bgm){ | ||
73 | + // 有背景音 融合 | ||
74 | + $audio = $this->getTempPath('.mp3'); | ||
75 | + $cmd = $this->ffmpeg. | ||
76 | + ' -y -i ' . escapeshellarg($file). | ||
77 | + ' -y -i ' . escapeshellarg($bgm). | ||
78 | + ' -filter_complex amix=inputs=2:duration=first:dropout_transition=2 ' . | ||
79 | + '-ar 48000 -ab 64k ' . escapeshellarg($audio); | ||
80 | + if (!$this->execmd($cmd)) return; | ||
81 | + | ||
82 | + $audio_input = ' -i ' . escapeshellarg($audio); | ||
83 | + $audio_filter = '[3:a]'; | ||
84 | + }else{ | ||
85 | + // 没有背景音 | ||
86 | + $audio_input = ''; | ||
87 | + $audio_filter = '[0:1]'; | ||
88 | + } | ||
89 | + }elseif ( $media_info['format']['nb_streams'] == 1 ){ | ||
90 | + $audio = $this->getTempPath('.mp3'); | ||
91 | + $cmd = $this->ffmpeg . | ||
92 | + ' -y -f lavfi -i aevalsrc=0:duration='. escapeshellarg($media_file_time_length) . | ||
93 | + ' -ar 48000 -ab 64k ' . escapeshellarg($audio); | ||
94 | + if (!$this->execmd($cmd)) return; | ||
95 | + | ||
96 | + if ($is_bgm){ | ||
97 | + $audio_empty = $audio; | ||
98 | + $audio = $this->getTempPath('.mp3'); | ||
99 | + $cmd = $this->ffmpeg. | ||
100 | + ' -y -i ' . escapeshellarg($audio_empty). | ||
101 | + ' -y -i ' . escapeshellarg($bgm). | ||
102 | + ' -filter_complex amix=inputs=2:duration=first:dropout_transition=2 ' . | ||
103 | + '-ar 48000 -ab 64k ' . escapeshellarg($audio); | ||
104 | + if (!$this->execmd($cmd)) return; | ||
105 | + } | ||
106 | + $audio_input = ' -i ' . escapeshellarg($audio); | ||
107 | + $audio_filter = '[3:a]'; | ||
108 | + | ||
109 | + }else{ /** 音频视频轨都没有 */ | ||
110 | + Log::channel('daily')->error('视频没有video track'); | ||
111 | + return; | ||
112 | + } | ||
53 | 113 | ||
54 | - $file = $adminMakeVideo->video_url; | ||
55 | - $watermark_x = 20; | ||
56 | - $watermark_y = 20; | ||
57 | $end_wallpaper = Storage::disk('public')->path('ffmpeg') . "/end_wallpaper.png"; | 114 | $end_wallpaper = Storage::disk('public')->path('ffmpeg') . "/end_wallpaper.png"; |
58 | $thumbnail = Storage::disk('public')->path('ffmpeg') . "/thumbnail.png"; | 115 | $thumbnail = Storage::disk('public')->path('ffmpeg') . "/thumbnail.png"; |
59 | $font = Storage::disk('public')->path('ffmpeg') . "/arialuni.ttf"; | 116 | $font = Storage::disk('public')->path('ffmpeg') . "/arialuni.ttf"; |
60 | - $signature = "一言"; | 117 | + $signature = "一言官方出品"; |
61 | - $signature_x = 0; | ||
62 | - $signature_y = -20; | ||
63 | - $content = $adminMakeVideo->poem->content . PHP_EOL; | ||
64 | - $content_position = $adminMakeVideo->getContentPosition(); | ||
65 | - | ||
66 | - // 转换logo大小 | ||
67 | -// $watermark = $this->translateLogo(Storage::disk('public')->path('image/logo.jpg')); | ||
68 | - $watermark = Storage::disk('public')->path('ffmpeg') . "/LOGO_eng.png"; | ||
69 | 118 | ||
70 | // 生成贴纸和签名 | 119 | // 生成贴纸和签名 |
71 | $end_wallpaper = $this->wallpaperWithSignature($end_wallpaper, $thumbnail, $signature, $font); | 120 | $end_wallpaper = $this->wallpaperWithSignature($end_wallpaper, $thumbnail, $signature, $font); |
72 | 121 | ||
73 | // 截取最后一帧 | 122 | // 截取最后一帧 |
74 | - $last_frame_video = $this->makeLastFrameVideo($file); | 123 | + $last_frame_video = $this->getTempPath(); |
124 | + $width = $media_info['streams'][0]['width']; | ||
125 | + $height = $media_info['streams'][0]['height']; | ||
126 | + $size = $width . 'x' . $height; | ||
127 | + $time_length = 0.7; | ||
128 | + $r = 24; | ||
129 | + $frame_n = $media_info['streams'][0]['nb_frames'] - 2; | ||
130 | + $cmd = $this->ffmpeg . ' -y -i ' . escapeshellarg($file) . | ||
131 | + " -f lavfi -i nullsrc=s={$size}:d={$time_length}:r={$r} -f lavfi -i aevalsrc=0:duration={$time_length}" . | ||
132 | + " -filter_complex \"[0:v]select='eq(n,{$frame_n})',setpts=PTS-STARTPTS[lastframe];[1:v][lastframe]overlay[v]\"" . | ||
133 | + ' -map [v] -map 2:a ' . escapeshellarg($last_frame_video); | ||
134 | + if (!$this->execmd($cmd)) return; | ||
75 | 135 | ||
76 | - $animate = ''; | ||
77 | - if ($last_frame_video) { | ||
78 | - $animate = $this->makeAnimate($last_frame_video, $end_wallpaper, '', $signature_x, $signature_y, $font); | ||
79 | - } | ||
80 | 136 | ||
81 | - $video = $this->getTempPath(); | 137 | + $signature_x = 0; |
82 | - $cmd = $this->ffmpeg . ' -y ' . | 138 | + $signature_y = -20; |
83 | - ' -i ' . escapeshellarg($file) . | 139 | + $animate = $this->makeAnimate($last_frame_video, $end_wallpaper, '', $signature_x, $signature_y, $font); |
84 | - ' -i ' . escapeshellarg($animate) . | ||
85 | - ' -i ' . escapeshellarg($watermark) . | ||
86 | 140 | ||
141 | + $font_size = ceil($width / 14); | ||
142 | + $content = $adminMakeVideo->poem->content . PHP_EOL; | ||
143 | + $content_position = $adminMakeVideo->getContentPosition(); | ||
144 | + $watermark = Storage::disk('public')->path('ffmpeg/LOGO_eng.png'); | ||
145 | + $font_family = Storage::disk('public')->path('ffmpeg/arialuni.ttf'); | ||
146 | + | ||
147 | + | ||
148 | + $video = $this->getTempPath('.mp4',false); | ||
149 | + $cmd = $this->ffmpeg . ' -y '. | ||
150 | + ' -i ' . escapeshellarg($file). | ||
151 | + ' -i ' . escapeshellarg($animate). | ||
152 | + ' -i ' . escapeshellarg($watermark). | ||
153 | + $audio_input . | ||
87 | ' -filter_complex "[0:0] ' . | 154 | ' -filter_complex "[0:0] ' . |
88 | - 'drawtext="' . | 155 | + 'drawtext="'. |
89 | - 'fontfile=' . escapeshellarg($font) . ':' . | 156 | + 'fontfile=' . escapeshellarg($font_family) . ':' . |
90 | - 'text=' . escapeshellcmd($content) . ':' . | 157 | + 'text=' . escapeshellarg($content) . ':'. |
91 | - 'fontsize=43:' . | 158 | + 'fontsize='.$font_size.':'. |
92 | - 'fontcolor=white@1.0:' . | 159 | + 'fontcolor=white@1.0:'. |
93 | - 'x=' . $content_position[0] . ':' . | 160 | + 'x=' . escapeshellarg($content_position[0]) . ':' . |
94 | - 'y=' . $content_position[1] . ':' . | 161 | + 'y=' . escapeshellarg($content_position[1]) . ':' . |
95 | - 'box=1:boxcolor=0xd0cdcc@0.5' . | 162 | + 'box=1:boxcolor=0xd0cdcc@0.5'. |
96 | - '" [text];' . | 163 | + '" [text];'. |
97 | - '[text] [2:v]overlay=' . $watermark_x . ':' . $watermark_y . '[water];[water][0:1][1:0][1:1] concat=n=2:v=1:a=1[v][a]" ' . | 164 | + '[text] [2:v]overlay=20:20[water];[water]' . $audio_filter . '[1:0][1:1] concat=n=2:v=1:a=1[v][a]" ' . |
98 | - ' -map [v] -map [a]' . | 165 | + ' -map [v] -map [a]'. |
99 | ' -c:v libx264 -bt 256k -r 25' . | 166 | ' -c:v libx264 -bt 256k -r 25' . |
100 | ' -ar 44100 -ac 2 -qmin 30 -qmax 60 -profile:v baseline -preset fast ' . | 167 | ' -ar 44100 -ac 2 -qmin 30 -qmax 60 -profile:v baseline -preset fast ' . |
101 | escapeshellarg($video); | 168 | escapeshellarg($video); |
102 | 169 | ||
103 | - $this->execmd($cmd); | 170 | + if (!$this->execmd($cmd)) return; |
104 | 171 | ||
105 | // $video = $this->getTempPath(); | 172 | // $video = $this->getTempPath(); |
106 | // if ( $adminMakeVideo->thumbnail == 1 && $adminMakeVideo->thumbnail_url){ | 173 | // if ( $adminMakeVideo->thumbnail == 1 && $adminMakeVideo->thumbnail_url){ |
... | @@ -108,7 +175,6 @@ class MakeVideo implements ShouldQueue | ... | @@ -108,7 +175,6 @@ class MakeVideo implements ShouldQueue |
108 | // }else{ | 175 | // }else{ |
109 | // $thumbnail = $last_frame_video; | 176 | // $thumbnail = $last_frame_video; |
110 | // } | 177 | // } |
111 | - | ||
112 | // $cmd = $this->ffmpeg. ' -y'. | 178 | // $cmd = $this->ffmpeg. ' -y'. |
113 | // ' -i ' . escapeshellarg($video_temp). | 179 | // ' -i ' . escapeshellarg($video_temp). |
114 | // ' -i ' . escapeshellarg($thumbnail). | 180 | // ' -i ' . escapeshellarg($thumbnail). |
... | @@ -330,10 +396,27 @@ class MakeVideo implements ShouldQueue | ... | @@ -330,10 +396,27 @@ class MakeVideo implements ShouldQueue |
330 | 396 | ||
331 | /** | 397 | /** |
332 | * 获取输出临时文件名 | 398 | * 获取输出临时文件名 |
399 | + * @param string $ext | ||
400 | + * @param bool $is_temp | ||
333 | * @return string | 401 | * @return string |
334 | */ | 402 | */ |
335 | - public function getTempPath() { | 403 | + public function getTempPath($ext = '.mp4',$is_temp = true) |
336 | - return Storage::disk('public')->path('ffmpeg') . "/output_" . time() . rand(0, 10000) . ".mp4"; | 404 | + { |
405 | + $filename = "/output_" . time() . rand(0, 10000); | ||
406 | + | ||
407 | + $prefix = $is_temp ? 'temp/' : 'video'; | ||
408 | + $hash_hex = md5($filename); | ||
409 | + // 16进制表示的字符串一共32字节,表示16个二进制字节。 | ||
410 | + // 前16个字符用来第一级求摸,后16个用做第二级 | ||
411 | + $hash_hex_l1 = substr($hash_hex, 0, 8); | ||
412 | + $hash_hex_l2 = substr($hash_hex, 8, 8); | ||
413 | + $dir_l1 = hexdec($hash_hex_l1) % 256; | ||
414 | + $dir_l2 = hexdec($hash_hex_l2) % 512; | ||
415 | + $dir = $prefix . $dir_l1 . '/' . $dir_l2; | ||
416 | + | ||
417 | + if( !Storage::disk('public')->exists($dir)) Storage::disk('public')->makeDirectory($dir); | ||
418 | + | ||
419 | + return Storage::disk('public')->path($dir . $filename . $ext); | ||
337 | } | 420 | } |
338 | 421 | ||
339 | /** | 422 | /** | ... | ... |
-
Please register or login to post a comment