ffmpeg 视频提取音频 php-ffmpeg

composer require php-ffmpeg/php-ffmpeg

注意:请在 php.ini 中开启这两个函数proc_open,proc_get_status。找到 disable_functions 将里面的这两个函数去掉就好了

ffmpeg下载

<?php

namespace App\Helpers\Utils;

use FFMpeg\FFMpeg;
use FFMpeg\Format\Video\X264;
use Illuminate\Support\Facades\Storage;

class FFMpegUtil
{
    protected $ffmpeg;

    public function __construct()
    {
        $this->ffmpeg = FFMpeg::create(array(
            'ffmpeg.binaries' => env('FFMPEG_PATH', '/usr/bin/ffmpeg'),
            'ffprobe.binaries' => env('FFPROBE_PATH', '/usr/bin/ffprobe'),
            'timeout' => 3600, // The timeout for the underlying process
            'ffmpeg.threads' => 12,   // The number of threads that FFMpegUtil should use
        ));
    }

    public function create()
    {
        return FFMpeg::create(array(
            'ffmpeg.binaries' => env('FFMPEG_PATH', '/opt/local/ffmpeg/bin/ffmpeg'),
            'ffprobe.binaries' => env('FFPROBE_PATH', '/opt/local/ffmpeg/bin/ffmpeg'),
            'timeout' => 3600, // The timeout for the underlying process
            'ffmpeg.threads' => 12,   // The number of threads that FFMpegUtil should use
        ));
    }

    public function getVideoSeconds($video_url)
    {
        $stream = $this->ffmpeg->getFFProbe()->streams($video_url)->videos()->first();
        return ceil($stream->get('duration'));
    }

    /**
     * video to audio
     * @param $video_url
     * @return array
     */
    public function transformToAudio($video_url, $audioformat = 'mp3')
    {
        $video = $this->ffmpeg->open($video_url);

        $format = new X264('libmp3lame', 'libx264');
        $format->setKiloBitrate(1000)          // 视频码率
        ->setAudioChannels(2)        // 音频声道
        ->setAudioKiloBitrate(256); // 音频码率

        // 保存为
        $store = Storage::disk('temp');
        // $store->makeDirectory(date('Ymd'));
        $filename = uniqid().'.'.$audioformat;
        $dir = $store->path($filename);
        $video->save($format, $dir);
        $url = env('APP_URL').'/'.str_replace("\\", "/", $dir);
        return ['message' => 'succeed', 'path' => $dir, 'url' => $url];
    }
}

config/filesystems.php

        'temp' => [
            'driver' => 'local',
            'root' => 'temp/'.date("Ymd"),
            'url' => env('APP_URL').'/temp/'.date("Ymd"),
            'visibility' => 'public',
        ],
'disks' => [ 

// ...

],

添加上面的内容

调用

    public function extractAudio(Request $request) {
        /** @var $file \Illuminate\Http\UploadedFile */
        $file = $request->file('file');

        //判断文件是否上传成功
        if (!$file->isValid()) {
            return $this->failed(ErrorCode::PARAM_ERROR);
        }
        $videoPath = "./upload/".uniqid().'.tmp';
        move_uploaded_file($file->getRealPath(), $videoPath);
        $ffmpeg = new FFMpegUtil();
        $ans = $ffmpeg->transformToAudio($videoPath, "wav");
        unlink($videoPath);
        return $ans;
    }

返回

{

    "message": "succeed",

    "path": "temp/20220907\\63181056de07f.wav",

    "url": "http://api-tts.021city.xyz/temp/20220907/63181056de07f.wav"

}

ffmpeg参数文档

视频去掉声音,换另一个声音

ffmpeg -i sampleVideo.mp4 -vcodec copy –an  audioless.mp4
ffmpeg -i audioless.mp4 -i ..\audio\huolala01.wav -c:v copy -c:a aac output.mp4
ffplay output.mp4

利用ffmpeg合并音频和视频

VideoService.php

<?php

namespace App\Services;

