Ich sende Android Kamera Vorschau Unity3D mit Textur und es ist gestreckt. Die Vorschau wird nicht in Android zu jeder Ansicht gerendert, sondern direkt auf eine Textur mit:Android Kamera Vorschau auf eine Textur gerendert ist gestreckt
setPreviewTexture(texture);
Dann werden die Bytes Unity3d gesendet und auf dem Bildschirm mit jedem onPreviewFrame gezogen.
Die Vorschaugröße der Kamera und die Texturgröße sind auf 1024x768 eingestellt und der Texturcontainer in Unity3d hat dieselbe Größe. Die Auflösung des Geräts ist 960x540, also ist es ein anderes Verhältnis. Ich wähle eine unterstützte Auflösung für die Kamera, die native Größe hat ein Verhältnis von 4: 3, also sollte es keine Dehnung geben. Es sieht so aus, als würde Android nur den Teil rendern, der tatsächlich gerendert werden kann - es benötigt ein 16: 9 Bild und rendert es zu einer 4: 3 Textur. Wenn ich falsch liege, bitte korrigieren Sie mich aber, wie es in diesem Beispiel zu funktionieren scheint. Hier ist ein Stück Code:
public int startCamera(int idx, int width, int height) {
nativeTexturePointer = createExternalTexture();
texture = new SurfaceTexture(nativeTexturePointer);
mCamera = Camera.open(idx);
setupCamera(width, height);
try {
mCamera.setPreviewTexture(texture);
mCamera.setPreviewCallback(this);
mCamera.startPreview();
Log.i("Unity", "JAVA: camera started");
} catch (IOException ioe) {
Log.w("Unity", "JAVA: CAM LAUNCH FAILED");
}
return nativeTexturePointer;
}
public void stopCamera() {
mCamera.setPreviewCallback(null);
mCamera.stopPreview();
mCamera.release();
GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, 0);
Log.i("Unity", "JAVA: Camera stopped");
}
private int createExternalTexture() {
int[] textureIdContainer = new int[1];
GLES20.glGenTextures(1, textureIdContainer, 0);
GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, textureIdContainer[0]);
return textureIdContainer[0];
}
@SuppressLint("NewApi")
private void setupCamera(int width, int height) {
Camera.Parameters params = mCamera.getParameters();
params.setRecordingHint(true);
params.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO);
params.setPreviewFormat(17);
params.setZoom(0);
// 16 ~ NV16 ~ YCbCr
// 17 ~ NV21 ~ YCbCr ~ DEFAULT *
// 4 ~ RGB_565
// 256~ JPEG
// 20 ~ YUY2 ~ YcbCr ...
// 842094169 ~ YV12 ~ 4:2:0 YCrCb comprised of WXH Y plane, W/2xH/2 Cr & Cb. see documentation *
params.setFlashMode(Camera.Parameters.FLASH_MODE_TORCH);
Camera.Size previewSize = getOptimalSize(width, height, mCamera.getParameters().getSupportedPreviewSizes());
Camera.Size picSize = getOptimalSize(width, height, mCamera.getParameters().getSupportedPictureSizes());
params.setPictureSize(picSize.width, picSize.height);
params.setPreviewSize(previewSize.width, previewSize.height);
params.setWhiteBalance(Camera.Parameters.WHITE_BALANCE_AUTO);
params.setExposureCompensation(0);
try{
mCamera.setParameters(params);
} catch (Exception e){
Log.i("Unity", "ERROR: " + e.getMessage());
}
Camera.Size mCameraPreviewSize = params.getPreviewSize();
prevWidth = mCameraPreviewSize.width;
prevHeight = mCameraPreviewSize.height;
int[] fpsRange = new int[2];
params.getPreviewFpsRange(fpsRange);
}
private Camera.Size getOptimalSize(int width, int height, List<Camera.Size> sizes) {
if(mCamera == null)
return null;
final double ASPECT_TOLERANCE = 0.1;
double targetRatio=(double)width/height;
if (sizes == null)
return null;
Camera.Size optimalSize = null;
double minDiff = Double.MAX_VALUE;
int targetWidth = width;
for (Camera.Size size : sizes) {
double ratio = (double) size.width/size.height;
Log.i("Unity", "RES: size=" + size.width + "/" + size.height + "/ Aspect Ratio: " + ratio + "target width: " + width + "target height: " + height);
if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE) continue;
if (Math.abs(size.width - targetWidth) < minDiff) {
optimalSize = size;
minDiff = Math.abs(size.width - targetWidth);
}
}
if (optimalSize == null) {
minDiff = Double.MAX_VALUE;
for (Camera.Size size : sizes) {
if (Math.abs(size.width - targetWidth) < minDiff) {
optimalSize = size;
minDiff = Math.abs(size.width - targetWidth);
}
}
}
Log.i("Unity", "optimal size=" + optimalSize.width + "/" + optimalSize.height + "/ Aspect Ratio: " + (double) optimalSize.width/optimalSize.height);
return optimalSize;
}
public int getPreviewSizeWidth() {
return prevWidth;
}
public int getPreviewSizeHeight() { return prevHeight; }
public byte[] bytes;
@Override
public void onPreviewFrame(byte[] data, Camera camera) {
bytes = data;
//Log.i("Unity", "JAVA: " + Integer.toString(data.length));
UnityPlayer.UnitySendMessage(gameObjectTargetName, "GetBuffer", "");
}
Es ist erforderlich, dass die Textur zu Unity3d 1024x768 ist ohne Zuschneiden gesendet. Hat irgendjemand eine Lösung dafür?
UPDATE (C# -Code hinzugefügt)
Dieser Code Vorschau von Java wird:
private RectTransform previewRect {
get {
if (!_previewRect)
_previewRect = cameraPreview.GetComponent<RectTransform>();
return _previewRect;
}
}
private void GetPreviewFromCamera() {
NativeCamera.OnCameraTextureCreated += (Texture2D cameraTex) => {
if (cameraPreview != null && cameraPreview.texture != null)
DestroyImmediate(cameraPreview.texture);
previewRect.sizeDelta = new Vector2(1024, 768);
cameraPreview.texture = cameraTex;
cameraPreview.enabled = true;
};
}
UPDATE: Added
void CreateCameraTexture() {
_texWidth = nativeCameraObject.Call<int>("getPreviewSizeWidth");
_texHeight = nativeCameraObject.Call<int>("getPreviewSizeHeight");
_cameraPreview = new Texture2D(_texWidth, _texHeight, TextureFormat.Alpha8, false);
_converter = new YUVDecode(_texWidth, _texHeight);
shaderMat.SetFloat("_Width", _texWidth);
if (OnCameraTextureCreated != null)
OnCameraTextureCreated(_cameraPreview);
}
private byte[] _bytes;
public void GetBuffer(string str) {
_bytes = nativeCameraObject.Get<byte[]>("bytes");
SetColor(_bytes);
_cameraPreview.LoadRawTextureData(_bytes);
_cameraPreview.Apply();
UpdateLibFrame();
}
void SetColor(byte[] bytes) {
_converter.SetBytes(bytes);
shaderMat.SetTexture("_YUVTex", _converter.yuvtexture);
}
void UpdateLibFrame() {
if (OnFrameUpdate != null) OnFrameUpdate(_cameraPreview.GetRawTextureData());
}
Dieser Code in einer anderen Klasse, die Daten zeigen, Link zu einem Beispielprojekt
Das Projekt ist hier: https://www.dropbox.com/s/wid1qa9cmq3ck6w/CameraPreview.zip?dl=0
CameraJava ein gradle Projekt. Die Ausgabe ist eine .AAR-Datei, die Sie in Assets/Plugins kopieren müssen.
wo ist der Einheitscode? – andruido
Ich habe den Beitrag mit C# -Code aktualisiert – krzychawe
Ich konnte Ihren Code nicht vollständig replizieren, texture2d bleibt schwarz auf Einheit. vielleicht, weil ich YUY2 Format verwende? Das würde deinen Shader-Code erklären. Kannst du den ganzen Code hochladen? – andruido