Camera2 API拍照失敗問題實錄:從錯誤碼到格式轉換的排坑之旅

一、問題背景

在開發基于Camera2 API的相機應用時,我們遇到了一個棘手的問題:預覽功能在所有設備上工作正常,但在某特定安卓設備上點擊拍照按鈕后無任何響應。值得注意的是,使用舊版Camera API時該設備可以正常拍照。本文記錄了完整的排查過程和解決方案。

二、問題現象與初步分析

2.1 異常現象特征

  • 設備特定性:僅在某一品牌設備出現(其他手機/平板正常)
  • 錯誤靜默:無崩潰日志,但捕獲失敗回調觸發
  • 兼容性矛盾:舊版Camera API工作正常

2.2 初始日志定位

    // 提交拍照請求captureSession?.apply {stopRepeating()abortCaptures()capture(captureRequest.build(), object : CameraCaptureSession.CaptureCallback() {override fun onCaptureCompleted(session: CameraCaptureSession,request: CaptureRequest,result: TotalCaptureResult) {super.onCaptureCompleted(session, request, result)Log.e(TAG, "onCaptureCompleted!!!!")// 恢復預覽}override fun onCaptureFailed(session: CameraCaptureSession,request: CaptureRequest,failure: CaptureFailure) {super.onCaptureFailed(session, request, failure)Log.e(TAG, "Capture failed with reason: ${failure.reason}")Log.e(TAG, "Failed frame number: ${failure.frameNumber}")Log.e(TAG, "Failure is sequence aborted: ${failure.sequenceId}")}}, null)} ?: Log.e(TAG, "Capture session is null")
} catch (e: CameraAccessException) {Log.e(TAG, "Camera access error: ${e.message}")
} catch (e: IllegalStateException) {Log.e(TAG, "Invalid session state: ${e.message}")
} catch (e: Exception) {Log.e(TAG, "Unexpected error: ${e.message}")
}

在onCaptureFailed回調中發現關鍵日志:

Capture failed with reason: 1 // ERROR_CAMERA_DEVICE

三、深度排查過程

3.1 對焦模式兼容性驗證

通過CameraCharacteristics查詢設備支持的自動對焦模式:

// 在初始化相機時檢查支持的 AF 模式
val characteristics = cameraManager.getCameraCharacteristics(cameraId)
val afModes = characteristics.get(CameraCharacteristics.CONTROL_AF_AVAILABLE_MODES) ?: emptyArray()// 選擇優先模式
val afMode = when {afModes.contains(CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE) -> CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTUREafModes.contains(CaptureRequest.CONTROL_AF_MODE_AUTO) -> CaptureRequest.CONTROL_AF_MODE_AUTOelse -> CaptureRequest.CONTROL_AF_MODE_OFF
}// 在拍照請求中設置
captureRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, afMode)

調整代碼邏輯后錯誤碼變為:

Capture failed with reason: 0 // ERROR_CAMERA_REQUEST
Failed frame number: 1949

3.2 HAL層日志分析

通過ADB獲取底層日志:

adb shell setprop persist.camera.hal.debug 3
adb shell logcat -b all -c
adb logcat -v threadtime > camera_log.txt

上述命令運行后,即可操作拍照,然后中斷上述命令,調查camera_log.txt中對應時間點的日志。
找到關鍵錯誤信息

 V4L2 format conversion failed (res -1)
Pixel format conflict: BLOB(JPEG) & YV12 mixed
SW conversion not supported from current sensor format

3.3 輸出格式兼容性驗證

通過StreamConfigurationMap查詢設備支持格式:

val characteristics = cameraManager.getCameraCharacteristics(cameraId)
val configMap = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP)
val supportedFormats = configMap?.outputFormats?.toList() ?: emptyList()Log.d(TAG, "Supported formats: ${supportedFormats.joinToString()}")// 檢查是否支持 NV21
if (!supportedFormats.contains(ImageFormat.NV21)) {Log.e(TAG, "NV21 is NOT supported on this device")
}

