一个用于记录和存储 H.264 视频帧的工具类
CarPlayPacketDumper
是一个用于记录和存储 CarPlay 数据包(特别是 H.264 视频帧)的工具类。它将接收到的数据帧按顺序写入文件,并提供开始、停止和写入操作。
public class CarPlayPacketDumper {private static final String TAG = "CarPlayPacketDumper";private final String filePath;private FileOutputStream fos; // 文件输出流private FileChannel channel; // 文件通道,提供更高效的文件操作public boolean isRecording = false; // 记录状态标志private final AtomicLong writtenBytes = new AtomicLong(0); // 线程安全的计数器public CarPlayPacketDumper(String filePath) {this.filePath = filePath;}public synchronized void start() throws IOException {Log.d(TAG, "启动H.264顺序录制...");stop(); // 确保先关闭现有资源// 追加模式(false表示覆盖原有文件)fos = new FileOutputStream(filePath, false);channel = fos.getChannel(); // 获取文件通道isRecording = true;writtenBytes.set(0);Log.d(TAG, "已清空并准备写入: " + filePath);}public synchronized void writeFrame(ByteBuffer frame) throws IOException {if (!isRecording) {Log.e(TAG, "当前未在录制状态!");throw new IllegalStateException("Not recording");}final int frameSize = frame.remaining(); // 获取剩余字节数// 调试信息:采样前16字节byte[] sample = new byte[Math.min(16, frameSize)];frame.get(sample); // 读取数据到字节数组Log.d(TAG, String.format("写入帧 [大小:%,d字节] [头16字节:%s]",frameSize,bytesToHex(sample)));frame.rewind(); // 重置position// 关键点:直接顺序写入channel.write(frame);writtenBytes.addAndGet(frameSize);}public synchronized void stop() {if (isRecording) {isRecording = false;Log.d(TAG, "停止录制,总写入大小: " + formatFileSize(writtenBytes.get()));try {if (channel != null) {channel.force(true); // 强制刷盘channel.close();}if (fos != null) fos.close();} catch (IOException e) {Log.e(TAG, "关闭资源失败", e);} finally {channel = null;fos = null;}}}// 辅助方法:字节转十六进制private static String bytesToHex(byte[] bytes) {StringBuilder sb = new StringBuilder();for (byte b : bytes) {sb.append(String.format("%02X ", b));}return sb.toString();}// 辅助方法:格式化文件大小private static String formatFileSize(long bytes) {if (bytes < 1024) return bytes + "B";return String.format("%.2fMB", bytes / (1024.0 * 1024.0));}
}
//使用示例//1.初始化
private final CarPlayPacketDumper dumper = new CarPlayPacketDumper("/storage/emulated/0/Movies/video.h264");//2.开始录制
dumper.start();//3.写入帧数据
// 在CarPlay视频流处理中的典型用法
public void onVideoFrameReceived(ByteBuffer frame) {if (dumper != null && dumper.isRecording) {try {dumper.writeFrame(frame);} catch (IOException e) {Log.e(TAG, "写入帧失败", e);dumper.stop();}}
}//4.停止录制
dumper.stop();
//5.异常处理:必须处理IOException,调用stop()确保资源释放