From 01f07011ee45d99e8b5f64824a5399b597b23be9 Mon Sep 17 00:00:00 2001
From: Dana <Dana_Lee1016@126.com>
Date: 星期二, 27 一月 2026 14:13:27 +0800
Subject: [PATCH] 1.usb rgba 2 ,正常颜色 2:使用帧索引计算时间戳,假设固定帧率。实际采集帧率可能不同,导致时间戳不准确  解决方案:使用实际经过的时间计算时间戳,确保时间戳与实际时间一致

---
 app/build/generated/aidl_source_output_dir/debug/out/com/safeluck/floatwindow/IMyCallback.java         |    2 
 app/build/generated/aidl_source_output_dir/debug/out/com/safeluck/floatwindow/IMediaAidlInterface.java |    2 
 app/src/main/java/com/safeluck/floatwindow/manager/UsbCameraRecordManager.java                         |  120 +++++++++++++++++++++------------------
 3 files changed, 67 insertions(+), 57 deletions(-)

diff --git a/app/build/generated/aidl_source_output_dir/debug/out/com/safeluck/floatwindow/IMediaAidlInterface.java b/app/build/generated/aidl_source_output_dir/debug/out/com/safeluck/floatwindow/IMediaAidlInterface.java
index ed3fbf5..5c6b6e0 100644
--- a/app/build/generated/aidl_source_output_dir/debug/out/com/safeluck/floatwindow/IMediaAidlInterface.java
+++ b/app/build/generated/aidl_source_output_dir/debug/out/com/safeluck/floatwindow/IMediaAidlInterface.java
@@ -1,6 +1,6 @@
 /*
  * This file is auto-generated.  DO NOT MODIFY.
- * Using: D:\Program\ Files\Android\Sdk\build-tools\35.0.0\aidl.exe -pD:\Program\ Files\Android\Sdk\platforms\android-35\framework.aidl -oD:\JetBrainsProjects\AndroidProject\anyunVideo\app\build\generated\aidl_source_output_dir\debug\out -ID:\JetBrainsProjects\AndroidProject\anyunVideo\app\src\main\aidl -ID:\JetBrainsProjects\AndroidProject\anyunVideo\app\src\debug\aidl -ID:\data\.gradle\caches\8.10.2\transforms\53a750d70626c759bd7a6dbaf50185ee\transformed\core-1.12.0\aidl -ID:\data\.gradle\caches\8.10.2\transforms\dc945394860d4e1c7d02ff0c8d3e2e6f\transformed\versionedparcelable-1.1.1\aidl -dC:\Users\Dana\AppData\Local\Temp\aidl1635290626695601630.d D:\JetBrainsProjects\AndroidProject\anyunVideo\app\src\main\aidl\com\safeluck\floatwindow\IMediaAidlInterface.aidl
+ * Using: D:\Program\ Files\Android\Sdk\build-tools\35.0.0\aidl.exe -pD:\Program\ Files\Android\Sdk\platforms\android-35\framework.aidl -oD:\JetBrainsProjects\AndroidProject\anyunVideo\app\build\generated\aidl_source_output_dir\debug\out -ID:\JetBrainsProjects\AndroidProject\anyunVideo\app\src\main\aidl -ID:\JetBrainsProjects\AndroidProject\anyunVideo\app\src\debug\aidl -ID:\data\.gradle\caches\8.10.2\transforms\53a750d70626c759bd7a6dbaf50185ee\transformed\core-1.12.0\aidl -ID:\data\.gradle\caches\8.10.2\transforms\dc945394860d4e1c7d02ff0c8d3e2e6f\transformed\versionedparcelable-1.1.1\aidl -dC:\Users\Dana\AppData\Local\Temp\aidl10441886692587460682.d D:\JetBrainsProjects\AndroidProject\anyunVideo\app\src\main\aidl\com\safeluck\floatwindow\IMediaAidlInterface.aidl
  */
 package com.safeluck.floatwindow;
 // Declare any non-default types here with import statements
diff --git a/app/build/generated/aidl_source_output_dir/debug/out/com/safeluck/floatwindow/IMyCallback.java b/app/build/generated/aidl_source_output_dir/debug/out/com/safeluck/floatwindow/IMyCallback.java
index 57e9e91..8b52912 100644
--- a/app/build/generated/aidl_source_output_dir/debug/out/com/safeluck/floatwindow/IMyCallback.java
+++ b/app/build/generated/aidl_source_output_dir/debug/out/com/safeluck/floatwindow/IMyCallback.java
@@ -1,6 +1,6 @@
 /*
  * This file is auto-generated.  DO NOT MODIFY.
- * Using: D:\Program\ Files\Android\Sdk\build-tools\35.0.0\aidl.exe -pD:\Program\ Files\Android\Sdk\platforms\android-35\framework.aidl -oD:\JetBrainsProjects\AndroidProject\anyunVideo\app\build\generated\aidl_source_output_dir\debug\out -ID:\JetBrainsProjects\AndroidProject\anyunVideo\app\src\main\aidl -ID:\JetBrainsProjects\AndroidProject\anyunVideo\app\src\debug\aidl -ID:\data\.gradle\caches\8.10.2\transforms\53a750d70626c759bd7a6dbaf50185ee\transformed\core-1.12.0\aidl -ID:\data\.gradle\caches\8.10.2\transforms\dc945394860d4e1c7d02ff0c8d3e2e6f\transformed\versionedparcelable-1.1.1\aidl -dC:\Users\Dana\AppData\Local\Temp\aidl7435277295093533370.d D:\JetBrainsProjects\AndroidProject\anyunVideo\app\src\main\aidl\com\safeluck\floatwindow\IMyCallback.aidl
+ * Using: D:\Program\ Files\Android\Sdk\build-tools\35.0.0\aidl.exe -pD:\Program\ Files\Android\Sdk\platforms\android-35\framework.aidl -oD:\JetBrainsProjects\AndroidProject\anyunVideo\app\build\generated\aidl_source_output_dir\debug\out -ID:\JetBrainsProjects\AndroidProject\anyunVideo\app\src\main\aidl -ID:\JetBrainsProjects\AndroidProject\anyunVideo\app\src\debug\aidl -ID:\data\.gradle\caches\8.10.2\transforms\53a750d70626c759bd7a6dbaf50185ee\transformed\core-1.12.0\aidl -ID:\data\.gradle\caches\8.10.2\transforms\dc945394860d4e1c7d02ff0c8d3e2e6f\transformed\versionedparcelable-1.1.1\aidl -dC:\Users\Dana\AppData\Local\Temp\aidl6260459078460591487.d D:\JetBrainsProjects\AndroidProject\anyunVideo\app\src\main\aidl\com\safeluck\floatwindow\IMyCallback.aidl
  */
 package com.safeluck.floatwindow;
 /**
diff --git a/app/src/main/java/com/safeluck/floatwindow/manager/UsbCameraRecordManager.java b/app/src/main/java/com/safeluck/floatwindow/manager/UsbCameraRecordManager.java
index 9c1e67c..1047097 100644
--- a/app/src/main/java/com/safeluck/floatwindow/manager/UsbCameraRecordManager.java
+++ b/app/src/main/java/com/safeluck/floatwindow/manager/UsbCameraRecordManager.java
@@ -70,6 +70,9 @@
     private File currentVideoFile;
     private long currentFileStartTime;
     
+    // 褰曞埗寮�濮嬫椂闂达紙绾崇锛夛紝鐢ㄤ簬鏃堕棿鎴冲悓姝�
+    private volatile long recordingStartTimeNs = 0;
+    
     /**
      * 褰曞儚鍥炶皟鎺ュ彛
      */
@@ -165,7 +168,7 @@
             usbCamera.setenv();
 
             // 浣跨敤prepareCamera鏂规硶锛宑amera_id鑼冨洿[0,9]
-            int[] cameraIds = {0, 9};
+            int[] cameraIds = {0, 2};
             String cameraName = null; // 涓嶆寚瀹氱壒瀹氬悕绉�
 
             // 濡傛灉杩斿洖闈�0锛屼唬琛ㄦ墦寮�澶辫触锛屽垯鍏坰topCamera鍐嶉噸璇曪紝鏈�澶�3娆�
@@ -366,19 +369,9 @@
                     Timber.d("闊抽褰曞埗宸插惎鍔�");
                 }
                 
-                // 涓诲姩妫�鏌ラ煶棰戠紪鐮佸櫒杈撳嚭鏍煎紡锛堝彲鑳藉湪澶勭悊鏁版嵁鍓嶅氨鏈夋牸寮忥級
-                try {
-                    MediaFormat audioFormat = audioEncoder.getOutputFormat();
-                    if (audioFormat != null) {
-                        synchronized (UsbCameraRecordManager.this) {
-                            audioTrackIndex = mediaMuxer.addTrack(audioFormat);
-                            Timber.d("闊抽杞ㄩ亾宸叉坊鍔狅紙涓诲姩妫�鏌ワ級: %d", audioTrackIndex);
-                            checkAndStartMuxer();
-                        }
-                    }
-                } catch (Exception e) {
-                    Timber.d("闊抽缂栫爜鍣ㄨ緭鍑烘牸寮忓皻鏈噯澶囧ソ锛屽皢鍦ㄥ鐞嗘暟鎹椂娣诲姞");
-                }
+                // 娉ㄦ剰锛氫笉瑕佸湪杩欓噷涓诲姩妫�鏌ラ煶棰戠紪鐮佸櫒杈撳嚭鏍煎紡
+                // 鍥犱负 MediaCodec 鐨� getOutputFormat() 鍦ㄧ紪鐮佸櫒鍚姩鍚庡彲鑳借繑鍥� null
+                // 搴旇绛夊緟 INFO_OUTPUT_FORMAT_CHANGED 浜嬩欢
                 
                 // 鍚姩闊抽缂栫爜绾跨▼
                 audioThread = new AudioThread();
@@ -386,10 +379,10 @@
                 
                 Timber.d("寮�濮嬪綍鍍忥紝鍒嗚鲸鐜�: %dx%d", width, height);
                 
+                // 璁板綍寮�濮嬫椂闂达紙绾崇锛岀敤浜庣簿纭椂闂存埑锛�
+                recordingStartTimeNs = System.nanoTime();
                 long frameCount = 0;
                 long lastFileChangeTime = System.currentTimeMillis();
-                long audioTrackWaitStartTime = System.currentTimeMillis();
-                final long AUDIO_TRACK_TIMEOUT_MS = 3000; // 3绉掕秴鏃�
                 
                 // 寰幆澶勭悊鎽勫儚澶存暟鎹�
                 while (isRunning && cameraExists) {
@@ -415,6 +408,9 @@
                             Timber.e("Failed to create new video file");
                             break;
                         }
+                        
+                        // 閲嶇疆寮�濮嬫椂闂�
+                        recordingStartTimeNs = System.nanoTime();
                         
                         // 閲嶆柊鍚姩闊抽褰曞埗
                         if (audioRecord != null) {
@@ -442,33 +438,14 @@
                     }
                     
                     // 鑾峰彇YUV鏁版嵁 (鍙傛暟0琛ㄧず褰曞儚)
-                    usbCamera.rgba(0, buffer);
+                    usbCamera.rgba(2, buffer);
                     
                     // 缂栫爜骞跺啓鍏ユ枃浠�
                     if (videoEncoder != null && mediaMuxer != null) {
-                        encodeFrame(buffer, frameCount, width, height);
+                        // 璁$畻瀹為檯缁忚繃鐨勬椂闂达紙寰锛�
+                        long elapsedTimeUs = (System.nanoTime() - recordingStartTimeNs) / 1000;
+                        encodeFrame(buffer, elapsedTimeUs, width, height);
                         frameCount++;
-                        
-                        // 濡傛灉闊抽杞ㄩ亾瓒呮椂鏈噯澶囧ソ锛屽皾璇曚粎鐢ㄨ棰戣建閬撳惎鍔�
-                        if (!muxerStarted && videoTrackIndex >= 0 && audioTrackIndex < 0) {
-                            // 閲嶇敤寰幆涓凡瀹氫箟鐨� currentTime 鍙橀噺
-                            if (currentTime - audioTrackWaitStartTime > AUDIO_TRACK_TIMEOUT_MS) {
-                                Timber.w("闊抽杞ㄩ亾瓒呮椂鏈噯澶囧ソ锛屼粎浣跨敤瑙嗛杞ㄩ亾鍚姩Muxer");
-                                synchronized (UsbCameraRecordManager.this) {
-                                    // 鍒涘缓涓�涓亣鐨勯煶棰戣建閬撶储寮曪紝鎴栬�呯洿鎺ュ惎鍔紙浣哅ediaMuxer瑕佹眰鑷冲皯涓�涓建閬擄級
-                                    // 瀹為檯涓奙ediaMuxer闇�瑕佽嚦灏戜竴涓建閬擄紝鎵�浠ュ鏋滆棰戣建閬撳噯澶囧ソ浜嗗氨鍙互鍚姩
-                                    if (videoTrackIndex >= 0) {
-                                        try {
-                                            mediaMuxer.start();
-                                            muxerStarted = true;
-                                            Timber.d("Muxer started with video track only: %d", videoTrackIndex);
-                                        } catch (Exception e) {
-                                            Timber.e(e, "Failed to start muxer with video only");
-                                        }
-                                    }
-                                }
-                            }
-                        }
                     }
                     
                     // 鎺у埗甯х巼锛岀害20fps
