有时候打开opengles的trace工具,录制opengles的调用的时候,无法复现问题。为了debug的确认video的输入source是否有问题,需要dump GraphicBuffer中的内容,读取出来保存成yuv的数据,但是这个仅限于format是YCrCb的格式,其他的RGBA的这种,需要调用另外的接口。
以TextureView中DeferredLayerUpdater为例,总结了这部分的内容如下:
- 获取到GraphicBuffer的指针,并保证指针有效的前提下,调用:
AHardwareBuffer* hardwareBuffer = ASurfaceTexture_dequeueBuffer( mSurfaceTexture.get(), &slot, &dataspace, transformMatrix, &newContent, createReleaseFence, fenceWait, &mRenderState); GraphicBuffer* old_buffer = GraphicBuffer::fromAHardwareBuffer(hardwareBuffer); dumpImage(old_buffer);
- dumpImage的接口实现了对GraphicBuffer的yuv数据的读操作:
int dumpImage(sp<GraphicBuffer> buffer) { ALOGE("dump image begin"); getDumpPath(dumpPath); if (buffer != NULL) { Rect bounds(buffer->getWidth(), buffer->getHeight()); void* vaddr; int32_t pixel_format = buffer->getPixelFormat(); if (pixel_format == HAL_PIXEL_FORMAT_YCbCr_420_SP || pixel_format == HAL_PIXEL_FORMAT_YCbCr_420_P || pixel_format == HAL_PIXEL_FORMAT_YV12 || pixel_format == HAL_PIXEL_FORMAT_YCbCr_422_SP) { android_ycbcr ycbcr = android_ycbcr(); //构造android_ycbcr的变量 buffer->lockYCbCr(GRALLOC_USAGE_SW_READ_OFTEN, &ycbcr); dump_yuv(buffer->getStride(), buffer->getHeight(), ycbcr.y, ycbcr.cb, ycbcr.cr, pixel_format, buffer_index);//这边设置stride的分量作为width,是因为GraphicBuffer的内部存储有对齐的操作,有时候调用getWidth获取到数据跟stride的值不同,会导致读取到的图片有问题,带斜纹,所以用stride. buffer->unlock(); } buffer_index++; return 0; } static void dump_yuv(unsigned int width, unsigned int height, const void *yBuf, const void *uBuf, const void *vBuf, int32_t pixel_format, int index) { char buf[256] = {'\0'}; FILE* file_fd = fopen(buf, "wb"); snprintf(buf, sizeof(buf), "/data/dump/%dx%dvideo%d.yuv",width,height,index); file_fd = fopen(buf, "wb"); if (file_fd != NULL) { const void *ydata = yBuf; const void *udata = uBuf; const void *vdata = vBuf; int written_len = 0; written_len += fwrite(ydata, width*height, 1, file_fd); //这部分保存y分量的数据 //下面的操作是根据format的不同,保存uv的分量 if(NULL == uBuf || NULL == vBuf) { ALOGE("%s: dump------- fail %s, uBuf = %p, vBuf = %p",__func__, buf, uBuf, vBuf); return; } unsigned int uvlen; switch (pixel_format) { case HAL_PIXEL_FORMAT_YCbCr_420_SP: uvlen = width * height/4; for (unsigned int i=0; i<uvlen; i++) { written_len += fwrite(udata, 1, 1, file_fd); written_len += fwrite(vdata, 1, 1, file_fd); } break; case HAL_PIXEL_FORMAT_YCbCr_422_SP: uvlen = width * height/2; for (unsigned int i=0; i<uvlen; i++) { written_len += fwrite(udata, 1, 1, file_fd); written_len += fwrite(vdata, 1, 1, file_fd); } break; case HAL_PIXEL_FORMAT_YCbCr_420_P: uvlen = width * height/4; written_len += fwrite(udata, 1, uvlen, file_fd); written_len += fwrite(vdata, 1, uvlen, file_fd); break; case HAL_PIXEL_FORMAT_YV12: uvlen = width * height/4; written_len += fwrite(vdata, 1, uvlen, file_fd); written_len += fwrite(udata, 1, uvlen, file_fd); break; default: ALOGE("%s: dump-------failed %s, because format %d is not support.",__func__, buf, pixel_format); break; } ALOGE("%s: dump-------sucess %s",__func__, buf); fclose(file_fd); index++; } else { ALOGE("%s: fail t open file for image dumping", __func__); } }
在手机上/data/dump的目录下,就保存了yuv的数据。
这个debug手段,只能说明输入的source是否有问题。
如果真是openglES的绘制问题,那就难定位问题,那就需要各显神通了。