我在Linearlayout中包装了SurfaceViewRenderer并以编程方式将其添加到已经包装的Linearlayout(id为dynamic_layout)
我在此视图中添加了子视图
<HorizontalScrollView
android:layout_width="match_parent"
android:layout_height="150dp"
android:layout_gravity="bottom">
<LinearLayout
android:id="@+id/dynamic_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
</LinearLayout>
</HorizontalScrollView>
这是subView
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/remote_video_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<org.webrtc.SurfaceViewRenderer
android:id="@+id/remote_video_view"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
这是java代码
mActivity.runOnUiThread(new Runnable() {
@Override
public void run() {
RtcAdapter.this.totalConnection = totalConnection;
for (int i = 0; i < totalConnection; i++) {
LayoutInflater inflater = LayoutInflater.from(mActivity);
final View view = inflater.inflate(R.layout.video_adapter, null);
mLinearLayout_papa.addView(view);
mList.add(new VideoViewLayout(R.id.remote_video_layout, RtcAdapter.this, R.id.remote_video_view, i, view));
}
}
});
这是我的 AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.gwl.webrtcnewgradle">
<uses-feature android:name="android.hardware.camera"
android:required="true" />
<uses-feature android:name="android.hardware.camera.autofocus" />
<uses-feature
android:glEsVersion="0x00020000"
android:required="true" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<supports-gl-texture android:name="GL_OES_compressed_ETC1_RGB8_texture" />
<supports-gl-texture android:name="GL_OES_compressed_paletted_texture" />
<supports-gl-texture android:name="GL_AMD_compressed_ATC_texture" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity"
android:configChanges="keyboard|keyboardHidden|orientation|screenSize"
android:theme="@style/AppTheme.NoActionBar"
>
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
这是app gradle app / build
apply plugin: 'com.android.application'
android {
compileSdkVersion 27
buildToolsVersion "26.0.2"
defaultConfig {
applicationId "com.gwl.webrtcnewgradle"
minSdkVersion 17
targetSdkVersion 27
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
implementation fileTree(include: ['*.jar'], dir: 'libs')
implementation 'com.android.support:appcompat-v7:27.0.0'
implementation 'com.android.support.constraint:constraint-layout:1.0.2'
testImplementation 'junit:junit:4.12'
androidTestImplementation('com.android.support.test.espresso:espresso-core:3.0.1', {
exclude group: 'com.android.support', module: 'support-annotations'
})
implementation 'org.webrtc:google-webrtc:1.0.+'
compile('io.socket:socket.io-client:0.8.3') {
exclude group: 'org.json', module: 'json'
}
implementation 'com.android.support:recyclerview-v7:27.0.0'
}
这是SurfaceViewRenderer类
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package org.webrtc;
import android.content.Context;
import android.content.res.Resources.NotFoundException;
import android.graphics.Point;
import android.os.Looper;
import android.util.AttributeSet;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.SurfaceHolder.Callback;
import org.webrtc.EglRenderer.FrameListener;
import org.webrtc.RendererCommon.GlDrawer;
import org.webrtc.RendererCommon.RendererEvents;
import org.webrtc.RendererCommon.ScalingType;
import org.webrtc.RendererCommon.VideoLayoutMeasure;
import org.webrtc.VideoRenderer.Callbacks;
import org.webrtc.VideoRenderer.I420Frame;
public class SurfaceViewRenderer extends SurfaceView implements Callback, Callbacks, VideoSink, RendererEvents {
private static final String TAG = "SurfaceViewRenderer";
private final String resourceName = this.getResourceName();
private final VideoLayoutMeasure videoLayoutMeasure = new VideoLayoutMeasure();
private final SurfaceEglRenderer eglRenderer;
private RendererEvents rendererEvents;
private int rotatedFrameWidth;
private int rotatedFrameHeight;
private boolean enableFixedSize;
private int surfaceWidth;
private int surfaceHeight;
public SurfaceViewRenderer(Context context) {
super(context);
this.eglRenderer = new SurfaceEglRenderer(this.resourceName);
this.getHolder().addCallback(this);
this.getHolder().addCallback(this.eglRenderer);
}
public SurfaceViewRenderer(Context context, AttributeSet attrs) {
super(context, attrs);
this.eglRenderer = new SurfaceEglRenderer(this.resourceName);
this.getHolder().addCallback(this);
this.getHolder().addCallback(this.eglRenderer);
}
public void init(org.webrtc.EglBase.Context sharedContext, RendererEvents rendererEvents) {
this.init(sharedContext, rendererEvents, EglBase.CONFIG_PLAIN, new GlRectDrawer());
}
public void init(org.webrtc.EglBase.Context sharedContext, RendererEvents rendererEvents, int[] configAttributes, GlDrawer drawer) {
ThreadUtils.checkIsOnMainThread();
this.rendererEvents = rendererEvents;
this.rotatedFrameWidth = 0;
this.rotatedFrameHeight = 0;
this.eglRenderer.init(sharedContext, this, configAttributes, drawer);
}
public void release() {
this.eglRenderer.release();
}
public void addFrameListener(FrameListener listener, float scale, GlDrawer drawerParam) {
this.eglRenderer.addFrameListener(listener, scale, drawerParam);
}
public void addFrameListener(FrameListener listener, float scale) {
this.eglRenderer.addFrameListener(listener, scale);
}
public void removeFrameListener(FrameListener listener) {
this.eglRenderer.removeFrameListener(listener);
}
public void setEnableHardwareScaler(boolean enabled) {
ThreadUtils.checkIsOnMainThread();
this.enableFixedSize = enabled;
this.updateSurfaceSize();
}
public void setMirror(boolean mirror) {
this.eglRenderer.setMirror(mirror);
}
public void setScalingType(ScalingType scalingType) {
ThreadUtils.checkIsOnMainThread();
this.videoLayoutMeasure.setScalingType(scalingType);
this.requestLayout();
}
public void setScalingType(ScalingType scalingTypeMatchOrientation, ScalingType scalingTypeMismatchOrientation) {
ThreadUtils.checkIsOnMainThread();
this.videoLayoutMeasure.setScalingType(scalingTypeMatchOrientation, scalingTypeMismatchOrientation);
this.requestLayout();
}
public void setFpsReduction(float fps) {
this.eglRenderer.setFpsReduction(fps);
}
public void disableFpsReduction() {
this.eglRenderer.disableFpsReduction();
}
public void pauseVideo() {
this.eglRenderer.pauseVideo();
}
public void renderFrame(I420Frame frame) {
this.eglRenderer.renderFrame(frame);
}
public void onFrame(VideoFrame frame) {
this.eglRenderer.onFrame(frame);
}
protected void onMeasure(int widthSpec, int heightSpec) {
ThreadUtils.checkIsOnMainThread();
Point size = this.videoLayoutMeasure.measure(widthSpec, heightSpec, this.rotatedFrameWidth, this.rotatedFrameHeight);
this.setMeasuredDimension(size.x, size.y);
this.logD("onMeasure(). New size: " + size.x + "x" + size.y);
}
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
ThreadUtils.checkIsOnMainThread();
this.eglRenderer.setLayoutAspectRatio((float)(right - left) / (float)(bottom - top));
this.updateSurfaceSize();
}
private void updateSurfaceSize() {
ThreadUtils.checkIsOnMainThread();
if(this.enableFixedSize && this.rotatedFrameWidth != 0 && this.rotatedFrameHeight != 0 && this.getWidth() != 0 && this.getHeight() != 0) {
float layoutAspectRatio = (float)this.getWidth() / (float)this.getHeight();
float frameAspectRatio = (float)this.rotatedFrameWidth / (float)this.rotatedFrameHeight;
int drawnFrameWidth;
int drawnFrameHeight;
if(frameAspectRatio > layoutAspectRatio) {
drawnFrameWidth = (int)((float)this.rotatedFrameHeight * layoutAspectRatio);
drawnFrameHeight = this.rotatedFrameHeight;
} else {
drawnFrameWidth = this.rotatedFrameWidth;
drawnFrameHeight = (int)((float)this.rotatedFrameWidth / layoutAspectRatio);
}
int width = Math.min(this.getWidth(), drawnFrameWidth);
int height = Math.min(this.getHeight(), drawnFrameHeight);
this.logD("updateSurfaceSize. Layout size: " + this.getWidth() + "x" + this.getHeight() + ", frame size: " + this.rotatedFrameWidth + "x" + this.rotatedFrameHeight + ", requested surface size: " + width + "x" + height + ", old surface size: " + this.surfaceWidth + "x" + this.surfaceHeight);
if(width != this.surfaceWidth || height != this.surfaceHeight) {
this.surfaceWidth = width;
this.surfaceHeight = height;
this.getHolder().setFixedSize(width, height);
}
} else {
this.surfaceWidth = this.surfaceHeight = 0;
this.getHolder().setSizeFromLayout();
}
}
public void surfaceCreated(SurfaceHolder holder) {
ThreadUtils.checkIsOnMainThread();
this.surfaceWidth = this.surfaceHeight = 0;
this.updateSurfaceSize();
}
public void surfaceDestroyed(SurfaceHolder holder) {
}
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
private String getResourceName() {
try {
return this.getResources().getResourceEntryName(this.getId());
} catch (NotFoundException var2) {
return "";
}
}
public void clearImage() {
this.eglRenderer.clearImage();
}
public void onFirstFrameRendered() {
if(this.rendererEvents != null) {
this.rendererEvents.onFirstFrameRendered();
}
}
public void onFrameResolutionChanged(int videoWidth, int videoHeight, int rotation) {
if(this.rendererEvents != null) {
this.rendererEvents.onFrameResolutionChanged(videoWidth, videoHeight, rotation);
}
int rotatedWidth = rotation != 0 && rotation != 180?videoHeight:videoWidth;
int rotatedHeight = rotation != 0 && rotation != 180?videoWidth:videoHeight;
this.postOrRun(new SurfaceViewRenderer$$Lambda$0(this, rotatedWidth, rotatedHeight));
}
private void postOrRun(Runnable r) {
if(Thread.currentThread() == Looper.getMainLooper().getThread()) {
r.run();
} else {
this.post(r);
}
}
private void logD(String string) {
Logging.d("SurfaceViewRenderer", this.resourceName + ": " + string);
}
}
我的代码在Pixel中运行良好,但在HTC和S7等其他设备中运行良好 边缘。我得到了以下例外。
SurfaceFlinger: dimensions too large 16777215 x 300
SurfaceFlinger: createNormalLayer() failed (Invalid argument)
SurfaceComposerClient: SurfaceComposerClient::createSurface error Invalid argument