2014-09-15 4 views
1

Я реализовал буфер цикла (или круговой буфер), содержащий в общей сложности 250 кадров необработанных видеоданных (разрешение кадра 1280x720). В качестве буфера я использую класс ByteBuffer. Буфер запускается в отдельном потоке с использованием Looper, каждый новый кадр передается через сообщение в поток Handler. Когда предел достигнут, позиция будет установлена ​​в 0, а весь буфер будет перезаписан с самого начала. Таким образом, буфер всегда содержит последние 250 видеокадров.Хранить части огромного ByteBuffer в файл

Поскольку количество требуемого пространства кучи огромно (около 320 мегабайт), я использую тег android:largeHeap="true" в манифесте.

Теперь мы приходим к проблеме. Петля работает хорошо, она потребляет немного меньше, чем допустимый размер пространства кучи (что приемлемо для меня). Но в некоторый момент времени я хочу сохранить весь буфер в необработанный двоичный файл, соблюдая текущую позицию буфера.

Позвольте мне объяснить, что с небольшим графиком:

Буфер цикла выглядит следующим образом:

| ========== ========== ГОЛОВЫ | =============== ХВОСТ ============ |

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

Хорошо, тем временем я немного исследовал и нашел решение.

Вместо объекта ByteBuffer Я использую простой массив byte[]. В начале я выделяю все пространство кучи, необходимое для фреймов. Во время его хранения я могу записать голову и хвост буфера, используя текущую позицию. Это работает и проще, чем ожидалось. :)

0

Просто создайте подраздел и напишите это в файл.

Или позвоните по номеру, а затем запишите его, а затем установите.

+0

Не могли бы вы привести мне пример, пожалуйста? Создание подсекции - вот в чем проблема, поэтому я не знаю, как это сделать. – Palund

+0

Просто создайте новый со смещением и длиной, используя старый, как src. – Jay

+0

Я не могу этого сделать, потому что для этого мне нужно выделить память. К сожалению, пустое место заполнено. Но я мог бы попытаться сделать это по-байт. Или есть лучшее решение? – Palund

Смежные вопросы