ffmpeg: Як визначити розширення виводу автоматично (-c: копія)


3

Чи можливо в ffmpeg визначити розширення звуку автоматично при витягуванні (копіюванні) аудіопотоку з відео?

ffmpeg -i movie.mkv -vn -c:a copy audioOnly.{?}

аудіо всередині movie.mkv може бути будь-якого формату (mpeg3, aac, flac, wav, vorbis тощо)


1
Не можливо ...
Gyan

-ac- це варіант аудіоканалів. Якщо ви намагаєтеся використовувати, щоб встановити режим копіювання потоку , ви отримаєте повідомлення про помилку: Expected number for ac but found: copy. Замість цього використовуйте -c:a\ -codec:a\ -acodec.
llogan

Спасибі, я виправив це. c:a
Азеведо

Як вирішення, ви можете використовувати .mkvдля вихідного контейнера, оскільки він підтримує aac, opus (здається, працює і сьогодні) тощо. Не дуже рекомендував би це, хоча.
Гра "Подвійний"

Відповіді:


1

Існує різниця між контейнерами та кодуванням. m4v - це контейнер, як і WAV, WMA, WMV, AAC тощо. Всі вони підтримують декілька кодувань. Але є деякі загальні закономірності. ffprobe може допомогти.

Витяг аудіо з відеофайлів за допомогою ffmpeg висвітлюється тут дуже ретельно: https://gist.github.com/protrolium/e0dbd4bb0f1a396fcb55

У цьому прикладі є приклад того, як ви могли робити те, що шукаєте, в деяких випадках, використовуючи ffprobe та sed:

for file in *mp4 *avi; do ffmpeg -i "$file" -vn -acodec copy "$file".`ffprobe "$file" 2>&1 |sed -rn 's/.Audio: (...), ./\1/p'`; done

На пов’язаній сторінці вказане вище виявилося зіпсованим кодуванням html. Я намагався це виправити. Можливо, для одного файлу може бути спрощено:

ffmpeg -i "myfile.m4v" -vn -acodec copy "myfile".`ffprobe "myfile.m4v" 2>&1 |sed -rn 's/.Audio: (...), ./\1/p'`

Але якщо ви не використовуєте sed і bash shell, це не спрацює. (тобто не буде працювати на Windows). Він також не працюватиме, якщо кодування у відеофайлі не збігається з розширенням файлу. У Windows, ймовірно, ви можете створити оболонку повноважень або vbscript, яка б зробила те саме.


2
Немає необхідності sed: ffprobe -loglevel error -select_streams a:0 -show_entries stream=codec_name -of csv=p=0 input.foo. Але, як ви вже згадували, це неміцний спосіб зробити це, оскільки ім'я кодека не завжди буде прирівнюватися до розширеного файлу, який можна використовувати.
логіан

Мені це теж подобається. Досі я не знаю, як використовувати вихід як частину іншої команди без оболонки Unix.
Гарр Годфрі

Нарешті відповідь, яку я шукав. Але користуватися таким кодом просто божевільно!
Двомісний Грас

1

Зустрічаючи ті самі потреби, я створив такий сценарій PHP:

isset($argv[1]) || exit('You have to specify a file.');


$file = new SplFileInfo($argv[1]);

$file->isFile() || exit('File not found.');


$input = '"' . $file->getPathname() . '"';


// full path to the containing folder
$full_dir = $file->getPathInfo()->getRealPath();

// filename only: without path, without extension
$base_name = $file->getBasename('.' . $file->getExtension());

// deduce file extension from the audio stream
$output_extension = get_output_extension($file->getPathname());

// combine all that stuff
$output = '"' . $full_dir . '/' . $base_name . '.' . $output_extension . '"';


exec('ffmpeg -i ' . $input . ' -vn -acodec copy ' . $output);


function get_output_extension($file)
{
    $file = '"' . trim($file, '"') . '"';

    $stream_info = shell_exec('ffprobe -v quiet -print_format json -show_streams -select_streams a ' . $file);

    $data = json_decode($stream_info);

    if (!isset($data->streams[0]->codec_name)) {
        exit('Audio not found - ' . $file);
    }

    $audio_format = $data->streams[0]->codec_name;

    $output_extensions = [
        'aac' => 'm4a',
        'mp3' => 'mp3',
        'opus' => 'opus',
        'vorbis' => 'ogg',
    ];

    if (!isset($output_extensions[$audio_format])) {
        exit('Audio not supported - ' . $file);
    }

    return $output_extensions[$audio_format];
}

Цей скрипт розроблений таким чином, що він може обробляти файли, які не містяться в поточному каталозі, незалежно від того, на них посилаються повні або відносні шляхи.

Я не дуже радий, оскільки код занадто довгий для такого простого завдання. Якщо хтось може зробити це більш лаконічним, ви дуже раді :)

Насправді найскладніший код стосується не ffmpeg, а про SplFileInfo (який має жахливий API, як це демонструє вищезазначений сценарій).

Для відповідного сценарію я pathinfo()спробував звичайний старий звичайний спробу, але він відомий локально, і він напевно пропустив деякі файли, тому для мене це ні-ні.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.