@@ -498,8 +475,12 @@
         
         /**
          * 缂栫爜涓�甯ф暟鎹�
+         * @param yuvData YUV鏁版嵁
+         * @param presentationTimeUs 鏃堕棿鎴筹紙寰锛夛紝鍩轰簬瀹為檯寮�濮嬫椂闂�
+         * @param width 瀹藉害
+         * @param height 楂樺害
          */
-        private void encodeFrame(byte[] yuvData, long frameIndex, int width, int height) {
+        private void encodeFrame(byte[] yuvData, long presentationTimeUs, int width, int height) {
             try {
                 // 鑾峰彇杈撳叆缂撳啿鍖�
                 int inputBufferIndex = videoEncoder.dequeueInputBuffer(10000);
@@ -509,7 +490,7 @@
                         inputBuffer.clear();
                         inputBuffer.put(yuvData);
                         
-                        long presentationTimeUs = (frameIndex * 1000000) / FRAME_RATE;
+                        // 浣跨敤瀹為檯缁忚繃鐨勬椂闂翠綔涓烘椂闂存埑
                         videoEncoder.queueInputBuffer(inputBufferIndex, 0, yuvData.length, 
                                 presentationTimeUs, 0);
                     }
@@ -524,18 +505,30 @@
                         // 杈撳嚭鏍煎紡鏀瑰彉锛屾坊鍔犺棰戣建閬�
                         MediaFormat newFormat = videoEncoder.getOutputFormat();
                         synchronized (UsbCameraRecordManager.this) {
-                            videoTrackIndex = mediaMuxer.addTrack(newFormat);
-                            Timber.d("瑙嗛杞ㄩ亾宸叉坊鍔�: %d", videoTrackIndex);
-                            checkAndStartMuxer();
+                            // 妫�鏌� muxer 鏄惁宸插惎鍔紝濡傛灉宸插惎鍔ㄥ垯鏃犳硶娣诲姞杞ㄩ亾
+                            if (muxerStarted) {
+                                Timber.e("Muxer already started, cannot add video track");
+                                break;
+                            }
+                            if (videoTrackIndex < 0) {
+                                videoTrackIndex = mediaMuxer.addTrack(newFormat);
+                                Timber.d("瑙嗛杞ㄩ亾宸叉坊鍔�: %d", videoTrackIndex);
+                                checkAndStartMuxer();
+                            }
                         }
                         outputBufferIndex = videoEncoder.dequeueOutputBuffer(bufferInfo, 0);
                         continue;
                     } else if (outputBufferIndex >= 0) {
                         ByteBuffer outputBuffer = videoEncoder.getOutputBuffer(outputBufferIndex);
+                        // 鍙湁鍦� muxer 宸插惎鍔ㄤ笖杞ㄩ亾绱㈠紩鏈夋晥鏃舵墠鍐欏叆鏁版嵁
                         if (outputBuffer != null && muxerStarted && videoTrackIndex >= 0) {
                             outputBuffer.position(bufferInfo.offset);
                             outputBuffer.limit(bufferInfo.offset + bufferInfo.size);
-                            mediaMuxer.writeSampleData(videoTrackIndex, outputBuffer, bufferInfo);
+                            try {
+                                mediaMuxer.writeSampleData(videoTrackIndex, outputBuffer, bufferInfo);
+                            } catch (Exception e) {
+                                Timber.e(e, "Error writing video sample data");
+                            }
                         }
                         videoEncoder.releaseOutputBuffer(outputBufferIndex, false);
                     }
@@ -583,7 +576,7 @@
             
             try {
                 byte[] audioBuffer = new byte[audioBufferSize];
-                long audioFrameCount = 0;
+                long totalSamplesRead = 0; // 鎬婚噰鏍锋暟
                 
                 while (isRecording && audioRecord != null && audioEncoder != null) {
                     // 璇诲彇闊抽鏁版嵁
@@ -594,8 +587,8 @@
                     }
                     
                     // 缂栫爜闊抽鏁版嵁
-                    encodeAudio(audioBuffer, readSize, audioFrameCount);
-                    audioFrameCount += readSize / 2; // 16浣嶉噰鏍凤紝姣忎釜閲囨牱2瀛楄妭
+                    encodeAudio(audioBuffer, readSize, totalSamplesRead);
+                    totalSamplesRead += readSize / 2; // 16浣嶉噰鏍凤紝姣忎釜閲囨牱2瀛楄妭
                 }
                 
             } catch (Exception e) {
@@ -607,10 +600,13 @@
         
         /**
          * 缂栫爜闊抽鏁版嵁
+         * @param audioData 闊抽鏁版嵁
+         * @param size 鏁版嵁澶у皬锛堝瓧鑺傦級
+         * @param totalSamples 鎬婚噰鏍锋暟锛堜粠寮�濮嬪埌鐜板湪鐨勭疮璁¢噰鏍锋暟锛�
          */
-        private void encodeAudio(byte[] audioData, int size, long frameCount) {
+        private void encodeAudio(byte[] audioData, int size, long totalSamples) {
             try {
-                // 鑾峰彇杈撳叆缂撳啿鍖�
+                // 鑾峰彇杈撳叆缂撳啿鍖猴紙鍗充娇 muxer 鏈惎鍔ㄤ篃瑕佺紪鐮侊紝浠ヤ究灏藉揩鑾峰緱杈撳嚭鏍煎紡锛�
                 int inputBufferIndex = audioEncoder.dequeueInputBuffer(10000);
                 if (inputBufferIndex >= 0) {
                     ByteBuffer inputBuffer = audioEncoder.getInputBuffer(inputBufferIndex);
@@ -618,7 +614,9 @@
                         inputBuffer.clear();
                         inputBuffer.put(audioData, 0, size);
                         
-                        long presentationTimeUs = (frameCount * 1000000) / SAMPLE_RATE;
+                        // 浣跨敤閲囨牱鏁拌绠楁椂闂存埑锛堝井绉掞級
+                        // totalSamples 鏄噰鏍锋暟锛孲AMPLE_RATE 鏄瘡绉掗噰鏍锋暟
+                        long presentationTimeUs = (totalSamples * 1000000) / SAMPLE_RATE;
                         audioEncoder.queueInputBuffer(inputBufferIndex, 0, size, 
                                 presentationTimeUs, 0);
                     }
@@ -633,18 +631,30 @@
                         // 杈撳嚭鏍煎紡鏀瑰彉锛屾坊鍔犻煶棰戣建閬�
                         MediaFormat newFormat = audioEncoder.getOutputFormat();
                         synchronized (UsbCameraRecordManager.this) {
-                            audioTrackIndex = mediaMuxer.addTrack(newFormat);
-                            Timber.d("闊抽杞ㄩ亾宸叉坊鍔�: %d", audioTrackIndex);
-                            checkAndStartMuxer();
+                            // 妫�鏌� muxer 鏄惁宸插惎鍔紝濡傛灉宸插惎鍔ㄥ垯鏃犳硶娣诲姞杞ㄩ亾
+                            if (muxerStarted) {
+                                Timber.e("Muxer already started, cannot add audio track");
+                                break;
+                            }
+                            if (audioTrackIndex < 0) {
+                                audioTrackIndex = mediaMuxer.addTrack(newFormat);
+                                Timber.d("闊抽杞ㄩ亾宸叉坊鍔�: %d", audioTrackIndex);
+                                checkAndStartMuxer();
+                            }
                         }
                         outputBufferIndex = audioEncoder.dequeueOutputBuffer(bufferInfo, 0);
                         continue;
                     } else if (outputBufferIndex >= 0) {
                         ByteBuffer outputBuffer = audioEncoder.getOutputBuffer(outputBufferIndex);
+                        // 鍙湁鍦� muxer 宸插惎鍔ㄤ笖杞ㄩ亾绱㈠紩鏈夋晥鏃舵墠鍐欏叆鏁版嵁
                         if (outputBuffer != null && muxerStarted && audioTrackIndex >= 0) {
                             outputBuffer.position(bufferInfo.offset);
                             outputBuffer.limit(bufferInfo.offset + bufferInfo.size);
-                            mediaMuxer.writeSampleData(audioTrackIndex, outputBuffer, bufferInfo);
+                            try {
+                                mediaMuxer.writeSampleData(audioTrackIndex, outputBuffer, bufferInfo);
+                            } catch (Exception e) {
+                                Timber.e(e, "Error writing audio sample data");
+                            }
                         }
                         audioEncoder.releaseOutputBuffer(outputBufferIndex, false);
                     }

--
Gitblit v1.8.0