| | |
| | | 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("音频编码器输出格式尚未准备好,将在处理数据时添加"); |
| | | } |
| | | |
| | | // 启动音频编码线程 |
| | | audioThread = new AudioThread(); |
| | | audioThread.start(); |
| | |
| | | |
| | | long frameCount = 0; |
| | | long lastFileChangeTime = System.currentTimeMillis(); |
| | | long audioTrackWaitStartTime = System.currentTimeMillis(); |
| | | final long AUDIO_TRACK_TIMEOUT_MS = 3000; // 3秒超时 |
| | | |
| | | // 循环处理摄像头数据 |
| | | while (isRunning && cameraExists) { |
| | |
| | | if (videoEncoder != null && mediaMuxer != null) { |
| | | encodeFrame(buffer, frameCount, width, height); |
| | | frameCount++; |
| | | |
| | | // 如果音频轨道超时未准备好,尝试仅用视频轨道启动 |
| | | if (!muxerStarted && videoTrackIndex >= 0 && audioTrackIndex < 0) { |
| | | // 重用循环中已定义的 currentTime 变量 |
| | | if (currentTime - audioTrackWaitStartTime > AUDIO_TRACK_TIMEOUT_MS) { |
| | | Timber.w("音频轨道超时未准备好,仅使用视频轨道启动Muxer"); |
| | | synchronized (UsbCameraRecordManager.this) { |
| | | // 创建一个假的音频轨道索引,或者直接启动(但MediaMuxer要求至少一个轨道) |
| | | // 实际上MediaMuxer需要至少一个轨道,所以如果视频轨道准备好了就可以启动 |
| | | 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 |
| | |
| | | MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo(); |
| | | int outputBufferIndex = videoEncoder.dequeueOutputBuffer(bufferInfo, 0); |
| | | |
| | | while (outputBufferIndex >= 0) { |
| | | while (outputBufferIndex != MediaCodec.INFO_TRY_AGAIN_LATER) { |
| | | if (outputBufferIndex == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) { |
| | | // 输出格式改变,添加视频轨道 |
| | | MediaFormat newFormat = videoEncoder.getOutputFormat(); |
| | | videoTrackIndex = mediaMuxer.addTrack(newFormat); |
| | | checkAndStartMuxer(); |
| | | synchronized (UsbCameraRecordManager.this) { |
| | | videoTrackIndex = mediaMuxer.addTrack(newFormat); |
| | | Timber.d("视频轨道已添加: %d", videoTrackIndex); |
| | | checkAndStartMuxer(); |
| | | } |
| | | outputBufferIndex = videoEncoder.dequeueOutputBuffer(bufferInfo, 0); |
| | | continue; |
| | | } else if (outputBufferIndex >= 0) { |
| | | ByteBuffer outputBuffer = videoEncoder.getOutputBuffer(outputBufferIndex); |
| | | if (outputBuffer != null && muxerStarted && videoTrackIndex >= 0) { |
| | |
| | | */ |
| | | private synchronized void checkAndStartMuxer() { |
| | | if (!muxerStarted && videoTrackIndex >= 0 && audioTrackIndex >= 0) { |
| | | mediaMuxer.start(); |
| | | muxerStarted = true; |
| | | try { |
| | | mediaMuxer.start(); |
| | | muxerStarted = true; |
| | | Timber.d("Muxer started, video track: %d, audio track: %d", videoTrackIndex, audioTrackIndex); |
| | | } catch (Exception e) { |
| | | Timber.e(e, "Failed to start muxer"); |
| | | } |
| | | } else { |
| | | Timber.d("Muxer not started yet, video track: %d, audio track: %d", videoTrackIndex, audioTrackIndex); |
| | | } |
| | | } |
| | | |
| | |
| | | MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo(); |
| | | int outputBufferIndex = audioEncoder.dequeueOutputBuffer(bufferInfo, 0); |
| | | |
| | | while (outputBufferIndex >= 0) { |
| | | while (outputBufferIndex != MediaCodec.INFO_TRY_AGAIN_LATER) { |
| | | if (outputBufferIndex == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) { |
| | | // 输出格式改变,添加音频轨道 |
| | | MediaFormat newFormat = audioEncoder.getOutputFormat(); |
| | | audioTrackIndex = mediaMuxer.addTrack(newFormat); |
| | | checkAndStartMuxer(); |
| | | synchronized (UsbCameraRecordManager.this) { |
| | | audioTrackIndex = mediaMuxer.addTrack(newFormat); |
| | | Timber.d("音频轨道已添加: %d", audioTrackIndex); |
| | | checkAndStartMuxer(); |
| | | } |
| | | outputBufferIndex = audioEncoder.dequeueOutputBuffer(bufferInfo, 0); |
| | | continue; |
| | | } else if (outputBufferIndex >= 0) { |
| | | ByteBuffer outputBuffer = audioEncoder.getOutputBuffer(outputBufferIndex); |
| | | if (outputBuffer != null && muxerStarted && audioTrackIndex >= 0) { |