Страницы

Поиск по вопросам

Показаны сообщения с ярлыком ffmpeg. Показать все сообщения
Показаны сообщения с ярлыком ffmpeg. Показать все сообщения

воскресенье, 26 января 2020 г.

Java объединение видеофайлов в один FFmpeg

#java #видео #ffmpeg #javacv

Код:

for (File f : files) {
            FrameGrabber grabber = new FFmpegFrameGrabber(f.getPath());
            grabber.start();
            while ((frame = grabber.grab()) != null) {
                recorder.record(frame);
            }
            grabber.stop();
        }


И вроде работает нормально, но если файлов много, то долго очень. Есть какой-нибудь
метод у этой библиотеки, чтобы просто склеить файлы, а не "грабить" каждый? 
    


Ответы

Ответ 1



Посмотрите в сторону FfmpegController.concatAndTrimFilesMP4Stream(): package org.ffmpeg.android.test; import java.io.File; import java.util.ArrayList; import java.util.Locale; import net.sourceforge.sox.SoxController; import org.ffmpeg.android.Clip; import org.ffmpeg.android.FfmpegController; import org.ffmpeg.android.ShellUtils; public class ConcatTest { public static void test (String videoRoot, String fileTmpPath, String fileOut, double fadeLen) throws Exception { File fileTmp = new File(fileTmpPath); File fileAppRoot = new File(""); File fileVideoRoot = new File(videoRoot); FfmpegController fc = new FfmpegController(null, fileTmp); SoxController sxCon = new SoxController(null, fileAppRoot, null); ArrayList listVideos = new ArrayList(); String[] fileList = fileVideoRoot.list(); for (String fileVideo : fileList) { if (fileVideo.endsWith("mp4")) { Clip clip = new Clip(); clip.path = new File(fileVideoRoot,fileVideo).getCanonicalPath(); fc.getInfo(clip); clip.duration = clip.duration-fadeLen; listVideos.add(clip); } } Clip clipOut = new Clip (); clipOut.path = new File(fileOut).getCanonicalPath(); fc.concatAndTrimFilesMP4Stream(listVideos, clipOut, false, false, new ShellUtils.ShellCallback() { @Override public void shellOut(String shellLine) { System.out.println("fc>" + shellLine); } @Override public void processComplete(int exitValue) { if (exitValue < 0) System.err.println("concat non-zero exit: " + exitValue); } }); } } Взято отсюда

Ответ 2



Возможно это вам поможет: cmd="( " h264options="-vcodec libx264 -b 512k -flags +loop+mv4 -cmp 256 \ -partitions +parti4x4+parti8x8+partp4x4+partp8x8+partb8x8 \ -me_method hex -subq 7 -trellis 1 -refs 5 -bf 3 \ -flags2 +bpyramid+wpred+mixed_refs+dct8x8 -coder 1 -me_range 16 \ -g 250 -keyint_min 25 -sc_threshold 40 -i_qfactor 0.71 -qmin 10\ -qmax 51 -qdiff 4" outfile="out-`date +%F-%H%M.%S`.mp4" for i; do cmd="${cmd}ffmpeg -i $i -ab 256000 -vb 10000000 -mbd rd -trellis 2 -cmp 2 -subcmp 2 -g 100 -f mpeg -; " done cmd="${cmd} ) | ffmpeg -y -i - -threads 8 ${h264options} -vb 10000000 -acodec libfaac -ar 44100 -ab 128k -s 1280x720 ${outfile}" echo "${cmd}" eval ${cmd}

среда, 22 января 2020 г.

Как конвертировать видео с avi в mkv формат

#python #python_3x #opencv #video #ffmpeg

Я занимаюсь обработкой видео и столкнулся с проблемой конвертации формата avi в mkv.
Для решения этой проблемы использовал библиотеку opencv, но не один кодек не смог записать
видео в mkv формате.

fourcc = cv2.VideoWriter_fourcc(*'DIB ')
out = cv2.VideoWriter('output.mkv', fourcc, 20.0, (frames[0].shape[1], frames[0].shape[0]))

for frame in frames:
    out.write(frame)
out.release()


Один из вариантов записи в mkv

После этого я нашел библиотеку ffmpy она может конвертировать из любого формата в
любой. Я решил, что результат своей обработки я буду сохранять в avi формат, а потом
конвертировать в mkv при помощи такого кода