use FFMpeg\Coordinate\TimeCode;
use FFMpeg\FFMpeg;
use FFMpeg\FFProbe;
use FFMpeg\Format\Audio\Wav;
use FFMpeg\Format\Video\X264;
use FFMpeg\Media\Video;
use Illuminate\Support\Facades\Log;

class VideoService
{
    /** @var FFMpeg */
    private $ffmpeg;

    const CHUNK_SECONDS = 60;  // 视频切分片段时长(s)

    /**
     * linux/mac上再安装 ffmpeg, ffprobe
     */
    public function __construct() {
        $this->ffmpeg = FFMpeg::create(array(
            'ffmpeg.binaries'  => base_path().'/bin/'.PHP_OS.'/ffmpeg.exe',
            'ffprobe.binaries' => base_path().'/bin/'.PHP_OS.'/ffprobe.exe',
            'timeout'          => 3600, // The timeout for the underlying process
            'ffmpeg.threads'   => 4,   // The number of threads that FFMpeg should use
        ));
    }

    /**
     * 用ffmpeg从视频提取音频
     * @param string $videoPath
     * @param array $audioPathList
     * @return array
     */
    public function extractVideo(string $videoPath, array &$audioPathList) {
        $today = date("Y-m-d");
        /** @var $dir string 创建临时工作目录 */
        $dir = public_path('temp').DIRECTORY_SEPARATOR.$today;
        if (!is_dir($dir)) {
            mkdir($dir, 0755, true);
        }
        // 取得视频时长
        $ffprobe = FFProbe::create();
        $duration = $ffprobe->format($videoPath)->get('duration');
        Log::debug("video duration=".$duration);

        /** @var $uriList array 音频相对路径 */
        $uriList = [];
        $startSeconds = 0;
        /** @var $video Video 切分视频 */
        $video = $this->ffmpeg->open($videoPath);

        $videoMd5 = md5_file($videoPath);
        $videoChunks = [];
        for ($leftSeconds = $duration, $i = 0; $leftSeconds > 0; $leftSeconds -= self::CHUNK_SECONDS, $i+=1) {
            if ($leftSeconds > self::CHUNK_SECONDS) {
                $endSeconds = $startSeconds + self::CHUNK_SECONDS;
            } else {
                $endSeconds = $duration; // 最后一段时长不足self::CHUNK_SECONDS
            }
            /** @var $clip \FFMpeg\Media\Clip 取一段试试 */
            $clip = $video->clip(TimeCode::fromSeconds($startSeconds), TimeCode::fromSeconds($endSeconds));
            $chunkPath = $dir.DIRECTORY_SEPARATOR.'video_'.$videoMd5.'_'.$i.'.avi';
            // 上一步超时文件已存在,继续上一步的
            if (!file_exists($chunkPath)) {
                $format = new X264();
                $clip->save($format, $chunkPath);
                // 记录执行的命令
                Log::info("ffmpeg ".json_encode($clip->getFinalCommand($format, $chunkPath)));
            }
            /** @var $video \FFMpeg\Media\AdvancedMedia */
            $advancedMedia = $this->ffmpeg->openAdvanced(array($chunkPath));
            $file = 'audio_'.$videoMd5.sprintf("%03d", $i).'.wav';
            $audioPath = $dir.DIRECTORY_SEPARATOR.$file;
            if (!file_exists($audioPath)) {
                $advancedMedia->map(array('0:a'), new Wav(), $audioPath)->save();
                Log::info("ffmpeg ".$advancedMedia->getFinalCommand());
            }
            $uri = "temp/".$today.'/'.$file;

            $audioPathList[] = $audioPath;
            $uriList[] = $uri;

            // 更新开始时刻
            $startSeconds = $endSeconds;
            // 准备删除临时文件
            $videoChunks[] = $chunkPath;
        }
        foreach ($videoChunks as $toDel) {
            unlink($toDel);
        }
        return array_map(function(string $uri) {
            return config("app.url").'/'.$uri;
        }, $uriList);
    }

    public function pcm2wav(string $pcmPath, string $wavPath) {
        $audio = $this->ffmpeg->open($pcmPath);
        return $audio->save(new Wav(), $wavPath);
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

fareast_mzh

打赏个金币

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值