package com.ociweb.iot.camera;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Map;

/**
 * Proxy implementation of {@link Camera} that loads 1080p RGB24
 * raw images from the filesystem.
 *
 * In this implementation, the "device" is a path to a folder
 * containing images on the filesystem.
 *
 * @author Brandon Sanders [brandon@alicorn.io]
 */
public class ProxyCam implements Camera {

    // Open camera file descriptors.
    private int cameraFds = 0;

    // Image files mapped by camera file descriptor.
    private Map<Integer, File[]> camerasToFrames = new HashMap<>();
    private Map<Integer, Integer> camerasToFrameSizes = new HashMap<>();
    private Map<Integer, Integer> camerasToNextFrameIndices = new HashMap<>();

    @Override
    public int open(String device, int width, int height) {

        // Track the file descriptor of the camera we are creating.
        int cameraFd = cameraFds++;

        // Calculate frame size and initialize indices.
        camerasToFrameSizes.put(cameraFd,width * height * 3);
        camerasToNextFrameIndices.put(cameraFd, 0);

        // Discover files.
        File framesDirectory = Paths.get(device).toFile();
        assert framesDirectory.isDirectory();
        camerasToFrames.put(cameraFd, framesDirectory.listFiles());
        assert camerasToFrames.get(cameraFd).length >= 1;

        return cameraFd;
    }

    @Override
    public int getFrameSizeBytes(int fd) {
        return camerasToFrameSizes.getOrDefault(fd, -1);
    }

    @Override
    public int readFrame(int fd, byte[] bytes, int start) {

        // Only read if the FD is valid.
        if (camerasToFrames.containsKey(fd)) {
            File[] frames = camerasToFrames.get(fd);

            // Calculate index of the next frame to read.
            int nextFrameIndex = camerasToNextFrameIndices.get(fd) % frames.length;

            // Perform file read.
            try (FileInputStream fis = new FileInputStream(frames[nextFrameIndex])) {
                return fis.read(bytes, start, camerasToFrameSizes.get(fd));

            } catch (IOException e) {
                e.printStackTrace();
                return -1;

            // Increment next frame index.
            } finally {
                camerasToNextFrameIndices.put(fd, nextFrameIndex + 1);
            }
        } else {
            return -1;
        }
    }

    @Override
    public int close(int fd) {
        camerasToFrames.remove(fd);
        camerasToFrameSizes.remove(fd);
        camerasToNextFrameIndices.remove(fd);
        return 0;
    }
}

@@ -40,20 +40,17 @@
 java.io.
-File
+*
 ;%0Aimport
@@ -59,26 +59,22 @@
 ava.
+n
 io.
-FileInputStream
+ByteBuffer
 ;%0Aim
@@ -87,22 +87,32 @@
 ava.
+n
 io.
-IOException
+channels.FileChannel
 ;%0Aim
@@ -640,16 +640,28 @@
 nteger, 
+RandomAccess
 File%5B%5D%3E 
@@ -1343,65 +1343,435 @@
     
-camerasToFrames.put(cameraFd, framesDirectory.listFiles()
+File%5B%5D directoryFiles = framesDirectory.listFiles();%0A        RandomAccessFile%5B%5D files = new RandomAccessFile%5BdirectoryFiles.length%5D;%0A        for (int i = 0; i %3C files.length; i++) %7B%0A            try %7B%0A                files%5Bi%5D = new RandomAccessFile(directoryFiles%5Bi%5D, %22rw%22);%0A            %7D  catch (FileNotFoundException e) %7B%0A                e.printStackTrace();%0A            %7D%0A        %7D%0A        camerasToFrames.put(cameraFd, files
 );%0A 
@@ -2032,14 +2032,18 @@
 fd, 
-byte%5B%5D
+ByteBuffer
  byt
@@ -2156,24 +2156,36 @@
             
+RandomAccess
 File%5B%5D frame
@@ -2416,46 +2416,22 @@
 File
-InputStream fis = new FileInputStream(
+Channel fis = 
 fram
@@ -2448,16 +2448,28 @@
 meIndex%5D
+.getChannel(
 )) %7B%0A   
@@ -2485,65 +2485,111 @@
     
-return fis.read(bytes, start, camerasToFrameSizes.get(fd)
+bytes.position(0);%0A                bytes.limit(bytes.capacity());%0A                return fis.read(bytes
 );%0A%0A

Fix proxy cam to use buffers.