李帅

1.重构模板和临境上传功能

......@@ -2,6 +2,7 @@
namespace App\Console\Commands;
use App\Models\AdminMakeVideo;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Storage;
......@@ -44,51 +45,44 @@ class DevFFmpeg extends Command
*/
public function handle()
{
$adminMakeVideo = AdminMakeVideo::query()->first();
$adminMakeVideo->video_url = Storage::disk('public')->path($adminMakeVideo->video_url);
// $adminMakeVideo->thumbnail_url = Storage::disk('public')->path($adminMakeVideo->thumbnail_url);
$adminMakeVideo->poem;
$adminMakeVideo->temp->components;
dd($adminMakeVideo->toArray());
$file = $adminMakeVideo->video_url;
// $watermark = Storage::disk('public')->path('image/logo.jpg');
// 转换logo大小
$watermark = $this->translateLogo(Storage::disk('public')->path('image/logo.jpg'));
$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 = '题破山寺后禅院' . "\t" . ' -- 常建' . PHP_EOL .
// '清晨入古寺,初日照高林。' . PHP_EOL .
// '曲径通幽处,禅房花木深。' . PHP_EOL .
// '山光悦鸟性,潭影空人心。' . PHP_EOL .
// '万籁此都寂,但余钟磬音。' . PHP_EOL ;
$content = $adminMakeVideo->poem->content;
// 生成贴纸和签名
$end_wallpaper = $this->wallpaperWithSignature($end_wallpaper, $thumbnail, $signature, $font);
// 截取最后一帧
$last_frame_video = $this->makeLastFrameVideo($file);
$animate = '';
if ($last_frame_video) {
$animate = $this->makeAnimate($last_frame_video, $end_wallpaper, '', $signature_x, $signature_y, $font);
}
// $file = Storage::disk('public')->path('ffmpeg') . "/qinghuaci.mp4";
// $font = Storage::disk('public')->path('ffmpeg') . "/arialuni.ttf";
// $signature = '题破山寺后禅院' . "\t" . ' -- 常建' . PHP_EOL .
// '清晨入古寺,初日照高林。' . PHP_EOL .
// '曲径通幽处,禅房花木深。' . PHP_EOL .
// '山光悦鸟性,潭影空人心。' . PHP_EOL .
// '万籁此都寂,但余钟磬音。' . PHP_EOL ;
//
//// $cmd = $this->ffplay . ' -i ' . escapeshellarg($file) .
//// ' -vf "'.
//// 'drawtext='.
//// 'fontfile=' . escapeshellarg($font) . ':'.
//// 'text=' . escapeshellarg($signature) . ':'.
//// 'fontsize=43:'.
//// 'fontcolor=white@1.0:'.
//// 'x=main_w/2' . '-260' . ':'.
//// 'y=main_h/2' . '-20' . ':'.
//// 'box=1:boxcolor=0xd0cdcc@0.5'.
//// '"';
// $video = $this->getTempPath();
// $cmd = $this->ffmpeg . ' -y -i ' . escapeshellarg($file) .
// ' -vf "'.
// 'drawtext='.
// 'fontfile=' . escapeshellarg($font) . ':'.
// 'text=' . escapeshellarg($signature) . ':'.
// 'fontsize=43:'.
// 'fontcolor=white@1.0:'.
// 'x=main_w/2' . '-260' . ':'.
// 'y=main_h/2' . '-20' . ':'.
// 'box=1:boxcolor=0xd0cdcc@0.5'.
// '" ' . escapeshellarg($video);
//
// $file = $this->execmd($cmd);
//
//dd($file);
$file = Storage::disk('public')->path('ffmpeg') . "/output_1646128658383.mp4";
$watermark = Storage::disk('public')->path('ffmpeg') . "/LOGO_eng.png";
$watermark_x = 20;
$watermark_y = 20;
$animate = Storage::disk('public')->path('ffmpeg') . "/output_16461288409938.mp4";
$video = $this->getTempPath();
$watermark_x = $watermark_x ? $watermark_x : 0;
......@@ -110,48 +104,34 @@ $animate = Storage::disk('public')->path('ffmpeg') . "/output_16461288409938.mp4
// ' -c:a libfdk_aac -ar 44100 -ac 2 -qmin 30 -qmax 60 -profile:v baseline -preset fast ' .
' -ar 44100 -ac 2 -qmin 30 -qmax 60 -profile:v baseline -preset fast ' .
escapeshellarg($video);
if ($this->execmd($cmd)) {
return $video;
// todo create insert
} else {
return false;
}
$video2 = $this->getTempPath();
$cmd = $this->ffmpeg . ' -y -i ' . escapeshellarg($video) .
' -vf '.
'drawtext="'.
'fontfile=' . escapeshellarg($font) . ':'.
'text=' . escapeshellarg($content) . ':'.
'fontsize=43:'.
'fontcolor=white@1.0:'.
'x=main_w/2' . '-260' . ':'.
'y=main_h/2' . '-20' . ':'.
'box=1:boxcolor=0xd0cdcc@0.5'.
'" ' . escapeshellarg($video2);
// $file = Storage::disk('public')->path('ffmpeg') . "/20180403172057586426000359.mp4";
$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;
$user_audio = Storage::disk('public')->path('ffmpeg') . "/20181128172555064722000590.aac";
$watermark = Storage::disk('public')->path('ffmpeg') . "/LOGO_eng.png";
$watermark_x = 20;
$watermark_y = 20;
// 生成贴纸和签名
$end_wallpaper = $this->wallpaperWithSignature($end_wallpaper, $thumbnail, $signature, $font);
// 截取最后一帧
$last_frame_video = $this->makeLastFrameVideo($file);
$animate = '';
if ($last_frame_video) {
$animate = $this->makeAnimate($last_frame_video, $end_wallpaper, '', $signature_x, $signature_y, $font);
if ($this->execmd($cmd)) {
// todo create insert
} else {
return false;
}
dd($animate);
//
$mofunshow = $this->makeMofunshow($file, $user_audio, $animate, null, $watermark, $watermark_x, $watermark_y);
dd($mofunshow);
return 0;
}
......@@ -523,6 +503,23 @@ $animate = Storage::disk('public')->path('ffmpeg') . "/output_16461288409938.mp4
/**
* logo 大小转换
* @param $logo
* @return bool
*/
public function translateLogo($logo)
{
$image = Storage::disk('public')->path('ffmpeg/output_150x150.jpg');
$cmd = $this->ffmpeg . ' -y -i ' . escapeshellarg($logo) .
' -vf scale=150:150 ' . escapeshellarg($image);
if ($this->execmd($cmd)) {
return $image;
} else {
return false;
}
}
/**
* 合成视频秀
* @param $file
* @param $audio
......
......@@ -40,12 +40,36 @@ class MakeVideo implements ShouldQueue
*/
public function handle()
{
// 执行合成逻辑
$file = Storage::disk('public')->path('ffmpeg') . "/output_1646128658383.mp4";
$watermark = Storage::disk('public')->path('ffmpeg') . "/LOGO_eng.png";
$adminMakeVideo = $this->adminMakeVideo;
$adminMakeVideo->video_url = Storage::disk('public')->path($adminMakeVideo->video_url);
$adminMakeVideo->poem;
$adminMakeVideo->temp->components;
$file = $adminMakeVideo->video_url;
$watermark_x = 20;
$watermark_y = 20;
$animate = Storage::disk('public')->path('ffmpeg') . "/output_16461288409938.mp4";
$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;
// 转换logo大小
$watermark = $this->translateLogo(Storage::disk('public')->path('image/logo.jpg'));
// 生成贴纸和签名
$end_wallpaper = $this->wallpaperWithSignature($end_wallpaper, $thumbnail, $signature, $font);
// 截取最后一帧
$last_frame_video = $this->makeLastFrameVideo($file);
$animate = '';
if ($last_frame_video) {
$animate = $this->makeAnimate($last_frame_video, $end_wallpaper, '', $signature_x, $signature_y, $font);
}
$video = $this->getTempPath();
$watermark_x = $watermark_x ? $watermark_x : 0;
......@@ -57,18 +81,32 @@ class MakeVideo implements ShouldQueue
' -i ' . escapeshellarg($file) .
' -i ' . escapeshellarg($animate) .
$am_inp .
// ' -filter_complex "[0:0]' . '' . $am_filter . 'setsar=sar=1/1[t];[t] [2:a] [1:0] [1:1] concat=n=2:v=1:a=1 [v] [a]"' .
' -filter_complex "[0:0]' . '' . $am_filter . '[0:1] [1:0] [1:1] concat=n=2:v=1:a=1 [v] [a]"' .
' -map [v] -map [a]';
$cmd .=
' -c:v libx264 -s 800x450 -bt 256k -r 25' .
// todo 没有libfdk_aac库
// ' -c:a libfdk_aac -ar 44100 -ac 2 -qmin 30 -qmax 60 -profile:v baseline -preset fast ' .
' -ar 44100 -ac 2 -qmin 30 -qmax 60 -profile:v baseline -preset fast ' .
escapeshellarg($video);
// 执行合成
$this->execmd($cmd);
$video2 = $this->getTempPath();
$cmd = $this->ffmpeg . ' -y -i ' . escapeshellarg($video) .
' -vf '.
'drawtext="'.
'fontfile=' . escapeshellarg($font) . ':'.
'text=' . escapeshellarg($content) . ':'.
'fontsize=43:'.
'fontcolor=white@1.0:'.
'x=main_w/2' . '-260' . ':'.
'y=main_h/2' . '-20' . ':'.
'box=1:boxcolor=0xd0cdcc@0.5'.
'" ' . escapeshellarg($video2);
if ($this->execmd($cmd)) {
return $video;
// 全部合成以后创建 临境
} else {
return false;
}
......@@ -440,4 +478,21 @@ class MakeVideo implements ShouldQueue
imagecopymerge($background, $thumbnail, 127, 26, 0, 0, imagesx($thumbnail), imagesy($thumbnail), 100);
return $background;
}
/**
* logo 大小转换
* @param $logo
* @return bool
*/
public function translateLogo($logo)
{
$image = Storage::disk('public')->path('ffmpeg/output_150x150.jpg');
$cmd = $this->ffmpeg . ' -y -i ' . escapeshellarg($logo) .
' -vf scale=150:150 ' . escapeshellarg($image);
if ($this->execmd($cmd)) {
return $image;
} else {
return false;
}
}
}
......
......@@ -5,6 +5,8 @@ namespace App\Models;
use Dcat\Admin\Traits\HasDateTimeFormatter;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Str;
class AdminMakeVideo extends Model
{
......@@ -12,4 +14,41 @@ class AdminMakeVideo extends Model
protected $table = 'admin_make_video';
protected $guarded = [''];
public function getVideoUrl()
{
if (Str::contains($this->video_url, '//')) {
return $this->video_url;
}
return Storage::disk('public')->url($this->video_url);
}
public function getThumbnailUrl()
{
if (Str::contains($this->thumbnail_url, '//')) {
return $this->thumbnail_url;
}
return Storage::disk('public')->url($this->thumbnail_url);
}
public function getImagesUrl()
{
if (Str::contains($this->images_url, '//')) {
return $this->images_url;
}
return Storage::disk('public')->url($this->images_url);
}
public function poem()
{
return $this->hasOne(OnePoem::class,'id','poem_id');
}
public function temp()
{
return $this->hasOne(VideoTemp::class,'id','temp_id');
}
}
......
......@@ -13,6 +13,7 @@
"jiannei/laravel-response": "^4.0",
"jpush/jpush": "^3.6",
"laravel/framework": "^8.75",
"laravel/horizon": "^5.9",
"laravel/sanctum": "^2.11",
"laravel/socialite": "^5.2",
"laravel/tinker": "^2.5",
......
......@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "aa46d9704a095f2da2d480e58e475235",
"content-hash": "653de2c6fbfa22bf510ea8db8c4b24ee",
"packages": [
{
"name": "asm89/stack-cors",
......@@ -2016,6 +2016,89 @@
"time": "2021-12-21T20:22:29+00:00"
},
{
"name": "laravel/horizon",
"version": "v5.9.3",
"source": {
"type": "git",
"url": "https://github.com/laravel/horizon.git",
"reference": "2c2c28dff4b0f8632f74ca1945f830fb462c6b56"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/laravel/horizon/zipball/2c2c28dff4b0f8632f74ca1945f830fb462c6b56",
"reference": "2c2c28dff4b0f8632f74ca1945f830fb462c6b56",
"shasum": "",
"mirrors": [
{
"url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%",
"preferred": true
}
]
},
"require": {
"ext-json": "*",
"ext-pcntl": "*",
"ext-posix": "*",
"illuminate/contracts": "^8.17|^9.0",
"illuminate/queue": "^8.17|^9.0",
"illuminate/support": "^8.17|^9.0",
"nesbot/carbon": "^2.17",
"php": "^7.3|^8.0",
"ramsey/uuid": "^4.0",
"symfony/error-handler": "^5.0|^6.0",
"symfony/process": "^5.0|^6.0"
},
"require-dev": {
"mockery/mockery": "^1.0",
"orchestra/testbench": "^6.0|^7.0",
"phpunit/phpunit": "^9.0",
"predis/predis": "^1.1"
},
"suggest": {
"ext-redis": "Required to use the Redis PHP driver.",
"predis/predis": "Required when not using the Redis PHP driver (^1.1)."
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "5.x-dev"
},
"laravel": {
"providers": [
"Laravel\\Horizon\\HorizonServiceProvider"
],
"aliases": {
"Horizon": "Laravel\\Horizon\\Horizon"
}
}
},
"autoload": {
"psr-4": {
"Laravel\\Horizon\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Taylor Otwell",
"email": "taylor@laravel.com"
}
],
"description": "Dashboard and code-driven configuration for Laravel queues.",
"keywords": [
"laravel",
"queue"
],
"support": {
"issues": "https://github.com/laravel/horizon/issues",
"source": "https://github.com/laravel/horizon/tree/v5.9.3"
},
"time": "2022-02-22T20:56:51+00:00"
},
{
"name": "laravel/sanctum",
"version": "v2.13.0",
"source": {
......
......@@ -173,6 +173,7 @@ return [
App\Providers\AuthServiceProvider::class,
// App\Providers\BroadcastServiceProvider::class,
App\Providers\EventServiceProvider::class,
App\Providers\HorizonServiceProvider::class,
App\Providers\RouteServiceProvider::class,
// 社会化登录
......
<?php
use Illuminate\Support\Str;
return [
/*
|--------------------------------------------------------------------------
| Horizon Domain
|--------------------------------------------------------------------------
|
| This is the subdomain where Horizon will be accessible from. If this
| setting is null, Horizon will reside under the same domain as the
| application. Otherwise, this value will serve as the subdomain.
|
*/
'domain' => env('HORIZON_DOMAIN', null),
/*
|--------------------------------------------------------------------------
| Horizon Path
|--------------------------------------------------------------------------
|
| This is the URI path where Horizon will be accessible from. Feel free
| to change this path to anything you like. Note that the URI will not
| affect the paths of its internal API that aren't exposed to users.
|
*/
'path' => env('HORIZON_PATH', 'horizon'),
/*
|--------------------------------------------------------------------------
| Horizon Redis Connection
|--------------------------------------------------------------------------
|
| This is the name of the Redis connection where Horizon will store the
| meta information required for it to function. It includes the list
| of supervisors, failed jobs, job metrics, and other information.
|
*/
'use' => 'default',
/*
|--------------------------------------------------------------------------
| Horizon Redis Prefix
|--------------------------------------------------------------------------
|
| This prefix will be used when storing all Horizon data in Redis. You
| may modify the prefix when you are running multiple installations
| of Horizon on the same server so that they don't have problems.
|
*/
'prefix' => env(
'HORIZON_PREFIX',
Str::slug(env('APP_NAME', 'laravel'), '_').'_horizon:'
),
/*
|--------------------------------------------------------------------------
| Horizon Route Middleware
|--------------------------------------------------------------------------
|
| These middleware will get attached onto each Horizon route, giving you
| the chance to add your own middleware to this list or change any of
| the existing middleware. Or, you can simply stick with this list.
|
*/
'middleware' => ['web'],
/*
|--------------------------------------------------------------------------
| Queue Wait Time Thresholds
|--------------------------------------------------------------------------
|
| This option allows you to configure when the LongWaitDetected event
| will be fired. Every connection / queue combination may have its
| own, unique threshold (in seconds) before this event is fired.
|
*/
'waits' => [
'redis:default' => 60,
],
/*
|--------------------------------------------------------------------------
| Job Trimming Times
|--------------------------------------------------------------------------
|
| Here you can configure for how long (in minutes) you desire Horizon to
| persist the recent and failed jobs. Typically, recent jobs are kept
| for one hour while all failed jobs are stored for an entire week.
|
*/
'trim' => [
'recent' => 60,
'pending' => 60,
'completed' => 60,
'recent_failed' => 10080,
'failed' => 10080,
'monitored' => 10080,
],
/*
|--------------------------------------------------------------------------
| Metrics
|--------------------------------------------------------------------------
|
| Here you can configure how many snapshots should be kept to display in
| the metrics graph. This will get used in combination with Horizon's
| `horizon:snapshot` schedule to define how long to retain metrics.
|
*/
'metrics' => [
'trim_snapshots' => [
'job' => 24,
'queue' => 24,
],
],
/*
|--------------------------------------------------------------------------
| Fast Termination
|--------------------------------------------------------------------------
|
| When this option is enabled, Horizon's "terminate" command will not
| wait on all of the workers to terminate unless the --wait option
| is provided. Fast termination can shorten deployment delay by
| allowing a new instance of Horizon to start while the last
| instance will continue to terminate each of its workers.
|
*/
'fast_termination' => false,
/*
|--------------------------------------------------------------------------
| Memory Limit (MB)
|--------------------------------------------------------------------------
|
| This value describes the maximum amount of memory the Horizon master
| supervisor may consume before it is terminated and restarted. For
| configuring these limits on your workers, see the next section.
|
*/
'memory_limit' => 64,
/*
|--------------------------------------------------------------------------
| Queue Worker Configuration
|--------------------------------------------------------------------------
|
| Here you may define the queue worker settings used by your application
| in all environments. These supervisors and settings handle all your
| queued jobs and will be provisioned by Horizon during deployment.
|
*/
'defaults' => [
'supervisor-1' => [
'connection' => 'redis',
'queue' => ['default'],
'balance' => 'auto',
'maxProcesses' => 1,
'maxTime' => 0,
'maxJobs' => 0,
'memory' => 128,
'tries' => 1,
'timeout' => 60,
'nice' => 0,
],
],
'environments' => [
'production' => [
'supervisor-1' => [
'maxProcesses' => 10,
'balanceMaxShift' => 1,
'balanceCooldown' => 3,
],
],
'local' => [
'supervisor-1' => [
'maxProcesses' => 3,
],
],
],
];