Toggle navigation
Toggle navigation
This project
Loading...
Sign in
OnePoem
/
OnePoem-Server
Go to a project
Toggle navigation
Toggle navigation pinning
Projects
Groups
Snippets
Help
Project
Activity
Repository
Pipelines
Graphs
Issues
0
Merge Requests
0
Wiki
Snippets
Network
Create a new issue
Builds
Commits
Issue Boards
Authored by
李帅
2022-04-08 17:38:20 +0800
Browse Files
Options
Browse Files
Download
Email Patches
Plain Diff
Commit
bde94bb3388b54d461a39836380dc333c2e4c1ff
bde94bb3
1 parent
adae1d78
1.重新整合ffmpeg命令
Show whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
252 additions
and
57 deletions
app/Console/Commands/DevFFmpeg.php
app/Jobs/MakeVideo.php
app/Console/Commands/DevFFmpeg.php
View file @
bde94bb
...
...
@@ -46,45 +46,143 @@ class DevFFmpeg extends Command
*/
public
function
handle
()
{
$path
=
'/Users/lishuai/Desktop/test/'
;
$file
=
$path
.
'qinghuaci.mp4'
;
// $file = $path . 'lingdang.mov';
$is_bgm
=
false
;
$bgm
=
$path
.
'bgm.aac'
;
// 1.getmediainfo 记录时长,音频视频取最长。
$cmd
=
$this
->
ffprobe
.
' -v quiet -print_format json -show_format -show_streams '
.
escapeshellarg
(
$file
);
$output
=
$this
->
execmd
(
$cmd
);
$media_info
=
json_decode
(
$output
,
true
);
if
(
json_last_error
()
===
JSON_ERROR_UTF8
)
{
$output
=
mb_convert_encoding
(
$output
,
"UTF-8"
);
$media_info
=
json_decode
(
$output
,
true
);
}
/** 记录媒体信息时长*/
$media_file_time_length
=
isset
(
$media_info
[
'format'
][
'duration'
])
?
$media_info
[
'format'
][
'duration'
]
:
0
;
$media_file_size
=
$media_info
[
'format'
][
'size'
];
if
(
$media_info
[
'streams'
][
0
][
'codec_type'
]
!==
'video'
)
{
return
0
;
}
// 2. 判断是否有视频原音,没有原音用背景音,没有背景音则混入anullsrc
if
(
$media_info
[
'format'
][
'nb_streams'
]
>=
2
){
/** 音频视频轨都有 */
if
(
$is_bgm
){
// 有背景音 融合
$audio
=
$this
->
getTempPath
(
'.mp3'
);
$cmd
=
$this
->
ffmpeg
.
' -y -i '
.
escapeshellarg
(
$file
)
.
' -y -i '
.
escapeshellarg
(
$bgm
)
.
' -filter_complex amix=inputs=2:duration=first:dropout_transition=2 '
.
'-ar 48000 -ab 64k '
.
escapeshellarg
(
$audio
);
if
(
!
$this
->
execmd
(
$cmd
))
return
0
;
$audio_input
=
' -i '
.
escapeshellarg
(
$audio
);
$audio_filter
=
'[3:a]'
;
}
else
{
// 没有背景音
$audio_input
=
''
;
$audio_filter
=
'[0:1]'
;
}
}
elseif
(
$media_info
[
'format'
][
'nb_streams'
]
==
1
){
$audio
=
$this
->
getTempPath
(
'.mp3'
);
$cmd
=
$this
->
ffmpeg
.
' -y -f lavfi -i aevalsrc=0:duration='
.
escapeshellarg
(
$media_file_time_length
)
.
' -ar 48000 -ab 64k '
.
escapeshellarg
(
$audio
);
if
(
!
$this
->
execmd
(
$cmd
))
return
0
;
if
(
$is_bgm
){
$audio_empty
=
$audio
;
$audio
=
$this
->
getTempPath
(
'.mp3'
);
$cmd
=
$this
->
ffmpeg
.
' -y -i '
.
escapeshellarg
(
$audio_empty
)
.
' -y -i '
.
escapeshellarg
(
$bgm
)
.
' -filter_complex amix=inputs=2:duration=first:dropout_transition=2 '
.
'-ar 48000 -ab 64k '
.
escapeshellarg
(
$audio
);
if
(
!
$this
->
execmd
(
$cmd
))
return
0
;
}
$audio_input
=
' -i '
.
escapeshellarg
(
$audio
);
$audio_filter
=
'[3:a]'
;
}
else
{
/** 音频视频轨都没有 */
return
0
;
}
$end_wallpaper
=
Storage
::
disk
(
'public'
)
->
path
(
'ffmpeg'
)
.
"/end_wallpaper.png"
;
$thumbnail
=
Storage
::
disk
(
'public'
)
->
path
(
'ffmpeg'
)
.
"/thumbnail.png"
;
$font
=
Storage
::
disk
(
'public'
)
->
path
(
'ffmpeg'
)
.
"/arialuni.ttf"
;
$signature
=
"一言 username"
;
// 生成贴纸和签名
$end_wallpaper
=
$this
->
wallpaperWithSignature
(
$end_wallpaper
,
$thumbnail
,
$signature
,
$font
);
// 截取最后一帧
$last_frame_video
=
$this
->
getTempPath
();
$width
=
$media_info
[
'streams'
][
0
][
'width'
];
$height
=
$media_info
[
'streams'
][
0
][
'height'
];
$size
=
$width
.
'x'
.
$height
;
$time_length
=
0.7
;
$r
=
24
;
$frame_n
=
$media_info
[
'streams'
][
0
][
'nb_frames'
]
-
2
;
$cmd
=
$this
->
ffmpeg
.
' -y -i '
.
escapeshellarg
(
$file
)
.
" -f lavfi -i nullsrc=s=
{
$size
}
:d=
{
$time_length
}
:r=
{
$r
}
-f lavfi -i aevalsrc=0:duration=
{
$time_length
}
"
.
" -filter_complex
\"
[0:v]select='eq(n,
{
$frame_n
}
)',setpts=PTS-STARTPTS[lastframe];[1:v][lastframe]overlay[v]
\"
"
.
' -map [v] -map 2:a '
.
escapeshellarg
(
$last_frame_video
);
if
(
!
$this
->
execmd
(
$cmd
))
return
0
;
$signature_x
=
0
;
$signature_y
=
-
20
;
$animate
=
$this
->
makeAnimate
(
$last_frame_video
,
$end_wallpaper
,
''
,
$signature_x
,
$signature_y
,
$font
);
$font_size
=
ceil
(
$width
/
14
);
$content
=
'题破山寺后禅院'
.
"
\t
"
.
' -- 常建'
.
PHP_EOL
.
'清晨入古寺,初日照高林。'
.
PHP_EOL
.
'曲径通幽处,禅房花木深。'
.
PHP_EOL
.
'山光悦鸟性,潭影空人心。'
.
PHP_EOL
.
'万籁此都寂,但余钟磬音。'
.
PHP_EOL
;
$path
=
'/Users/lishuai/Desktop/test/'
;
$cmd
=
$this
->
ffmpeg
.
' -y '
.
' -i '
.
escapeshellarg
(
$
path
.
'qinghuaci.mp4'
)
.
' -i '
.
escapeshellarg
(
$
path
.
'suffiix.mp4'
)
.
' -i '
.
escapeshellarg
(
$
file
)
.
' -i '
.
escapeshellarg
(
$
animate
)
.
' -i '
.
escapeshellarg
(
$path
.
'logo.png'
)
.
$audio_input
.
' -filter_complex "[0:0] '
.
'drawtext="'
.
'fontfile='
.
escapeshellarg
(
$path
.
'arialuni.ttf'
)
.
':'
.
'text='
.
escapeshellarg
(
$content
)
.
':'
.
'fontsize=
43
:'
.
'fontsize=
'
.
$font_size
.
'
:'
.
'fontcolor=white@1.0:'
.
'x=
main_w/2'
.
'-260'
.
':'
.
'y=
main_h/2'
.
'-20'
.
':'
.
'x=
'
.
escapeshellarg
(
'(w-text_w)/2'
)
.
':'
.
'y=
'
.
escapeshellarg
(
'(h-text_h)/2'
)
.
':'
.
'box=1:boxcolor=0xd0cdcc@0.5'
.
'" [text];'
.
'[text] [2:v]overlay=20:20[water];[water]
[0:1]
[1:0][1:1] concat=n=2:v=1:a=1[v][a]" '
.
'[text] [2:v]overlay=20:20[water];[water]
'
.
$audio_filter
.
'
[1:0][1:1] concat=n=2:v=1:a=1[v][a]" '
.
' -map [v] -map [a]'
.
' -c:v libx264 -bt 256k -r 25'
.
// ' -c:v:thumb png -disposition:v:thumb attached_pic' .
' -ar 44100 -ac 2 -qmin 30 -qmax 60 -profile:v baseline -preset fast '
.
escapeshellarg
(
$path
.
'out.mp4'
);
$this
->
execmd
(
$cmd
);
$cmd
=
$this
->
ffmpeg
.
' -y'
.
' -i '
.
escapeshellarg
(
$path
.
'out.mp4'
)
.
' -i '
.
escapeshellarg
(
$path
.
'thumbnail.png'
)
.
' -map 1 -map 0 -c copy -disposition:0 attached_pic '
.
escapeshellarg
(
$path
.
'out2.mp4'
);
$this
->
execmd
(
$cmd
);
//
$cmd = $this->ffmpeg. ' -y'.
//
' -i ' . escapeshellarg($path . 'out.mp4').
//
' -i ' . escapeshellarg($path . 'thumbnail.png').
//
' -map 1 -map 0 -c copy -disposition:0 attached_pic '.
//
escapeshellarg($path . 'out2.mp4');
//
//
$this->execmd($cmd);
return
0
;
...
...
@@ -385,8 +483,22 @@ class DevFFmpeg extends Command
* 获取输出临时文件名
* @return string
*/
public
function
getTempPath
()
{
return
Storage
::
disk
(
'public'
)
->
path
(
'ffmpeg'
)
.
"/output_"
.
time
()
.
rand
(
0
,
10000
)
.
".mp4"
;
public
function
getTempPath
(
$ext
=
'.mp4'
)
{
$filename
=
"/output_"
.
time
()
.
rand
(
0
,
10000
);
$hash_hex
=
md5
(
$filename
);
// 16进制表示的字符串一共32字节,表示16个二进制字节。
// 前16个字符用来第一级求摸,后16个用做第二级
$hash_hex_l1
=
substr
(
$hash_hex
,
0
,
8
);
$hash_hex_l2
=
substr
(
$hash_hex
,
8
,
8
);
$dir_l1
=
hexdec
(
$hash_hex_l1
)
%
256
;
$dir_l2
=
hexdec
(
$hash_hex_l2
)
%
512
;
$dir
=
'temp/'
.
$dir_l1
.
'/'
.
$dir_l2
;
if
(
!
Storage
::
disk
(
'public'
)
->
exists
(
$dir
))
Storage
::
disk
(
'public'
)
->
makeDirectory
(
$dir
);
return
Storage
::
disk
(
'public'
)
->
path
(
$dir
.
$filename
.
$ext
);
}
/**
...
...
app/Jobs/MakeVideo.php
View file @
bde94bb
...
...
@@ -47,60 +47,127 @@ class MakeVideo implements ShouldQueue
public
function
handle
()
{
$adminMakeVideo
=
$this
->
adminMakeVideo
;
$adminMakeVideo
->
video_url
=
Storage
::
disk
(
'public'
)
->
path
(
$adminMakeVideo
->
video_url
);
$adminMakeVideo
->
poem
;
$adminMakeVideo
->
temp
->
components
;
$file
=
Storage
::
disk
(
'public'
)
->
path
(
$adminMakeVideo
->
video_url
);
$is_bgm
=
$adminMakeVideo
->
bg_music
;
$bgm
=
Storage
::
disk
(
'public'
)
->
path
(
$adminMakeVideo
->
bgm_url
);
// 1.getmediainfo 记录时长,音频视频取最长。
$cmd
=
$this
->
ffprobe
.
' -v quiet -print_format json -show_format -show_streams '
.
escapeshellarg
(
$file
);
$output
=
$this
->
execmd
(
$cmd
);
$media_info
=
json_decode
(
$output
,
true
);
if
(
json_last_error
()
===
JSON_ERROR_UTF8
)
{
$output
=
mb_convert_encoding
(
$output
,
"UTF-8"
);
$media_info
=
json_decode
(
$output
,
true
);
}
/** 记录媒体信息时长*/
$media_file_time_length
=
isset
(
$media_info
[
'format'
][
'duration'
])
?
$media_info
[
'format'
][
'duration'
]
:
0
;
if
(
$media_info
[
'streams'
][
0
][
'codec_type'
]
!==
'video'
)
{
Log
::
channel
(
'daily'
)
->
error
(
'视频没有video track'
);
return
;
}
// 2. 判断是否有视频原音,没有原音用背景音,没有背景音则混入anullsrc
if
(
$media_info
[
'format'
][
'nb_streams'
]
>=
2
){
/** 音频视频轨都有 */
if
(
$is_bgm
){
// 有背景音 融合
$audio
=
$this
->
getTempPath
(
'.mp3'
);
$cmd
=
$this
->
ffmpeg
.
' -y -i '
.
escapeshellarg
(
$file
)
.
' -y -i '
.
escapeshellarg
(
$bgm
)
.
' -filter_complex amix=inputs=2:duration=first:dropout_transition=2 '
.
'-ar 48000 -ab 64k '
.
escapeshellarg
(
$audio
);
if
(
!
$this
->
execmd
(
$cmd
))
return
;
$audio_input
=
' -i '
.
escapeshellarg
(
$audio
);
$audio_filter
=
'[3:a]'
;
}
else
{
// 没有背景音
$audio_input
=
''
;
$audio_filter
=
'[0:1]'
;
}
}
elseif
(
$media_info
[
'format'
][
'nb_streams'
]
==
1
){
$audio
=
$this
->
getTempPath
(
'.mp3'
);
$cmd
=
$this
->
ffmpeg
.
' -y -f lavfi -i aevalsrc=0:duration='
.
escapeshellarg
(
$media_file_time_length
)
.
' -ar 48000 -ab 64k '
.
escapeshellarg
(
$audio
);
if
(
!
$this
->
execmd
(
$cmd
))
return
;
if
(
$is_bgm
){
$audio_empty
=
$audio
;
$audio
=
$this
->
getTempPath
(
'.mp3'
);
$cmd
=
$this
->
ffmpeg
.
' -y -i '
.
escapeshellarg
(
$audio_empty
)
.
' -y -i '
.
escapeshellarg
(
$bgm
)
.
' -filter_complex amix=inputs=2:duration=first:dropout_transition=2 '
.
'-ar 48000 -ab 64k '
.
escapeshellarg
(
$audio
);
if
(
!
$this
->
execmd
(
$cmd
))
return
;
}
$audio_input
=
' -i '
.
escapeshellarg
(
$audio
);
$audio_filter
=
'[3:a]'
;
}
else
{
/** 音频视频轨都没有 */
Log
::
channel
(
'daily'
)
->
error
(
'视频没有video track'
);
return
;
}
$file
=
$adminMakeVideo
->
video_url
;
$watermark_x
=
20
;
$watermark_y
=
20
;
$end_wallpaper
=
Storage
::
disk
(
'public'
)
->
path
(
'ffmpeg'
)
.
"/end_wallpaper.png"
;
$thumbnail
=
Storage
::
disk
(
'public'
)
->
path
(
'ffmpeg'
)
.
"/thumbnail.png"
;
$font
=
Storage
::
disk
(
'public'
)
->
path
(
'ffmpeg'
)
.
"/arialuni.ttf"
;
$signature
=
"一言"
;
$signature_x
=
0
;
$signature_y
=
-
20
;
$content
=
$adminMakeVideo
->
poem
->
content
.
PHP_EOL
;
$content_position
=
$adminMakeVideo
->
getContentPosition
();
// 转换logo大小
// $watermark = $this->translateLogo(Storage::disk('public')->path('image/logo.jpg'));
$watermark
=
Storage
::
disk
(
'public'
)
->
path
(
'ffmpeg'
)
.
"/LOGO_eng.png"
;
$signature
=
"一言官方出品"
;
// 生成贴纸和签名
$end_wallpaper
=
$this
->
wallpaperWithSignature
(
$end_wallpaper
,
$thumbnail
,
$signature
,
$font
);
// 截取最后一帧
$last_frame_video
=
$this
->
makeLastFrameVideo
(
$file
);
$last_frame_video
=
$this
->
getTempPath
();
$width
=
$media_info
[
'streams'
][
0
][
'width'
];
$height
=
$media_info
[
'streams'
][
0
][
'height'
];
$size
=
$width
.
'x'
.
$height
;
$time_length
=
0.7
;
$r
=
24
;
$frame_n
=
$media_info
[
'streams'
][
0
][
'nb_frames'
]
-
2
;
$cmd
=
$this
->
ffmpeg
.
' -y -i '
.
escapeshellarg
(
$file
)
.
" -f lavfi -i nullsrc=s=
{
$size
}
:d=
{
$time_length
}
:r=
{
$r
}
-f lavfi -i aevalsrc=0:duration=
{
$time_length
}
"
.
" -filter_complex
\"
[0:v]select='eq(n,
{
$frame_n
}
)',setpts=PTS-STARTPTS[lastframe];[1:v][lastframe]overlay[v]
\"
"
.
' -map [v] -map 2:a '
.
escapeshellarg
(
$last_frame_video
);
if
(
!
$this
->
execmd
(
$cmd
))
return
;
$animate
=
''
;
if
(
$last_frame_video
)
{
$signature_x
=
0
;
$signature_y
=
-
20
;
$animate
=
$this
->
makeAnimate
(
$last_frame_video
,
$end_wallpaper
,
''
,
$signature_x
,
$signature_y
,
$font
);
}
$video
=
$this
->
getTempPath
();
$cmd
=
$this
->
ffmpeg
.
' -y '
.
' -i '
.
escapeshellarg
(
$file
)
.
' -i '
.
escapeshellarg
(
$animate
)
.
' -i '
.
escapeshellarg
(
$watermark
)
.
$font_size
=
ceil
(
$width
/
14
);
$content
=
$adminMakeVideo
->
poem
->
content
.
PHP_EOL
;
$content_position
=
$adminMakeVideo
->
getContentPosition
();
$watermark
=
Storage
::
disk
(
'public'
)
->
path
(
'ffmpeg/LOGO_eng.png'
);
$font_family
=
Storage
::
disk
(
'public'
)
->
path
(
'ffmpeg/arialuni.ttf'
);
$video
=
$this
->
getTempPath
(
'.mp4'
,
false
);
$cmd
=
$this
->
ffmpeg
.
' -y '
.
' -i '
.
escapeshellarg
(
$file
)
.
' -i '
.
escapeshellarg
(
$animate
)
.
' -i '
.
escapeshellarg
(
$watermark
)
.
$audio_input
.
' -filter_complex "[0:0] '
.
'drawtext="'
.
'fontfile='
.
escapeshellarg
(
$font
)
.
':'
.
'text='
.
escapeshell
cmd
(
$content
)
.
':'
.
'fontsize=
43:'
.
'fontcolor=white@1.0:'
.
'x='
.
$content_position
[
0
]
.
':'
.
'y='
.
$content_position
[
1
]
.
':'
.
'box=1:boxcolor=0xd0cdcc@0.5'
.
'" [text];'
.
'[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]" '
.
' -map [v] -map [a]'
.
'drawtext="'
.
'fontfile='
.
escapeshellarg
(
$font
_family
)
.
':'
.
'text='
.
escapeshell
arg
(
$content
)
.
':'
.
'fontsize=
'
.
$font_size
.
':'
.
'fontcolor=white@1.0:'
.
'x='
.
escapeshellarg
(
$content_position
[
0
])
.
':'
.
'y='
.
escapeshellarg
(
$content_position
[
1
])
.
':'
.
'box=1:boxcolor=0xd0cdcc@0.5'
.
'" [text];'
.
'[text] [2:v]overlay=
20:20[water];[water]'
.
$audio_filter
.
'
[1:0][1:1] concat=n=2:v=1:a=1[v][a]" '
.
' -map [v] -map [a]'
.
' -c:v libx264 -bt 256k -r 25'
.
' -ar 44100 -ac 2 -qmin 30 -qmax 60 -profile:v baseline -preset fast '
.
escapeshellarg
(
$video
);
$this
->
execmd
(
$cmd
)
;
if
(
!
$this
->
execmd
(
$cmd
))
return
;
// $video = $this->getTempPath();
// if ( $adminMakeVideo->thumbnail == 1 && $adminMakeVideo->thumbnail_url){
...
...
@@ -108,7 +175,6 @@ class MakeVideo implements ShouldQueue
// }else{
// $thumbnail = $last_frame_video;
// }
// $cmd = $this->ffmpeg. ' -y'.
// ' -i ' . escapeshellarg($video_temp).
// ' -i ' . escapeshellarg($thumbnail).
...
...
@@ -330,10 +396,27 @@ class MakeVideo implements ShouldQueue
/**
* 获取输出临时文件名
* @param string $ext
* @param bool $is_temp
* @return string
*/
public
function
getTempPath
()
{
return
Storage
::
disk
(
'public'
)
->
path
(
'ffmpeg'
)
.
"/output_"
.
time
()
.
rand
(
0
,
10000
)
.
".mp4"
;
public
function
getTempPath
(
$ext
=
'.mp4'
,
$is_temp
=
true
)
{
$filename
=
"/output_"
.
time
()
.
rand
(
0
,
10000
);
$prefix
=
$is_temp
?
'temp/'
:
'video'
;
$hash_hex
=
md5
(
$filename
);
// 16进制表示的字符串一共32字节,表示16个二进制字节。
// 前16个字符用来第一级求摸,后16个用做第二级
$hash_hex_l1
=
substr
(
$hash_hex
,
0
,
8
);
$hash_hex_l2
=
substr
(
$hash_hex
,
8
,
8
);
$dir_l1
=
hexdec
(
$hash_hex_l1
)
%
256
;
$dir_l2
=
hexdec
(
$hash_hex_l2
)
%
512
;
$dir
=
$prefix
.
$dir_l1
.
'/'
.
$dir_l2
;
if
(
!
Storage
::
disk
(
'public'
)
->
exists
(
$dir
))
Storage
::
disk
(
'public'
)
->
makeDirectory
(
$dir
);
return
Storage
::
disk
(
'public'
)
->
path
(
$dir
.
$filename
.
$ext
);
}
/**
...
...
Please
register
or
login
to post a comment