diff --git a/Live/src/main/java/com/frank/live/camera/Camera2Helper.java b/Live/src/main/java/com/frank/live/camera/Camera2Helper.java index 77c7354..65b9a1f 100644 --- a/Live/src/main/java/com/frank/live/camera/Camera2Helper.java +++ b/Live/src/main/java/com/frank/live/camera/Camera2Helper.java @@ -36,6 +36,8 @@ import java.util.concurrent.locks.ReentrantLock; import androidx.annotation.NonNull; +import com.frank.live.util.YUVUtil; + /** * Camera2: open, preview and close * Created by frank on 2019/12/18. @@ -67,11 +69,14 @@ public class Camera2Helper { private Size mPreviewSize; + private int rotateDegree = 0; + private Camera2Helper(Builder builder) { mTextureView = builder.previewDisplayView; specificCameraId = builder.specificCameraId; camera2Listener = builder.camera2Listener; rotation = builder.rotation; + rotateDegree = builder.rotateDegree; previewViewSize = builder.previewViewSize; context = builder.context; } @@ -479,12 +484,13 @@ public class Camera2Helper { private int rotation; + private int rotateDegree; + private Context context; public Builder() { } - public Builder previewOn(TextureView val) { previewDisplayView = val; return this; @@ -500,6 +506,10 @@ public class Camera2Helper { return this; } + public Builder rotateDegree(int val) { + rotateDegree = val; + return this; + } public Builder specificCameraId(String val) { specificCameraId = val; @@ -527,6 +537,7 @@ public class Camera2Helper { private class OnImageAvailableListenerImpl implements ImageReader.OnImageAvailableListener { private byte[] temp = null; private byte[] yuvData = null; + private byte[] dstData = null; private final ReentrantLock lock = new ReentrantLock(); @Override @@ -569,9 +580,20 @@ public class Camera2Helper { offset += len / 4; } - if (camera2Listener != null) { - camera2Listener.onPreviewFrame(yuvData); + if (rotateDegree == 90) { + if (dstData == null) { + dstData = new byte[len * 3 / 2]; + } + YUVUtil.YUV420pRotate90(dstData, yuvData, width, height); + if (camera2Listener != null) { + camera2Listener.onPreviewFrame(dstData); + } + } else { + if (camera2Listener != null) { + camera2Listener.onPreviewFrame(yuvData); + } } + lock.unlock(); } image.close(); diff --git a/Live/src/main/java/com/frank/live/stream/VideoStreamNew.java b/Live/src/main/java/com/frank/live/stream/VideoStreamNew.java index d61ab3d..3ad6ba1 100644 --- a/Live/src/main/java/com/frank/live/stream/VideoStreamNew.java +++ b/Live/src/main/java/com/frank/live/stream/VideoStreamNew.java @@ -6,6 +6,7 @@ import android.graphics.Point; import android.graphics.SurfaceTexture; import android.util.Log; import android.util.Size; +import android.view.Surface; import android.view.SurfaceHolder; import android.view.TextureView; import android.view.View; @@ -24,6 +25,7 @@ public class VideoStreamNew extends VideoStreamBase private static final String TAG = VideoStreamNew.class.getSimpleName(); + private int rotation = 0; private boolean isLiving; private final Context mContext; private Camera2Helper camera2Helper; @@ -47,9 +49,8 @@ public class VideoStreamNew extends VideoStreamBase * start previewing */ private void startPreview() { - int rotateDegree = 0; if (mContext instanceof Activity) { - rotateDegree = ((Activity) mContext).getWindowManager().getDefaultDisplay().getRotation(); + rotation = ((Activity) mContext).getWindowManager().getDefaultDisplay().getRotation(); } camera2Helper = new Camera2Helper.Builder() .cameraListener(this) @@ -57,7 +58,8 @@ public class VideoStreamNew extends VideoStreamBase .context(mContext.getApplicationContext()) .previewOn(mTextureView) .previewViewSize(new Point(mVideoParam.getWidth(), mVideoParam.getHeight())) - .rotation(rotateDegree) + .rotation(rotation) + .rotateDegree(getPreviewDegree(rotation)) .build(); camera2Helper.start(); } @@ -137,12 +139,33 @@ public class VideoStreamNew extends VideoStreamBase } } + private int getPreviewDegree(int rotation) { + switch (rotation) { + case Surface.ROTATION_0: + return 90; + case Surface.ROTATION_90: + return 0; + case Surface.ROTATION_180: + return 270; + case Surface.ROTATION_270: + return 180; + default: + return -1; + } + } + @Override public void onCameraOpened(Size previewSize, int displayOrientation) { Log.i(TAG, "onCameraOpened previewSize=" + previewSize.toString()); if (mCallback != null && mVideoParam != null) { - mCallback.onVideoCodecInfo(previewSize.getWidth(), previewSize.getHeight(), - mVideoParam.getFrameRate(), mVideoParam.getBitRate()); + int width = previewSize.getWidth(); + int height = previewSize.getHeight(); + if (getPreviewDegree(rotation) == 90 || getPreviewDegree(rotation) == 270) { + int temp = width; + width = height; + height = temp; + } + mCallback.onVideoCodecInfo(width, height, mVideoParam.getFrameRate(), mVideoParam.getBitRate()); } } diff --git a/Live/src/main/java/com/frank/live/util/YUVUtil.java b/Live/src/main/java/com/frank/live/util/YUVUtil.java index eb30837..4786703 100644 --- a/Live/src/main/java/com/frank/live/util/YUVUtil.java +++ b/Live/src/main/java/com/frank/live/util/YUVUtil.java @@ -19,23 +19,22 @@ public class YUVUtil { for (int j = 0; j < height; j++) { for (int i = 0; i < width; i++) { - a = (input[index] & 0xff000000) >> 24; // a is not used obviously + a = (input[index] & 0xff000000) >> 24; R = (input[index] & 0xff0000) >> 16; G = (input[index] & 0xff00) >> 8; B = (input[index] & 0xff); - // well known RGB to YUV algorithm + // RGB to YUV algorithm Y = ((66 * R + 129 * G + 25 * B + 128) >> 8) + 16; U = ((-38 * R - 74 * G + 112 * B + 128) >> 8) + 128; V = ((112 * R - 94 * G - 18 * B + 128) >> 8) + 128; // NV21 has a plane of Y and interleaved planes of VU each sampled by a factor of 2 - // meaning for every 4 Y pixels there are 1 V and 1 U. Note the sampling is every other - // pixel AND every other scanLine. - yuv420sp[yIndex++] = (byte) ((Y < 0) ? 0 : ((Y > 255) ? 255 : Y)); + // meaning for every 4 Y pixels there are 1 V and 1 U. + yuv420sp[yIndex++] = (byte) ((Y < 0) ? 0 : (Math.min(Y, 255))); if (j % 2 == 0 && index % 2 == 0) { - yuv420sp[uvIndex++] = (byte) ((V < 0) ? 0 : ((V > 255) ? 255 : V)); - yuv420sp[uvIndex++] = (byte) ((U < 0) ? 0 : ((U > 255) ? 255 : U)); + yuv420sp[uvIndex++] = (byte) ((V < 0) ? 0 : (Math.min(V, 255))); + yuv420sp[uvIndex++] = (byte) ((U < 0) ? 0 : (Math.min(U, 255))); } index++; @@ -44,4 +43,27 @@ public class YUVUtil { return yuv420sp; } + public static void YUV420pRotate90(byte[] dstData, byte[] data, int width, int height) { + int n = 0; + int wh = width * height; + //y + for (int j = 0; j < width; j++) { + for(int i = height - 1; i >= 0; i--) { + dstData[n++] = data[width * i + j]; + } + } + //u + for (int i = 0; i < width / 2; i++) { + for (int j = 1; j <= height / 2; j++) { + dstData[n++] = data[wh + ((height/2 - j) * (width / 2) + i)]; + } + } + //v + for(int i = 0; i < width / 2; i++) { + for(int j = 1; j <= height / 2; j++) { + dstData[n++] = data[wh + wh / 4 + ((height / 2 - j) * (width / 2) + i)]; + } + } + } + } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 172c5a6..44d5f8b 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -38,16 +38,13 @@ + android:configChanges="orientation|screenSize" /> - - - + + +