最近有一個項目需要使用ffmpeg處理視頻,這里我寫了一個demo,方便我們來實現視頻操作
ffmpeg操作demo
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
|
<?php namespace common\helpers; use common\models\Config; use common\models\VideoApiLog; use Yii; use yii\helpers\ArrayHelper; use common\helpers\Universal; use yii\helpers\FileHelper; use yii\httpclient\Client; use yii\web\ServerErrorHttpException; /** * ffmpeg視頻處理 * * @author wangjian * @since 0.1 */ class FfmpegVideo { public $ffmpeg = 'ffmpeg' ; public function __construct( $ffmpeg = null) { if ( $ffmpeg ) { $this ->ffmpeg = $ffmpeg ; } } /** * 添加視頻文字滾動 * @param $source string 視頻 * @param $saveFile string 保存文件 * @param $text string 水印文字 * @param array $options 水印樣式 * @param int $step 每秒步長 * @param int $star 出現時間 */ public function titleMod( $source , $saveFile , $text , $options = [], $step = 20, $star = 0) { $command = $this ->ffmpeg . ' -y -i ' . $source . ' -async 1 -metadata:s:v:0 start_time=0 -vf ' ; $fonts = Yii::getAlias( '@webroot' ) . "/fonts/simsun.ttc" ; $fonts = str_replace ( '\\' , '/' , $fonts ); $fonts = str_replace ( ':' , '\\:' , $fonts ); $command .= '"drawtext=fontfile=\'' . $fonts . '\': text=\'' . $text . '\'' ; foreach ( $options as $key => $value ) { $command .= ':' . $key . '=' . $value ; } $command .= ':x=\'if(gte(t,' . $star . '),((t-' . $star . ') * ' . $step . '),NAN)\'' ; $command .= '" ' ; $command .= $saveFile ; exec ( $command , $output , $result_code ); if ( $result_code == 0) { return true; } return false; } /** * 圖片水印 * @param $source string 視頻 * @param $saveFile string 保存文件 * @param $waterImage string 水印圖片 * @param $left integer 水印水平位置 * @param $top integer 水印垂直位置 * @param null $star 水印開始時間 * @param null $duration 水印時長 */ public function imageWater( $source , $saveFile , $waterImage , $left , $top , $star = null, $duration = null) { $waterImage = str_replace ( '\\' , '/' , $waterImage ); $waterImage = str_replace ( ':' , '\\:' , $waterImage ); $command = $this ->ffmpeg . ' -y -i ' . $source . ' -vf "movie=\'' . $waterImage . '\'[watermark];' ; $command .= '[in][watermark] overlay=' . $left . ':' . $top ; if ( $star ) { $end = ( $duration ) ? $star + $duration : $star ; $command .= ':enable=\'between(t,' . $star . ',' . $end . ')\'' ; } $command .= '[out] " ' . $saveFile ; exec ( $command , $output , $result_code ); if ( $result_code == 0) { return true; } return false; } /** * 給視頻添加文字水印 * @param $source string 視頻 * @param $saveFile string 保存文件 * @param $text string 水印文字 * @param array $options 水印樣式 * @param null $star 水印開始時間 * @param null $duration 水印時長 */ public function titleWater( $source , $saveFile , $text , $options = [], $star = null, $duration = null) { $command = $this ->ffmpeg . ' -y -i ' . $source . ' -vf ' ; $fonts = Yii::getAlias( '@webroot' ) . "/fonts/STZHONGS.TTF" ; $fonts = str_replace ( '\\' , '/' , $fonts ); $fonts = str_replace ( ':' , '\\:' , $fonts ); $command .= '"drawtext=fontfile=\'' . $fonts . '\': text=\'' . $text . '\'' ; foreach ( $options as $key => $value ) { $command .= ':' . $key . '=' . $value ; } if ( $star ) { $end = ( $duration ) ? $star + $duration : $star ; $command .= ':enable=\'between(t,' . $star . ',' . $end . ')\'' ; } $command .= '" ' ; $command .= $saveFile ; exec ( $command , $output , $result_code ); if ( $result_code == 0) { return true; } return false; } /** * 將音頻合并到視頻中 * @param $videoFile string 視頻文件 * @param $audioFile string 音頻文件 * @param $saveFile string 保存文件 * @param $delay integer 聲音插入延時秒數 */ public function mergeVideoAudio( $videoFile , $audioFile , $saveFile , $delay = null) { $delayTime = 0; if ( $delay ) { $delayTime = $delay * 1000; } $command = $this ->ffmpeg . ' -y -i ' . $audioFile . ' -i ' . $videoFile . ' -c:v copy -c:a aac -strict experimental -filter_complex "[0]adelay=' . $delayTime . '|' . $delayTime . '[del1],[1][del1]amix" ' . $saveFile ; exec ( $command , $output , $result_code ); if ( $result_code == 0) { return true; } return false; } /** * 靜音 */ public function audioMute( $source , $saveFile ) { $command = $this ->ffmpeg . ' -y -i ' . $source . ' -filter:a "volume=0" ' . $saveFile ; exec ( $command , $output , $result_code ); if ( $result_code == 0) { return true; } return false; } /** * 提取視頻的音頻 * @param $source string 需要提取聲音的視頻 * @param $saveFile string 提取聲音后保存的音頻 * @return bool */ public function collectAudio( $source , $saveFile ) { $command = $this ->ffmpeg . ' -y -i ' . $source . ' -vn -acodec copy ' . $saveFile ; exec ( $command , $output , $result_code ); if ( $result_code == 0) { return true; } return false; } /** * 去除視頻聲音 * @param $source string 需要去除聲音的視頻 * @param $saveFile string 去除聲音后保存的視頻 */ public function removeAudio( $source , $saveFile ) { $command = $this ->ffmpeg . ' -y -i ' . $source . ' -an ' . $saveFile ; exec ( $command , $output , $result_code ); if ( $result_code == 0) { return true; } return false; } /** * 視頻拼接 * @param $sources array 需要拼接的視頻/音頻 * @param $saveFile string 拼接后的視頻/音頻 */ public function spliceVideo( $sources , $saveFile ) { $commands = []; $temporaryFile = []; $basePath = sys_get_temp_dir(); $index = 0; foreach ( $sources as $i => $source ) { $file = $basePath . '/' . $i . '.ts' ; $commands [ $index ] = $this ->ffmpeg . ' -y -i ' . $source . ' -vcodec copy -acodec copy -vbsf h264_mp4toannexb ' . $file ; $temporaryFile [] = $file ; $index ++; } $commands [ $index ] = $this ->ffmpeg . ' -y -i "concat:' . implode( '|' , $temporaryFile ) . '" -acodec copy -vcodec copy -absf aac_adtstoasc ' . $saveFile ; foreach ( $commands as $command ) { exec ( $command , $output , $result_code ); } foreach ( $temporaryFile as $file ) { @unlink( $file ); } return true; } /** * 視頻剪切 * @param $source string 需要剪切視頻/音頻 * @param $saveFile string 剪切后保存視頻/音頻 * @param $star string 剪切開始時間 * @param null $duration string 剪切時長 */ public function clipVideo( $source , $saveFile , $star , $duration = null) { $command = $this ->ffmpeg . ' -y -ss ' . $star ; if ( $duration ) { $command .= ' -t ' . $duration ; } $command .= ' -i ' . $source . ' -acodec copy ' . $saveFile ; exec ( $command , $output , $result_code ); if ( $result_code == 0) { return true; } return false; } const ROTATE_90 = 'transpose=1' ; const ROTATE_180 = 'hflip,vflip' ; const ROTATE_270 = 'transpose=2' ; /** * 視頻旋轉 * @param $source string 需要旋轉的視頻 * @param $saveFile string 旋轉后視頻 * @param $rotate string 旋轉角度 */ public function transposeVideo( $source , $saveFile , $rotate ) { $command = $this ->ffmpeg . ' -y -i ' . $source . ' -vf ""transpose=1"" ' . $saveFile ; exec ( $command , $output , $result_code ); if ( $result_code == 0) { return true; } return false; } /** * 視頻轉碼 * @param $source string 需要轉碼的視頻/音頻 * @param $saveFile string 轉碼后的視頻/音頻 */ public function acodecVideo( $source , $saveFile ) { $command = $this ->ffmpeg . ' -y -i ' . $source . ' -acodec copy -vcodec copy -f mp4 ' . $saveFile ; exec ( $command , $output , $result_code ); if ( $result_code == 0) { return true; } return false; } /** * 視頻拼接 * @param $sources array 需要拼接的視頻/音頻 * @param $saveFile string 拼接后的視頻/音頻 */ public function concatVideo( $sources , $saveFile ) { $file = $this ->createTemporaryFile(); $fileStream = @ fopen ( $file , 'w' ); if ( $fileStream === false) { throw new ServerErrorHttpException( 'Cannot open the temporary file.' ); } $count_videos = 0; if ( is_array ( $sources ) && ( count ( $sources ) > 0)) { foreach ( $sources as $videoPath ) { $line = "" ; if ( $count_videos != 0) $line .= "\n" ; $line .= "file '" . str_replace ('\\ ',' / ',$videoPath) ."' "; fwrite( $fileStream , $line ); $count_videos ++; } } else { throw new ServerErrorHttpException( 'The list of videos is not a valid array.' ); } $command = $this ->ffmpeg . ' -y -f concat -safe 0 -i ' . $file . ' -c copy ' . $saveFile ; exec ( $command , $output , $result_code ); fclose( $fileStream ); @unlink( $file ); //刪除文件 if ( $result_code == 0) { return true; } return false; } /** * 創建一個臨時文件 */ public function createTemporaryFile() { $basePath = sys_get_temp_dir(); if (false === $file = @tempnam( $basePath , null)) { throw new ServerErrorHttpException( 'Unable to generate a temporary filename' ); } return $file ; } /** * 獲取視頻信息 * @param $source string 需要獲取時長的資源 */ public function getAttributes( $source ) { ob_start(); $command = $this ->ffmpeg . ' -i "' . $source . '" 2>&1' ; passthru ( $command ); $getContent = ob_get_contents(); ob_end_clean(); $duration = 0; $widht = 0; $height = 0; if (preg_match( "/Duration: (.*?), start: (.*?), bitrate: (\d*) kb\/s/" , $getContent , $match )) { $matchs = explode ( ':' , $match [1]); $duration = $matchs [0] * 3600 + $matchs [1] * 60 + $matchs [2]; //轉換播放時間為秒數 } if (preg_match( "/Video: (.*?), (.*?), (.*?)[,\s]/" , $getContent , $match )) { $matchs = explode ( 'x' , $match [3]); $widht = $matchs [0]; $height = $matchs [1]; } return [ 'duration' => intval ( $duration ), 'widht' => intval ( $widht ), 'height' => intval ( $height ), ]; } } |
使用簡單示例
這里注意如果無法執行ffmpeg,實例化時需要傳入ffmpeg的安裝地址,例如linux下ffmpeg安裝地址為/usr/local/ffmepg,那么實例化時需要傳入/usr/local/ffmpeg/bin/ffmpeg
1:給視頻添加文字
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
$ffmpeg = new FfmpegVideo(); $ffmpeg ->titleWater( 'XXX' , //原視頻 'XXX' , //處理后保存視頻 'XXX' , //文字 [ 'x' => 30, //水平距離 'y' => 30, //垂直距離 'fontsize' => 20, //文字大小 'fontcolor' => 'red' , //文字顏色 'shadowy' => 2, //文字陰影 ], 200, //每秒移動步長 2 //文字出現時間(秒) ); |
2:將視頻設為靜音
1
2
3
4
5
|
$ffmpeg = new FfmpegVideo(); $ffmpeg ->audioMute( 'XXX' , //原視頻 'XXX' , //處理后保存視頻 ); |
3:視頻裁剪
1
2
3
4
5
6
7
|
$ffmpeg = new FfmpegVideo(); $ffmpeg ->clipVideo( 'XXX' , //原視頻 'XXX' , //處理后保存視頻 0, //裁剪開始時間 10 //裁剪時長 ); |
4:視頻拼接
1
2
3
4
5
|
$ffmpeg = new FfmpegVideo(); $ffmpeg ->concatVideo( [ 'XXX' , 'XXX' ], //需要拼接的視頻 'XXX' , //處理后保存視頻 ); |
5:將音頻合并到視頻中
1
2
3
4
5
6
7
|
$ffmpeg = new FfmpegVideo(); $ffmpeg ->mergeVideoAudio( 'XXX' , //視頻 'XXX' , //音頻 'XXX' , //處理后保存視頻 0 //音頻插入視頻延時時間(秒) ); |
6:獲取視頻信息(長,寬,時長)
1
2
3
4
|
$ffmpeg = new FfmpegVideo(); $ffmpeg ->getAttributes( 'XXX' , //視頻 ); |
到此這篇關于php實現ffmpeg處理視頻的實踐的文章就介紹到這了,更多相關php ffmpeg處理視頻內容請搜索服務器之家以前的文章或繼續瀏覽下面的相關文章希望大家以后多多支持服務器之家!
原文鏈接:https://segmentfault.com/a/1190000041122598