def convertVideo():
    ff = ffmpy.FFmpeg(
        inputs={'output.avi': None},
        outputs={'output.mkv': None}
    )
    ff.run()


Данный фрагмент действительно конвертирует avi в mkv, но если avi файл создан при
помощи opencv, то конвертация не проходит. 
Как записать файл в mkv формат на виндоус при помощи opencv и python?
Как при помощи ffmpy конвертировать файл полученный opencv в формате avi в формат mkv?
    


Ответы

Ответ 1



Решение было очень просто нужно было использовать кодек MJPG типа. fourcc = cv2.VideoWriter_fourcc(*'MJPG') out = cv2.VideoWriter('output.mkv', fourcc, 20.0, (frames[0].shape[1], frames[0].shape[0])) for frame in frames: out.write(frame) out.release() Данный код позволяет записывать файлы в mkv формате.

воскресенье, 12 января 2020 г.

Как склеить видео ffmpeg( все в папке)

#ffmpeg

Как можно, используя утилиту ffmpeg, одной командой склеить все видео которые находятся
в одной папке? 
    


Ответы

Ответ 1



Выполнение этой операции хорошо описано в документации ffmpeg'a: ffmpeg -f concat -i <(for f in ./*.wav; do echo "file '$PWD/$f'"; done) -c copy output.wav ffmpeg -f concat -i <(printf "file '$PWD/%s'\n" ./*.wav) -c copy output.wav ffmpeg -f concat -i <(find . -name '*.wav' -printf "file '$PWD/%p'\n") -c copy output.wav Подробнее можно узнать тут: https://trac.ffmpeg.org/wiki/Concatenate

понедельник, 6 января 2020 г.

аналог avformat_open_input со строкой вместо файла

#cpp #ffmpeg

Есть строка с SDP информацией, содержащей всю нужную информацию по кодекам. Не хочется
создавать для нее файл, передавать его в avformat_open_input, а затем удалять и так
каждый раз.  А надо бы разбирать sdp-строку и настраивать тип входящего кодека и проч.
без создания файла.
Я не нашел функционала ffmpeg, который бы со строки инитил бы кодеки. Может, кто-то
знает его?
Или придется писать свой парсер и вручную настраивать кодеки?
    


Ответы

Ответ 1



Смотря что понимать под нужным функционалом. Ты можешь созать свой AVIO контекст, а он, в качестве источника данных, может хоть базу данных, хоть общую память, хоть просто кусок памяти использовать. Курить: avio_alloc_context() AVFormatContext::pb avformat_open_input() Т.е. алгоритм ваших действий будет примерно такой: Аллоцировать AVFormatContext (avformat_alloc_context()) Аллоцировать AVIOContext с нужными функциями, и структурой контекста Присвоить AVFormatContext::pb значение вашего контекста IO Вызвать avformat_open_input() где первым параметром передать указатель на ваш, уже аллоцированный, контекст формата - он любезно им воспользуется. При вызове вашей процедуры чтения вполне возможно, что запросится только часть данных, поэтому нужно где-то хранить позицию чтения (opaque вам в помощь) и контроллировать границу данных (когда у вас осталось, допустим, 2 байта, а запросили буфер 1024 - записать только 2 и вернуть реальное число записанный байт, т.е. снова - 2). А вот и рабочий, компилируемый (GCC 4.9, FFmpeg 2.8.6) пример: #include #include #include extern "C" { #include } using namespace std; static const char* SDP_DATA = R"( v=0 o=- 1376063087593 1 IN IP4 127.0.0.1 s=- t=0 0 m=audio 50008 RTP/AVP 0 c=IN IP4 192.168.2.196 a=rtcp:50009 IN IP4 192.168.2.196 a=rtpmap:0 PCMU/8000 a=sendrecv m=video 50010 RTP/AVP 120 c=IN IP4 192.168.2.196 a=rtcp:50011 IN IP4 192.168.2.196 a=rtpmap:120 VP8/90000 a=sendrecv a=rtcp-fb:* nack a=rtcp-fb:* ccm fir )"; struct SdpOpaque { using Vector = std::vector; Vector data; Vector::iterator pos; }; int sdp_read(void *opaque, uint8_t *buf, int size) noexcept { assert(opaque); assert(buf); auto octx = static_cast(opaque); if (octx->pos == octx->data.end()) { return 0; } auto dist = static_cast(std::distance(octx->pos, octx->data.end())); auto count = std::min(size, dist); std::copy(octx->pos, octx->pos + count, buf); octx->pos += count; return count; } int sdp_open(AVFormatContext **pctx, const char *data, AVDictionary **options) noexcept { assert(pctx); *pctx = avformat_alloc_context(); assert(*pctx); const size_t avioBufferSize = 4096; auto avioBuffer = static_cast(av_malloc(avioBufferSize)); auto opaque = new SdpOpaque(); opaque->data = SdpOpaque::Vector(data, data + strlen(data)); opaque->pos = opaque->data.begin(); auto pbctx = avio_alloc_context(avioBuffer, avioBufferSize, 0, opaque, sdp_read, nullptr, nullptr); assert(pbctx); (*pctx)->pb = pbctx; auto infmt = av_find_input_format("sdp"); return avformat_open_input(pctx, "memory.sdp", infmt, options); } void sdp_close(AVFormatContext **fctx) noexcept { assert(fctx); auto ctx = *fctx; // Opaque can be non-POD type, free it before and assign to null auto opaque = static_cast(ctx->pb->opaque); delete opaque; ctx->pb->opaque = nullptr; avio_close(ctx->pb); avformat_close_input(fctx); } int main() { av_register_all(); avformat_network_init(); AVFormatContext *sdpctx = nullptr; sdp_open(&sdpctx, SDP_DATA, nullptr); av_dump_format(sdpctx, 0, "memory.sdp", 0); // Copy settings to target context from SDP context: /* for (size_t i = 0; i < sdpctx->nb_streams; ++i) { AVStream *st = avformat_new_stream(otherctx, nullptr); st->id = i; avcodec_copy_context(st->codec, sdpctx->streams[i]->codec); st->time_base = sdpctx->streams[i]->time_base; } */ sdp_close(&sdpctx); return 0; } После запуска выводит: Input #0, sdp, from 'memory.sdp': Metadata: title : - Duration: N/A, bitrate: N/A Stream #0:0: Audio: pcm_mulaw, 8000 Hz, 1 channels, 64 kb/s Stream #0:1: Video: vp8, none, 90k tbn Собственно, что и описано в SDP.

