在智能穿戴設備日益普及的今天,AR眼鏡已經不再是科幻作品中的概念,而是可以真正融入我們日常生活的工具。本文將分享一個基於 Rokid CXR-S SDK 的純眼鏡端實戰項目——生活小記Glass拍照錄像應用(Glass記小圈應用)。通過這一實戰項目,我將帶你從零構建一個能夠拍照、錄像、錄音並進行基本媒體管理的眼鏡端應用,並分享開發過程中遇到的技術細節與優化經驗。
一、項目背景與目標
在日常生活中,我們經常希望隨手記錄瞬間,但拿出手機拍照或錄像有時不夠便利。AR眼鏡的優勢在於 免手持、即時記錄。
Glass記小圈應用目標:
- 通過眼鏡單機操作或AI場景,實現拍照、錄像、錄音功能。
- 支持拍照與錄像參數自定義,如分辨率、畫質、時長等。
- 提供回調機制,方便獲取拍照圖片或錄像路徑,實現後續數據同步或處理。
- 純眼鏡端實現,無需依賴移動端應用。
信息交互模型如下。
二、開發環境與依賴
- 開發語言:Kotlin
- SDK版本:CXR-S SDK 1.0.1
- IDE:Android Studio Arctic Fox 或以上
- 權限:相機、麥克風、存儲
在 AndroidManifest.xml 中,需要聲明以下權限:
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
運行時需動態申請權限,以保證拍照、錄像和錄音功能正常。
三、拍照功能實現
CXR-M SDK 是一款移動端開發工具包,專為構建 Rokid 眼鏡的配套應用和控制應用而設計。它支持手機與眼鏡之間的穩定連接、數據通信、實時音視頻訪問以及場景自定義。非常適合需要基於手機的用户界面、遠程控制或與眼鏡進行高級協作的應用。目前適用於 Android 系統。
3.1 單機功能鍵拍照
通過 SDK 提供的接口 setPhotoParams(width: Int, height: Int),可以設置單機按鍵拍照的分辨率:
val status = CxrApi.getInstance().setPhotoParams(1920, 1080)
when (status) {
ValueUtil.CxrStatus.REQUEST_SUCCEED -> Log.d(TAG, "單機拍照參數設置成功")
else -> Log.e(TAG, "設置失敗: $status")
}
用户按下眼鏡功能鍵即可拍照,拍照結果存儲在未同步媒體文件中。
3.2 AI場景拍照
在AI場景中,可以直接控制相機並獲取圖片數據:
private val photoCallback = object : PhotoResultCallback {
override fun onPhotoResult(status: ValueUtil.CxrStatus?, photo: ByteArray?) {
if (status == ValueUtil.CxrStatus.RESPONSE_SUCCEED && photo != null) {
// 將WebP圖片保存或處理
savePhoto(photo, "ai_scene_photo.webp")
}
}
}
fun takeAiScenePhoto() {
CxrApi.getInstance().openGlassCamera(1280, 720, 80)
CxrApi.getInstance().takeGlassPhoto(1280, 720, 80, photoCallback)
}
Tips:AI場景拍照通過藍牙傳輸圖片,建議選擇 較小分辨率和適中壓縮質量。
3.3 獲取拍照路徑
如果需要獲取圖片的文件路徑,可以使用 takeGlassPhoto(width, height, quality, PhotoPathCallback):
private val photoPathCallback = object : PhotoPathCallback {
override fun onPhotoPath(status: ValueUtil.CxrStatus?, path: String?) {
if (status == ValueUtil.CxrStatus.RESPONSE_SUCCEED && path != null) {
Log.d(TAG, "拍照文件路徑: $path")
}
}
}
fun takePhotoWithPath() {
CxrApi.getInstance().takeGlassPhoto(1280, 720, 90, photoPathCallback)
}
四、錄像功能實現
4.1 錄像參數設置
通過 setVideoParams(duration, fps, width, height, unit) 可以自定義錄像參數:
CxrApi.getInstance().setVideoParams(
duration = 60, fps = 30,
width = 1280, height = 720,
unit = 1 // 1=秒
)
4.2 開啓與關閉錄像場景
錄像通過控制場景實現:
fun startVideoRecord() {
CxrApi.getInstance().controlScene(ValueUtil.CxrSceneType.VIDEO_RECORD, true, null)
}
fun stopVideoRecord() {
CxrApi.getInstance().controlScene(ValueUtil.CxrSceneType.VIDEO_RECORD, false, null)
}
用户可以通過手勢或按鍵快速開啓/關閉錄像,實現便捷記錄。
五、錄音功能實現
錄音可以結合AI應用場景實現,SDK提供回調監聽音頻流:
private val audioListener = object : AudioStreamListener {
override fun onStartAudioStream(codecType: Int, streamType: String?) {
Log.d(TAG, "音頻流開始,codec=$codecType")
}
override fun onAudioStream(data: ByteArray?, offset: Int, length: Int) {
// 處理PCM或Opus音頻數據
}
}
fun startAudioRecord() {
CxrApi.getInstance().setAudioStreamListener(audioListener)
CxrApi.getInstance().openAudioRecord(codecType = 1, streamType = "DailyNote")
}
fun stopAudioRecord() {
CxrApi.getInstance().closeAudioRecord("DailyNote")
}
六、服務端處理與場景落地應用
雖然 Glass記小圈 應用實現了完整的拍照、錄像、錄音等能力,且可在眼鏡端本地完成所有操作,但在真實生活場景中,如果僅依賴眼鏡本地存儲會出現諸多限制:
如存儲空間有限、文件難以整理、無法跨設備查看、AI 分析難以在本地運行等。
因此服務端的作用絕不僅僅是“接收與後處理”,而是構建一個完整的生活記錄系統的關鍵基礎。
為了便於理解,我們從“真實使用場景”出發,拆解服務端的作用。
6.1 場景:生活記錄歸檔(Life Log場景)
在 Glass 記小圈 應用的使用場景中,最核心、最貼近用户日常的是“生活記錄歸檔”。AR 眼鏡的優勢在於解放雙手、隨時可用,使其非常適合承擔低干擾、不打斷當下體驗的實時記錄任務。因此,Life Log 的設計不僅僅是簡單的拍照與錄像,而是圍繞“如何讓用户毫無感知地記錄生活點滴,並在之後自動歸類、整理、備份”這一目標構建的完整交互鏈路。
①即時記錄:無感操作的核心體驗
在真實的生活場景中,例如散步、騎行、與朋友聊天、做手工、下廚時,用户往往沒有額外的手去操作設備。眼鏡端的操作設計因此強調“輕觸即用”——短按拍照、長按錄像、語音觸發錄音,整個操作無需用户停下手中的動作,也不會改變當下沉浸體驗。
在這一模式下,眼鏡端利用 CXR-S SDK 對相機和音頻模塊進行輕量化調用,確保操作延遲極低。例如拍照調用通常在 150–300ms 內完成拍攝與寫入,用户幾乎無感延時;錄音與錄像在觸發後會立即返回場景啓動狀態,確保不會錯過關鍵畫面。
即時記錄的核心,是讓設備成為用户身體的延伸,而不是額外的負擔。
②本地歸檔:結構化存儲與未同步機制
為了保證數據安全性和高可靠性,眼鏡端採用“本地優先”的存儲策略:
- 每一張照片、視頻、錄音,都先寫入本地的未同步目錄(/media/unsync)
- 並生成組件化的元數據(時間戳、類型、大小、參數、觸發方式)
- 在 UI 側實時更新歷史記錄列表,讓用户能夠隨時回看
這樣的機制允許在無網絡、弱網絡或用户尚未登錄雲端服務的場景下,依然能保持完整的記錄。
為了避免存儲膨脹,系統還實現了輕量化資源回收策略,例如: - 對於超長視頻自動按 10 分鐘切片
- 自動壓縮 AI 場景下的 WebP 圖片
- 本地媒體達到閾值時觸發提示與自動清理候選列表
本地歸檔系統在極端情況下也能保證記錄不丟,從而構建 Life Log 的基礎可靠性。
6.2 場景:AI 輔助生活的小助手(未來擴展場景)
在 Glass 記小圈 的整體架構中,服務端不僅承擔媒體存儲與同步的角色,更是未來智能能力的核心承載者。隨着用户逐漸形成連續的拍照、錄像、錄音習慣,系統會積累大量生活切片,而真正的價值在於如何將這些碎片加工為“可理解、可索引、可回顧”的記憶資產。這正是 AI 生活助手的作用所在。
AI 智能總結:把一天的碎片拼成“生活日記”
用户的一天通常由散落的照片、零星的視頻和短暫的錄音組成。單獨看這些媒體,它們只是孤立的文件;但經過 AI 處理後,它們可以被組織成一篇有結構、有內容、有主題的自動化日記。
這一過程涉及多個服務端能力協同工作:
(1)圖像理解與場景識別
服務端模型會對每張圖片進行:
- 場景類別識別(如“公園”“廚房”“辦公室”)
- 物體檢測(如“貓”“植物”“餐盤”)
- OCR 提取文字(如菜單、路牌、白板內容)
這些語義將作為後續日記生成的“素材語料”。
(2)視頻摘要處理
視頻比圖片包含更豐富但更分散的信息,因此需要:關鍵幀提取、場景變化檢測、物體持續性跟蹤、簡短文本摘要(如“製作食物過程片段”“散步中的街景”)。服務端可根據時長自動壓縮信息量,使其更適合寫入生活日記。
(3)音頻轉寫與內容提取
對於會議、對話、分享記錄等音頻片段,服務端可執行:ASR 語音轉文字、説話人區分、關鍵句抽取,情緒識別(如激動、開心、平靜)。這讓日記不僅記錄“做了什麼”,也記錄“説了什麼”。
(4)AI 生成式總結:構建結構化生活小記
當一天的媒體數據被整合後,AI 日記生成器會根據時間線、地理位置(如用户開啓定位)、場景標籤與內容文字生成一段結構化敍述。例如:
下午 2 點,你在植物園拍攝了 7 張照片,AI 識別到三類植物:向日葵、薰衣草與蘆薈。
稍後你錄製了一段 18 秒的視頻,內容是你在園區小徑散步。
當天總計拍攝 3 分鐘視頻、記錄 2 段語音、10 張照片,整體主題偏向“自然與户外活動”。
這樣的“生活小記”不再是一堆文件,而是一個可閲讀、可分享、可檢索的記憶摘要。
6.3服務層處理邏輯
在 Glass記小圈應用中,雖然所有功能均可在眼鏡端完成,但為了實現數據集中管理、雲端同步、備份以及後續 AI 分析,我們需要搭建一個服務端系統,用於接收、存儲和管理多媒體文件。服務端主要職責包括:
- 文件接收與存儲:通過 HTTP 或 WebSocket 接收眼鏡端上傳的照片、視頻、音頻文件,並存儲到服務器指定路徑。
- 文件元數據管理:記錄文件名稱、路徑、拍攝時間、類型等信息,方便後續檢索和展示。
- 異常處理與重試機制:處理傳輸中斷、文件損壞、重複上傳等問題。
- 接口設計:提供 RESTful API 供眼鏡端上傳和獲取數據。
package com.glassserver.controller
import com.glassserver.model.MediaFile
import com.glassserver.service.MediaService
import org.springframework.http.ResponseEntity
import org.springframework.web.bind.annotation.*
import org.springframework.web.multipart.MultipartFile
@RestController
@RequestMapping("/media")
class MediaController(private val mediaService: MediaService) {
@PostMapping("/upload/{type}")
fun uploadMedia(
@RequestParam("file") file: MultipartFile,
@PathVariable type: String
): ResponseEity<MediaFile> {
return try {
val savedFile = mediaService.saveMedia(file, type)
ResponseEntity.ok(savedFile)
} catch (e: Exception) {
ResponseEntity.status(500).build()
}
}
@GetMapping("/list/{type}")
fun listMedia(@PathVariable type: String): ResponseEntity<List<MediaFile>> {
val files: List<MediaFile> = mediaService.listMediaByType(type)
return ResponseEntity.ok(files)
}
}
眼鏡端上傳
fun uploadPhotoToServer(photoPath: String) {
val file = File(photoPath)
val client = OkHttpClient()
val body = MultipartBody.Builder()
.setType(MultipartBody.FORM)
.addFormDataPart("file", file.name, file.asRequestBody("image/webp".toMediaType()))
.build()
val request = Request.Builder()
.url("http://yourserver.com/media/upload/photo")
.post(body)
.build()
client.newCall(request).enqueue(object : Callback {
override fun onFailure(call: Call, e: IOException) {
Log.e(TAG, "上傳失敗: ${e.message}")
}
override fun onResponse(call: Call, response: Response) {
if (response.isSuccessful) {
Log.d(TAG, "上傳成功")
} else {
Log.e(TAG, "服務器返回異常: ${response.code}")
}
}
})
}
這個服務端模塊不僅可以支持 Glass記小圈應用的多媒體管理,也可以為未來 AI 分析、用户雲端備份等功能打下基礎。
七、應用交互與實戰經驗
在開發 Glass記小圈應用 的過程中,眼鏡端的交互設計和實戰經驗起到了核心作用。由於應用完全運行在眼鏡端,用户的操作主要依賴功能鍵和有限的觸控/語音輸入,因此在設計交互流程時必須充分考慮操作的直觀性與反饋的及時性。
在拍照和錄像功能上,我們採用單機按鍵和長按兩種觸發方式,短按用於拍照、長按用於錄像的開始和結束,同時在操作過程中加入狀態鎖定,避免重複觸發或衝突操作,保證應用的穩定性。在AI場景拍照時,為了應對藍牙傳輸延遲和圖片體積較大的問題,我們對分辨率和壓縮質量進行了優化選擇,優先使用適合傳輸的中低分辨率,同時通過回調機制及時獲取拍照結果,並在UI中提供加載狀態和完成提示,讓用户明確操作是否成功。在錄像和錄音功能上,考慮到眼鏡端硬件性能和功耗,我們在開啓前設置了合理的參數,包括時長、幀率和編碼類型,並通過狀態回調實時監控錄像、錄音過程,確保異常情況下可以立即停止或重新初始化。
在數據管理方面,我們統一了照片、視頻和音頻的存儲路徑,結合未同步媒體文件夾和回調機制實現文件的本地緩存和後續同步,保證數據不會丟失,同時在UI上以列表或歷史記錄的方式呈現,方便用户快速回顧。在開發過程中,我們也積累了大量實戰經驗,包括優化藍牙連接的重試機制、在長時間操作中合理釋放資源以降低功耗、處理拍照和錄音的異常情況、防止連續操作造成回調阻塞,以及在UI中提供明確的狀態提示以提升用户體驗。
這些實踐經驗不僅保證了應用的穩定性和交互流暢性,也為今後擴展多媒體功能、加入更多AI場景或優化用户體驗提供了堅實基礎。
八、總結
通過本次 Glass記小圈應用 的開發實戰,我們完整地梳理了純眼鏡端應用從功能設計、SDK集成到多媒體交互的開發流程。在拍照、錄像和錄音的實現過程中,我們不僅熟悉了CXR-S SDK提供的接口和回調機制,還深入理解了眼鏡端在硬件性能、功耗和藍牙傳輸等方面的限制與優化策略。
實踐中,我們積累了豐富的經驗,包括參數設置優化、異常處理與重試機制、文件管理與歷史記錄維護,以及用户交互的直觀設計與反饋提示,這些都有效提升了應用的穩定性和用户體驗。此外,通過對AI場景拍照和錄像功能的深入調試,我們掌握瞭如何在受限資源環境下平衡數據質量與傳輸效率,為未來擴展更復雜的多媒體和AI交互場景打下了堅實基礎。總體而言,本次開發不僅讓我們熟練掌握了Rokid眼鏡端的核心能力,也為後續構建更完整的AR生活應用提供了寶貴的實戰參考和可複用經驗。