-
Notifications
You must be signed in to change notification settings - Fork 6k
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
60 FPS Widevine DASH content stutters on some devices #6348
Comments
@ojw28 Have you had already time to check this? If not, can you maybe provide a time frame? We are happy to support you in further investigation, just let me know. |
@christosts - We should probably treat this as a duplicate of #5796 (or at least investigate both at the same time). The test content and information above will be useful for helping to look at that issue. |
Ack |
Hi @matamegger Checked the DASH links provided over email yesterday and they returned 404*. Can you please check the health status of the links, and if they are not alive anymore, maybe provide new ones? Also, regarding:
Can you please share the change you made so that we can attempt to reproduce the behavior? Thanks. [edit] |
We are experiencing - what probably is - the same issue with widevine drm, but with video tracks that are 720p50fps. They work fine unencrypted. Iv'e done several tests with one problematic device, Xiamo Mi A3 (with Android One). Changing between L1/L3 does nothing. The only thing that helps is disableing the audio renderer (for some reason) There's also an old issue from last year about this, but it's closed with no resolution. |
@christosts |
Regarding the "renderTimeStamp". It's basically something like the following patch shows. .../library/core/src/main/java/com/google/android/exoplayer2/video/MediaCodecVideoRenderer.java
@@ -912,8 +912,8 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
protected void renderOutputBufferV21(
MediaCodec codec, int index, long presentationTimeUs, long releaseTimeNs) {
maybeNotifyVideoSizeChanged();
TraceUtil.beginSection("releaseOutputBuffer");
- codec.releaseOutputBuffer(index, releaseTimeNs);
+ codec.releaseOutputBuffer(index, 0);
TraceUtil.endSection();
lastRenderTimeUs = SystemClock.elapsedRealtime() * 1000;
decoderCounters.renderedOutputBufferCount++; Note: This is only executed on devices API >= 21 |
thanks. If you can check the content links (they are returning 404) and provide working links, I will try to repro and come back with findings. |
Mailed you a new set of assets. |
Hi Matthias. An update: When tested with a Galaxy S7 (SM-G930F), I can see frames being dropped by the player at 60fps at the highest bitrate track. I will work on that to see why the player drops frames. Apart from that, there is the issue for frames being dropped by the surface and not the player. For example, in the test content I can see there's a news reel at the bottom which sometimes has glitches, and also there are glitches on the bottom right window. Is this the problem you observed? On my tests, I can see these glitches but not with the same severity across different devices (Samsung Galaxy S7, Pixel 2/3). In addition, I cannot observe glitches on the main window of the content. Therefore I am not 100% sure if these glitches are in content itself (from encoding) or happening at the device, therefore what you describe as frames being dropped by the surface. I did not see a difference in the glitches by changing the releaseOutputBuffer() param to 0. |
Yes, depending on the device the "main content" is not glitching, on older or weaker phones the main content also has glitches, but in this case the glitches might be expected due to the processing power of the devices. Depending on the device either exoplayer or the surface (maybe even both) drop frames. |
Hey there. We've also been facing exactly this issue. I agree with @ojw28 in that in order to really fix this problem, multithreaded rendering is required. I noticed that changing the time interval between rendering loops helps a bit. The delay is hardcoded to be 10ms, changing it to 0 definitely helped us. .../library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java
@@ -83,7 +83,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
private static final int MSG_PLAYBACK_PARAMETERS_CHANGED_INTERNAL = 17;
private static final int PREPARING_SOURCE_INTERVAL_MS = 10;
- private static final int RENDERING_INTERVAL_MS = 10;
+ private static final int RENDERING_INTERVAL_MS = 0;
private static final int IDLE_INTERVAL_MS = 1000;
private final Renderer[] renderers; With this change, some frames are still dropped depending on the device used though. I'm pretty sure this is not enough to be a production-ready patch, but maybe an improvement could be done by dynamically adjusting this value until proper multithreaded rendering is implemented. |
Just an update: As mentioned in my previous comment, when tested the 60fps 5.7Mbits widevine stream on a Galaxy S7, I can see ExoPlayer (not the surface) is dropping frames. I am working to address that. The fix will probably be inline with adding threads to handle rendering. With regards to the 'glitches' in the news ticker. I am not sure it is the surface or I am not seeing the same symptoms. In detail, I played the 60fps track offline on multiple devices and multiple players (and asked more people to view!) and saw glitching on the news ticker on all setups.
In all devices/players, the ticker did not run 100% smoothly, which I interpret there is some glitching encoded. But I can't tell of course if the glitching that I observe is the same as the glitch reported originally. @matamegger would you mind trying something similar, that is try to play offline the 60fps/5.7mbit content and see if you can see similar glitch along devices/players? |
There are no glitches in the stream itself. We have validated this many times. Also by observing the glitches closer and multiple times, one can see that they do not happen on the same position in the content. |
Hi. We are facing similar problems. Is there any updates to this issue? In our case it's 720p50fps which is causing stuttering and a lot of dropped frames on some devices. Most problematic on Google Pixel (Gen1) running Android 10, but also on a few other devices. We found a (to us) weird thing though which I would love to get help understanding. If we keep the main thread busy by either tapping quickly on the screen to show/hide player controls or by pressing the volume rocker to show the volume slider video becomes smooth with no dropped frames. You can see the behavior in this screen capture: Video is blacked out, but you can see the db count increasing quickly until I start toggling the player controls during which db count is not increasing and video is playing fine. We could also reduce the dropped frames by starting an endless Runnable no-op loop on the main thread while video was playing. But this still causes a few frame drops, so not a production stable workaround. Reproduced this issue on the ExoPlayer demo app, running version 2.11.1. |
We have been working on it. It is still in progress but let me share an update. Note: the following comment points to experimental code that is available on the dev-2 branch but it is still under testing/evaluation. Therefore we cannot guarantee at the moment the feature's stability or that the API will not change in a future release. As a first step, we are experimenting with operating Android's MediaCodec in asynchronous mode. We have seen (in some devices) this alone improves the MediaCodec's performance. In the dev2 branch, the DefaultRenderersFactory currently has the method For high frame rate video, we expect We will be happy if you can experiment with the feature and provide feedback, but let me repeat that this feature is still under internal evaluation and the API is not final. An easy way would be to checkout the dev2 branch, set the MediaCdec operation mode in the demo app and play your test video. On top of this work, we plan to add additional parallelization to offload the player's internal thread. When this feature is available on the dev2 branch, we will announce the experimental features (possibly in our blog) and invite the community to experiment and provide feedback. |
@fredrikeneroth can share a link to the 720p50fps video to test it on a Pixel? If you cannot share it in public, will you be able to email to dev.exoplayer@gmail.com with subject "Issue #6348"? Thanks |
Okay, that sounds promising @christosts. Will try it out. I've sent the test content to your email. Let me know if it doesn't work or if you need any additional content. |
Nice to to see improvements! We are still evaluating those modes internally, and we haven't had the opportunity (and backing data) to plan additional steps yet. Since you have a device, may I ask you to try the following? Can you please try increasing the hardcoded earlyUs threshold in the MediaCodecVideoRender? Try increasing it to What does it do? This threshold controls how early ExoPlayer sends a decoded video frame to the MediaCodec to be rendered later on screen, in microseconds. Right now, ExoPlayer submits video frames up to 50ms ahead of time. Increasing the value to 100ms or 200ms will allow sending the decoded video frames sooner to the MediaCodec (they will still be displayed on time, MediaCodec will ensure that). By increasing the threshold, ExoPlayer will be placing a few more video frames in the MediaCodec's rendering queue waiting to be displayed, hence making the player somewhat more robust to sudden delays that might occur in other parts of the player's processing loop. The caveat: decoded video frames that are passed to the MediaCodec for release, will definitely be displayed on screen. That is, if the user pauses, but the player has released video frames up to 200ms ahead, these will be rendered on screen first, and then playback will pause. If you try this, please let us know if it mitigated the remaining dropped frames on the Sony device, but also consider pausing playback to see if UX is impacted. Note that this is an early thought and not an agreed idea that we have planned to implement. As said above, we are still collecting data on the existing experimental modes. |
I've noticed an improvement with I also tried increasing the One interesting thing that I've noticed is that if I repeatedly put my fingers on the display then the issue mostly goes away! That's also visible from the My guess is that this happens because Android by default boosts the CPU frequency as soon as you touch the display in order to make interaction smoother. That boost seems to be enough to get the video to play smoothly. Here is a chart (obtained by running Unfortunately, my device does not support |
Update: CPU (or maybe GPU?) frequency definitely seems to play a role here. Since it's known that MediaTek cheats on benchmarks, and my device has a MediaTek SoC, I decided to take advantage of this to increase the CPU frequency (since my device is not rooted). I changed my With I did notice stuttering with So what does this tell us? Honestly, I don't know if there is much that ExoPlayer can do here. It seems to me that the device's CPU governor is over-conservative, and doesn't scale up enough to meet the demands of 1080p50 video playback. |
Hi ExoPlayer team, The issue we have with Live Dash HD streams with 50fps, is kind a burning one. Can we have a feedback if the experimental feature is stable enough to be added to any of the next stable versions? If so, is there a timeline for it? |
We're planning to do a release pretty soon (i.e., within the next couple of weeks) to pick up changes related to #6429, but it will be based on 2.11.X rather than tip-of-tree It seems reasonable that we would try and also pick up the changes for this issue at the same time, but whether that's practical will depend on how nicely they cherry-pick onto 2.11.X, which we wont know until we try. So, we'll see if it's possible, but we can't promise anything. If it's not possible then the changes will need to wait until 2.12.0, for which we don't have a good time estimate yet. |
@ojw28 any update on this? |
@RichardDapice I found forcing certain devices to use L3 worked as well, however this used to be easy by using |
We plan to include this API as experimental (therefore subject to change) in 2.12. We cannot promise a date yet though. |
Are there any new updates to this topic? I've been experimenting now with the dev-v2 branch for a while and as the Modes 2 and 4 certainly help with performance. It for sure doesn't make the stream run flawlessly. I've been testing Dash/Widevine Streams mainly with a Samsung Galaxy Tab 2 and with either Mode 2 or 4, I'd still need to cancel out the highest abr profile to achieve a somewhat acceptable result. The best result i achieved on the Tab S2 is by filtering the max Bitrate to 2048kbps with Mode 2. This gave me an average vfpo of 40ms with occasional dropped frames every now and then. I've also been testing with a Pixel 3a, and tho this device is not as problematic with stuttering playback, Mode 4 always result in a DecoderFailure Message. I'd appreciate if someone could give me an update on this topic, if it is even worked on currently and i there is anything new to expect anytime soon. Thank you very much. |
We are targeting to release v2.12 soon (within September) and these APIs will be available for use, but as experimental. The API will allow enabling modes 2 and 4 separately for audio and video. If you upgrade to v2.12, you can opt-in to these modes in your app. Our internal evaluation shows that the overall best performance is achieved with mode 4 enabled on both audio and video. Our future plan is to have mode 4 enabled by default for audio and video in a future release. However, we do see some sporadic errors that we need to analyse first before we enable this by default.
It's likely that is hitting the device limits and there's not much room for improvement inside ExoPlayer.
Can you please help us to investigate this further? A bugreport obtained from the device when the error happens and a link to test content would be great. Can you email them to dev.exoplayer@gmail.com with subject "Issue #6348"? |
Hi @christosts. I'm trying to work on this issue, I've found out if I increase |
@mahdi24rajabi what is the Android version of your device? The experimental APIs introduced are available for Android API 23+ and modifying the |
@christosts It's pretty old device and API version is 19. |
@mahdi24rajabi the Can you please point me the exact changes you made? If it's just one line, a link to the source code will do explaining what values you are setting, otherwise can you attach a patch? |
@christosts Just changed following lines in
I've prevented frame dropping in short time in this way. It's smooth now, but not sure whether does it have any side effects or not. |
There can be some interesting timing interactions between audio and video if the video renderer keeps trying to present frames that should have been dropped otherwise. For example, I've seen the side effect where a bunch of delayed video frames are displayed in higher rate, so the user sees video playing faster for a short duration (1 second). However, I have not investigated these changes further, so I cannot offer more information. I would be interesting to hear your findings, in case you notice a certain kind of side effects. |
@christosts I've found something that improves the situation: Instead of sending By doing so, I reduced worst value for Previously I got smooth rendering at 1s. Now I get it at 250ms. I have one question. The code inside the |
The various improvements mentioned in this thread are actually offloading some of the work done inside renderers in other threads so that the actual time that each Renderer.render() takes is minimal. Unfortunately, we are seeing some errors raised from the device when multiple threads are interacting with MediaCodec instances, especially on older Android versions. Therefore, accessing media components from multiple threads is not 100% safe and it takes us time until we are confident we can enable any form of parallelisation by default. Triggering renderers fully in parallel is in our radar and tracked in #5796, but our plans for the immediate future is to stabilize the performance improvements mentioned in this thread and enabling them by default. |
Hi All, I have one issue, In my case, I need to show the video player rotated for example 45 degrees, for rotation I found that needed to use |
@Rafayel93 the optimizations described in this thread were made with respect to the performance of Android's If you use the player's default renderers, you need to create a |
Hi All, I tried the experimental mode on Galaxy S6 (European version) and it worked well. We got many issues related to the Exynos chip here. Firstly, I have used the branch v2.12.2 Then I have modified MediaCodecVideoRenderer as below as it was recommended: //codec.releaseOutputBuffer(index, releaseTimeNs); And the MainActivity as below:
Previously we were not able to play a LIVE DASH widevine content smoothly on this layer : And we were limiting the track selector to max bitrate 1500000 because it got worse for the layers up. Now we are able to play this level smoothly but also the higher levels: Finally, the MediaCodecOperation configuration solves my issue. Let me know when you will release the change. Zaki |
This change makes asynchronous queueing non-experimental, it enables the feature by default on devices with API level >= 31 (Android 12+) and exposes APIs for apps to either fully opt-in or opt-out from the feature. The choice to use or not asynchronous queueing is moved out of MediaCodecRenderer to a new MediaCodecAdapter factory, the DefaultMediaCodecAdapterFactory. This is because, at the moment, if an app passes a custom adapter factory to a MediaCodecRenderer and then enables asynchronous queueing on it, the custom adapter factory is not used but this is not visible to the user. The default behavior of DefaultMediaCodecAdapterFactory is to create asynchronous MediaCodec adapters for devices with API level >= 31 (Android 12+), and synchronous MediaCodec adapters on devices with older API versions. DefaultMediaCodecAdapterFactory exposes methods to force enable or force disable the use of asynchronous adapters so that applications can enable asynchronous queueing on devices with API versions before 31 (but not before 23), or fully disable the feature. For applications that build MediaCodecRenderers directly, they will need to create a DefaultMediaCodecAdapterFactory and pass it to the renderer constructor. For applications that rely on the DefaultRenderersFactory, additional methods have been added on the DefaultRenderersFactory to control enabling/disabling asynchronous queueing. Issue: #6348 PiperOrigin-RevId: 400733506
We pushed commit 7a2c7c3 that promotes the experimental asynchronous queueing feature to be used by default. This will be included on the next release ( The player will use this feature by default on devices with Android 12+, but it will not enable it automatically for devices running previous Android versions. Asynchronous queueing largely addressed stuttering and dropped frames observed on some devices when playing high frame Widevine-encrypted content. However, we observed some devices can be fragile to the additional threads introduced, especially on older platforms (e.g., prior to Android 8). The number of issues was very low, yet is prevented us from widely enabling the feature on all platforms. The commit adds APIs to enable/disable the feature, therefore you can manually enable it on a device running an earlier Android version. I will close this issue. If you observe any issues with the new feature, please file a new ticket in order to focus the conversation on the specific feature. Thanks. |
Content description
60 FPS Widevine encrypted DASH streams stutter and/or have many dropped frames.
The (per email) provided content shows a live ticker at the bottom, where this stuttering and frame drops can be observed very well.
There are players like the NexPlayer (https://www.nexplayersdk.com/), which shows better performance on the same content and devices, therefore we rule out a weak DRM decryption module or hardware decoders.
We also tried to find the bottleneck in the code base, tried to tweak several parameters, and implemented a decoder version using the asynchronous callback Android provides. Unfortunately without major improvements.
Additionally, on the more powerful/recent devices we observed that frames are provided to the Surface in time (ExoPlayer business logic did not drop the frames) but the stuttering was still visible. When we changed the code so that the
renderTimeStamp
passed toreleaseOutputBuffer
is not "reasonably close" to the current system time (which causes the Surface to ignore the timestamp and display the buffer at the earliest feasible time. In this mode the Surface will not drop frames), we did not see any stuttering/frame drops anymore as expected. However, over time video and audio were drifting apart as if video would not be playing at 60 FPS anymore but rather at a lower frame rate. This observation lead us to the assumption that the surface itself maybe cannot keep up with the high frame rate.Link to test content
Provided per email.
Version of ExoPlayer being used
2.10.4
and at least back to2.9.6
Device(s) and version(s) of Android being used
Seems unrelated to the Android version.
Seen issues with:
A full bug report captured from the device
Provided per email.
The text was updated successfully, but these errors were encountered: