PHP项目音频文件如何转码格式处理

wen PHP项目 26

本文目录导读:

PHP项目音频文件如何转码格式处理

  1. 安装 FFmpeg
  2. PHP中使用 exec() 调用 FFmpeg
  3. 常用的音频格式转换场景
  4. 使用 PHP-FFMpeg 库(推荐)
  5. 完整的上传转码示例
  6. 安全注意事项
  7. 异步处理建议

在PHP项目中处理音频文件转码,最常用的方案是通过 FFmpeg 进行操作,下面详细介绍几种常见的实现方法。

安装 FFmpeg

Linux (Ubuntu/Debian)

sudo apt update
sudo apt install ffmpeg

macOS

brew install ffmpeg

Windows

从官网下载:https://ffmpeg.org/download.html

PHP中使用 exec() 调用 FFmpeg

基本转换示例

<?php
class AudioConverter {
    private $ffmpegPath;
    public function __construct($ffmpegPath = 'ffmpeg') {
        $this->ffmpegPath = $ffmpegPath;
    }
    /**
     * 转换音频格式
     * @param string $inputFile 输入文件路径
     * @param string $outputFile 输出文件路径
     * @param array $options 额外参数
     * @return array
     */
    public function convert($inputFile, $outputFile, $options = []) {
        // 构建命令
        $cmd = $this->ffmpegPath . ' -i ' . escapeshellarg($inputFile);
        // 添加选项
        if (!empty($options)) {
            foreach ($options as $key => $value) {
                $cmd .= " -{$key} {$value}";
            }
        }
        $cmd .= ' ' . escapeshellarg($outputFile);
        $cmd .= ' 2>&1'; // 错误输出重定向
        // 执行命令
        exec($cmd, $output, $returnCode);
        return [
            'success' => $returnCode === 0,
            'output' => $output,
            'command' => $cmd
        ];
    }
}

常用的音频格式转换场景

MP3 转 WAV

$converter = new AudioConverter();
$result = $converter->convert('input.mp3', 'output.wav', [
    'acodec' => 'pcm_s16le',
    'ar' => '44100',
    'ac' => '2'
]);

WAV 转 MP3

$result = $converter->convert('input.wav', 'output.mp3', [
    'codec:a' => 'libmp3lame',
    'b:a' => '192k',
    'ar' => '44100',
    'ac' => '2'
]);

其他格式转换

// OGG 转 MP3
$result = $converter->convert('input.ogg', 'output.mp3', [
    'codec:a' => 'libmp3lame',
    'q:a' => '2' // 质量 0-9,2 为高质量
]);
// FLAC 转 AAC
$result = $converter->convert('input.flac', 'output.aac', [
    'codec:a' => 'aac',
    'b:a' => '192k'
]);
// 任意格式转 WAV(常用于语音识别)
$result = $converter->convert('input.any', 'output.wav', [
    'acodec' => 'pcm_s16le',
    'ar' => '16000',  // 16kHz 采样率
    'ac' => '1',      // 单声道
    'sample_fmt' => 's16'
]);

使用 PHP-FFMpeg 库(推荐)

如果你更喜欢面向对象的接口,可以使用 php-ffmpeg 库:

安装

composer require php-ffmpeg/php-ffmpeg

使用示例

<?php
require_once 'vendor/autoload.php';
use FFMpeg\FFMpeg;
use FFMpeg\Format\Audio\Mp3;
use FFMpeg\Format\Audio\Wav;
use FFMpeg\Format\Audio\Aac;
class AudioProcessor {
    private $ffmpeg;
    public function __construct() {
        $this->ffmpeg = FFMpeg::create([
            'ffmpeg.binaries'  => '/usr/bin/ffmpeg',
            'ffprobe.binaries' => '/usr/bin/ffprobe',
            'timeout'          => 3600,
            'ffmpeg.threads'   => 12,
        ]);
    }
    /**
     * 转换音频格式
     */
    public function convertToMp3($inputFile, $outputFile) {
        $audio = $this->ffmpeg->open($inputFile);
        $format = new Mp3();
        $format->setAudioKiloBitrate(192)
               ->setAudioChannels(2)
               ->setAudioCodec('libmp3lame');
        $audio->save($format, $outputFile);
        return true;
    }
    /**
     * 提取音频片段
     */
    public function extractSegment($inputFile, $outputFile, $start, $duration) {
        $audio = $this->ffmpeg->open($inputFile);
        $format = new Mp3();
        $audio->filters()->clip(\FFMpeg\Coordinate\TimeCode::fromSeconds($start), 
                                \FFMpeg\Coordinate\TimeCode::fromSeconds($duration));
        $audio->save($format, $outputFile);
        return true;
    }
}

完整的上传转码示例

