RenderHeads / UnityPlugin-AVProVideo

AVPro Video is a multi-platform Unity plugin for advanced video playback
https://www.renderheads.com/products/avpro-video/
237 stars 29 forks source link

[Question] Display the currently playing url in hls player #2073

Closed HyundongHwang closed 1 week ago

HyundongHwang commented 1 week ago

AVPro Video Version

3.1.2

Which platform is your question for?

macOS

Your question

Hello. As you previously informed me (#2072), I prepared the hls stream by configuring it with master and various profiles. First, thank you for your kind reply. I haven't tested it on a mobile device yet, but I tested it on MacOS Editor. I want to check whether the hls adaptive play function is working properly in the log, but I can't find it easily. As shown below, the length of Buffer is output normally, but VideoBitrate and AudioBitrate are always output as 0. I would like to be able to check the currently loaded m3u8 profile url in real time in the log. Is this function not testable in the Editor and only works on mobile devices?

my code

    private async void _mp_Events(MediaPlayer mp, MediaPlayerEvent.EventType eventType, ErrorCode errorCode)
    {
        var log = new StringBuilder();
        log.Append($"MP_EVENT mp:{mp.GetHashCode()} eventType:{eventType} errorCode:{errorCode} ");

        if (mp.MediaPath != null)
        {
            log.Append($"MediaPath:{mp.MediaPath.Path} ");
        }

        if (mp.Control != null)
        {
            log.Append($"CurrentTime:{mp.Control.GetCurrentTime():F3} ");
            log.Append($"IsFinished:{mp.Control.IsFinished()} ");
            log.Append($"IsLooping:{mp.Control.IsLooping()} ");
            log.Append($"IsPaused:{mp.Control.IsPaused()} ");
            log.Append($"IsPlaying:{mp.Control.IsPlaying()} ");
            log.Append($"IsBuffering:{mp.Control.IsBuffering()} ");
            log.Append($"Buffer:{mp.Control.GetBufferedTimes().Duration:F3} ");
        }

        if (mp.Info != null)
        {
            log.Append($"Video:{mp.Info.GetVideoWidth()}x{mp.Info.GetVideoHeight()} ");
        }

        if (mp.VideoTracks?.GetActiveVideoTrack() != null)
        {
            log.Append($"VideoBitrate:{mp.VideoTracks.GetActiveVideoTrack().Bitrate} ");
        }

        if (mp.AudioTracks?.GetActiveAudioTrack() != null)
        {
            log.Append($"AudioBitrate:{mp.AudioTracks.GetActiveAudioTrack().Bitrate} ");
        }

        LogSloth.d(log.ToString());

my log

LOGSLOTH ZClassFlickSnap:0:_mp_Events T_MAIN MP_EVENT mp:-149984 eventType:Closing errorCode:None MediaPath:https://my.cloudfront.net/class/class000054_Stayc_CheekyIcyThang_violette554/class_front_hls/master.m3u8 CurrentTime:0.000 IsFinished:False IsLooping:True IsPaused:False IsPlaying:False IsBuffering:False Buffer:28.933 Video:1080x1920 VideoBitrate:0 AudioBitrate:0 
LOGSLOTH ZClassFlickSnap:0:_mp_Events T_MAIN MP_EVENT mp:-149978 eventType:Paused errorCode:None MediaPath:https://my.cloudfront.net/class/class000056_NewJeans_HypeBoy_violette554/class_front_hls/master.m3u8 CurrentTime:32.457 IsFinished:False IsLooping:True IsPaused:True IsPlaying:False IsBuffering:False Buffer:46.933 Video:1080x1920 VideoBitrate:0 AudioBitrate:0 
LOGSLOTH ZClassFlickSnap:0:_mp_Events T_MAIN MP_EVENT mp:-149996 eventType:Started errorCode:None MediaPath:https://my.cloudfront.net/class/class000088_Meovv_Meow_hoois127/class_front_hls/master.m3u8 CurrentTime:0.000 IsFinished:False IsLooping:True IsPaused:False IsPlaying:True IsBuffering:False Buffer:34.633 Video:1080x1920 VideoBitrate:0 AudioBitrate:0 
LOGSLOTH ZClassFlickSnap:0:_mp_Events T_MAIN MP_EVENT mp:-149996 eventType:StartedSeeking errorCode:None MediaPath:https://my.cloudfront.net/class/class000088_Meovv_Meow_hoois127/class_front_hls/master.m3u8 CurrentTime:0.000 IsFinished:False IsLooping:True IsPaused:False IsPlaying:True IsBuffering:False Buffer:34.633 Video:1080x1920 VideoBitrate:0 AudioBitrate:0 
LOGSLOTH ZClassFlickSnap:0:_mp_Events T_MAIN MP_EVENT mp:-149996 eventType:Stalled errorCode:None MediaPath:https://my.cloudfront.net/class/class000088_Meovv_Meow_hoois127/class_front_hls/master.m3u8 CurrentTime:0.000 IsFinished:False IsLooping:True IsPaused:False IsPlaying:True IsBuffering:False Buffer:34.633 Video:1080x1920 VideoBitrate:0 AudioBitrate:0 
LOGSLOTH ZClassFlickSnap:0:_mp_Events T_MAIN MP_EVENT mp:-149996 eventType:Unstalled errorCode:None MediaPath:https://my.cloudfront.net/class/class000088_Meovv_Meow_hoois127/class_front_hls/master.m3u8 CurrentTime:2.100 IsFinished:False IsLooping:True IsPaused:False IsPlaying:True IsBuffering:False Buffer:34.633 Video:1080x1920 VideoBitrate:0 AudioBitrate:0 
LOGSLOTH ZClassFlickSnap:0:_mp_Events T_MAIN MP_EVENT mp:-149996 eventType:FinishedSeeking errorCode:None MediaPath:https://my.cloudfront.net/class/class000088_Meovv_Meow_hoois127/class_front_hls/master.m3u8 CurrentTime:2.100 IsFinished:False IsLooping:True IsPaused:False IsPlaying:True IsBuffering:False Buffer:34.633 Video:1080x1920 VideoBitrate:0 AudioBitrate:0 
LOGSLOTH ZClassFlickSnap:0:_mp_Events T_MAIN MP_EVENT mp:-149984 eventType:MetaDataReady errorCode:None MediaPath:https://my.cloudfront.net/class/class000054_Stayc_CheekyIcyThang_violette554/class_front_hls/master.m3u8 CurrentTime:0.000 IsFinished:False IsLooping:True IsPaused:False IsPlaying:False IsBuffering:False Buffer:28.933 Video:0x0 AudioBitrate:0 
LOGSLOTH ZClassFlickSnap:0:_mp_Events T_MAIN MP_EVENT mp:-149984 eventType:ResolutionChanged errorCode:None MediaPath:https://my.cloudfront.net/class/class000054_Stayc_CheekyIcyThang_violette554/class_front_hls/master.m3u8 CurrentTime:0.000 IsFinished:False IsLooping:True IsPaused:False IsPlaying:False IsBuffering:False Buffer:0.000 Video:1080x1920 VideoBitrate:0 AudioBitrate:0 
LOGSLOTH ZClassFlickSnap:0:_mp_Events T_MAIN MP_EVENT mp:-149984 eventType:StartedBuffering errorCode:None MediaPath:https://my.cloudfront.net/class/class000054_Stayc_CheekyIcyThang_violette554/class_front_hls/master.m3u8 CurrentTime:0.000 IsFinished:False IsLooping:True IsPaused:False IsPlaying:False IsBuffering:True Buffer:0.000 Video:1080x1920 VideoBitrate:0 AudioBitrate:0 
LOGSLOTH ZClassFlickSnap:0:_mp_Events T_MAIN MP_EVENT mp:-149984 eventType:ReadyToPlay errorCode:None MediaPath:https://my.cloudfront.net/class/class000054_Stayc_CheekyIcyThang_violette554/class_front_hls/master.m3u8 CurrentTime:0.000 IsFinished:False IsLooping:True IsPaused:False IsPlaying:False IsBuffering:True Buffer:0.933 Video:1080x1920 VideoBitrate:0 AudioBitrate:0 
LOGSLOTH ZClassFlickSnap:0:_mp_Events T_MAIN MP_EVENT mp:-149984 eventType:FirstFrameReady errorCode:None MediaPath:https://my.cloudfront.net/class/class000054_Stayc_CheekyIcyThang_violette554/class_front_hls/master.m3u8 CurrentTime:0.000 IsFinished:False IsLooping:True IsPaused:False IsPlaying:False IsBuffering:True Buffer:0.933 Video:1080x1920 VideoBitrate:0 AudioBitrate:0 
LOGSLOTH ZClassFlickSnap:0:_mp_Events T_MAIN MP_EVENT mp:-149984 eventType:FinishedBuffering errorCode:None MediaPath:https://my.cloudfront.net/class/class000054_Stayc_CheekyIcyThang_violette554/class_front_hls/master.m3u8 CurrentTime:0.000 IsFinished:False IsLooping:True IsPaused:False IsPlaying:False IsBuffering:False Buffer:34.100 Video:1080x1920 VideoBitrate:0 AudioBitrate:0 
LOGSLOTH ZClassFlickSnap:0:_mp_Events T_MAIN MP_EVENT mp:-149990 eventType:Closing errorCode:None MediaPath:https://my.cloudfront.net/class/class000059_Enhypen_XO_hoois127/class_front_hls/master.m3u8 CurrentTime:0.000 IsFinished:False IsLooping:True IsPaused:False IsPlaying:False IsBuffering:False Buffer:27.467 Video:1080x1920 VideoBitrate:0 AudioBitrate:0 

my hls server files

├── 1080p
│   ├── 000000.ts
│   ├── 000001.ts
│   ├── 000002.ts
│   ├── 000003.ts
│   └── av.m3u8
├── 240p
│   ├── 000000.ts
│   ├── 000001.ts
│   ├── 000002.ts
│   ├── 000003.ts
│   └── av.m3u8
├── 360p
│   ├── 000000.ts
│   ├── 000001.ts
│   ├── 000002.ts
│   ├── 000003.ts
│   └── av.m3u8
├── 480p
│   ├── 000000.ts
│   ├── 000001.ts
│   ├── 000002.ts
│   ├── 000003.ts
│   └── av.m3u8
├── 720p
│   ├── 000000.ts
│   ├── 000001.ts
│   ├── 000002.ts
│   ├── 000003.ts
│   └── av.m3u8
└── master.m3u8
cat master.m3u8
#EXTM3U
#EXT-X-VERSION:6
#EXT-X-STREAM-INF:BANDWIDTH=5711200,RESOLUTION=1080x1920,CODECS="avc1.640028,mp4a.40.2"
1080p/av.m3u8

#EXT-X-STREAM-INF:BANDWIDTH=3220800,RESOLUTION=720x1280,CODECS="avc1.64001f,mp4a.40.2"
720p/av.m3u8

#EXT-X-STREAM-INF:BANDWIDTH=1680800,RESOLUTION=480x854,CODECS="avc1.64001f,mp4a.40.2"
480p/av.m3u8

#EXT-X-STREAM-INF:BANDWIDTH=985600,RESOLUTION=360x640,CODECS="avc1.64001e,mp4a.40.2"
360p/av.m3u8

#EXT-X-STREAM-INF:BANDWIDTH=510400,RESOLUTION=240x426,CODECS="avc1.640015,mp4a.40.2"
240p/av.m3u8
Chris-RH commented 1 week ago

There is a simple example of an event listener here. You don't need to worry about looking at bitrate etc. You'll know its working due to the ResolutionChanged events.

HyundongHwang commented 1 week ago

Thank you for your kind reply. When I checked on iOS, I confirmed that the resolution changed (= ResolutionChanged) according to the network status. Are you saying that I can infer the currently playing profile with this resolution size?

I have an additional question. I set the MediaPlayer settings to correspond to the above 5 profiles as follows. When I didn't set anything, 720p was selected first even if the network was good, but if I do this, will 1080p be selected first? Do you have a recommended setting method?

mp.PlatformOptionsWindows.startWithHighestBitrate = true;
mp.PlatformOptionsWindows.StartWithHighestBandwidth();

mp.PlatformOptions_macOS.StartWithHighestBandwidth();
mp.PlatformOptions_macOS.preferredMaximumResolution = MediaPlayer.PlatformOptions.Resolution._2160p;
mp.PlatformOptions_macOS.preferredPeakBitRateUnits = MediaPlayer.PlatformOptions.BitRateUnits.Mbps;

mp.PlatformOptions_iOS.StartWithHighestBandwidth();
mp.PlatformOptions_iOS.preferredMaximumResolution = MediaPlayer.PlatformOptions.Resolution._2160p;
mp.PlatformOptions_iOS.flags = MediaPlayer.OptionsApple.Flags.PlayWithoutBuffering | MediaPlayer.OptionsApple.Flags.AllowExternalPlayback;
mp.PlatformOptions_iOS.preferredPeakBitRate = 100F;
mp.PlatformOptions_iOS.preferredPeakBitRateUnits = MediaPlayer.PlatformOptions.BitRateUnits.Mbps;

mp.PlatformOptionsAndroid.videoApi = Android.VideoApi.ExoPlayer;
mp.PlatformOptionsAndroid.startWithHighestBitrate = true;
mp.PlatformOptionsAndroid.StartWithHighestBandwidth();
mp.PlatformOptionsAndroid.preferredMaximumResolution = MediaPlayer.PlatformOptions.Resolution._2160p;
mp.PlatformOptionsAndroid.preferredPeakBitRate = 100F;
mp.PlatformOptionsAndroid.preferredPeakBitRateUnits = MediaPlayer.PlatformOptions.BitRateUnits.Mbps;
Ste-RH commented 1 week ago

For your simple adaptive HLS manifest, yes. But this is not always the case. The HLS standard allows you to have streams with different codecs, bitrates (etc) with the same resolution.

Each platform API uses a set heuristics to determine current bandwidth status. This is something not exposed to developers at any level. Very much a magic black box. This is used regardless of what settings you choose, save with the exception of 'starting with highest bitrate. If you set that, I believe we are in essence tricking the API bandwidth meter to think it is 'excellent'. That is not to say that it does not kick in and will limit back down the adaptive streams until it is satisfied.

'Preferred maximum' is an upper clamp on resolution and/or bitrate. Streams that exceed the set values will never be selected for playback no matter how much bandwidth the APIs think they have available (in an upper sense).

Does this answer your questions?

Do you have a recommended setting method?

No, because we are not coding your project/use-case. Only you know what you need...we just simple (hopefully) provide all the tools in the asset for you to implement solution(s) to your projects needs.

HyundongHwang commented 1 week ago

Thank you for your kind reply. It was very helpful.