LINUX.ORG.RU

Пакетная обработка видеофайлов с помощью ffmpeg. Что-то идёт не так ...

 , ,


1

3

Есть коллекция видеофайлов из 1023 штук. Все лежат в одной папке. У меня такая вот задача: сделать скриншот на 7 секунде из каждого файла и поместить их в папку folder, которая лежит в той же папке, где хранятся эти видеофайлы. Пробовал решить задачу двумя способами. Точнее одним, а на втором экспериментировал, экспериментировал, но так удобоваримого результата не получил.
Первый вариант сделан в стиле python-zen, то есть я по максимуму сделал упрощение, примитивизировал решение, поделил его на кучу «простых» задач.
Во втором варианте, я решил немного поиграть в кулхацкера и замахнулся даже на владение приёмами regex. Получилось краткое решение, мне оно нравится, почему-то. Люблю краткость. Но вот незадача, почему-то скрипт работает менее эффективно. То есть, вместо 1023 штук скриншотов он делает 900 штук.
В общем-то, такой вариант меня бы тоже устроил, но хотелось бы понять, в чём моя ошибка. Может быть я с синтаксисом намудрил? Переборщил с regex? Первый вариант работает на ура, делает 1015 штук - меня это устраивает вполне.
То, что ни тот, ни другой вариант не делает все 1023 штуки скриншотов - меня устраивает, потому что некоторые скрины, судя по логам, цепляются с какими-то ошибками и отказами и т.п., то есть ffmpeg «решает» их пропускать. Это не проблема.
Проверьте, пожалуйста, второй вариант. Может быть, незамыленный глаз увидит лучше.

Вариант №1

#!/bin/bash

# Папка для сохранения превьюшек должна находится в той же папке, в которой находятся видеофайлы!!
# Статья, где я взял команду по ffmpeg находится здесь: https://annimon.com/article/4008
folder_to_save="folder"

# 1. Находим скриншоты для mp4-файлов
for file in *.mp4; do
	ffmpeg -i "${file}" -ss 00:00:07 -frames:v 1 "${folder_to_save}/${file%.mp4}_${RANDOM}.jpeg"
done

# 2. Находим скриншоты для avi-файлов
for file in *.avi; do
	ffmpeg -i "${file}" -ss 00:00:07 -frames:v 1 "${folder_to_save}/${file%.avi}_${RANDOM}.jpeg"
done

# 3. Находим скриншоты для rmvb-файлов
for file in *.rmvb; do
	ffmpeg -i "${file}" -ss 00:00:07 -frames:v 1 "${folder_to_save}/${file%.rmvb}_${RANDOM}.jpeg"
done

# 4. Находим скриншоты для 3gp-файлов
for file in *.3gp; do
	ffmpeg -i "${file}" -ss 00:00:07 -frames:v 1 "${folder_to_save}/${file%.3gp}_${RANDOM}.jpeg"
done

# 5. Находим скриншоты для mov-файлов
for file in *.mov; do
	ffmpeg -i "${file}" -ss 00:00:07 -frames:v 1 "${folder_to_save}/${file%.mov}_${RANDOM}.jpeg"
done

# 6. Находим скриншоты для mpg-файлов
for file in *.mpg; do
	ffmpeg -i "${file}" -ss 00:00:07 -frames:v 1 "${folder_to_save}/${file%.mpg}_${RANDOM}.jpeg"
done

# 7. Находим скриншоты для flv-файлов
for file in *.flv; do
	ffmpeg -i "${file}" -ss 00:00:07 -frames:v 1 "${folder_to_save}/${file%.flv}_${RANDOM}.jpeg"
done

# 8. Находим скриншоты для mkv-файлов
for file in *.mkv; do
	ffmpeg -i "${file}" -ss 00:00:07 -frames:v 1 "${folder_to_save}/${file%.mkv}_${RANDOM}.jpeg"
done

# 9. Находим скриншоты для mpeg-файлов
for file in *.mpeg; do
	ffmpeg -i "${file}" -ss 00:00:07 -frames:v 1 "${folder_to_save}/${file%.mpeg}_${RANDOM}.jpeg"
done

# 10. Находим скриншоты для mp-файлов
for file in *.mp; do
	ffmpeg -i "${file}" -ss 00:00:07 -frames:v 1 "${folder_to_save}/${file%.mp}_${RANDOM}.jpeg"
done

# 11. Находим скриншоты для wmv-файлов
for file in *.wmv; do
	ffmpeg -i "${file}" -ss 00:00:07 -frames:v 1 "${folder_to_save}/${file%.wmv}_${RANDOM}.jpeg"
done

Вариант №2

#!/bin/bash

# Упрощённый вариант (получилось всего 900 картинок, а надо было 1023)
for file in {*.mp4,*.avi,*.rmvb,*.3gp,*.mov,*.mpg,*.flv,*.mkv,*.mpeg,*.mp,*.wmv}; do
	ffmpeg -i "${file}" -ss 00:00:07 -frames:v 1 "folder/${file%.[mp4,avi,rmvb,3gp,mov,mpg,flv,mkv,mpeg,mp,wmv]}_${RANDOM}.jpeg"
done

Перемещено hobbit из general