вторник, 31 декабря 2019 г.

Python и FFmpeg: создать видео с аудио за один проход или иначе ускорить процесс

#python #windows #ffmpeg #видео

пытаюсь подружить Python и FFmpeg под Windows.

Необходимо из набора изображений и звуковых дорожек (хранятся в памяти программы
как numpy array) сделать одно длинное видео. 

Смог сделать это в 2 прохода: 


сначала создаю видео файл без аудио дорожки, 
потом прибавляю к нему аудио, но хотелось бы оптимальнее и быстрее:


 

ffmpeg -y -f rawvideo -vcodec rawvideo -s 1920x1080 -pix_fmt bgr24 -r 5.00 ^
       -i pipe:0 -an -vcodec libx264 -preset medium -pix_fmt yuv420p video.avi


- создаю видео

ffmpeg -y -f s16le -acodec pcm_s16le -ar 44100 -ac 1 ^
       -i pipe:0 -i video.avi -c:v h264 -c:a ac3 videoANDaudio.avi


- добавляю аудио.

Можно ли сделать это в 1 проход? Т.е. как то надо передавать видео и аудио одновременно,
в 2 потока. Думал о NamedPipe, но не нашел в интернете информацию о том, как его создать
в Windows.

PS. Предложите технологию, лучше FFmpeg, для решения задачи, если такая имеется.
    


Ответы

Ответ 1



