Determine if YouTube video is widescreen?
Asked Answered
L

2

8

I would like to know with certainty if a YouTube video is widescreen or not using the v3 API. There are many old videos that have a 4:3 ratio, so I need to detect this.

This was possible with API v2, but it is officially retired now. Here are the API v3 docs.

An API call looks something like this:

https://www.googleapis.com/youtube/v3/videos?id=[VIDEOID]&part=snippet&key=[DEVELOPERKEY]

Also, the thumbnail data always returns dimensions of 4:3, so that doesn't help. Here is an example:

[thumbnails] => Array
(
    [default] => Array
    (
        [url] => https://i.ytimg.com/vi/nnnnnnnnn/default.jpg
        [width] => 120
        [height] => 90
    )
    ...
)

Any ideas?

(I'm currently hacking this by analyzing pixels in the thumbnails where tell-tale black bars on 4:3 videos will be.)

Here is a sample video in 4:3 ratio:

https://www.youtube.com/watch?v=zMJ-Dl4eJu8 (old martial arts video)

martial arts in 4:3

and one in 16:9:

https://www.youtube.com/watch?v=7O2Jqi-LhEI (a new workout video)

workout video


Update: One promising suggestion was to explore fileDetails.videoStreams[].aspectRatio but it seems that this is only available to the video owner. Otherwise requesting fileDetails results in

The request cannot access user rating information. This error may occur because the request is not properly authorized

Laurentian answered 2/7, 2015 at 15:1 Comment(9)
Are you sure you can customize an aspect ratio? I think all videos are fixed to 16:9.Thermae
@Thermae Many old videos are standard aspect ratio still. I could detect that with v2 until recently.Laurentian
fileDetails.videoStreams[].aspectRatio gives the video content's display aspect ratio, which specifies the aspect ratio in which the video should be displayed.Eberle
@Eberle Does that work for any video, or just when the user is authenticated (i.e. the video owner)?Laurentian
Must admit I've never used the YT API before, but according to the docs a videos-resource contains this info, and it doesn't state anywhere that it is only for logged in users. It only states A video resource represents a YouTube video. So I assume no authentication needed.Eberle
@Eberle Thanks for the suggestion. I just ran the API on a public video. It's a blind alley I'm afraid. Requires authentication.Laurentian
This info is no longer exposed via the API. There's no official reason, but I suspect it's because, from the client's point of view, all player sizes (and thumbnail sizes) have been standardized. As a side point, if there is a 'maxres' thumbnail version, it will be 16:9 (rather than 4:3 as all the others), but on 4x3 videos with a maxres thumbnail it just letterboxes the thumbnail on the left and right sides like it does the video. So your hack is likely the only solution.Fennec
I was going to suggest the oEmbed API (if you were not limited to V3 of the API) by querying http://www.youtube.com/oembed?url={VIDEO_URL}&format=json, but it appears it'll always return 480 x 270 for the examples I tried. Perhaps you could provide some video examples?Obligate
@JamieBicknell I'm not limited to V3 by any means, but whichever API is used will be utilized by PHP. I've added a sample video in 4:3 as requested. A lot of videos over 4 or 5 years old will probably be in 4:3 hence the necessity.Laurentian
O
2

If you're open to using a different method other than V3 of the API, then I believe it is possible via the oEmbed API.

http://www.youtube.com/oembed?url={VIDEO_URL}&format=json

Like so:

http://www.youtube.com/oembed?url=https://www.youtube.com/watch?v=zMJ-Dl4eJu8&format=json

Would produce:

{  
    "provider_url":"https:\/\/www.youtube.com\/",
    "thumbnail_url":"https:\/\/i.ytimg.com\/vi\/zMJ-Dl4eJu8\/hqdefault.jpg",
    "thumbnail_height":360,
    "height":344,
    "type":"video",
    "version":"1.0",
    "html":"\u003ciframe width=\"459\" height=\"344\" src=\"https:\/\/www.youtube.com\/embed\/zMJ-Dl4eJu8?feature=oembed\" frameborder=\"0\" allowfullscreen\u003e\u003c\/iframe\u003e",
    "author_name":"hadronica2",
    "width":459,
    "provider_name":"YouTube",
    "author_url":"https:\/\/www.youtube.com\/user\/hadronica2",
    "title":"Aikido - Kazuo Chiba sensei - 1\u00ba part",
    "thumbnail_width":480
}

In the examples you've given, the output was as follows:

http://www.youtube.com/oembed?url=https://www.youtube.com/watch?v=zMJ-Dl4eJu8&format=json

Width: 459
Height: 344
Ratio: w/h = 1.3343 = 4:3 (ish)

http://www.youtube.com/oembed?url=https://www.youtube.com/watch?v=zMJ-Dl4eJu8&format=json

Width: 480
Height: 270
Ratio: w/h = 1.7777 = 16/9

This appears to work in the examples you've provided.

Obligate answered 10/8, 2015 at 9:45 Comment(0)
L
1

Here is the abridged version that I have been using since v2 of the API retired.

It tests a few points on the top and bottom of the default.jpg thumbnail image of a given video where black bars might be. A vertically opposite point from a top point is tested to see if those pixels are similar to each other to within some delta. This is repeated for a few more points.

function isWidescreen($video = null) {

    // LOGIC:
    // 4:3 videos will have default.jpg with no top black bars
    // 16:9 videos will have black top and bottom borders on default.jpg

    // Get the default thumbnail (may have black bars on top and bottom)
    $response = self::accessCurlObj()->get("https://i.ytimg.com/vi/{$video}/default.jpg");
    $defaultImgRes = imagecreatefromstring($response);

    $samplePoints = array(array(20,2), array(40,4), array(60,6), array(80,8));

    // Scan a few points for equality between top and bottom
    $height = imagesy($defaultImgRes);
    foreach($samplePoints as $point) {
        // Top
        $rgbTop = imagecolorat($defaultImgRes, $point[0], $point[1]);
        $colorsTop = imagecolorsforindex($defaultImgRes, $rgbTop);

        // Bottom
        $rgbBottom = imagecolorat($defaultImgRes, $point[0], $height - $point[1]);
        $colorsBottom = imagecolorsforindex($defaultImgRes, $rgbBottom);

        // If these arrays are not close, then let's call this 4:3 aspect
        if(!$this->areArraysClose($colorsTop, $colorsBottom, 20)) {
            return false;
        }
    }

    // Default to widescreen
    return true;
}

// Determine if the numeric values in the RGBA array are within some delta from each other
function areArraysClose(&$a, &$b, $delta = 10) {
    foreach($a as $key => $val) {
        if(abs($val - $b[$key]) > $delta) {
            return false;
        }
    }
    return true;
}

This seems to be working sufficiently enough. An obvious improvement is to check if the pixels are close to black, or apply some image processing to remove black bars automatically then check the dimensions of the remaining image.

However, my hope was that a domain-knowledgeable SO member would have a better solution before going deeper down this rabbit hole... and someone came through.

Laurentian answered 11/8, 2015 at 0:22 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.