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/src/main/java/com/safeluck/floatwindow/manager/UsbCameraRecordManager.java | 120 ++++++++++++++++++++++++++++++++---------------------------
1 files changed, 65 insertions(+), 55 deletions(-)
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