Про обработку видео в Python PS. Предложите технологию, лучше FFMpeg для решения задачи, если такая имеется. PyAV Есть такой замечаетельный проект: PyAV. Это питонячие биндинги к libav. Для работы с видео в Python я использую его. АPI PyAV сильно не совпадает с аргументами ffmpeg и ванильного libav, но при этом оно кажется весьма понятным и логичным в контексте Python. PyAV: Пример https://gist.github.com/w495/7d843bd5d42fc35e15486ec60a87d9bf import av from av.video.frame import VideoFrame from av.video.stream import VideoStream # В этом списке будем хранить кадры в виде numpy-векторов. array_list = [] # Откроем контейнер на чтение input_container = av.open('input.mp4') # Применим «инверсное мультиплексирование» =) # Получим пакеты из потока. input_packets = input_container.demux() # Получии все кадры видео и положим их в `array_list`. for packet in input_packets: if isinstance(packet.stream, VideoStream): # Получим все кадры пакета frames = packet.decode() for raw_frame in frames: # Переформатируем кадры, к нужному размеру и виду. # Это лучше делать средствами pyav (libav) # потому что быстрее. frame = raw_frame.reformat(32, 32, 'rgb24') # Превратить каждый кадр в numpy-вектор (dtype=int). array = frame.to_nd_array() # Положим в список numpy-векторов. array_list += [array] # Откроем контейнер на запись. output_container = av.open('out.mp4', mode='w', format='mp4') # Добавим к контейнеру поток c кодеком h264. output_stream = output_container.add_stream('h264', rate=25) # В этом списке будем хранить пакеты выходного потока. output_packets = [] # Пройдем по списку векторов и упакуем их в пакеты выходного протока. for array in array_list: # Построим видео-кадр по вектору. frame = VideoFrame.from_ndarray(array, format='rgb24') # Запакуем полученный кадр. packet = output_stream.encode(frame) # Положим в список пакетов. output_packets += [packet] # Применим «прямое мультиплексирование» =) # Для каждого пакета вызовем мультиплексор. for packet in output_packets: if packet: output_container.mux(packet) output_container.close() Еще примеры: encode_frames.py — создает видео из последовательности переданных изображений; для работы с изображениями использует OpenCV. На самом деле, тут можно обойтись и без OpenCV. gen_rgb_rotate.py — создает видео, в котором цвет кадра меняется в последовательности цветов радуги. encode.py — записывает кадры исходного видео, до тех пор пока, их количество видео-кадров не превысит 100. Сам я активно использую PyAV в этом проекте: Video Shot Detector. Возможно, в его коде будет что-то полезное для Вас. https://github.com/w495/python-video-shot-detector PyAV: Установка Есть маленькая проблема в том, что PyAV достаточно тяжело собрать. Тем более под Windows. Для сборки из исходников требуются конкретные версии зависимостей (ffmpeg, h264 и пр.) Но есть уже готовые сборки для питонячьего пакетного менеджера conda. Я не пробовал, но кажется достаточно просто поставить conda на Windows: Выбираете нужный вам инсталлятор тут: Miniconda. Я предполагаю что это будет Python 2.7 64-bit (exe installer) Дальше запускаете и следуете его инструкциям. Далее как описано в Windows Miniconda Install в командной строке Windows conda list . После этого вам потребуется поставить нужные пакеты. conda install numpy conda install -c danielballan pyav # или conda install -c soft-matter pyav Я не уверен, что это все заведется под Windows — я не пробовал. Если нет, то на официальном сайте есть инcтрукция как собрать самостоятельно: PyAV Installation On Windows; + еще есть вот такая заметка PyAV for Windows. Авторы библиотеки весьма отзывчивы, и им можно смело задавать вопросы и писать о проблемах тут: PyAV Issues. Альтернативы Из альтернатив, еще наталкивался на Avpy — просто биндинг к ffmpeg и libav; pyffmpeg — тоже биндинг к ffmpeg; ffmpeg-cffi-py — еще один биндинг, работает только на Windows; pyVideoInput — используют свой обработчик видео без ffmpeg, выглядит он слишком заморочено; Python GStreamer — используют свой обработчик видео, пока не осилил, но при беглом осмотре, выглядит удобным; Python OpenCV — обработка видео через OpenCV изначально похожа на забивание гвоздей микроскопом; MoviePy — библиотека для не линейного монтажа видео, но кодировать ей тоже можно. Отчасти тоже забивание гвоздей микроскопом. Про Python GStreamer: Using GStreamer with Python; Getting started with GStreamer with Python; Python GStreamer Tutorial. Качество альтернатив Avpy у меня почему-то так и не завелся. pyffmpeg тоже сходу не собирается, а перед началом установки приходится править код. ffmpeg-cffi-py не смог найти путей до нужных библиотек. Остальные пока не пробовал.

Ответ 2



Про FFMpeg Кратко Можно ли сделать это в 1 проход Можно. Для этого нужно ffmpeg в одной команде передать и звук и видео. Это легко делается, если просто исходной команде передать еще один входной поток ffmpeg -f rawvideo -codec:v rawvideo -s 1920x1080 -pix_fmt bgr24 -r 5.00 -i pipe:0 # video -f s16le -codec:a pcm_s16le -ar 44100 -ac 1 -i pipe:0 # audio -codec:v libx264 -preset medium -pix_fmt yuv420p -codec:a ac3 Но проблема в том, что вы посылаете ему изображения и семплы через stdin (pipe:0). Самым простым решением было бы: Записать изображения из Вашей программы в один файл. Семплы записать в другой файл. причем эти действия можно совершать параллельно (multiprocessing); Оба файла скормить как -i filename. Предполагаю, что это будет работать быстрее. но хотелось бы оптимальнее и быстрее. Для FFmpeg ключ -threads со значением 0 позволяет работаеть многопоточно, и распределять вычисления по всем процессорам. Много букв У ffmpeg есть некоторая особенность — можно передавать много одноименных аргументов. Причем порядок этих аргументов имеет значение. Во многих случаях эта особенность не очень заментна. Но в какой-то момент сильно выстреливает. Порядок аргументов подчиняется следуюшей логике. Параметры входных потоков сначала общие: формат, смещение по времени и пр, что-то типа: -ss '00:05:00' — кодировать с пятой минуты. потом раздельные: видео, аудио, субтитры: -f rawvideo -codec:v rawvideo ...; -f s16le -codec:a pcm_s16le ...; Параметры выходных потоков сначала раздельные: видео, аудио, субтитры: -codec:v 'libx264' -profile:v 'main' -b:v '1000k' -filter:v "yadif=1:-1:0,scale=0:576"; -strict 'experimental' -codec:a 'aac' -b:a '196k' -ac '6'. потом общие: смещение по времени, формат контейнера и пр, что-то типа: * -ss '00:05:01' -to '00:05:30' * -movflags '+faststart' -f 'mp4' -y file_name.mp4 При соблюдении этой логики можно будет в одной команде собирать, видео более чем из одного потока. И даже больше чем в один поток: Creating Multiple Outputs. У меня под рукой есть несколько примеров (из Bulk Video Converter). Кажется, что запись видео с экрана и аудио с микрофона очень похожа на вашу ситуацию. /usr/bin/ffmpeg \ -threads '0' \ -f x11grab \ -s wxga \ -i ':0.0' \ -f alsa \ -i hw:0 \ -codec:v 'libx264' \ -profile:v 'main' \ -b:v '1000k' \ -filter:v "yadif=1:-1:0,scale=0:576" \ -codec:a 'libmp3lame' \ -b:a '196k' \ -f 'mp4' -y 'video_pal_sd.mp4' \ На *nix это работает. Предполагаю, что на Windows будет работать с точностью до имен кодеров. Я не до конца понимаю, вашу задачу, потому тут сейчас распишу, что означает каждый из аргументов. Настройки входных потоков: Входное видео: -f x11grab — формат аудио, в моем случае — название драйвера; -s wxga — размер входного видео-кадра, тут мы говорим ffmpeg как воспринимать, то что мы его передаем — в моем случае: размер моего монитора — -i ':0.0' — тут, номер дисплея, но возомжен любой иной источник; Входное аудио: -f 'alsa — формат аудио, в моем случае — название драйвера аудио-карты; -i 'hw:0' — тут, аудио-карты (входной поток — т.е. микрофон), но возможен любой иной источник; Настройки результирующих потоков: Результирующее видео: -codec:v 'libx264' — определяем кодек, которым будем кодировать видео (h264). -profile:v 'main' — профиль кодирования для h264. -b:v '1000k' — битрейт для видео-потока. -filter:v "yadif=1:-1:0,scale=0:576" — фильтры для видео-потока: yadif=1:-1:0 — убирает чересстрочность; scale=0:576 — приводит выходной видео-поток к ножному размеру — этот размер никак не соотносится с размером входного потока. Результирующее аудио: -codec:a 'libmp3lame' — определяем кодек, которым будем кодировать аудио (mp3). -b:a '196k' — битрейт для аудио-потока. Настройки результирующего файла (контейнера): * -f 'mp4' — формат, можно не указывать, и тогда ffmpeg попробует «догадаться» сам; * -y 'video_pal_sd.mp4' — флаг перезаписи -y и имя выходного файла.

понедельник, 16 декабря 2019 г.

Вырезать кадры из видео

#cpp #c #video #opencv #ffmpeg

На вход подается видео с большим содержанием белых кадров. Их надо вырезать.

Кадров белых может быть 5-90% всего видео. Поэтому ручками их вырезать не вариант.
У меня opencv составляет txt-документ с номерами кадров, можно указывать время кадра,
или хранить данные в массиве.

