Package org.openmeetings.app.data.flvrecord.converter

Source Code of org.openmeetings.app.data.flvrecord.converter.FlvInterviewConverter

package org.openmeetings.app.data.flvrecord.converter;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;

import org.openmeetings.app.data.basic.Configurationmanagement;
import org.openmeetings.app.data.flvrecord.FlvRecordingDaoImpl;
import org.openmeetings.app.data.flvrecord.FlvRecordingLogDaoImpl;
import org.openmeetings.app.data.flvrecord.FlvRecordingMetaDataDaoImpl;
import org.openmeetings.app.data.flvrecord.FlvRecordingMetaDeltaDaoImpl;
import org.openmeetings.app.documents.GenerateSWF;
import org.openmeetings.app.persistence.beans.flvrecord.FlvRecording;
import org.openmeetings.app.persistence.beans.flvrecord.FlvRecordingMetaData;
import org.openmeetings.app.persistence.beans.flvrecord.FlvRecordingMetaDelta;
import org.openmeetings.app.remote.red5.ScopeApplicationAdapter;
import org.openmeetings.utils.math.CalendarPatterns;
import org.red5.logging.Red5LoggerFactory;
import org.slf4j.Logger;

public class FlvInterviewConverter {
 
  //Windows has some problems in reading the image number correctly without index
  //that is why we have to say %09d (=max a number with 9 decimals) instead of %d (=infinite)
  //private final int maxDecimalPoint = 9;

  private static final Logger log = Red5LoggerFactory
      .getLogger(FlvInterviewConverter.class);

  // Spring loaded Beans
  private FlvRecordingDaoImpl flvRecordingDaoImpl = null;
  private FlvRecordingMetaDataDaoImpl flvRecordingMetaDataDaoImpl = null;
  private Configurationmanagement configurationmanagement;
  private FlvRecordingLogDaoImpl flvRecordingLogDaoImpl;
  private FlvRecordingMetaDeltaDaoImpl flvRecordingMetaDeltaDaoImpl;

  public FlvRecordingDaoImpl getFlvRecordingDaoImpl() {
    return flvRecordingDaoImpl;
  }
  public void setFlvRecordingDaoImpl(FlvRecordingDaoImpl flvRecordingDaoImpl) {
    this.flvRecordingDaoImpl = flvRecordingDaoImpl;
  }

  public FlvRecordingMetaDataDaoImpl getFlvRecordingMetaDataDaoImpl() {
    return flvRecordingMetaDataDaoImpl;
  }
  public void setFlvRecordingMetaDataDaoImpl(
      FlvRecordingMetaDataDaoImpl flvRecordingMetaDataDaoImpl) {
    this.flvRecordingMetaDataDaoImpl = flvRecordingMetaDataDaoImpl;
  }

  public Configurationmanagement getConfigurationmanagement() {
    return configurationmanagement;
  }
  public void setConfigurationmanagement(
      Configurationmanagement configurationmanagement) {
    this.configurationmanagement = configurationmanagement;
  }

  public FlvRecordingLogDaoImpl getFlvRecordingLogDaoImpl() {
    return flvRecordingLogDaoImpl;
  }
  public void setFlvRecordingLogDaoImpl(
      FlvRecordingLogDaoImpl flvRecordingLogDaoImpl) {
    this.flvRecordingLogDaoImpl = flvRecordingLogDaoImpl;
  }
 
  public FlvRecordingMetaDeltaDaoImpl getFlvRecordingMetaDeltaDaoImpl() {
    return flvRecordingMetaDeltaDaoImpl;
  }
  public void setFlvRecordingMetaDeltaDaoImpl(
      FlvRecordingMetaDeltaDaoImpl flvRecordingMetaDeltaDaoImpl) {
    this.flvRecordingMetaDeltaDaoImpl = flvRecordingMetaDeltaDaoImpl;
  }
 
  public void startConversion(Long flvRecordingId) {
    try {

      FlvRecording flvRecording = this.flvRecordingDaoImpl
          .getFlvRecordingById(flvRecordingId);
      log.debug("flvRecording " + flvRecording.getFlvRecordingId());

      // Strip Audio out of all Audio-FLVs
      this.stripAudioFromFLVs(flvRecording);

      // Add empty pieces at the beginning and end of the wav

    } catch (Exception err) {
      log.error("[startConversion]", err);
    }
  }

  private String getPathToFFMPEG() {
    String pathToFFMPEG = this.configurationmanagement.getConfKey(3,
        "ffmpeg_path").getConf_value();
    if (!pathToFFMPEG.equals("") && !pathToFFMPEG.endsWith(File.separator)) {
      pathToFFMPEG += File.separator;
    }
    pathToFFMPEG += "ffmpeg";
    return pathToFFMPEG;
  }

  private String getPathToSoX() {
    String pathToSoX = this.configurationmanagement.getConfKey(3,
        "sox_path").getConf_value();
    if (!pathToSoX.equals("") && !pathToSoX.endsWith(File.separator)) {
      pathToSoX += File.separator;
    }
    pathToSoX += "sox";
    return pathToSoX;
  }
 
  private String getPathToImageMagick() {
    String pathToImageMagick = this.configurationmanagement.getConfKey(3,
        "imagemagick_path").getConf_value();
    if (!pathToImageMagick.equals("") && !pathToImageMagick.endsWith(File.separator)) {
      pathToImageMagick += File.separator;
    }
    pathToImageMagick += "convert"+GenerateSWF.execExt;
    return pathToImageMagick;
  }

  public void stripAudioFromFLVs(FlvRecording flvRecording) {
    List<HashMap<String, Object>> returnLog = new LinkedList<HashMap<String, Object>>();
    try {

      List<FlvRecordingMetaData> metaDataList = this
          .getFlvRecordingMetaDataDaoImpl()
          .getFlvRecordingMetaDataAudioFlvsByRecording(
              flvRecording.getFlvRecordingId());

      // Init variables
      String streamFolderName = ScopeApplicationAdapter.webAppPath
          + File.separatorChar + "streams" + File.separatorChar
          + flvRecording.getRoom_id() + File.separatorChar;

      log.debug("###################################################");
      log.debug("### streamFolderName - " + streamFolderName);
      log.debug("### meta Data Number - " + metaDataList.size());
      log.debug("###################################################");

      List<String> listOfFullWaveFiles = new LinkedList<String>();

      for (FlvRecordingMetaData flvRecordingMetaData : metaDataList) {

        String inputFlv = streamFolderName
            + flvRecordingMetaData.getStreamName() + ".flv";

        String hashFileName = flvRecordingMetaData.getStreamName()
            + "_WAVE.wav";
        String outputWav = streamFolderName + hashFileName;

        flvRecordingMetaData.setWavAudioData(hashFileName);
       
        File inputFlvFile = new File(inputFlv);
       
        if (inputFlvFile.exists()) {

          String[] argv = new String[] { this.getPathToFFMPEG(),
               "-async", "1",
              "-i", inputFlv, outputWav };
 
          log.debug("START stripAudioFromFLVs ################# ");
          for (int i = 0; i < argv.length; i++) {
            log.debug(" i " + i + " argv-i " + argv[i]);
          }
          log.debug("END stripAudioFromFLVs ################# ");
 
          returnLog.add(GenerateSWF.executeScript("generateFFMPEG", argv));
 
          // check if the resulting Audio is valid
          File output_wav = new File(outputWav);
 
          if (!output_wav.exists()) {
            flvRecordingMetaData.setAudioIsValid(false);
          } else {
            if (output_wav.length() == 0) {
              flvRecordingMetaData.setAudioIsValid(false);
            } else {
              flvRecordingMetaData.setAudioIsValid(true);
            }
          }
       
        } else {
          flvRecordingMetaData.setAudioIsValid(false);
        }
       
        if (flvRecordingMetaData.getAudioIsValid()) {
         
          // Strip Wave to Full Length
          String outputGapFullWav = outputWav;
         
          //Fix Gaps in Audio
          List<FlvRecordingMetaDelta> flvRecordingMetaDeltas = this.flvRecordingMetaDeltaDaoImpl.getFlvRecordingMetaDeltaByMetaId(flvRecordingMetaData.getFlvRecordingMetaDataId());
         
          int counter = 0;
         
          //double startGap = 0;
         
          for (FlvRecordingMetaDelta flvRecordingMetaDelta : flvRecordingMetaDeltas) {
           
            String inputFile = outputGapFullWav;
           
            // Strip Wave to Full Length
            String hashFileGapsFullName = flvRecordingMetaData.getStreamName()
                      + "_GAP_FULL_WAVE_"+counter+".wav";
            outputGapFullWav = streamFolderName + hashFileGapsFullName;
           
            flvRecordingMetaDelta.setWaveOutPutName(hashFileGapsFullName);
           
            String[] argv_sox = null;
           
           
            if (flvRecordingMetaDelta.getIsStartPadding() != null && flvRecordingMetaDelta.getIsStartPadding()) {
             
              double gapSeconds = Double.valueOf(flvRecordingMetaDelta.getDeltaTime().toString()).doubleValue()/1000;
             
              Double.valueOf(flvRecordingMetaDelta.getDeltaTime().toString()).doubleValue();
             
              if (gapSeconds > 0) {
                //Add the item at the beginning
                argv_sox = new String[] { this.getPathToSoX(),
                    inputFile, outputGapFullWav, "pad",
                    String.valueOf(gapSeconds).toString(),"0" };
              }
             
            } else if (flvRecordingMetaDelta.getIsEndPadding() != null && flvRecordingMetaDelta.getIsEndPadding()) {
             
              double gapSeconds = Double.valueOf(flvRecordingMetaDelta.getDeltaTime().toString()).doubleValue()/1000;
             
              if (gapSeconds > 0) {
                //Add the item at the end
                argv_sox = new String[] { this.getPathToSoX(),
                    inputFile, outputGapFullWav, "pad",
                    "0",String.valueOf(gapSeconds).toString() };
              }
            }
//             
//            } else if (flvRecordingMetaDelta.getDeltaTime().equals(flvRecordingMetaDelta.getTimeStamp())) {
//             
//              double gapSeconds = Double.valueOf(flvRecordingMetaDelta.getDeltaTime().toString()).doubleValue()/1000;
//             
//              //Add the item at the beginning
//              argv_sox = new String[] { this.getPathToSoX(),
//                  inputFile, outputGapFullWav, "pad",
//                  String.valueOf(gapSeconds).toString() };
//             
//            } else {
//             
//              double gapSeconds = Double.valueOf(flvRecordingMetaDelta.getDeltaTime().toString()).doubleValue()/1000;
//              double posSeconds = ( ( Double.valueOf(flvRecordingMetaDelta.getTimeStamp().toString()).doubleValue() + startGap ) - Double.valueOf(flvRecordingMetaDelta.getDeltaTime().toString()).doubleValue() - 50 ) /1000;
//             
//              if (posSeconds < 0) {
//                throw new Exception("posSeconds is Negative, this should never happen! flvRecordingMetaDeltaId ::"+flvRecordingMetaDelta.getFlvRecordingMetaDeltaId()+" posSeconds :: "+posSeconds);
//                //posSeconds = 0;
//              }
//             
//              //Add the item in-between
//              argv_sox = new String[] { this.getPathToSoX(),
//                  inputFile, outputGapFullWav, "pad",
//                  ""+String.valueOf(gapSeconds).toString()
//                  +"@"+String.valueOf(posSeconds).toString() };
//
//            }
           
            if (argv_sox != null) {
              log.debug("START addGapAudioToWaves ################# ");
              log.debug("START addGapAudioToWaves ################# Delta-ID :: "+flvRecordingMetaDelta.getFlvRecordingMetaDeltaId());
              String commandHelper = " ";
              for (int i = 0; i < argv_sox.length; i++) {
                commandHelper += " "+argv_sox[i];
                //log.debug(" i " + i + " argv-i " + argv_sox[i]);
              }
              log.debug(" commandHelper " + commandHelper);
              log.debug("END addGapAudioToWaves ################# ");
 
              returnLog.add(GenerateSWF.executeScript("fillGap",argv_sox));
             
              this.flvRecordingMetaDeltaDaoImpl.updateFlvRecordingMetaDelta(flvRecordingMetaDelta);
              counter++;
            } else {
              outputGapFullWav = inputFile;
            }
           
          }
         
//          // Strip Wave to Full Length
//          String hashFileNormalizeName = flvRecordingMetaData.getStreamName()
//                        + "_FULL_NORMALIZE.wav";
//          String outputNormalizeWav = streamFolderName + hashFileNormalizeName;
//         
//          //Normalize Sound
////          $SOX "$1" "$2" \
////             16   remix - \
////             17   highpass 100 \
////             18   norm \
////             19   compand 0.05,0.2 6:-54,-90,-36,-36,-24,-24,0,-12 0 -90 0.1 \
////             20   vad -T 0.6 -p 0.2 -t 5 \
////             21   fade 0.1 \
////             22   reverse \
////             23   vad -T 0.6 -p 0.2 -t 5 \
////             24   fade 0.1 \
////             25   reverse \
////             26   norm -0.5
//
//          String[] argv_sox_normalize = new String[] { this.getPathToSoX(),
//              outputGapFullWav, outputNormalizeWav,
//              "remix","-",
//              "highpass","100",
//              "norm",
//              "compand","0.05,0.2","6:-54,-90,-36,-36,-24,-24,0,-12","0","-90","0.1",
//              "vad","-T","0.6","-p","0.2","-t","5",
//              "fade","0.1",
//              "reverse",
//              "vad","-T","0.6","-p","0.2","-t","5",
//              "fade","0.1",
//              "reverse",
//              "norm","-0.5"};
//
//          log.debug("START startNormalizeToWaves ################# ");
//          String argv_sox_normalizeString = "";
//          for (int i = 0; i < argv_sox_normalize.length; i++) {
//            argv_sox_normalizeString +=  " "+argv_sox_normalize[i];
//            //log.debug(" i " + i + " argv-i " + argv_sox[i]);
//          }
//          log.debug("argv_sox_normalize: "+argv_sox_normalize);
//          log.debug("END endNormalizeToWaves ################# ");
//
//          returnLog.add(GenerateSWF.executeScript("normalizeWave",argv_sox_normalize));
         
         
         
          // Strip Wave to Full Length
          String hashFileFullName = flvRecordingMetaData.getStreamName()
                        + "_FULL_WAVE.wav";
          String outputFullWav = streamFolderName + hashFileFullName;

          // Calculate delta at beginning
          Long deltaTimeStartMilliSeconds = flvRecordingMetaData.getRecordStart().getTime()
                              - flvRecording.getRecordStart().getTime();
         
          Float startPadding = Float.parseFloat(deltaTimeStartMilliSeconds.toString()) / 1000;

          // Calculate delta at ending
          Long deltaTimeEndMilliSeconds = flvRecording.getRecordEnd().getTime()
                              - flvRecordingMetaData.getRecordEnd().getTime();
         
          Float endPadding = Float.parseFloat(deltaTimeEndMilliSeconds.toString()) / 1000;

          String[] argv_sox = new String[] { this.getPathToSoX(),
              outputGapFullWav, outputFullWav, "pad",
              startPadding.toString(), endPadding.toString() };

          log.debug("START addAudioToWaves ################# ");
          String padString = "";
          for (int i = 0; i < argv_sox.length; i++) {
            padString += " "+argv_sox[i];
            //log.debug(" i " + i + " argv-i " + argv_sox[i]);
          }
          log.debug("padString :: "+padString);
          log.debug("END addAudioToWaves ################# ");

          returnLog.add(GenerateSWF.executeScript("addStartEndToAudio",argv_sox));
         
          //Fix for Audio Length - Invalid Audio Length in Recorded Files
          //Audio must match 100% the Video
          log.debug("############################################");
          log.debug("Trim Audio to Full Length -- Start");
          File aFile = new File(outputFullWav);
         
          if (!aFile.exists()) {
            throw new Exception("Audio File does not exist , could not extract the Audio correctly");
          }
         
//          AudioInputStream aInputStream = AudioSystem.getAudioInputStream(aFile);
//          AudioFormat aFormat = aInputStream.getFormat();
//          long frameLength = aInputStream.getFrameLength();
//          float frameRate = aFormat.getFrameRate();
//         
//          double audioLength = Math.round(frameLength / frameRate);
//         
//          log.debug("audioLength "+audioLength);
//         
//          double audioShouldLength = (Math.round( (flvRecording.getRecordEnd().getTime() - flvRecording.getRecordStart().getTime()) / 1000))-2;
//         
//          log.debug("audioShouldLength "+audioShouldLength);
//         
//          double missingLength = audioShouldLength - audioLength;
//         
//          log.debug("missingLength "+missingLength);
//         
//          //audioLength == 100
//          //
//          //1 == audioLength
//          //(0.5 / audioLength) * audioShouldLength
//         
//          double percentage = audioShouldLength / audioLength;
//         
//          log.debug("percentage "+percentage);
//         
//          //1 => 1
//          //0.75 => 1.3333
//          //0.5 => 2
//          //0.25 => 4
//          //0.125 => 8
//         
//          double scaleFactor = 1 / percentage;
//         
//          log.debug("scaleFactor "+scaleFactor);
//         
//          //sox myout.wav outwavTempo2.wav tempo 0.85
//         
//          String hashFileTrimFullName = flvRecordingMetaData.getStreamName()
//                            + "_FULL_TRIM_WAVE.wav";
//          String outputFullTrimWav = streamFolderName + hashFileTrimFullName;
//         
//          String[] argv_sox2 = new String[] { this.getPathToSoX(),
//              outputFullWav, outputFullTrimWav, "tempo",
//              ""+scaleFactor, ""+30 };
//
//          log.debug("START trimAudioToWaves ################# ");
//          String tString = "";
//          for (int i = 0; i < argv_sox2.length; i++) {
//            tString += argv_sox2[i];
//            //log.debug(" i " + i + " argv-i " + argv_sox[i]);
//          }
//          log.debug(tString);
//          log.debug("END tAudioToWaves ################# ");
//
//          returnLog.add(GenerateSWF.executeScript("trimWave",argv_sox2));
//         
//          log.debug("Trim Audio to Full Length -- End");
//          log.debug("############################################");
         
          flvRecordingMetaData.setFullWavAudioData(hashFileFullName);
         
          //Finally add it to the row!
          listOfFullWaveFiles.add(outputFullWav);
         
        }

        this.getFlvRecordingMetaDataDaoImpl()
            .updateFlvRecordingMetaData(flvRecordingMetaData);

      }

      // Merge Wave to Full Length
      String streamFolderGeneralName = ScopeApplicationAdapter.webAppPath
          + File.separatorChar + "streams" + File.separatorChar
          + "hibernate" + File.separatorChar;

      String hashFileFullName = "INTERVIEW_"+flvRecording.getFlvRecordingId()
          + "_FINAL_WAVE.wav";
      String outputFullWav = streamFolderName + hashFileFullName;

      if (listOfFullWaveFiles.size() == 1) {

        outputFullWav = listOfFullWaveFiles.get(0);
       
      } else if (listOfFullWaveFiles.size() > 0) {

        String[] argv_full_sox = new String[listOfFullWaveFiles.size() + 3];
        argv_full_sox[0] = this.getPathToSoX();
        argv_full_sox[1] = "-m";

        int counter = 0;
        for (int i = 0; i < listOfFullWaveFiles.size(); i++) {
          argv_full_sox[2 + i] = listOfFullWaveFiles.get(i);
          counter = i;
        }
        argv_full_sox[counter + 3] = outputFullWav;

        log.debug("START mergeAudioToWaves ################# ");
        log.debug(argv_full_sox.toString());
        String iString = "";
        for (int i = 0; i < argv_full_sox.length; i++) {
          iString += argv_full_sox[i] + " ";
          //log.debug(" i " + i + " argv-i " + argv_full_sox[i]);
        }
        log.debug(iString);
        log.debug("END mergeAudioToWaves ################# ");

        returnLog.add(GenerateSWF.executeScript("mergeWave",
            argv_full_sox));
      } else {

        // create default Audio to merge it.
        // strip to content length
        String outputWav = streamFolderGeneralName + "one_second.wav";

        // Calculate delta at beginning
        Long deltaTimeMilliSeconds = flvRecording.getRecordEnd()
            .getTime()
            - flvRecording.getRecordStart().getTime();
        Float deltaPadding = (Float.parseFloat(deltaTimeMilliSeconds
            .toString()) / 1000) - 1;

        String[] argv_full_sox = new String[] { this.getPathToSoX(),
            outputWav, outputFullWav, "pad", "0",
            deltaPadding.toString() };

        log.debug("START generateSampleAudio ################# ");
        String tString = "";
        for (int i = 0; i < argv_full_sox.length; i++) {
          tString += argv_full_sox[i] + " ";
          //log.debug(" i " + i + " argv-i " + argv_full_sox[i]);
        }
        log.debug(tString);
        log.debug("END generateSampleAudio ################# ");

        returnLog.add(GenerateSWF.executeScript("mergeWave",
            argv_full_sox));

      }

      // Merge Audio with Video / Calculate resulting FLV

//      String inputScreenFullFlv = streamFolderName
//          + flvRecordingMetaDataOfScreen.getStreamName() + ".flv";

      //Start extracting image sequence
      int frameRate = 25;
     
      for (FlvRecordingMetaData flvRecordingMetaData : metaDataList) {
       
        //FLV to 24 FPS Sequence AVI
        String inputFlv = streamFolderName
              + "AV_" + flvRecordingMetaData.getStreamName() + ".flv";
       
        File inputFlvFile = new File(inputFlv);
       
        if (inputFlvFile.exists()) {
         
          //TO 24FPS AVI
         
//          String outputAVI = streamFolderName
//                    + "AV_" + flvRecordingMetaData.getStreamName() + ".avi";
//         
//          String[] argv_24AVI = new String[] { this.getPathToFFMPEG(), "-i",
//              inputFlv, "-an", "-vcodec", "copy", outputAVI };
//
//          log.debug("START generateImageSequenceAVI ################# ");
//          String tString = "";
//          for (int i = 0; i < argv_24AVI.length; i++) {
//            tString += argv_24AVI[i] + " ";
//            //log.debug(" i " + i + " argv-i " + argv_fullFLV[i]);
//          }
//          log.debug(tString);
//          log.debug("END generateImageSequenceAVI ################# ");
//
//          returnLog.add(GenerateSWF.executeScript("generateImageSequenceAVI",
//              argv_24AVI));

          //TO Image Sequence
         
          String outputMetaImageData = streamFolderName + flvRecordingMetaData.getFlvRecordingMetaDataId()
                            + File.separatorChar;
         
          //Image Folder
          File imageSequenceFolder = new File(outputMetaImageData);
          imageSequenceFolder.mkdir();
         
          String outputImages = outputMetaImageData + "image%d.png";
         
          String[] argv_imageSeq = new String[] { this.getPathToFFMPEG(), "-i",
                  inputFlv, "-r", ""+frameRate, "-s", "320x240",
                  outputImages  };

          log.debug("START generateImageSequence ################# ");
          String iString = "";
          for (int i = 0; i < argv_imageSeq.length; i++) {
            iString += argv_imageSeq[i] + " ";
            //log.debug(" i " + i + " argv-i " + argv_fullFLV[i]);
          }
          log.debug(iString);
          log.debug("END generateImageSequence ################# ");

          returnLog.add(GenerateSWF.executeScript("generateImageSequence",
              argv_imageSeq));
         
        }
       
      }
     
      //Default Image for empty interview video pods
      String defaultInterviewImage = streamFolderGeneralName + "default_interview_image.png";
      File defaultInterviewImageFile = new File (defaultInterviewImage);
     
      if (!defaultInterviewImageFile.exists()) {
        throw new Exception("defaultInterviewImageFile does not exist!");
      }
     
      //Create Folder for the output Image Sequence
      String outputImageMergedData = streamFolderName + "INTERVIEW_"
                        + flvRecording.getFlvRecordingId() + File.separatorChar;
     
      //Merged Image Folder
      File outputImageMergedDateFolder = new File(outputImageMergedData);
      outputImageMergedDateFolder.mkdir();
     
      //Generate the Single Image by sequencing
      boolean jobRunning = true;
      long currentTimeInMilliSeconds = 0;
     
      long completeLengthInSeconds = flvRecording.getRecordEnd().getTime() - flvRecording.getRecordStart().getTime();
     
      log.debug("completeLengthInSeconds :: "+completeLengthInSeconds);
     
      int sequenceCounter = 0;
     
      while (jobRunning) {
       
        //Process one Second of Movie
        String[] interviewPod1Images = new String[frameRate];
        String[] interviewPod2Images = new String[frameRate];
        int[] outputFrameNumbers = new int[frameRate];
       
        for (FlvRecordingMetaData flvRecordingMetaData : metaDataList) {
         
          long deltaStartRecording = flvRecordingMetaData.getRecordStart().getTime() - flvRecording.getRecordStart().getTime();
       
          if (flvRecording.getRecordStart().getTime() + currentTimeInMilliSeconds >= flvRecordingMetaData.getRecordStart().getTime()
              &&
              flvRecording.getRecordStart().getTime() + currentTimeInMilliSeconds <= flvRecordingMetaData.getRecordEnd().getTime()) {
           
            //Calculate which images should be in here
           
            //Calculate the relative starting point
            long thisImageSequenceStartingPoint = currentTimeInMilliSeconds - deltaStartRecording;
           
//            log.debug("-- thisImageSequenceStartingPoint "+thisImageSequenceStartingPoint );
//            log.debug("-- currentTimeInMilliSeconds "+currentTimeInMilliSeconds );
//            log.debug("-- deltaStartRecording "+deltaStartRecording );
           
            //Calculate the first and following frameRate FPS Number
            int secondToStart = Long.valueOf(thisImageSequenceStartingPoint/1000).intValue();
           
            int firstFrame = secondToStart*frameRate;
           
            //log.debug("-- secondToStart "+secondToStart + " firstFrame " + firstFrame);
           
            for (int i=0;i<frameRate;i++) {
             
              int currentImageNumber = firstFrame + i;
              currentImageNumber -= (frameRate/2); //Remove the first half seconds and fill it up with black screens
             
              //Remove the first period of Images, this is where the user has started
              //to share his Video but does not have agreed in the Flash Security Warning Dialogue
              Integer initialGapSeconds = flvRecordingMetaData.getInitialGapSeconds();
              if (initialGapSeconds != null) {
                int initialMissingImages = Double.valueOf(Math.floor((initialGapSeconds/1000) * frameRate)).intValue();
                currentImageNumber -= initialMissingImages;
              }
             
              //String roundUpName = ""+currentImageNumber;
              //int missingDecimals = maxDecimalPoint - roundUpName.length();
             
              String addZeros = "";
//              if (missingDecimals > 0) {
//                for (int tK=0;tK<missingDecimals;tK++) {
//                  addZeros += "0";
//                }
//              }
              String imageName = "image"+addZeros+currentImageNumber+".png";
             
             
              //log.debug("imageName :: "+imageName+" AT: "+sequenceCounter+ " ZT: "+missingDecimals+" AZ "+addZeros);
             
              String outputMetaImageFullData = streamFolderName + flvRecordingMetaData.getFlvRecordingMetaDataId()
                                + File.separatorChar + imageName;
             
              //log.debug("outputMetaImageFullData :: "+outputMetaImageFullData);
             
              File outputMetaImageFullDataFile = new File(outputMetaImageFullData);
             
              if (!outputMetaImageFullDataFile.exists()) {
                outputMetaImageFullData = defaultInterviewImage;
              }
             
              if (flvRecordingMetaData.getInteriewPodId() == 1) {
                interviewPod1Images[i] = outputMetaImageFullData;
              } else if (flvRecordingMetaData.getInteriewPodId() == 2){
                interviewPod2Images[i] = outputMetaImageFullData;
              }
             
            }
           
          }
         
        }
       
        //Update Sequence Count
        for (int i=0;i<frameRate;i++) {
          outputFrameNumbers[i] = sequenceCounter;
          sequenceCounter++;
        }
       
       
        //Now we should have found the needed Images to calculate, in case not we add an empty black screen
        for (int i=0;i<frameRate;i++) {
         
//          String roundUpName = ""+outputFrameNumbers[i];
//          int missingDecimals = maxDecimalPoint - roundUpName.length();
         
          String addZeros = "";
//          if (missingDecimals > 0) {
//            for (int tK=0;tK<missingDecimals;tK++) {
//              addZeros += "0";
//            }
//          }
         
          String outputImageName = outputImageMergedData + "image" + addZeros + outputFrameNumbers[i] + ".png";
         
          if (interviewPod1Images[i] == null) {
            interviewPod1Images[i] = defaultInterviewImage;
          }
          if (interviewPod2Images[i] == null) {
            interviewPod2Images[i] = defaultInterviewImage;
          }
         
          if (System.getProperty("os.name").toUpperCase().indexOf("WINDOWS") == -1) {
            String[] argv_imageMagick = new String[] { this.getPathToImageMagick(), "+append",
                interviewPod1Images[i], interviewPod2Images[i], outputImageName  };
   
  //          log.debug("START generateImageSequence ################# ");
  //          String iString = "";
  //          for (int k = 0; k < argv_imageMagick.length; k++) {
  //            iString += argv_imageMagick[k] + " ";
  //            //log.debug(" i " + i + " argv-i " + argv_fullFLV[i]);
  //          }
  //          log.debug(iString);
  //          log.debug("END generateImageSequence ################# ");
           
            //log.debug("returnLog "+returnLog);
            //log.debug("returnLog "+argv_imageMagick);
           
            returnLog.add(GenerateSWF.executeScript("generateImageSequence",
                          argv_imageMagick));
          } else {
           
//            String[] argv_imageMagick = new String[] { this.getPathToImageMagick(), "+append",
//                interviewPod1Images[i], interviewPod2Images[i], outputImageName  };
//           
//            returnLog.add(GenerateSWF.executeScript("generateImageSequence",
//                argv_imageMagick));
           
            returnLog.add(this.processImageWindows(interviewPod1Images[i], interviewPod2Images[i], outputImageName));
           
          }
        }
       
        currentTimeInMilliSeconds+=1000;
       
        double cLength = 100 * ((double)currentTimeInMilliSeconds) / ((double)completeLengthInSeconds);
       
        int progress = Double.valueOf(cLength).intValue();
       
        log.debug("completeLengthInSeconds|currentTimeInMilliSeconds " +
            completeLengthInSeconds + "|" + currentTimeInMilliSeconds + "|" + progress + "|" + cLength);
       
        FlvRecordingDaoImpl.getInstance().updateFlvRecordingProgress(flvRecording.getFlvRecordingId(), progress);
       
        if (currentTimeInMilliSeconds >= completeLengthInSeconds) {
       
          jobRunning = false;
       
        }
       
       
      }
     
      //Generate Movie by sequence of Images
     
      String imagescomplete = outputImageMergedData + "image%d.png";
     
      String[] argv_generatedMoview = null;
     
      String inputScreenFullFlv = streamFolderName + "COMPLETE_INTERVIEW_"
                      + flvRecording.getFlvRecordingId() + ".flv";

      argv_generatedMoview = new String[] { this.getPathToFFMPEG(),
          "-i", imagescomplete,
          "-r", ""+frameRate,
          "-vcodec", "flv",
          "-qmax", "1", "-qmin", "1",
          inputScreenFullFlv };

      log.debug("START generateFullBySequenceFLV ################# ");
      String tString2 = "";
      for (int i = 0; i < argv_generatedMoview.length; i++) {
        tString2 += argv_generatedMoview[i] + " ";
        //log.debug(" i " + i + " argv-i " + argv_fullFLV[i]);
      }
      log.debug(tString2);
      log.debug("END generateFullBySequenceFLV ################# ");

      returnLog.add(GenerateSWF.executeScript("generateFullBySequenceFLV",
          argv_generatedMoview));

     
      File outputFolder = new File(streamFolderGeneralName);
      if (!outputFolder.exists()) {
        outputFolder.mkdir();
      }

      String hashFileFullNameFlv = "flvRecording_"
          + flvRecording.getFlvRecordingId() + ".flv";
      String outputFullFlv = streamFolderGeneralName
          + hashFileFullNameFlv;

      // ffmpeg -vcodec flv -qscale 9.5 -r 25 -ar 22050 -ab 32k -s 320x240
      // -i
      // 65318fb5c54b1bc1b1bca077b493a914_28_12_2009_23_38_17_FINAL_WAVE.wav
      // -i 65318fb5c54b1bc1b1bca077b493a914_28_12_2009_23_38_17.flv
      // final1.flv

      int flvWidth = 640;
      int flvHeight = 240;

      flvRecording.setFlvWidth(flvWidth);
      flvRecording.setFlvHeight(flvHeight);

      String[] argv_fullFLV = null;

      argv_fullFLV = new String[] { this.getPathToFFMPEG(),
          "-r", ""+frameRate,
          "-vcodec", "flv",
          "-ar", "22050",
          "-ab", "32k",
          "-s", flvWidth + "x" + flvHeight,
          "-qmax", "1", "-qmin", "1",
          "-i", inputScreenFullFlv,
          "-i", outputFullWav,
          outputFullFlv };

      log.debug("START generateFullFLV ################# ");
      String tString = "";
      for (int i = 0; i < argv_fullFLV.length; i++) {
        tString += argv_fullFLV[i] + " ";
        //log.debug(" i " + i + " argv-i " + argv_fullFLV[i]);
      }
      log.debug(tString);
      log.debug("END generateFullFLV ################# ");

      returnLog.add(GenerateSWF.executeScript("generateFullFLV",
          argv_fullFLV));

      flvRecording.setFileHash(hashFileFullNameFlv);

      // Extract first Image for preview purpose
      // ffmpeg -i movie.flv -vcodec mjpeg -vframes 1 -an -f rawvideo -s
      // 320x240 movie.jpg

      String hashFileFullNameJPEG = "flvRecording_"
          + flvRecording.getFlvRecordingId() + ".jpg";
      String outPutJpeg = streamFolderGeneralName + hashFileFullNameJPEG;

      flvRecording.setPreviewImage(hashFileFullNameJPEG);

      String[] argv_previewFLV = new String[] { this.getPathToFFMPEG(),
          "-i", outputFullFlv, "-vcodec", "mjpeg",
          "-vframes","100",
          "-an", "-f", "rawvideo",
          "-s", flvWidth + "x" + flvHeight,
          outPutJpeg };

      log.debug("START previewFullFLV ################# ");
      log.debug(argv_previewFLV.toString());
      String kString = "";
      for (int i = 0; i < argv_previewFLV.length; i++) {
        kString += argv_previewFLV[i] + " ";
        //log.debug(" i " + i + " argv-i " + argv_previewFLV[i]);
      }
      log.debug(kString);
      log.debug("END previewFullFLV ################# ");

      returnLog.add(GenerateSWF.executeScript("generateFullFLV",
          argv_previewFLV));

     
      String alternateDownloadName = "flvRecording_"
            + flvRecording.getFlvRecordingId() + ".avi";
      String alternateDownloadFullName = streamFolderGeneralName
          + alternateDownloadName;
     
      String[] argv_alternateDownload = new String[] { this.getPathToFFMPEG(),
          "-i", outputFullFlv, alternateDownloadFullName };

      log.debug("START alternateDownLoad ################# ");
      log.debug(argv_previewFLV.toString());
      String sString = "";
      for (int i = 0; i < argv_alternateDownload.length; i++) {
        sString += argv_alternateDownload[i] + " ";
        //log.debug(" i " + i + " argv-i " + argv_previewFLV[i]);
      }
      log.debug(kString);
      log.debug("END alternateDownLoad ################# ");

      returnLog.add(GenerateSWF.executeScript("alternateDownload",
          argv_alternateDownload));     
     
      flvRecording.setAlternateDownload(alternateDownloadName);
     
      this.flvRecordingDaoImpl.updateFlvRecording(flvRecording);
     

      for (HashMap<String, Object> returnMap : returnLog) {
        this.flvRecordingLogDaoImpl.addFLVRecordingLog(
            "generateFFMPEG", flvRecording, returnMap);
      }
     
      //Delete Wave Files
      for (String fileName : listOfFullWaveFiles) {
        File audio = new File(fileName);
        if (audio.exists()) {
          audio.delete();
        }
      }
     
      //Delete all Image temp dirs
      for (FlvRecordingMetaData flvRecordingMetaData : metaDataList) {
        String outputMetaImageFullData = streamFolderName
                + flvRecordingMetaData.getFlvRecordingMetaDataId()
                + File.separatorChar ;
         
        //this.deleteDirectory(new File(outputMetaImageFullData));
      }
     
      //this.deleteDirectory(new File(outputImageMergedData));

    } catch (Exception err) {
      log.error("[stripAudioFromFLVs]", err);
    }
  }
 