<?php
class AudioUploadHandler {
    private $uploadDir;
    private $ffmpeg;
    public function __construct($uploadDir = 'uploads/') {
        $this->uploadDir = $uploadDir;
        $this->ffmpeg = new AudioConverter();
        // 确保目录存在
        if (!is_dir($uploadDir)) {
            mkdir($uploadDir, 0755, true);
        }
    }
    /**
     * 上传并转码音频文件
     */
    public function uploadAndConvert($file, $targetFormat = 'mp3') {
        // 验证文件
        $this->validateFile($file);
        // 生成唯一文件名
        $extension = pathinfo($file['name'], PATHINFO_EXTENSION);
        $filename = uniqid() . '.' . $extension;
        $inputPath = $this->uploadDir . $filename;
        // 上传文件
        if (!move_uploaded_file($file['tmp_name'], $inputPath)) {
            throw new Exception("文件上传失败");
        }
        // 生成输出路径
        $outputFilename = uniqid() . '.' . $targetFormat;
        $outputPath = $this->uploadDir . $outputFilename;
        // 根据目标格式设置参数
        $options = $this->getFormatOptions($targetFormat);
        // 执行转码
        $result = $this->ffmpeg->convert($inputPath, $outputPath, $options);
        if ($result['success']) {
            // 删除原始文件
            unlink($inputPath);
            return [
                'success' => true,
                'file' => $outputPath,
                'filename' => $outputFilename,
                'format' => $targetFormat
            ];
        } else {
            // 清理失败的文件
            unlink($inputPath);
            if (file_exists($outputPath)) {
                unlink($outputPath);
            }
            throw new Exception("转码失败: " . implode("\n", $result['output']));
        }
    }
    /**
     * 获取格式参数
     */
    private function getFormatOptions($format) {
        $options = [
            'mp3' => [
                'codec:a' => 'libmp3lame',
                'b:a' => '192k',
                'ar' => '44100',
                'ac' => '2'
            ],
            'wav' => [
                'acodec' => 'pcm_s16le',
                'ar' => '44100',
                'ac' => '2'
            ],
            'aac' => [
                'codec:a' => 'aac',
                'b:a' => '128k'
            ],
            'ogg' => [
                'codec:a' => 'libvorbis',
                'q:a' => '3'
            ]
        ];
        return $options[$format] ?? [];
    }
    /**
     * 验证上传的文件
     */
    private function validateFile($file) {
        $allowedTypes = ['audio/mpeg', 'audio/wav', 'audio/ogg', 'audio/x-wav', 'audio/mp4'];
        if ($file['error'] !== UPLOAD_ERR_OK) {
            throw new Exception("上传错误");
        }
        if (!in_array($file['type'], $allowedTypes)) {
            throw new Exception("不支持的音频格式");
        }
        if ($file['size'] > 100 * 1024 * 1024) { // 100MB
            throw new Exception("文件过大");
        }
    }
}
// 使用示例
try {
    $handler = new AudioUploadHandler();
    $result = $handler->uploadAndConvert($_FILES['audio'], 'mp3');
    echo "成功: " . $result['filename'];
} catch (Exception $e) {
    echo "错误: " . $e->getMessage();
}

安全注意事项

// 1. 始终对输入进行转义
$cmd = 'ffmpeg -i ' . escapeshellarg($inputFile) . ' ' . escapeshellarg($outputFile);
// 2. 设置执行超时
set_time_limit(300); // 5分钟超时
// 3. 限制资源使用
$cmd = 'nice -n 19 ffmpeg -i input.mp3 -threads 2 output.mp3';
// 4. 验证输出文件
if (file_exists($outputFile) && filesize($outputFile) > 0) {
    // 文件生成成功
}
// 5. 清理临时文件
register_shutdown_function(function() use ($tempFile) {
    if (file_exists($tempFile)) {
        unlink($tempFile);
    }
});

异步处理建议

对于大文件,建议使用消息队列异步处理:

// 使用 Redis 或 RabbitMQ
$job = [
    'input' => '/path/to/input.mp3',
    'output' => '/path/to/output.wav',
    'format' => 'wav',
    'options' => ['ar' => 16000, 'ac' => 1]
];
// 将任务添加到队列
$queue->push('audio_convert', json_encode($job));
// 在 Worker 进程中处理
// worker.php
while ($job = $queue->pop('audio_convert')) {
    $data = json_decode($job, true);
    convertAudio($data['input'], $data['output'], $data['options']);
    // 更新数据库状态
    $db->update('files', ['status' => 'completed'], ['id' => $data['id']]);
}

这个方案涵盖了大部分的音频转码需求,你可以根据具体项目需求进行调整和扩展。

抱歉,评论功能暂时关闭!