gpt4 book ai didi

android - 如何用静态 YUV 帧覆盖 onPreviewFrame 数据?

转载 作者:行者123 更新时间:2023-11-29 21:11:21 29 4
gpt4 key购买 nike

我的应用程序覆盖了 onPreviewFrame 回调以将当前相机帧传递给 webrtc native 函数。这非常有效,但是如果在我的应用程序中选择了该选项,我希望能够切换到发送静态帧而不是视频。

到目前为止,我已经创建了一个 YUV NV21 图像,我将其存储在 Assets 目录中。将该帧传递给 native 函数的所有尝试都导致了紫色/绿色条纹,而不是实际图像。

这就是我目前所拥有的;

@Override
public void onPreviewFrame(byte[] data, Camera camera) {
previewBufferLock.lock();

if (mFrameProvider.isEnabled()) {
mFrameProvider.overwriteWithFrame(data, expectedFrameSize);
}

if (isCaptureRunning) {
if (data.length == expectedFrameSize) {
ProvideCameraFrame(data, expectedFrameSize, context);
cameraUtils.addCallbackBuffer(camera, data);
}
}
previewBufferLock.unlock();
}


@Override
public byte[] overwriteWithPreviewFrame(byte[] data, int expectedFrameSize) {
if (mFrameData == null) {
loadPreviewFrame();
}

for (int i=0; i < expectedFrameSize; i++) {
if (i < mFrameData.length) {
data[i] = mFrameData[i];
}
}

return data;
}

private void loadPreviewFrame() {
try {
InputStream open = mContext.getResources().getAssets().open(PREVIEW_FRAME_FILE);

mFrameData = IOUtils.toByteArray(open);
open.close();
} catch (Exception e) {
Log.e("", "", e);
}
}

我也试过将图像转换为位图。所以问题是如何从 Assets 中打开 YUV 帧并将其转换为合适的格式以传递给 native 方法。

结果如下;

enter image description here

最佳答案

在与 Android API 进行了长时间的斗争之后,我设法让它工作了。

有两个问题导致了绿色/紫色输出;

数据丢失:在相同分辨率下,生成的 YUV 帧比原始预览帧大,因此传递给 native 代码的数据丢失了大约 30% 的图像数据。

错误的分辨率: native 代码需要预览帧的分辨率,而不是相机的分辨率。

以下是适用于希望添加静态框架的任何人的可行解决方案;

所以更新了代码:

@Override
public byte[] getPreviewFrameData(int width, int height) {
if (mPreviewFrameData == null) {
loadPreviewFrame(width, height);
}

return mPreviewFrameData;
}

private void loadPreviewFrame(int width, int height) {
try {
Bitmap previewImage = BitmapFactory.decodeResource(mContext.getResources(), R.drawable.frame);
Bitmap resizedPreviewImage = Bitmap.createScaledBitmap(previewImage, width, height, false);

BitmapConverter bitmapConverter = new BitmapConverter();
mPreviewFrameData = bitmapConverter.convertToNV21(resizedPreviewImage);
} catch (Exception e) {
Log.e("DisabledCameraFrameProvider", "Failed to loadPreviewFrame");
}
}

class BitmapConverter {
byte [] convertToNV21(Bitmap bitmap) {
int inputWidth = bitmap.getWidth();
int inputHeight = bitmap.getHeight();

int [] argb = new int[inputWidth * inputHeight];

bitmap.getPixels(argb, 0, inputWidth, 0, 0, inputWidth, inputHeight);

byte [] yuv = new byte[inputWidth*inputHeight*3/2];
encodeYUV420SP(yuv, argb, inputWidth, inputHeight);

bitmap.recycle();

return yuv;
}

void encodeYUV420SP(byte[] yuv420sp, int[] argb, int width, int height) {
final int frameSize = width * height;

int yIndex = 0;
int uvIndex = frameSize;

int R, G, B, Y, U, V;
int index = 0;
for (int j = 0; j < height; j++) {
for (int i = 0; i < width; i++) {
R = (argb[index] & 0xff0000) >> 16;
G = (argb[index] & 0xff00) >> 8;
B = (argb[index] & 0xff);

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;

yuv420sp[yIndex++] = (byte) ((Y < 0) ? 0 : ((Y > 255) ? 255 : Y));
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));
}

index ++;
}
}
}
}

然后终于在你的回调中;

public void onPreviewFrame(byte[] data, Camera camera) {

byte[] bytes = data;

if (!mProvider.isVideoEnabled()) {
Camera.Size previewSize = camera.getParameters().getPreviewSize();
bytes = mProvider.getPreviewFrameData(previewSize.width, previewSize.height);
}

ProvideCameraFrame(bytes, bytes.length, context);
}

关键是将图像缩放到相机预览大小并将图像转换为 YUV 色彩空间。

关于android - 如何用静态 YUV 帧覆盖 onPreviewFrame 数据?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22713664/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com