★★★★★

Последнее исправление: Desmond_Hume (всего исправлений: 2)

Ответ на: комментарий от yuripv79

Вот в строчке

${file}%.[mp4,avi,rmvb,3gp,mov,mpg,flv,mkv,mpeg,mp,wmv]_${RANDOM}.jpeg

я уже не вспомню. По-моему, там был сначала такой вариант:

${file}%.{mp4,avi,rmvb,3gp,mov,mpg,flv,mkv,mpeg,mp,wmv}_${RANDOM}.jpeg

Просто я с этими скобками бился-бился, что уже забыл, как было)).

${file%.mp4} - обрезает расширение .mp4 Именно это мне и нужно было сделать, но только не с одним mp4, но и с другими видеофайлами других видеоформатов … я поэтому и решил там regex замутить, но несколько неудачно.

По поводу «уникальности» - $RANDOM помогает. Без него, сначала, вообще получалось не более 50% файлов сделать)).

Desmond_Hume ★★★★★
() автор топика
Ответ на: комментарий от Desmond_Hume

Проще действительно использовать regex:

ffmpeg -i "${file}" -ss 00:00:07 -frames:v 1 "$folder/$(echo $file | sed -E 's/\.[a-z0-9]+$//')_${RANDOM}.jpeg"

yuripv79
()
Последнее исправление: yuripv79 (всего исправлений: 1)
Ответ на: комментарий от yuripv79

Можно, но я побоялся, что попадётся файл, у которого будет точка где-нибудь в середине. Хотелось конкретно расширение файла обрезать в названии …

Desmond_Hume ★★★★★
() автор топика
Ответ на: комментарий от Desmond_Hume

%% жадное откусывание суффикса, % должно откусить начиная с последней точки.

Как пример:

$ file="foo.bar"; echo ${file%%.*}
foo
$ file="foo.bar.mp4"; echo ${file%%.*}
foo
$ file="foo.bar.mp4"; echo ${file%.*}
foo.bar
$ file="foo.bar"; echo ${file%.*}
foo
yuripv79
()
Последнее исправление: yuripv79 (всего исправлений: 2)

for file in *.mp4; do

Добавляй тогда ещё shopt -s nullglob. Иначе при отсутствии файлов соответствующих маске будет возвращена сама маска.

Регистр расширений файлов всегда нижний? shopt -s nocaseglob

Зачем RANDOM?

.jpeg

А чего не .jpg?

Tanger ★★★★★
()
Ответ на: комментарий от Tanger

$RANDOM для уникальности названия файла, потому что встречаются видеофайлы с одним и тем же содержанием, но с разным форматом файла типа videofile1.avi, videofile1.wmv, videofile1.mkv …

Desmond_Hume ★★★★★
() автор топика
Ответ на: комментарий от Desmond_Hume

одним и тем же содержанием, но с разным форматом

Почему бы не сделать videofile1.avi.jpg?

С рандомом у тебя получается необратимое отображение, если файлы совпадают по названию без расширения.

Tanger ★★★★★
()
Последнее исправление: Tanger (всего исправлений: 2)
Ответ на: комментарий от Tanger

Почему бы не сделать videofile1.avi.jpg?

Уже тоже начинаю думать о таком варианте, но хотелось сделать «не хуже первого варианта, зато кратко». В первом варианте - прям всё, как нужно: и названия чёткие, и количество устраивающее. Но вот эта портянка наводит грусть, хочется красивых кратких решений.

К тому же, хочется понять, почему названия не секутся, как надо. Меня смущает %.[…] выражение. Чувствую, загвоздка в этом. %.{..} тоже не то …

Desmond_Hume ★★★★★
() автор топика
Последнее исправление: Desmond_Hume (всего исправлений: 3)

получилось всего 900 картинок, а надо было 1023

Ты проверял, что у тебя тело цикла выполняется ровно 1023 раза? Возможно, ты пропускаешь некоторые файлы.

${RANDOM}

Если у тебя много видеофайлов с одинаковыми именами, но разными расширениями, то есть небольшой шанс коллизий имён.

Вообще если взять 1000 экземпляров $RANDOM, то в среднем будет только около 985 уникальных чисел. В $RANDOM слишком мало бит.

i-rinat ★★★★★
()
Ответ на: комментарий от i-rinat

Да, вполне возможно. Но $RANDOM работает в интервале [0-32767] … хотя файлов и так тысяча. Да, может быть совпадение. Но почему тогда первый скрипт, который тоже использует $RANDOM отрабатывает лучше? Там теория вероятностей работает иначе?

Desmond_Hume ★★★★★
() автор топика
Ответ на: комментарий от i-rinat

Наверное, это будет совсем уже извращением, но связка «$RANDOM_$RANDOM» уже гораздо надёжнее по уникальности будет. Чтобы сразу совпало два номера - это уже слишком).

Desmond_Hume ★★★★★
() автор топика
Ответ на: комментарий от Desmond_Hume

Тебе уже сказали рабочий способ. Если «${filename}» — уникальные имена, то «${filename}.jpg» тоже будут уникальные. При условии, что изначально .jpg-файлов вообще в директории не было.

i-rinat ★★★★★
()