  public boolean deleteDirectory(File path) throws Exception {
      if( path.exists() ) {
        File[] files = path.listFiles();
        for(int i=0; i<files.length; i++) {
           if(files[i].isDirectory()) {
             deleteDirectory(files[i]);
           }
           else {
             files[i].delete();
           }
        }
      }
      return( path.delete() );
    }

 
  public HashMap<String,Object> processImageWindows(String file1, String file2, String file3) {
        HashMap<String,Object> returnMap = new HashMap<String,Object>();
        returnMap.put("process", "processImageWindows");
        try {
               
                //Init variables
                String[] cmd;
                String executable_fileName = "";       
                String pathToIMagick = this.getPathToImageMagick();
               
                Date tnow = new Date();
                String runtimeFile = "interviewMerge"+tnow.getTime()+".bat";
               
                //String runtimeFile = "interviewMerge.bat";
                executable_fileName = ScopeApplicationAdapter.batchFileFir
                       + runtimeFile;
               
                cmd = new String[1];
                //cmd[0] = "cmd.exe";
                //cmd[1] = "/C";
                //cmd[2] = "start";
                cmd[0] = executable_fileName;
               
                //log.debug("executable_fileName: "+executable_fileName);
               
                //Create the Content of the Converter Script (.bat or .sh File)
                String fileContent = pathToIMagick +
                                " " + file1 +
                                " " + file2 +
                                " " + "+append" +
                                " " + file3 +
                                ScopeApplicationAdapter.lineSeperator + "exit";
                       
                File previous = new File(executable_fileName);
                if (previous.exists()) {
                  previous.delete();
            }
               
                //execute the Script
                FileOutputStream fos = new FileOutputStream(executable_fileName);
                fos.write(fileContent.getBytes());
                fos.close();
               
                File now = new File(executable_fileName);
                now.setExecutable(true);
               
                Runtime rt = Runtime.getRuntime();                     
                returnMap.put("command", cmd.toString());
                Process proc = rt.exec(cmd);
               
                InputStream stderr = proc.getErrorStream();
                InputStreamReader isr = new InputStreamReader(stderr);
                BufferedReader br = new BufferedReader(isr);
                String line = null;
                String error = "";
                while ((line = br.readLine()) != null){
                        error += line;
                        //log.debug("line: "+line);
                }
                returnMap.put("error", error);
                int exitVal = proc.waitFor();
                //log.debug("exitVal: "+exitVal);
                returnMap.put("exitValue", exitVal);
               
                if (now.exists()) {
                  now.delete();
                }
               
                return returnMap;
        } catch (Throwable t) {
                t.printStackTrace();
                returnMap.put("error", t.getMessage());
                returnMap.put("exitValue", -1);
                return returnMap;
        }
  }
 

}
TOP

Related Classes of org.openmeetings.app.data.flvrecord.converter.FlvInterviewConverter

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.