Tec*_*et9 7 java android android-bitmap android-5.0-lollipop nexus6
我正在开发一个需要捕获屏幕到位图进行传输的应用程序.我正在尝试使用新的Android 5.0 android.media.projection API来进行屏幕捕获.
此API的工作流程最终会调用
mediaProjection.createVirtualDisplay("Test Screen", WIDTH, HEIGHT, DPI,
DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR, surface, null, null);
Run Code Online (Sandbox Code Playgroud)
在我最初尝试捕获时,我从SurfaceView中获取了表面对象.这工作正常; 最终结果是在屏幕上绘制的显示器的微小副本(导致Droste效果)
我认为这个功能几近完成,但我发现 SurfaceViews(从代码的角度来看)是不可读的; 你不能从他们那里得到一个位图.
在寻找其他解决方案时,我遇到了这个与我的目标非常相似的问题,并且在该线程中建议使用ImageReader而不是SurfaceView来获取传递给createVirtualDisplay API调用的Surface.
但是,当我更改我的代码以使用ImageReader代替SurfaceView时,我得到运行时logcat错误(没有异常),并且永远不会调用ImageReader的回调函数.createVirtualDisplay调用还返回一个看似有效的VirtualDisplay对象.
这是logcat:
9230-9270/com.android.techrocket9.nanoid E/BufferQueueProducer? [unnamed-9230-0] dequeueBuffer: createGraphicBuffer failed
9230-9246/com.android.techrocket9.nanoid E/BufferQueueProducer? [unnamed-9230-0] dequeueBuffer: can't dequeue multiple buffers without setting the buffer count
9230-9246/com.android.techrocket9.nanoid E/BufferQueueProducer? [unnamed-9230-0] dequeueBuffer: can't dequeue multiple buffers without setting the buffer count
9230-9246/com.android.techrocket9.nanoid E/BufferQueueProducer? [unnamed-9230-0] dequeueBuffer: can't dequeue multiple buffers without setting the buffer count
9230-9246/com.android.techrocket9.nanoid E/BufferQueueProducer? [unnamed-9230-0] dequeueBuffer: can't dequeue multiple buffers without setting the buffer count
Run Code Online (Sandbox Code Playgroud)
第二行在它停止发生之前重复约100次.
单步执行调试器,我看到第一个错误发生在createVirtualDisplay调用期间,所有其他错误在执行返回系统代码后发生.
该唯一有意义的结果,这个错误涉及奇巧的问题,在这里我想消耗API不存在.尽管如此,我尝试了这里建议的修复(放入android:hardwareAccelerated="false"
清单).这并没有改变应用程序的行为.
如何"设置缓冲区计数"或以其他方式解决此错误并将屏幕作为位图?
PS我的开发平台是Nexus 6.
完整的代码块,根据要求:
MediaProjection mediaProjection = mgr.getMediaProjection(resultCode, data);
ImageReader ir = ImageReader.newInstance(WIDTH, HEIGHT, ImageFormat.JPEG, 5);
VirtualDisplay v = mediaProjection.createVirtualDisplay("Test Screen", WIDTH, HEIGHT, getApplicationContext().getResources().getDisplayMetrics().densityDpi, DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR, ir.getSurface(), null, null);
Run Code Online (Sandbox Code Playgroud)
编辑:关于工件问题,这里是我用来从图像中获取位图并显示它的代码:
public void onImageAvailable(ImageReader reader) {
Image image = null;
ByteArrayOutputStream bos = null;
try {
image = reader.acquireLatestImage();
if (null == image){
return;
}
bos = new ByteArrayOutputStream();
final Image.Plane[] planes = image.getPlanes();
final ByteBuffer buffer = (ByteBuffer) planes[0].getBuffer().rewind();
final Bitmap bitmap = Bitmap.createBitmap(image.getWidth(), image.getHeight(), Bitmap.Config.ARGB_8888);
bitmap.copyPixelsFromBuffer(buffer);
//bitmap.compress(Bitmap.CompressFormat.WEBP, 50, bos);
runOnUiThread(new Runnable() {
public void run() {
iv.setImageBitmap(bitmap);
}
});
Run Code Online (Sandbox Code Playgroud)
我想我现在可以回答这个问题,我遇到了同样的问题后,我改变ImageFormat.JPEG
对PixelFormat.RGBA_8888
一切顺利.似乎不支持ImageFormat.JPEG.
您需要使用以下代码来获取正确的位图:
int width = img.getWidth();
int height = img.getHeight();
int pixelStride = planes[0].getPixelStride();
int rowStride = planes[0].getRowStride();
int rowPadding = rowStride - pixelStride * width;
byte[] newData = new byte[width * height * 4];
int offset = 0;
bitmap = Bitmap.createBitmap(metrics,width, height, Bitmap.Config.ARGB_8888);
ByteBuffer buffer = planes[0].getBuffer();
for (int i = 0; i < height; ++i) {
for (int j = 0; j < width; ++j) {
int pixel = 0;
pixel |= (buffer.get(offset) & 0xff) << 16; // R
pixel |= (buffer.get(offset + 1) & 0xff) << 8; // G
pixel |= (buffer.get(offset + 2) & 0xff); // B
pixel |= (buffer.get(offset + 3) & 0xff) << 24; // A
bitmap.setPixel(j, i, pixel);
offset += pixelStride;
}
offset += rowPadding;
}
Run Code Online (Sandbox Code Playgroud)
通过这种方式,位图的内容就是你想要的.
PS:我真的想说,android的doc很糟糕.我们需要调查太多细节才能正确使用sdk api.
归档时间: |
|
查看次数: |
3679 次 |
最近记录: |