Android 将大型ByteBuffer的部分存储到文件中

Android 将大型ByteBuffer的部分存储到文件中,android,memory-management,io,Android,Memory Management,Io,我已经实现了一个循环缓冲区或循环缓冲区,以总帧分辨率1280x720存储250帧原始视频数据。作为缓冲区,我使用ByteBuffer类。缓冲区使用循环器在单独的线程中运行,每个新帧都通过消息传递给线程处理程序对象。当达到限制时,位置设置为0,并且从一开始就覆盖整个缓冲区。这样,缓冲区总是包含最后250个视频帧 由于所需的堆空间大约为320 MB,因此我在清单中使用了标记android:largeHeap=true 现在我们来讨论这个问题。循环运行良好,它消耗的堆空间略小于允许的大小,这对我来说是

我已经实现了一个循环缓冲区或循环缓冲区,以总帧分辨率1280x720存储250帧原始视频数据。作为缓冲区,我使用ByteBuffer类。缓冲区使用循环器在单独的线程中运行,每个新帧都通过消息传递给线程处理程序对象。当达到限制时,位置设置为0,并且从一开始就覆盖整个缓冲区。这样,缓冲区总是包含最后250个视频帧

由于所需的堆空间大约为320 MB,因此我在清单中使用了标记android:largeHeap=true

现在我们来讨论这个问题。循环运行良好,它消耗的堆空间略小于允许的大小,这对我来说是可以接受的。但在某个时候,我希望将整个缓冲区存储到原始二进制文件中,同时考虑缓冲区的当前位置

让我用一个小图表来解释:

循环缓冲区如下所示:

|=======================================================================================尾部============|

0---------buffer.position---------buffer.limit

在保存时,我想首先将尾部存储到文件中,因为它包含视频的开头,然后是头部,直到当前buffer.position。由于ByteBuffer堆空间已满,我无法分配更多的字节数组来从中提取数据,因此,我必须直接将ByteBuffer写入文件

目前ByteBuffer只允许使用完全写入方法写入文件。有人知道解决办法吗?或者对于我的任务有更好的解决方案吗

我将在下面给出我的代码:

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();
}}

提前非常感谢

只需创建一个小节并将其写入文件


或者调用set Length,然后写入它,然后将其设置回原来的值。

好的,与此同时,我进一步研究了一下,找到了一个解决方案


我使用的不是ByteBuffer对象,而是简单的byte[]数组。开始时,我分配帧所需的所有堆空间。在存储时,我可以使用当前位置写入缓冲区的头部和尾部。这是可行的,比预期的要容易

你能给我举个例子吗?生成一个小节正是这里的问题,所以我不知道怎么做。只需创建一个具有所需偏移量和长度的新小节,使用旧小节作为src。我不能这样做,因为我需要为此分配内存。不幸的是,堆空间已满。但我可以试着按字节来做。或者有更好的解决方案吗?调用长度大小,写块,然后调用翻转