I'm working on PiP mode in my app. In fact it is working pretty fine, but I have a problem with blinking/disappearing video for a split second.
I have VideoActivity in "fullscreen"/normal mode. I'm calling enterPictureInPictureMode(); and Activity is collapsing to small PiP-frame. At the moment when animation is ending shrinking layout then video get transparent for a split second/one frame. Also exacly in this frame whole PiP-frame gets shadow under (elevation). When I touch this small PiP-frame it expands a bit to big PiP-frame (not fullscreen) and this anim is smooth, but when auto-collapse to small PiP-frame it blinks again on the end... Everytime when Activity is animating to small PiP-frame (no matter if is collapsing from big PiP-frame or fullscreen Activity) one-frame transparency-blink occurs when reaching final "small bounds". No impact to sound, video is playing steady, no calls to onPlayerStateChanged.
With newer API version we can create animation with bounds and thats how I know the video view is blinking... Using no-attribute method makes whole layout collapses and I can see blink only on area with video/player/surface view (black stripes above and below video). When I use newer method and setSourceRectHint I can see whole PiP-frame disapears without respecting black background of its parent. In fact I've added dummy View with fixed size, background color and centerInParent like PlayerView - it blinks/hides just like player when is placed below (first in parent) PlayerView layer, but placed above doesn't blink at all and is showing above PlayerView even when it disappears for split sec.
How to fix that blink or maybe though set black background, not transparent...
if (Build.VERSION.SDK_INT >= 26) {
Rect bounds = new Rect();
playerView.getVideoSurfaceView().getDrawingRect(bounds);
int toTop = (playerView.getMeasuredHeight() - bounds.height()) / 2,
toLeft = (playerView.getMeasuredWidth() - bounds.width()) / 2;
bounds.top += toTop;
bounds.left += toLeft;
bounds.bottom += toTop;
bounds.right += toLeft;
enterPictureInPictureMode(new PictureInPictureParams.Builder().
setSourceRectHint(bounds).
setAspectRatio(new Rational(bounds.width(), bounds.height())).
build());
} else
enterPictureInPictureMode();
xml:
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#android:color/black">
<com.google.android.exoplayer2.ui.PlayerView
android:id="#+id/activity_video_player_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_centerInParent="true"
android:background="#android:color/black"
app:controller_layout_id="#layout/exo_custom_control_view"
app:fastforward_increment="10000"
app:rewind_increment="10000"
app:show_timeout="100" />
...
PS. Above problem also appears when using usual VideoView played in WebView and got into fullscreen by VideoEnabledWebChromeClient. But in this case blink reveals for a split second part of WebViews content
edit: I've just found a workaround for blinking ExoPlayer - by replacing SurfaceView with TextureView, adding app:surface_type="texture_view" - but I'm reading that TextureView is a bit less efficient and also this is not fixing VideoView blink (fullscreen from WebView)
edit2: can confirm blinks on Android 8 (Xiaomi) and 9 (Pixel)
Related
I'm having a problem with the video output on a VLCVideoLayout.
Video plays fine, however it plays with its original size instead of fitting inside of the VLCVideoLayout.
Here's what I already attempted but failed:
ViewGroup.LayoutParams videoParams = videoLayout.getLayoutParams();
mMediaPlayer.getVLCVout().setWindowSize(videoParams.width, videoParams.height);
Here's part of my layout:
<org.videolan.libvlc.util.VLCVideoLayout
android:id="#+id/player"
android:layout_width="200dp"
android:layout_height="120dp"
android:fitsSystemWindows="false"/>
I'm using version 3.2.6
implementation 'org.videolan.android:libvlc-all:3.2.6'
The end result it's the crop of center part of the video (or a zoom on the center?).
This is a picture with the problem.
The white part is the rest of the layout, on the center i have the VLCVideoLayout.
The video has a lot more than what the VLCVideoLayout is showing.
Anybody can help?
Thanks.
I am using two GLSUrfaceView to render video of my own camera and video i receive from server. They are video call data. One small and one large in size. The large GLSurfaceView has two mode, one is Normal Screen mode which is done by filling screen width and calculating the screen height as (DISPLAY_WIDTH * ASPECT_RATIO_OF_IMAGE), and the second mode is full screen mode which is done by filling screen height and calculating the screen width as (DISPLAY_HEIGHT * ASPECT_RATIO_OF_IMAGE). I make the screen large on double tap and again normal in double tap again. But the problem is in large mode the image is cut in the right side only. I want my image to be cut in all side fitting the FrameLayout center at GLSurfaceView center. I am adding my Code part also. See the below image also which describe my need.
<RelativeLayout
android:id="#+id/video_call_views_container_outgoing"
android:layout_width="match_parent"
android:visibility="gone"
android:layout_height="match_parent">
<FrameLayout
android:id="#+id/largeGLSurfaceViewContainer"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:orientation="vertical"/>
<FrameLayout
android:id="#+id/smallGLSurfaceViewContainer"
android:layout_width="120dp"
android:layout_height="170dp"
android:orientation="vertical"
android:visibility="gone"/>
</RelativeLayout>
Here is my coding part :
GLSurfaceView frontCameraGLView = new GLSurfaceView (this);
GLSurfaceView opponentCameraGLView = new GLSurfaceView (this);
largeVideoRenderLayoutOutgoing.addView(opponentCameraGLView );
largeVideoRenderLayoutOutgoing.setOnClickListener(this);
opponentCameraGLView.setZOrderMediaOverlay(false);
smallVideoRenderLayoutOutgoing.addView(frontCameraGLView );
smallVideoRenderLayoutOutgoing.setOnClickListener(this);
largeVideoRenderLayoutOutgoing is the reference of FrameLayout having id largeGLSurfaceViewContainer , smallVideoRenderLayoutOutgoing also refer FrameLayout having id of smallGLSurfaceViewContainer. GLSurfaceView are added to FrameLayout's during onCreate of Activity. The problem is specified in the below image's
This image is image in the Upeer side is in Normal Mode. And the Below image is in Full Screen Mode. See the left side of these image. They are same but the right is cut in FullScreen mode i mean the last image. I wish that the image should be center fitted so that the image is cut in all side focusing my incoming video's center
If a GLSurfaceView's width is or height is larger than the device screen, it will behave like below:
1. For width larger than device width but height is same as device height: the GLSurfaceView will start drawing from top left corner which co-ordinate will be (0,0) and the extra image will be out of screen right side. So the image center will not be in layout's center. To solve this problem we need to shift image left as leftMargin which value will be half of (imageWidth-deviceWidth). The code's are like
ViewGroup.MarginLayoutParams marginLayoutParams = (ViewGroup.MarginLayoutParams) glSurfaceView.getLayoutParams();
int margin = (-1 * (int) ((glSurfaceView.getWidth() - displayWidth) / 2));
marginLayoutParams.setMargins(margin, 0, 0, 0);
setLayoutParams(marginLayoutParams);
Please do write a similar code if the heigh of the glsurfaceview is larger than device height. Add a margin on top so that the image is fitted in center of the device
When youtube player fragment nested in ScrollView I get error when rotate device to landscape:
YouTubePlayer.ErrorReason.UNAUTHORIZED_OVERLAY
And what is more interesting, is that the problem disappears when I remove ScrollView! But I can
<ScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
/>
<fragment
android:name="com.google.android.youtube.player.YouTubePlayerFragment"
android:id="#+id/youtubeplayerfragment"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</LinearLayout>
</ScrollView>
YouTubePlayer.ErrorReason.UNAUTHORIZED_OVERLAY error indicates that *Playback has been stopped due to a view overlaying the player. This means that the YouTube Player has been obscured by some other view on top of it. The YouTube API can detect it and stop the Playback.
One very common reason for this to happen is when the fragment for holding the YouTube player is embedded in a scroll view. Scroll View adds additional layer of elements can be be scrolled. For.eg the in your case. The player contained in the same declaration would detect the overlap and would eventually stop giving the above error.
I have the same problem with a YoutubePlayer inside of a ScrollView and it stops with this message:
W/YouTubeAndroidPlayerAPI: YouTube video playback stopped due to unauthorized overlay on top of player. The YouTubePlayerView is not contained inside its ancestor android.widget.ScrollView{69b88e5 VFED.V... ........ 0,0-1794,1017 #7f0d0070 app:id/scrollview}. The distances between the ancestor's edges and that of the YouTubePlayerView is: left: 21, top: 196, right: 21, bottom: -164 (these should all be positive).
This happens all the time when the video is not fully visible on the screen. When it is visible completely, rotating the device works fine. To me this looks like a bug in the Youtube Android Player. I made a workaround with the following code:
#Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
// This is an ugly workaround to prevent youtube from (wrongly) thinking we have an
// overlay above the video. Having overlays is not allowed and the video would stop otherwise.
DisplayMetrics metrics = getResources().getDisplayMetrics();
int offset = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 25, metrics);
scrollView.scrollTo(0, youtubePlayer.getView().getTop() - offset);
}
This obviously is not a good fix, because it depends on the ratio of the video and how it is shown on your display. Also your ScrollView will be scrolled to a different place after rotation (which you could re-reset manually later on).
I have simple task: fade screen (+ other actions, but it doesnt matter now) when something happens (say, button pressed).
My minSDKVersion is 11. I do it in this way: activity layout contains a view:
<View
android:id="#+id/bgFadingView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:alpha="0"
android:background="#android:color/black" />
and method where I fade screen is as follows:
protected void fadeBGView(boolean fadeIn)
{
ObjectAnimator animator = ObjectAnimator.ofFloat(bgFadingView, "alpha", fadeIn ? 0.75f : 0f); //bgFadingView is initialized via findViewById(R.id.bgFadingView);
animator.setDuration(1000);
animator.start();
}
in other words, I have black view, which occupies the whole screen and when I need to fadeIn, I change view's alpha from 0 to 0.75.
The problem is that it works with bad framerate... I see fading animation frame by frame - it works at about 15fps. What am I doing wrong? Android system fading works much more smoothly - I want to archieve the same result or close. How to?
All I had to do was:
ObjectAnimator.setFrameDelay(10);
default frame delay was too long, so my animations didnt work smoothly. The problem was not due to device performance limitations.
I am trying to make a game with several "screen". If the user goes to the edge of a screen, an animation should pop in that shifts out the current screen and shifts in the new screen.
I wanted to do this with a TranslateAnimation. First I calculate an bitmap which contains the first and the second screen and then i want to play this in the view 'transitionView' while i hide the view 'levelView', which originally contained the first screen. After the transition is finished, i want to hide 'transitionView' again and display the new screen in 'levelView'.
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/viewGroup"
android:layout_width="match_parent"
android:layout_height="match_parent">
<view
class="at.test.game.ScreenTransitionTest2$LevelView"
android:id="#+id/levelView"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
<view
class="at.test.game.ScreenTransitionTest2$TransitionView"
android:id="#+id/transitionView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="gone"/>
</RelativeLayout>
I first tried to to it with an ImageView, but it would always scale down the bitmap regardless of the settings i used. So I now created my own View, which just draws the image from (0, 0).
Since clipping occured, I disabled it in the onCreate method:
((RelativeLayout)findViewById(R.id.viewGroup)).setClipChildren(false);
The animation looks like this:
this.transitionView.setBitmap(calculateBitmap(screen1, screen2));
TranslateAnimation a = new TranslateAnimation(
Animation.ABSOLUTE, startx, Animation.ABSOLUTE, endx,
Animation.ABSOLUTE, starty, Animation.ABSOLUTE, endy);
a.setDuration(3000);
a.setFillAfter(true);
this.transitionView.setAnimation(a);
a.start();
My problem: Only 480x800 of the bitmap is rendered/moved correctly (the bitmap is about 1000x880 and its starting coordinates are like (-40, -40), endcoordinates (-520, -40)) outside this area (so on the bottom of the screen and to the right as the 2nd frame should move in) instead of displaying the rest of the bitmap nothing is drawn or just smeared (see screenshot)
Why does the bitmap not get correctly drawn in the animation? Did I miss some settings? I tried 'wrap_content' for the viewgroup, but that did not help either. Or is it just not possible to slide bigger bitmaps through the whole screen?
screenshot - nothing is drawn on bottom and smearing occurs on the right