Думал, с помощью ffmpeg их вырезать, но столкнулся с проблемой, что вырезать с помощью
txt он не может. Или я не нашел такой вариант.

Как решить данную проблему?

Может быть, другой проигрыватель использовать, или сам opencv умеет так делать?
    


Ответы

Ответ 1



OpenCV умеет работать с FFmpeg: использует его муксер и кодеки. Либо, использовать самому libavformat, libavcodec и иже с ними (либы FFmpeg), декодировать кадр, отдавать OpenCV, детектировать, что он "белый" пропускать его в итоговом кодеке/муксере. Естественно, нужно корректировать PTS/DTS. Как использовать FFmpeg для декодирования/кодирования, муксинга/демуксинга можно в его документации, примерах. Для приведения к нужному формуту пикселя использовать swscale()

четверг, 11 июля 2019 г.

Разрезать видео с помощью opencv c++

С помощью videocapture из видеоролика длиной N минут делать много удалений длиной несколько секунд. Знаю есть вариант, через VideoWriter просто переписывать видео. Но зачем он тогда нужен, когда через вызов cmd можно использовать ffmpeg?
Ищу нормальный способ из in.mp4 вырезать секундные куски и получить out.mp4 без ffmpeg. И еще вопрос, везде при разрезке in.mp4 потом надо склеивать все куски. Избежать такого возможно?


Ответ

Нарезать видеофайл на отдельные отрезки OpenCV позволяет, но по большому счёту это неподходящий для данной задачи инструмент. Всё равно, что саблей косить траву. Вроде и замах красивый, а некое неудоумение не отпускает.
В OpenCV класс VideoWriter является обёрткой над FFmpeg и предоставляет лишь базовый функционал по сохранению видеокадров в файл. Создан он лишь для удобства разработки приложений, не претендующих на гибкую настройку параметров видеоформатов и кодеков, которые неизбежно приходится учитывать непосредственно при работе с C API FFmpeg.
Чтобы не заниматься "склеиванием" кусков, нужно, используя тот же C API FFmpeg, читать видеокадры из исходного файла и записывать желаемые в отдельный файл. Очень вероятно, что для этой операции и промежуточные декодирование с кодированием не потребуются. Читаем из входного потока AVPacket и без перекодирования записываем в выходной поток.

среда, 10 июля 2019 г.

Склейка видео с помощью ffmpeg

Добрый день, встала задача склеить несколько видео в одно (количество видео всегда разное (т.е. возможно 1, возможно 2, возможно n), собственно нагуглил такой вот пример:
ffmpeg -i new_1.mp4 -i new_2.mp4 -i new_3.mp4 -i new_4.mp4 -filter_complex "nullsrc=size=640x480 [base]; \ [0:v] setpts=PTS-STARTPTS, scale=320x240 [upperleft]; \ [1:v] setpts=PTS-STARTPTS, scale=320x240 [upperright]; \ [2:v] setpts=PTS-STARTPTS, scale=320x240 [lowerleft]; \ [3:v] setpts=PTS-STARTPTS, scale=320x240 [lowerright]; \ [base][upperleft] overlay=shortest=1 [tmp1]; \ [tmp1][upperright] overlay=shortest=1:x=320 [tmp2]; \ [tmp2] [lowerleft] overlay=shortest=1:y=240 [tmp3]; \ [tmp3][lowerright] overlay=shortest=1:x=320:y=240" -c:v output.mp4
в данном примере идет склейка 4-х видео, но не совсем понимаю, возможно ли вместо upperright - писать позицию видео?
пример. положим что канва на которой работает будет 1280 на 768 и у нас есть 6 видео (все видео одинакового размера, но имеют разную продолжительность, положим что размер одного видео 1024 на 768). Пробуем разместить их в две строки, по три видео на строку. получаем следующие размеры для видео: ширина: 1280/3 = 426 пикселей высота: 768 / 2 = 384, где 2 - количество строк
собственно вопросы: 1) могу ли я задавать позицию видео не так
[0:v] setpts=PTS-STARTPTS, scale=320x240 [upperleft];
а вот так например:
[0:v] setpts=PTS-STARTPTS, scale=426x384 [0,384];
[1:v] setpts=PTS-STARTPTS, scale=426x384 [426,384];
или как-то по другому? как правильно сделать сетку в ffmpeg?
2) в случае с видео, которые разные по времени, по истечению самого короткого видео картинка дальше тормозиться, но звуковая дорожка идет, как решить данные вопрос? подогнать короткое видео по таймингу к самому длинному? тогда как это делается? нечто вроде заполняем 4-ми кадрами остаток?
спасибо за помощь.


