【发布时间】:2017-12-22 15:20:15
【问题描述】:
我需要使用WebRTC for android 将特定的裁剪(面部)视频发送到 videoChannel。我能够操纵Camera1Session WebRTC 类来裁剪脸部。现在我将它设置为 ImageView。
listenForBytebufferFrames() 的Camera1Session.java
private void listenForBytebufferFrames() {
this.camera.setPreviewCallbackWithBuffer(new PreviewCallback() {
public void onPreviewFrame(byte[] data, Camera callbackCamera) {
Camera1Session.this.checkIsOnCameraThread();
if(callbackCamera != Camera1Session.this.camera) {
Logging.e("Camera1Session", "Callback from a different camera. This should never happen.");
} else if(Camera1Session.this.state != Camera1Session.SessionState.RUNNING) {
Logging.d("Camera1Session", "Bytebuffer frame captured but camera is no longer running.");
} else {
mFrameProcessor.setNextFrame(data, callbackCamera);
long captureTimeNs = TimeUnit.MILLISECONDS.toNanos(SystemClock.elapsedRealtime());
if(!Camera1Session.this.firstFrameReported) {
int startTimeMs = (int)TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - Camera1Session.this.constructionTimeNs);
Camera1Session.camera1StartTimeMsHistogram.addSample(startTimeMs);
Camera1Session.this.firstFrameReported = true;
}
ByteBuffer byteBuffer1 = ByteBuffer.wrap(data);
Frame outputFrame = new Frame.Builder()
.setImageData(byteBuffer1,
Camera1Session.this.captureFormat.width,
Camera1Session.this.captureFormat.height,
ImageFormat.NV21)
.setTimestampMillis(mFrameProcessor.mPendingTimeMillis)
.setId(mFrameProcessor.mPendingFrameId)
.setRotation(3)
.build();
int w = outputFrame.getMetadata().getWidth();
int h = outputFrame.getMetadata().getHeight();
SparseArray<Face> detectedFaces = mDetector.detect(outputFrame);
if (detectedFaces.size() > 0) {
Face face = detectedFaces.valueAt(0);
ByteBuffer byteBufferRaw = outputFrame.getGrayscaleImageData();
byte[] byteBuffer = byteBufferRaw.array();
YuvImage yuvimage = new YuvImage(byteBuffer, ImageFormat.NV21, w, h, null);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
//My crop logic to get face co-ordinates
yuvimage.compressToJpeg(new Rect(left, top, right, bottom), 80, baos);
final byte[] jpegArray = baos.toByteArray();
Bitmap bitmap = BitmapFactory.decodeByteArray(jpegArray, 0, jpegArray.length);
Activity currentActivity = getActivity();
if (currentActivity instanceof CallActivity) {
((CallActivity) currentActivity).setBitmapToImageView(bitmap); //face on ImageView is set just fine
}
Camera1Session.this.events.onByteBufferFrameCaptured(Camera1Session.this, data, Camera1Session.this.captureFormat.width, Camera1Session.this.captureFormat.height, Camera1Session.this.getFrameOrientation(), captureTimeNs);
Camera1Session.this.camera.addCallbackBuffer(data);
} else {
Camera1Session.this.events.onByteBufferFrameCaptured(Camera1Session.this, data, Camera1Session.this.captureFormat.width, Camera1Session.this.captureFormat.height, Camera1Session.this.getFrameOrientation(), captureTimeNs);
Camera1Session.this.camera.addCallbackBuffer(data);
}
}
}
});
}
jpegArray 是我需要通过WebRTC 流式传输的最后一个字节数组,我尝试过这样的事情:
Camera1Session.this.events.onByteBufferFrameCaptured(Camera1Session.this, jpegArray, (int) face.getWidth(), (int) face.getHeight(), Camera1Session.this.getFrameOrientation(), captureTimeNs);
Camera1Session.this.camera.addCallbackBuffer(jpegArray);
像这样设置它们会给我以下错误:
../../webrtc/sdk/android/src/jni/androidvideotracksource.cc line 82
Check failed: length >= width * height + 2 * uv_width * ((height + 1) / 2) (2630 vs. 460800)
我认为这是因为 androidvideotracksource 没有得到与预期相同的 byteArray 长度,因为现在已经裁剪了帧。
有人可以指出如何实现它的方向吗?这是操作数据并输入videoTrack 的正确方法/位置吗?
编辑:bitmap of byteArray data 不会在 ImageView 上给我一个相机预览,这与 byteArray jpegArray 不同。也许是因为它们的包装不同?
【问题讨论】:
-
回复:byteArray 数据位图无法在 ImageView 上提供相机预览 - 如何从 NV21 数据创建位图?
-
yuvimage.compressToJpeg(new Rect(left, top, right, bottom), 80, baos);对 byteArray 执行此操作。我从decodeByteArray得到一张位图 -
那么,
((CallActivity) currentActivity).setBitmapToImageView(bitmap)没有按预期工作,但((CallActivity) currentActivity).setBitmapToImageView(jpegArray)工作? -
从
byte[] data创建位图并将其设置为 imageView 不起作用,但从byte[] jpegArray创建位图确实有效。无论如何,我已经发布了我的修复答案。此外,正如您所指出的,我还缩放到了预期的尺寸。但是我无法让I420Frame工作。 -
刚刚检查过这个。浏览 jpeg 需要 5-10 毫秒,
scale()+getNV21()需要 50-70 毫秒。这些都不会发生在 UI 线程上。我只在setBitmapToImageView(bitmap);内返回 UI 线程
标签: android android-camera webrtc android-vision apprtcdemo