// 輸出結果為 [256, 34, 35]
我使用python來做個轉換,很舒適:

>>> hex(34)
'0x22'
>>> hex(35)
'0x23'
>>> hex(256)
'0x100'
>>>

格式解碼對照表(請查ImageFormat.java源文件):

十進制十六進制Android格式
2560x100ImageFormat.PRIVATE
340x22ImageFormat.YV12
350x23ImageFormat.YUV_420_888

四、核心問題定位

4.1 格式轉換失敗原因

  1. 硬件限制:設備不支持YU12格式的軟件轉換
  2. 格式沖突:JPEG(BLOB)與YV12格式混合使用導致HAL層異常

4.2 YUV格式轉換關鍵點

YUV_420_888與NV21格式對比:
冷知識:NV21是Camera API默認的格式;YUV_420_888是Camera2 API默認的格式。而且不能直接將 YUV 原始數據保存為 JPG,必須經過格式轉換。

特征YUV_420_888NV21
平面排列半平面+全平面半平面
內存布局Y + U + V平面Y + VU交錯
色度采樣4:2:04:2:0
Android支持API 21+API 1+

五、解決方案實現

5.1 格式轉換核心代碼

  //  將 YUV_420_888 轉換為 NV21 格式的字節數組private fun convertYUV420ToNV21(image: Image): ByteArray {val planes = image.planesval yBuffer = planes[0].bufferval uBuffer = planes[1].bufferval vBuffer = planes[2].bufferval ySize = yBuffer.remaining()val uSize = uBuffer.remaining()val vSize = vBuffer.remaining()val nv21 = ByteArray(ySize + uSize + vSize)yBuffer.get(nv21, 0, ySize)vBuffer.get(nv21, ySize, vSize)uBuffer.get(nv21, ySize + vSize, uSize)return nv21}/* 將 YUV_420_888 轉換為 JPEG 字節數組 */private fun convertYUVtoJPEG(image: Image): ByteArray {val nv21Data = convertYUV420ToNV21(image)  val yuvImage = YuvImage(nv21Data,ImageFormat.NV21,image.width,image.height,null)// 將 JPEG 數據寫入 ByteArrayOutputStreamval outputStream = ByteArrayOutputStream()yuvImage.compressToJpeg(Rect(0, 0, image.width, image.height),90,outputStream)return outputStream.toByteArray()}