Ответ

upperleft здесь - это не позиция, а псевдоним для потока-результата scale
[0:v] setpts=PTS-STARTPTS, scale=320x240 [upperleft];
Взять поток 0:v, пожать его до 320x240 и обозвать upperleft для дальнейшего использования. Здесь видео пока никак не компонуется с другими - только пережимается до нужного размера.
[base][upperleft] overlay=shortest=1 [tmp1]
Взять потоки base и upperleft, применить overlay с такими параметрами и выдать результат в поток tmp1. Сами имена потоков могут быть любые. Вот тут как раз и идёт склейка видео.
Позиция оверлея на результирующем потоке - это параметры overlay x и y, которые видны в последних 3 строках. Вот список возможных параметров. По второму вопросу посмотрите eof_action и repeatlast
Для 6 видео что-то вроде этого получится:
ffmpeg -i new_1.mp4 -i new_2.mp4 -i new_3.mp4 -i new_4.mp4 -i new_5.mp4 -i new_6.mp4 -filter_complex "nullsrc=size=1280x768 [base]; \ [0:v] setpts=PTS-STARTPTS, scale=426x384 [upper1]; \ [1:v] setpts=PTS-STARTPTS, scale=426x384 [upper2]; \ [2:v] setpts=PTS-STARTPTS, scale=426x384 [upper3]; \ [3:v] setpts=PTS-STARTPTS, scale=426x384 [lower1]; \ [4:v] setpts=PTS-STARTPTS, scale=426x384 [lower2]; \ [5:v] setpts=PTS-STARTPTS, scale=426x384 [lower3]; \ [base][upper1] overlay=shortest=1 [tmp1]; \ [tmp1][upper2] overlay=shortest=1:x=426 [tmp2]; \ [tmp2][upper3] overlay=shortest=1:x=852 [tmp3]; \ [tmp3][lower1] overlay=shortest=1:y=384 [tmp4]; \ [tmp4][lower2] overlay=shortest=1:y=384:x=426 [tmp5]; \ [tmp5][lower3] overlay=shortest=1:y=384:x=852" -c:v output.mp4

вторник, 12 марта 2019 г.

Как конвертировать видео с avi в mkv формат

Я занимаюсь обработкой видео и столкнулся с проблемой конвертации формата avi в mkv. Для решения этой проблемы использовал библиотеку opencv, но не один кодек не смог записать видео в mkv формате.
fourcc = cv2.VideoWriter_fourcc(*'DIB ') out = cv2.VideoWriter('output.mkv', fourcc, 20.0, (frames[0].shape[1], frames[0].shape[0]))
for frame in frames: out.write(frame) out.release()
Один из вариантов записи в mkv
После этого я нашел библиотеку ffmpy она может конвертировать из любого формата в любой. Я решил, что результат своей обработки я буду сохранять в avi формат, а потом конвертировать в mkv при помощи такого кода
def convertVideo(): ff = ffmpy.FFmpeg( inputs={'output.avi': None}, outputs={'output.mkv': None} ) ff.run()
Данный фрагмент действительно конвертирует avi в mkv, но если avi файл создан при помощи opencv, то конвертация не проходит. Как записать файл в mkv формат на виндоус при помощи opencv и python? Как при помощи ffmpy конвертировать файл полученный opencv в формате avi в формат mkv?


Ответ

Решение было очень просто нужно было использовать кодек MJPG типа.
fourcc = cv2.VideoWriter_fourcc(*'MJPG') out = cv2.VideoWriter('output.mkv', fourcc, 20.0, (frames[0].shape[1], frames[0].shape[0]))
for frame in frames: out.write(frame) out.release()
Данный код позволяет записывать файлы в mkv формате.

четверг, 14 февраля 2019 г.

аналог avformat_open_input со строкой вместо файла

Есть строка с SDP информацией, содержащей всю нужную информацию по кодекам. Не хочется создавать для нее файл, передавать его в avformat_open_input, а затем удалять и так каждый раз. А надо бы разбирать sdp-строку и настраивать тип входящего кодека и проч. без создания файла. Я не нашел функционала ffmpeg, который бы со строки инитил бы кодеки. Может, кто-то знает его? Или придется писать свой парсер и вручную настраивать кодеки?


