PIP aspect ratio should match video aspect ratio. fixes #4077

This commit is contained in:
Daniel Gultsch 2021-08-24 14:40:12 +02:00
parent e6d8bee035
commit 88d7ddf124
4 changed files with 98 additions and 7 deletions

View file

@ -1,5 +1,8 @@
package eu.siacs.conversations.ui; package eu.siacs.conversations.ui;
import static java.util.Arrays.asList;
import static eu.siacs.conversations.utils.PermissionUtils.getFirstDenied;
import android.Manifest; import android.Manifest;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
import android.app.PictureInPictureParams; import android.app.PictureInPictureParams;
@ -55,6 +58,7 @@ import eu.siacs.conversations.services.AppRTCAudioManager;
import eu.siacs.conversations.services.XmppConnectionService; import eu.siacs.conversations.services.XmppConnectionService;
import eu.siacs.conversations.ui.util.AvatarWorkerTask; import eu.siacs.conversations.ui.util.AvatarWorkerTask;
import eu.siacs.conversations.ui.util.MainThreadExecutor; import eu.siacs.conversations.ui.util.MainThreadExecutor;
import eu.siacs.conversations.ui.util.Rationals;
import eu.siacs.conversations.utils.PermissionUtils; import eu.siacs.conversations.utils.PermissionUtils;
import eu.siacs.conversations.utils.TimeFrameUtils; import eu.siacs.conversations.utils.TimeFrameUtils;
import eu.siacs.conversations.xml.Namespace; import eu.siacs.conversations.xml.Namespace;
@ -65,10 +69,7 @@ import eu.siacs.conversations.xmpp.jingle.JingleRtpConnection;
import eu.siacs.conversations.xmpp.jingle.Media; import eu.siacs.conversations.xmpp.jingle.Media;
import eu.siacs.conversations.xmpp.jingle.RtpEndUserState; import eu.siacs.conversations.xmpp.jingle.RtpEndUserState;
import static eu.siacs.conversations.utils.PermissionUtils.getFirstDenied; public class RtpSessionActivity extends XmppActivity implements XmppConnectionService.OnJingleRtpConnectionUpdate, eu.siacs.conversations.ui.widget.SurfaceViewRenderer.OnAspectRatioChanged {
import static java.util.Arrays.asList;
public class RtpSessionActivity extends XmppActivity implements XmppConnectionService.OnJingleRtpConnectionUpdate {
public static final String EXTRA_WITH = "with"; public static final String EXTRA_WITH = "with";
public static final String EXTRA_SESSION_ID = "session_id"; public static final String EXTRA_SESSION_ID = "session_id";
@ -446,12 +447,14 @@ public class RtpSessionActivity extends XmppActivity implements XmppConnectionSe
public void onStart() { public void onStart() {
super.onStart(); super.onStart();
mHandler.postDelayed(mTickExecutor, CALL_DURATION_UPDATE_INTERVAL); mHandler.postDelayed(mTickExecutor, CALL_DURATION_UPDATE_INTERVAL);
this.binding.remoteVideo.setOnAspectRatioChanged(this);
} }
@Override @Override
public void onStop() { public void onStop() {
mHandler.removeCallbacks(mTickExecutor); mHandler.removeCallbacks(mTickExecutor);
binding.remoteVideo.release(); binding.remoteVideo.release();
binding.remoteVideo.setOnAspectRatioChanged(null);
binding.localVideo.release(); binding.localVideo.release();
final WeakReference<JingleRtpConnection> weakReference = this.rtpConnectionReference; final WeakReference<JingleRtpConnection> weakReference = this.rtpConnectionReference;
final JingleRtpConnection jingleRtpConnection = weakReference == null ? null : weakReference.get(); final JingleRtpConnection jingleRtpConnection = weakReference == null ? null : weakReference.get();
@ -515,9 +518,12 @@ public class RtpSessionActivity extends XmppActivity implements XmppConnectionSe
@RequiresApi(api = Build.VERSION_CODES.O) @RequiresApi(api = Build.VERSION_CODES.O)
private void startPictureInPicture() { private void startPictureInPicture() {
try { try {
final Rational rational = this.binding.remoteVideo.getAspectRatio();
final Rational clippedRational = Rationals.clip(rational);
Log.d(Config.LOGTAG, "suggested rational " + rational + ". clipped to " + clippedRational);
enterPictureInPictureMode( enterPictureInPictureMode(
new PictureInPictureParams.Builder() new PictureInPictureParams.Builder()
.setAspectRatio(new Rational(10, 16)) .setAspectRatio(clippedRational)
.build() .build()
); );
} catch (final IllegalStateException e) { } catch (final IllegalStateException e) {
@ -526,6 +532,17 @@ public class RtpSessionActivity extends XmppActivity implements XmppConnectionSe
} }
} }
@Override
public void onAspectRatioChanged(final Rational rational) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && isPictureInPicture()) {
final Rational clippedRational = Rationals.clip(rational);
Log.d(Config.LOGTAG, "suggested rational after aspect ratio change " + rational + ". clipped to " + clippedRational);
setPictureInPictureParams(new PictureInPictureParams.Builder()
.setAspectRatio(clippedRational)
.build());
}
}
private boolean deviceSupportsPictureInPicture() { private boolean deviceSupportsPictureInPicture() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
return getPackageManager().hasSystemFeature(PackageManager.FEATURE_PICTURE_IN_PICTURE); return getPackageManager().hasSystemFeature(PackageManager.FEATURE_PICTURE_IN_PICTURE);

View file

@ -0,0 +1,26 @@
package eu.siacs.conversations.ui.util;
import android.util.Rational;
public final class Rationals {
//between 2.39:1 and 1:2.39 (inclusive).
private static final Rational MIN = new Rational(100,239);
private static final Rational MAX = new Rational(239,100);
private Rationals() {
}
public static Rational clip(final Rational input) {
if (input.compareTo(MIN) < 0) {
return MIN;
}
if (input.compareTo(MAX) > 0) {
return MAX;
}
return input;
}
}

View file

@ -0,0 +1,48 @@
package eu.siacs.conversations.ui.widget;
import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.util.Rational;
import eu.siacs.conversations.Config;
public class SurfaceViewRenderer extends org.webrtc.SurfaceViewRenderer {
private Rational aspectRatio = new Rational(1,1);
private OnAspectRatioChanged onAspectRatioChanged;
public SurfaceViewRenderer(Context context) {
super(context);
}
public SurfaceViewRenderer(Context context, AttributeSet attrs) {
super(context, attrs);
}
public void onFrameResolutionChanged(int videoWidth, int videoHeight, int rotation) {
super.onFrameResolutionChanged(videoWidth, videoHeight, rotation);
final int rotatedWidth = rotation != 0 && rotation != 180 ? videoHeight : videoWidth;
final int rotatedHeight = rotation != 0 && rotation != 180 ? videoWidth : videoHeight;
final Rational currentRational = this.aspectRatio;
this.aspectRatio = new Rational(rotatedWidth, rotatedHeight);
Log.d(Config.LOGTAG,"onFrameResolutionChanged("+rotatedWidth+","+rotatedHeight+","+aspectRatio+")");
if (currentRational.equals(this.aspectRatio) || onAspectRatioChanged == null) {
return;
}
onAspectRatioChanged.onAspectRatioChanged(this.aspectRatio);
}
public void setOnAspectRatioChanged(final OnAspectRatioChanged onAspectRatioChanged) {
this.onAspectRatioChanged = onAspectRatioChanged;
}
public Rational getAspectRatio() {
return this.aspectRatio;
}
public interface OnAspectRatioChanged {
void onAspectRatioChanged(final Rational rational);
}
}

View file

@ -98,13 +98,13 @@
android:gravity="center" android:gravity="center"
android:visibility="gone"> android:visibility="gone">
<org.webrtc.SurfaceViewRenderer <eu.siacs.conversations.ui.widget.SurfaceViewRenderer
android:id="@+id/remote_video" android:id="@+id/remote_video"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" /> android:layout_height="wrap_content" />
</LinearLayout> </LinearLayout>
<org.webrtc.SurfaceViewRenderer <eu.siacs.conversations.ui.widget.SurfaceViewRenderer
android:id="@+id/local_video" android:id="@+id/local_video"
android:layout_width="@dimen/local_video_preview_width" android:layout_width="@dimen/local_video_preview_width"
android:layout_height="@dimen/local_video_preview_height" android:layout_height="@dimen/local_video_preview_height"