ffmpeg: обрабатывать видео с изменяющимся разрешением

#ffmpeg

#ffmpeg

Вопрос:

Я пишу программу, которая программно объединяет входной список видео. Проблема в том, что эти видео являются частями записанного потока, и их разрешение может меняться несколько раз в пределах одного и того же файла. В настоящее время, если это произойдет, ffmpeg завершается с ошибкой, сообщая, что невозможно объединить файлы с разными разрешениями. Есть ли способ заставить ffmpeg обрабатывать это автоматически? Хорошим решением было бы выборочное масштабирование кадров с неожиданным разрешением.

Вот список:

 ffmpeg -y -i 1.mkv -i 1.mka
-max_muxing_queue_size 10000
-preset veryfast -r 30 -crf 20 -b:a 96000 -vbr on
-strict experimental
-filter_complex '
color=black:s=320x240:d=7ms[black0];
aevalsrc=0:d=15ms[silence1];
[black0][0]concat=n=2:v=1:a=0
;
[1][silence1]concat=n=2:v=0:a=1
'
-map
 -map
 -c:v libvpx -c:a libopus output.webm

ffmpeg version 4.3.1 Copyright (c) 2000-2020 the FFmpeg developers
  built with Apple clang version 11.0.0 (clang-1100.0.33.17)
  configuration: --prefix=/usr/local/Cellar/ffmpeg/4.3.1_9 --enable-shared --enable-pthreads --enable-version3 --enable-avresample --cc=clang --host-cflags= --host-ldflags= --enable-ffplay --enable-gnutls --enable-gpl --enable-libaom --enable-libbluray --enable-libdav1d --enable-libmp3lame --enable-libopus --enable-librav1e --enable-librubberband --enable-libsnappy --enable-libsrt --enable-libtesseract --enable-libtheora --enable-libvidstab --enable-libvorbis --enable-libvpx --enable-libwebp --enable-libx264 --enable-libx265 --enable-libxml2 --enable-libxvid --enable-lzma --enable-libfontconfig --enable-libfreetype --enable-frei0r --enable-libass --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-libopenjpeg --enable-librtmp --enable-libspeex --enable-libsoxr --enable-videotoolbox --enable-libzmq --enable-libzimg --disable-libjack --disable-indev=jack
  libavutil      56. 51.100 / 56. 51.100
  libavcodec     58. 91.100 / 58. 91.100
  libavformat    58. 45.100 / 58. 45.100
  libavdevice    58. 10.100 / 58. 10.100
  libavfilter     7. 85.100 /  7. 85.100
  libavresample   4.  0.  0 /  4.  0.  0
  libswscale      5.  7.100 /  5.  7.100
  libswresample   3.  7.100 /  3.  7.100
  libpostproc    55.  7.100 / 55.  7.100
Input #0, matroska,webm, from '1.mkv':
  Metadata:
    encoder         : GStreamer matroskamux version 1.8.1.1
    creation_time   : 2021-03-02T13:44:03.000000Z
  Duration: 00:01:48.41, start: 0.710000, bitrate: 757 kb/s
    Stream #0:0(eng): Video: vp8, yuv420p(progressive), 320x240, SAR 1:1 DAR 4:3, 120 tbr, 1k tbn, 1k tbc (default)
    Metadata:
      title           : Video
Input #1, matroska,webm, from '1.mka':
  Metadata:
    encoder         : GStreamer matroskamux version 1.8.1.1
    creation_time   : 2021-03-02T13:44:03.000000Z
  Duration: 00:01:48.40, start: 0.703000, bitrate: 38 kb/s
    Stream #1:0(eng): Audio: opus, 48000 Hz, stereo, fltp (default)
    Metadata:
      title           : Audio
Codec AVOption preset (Configuration preset) specified for output file #0 (output.webm) has not been used for any stream. The most likely reason is either wrong type (e.g. a video option with no video streams) or that it is a private option of some encoder which was not actually used for any stream.
Stream mapping:
  Stream #0:0 (vp8) -> concat:in1:v0
  Stream #1:0 (opus) -> concat:in0:a0
  concat -> Stream #0:0 (libvpx)
  concat -> Stream #0:1 (libopus)
Press [q] to stop, [?] for help
[libvpx @ 0x7fe08a80bc00] v1.9.0
[libvpx @ 0x7fe08a80bc00] Bitrate not specified for constrained quality mode, using default of 256kbit/sec
Output #0, webm, to 'output.webm':
  Metadata:
    encoder         : Lavf58.45.100
    Stream #0:0: Video: vp8 (libvpx), yuv420p, 320x240 [SAR 1:1 DAR 4:3], q=-1--1, 256 kb/s, 30 fps, 1k tbn, 30 tbc (default)
    Metadata:
      encoder         : Lavc58.91.100 libvpx
    Side data:
      cpb: bitrate max/min/avg: 0/0/0 buffer size: 0 vbv_delay: N/A
    Stream #0:1: Audio: opus (libopus), 48000 Hz, stereo, flt, 96 kb/s (default)
    Metadata:
      encoder         : Lavc58.91.100 libopus
