com.chiorichan.dvr.VideoWriter.java Source code

Java tutorial

Introduction

Here is the source code for com.chiorichan.dvr.VideoWriter.java

Source

/*
 * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not
 * distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
 * 
 * Copyright 2014, OpenSpace Solutions LLC. All Right Reserved.
 */
package com.chiorichan.dvr;

import com.chiorichan.ChatColor;
import com.chiorichan.Loader;
import com.chiorichan.dvr.registry.VideoInput;
import com.chiorichan.dvr.storage.Interface;
import com.google.common.collect.Maps;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import static java.lang.Thread.sleep;
import java.util.Map.Entry;
import java.util.TreeMap;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
import javax.imageio.ImageIO;
import net.lingala.zip4j.model.ZipParameters;
import net.lingala.zip4j.util.Zip4jConstants;
import org.joda.time.DateTime;

/**
 *
 * @author Chiori Greene
 */
public class VideoWriter implements Runnable {
    public boolean isRunning;
    public Thread currentThread;
    private Interface storageInterface = new Interface();
    private long lastTen = 0L;
    private ZipOutputStream containerStream = null;
    private boolean frameEncoding = false;
    private final TreeMap<DateTime, BufferedImage> timeCodedFrames = Maps.newTreeMap();
    public boolean detachedFromInput = false;
    private final VideoInput vi;
    private File destFile;
    private ZipParameters parameters;

    public VideoWriter(VideoInput _vi) {
        vi = _vi;

        DVRLoader.getExecutor().execute(this);

        parameters = new ZipParameters();
        parameters.setCompressionMethod(Zip4jConstants.COMP_DEFLATE);
        parameters.setCompressionLevel(Zip4jConstants.DEFLATE_LEVEL_NORMAL);
        parameters.setEncryptFiles(true);
        parameters.setEncryptionMethod(Zip4jConstants.ENC_METHOD_AES);
        parameters.setAesKeyStrength(Zip4jConstants.AES_STRENGTH_256);
        parameters.setPassword("OpenSpaceDVR2014"); // Generate a private key for each DVR install. Installation ID maybe?
    }

    @Override
    public void run() {
        currentThread = Thread.currentThread();

        Loader.getLogger().info("Starting Video Writer Thread - " + currentThread.getName());

        isRunning = true;

        do {
            try {
                if (containerStream == null)
                    changeDestFile();

                Entry<DateTime, BufferedImage> firstFrame = getFrame();

                if (firstFrame != null) {
                    frameHandler(firstFrame.getKey(), firstFrame.getValue());
                    timeCodedFrames.remove(firstFrame.getKey());
                }

                Thread.sleep(10L);
            } catch (Exception ex) {
                Loader.getLogger().severe(
                        "Exception Encountered in the Video Writer Thread (" + currentThread.getName() + ")", ex);
            }
        } while (DVRLoader.isRunning && !detachedFromInput);

        Loader.getLogger().info("Stopping Video Writer Thread - " + Thread.currentThread().getName());

        try {
            finishUp();
        } catch (IOException e) {
            e.printStackTrace();
        }

        isRunning = false;
        currentThread = null;

        Loader.getLogger().info("Video Writer Thread STOPPED! - " + Thread.currentThread().getName());
    }

    public synchronized void addFrame(DateTime dt, BufferedImage bi) {
        timeCodedFrames.put(dt, bi);
    }

    private synchronized Entry<DateTime, BufferedImage> getFrame() {
        if (timeCodedFrames.isEmpty())
            return null;

        return timeCodedFrames.firstEntry();
    }

    private void changeDestFile() throws IOException {
        File lastDestFile = destFile;
        destFile = storageInterface.calculateContainingFile(new DateTime(), vi.getChannelName());

        Loader.getLogger().info(
                "New destination selected for input " + vi.getChannelName() + ": " + destFile.getAbsolutePath());

        // Close previous zip stream
        if (containerStream != null)
            containerStream.finish();

        // Open new zip stream
        containerStream = new ZipOutputStream(new FileOutputStream(destFile));
        containerStream.setComment("OpenSpaceDVR video storage container!");

    }

    private void frameHandler(DateTime dt, BufferedImage img) {
        try {
            if (img == null)
                return;

            frameEncoding = true;

            long start = System.currentTimeMillis();

            if (lastTen != storageInterface.getTen(dt)) {
                lastTen = storageInterface.getTen(dt);
                changeDestFile();
            }

            containerStream.putNextEntry(new ZipEntry(dt.getMillis() + ".jpg"));

            ByteArrayOutputStream bs = new ByteArrayOutputStream();
            ImageIO.write(img, "JPG", bs);

            containerStream.write(bs.toByteArray());

            containerStream.closeEntry();

            Loader.getLogger()
                    .info(ChatColor.YELLOW + "Writing Frame: Capture Time: " + dt.toString() + ", File Size: "
                            + bs.size() + " bytes, Frames Buffered: " + timeCodedFrames.size() + ", Time Taken: "
                            + (System.currentTimeMillis() - start) + ", Thread: "
                            + Thread.currentThread().getName());

            frameEncoding = false;
        } catch (IOException ex) {
            Loader.getLogger().severe("Exception encountered within the frameHandler method:", ex);
        }
    }

    private synchronized void finishUp() throws IOException {
        while (frameEncoding) {
            try {
                sleep(10);
            } catch (InterruptedException ex) {
            }
        }

        containerStream.close();
    }
}