5.2 保存系統相冊示例:

   /* 保存到系統相冊 */private fun saveToGallery(jpegBytes: ByteArray) {val contentValues = ContentValues().apply {put(MediaStore.Images.Media.DISPLAY_NAME, "IMG_${System.currentTimeMillis()}.jpg")put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg")if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {put(MediaStore.Images.Media.RELATIVE_PATH, Environment.DIRECTORY_PICTURES)put(MediaStore.Images.Media.IS_PENDING, 1)  // Android 10+ 需要}}try {// 插入媒體庫val uri = contentResolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,contentValues) ?: throw IOException("Failed to create media store entry")contentResolver.openOutputStream(uri)?.use { os ->os.write(jpegBytes)os.flush()// 更新媒體庫(Android 10+ 需要)if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {contentValues.clear()contentValues.put(MediaStore.Images.Media.IS_PENDING, 0)contentResolver.update(uri, contentValues, null, null)}runOnUiThread {Toast.makeText(this, "保存成功", Toast.LENGTH_SHORT).show()// 觸發媒體掃描(針對舊版本)sendBroadcast(Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, uri))}}} catch (e: Exception) {Log.e(TAG, "保存失敗: ${e.message}")runOnUiThread {Toast.makeText(this, "保存失敗", Toast.LENGTH_SHORT).show()}}}

上述修改后,再次測試驗證,這次是可以拍照成功的,并且相冊中也會新增剛剛的照片。

六、最后的小經驗

排錯時別忘記:
設備兼容性檢查清單

  • 輸出格式支持性驗證
  • 對焦模式白名單檢查
  • 最大分辨率兼容測試
  • HAL層日志的輸出

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/74085.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/74085.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/74085.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Jmeter舊版本如何下載

1.Jmeter最新版本下載位置 https://jmeter.apache.org/download_jmeter.cgi2.Jmeter舊版本下載位置 https://archive.apache.org/dist/jmeter/binaries穩定版本:5.4.1

css-grid布局

文章目錄 1、布局2、網格軌道3、間距Gap4、網格線5、網格別名 當一個 HTML 元素將 display 屬性設置為 grid 或 inline-grid 后,它就變成了一個網格容器,這個元素的所有直系子元素將成為網格元素。 1、布局 啟用grid布局類似與flex布局,不過g…

SolidWorks使用顯卡教程

操作步驟: 打開注冊表編輯器 按下鍵盤上的 Win R 組合鍵,輸入 regedit 并按回車鍵,打開注冊表編輯器。 導航到顯卡信息路徑 在注冊表中依次展開以下路徑: plaintext HKEY_CURRENT_USER\Software\SolidWorks\SOLIDWORKS 2021\Per…

【C++11】左值引用、右值引用、移動語義和完美轉發

🦄個人主頁:修修修也 🎏所屬專欄:C ??操作環境:Visual Studio 2022 目錄 📌左值引用和右值引用 🎏左值和左值引用 🎏右值和右值引用 📌左值引用和右值引用比較 🎏左值引用 🎏右值…

麒麟系列Linux發行版探秘

以下內容摘自《銀河麒麟操作系統進階應用》一書。 銀河麒麟操作系統(Kylin) 銀河麒麟(Kylin)操作系統是中國自主研發的一款基于Linux內核的操作系統。它的發展歷程可以追溯到2002年,最初由國防科技大學主導研發&…

【機密計算頂會解讀】11:ACAI——使用 Arm 機密計算架構保護加速器執行

導讀:本文介紹ACAI,其構建一個基于CCA的解決方案,使得機密虛擬機能夠安全地使用加速器,同時保持與現有應用程序的兼容性和安全性,能夠實現對加速器的安全訪問。 原文鏈接:ACAI: Protecting Accelerator Ex…

第一天 UnityShader的結構

Shader初學者的學習筆記 第一天 Unity Shader的結構 文章目錄 Shader初學者的學習筆記前言一、Unity Shader結構二、Unity Shader結構解析① Properties② Tags③ RenderSetup(可選狀態)④ Name⑤ [Tags]⑥ [RenderSetup]⑦ 頂點著色器和片元著色器的代碼 (Unity最聰明的孩子)…

VL開源模型實現文本生成圖片

一、 基礎知識 根據描述生成圖片的視覺-語言模型(Vision-Language Models, VL 模型)是近年來多模態生成領域的熱點研究方向。這些模型能夠根據自然語言描述生成高質量的圖像,廣泛應用于藝術創作、設計輔助、虛擬場景構建等領域。 1 根據描述…

【Java SE】抽象類/方法、模板設計模式

目錄 1.抽象類/方法 1.1 基本介紹 1.2 語法格式 1.3 使用細節 2. 模板設計模式(抽象類使用場景) 2.1 基本介紹 2.2 具體例子 1.抽象類/方法 1.1 基本介紹 ① 當父類的某些方法,需要聲明,但是又不確定如何實現時&#xff…

【人工智能】LM Studio 的 GPU 加速:釋放大模型推理潛能的極致優化

《Python OpenCV從菜鳥到高手》帶你進入圖像處理與計算機視覺的大門! 解鎖Python編程的無限可能:《奇妙的Python》帶你漫游代碼世界 隨著大語言模型(LLM)的廣泛應用,其推理效率成為限制性能的關鍵瓶頸。LM Studio 作為一個輕量級機器學習框架,通過 GPU 加速顯著提升了大…

深度學習:從零開始的DeepSeek-R1-Distill有監督微調訓練實戰(SFT)

原文鏈接:從零開始的DeepSeek微調訓練實戰(SFT) 微調參考示例:由unsloth官方提供https://colab.research.google.com/github/unslothai/notebooks/blob/main/nb/Qwen2.5_(7B)-Alpaca.ipynbhttps://colab.research.google.com/git…

流暢如絲:利用requestAnimationFrame優化你的Web動畫體驗

requestAnimationFrame 是前端開發中用于優化動畫性能的 API。它允許瀏覽器在下一次重繪之前執行指定的回調函數,通常用于實現平滑的動畫效果。 1.作用 優化性能:requestAnimationFrame 會根據瀏覽器的刷新率(通常是 60Hz,即每秒…

【pytest框架源碼分析五】pytest插件的注冊流程

前文介紹到pytest整體是運用插件來實現其運行流程的。這里仔細介紹下具體過程。 首先進入main方法 def main(args: list[str] | os.PathLike[str] | None None,plugins: Sequence[str | _PluggyPlugin] | None None, ) -> int | ExitCode:"""Perform an i…

IoTDB日志提示Too many open files

問題 時序數據庫 IoTDB 1.3.3 版本 IoTDB 執行查詢操作失敗,日志打印提示 Too many open files。通過命令查看打開文件數,結果如下: [root0002 DataReceiver]# lsof|grep 28347|wc -l DataNode 55444 [root0002 DataReceiver]# lsof|g…

prometheus 添加alertmanager添加dingtalk機器人告警

1、dingtalk創建機器人,目前我們采用加白名單的方式校驗 2、定位到如下圖 test結果如下

C 語 言 --- 操 作 符 2

C 語 言 --- 操 作 符 2 移 位 操 作 符定 義原 碼 補 碼 和 反 碼左 移&#xff08;<<&#xff09;右 移&#xff08;>>&#xff09;算 術 右 移邏 輯 右 移 按 位 與、按 位 或、和 按 位 異 或按 位 與按 位 或按 位 異 或 邏 輯 反 操 作負 值 操 作按 位 取 反…

基于Spring Boot的公司資產網站的設計與實現(LW+源碼+講解)

專注于大學生項目實戰開發,講解,畢業答疑輔導&#xff0c;歡迎高校老師/同行前輩交流合作?。 技術范圍&#xff1a;SpringBoot、Vue、SSM、HLMT、小程序、Jsp、PHP、Nodejs、Python、爬蟲、數據可視化、安卓app、大數據、物聯網、機器學習等設計與開發。 主要內容&#xff1a;…

零碳工廠能源管理系統的核心技術與應用實踐

零碳工廠能源管理系統是一種高效的解決方案&#xff0c;旨在優化能源使用并減少碳排放&#xff0c;以幫助工廠實現低碳或零碳的生產目標。以下是該系統的詳細構成和功能&#xff1a; 1. 核心組件 傳感器和監測設備&#xff1a;用于實時監測工廠內的能源使用情況&#xff0c;包…

美攝接入DeepSeek等大模型,用多模態融合重構視頻創作新邊界!

今年以來&#xff0c;DeepSeek憑借其強大的深度推理分析能力&#xff0c;在AI領域掀起新的熱潮。美攝科技快速響應市場需求&#xff0c;迅速接入以DeepSeek、通義千問、商湯、文心一言為代表的大模型&#xff0c;為企業視頻創作生產帶來全新體驗。 傳統視頻創作面臨著同質化、…

JAVA————十五萬字匯總

JAVA語言概述 JAVA語句結構 JAVA面向對象程序設計&#xff08;一&#xff09; JAVA面向對象程序設計&#xff08;二&#xff09; JAVA面向對象程序設計&#xff08;三&#xff09;工具類的實現 JAVA面向對象程序設計&#xff08;四&#xff09;錄入異常處理 JAVA圖形用戶界面設…