shengjunhu / android_camera_v4l2

🔥 V4L2 Camera on Android.
44 stars 14 forks source link

可否增加拍照回调 #7

Closed GTX-GSO closed 1 year ago

shengjunhu commented 1 year ago

No description provided.

目前代码在加功能中,包括拍照回调,加完会一起推上来的

GTX-GSO commented 1 year ago

No description provided.

目前代码在加功能中,包括拍照回调,加完会一起推上来的 感谢!我在java层通过截取视频帧回调I422 -> I420 -> NV21 ->YuvImage ->jpeg 的方式实现了抓拍功能 另外提一个小小的建议,我在测试中发现大多数联发科设备不支持mjpeg格式硬解码,采用libjpeg-turbo进行软解码在1080P下产生了不小的性能开销(56ms),如果跟ARGB转码与绘制surface在同一线程执行(13ms),会阻塞UVC摄像头的回调帧率,我进行了一点修改,通过将YUV422数据写入队列,另起循环线程进行转码绘制任务的方式实现,另增加一个JNI接口,在surface Destory时调用通知该线程停止转码绘制工作以实现息屏录制,不过C++水平实在有限,不好意思把代码提上来

GTX-GSO commented 1 year ago

看到代码中有部分关于v4l2相机帧率的设置,遗憾的是在手头的两个uvc设备上进行测试,实际都没有生效

shengjunhu commented 1 year ago

No description provided.

目前代码在加功能中,包括拍照回调,加完会一起推上来的 感谢!我在java层通过截取视频帧回调I422 -> I420 -> NV21 ->YuvImage ->jpeg 的方式实现了抓拍功能 另外提一个小小的建议,我在测试中发现大多数联发科设备不支持mjpeg格式硬解码,采用libjpeg-turbo进行软解码在1080P下产生了不小的性能开销(56ms),如果跟ARGB转码与绘制surface在同一线程执行(13ms),会阻塞UVC摄像头的回调帧率,我进行了一点修改,通过将YUV422数据写入队列,另起循环线程进行转码绘制任务的方式实现,另增加一个JNI接口,在surface Destory时调用通知该线程停止转码绘制工作以实现息屏录制,不过C++水平实在有限,不好意思把代码提上来

刚注意到你的回复,公司网络禁用了,github访问不了。 现在大部分Android系都移除了MJPEG硬解码,我这边在rk3399、msm8953、mtk8788平台上mjpeg转yuv使用libjpeg-turbo解码1080p都在18-25ms之间,你那边是mtk什么型号?关于你表示:“如果跟ARGB转码与绘制surface在同一线程执行”,我没明白,是一种解码方式吗?如果不是那可能是,我觉得可能是surface渲染线程优先级高一些的原因。

shengjunhu commented 1 year ago

看到代码中有部分关于v4l2相机帧率的设置,遗憾的是在手头的两个uvc设备上进行测试,实际都没有生效

虽然是帧率设置,其实也是从v4l2的协议中获取到支持的分辨率和帧率,然后再设置支持分辨率和帧率的中的一个,是不可以修改分辨率帧率.。如果说读取出来的帧率,不修改再设置回去不生效,那很可能是sensor驱动不匹配。我之前发现有些小众摄像头,支持很多分辨率帧率,部分帧率到达几百fps,但是在好几个平台上用成熟的工具测试都是不生效的。但有一部分是生效的,我觉得可能是sensor厂商部分固件不支持的分辨率和帧率没删除,导致驱动依然可以读取到这部分参数信息。

GTX-GSO commented 1 year ago

看到代码中有部分关于v4l2相机帧率的设置,遗憾的是在手头的两个uvc设备上进行测试,实际都没有生效

虽然是帧率设置,其实也是从v4l2的协议中获取到支持的分辨率和帧率,然后再设置支持分辨率和帧率的中的一个,是不可以修改分辨率帧率.。如果说读取出来的帧率,不修改再设置回去不生效,那很可能是sensor驱动不匹配。我之前发现有些小众摄像头,支持很多分辨率帧率,部分帧率到达几百fps,但是在好几个平台上用成熟的工具测试都是不生效的。但有一部分是生效的,我觉得可能是sensor厂商部分固件不支持的分辨率和帧率没删除,导致驱动依然可以读取到这部分参数信息。

主要是在MT6762V/CB这类低端芯片上比较耗时,MT6833V/ZA、SDM450都没有这么差的cpu解码速度。 关于影响帧率主要是在loopFrame方法中的renderFrame(data)是调用libyuv把解压出来的I422再次转码成RGBA用来渲染到surface,这一步跟mjpeg解码在同一个线程,所以他的耗时会影响到整个到oopThread循环速度,导致实际帧率低于设备硬件支持的帧率。 uint8_t *data = camera->decoder->convert2YUV(camera->buffers[buffer.index].start, buffer.bytesused); //LOGD(TAG, "Mjpeg->I422 Time=%lld", timeMs() - time1); //Data->Java sendFrame(env, data); //Render->RGBA //这里走子线程进行渲染 addDataToList(data, pixelBytes); //12ms //renderFrame(data);

shengjunhu commented 1 year ago

看到代码中有部分关于v4l2相机帧率的设置,遗憾的是在手头的两个uvc设备上进行测试,实际都没有生效

虽然是帧率设置,其实也是从v4l2的协议中获取到支持的分辨率和帧率,然后再设置支持分辨率和帧率的中的一个,是不可以修改分辨率帧率.。如果说读取出来的帧率,不修改再设置回去不生效,那很可能是sensor驱动不匹配。我之前发现有些小众摄像头,支持很多分辨率帧率,部分帧率到达几百fps,但是在好几个平台上用成熟的工具测试都是不生效的。但有一部分是生效的,我觉得可能是sensor厂商部分固件不支持的分辨率和帧率没删除,导致驱动依然可以读取到这部分参数信息。

主要是在MT6762V/CB这类低端芯片上比较耗时,MT6833V/ZA、SDM450都没有这么差的cpu解码速度。 关于影响帧率主要是在loopFrame方法中的renderFrame(data)是调用libyuv把解压出来的I422再次转码成RGBA用来渲染到surface,这一步跟mjpeg解码在同一个线程,所以他的耗时会影响到整个到oopThread循环速度,导致实际帧率低于设备硬件支持的帧率。 uint8_t *data = camera->decoder->convert2YUV(camera->buffers[buffer.index].start, buffer.bytesused); //LOGD(TAG, "Mjpeg->I422 Time=%lld", timeMs() - time1); //Data->Java sendFrame(env, data); //Render->RGBA //这里走子线程进行渲染 addDataToList(data, pixelBytes); //12ms //renderFrame(data);

我个人也是推荐使用帧池这样的方案的,但是还是得有牺牲的地方; 这种方式回调帧率可以达到,但是渲染会有延时甚至丢帧。