Используем ffmpeg в Python: DAR, scale и работа с видео с неправильно записанным width / height

Столкнулся с довольно специфичной проблемой связанной с видеороликами, в которых «неправильно» указана высота и ширина. Изначально стояла задача извлекать на определенной временной метке кадр при помощи ffmpeg и изначально все было хорошо, ниже привожу пример команды, с помощью которой можно спокойно извлекать кадры из видео:

ffmpeg -ss 00:0:02 -i file.mp4 -frames:v 1 -q:v 2 out.jpg

все предельно просто, берется кадр со второй секунды видео. Так как я разрабатывал программу, которая будет обрабатывать сотни видео, в процессе тестирования попалось первый файл, извлечение кадра из которого отработало некорректно.

В частности файл имел разрешение 1080*720 пикселей, но по факту видео воспроизводилось горизонтально, т.е. оно не было широкоформатным, и справедливым было бы указать разрешение 720*1080 пикселей, а экспорт картинки происходил соответственно как изначальный размер видео в связи с чем извлеченный кадр получался широкоформатным. При этом, в видео не было метаданных, не было информации об rotation и пр.

К решению проблемы. Скажу сразу, возможно, это решение не самое правильное и красивое, но оно работает. Ориентироваться мы будем на DAR (display aspect ratio) для того, чтобы правильно посчитать ширину и заскейлить получаемый кадр с правильным соотношением сторон. Ниже код, который собственно делает все, что необходимо:

def get_resolution(self, file):
    """Вернет разрешение картинки видео"""
    probe = ffmpeg.probe(file)
    video_bitrate = next(s for s in probe['streams'] if s['codec_type'] == 'video')
    with_height = (video_bitrate['width'], video_bitrate['height'])
    return with_height

@staticmethod
def get_scale(file):
    """
    Вернет список ширина / высота для скейла
    :param file:
    :return:
    """
    probe = ffmpeg.probe(file)
    dar = probe['streams'][0].get('display_aspect_ratio')
    height = probe['streams'][0].get('height')
    width = probe['streams'][0].get('width')
    x, y = dar.split(':')
    width = height * int(x) / int(y)
    return [int(width), height]

Как видно из видео мы берем dar, пускай это будет 16:9 (x, y) и текущее значение резолюции видео. Формула подсчета новой ширины следующая: width = height * x / y полученное значение, это наша новая ширина. Функция возвращает также и высоту, эти два значения теперь необходимо подставить в команду ffmpeg и получим следующее:

ffmpeg -ss 00:0:02 -i file.mp4 -frames:v 1 -q:v 2 -vf scale=405×720 out.jpg

где в scale 405 это ширина, а 720 высота. Такой прием помогает извлекать кадры из видео через ffmpeg и сохраняться правильное соотношение сторон, но при этом теряется оригинальный размер.