Получите размер отображения для анаморфного видео из свойств метаданных оболочки

Я использую Microsoft.WindowsAPICodePack.Shell.ShellFile, чтобы получить размер видео (ширину и высоту) из пути к файлу.

public Size GetVideoSize(string videoFullPath)
{
    if (File.Exists(videoFullPath))
    {
        ShellFile shellFile = ShellFile.FromFilePath(videoFullPath);

        int videoWidth = (int)shellFile.Properties.System.Video.FrameWidth.Value;
        int videoHeight = (int)shellFile.Properties.System.Video.FrameHeight.Value;

        return new Size(videoWidth, videoHeight);
    }
    return Size.Empty;
}

Проблема в том, что этот метод не получает правильный размер для файла m4v. У Вас есть какие-то предложения? Что я могу использовать, чтобы получить фактическую ширину / высоту?

Пример: у меня есть видео в формате m4v с реальным размером 856x480.

  • если я посмотрю на свойства файла в проводнике Windows, размер будет 720x480 (неверно)
  • если я открываю видео в проигрывателе, видео отображается с правильным размером, даже если в деталях видео по-прежнему отображается размер 720 x 480
  • если я загружаю видео в элемент управления MediaElement в WPF, я получаю правильный размер через mediaElement.NaturalVideoWidth, mediaElement.NaturalVideoHeight, но проблема в том, что мне нужно получить размер в библиотеке классов, которая не имеет ссылок на WPF.

person melculetz    schedule 13.11.2012    source источник
comment
вы можете попробовать открыть файл и извлечь метаданные, разрешение может быть сохранено там   -  person fnurglewitz    schedule 13.11.2012
comment
См. stackoverflow.com/questions/11346136/ - аналогичным образом можно получить разрешение.   -  person Roman R.    schedule 20.11.2012
comment
Я не могу себе представить, что приложение с открытым исходным кодом FFmpeg выдаст неверную информацию, если вы его спросите. Инструмент командной строки FFmpeg.exe -i [путь к вашему файлу]. Может быть, подключите его к своему приложению? Или не использует внешний исполняемый файл. В противном случае вы могли бы увидеть метод FFmpeg в исходниках ...   -  person Mike de Klerk    schedule 20.11.2012
comment
Я подозреваю, что эти числа являются фактическим размером изображения в пикселях, а ваш ожидаемый размер - это то, как оно должно отображаться с использованием неквадратных пикселей.   -  person CodesInChaos    schedule 25.11.2012
comment
@MikedeKlerk: вообще-то ffmpeg не работает :( Я пробовал.   -  person melculetz    schedule 29.11.2012


Ответы (1)


Ключевой намек здесь в том, что 856/480 = 1,78, что примерно равно 16/9 = 1,77, обычному соотношению сторон для широкоэкранного видео. Нет ничего необычного в том, чтобы иметь видео с разрешением пикселей, которое имеет соотношение 1: 1,33 или 1: 1,5 (например, 640x480 или 720x480), но которое предназначено для отображения с более широким соотношением сторон 1: 1,77 (например, 856x480). Это называется анаморфным широкоформатным экраном. Таким образом, 720 x 480, вероятно, является правильным разрешением видео, но не правильным размером экрана.

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

Чтобы получить размер дисплея (который, кажется, вам нужен), нам нужно соотношение сторон. К счастью, тот же API свойств метаданных, который вы используете для получения ширины и высоты кадра, также имеет свойства соотношения сторон, а именно System.Video.HorizontalAspectRatio и System.Video.VerticalAspectRatio. Хотя это недокументировано, похоже, что это относится к соотношению сторон пикселя, а не к соотношению сторон изображения. Для анаморфного видео вам нужны следующие строки:

int videoWidth = (int)shellFile.Properties.System.Video.FrameWidth.Value;
int videoHeight = (int)shellFile.Properties.System.Video.FrameHeight.Value;
int horizontalAspect = (int)shellFile.Properties.System.Video.HorizontalAspectRatio.Value;
int verticalAspect = (int)shellFile.Properties.System.Video.VerticalAspectRatio.Value;
int displayWidth = videoWidth * horizontalAspect / verticalAspect;
int displayHeight = videoHeight;

В вашем случае я бы ожидал, что horizontalAspect = 53 и verticalAspect = 45 (или другие значения, дающие аналогичное соотношение).

Разрешение дисплея можно округлить до целого числа, кратного 16 или 8 пикселей, поэтому вам также может потребоваться сделать что-то вроде этого:

int roundingMultiple = 8;
int displayWidth = videoWidth * horizontalAspect / verticalAspect;
displayWidth = ((displayWidth - 1) / roundingMultiple + 1) * roundingMultiple;

Это не относится к файлам mkv; любой анаморфный видеофайл в любом формате контейнера должен обрабатываться одинаково.

РЕДАКТИРОВАТЬ: изменен приведенный выше код, чтобы отразить тот факт, что horizontalAspect / verticalAspect, по-видимому, имеет соотношение сторон pixel.

person Alex I    schedule 25.11.2012
comment
@melculetz: не могли бы вы протестировать решение выше и сообщить мне, работает ли оно для вас? Я чувствую, что это именно то, что вы искали, было трудно узнать, и я был бы признателен за награду. Спасибо! - person Alex I; 26.11.2012
comment
Спасибо за попытку, Алекс, я попробовал код, но он не возвращает правильный размер ... фактическая ширина составляет 856.903761349, но я получаю 571.26917712691773 после вашего первого фрагмента кода и 578.26917712691773 после запуска второго фрагмента код. - person melculetz; 29.11.2012
comment
@melculetz: А, понятно. horizontalAspect и verticalAspect явно содержат соотношение сторон пикселя, а не соотношение сторон дисплея; это не то, что говорится в документации, но он будет работать нормально с небольшими изменениями, см. обновленный код выше. - person Alex I; 29.11.2012