哔哩哔哩缓存转码|FFmpeg将m4s文件转为mp4|PHP自动批量转码B站视频

window下载安装FFmpeg

配置FFmpeg环境变量

上面下载的FFmpeg是绿色软件,下载解压到你的常用软件安装目录即可,然后进入bin复制全路径配置下系统环境变量即可


终端命令处理

bash 复制代码
ffmpeg -i video.m4s -i audio.m4s -codec copy video.mp4

使用PHP调用FFmpeg

php 复制代码
<?php

// require 'vendor/autoload.php';
// $ffmpeg = FFMpeg\FFMpeg::create();
// $oldAudio = $ffmpeg->open('./assets/32.amr');
// $newAudio = new FFMpeg\Format\Audio\Mp3();
// $newAudio->setAudioKiloBitrate(8); // 设置音频比特
// $oldAudio->save($newAudio, './assets/32.mp3');

// shell_exec("ffmpeg -i 32.amr b.mp3"); // cmd可执行

/* http请求可执行 */
// $file = './src/32.amr';
// $outFile = './src/b.mp3';
// $handle = popen("ffmpeg -i $file $outFile", 'w'); 
// pclose($handle);


// $filePath = './src/32.amr';
// $filePath_mp =  './src/b.mp3';
// echo "ffmpeg -i $filePath $filePath_mp";
// $handle = popen("ffmpeg -i $filePath  $filePath_mp", 'w');
// pclose($handle);



shell_exec("ffmpeg -i video.m4s -i audio.m4s -codec copy video.mp4"); // cmd可执行
  • 批量处理程序
php 复制代码
<?php
date_default_timezone_set("PRC");
header("Content-type: text/html; charset=utf-8"); 
set_time_limit(0);

// 遍历获取文件
function getDirFile($path = null, $deep = true) {
    if (empty($path)) {
        return [];
    }
    $files = scandir($path);
    $fileItem = [];
    foreach($files as $v) {
        $newPath = $path .DIRECTORY_SEPARATOR.$v;
        if($deep && is_dir($newPath) && $v != '.' && $v != '..') {
        	if (is_numeric($deep)) {
        		$deep--;
        	}
            $fileItem = array_merge($fileItem, getDirFile($newPath, $deep));
        }else if(is_file($newPath)){
            $fileItem[] = $newPath;
        }
    }
    return $fileItem;
}

// 遍历获取文件夹
function getDir($path = null, $deep = true) {
    if (empty($path)) {
        return [];
    }
    $files = scandir($path);
    $dirList = [];
    foreach($files as $v) {
        $newPath = $path .DIRECTORY_SEPARATOR.$v;
        if (is_dir($newPath) && $v != '.' && $v != '..') {
        	$dirList[] = $newPath;
        	if ($deep) {
        		if (is_numeric($deep)) {
		    		$deep--;
		    	}
		    	$dirList = array_merge($dirList, getDir($newPath, $deep));
        	}
        }
    }
    return $dirList;
}

//判断文件夹是否存在,没有则新建。
if (!function_exists('mkdirs')) {
    function mkdirs($dir, $mode = 0777)
    {
        if (is_dir($dir) || @mkdir($dir, $mode)) {
            return true;
        }
        if (!mkdirs(dirname($dir), $mode)) {
            return false;
        }
        return @mkdir($dir, $mode);
    }
}

/**
 * 操作文件夹
 * addtime 2020年7月17日
 * @param [type] $dirname 文件夹路径
 * @param boolean $self  是否删除文件夹本身[true是 false否] 具体看需求
 * @return void
 */
function do_rmdir($dirname, $self = false) 
{
    # 检查文件或目录是否存在
    if (!file_exists($dirname)) {
      return false;
    }
    # 是文件进行删除
    if (is_file($dirname) || is_link($dirname)) {
      return unlink($dirname);
    }
    # 开始读取目录
    $dir = dir($dirname);
    if ($dir) {
      while (false !== $entry = $dir->read()) {
        if ($entry == '.' || $entry == '..') {
          continue;
        }
        # 进行文件删除
        do_rmdir($dirname . '/' . $entry);
      }
    }
    # 关闭目录
    $dir->close();
    # 是否删除本身文件夹
    $self && rmdir($dirname);
    # 成功返回
    return ['code' => 200];
}

$inputParams = getopt('d:'); // 接收-d参数
if (empty($inputParams['d']) || !file_exists($inputParams['d'])) {
	die(PHP_EOL.'请输入正确的B站视频文件目录');
}
$inputDir = $inputParams['d'];
$outputDir = dirname(__FILE__).DIRECTORY_SEPARATOR. $inputDir.'Mp4';
do_rmdir($outputDir, true);
mkdirs($outputDir);
$isDebug = false;


$list = getDir($inputDir, false);
if (empty($list)) {
	die(PHP_EOL.'空文件夹。。。');
}
foreach ($list as $key => $item) {
	$entryJson = $item. DIRECTORY_SEPARATOR . 'entry.json';
	$audio = $item. DIRECTORY_SEPARATOR . '80' . DIRECTORY_SEPARATOR . 'audio.m4s';
	$video = $item. DIRECTORY_SEPARATOR . '80' . DIRECTORY_SEPARATOR . 'video.m4s';
	if (file_exists($entryJson) && file_exists($audio) && file_exists($video)) {
		$entryJsonText = file_get_contents($item. DIRECTORY_SEPARATOR . 'entry.json');
		if (!empty($entryJsonText)) { 
			$entryJsonText = json_decode($entryJsonText, true);
			$fileName = $entryJsonText['page_data']['part'];
			$fileName = explode('.', $fileName, 2);
			$fileName[0] = str_pad($fileName[0], 3, '0', STR_PAD_LEFT );
			$fileName = implode('.', $fileName);
			$fileName = $outputDir . DIRECTORY_SEPARATOR . $fileName . '.mp4';
			print_r([
				'path' => $item,
				'fileName' => $fileName,
			]);
			// 拼接文件名并转为gbk为window支持的编码
			$fileName = iconv('utf-8' , 'gbk', $fileName);
			$cmd = "ffmpeg ".($isDebug? "": "-loglevel quiet")." -i {$audio} -i {$video} -codec copy {$fileName}";
			shell_exec($cmd); // cmd可执行
		}
	}	
}

参考

相关推荐
JaguarJack2 天前
FrankenPHP 原生支持 Windows 了
后端·php·服务端
BingoGo2 天前
FrankenPHP 原生支持 Windows 了
后端·php
JaguarJack3 天前
PHP 的异步编程 该怎么选择
后端·php·服务端
BingoGo3 天前
PHP 的异步编程 该怎么选择
后端·php
JaguarJack4 天前
为什么 PHP 闭包要加 static?
后端·php·服务端
ServBay5 天前
垃圾堆里编码?真的不要怪 PHP 不行
后端·php
用户962377954485 天前
CTF 伪协议
php
BingoGo7 天前
当你的 PHP 应用的 API 没有限流时会发生什么?
后端·php
JaguarJack7 天前
当你的 PHP 应用的 API 没有限流时会发生什么?
后端·php·服务端
BingoGo8 天前
OpenSwoole 26.2.0 发布:支持 PHP 8.5、io_uring 后端及协程调试改进
后端·php