我已经实现了一个循环缓冲区(或循环缓冲区),总共存储250帧原始视频数据(帧分辨率1280x720)。作为缓冲区,我正在使用ByteBuffer
类。缓冲区使用Looper在单独的线程中运行,每个新帧都通过消息传递给线程Handler
对象。达到限制时,位置设置为0,整个缓冲区从头开始被覆盖。像那样,缓冲区总是包含最后250个视频帧。
由于所需的堆空间量很大(大约320 MB),我在清单中使用了标记android:largeHeap="true"
。
现在我们来解决这个问题。循环运行良好,它的消耗量略小于允许的堆空间大小(这对我来说是可接受的)。但是在某些时候,我想将整个缓冲区存储到原始二进制文件中,同时尊重缓冲区的当前位置。
让我用一个小图解释:
循环缓冲区如下所示:
| ========== HEAD ========== | =============== TAIL ======== ==== |
0 ------------------------- buffer.position()
---------------- ------- buffer.limit()
在保存时,我想先将尾部存储到文件中(因为它包含视频的开头),然后将头部存储到当前buffer.position()
。我不能再分配任何字节数组来从ByteBuffer
中提取数据(堆空间已满),因此,我必须直接将ByteBuffer
写入文件。
目前ByteBuffer
只允许完全写入文件(write()
方法。)有人知道什么是解决方案吗?或者我的任务是否有更好的解决方案?
我将在下面提供我的代码:
public class FrameRecorderThread extends Thread {
public int MAX_NUMBER_FRAMES_QUEUE = 25 * 10; // 25 fps * 10 seconds
public Handler frameHandler;
private ByteBuffer byteBuffer;
byte[] image = new byte[1382400]; // bytes for one image
@Override
public void run() {
Looper.prepare();
byteBuffer = ByteBuffer.allocateDirect(MAX_NUMBER_FRAMES_QUEUE * 1382400); // A lot of memory is allocated
frameHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
// Store message content (byte[]) to queue
if(msg.what == 0) { // STORE FRAME TO BUFFER
if(byteBuffer.position() < MAX_NUMBER_IMAGES_QUEUE * 1382400) {
byteBuffer.put((byte[])msg.obj);
}
else {
byteBuffer.position(0); // Start overwriting from the beginning
}
}
else if(msg.what == 1) { // SAVE IMAGES
String fileName = "VIDEO_BUF_1.raw";
File directory = new File(Environment.getExternalStorageDirectory()
+ "/FrameRecorder/");
directory.mkdirs();
try {
FileOutputStream outStream = new FileOutputStream(Environment.getExternalStorageDirectory()
+ "/FrameRecorder/" + fileName);
// This is the current position of the split between head and tail
int position = byteBuffer.position();
try {
// This stores the whole buffer in a file but does
// not respect the order (tail before head)
outStream.getChannel().write(byteBuffer);
} catch (IOException e) {
e.printStackTrace();
}
} catch (FileNotFoundException e) {
Log.e("FMT", "File not found. (" + e.getLocalizedMessage() + ")");
}
}
else if(msg.what == 2) { // STOP LOOPER
Looper looper = Looper.myLooper();
if(looper != null) {
looper.quit();
byteBuffer = null;
System.gc();
}
}
}
};
Looper.loop();
}}
非常感谢你!
答案 0 :(得分:0)
只需创建一个子部分并将其写入文件。
或者调用set Length然后将其写入然后重新设置。
答案 1 :(得分:0)
好的,与此同时我进一步调查并找到了解决方案。
我使用简单的ByteBuffer
数组而不是byte[]
个对象。在开始时,我正在分配帧所需的所有堆空间。在存储它时,我可以使用当前位置写入缓冲区的头部和尾部。这工作并且比预期容易。 :)