Ответ

Смотря что понимать под нужным функционалом. Ты можешь созать свой AVIO контекст, а он, в качестве источника данных, может хоть базу данных, хоть общую память, хоть просто кусок памяти использовать.
Курить:
avio_alloc_context() AVFormatContext::pb avformat_open_input()
Т.е. алгоритм ваших действий будет примерно такой:
Аллоцировать AVFormatContext (avformat_alloc_context()) Аллоцировать AVIOContext с нужными функциями, и структурой контекста Присвоить AVFormatContext::pb значение вашего контекста IO Вызвать avformat_open_input() где первым параметром передать указатель на ваш, уже аллоцированный, контекст формата - он любезно им воспользуется.
При вызове вашей процедуры чтения вполне возможно, что запросится только часть данных, поэтому нужно где-то хранить позицию чтения (opaque вам в помощь) и контроллировать границу данных (когда у вас осталось, допустим, 2 байта, а запросили буфер 1024 - записать только 2 и вернуть реальное число записанный байт, т.е. снова - 2).
А вот и рабочий, компилируемый (GCC 4.9, FFmpeg 2.8.6) пример:
#include #include #include
extern "C" { #include }
using namespace std;
static const char* SDP_DATA = R"( v=0 o=- 1376063087593 1 IN IP4 127.0.0.1 s=- t=0 0 m=audio 50008 RTP/AVP 0 c=IN IP4 192.168.2.196 a=rtcp:50009 IN IP4 192.168.2.196 a=rtpmap:0 PCMU/8000 a=sendrecv m=video 50010 RTP/AVP 120 c=IN IP4 192.168.2.196 a=rtcp:50011 IN IP4 192.168.2.196 a=rtpmap:120 VP8/90000 a=sendrecv a=rtcp-fb:* nack a=rtcp-fb:* ccm fir )";
struct SdpOpaque { using Vector = std::vector; Vector data; Vector::iterator pos; };
int sdp_read(void *opaque, uint8_t *buf, int size) noexcept { assert(opaque); assert(buf); auto octx = static_cast(opaque);
if (octx->pos == octx->data.end()) { return 0; }
auto dist = static_cast(std::distance(octx->pos, octx->data.end())); auto count = std::min(size, dist);
std::copy(octx->pos, octx->pos + count, buf); octx->pos += count;
return count; }
int sdp_open(AVFormatContext **pctx, const char *data, AVDictionary **options) noexcept { assert(pctx); *pctx = avformat_alloc_context(); assert(*pctx);
const size_t avioBufferSize = 4096; auto avioBuffer = static_cast(av_malloc(avioBufferSize)); auto opaque = new SdpOpaque();
opaque->data = SdpOpaque::Vector(data, data + strlen(data)); opaque->pos = opaque->data.begin();
auto pbctx = avio_alloc_context(avioBuffer, avioBufferSize, 0, opaque, sdp_read, nullptr, nullptr); assert(pbctx);
(*pctx)->pb = pbctx;
auto infmt = av_find_input_format("sdp");
return avformat_open_input(pctx, "memory.sdp", infmt, options); }
void sdp_close(AVFormatContext **fctx) noexcept { assert(fctx); auto ctx = *fctx;
// Opaque can be non-POD type, free it before and assign to null auto opaque = static_cast(ctx->pb->opaque); delete opaque; ctx->pb->opaque = nullptr;
avio_close(ctx->pb); avformat_close_input(fctx); }
int main() { av_register_all(); avformat_network_init();
AVFormatContext *sdpctx = nullptr; sdp_open(&sdpctx, SDP_DATA, nullptr);
av_dump_format(sdpctx, 0, "memory.sdp", 0); // Copy settings to target context from SDP context: /* for (size_t i = 0; i < sdpctx->nb_streams; ++i) { AVStream *st = avformat_new_stream(otherctx, nullptr); st->id = i; avcodec_copy_context(st->codec, sdpctx->streams[i]->codec); st->time_base = sdpctx->streams[i]->time_base; } */
sdp_close(&sdpctx); return 0; }
После запуска выводит:
Input #0, sdp, from 'memory.sdp': Metadata: title : - Duration: N/A, bitrate: N/A Stream #0:0: Audio: pcm_mulaw, 8000 Hz, 1 channels, 64 kb/s Stream #0:1: Video: vp8, none, 90k tbn
Собственно, что и описано в SDP.