Skip to content

Custom Device Profile(s) #1168

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
JPKribs opened this issue Aug 4, 2024 · 6 comments
Closed

Custom Device Profile(s) #1168

JPKribs opened this issue Aug 4, 2024 · 6 comments
Labels
enhancement New feature or request

Comments

@JPKribs
Copy link
Member

JPKribs commented Aug 4, 2024

Describe the feature you'd like
Have Swiftfin default to a standard, universally functional Device Profile, but allow users to manually specify/override with their own profile for better compatibility.

Additional context
Currently, Apple does a good job of keeping devices fairly standard but recently I have found there are some issues with codecs like AV1 between devices. Officially, Apple does not support AV1 hardware decoding on currently available Apple TVs. However, using players like Infuse, Software Decoding appears to work great for some models. 4K gen 1 and 2 stutter and playback is very poor but gen 3 playback works great with the software decoder. Additionally, many iPhones/iPads can software decode AV1 without issue, with the M4/A17 SOCs having hardware accelerated playback.

As a result of this, it's probably best for Swiftfin to default to transcoding AV1 content on the Server but allowing users to manually enable it. Roku has gone the route of allowing users to manually enable/disables things like HEVC/AV1 but it might make the most sense to just allow users to make their own profile. This way, so long as the enum for Video/Audio codecs are up to date, users can try whatever settings make the most sense.

Additionally, this lets users with older devices to downgrade their profiles to force transcoding for lower powered devices.

I have a PR where I have been messing around with this. I will like this issue on that Draft PR for feedback!

@JPKribs JPKribs added the enhancement New feature or request label Aug 4, 2024
@LePips
Copy link
Member

LePips commented Aug 27, 2024

Since this is all about media compatibility, we can change this to encompass everything when it comes to how media is played, including combining the direct play setting and providing that very compatible profile as a preset.

Just as a design prototype, I've come up with the following (but only Profiles appears for Custom selection). Designs are not final as they are missing footer descriptions and design could be changed.

Compatibility

Screenshot 2024-08-27 at 1 09 58 PM

Profile - Empty Screenshot 2024-08-27 at 1 11 34 PM
Profile - 2 profiles + swipe to delete Screenshot 2024-08-27 at 1 11 53 PM

I didn't make a prototype for the profile creation screen but that shouldn't be too difficult and doesn't need to be fancy. Since there can be multiple profiles used I don't see why not to make that the functionality which also covers the single-profile case and allows people "who know what they're doing" to do what they want to do. We also need to have protections in case the user selects Replace and a profile isn't defined as that seems like unexpected behavior.

For the Most Compatible option, we can make the profile as described in the PR description. For combining with Direct Play, remove it from Experimental. All of this will require new types and such.

@JPKribs
Copy link
Member Author

JPKribs commented Aug 28, 2024

@LePips This looks awesome! Do you want me to finish out the PR with what I have now and then I can look towards this or should I go straight to trying towards this?

@LePips
Copy link
Member

LePips commented Aug 28, 2024

Let's do this right at the beginning alongside the cleanup.

@JPKribs
Copy link
Member Author

JPKribs commented Aug 29, 2024

I've been working on this and I think my biggest snag is storing this. If we're allowing more than one profile, it makes the most sense to store it all together. Since we're allowing changes to Audio, Video, and Container, I thought making a struct to store it made the most sense. Something like:

//
// Swiftfin is subject to the terms of the Mozilla Public
// License, v2.0. If a copy of the MPL was not distributed with this
// file, you can obtain one at https://mozilla.org/MPL/2.0/.
//
// Copyright (c) 2024 Jellyfin & Jellyfin Contributors
//

import Defaults
import Foundation
import JellyfinAPI

struct PlaybackDeviceProfile: Codable {
    var type: DlnaProfileType
    var audio: [AudioCodec]
    var video: [VideoCodec]
    var container: [MediaContainer]

    init(
        type: DlnaProfileType,
        audio: [AudioCodec] = [],
        video: [VideoCodec] = [],
        container: [MediaContainer] = []
    ) {
        self.type = type
        self.audio = audio
        self.video = video
        self.container = container
    }

    var directPlayProfile: DirectPlayProfile {
        switch type {
        case .video:
            return DirectPlayProfile(
                audioCodec: AudioCodec.unwrap(audio),
                container: MediaContainer.unwrap(container),
                type: type,
                videoCodec: VideoCodec.unwrap(video)
            )
        default:
            assertionFailure("Only Video is currently supported.")
            return DirectPlayProfile()
        }
    }

    var transcodingProfile: TranscodingProfile {
        switch type {
        case .video:
            return TranscodingProfile(
                audioCodec: AudioCodec.unwrap(audio),
                isBreakOnNonKeyFrames: true,
                container: MediaContainer.unwrap(container),
                context: .streaming,
                maxAudioChannels: "8",
                minSegments: 2,
                protocol: StreamType.hls.rawValue,
                type: .video,
                videoCodec: VideoCodec.unwrap(video)
            )
        default:
            assertionFailure("Only Video is currently supported.")
            return TranscodingProfile()
        }
    }
}

Then we can just call the var depending on whether this is a directPlay or transcodingProfile. The type is almost always going to be video but I thought I would include that so down the road we'd have something in place if we ever start looking at audio.

Does this make sense to store our profiles as [PlaybackDeviceProfile]? If so, how would I represent that in StoredValues?

@LePips
Copy link
Member

LePips commented Aug 29, 2024

Yes, combining them into single objects makes the most sense.

@JPKribs
Copy link
Member Author

JPKribs commented Aug 29, 2024

I've made some progress on this. This feature is now entirely functional but I have some weird bugs I still need to work out. For some reason, I started on tvOS so that's just what I have done. I expect iOS to be easier once I have the quirks figured out.

Here is my current state:

Playback Quality Menu (Complete) Simulator Screenshot - Apple TV 4K (3rd generation) - 2024-08-29 at 01 04 45 Simulator Screenshot - Apple TV 4K (3rd generation) - 2024-08-29 at 01 04 50
Custom Device Profiles Menu (Done but with a Bug) Simulator Screenshot - Apple TV 4K (3rd generation) - 2024-08-29 at 02 12 49 Simulator Screenshot - Apple TV 4K (3rd generation) - 2024-08-29 at 01 05 01
Custom Device Profiles Menu (Bug)

Focusing I lose my text...

Simulator Screenshot - Apple TV 4K (3rd generation) - 2024-08-29 at 01 05 07
Custom Device Profiles Editor Simulator Screenshot - Apple TV 4K (3rd generation) - 2024-08-29 at 01 05 12 Simulator Screenshot - Apple TV 4K (3rd generation) - 2024-08-29 at 01 05 18

Issues:

  1. Focusing the Device Profile the text disappears. I can make a custom focus but I think I just need to rework my buttons.
  2. Missing Navigation header for the Custom Device Profiles Editor. No idea what's going on there.
  3. Routing back from Custom Device Profiles Editor to Custom Device Profiles Menu jerks between the 2 screens a couple times. I think I need to redo the routing.
  4. Updating a value on the Custom Device Profiles Editor for 'use as transcoding profile' updates the variable but the label that says On/Off doesn't update

I'm committing everything I have now. I'm hoping to knock out the issues above before I move to iOS.

@JPKribs JPKribs closed this as completed Oct 5, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

2 participants