4

I am using Microsoft.WindowsAPICodePack.Shell.ShellFile to get the video size (width and height) from a file path.

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;
}

The problem is that this method doesn't retrieve the correct size for m4v file. Do you have any suggestions? What can I use in order to get the actual width/height?

Example: I have a m4v video, which has a real size of 856x480

  • if I look at the file's properties in Windows explorer, the size is 720x480 (wrong)
  • if I open the video in a video player, the video is rendered at the correct size, even if the video details still show a size of 720x480
  • if I load the video in a MediaElement control in WPF, I get the correct size, through mediaElement.NaturalVideoWidth, mediaElement.NaturalVideoHeight, but the problem is that I need to get the size in a class library which doesn't have any WPF references.
Alex I
  • 19,689
  • 9
  • 86
  • 158
melculetz
  • 1,961
  • 8
  • 38
  • 51
  • you could try to open the file and extract the metadata, the resolution could be saved there – fnurglewitz Nov 13 '12 at 15:26
  • See http://stackoverflow.com/questions/11346136/getting-mp4-file-duration-with-directshow - you can get resolution in a similar way as well. – Roman R. Nov 19 '12 at 20:50
  • I can't imagine FFmpeg open source application will spit out the wrong info if you would ask it. Commandline tool FFmpeg.exe -i [path to your file]. Maybe pipe it to your application? Or is using an external exectuable no option. Otherwise you could see the method of FFmpeg in the sources... – Mike de Klerk Nov 20 '12 at 13:27
  • 1
    I suspect these numbers are the actual size of the image in pixels and your expected size is how it should be rendered using non-square pixels. – CodesInChaos Nov 24 '12 at 21:37
  • @MikedeKlerk: actually, ffmpeg doesn't work :( I tried it. – melculetz Nov 29 '12 at 14:29

1 Answers1

1

The key hint here is that 856/480 = 1.78 which is approx equal to 16/9 = 1.77, a common aspect ratio for widescreen video. It is not unusual to have video with pixel resolution that has a ratio 1:1.33 or 1:1.5 (for example 640x480 or 720x480), but which is meant to be displayed stretched to a wider aspect ratio, at 1:1.77 (for example 856x480). This is called Anamorphic Widescreen. So 720x480 is probably the correct resolution of the video, but not the correct display size.

When displaying anamorphic widescreen in a window, video players usually just keep the same height and stretch the width to obtain the correct display aspect ratio. If fullscreen, both width and height may be stretched but not by the same factor, so that the display aspect ratio comes correct and the video fits exactly within the screen resolution.

To obtain the display size (which seems to be what you want), we need the aspect ratio. Fortunately, the same metadata properties API you're using to get frame width and height also has aspect ratio properties, namely System.Video.HorizontalAspectRatio and System.Video.VerticalAspectRatio. While this is undocumented, these appear to refer to the pixel aspect ratio, not the picture display aspect ratio. What you want for anamorphic video is along these lines:

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;

What I'd expect in your case is that horizontalAspect = 53 and verticalAspect = 45 (or other values producing a similar ratio).

Display resolutions may be rounded up to an exact multiple of 16 or 8 pixels, so you might also need to do something like this:

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

This is not specific to mkv files; any anamorphic video file in any container format would have to be handled the same.

EDIT: Changed code above to reflect the fact that horizontalAspect / verticalAspect is apparently the pixel aspect ratio.

Alex I
  • 19,689
  • 9
  • 86
  • 158
  • @melculetz: can you please test the solution above and let me know if it works for you? I feel this is exactly what you were looking for, it was hard to find out, and I would appreciate the bounty. Thanks! – Alex I Nov 26 '12 at 19:31
  • Thanks for the try, Alex, I tried the code, but it's not giving back the correct size ... the actual width is 856.903761349, but I get 571.26917712691773, after your first piece of code and 578.26917712691773, after i run the second piece of code. – melculetz Nov 29 '12 at 10:44
  • @melculetz: Ah, I see. horizontalAspect and verticalAspect apparently contain the pixel aspect ratio not display aspect ratio; this is not what the docs say, but it will work fine with some slight changes, please see updated code above. – Alex I Nov 29 '12 at 11:22