alexeichhorn / YouTubeKit

YouTube video and audio extractor for iOS, watchOS, visionOS, tvOS and macOS
MIT License
176 stars 36 forks source link

The flag isNativelyPlayable is returning a wrong value #38

Open joaodordio opened 4 months ago

joaodordio commented 4 months ago

On the Stream model, the isNativelyPlayable flag is returning true even if the videoCodec or the audioCodec are nil.

public var isNativelyPlayable: Bool {
    (videoCodec?.isNativelyPlayable ?? true) && (audioCodec?.isNativelyPlayable ?? true)
}

A better default value would be false.

public var isNativelyPlayable: Bool {
    (videoCodec?.isNativelyPlayable ?? false) && (audioCodec?.isNativelyPlayable ?? false)
}

Additionally, the video codec AVC1: 42001E is not compatible with the Apple TV platform, only the AVC1: 64001F.


AVC1: 42001E Stream:

Stream(
    url: https://rr3---sn-2vgu0b5auxaxjvh-apnd.googlevideo.com/videoplayback?expire=171218………, 
    itag: YouTubeKit.ITag(
        itag: 18, 
        videoResolution: Optional(360), 
        audioBitrate: Optional(96)), 
    mimeType: "video/mp4", 
    videoCodec: Optional(YouTubeKit.VideoCodec.avc1(version: "42001E")), 
    audioCodec: Optional(YouTubeKit.AudioCodec.mp4a(version: "40.2")), 
    fileExtension: YouTubeKit.FileExtension.mp4, bitrate: Optional(137681), 
    averageBitrate: nil, 
    type: "video", 
    subtype: "mp4", 
    filesize: nil
)

AVC1: 64001F Stream:

Stream(
    url: https://rr1---sn-2vgu0b5auxaxjvh-apnd.googlevideo.com/videoplayback?expire=171218………,
    itag: YouTubeKit.ITag(
        itag: 22, 
        videoResolution: Optional(720), 
        audioBitrate: Optional(192)), 
    mimeType: "video/mp4", 
    videoCodec: Optional(YouTubeKit.VideoCodec.avc1(version: "64001F")), 
    audioCodec: Optional(YouTubeKit.AudioCodec.mp4a(version: "40.2")), 
    fileExtension: YouTubeKit.FileExtension.mp4, 
    bitrate: Optional(981047), 
    averageBitrate: nil, 
    type: "video", 
    subtype: "mp4", 
    filesize: nil
)

Right now my implementation to filter the streams for playback on Apple TV using AVPlayer, looks like this:

videoStream = streams.filter { ($0.audioCodec?.isNativelyPlayable ?? false) && ($0.videoCodec?.isNativelyPlayable ?? false) && $0.videoCodec.debugDescription.contains("64001F") }.first?.url
alexeichhorn commented 4 months ago

Thank you very much for the remark about codec compatibility. Will look into it - especially to have better testing for this.

Regarding your first remark about (videoCodec?.isNativelyPlayable ?? true) && (audioCodec?.isNativelyPlayable ?? true): If videoCodec is nil, this means that there is no video in this stream. E.g. an audio-only mp3 stream would have videoCodec = nil, but would still be very much playable in AVPlayer.

alexeichhorn commented 4 months ago

@joaodordio follow-up question regarding codecs. Can you maybe provide me with a sample YouTube video that has 42001E streams. I only get 4D401F and 4D4020 - and they seem to work. Also did you know of any docs about this codec compatibility on tvOS?

joaodordio commented 4 months ago

@joaodordio follow-up question regarding codecs. Can you maybe provide me with a sample YouTube video that has 42001E streams. I only get 4D401F and 4D4020 - and they seem to work. Also did you know of any docs about this codec compatibility on tvOS?

You can try this one: https://www.youtube.com/watch?v=g8YXqBlXuoc&list=PLQGn5u8-Sq2KsjnhjZztLCzjZL4hEPhNc&index=2

alexeichhorn commented 4 months ago

Thanks. I was able to get at least one 42001E stream now, but the stream was playable on the tvOS Simulator (I don't own a real one). Up to this point, the simulator has always matched the codec compatibility with the real device, so I'm not 100% sure. Also, I couldn't find anything hinting at any incompatibility - one Stack Overflow article even insinuated it works for them.

So my question is: Did you test it on a real tvOS device or in the Simulator? And if it was a real one, could you maybe test it on the Simulator and tell me if playback works for you or not?