Android GraphicBuffer的dump保存成yuv文件

有时候打开opengles的trace工具,录制opengles的调用的时候,无法复现问题。为了debug的确认video的输入source是否有问题,需要dump GraphicBuffer中的内容,读取出来保存成yuv的数据,但是这个仅限于format是YCrCb的格式,其他的RGBA的这种,需要调用另外的接口。
以TextureView中DeferredLayerUpdater为例,总结了这部分的内容如下:

  1. 获取到GraphicBuffer的指针,并保证指针有效的前提下,调用:
     AHardwareBuffer* hardwareBuffer = ASurfaceTexture_dequeueBuffer(
                        mSurfaceTexture.get(), &slot, &dataspace, transformMatrix, &newContent,
                        createReleaseFence, fenceWait, &mRenderState);
     GraphicBuffer* old_buffer = GraphicBuffer::fromAHardwareBuffer(hardwareBuffer);
     dumpImage(old_buffer);
    
  2. 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的绘制问题,那就难定位问题,那就需要各显神通了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值