[Parsed_color_0 @ 0x7fe089815940] EOF timestamp not reliable
[Parsed_concat_2 @ 0x7fe088501980] Input link in0:v0 parameters (size 640x480, SAR 1:1) do not match the corresponding output link in0:v0 parameters (320x240, SAR 1:1)
[Parsed_concat_2 @ 0x7fe088501980] Failed to configure output pad on Parsed_concat_2
Error reinitializing filters!
Failed to inject frame into filter network: Invalid argument
Error while processing the decoded data for stream #0:0
[libopus @ 0x7fe08a810c00] 1 frames left in the queue on closing
Conversion failed!
 

Вот единственное такое видео с «плавающим» разрешением, которое нельзя объединить с цветным фильтром 320×240.

Комментарии:

1. Покажите свою команду ffmpeg и полный журнал.

2. Я добавил журнал.

Ответ №1:

если я не ошибаюсь, вы просто хотите объединить видео, которые могут иметь разные разрешения, тогда это сработает для вас, взгляните на данный код:

Объяснение: Здесь я создал pad (один тип контейнера), в который я помещаю видео, чтобы каждое видео автоматически вписывалось в заданный размер пэда, плюс еще одна вещь, если какое-либо из ваших видео отключено, чем команда завершится ошибкой, поэтому я добавил новый метод isVideoHaveAudioTrack() , который проверяет, есть ли в видео звук или нети если в видео нет звука, мы должны добавить звук без звука, чтобы команда out могла успешно работать.

 private boolean isVideoHaveAudioTrack(String path) {

    boolean isAudioTrackAvailable;
    MediaMetadataRetriever retriever = new MediaMetadataRetriever();
    try {
        retriever.setDataSource(path);
        String hasAudioStr = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_HAS_AUDIO);
        isAudioTrackAvailable = hasAudioStr != null amp;amp; hasAudioStr.equals("yes");
    } catch (Exception e) {
        isAudioTrackAvailable = false;
    }

    return isAudioTrackAvailable;
}


public static LinkedList<String> mergeVideo(ArrayList<Video> selectedVideos, String silencedAudio, String filepath) {

    String str3 = "";
    StringBuilder str4 = new StringBuilder(str3);
    StringBuilder str5 = new StringBuilder(str4.toString());

    boolean isAnyMuteVideo = false;

    LinkedList<String> commandList = new LinkedList<>();
    for (int i = 0; i < selectedVideos.size(); i  ) {
        commandList.add("-i");
        commandList.add(selectedVideos.get(i).getLocation());
        if (!isVideoHaveAudioTrack(selectedVideos.get(i).getPath())) {
            isAnyMuteVideo = true;
        }
        if (i == selectedVideos.size() - 1) {
            if (isAnyMuteVideo) {
                commandList.add("-i");
                commandList.add(silencedAudio);
            }
        }

        String str6 = str3   "["   i   ":v]fps=25,scale=w=min(iw*"   "1280"   "/ih\,"   "720"   "):h=min("  
                "1280"   "\,ih*"   "720"   "/iw), pad=w="   "720"  
                ":h="   "1280"   ":x=( "   "720"   "-iw)/2:y=("   "1280"   "-ih)/2,format=yuv420p,setsar=1,setpts=PTS-STARTPTS[v"   i   "];";

        if (isVideoHaveAudioTrack(selectedVideos.get(i).getPath())) {
            str4.append("[").append(i).append(":a]aformat=channel_layouts=stereo:sample_rates=44100,asetpts=PTS-STARTPTS[a").append(i).append("];");
            str5.append("[v").append(i).append("][a").append(i).append("]");
        } else {
            str4.append("[").append(selectedVideos.size()).append(":a]aformat=channel_layouts=stereo:sample_rates=44100,asetpts=PTS-STARTPTS[a").append(selectedVideos.size()).append("];");
            str5.append("[v").append(i).append("][a").append(selectedVideos.size()).append("]");
        }
        str3 = str6;
    }
    commandList.add("-filter_complex");
    commandList.add(str3   str4   str5   "concat=n="   selectedVideos.size()   ":v=1:a=1[v][a]");
    commandList.add("-map");
    commandList.add("[v]");
    commandList.add("-map");
    commandList.add("[a]");
    commandList.add("-c:v");
    commandList.add("libx264");
    commandList.add("-c:a");
    commandList.add("aac");
    commandList.add("-preset");
    commandList.add("ultrafast");
    commandList.add(filepath);
    return commandList;
}
 

Попробуйте это и сообщите нам, будет ли это работать для вас или нет с журналами ffmpeg, чтобы мы могли помочь вам, улучшив приведенный выше ответ.