Package org.openmeetings.app.data.flvrecord.listener

Source Code of org.openmeetings.app.data.flvrecord.listener.StreamTranscodingListener

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

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;

import org.apache.mina.core.buffer.IoBuffer;
//import org.openmeetings.app.data.flvrecord.FlvRecordingHelperDaoImpl;
import org.openmeetings.app.data.flvrecord.FlvRecordingMetaDeltaDaoImpl;
//import org.openmeetings.app.hibernate.beans.flvrecord.FlvRecordingHelper;
import org.openmeetings.app.persistence.beans.flvrecord.FlvRecordingMetaDelta;
import org.openmeetings.app.remote.red5.ScopeApplicationAdapter;
import org.openmeetings.utils.math.CalendarPatterns;
import org.red5.io.IStreamableFile;
import org.red5.io.IStreamableFileFactory;
import org.red5.io.IStreamableFileService;
import org.red5.io.ITag;
import org.red5.io.ITagWriter;
import org.red5.io.StreamableFileFactory;
import org.red5.io.flv.impl.FLVWriter;
import org.red5.io.flv.impl.Tag;
import org.red5.logging.Red5LoggerFactory;
import org.red5.server.api.IScope;
import org.red5.server.api.ScopeUtils;
import org.red5.server.api.stream.IBroadcastStream;
import org.red5.server.api.stream.IStreamListener;
import org.red5.server.api.stream.IStreamPacket;
import org.red5.server.net.rtmp.event.SerializeUtils;
import org.slf4j.Logger;

public class StreamTranscodingListener implements IStreamListener {
 
  private ITagWriter writer = null;
 
  private File file;
 
  private boolean debug = false;
 
  private IScope scope;
 
  private int startTimeStamp = -1;
 
  private int lastTimeStamp = -1;
 
  private int lastStreamPacketTimeStamp = -1;
  private Date startedSessionTimeDate = null;
 
  private long byteCount = 0;

  private String folderPath = null;

  private Long flvRecordingMetaDataId = null;
  private List<FlvRecordingMetaDelta> flvRecordingMetaDeltas;
  //private Long flvRecordingId = null;

  private String streamName = "";

  private boolean isClosed = false;

  private boolean isScreenData = false;

  private int duration;
 
  private static final Logger log = Red5LoggerFactory.getLogger(StreamTranscodingListener.class, ScopeApplicationAdapter.webAppRootKey);

 
  public StreamTranscodingListener(String streamName, IScope scope,
      Long flvRecordingMetaDataId, boolean isScreenData) {
    super();
    this.startedSessionTimeDate = new Date();
    this.isScreenData  = isScreenData;
    this.streamName  = streamName;
    this.flvRecordingMetaDataId = flvRecordingMetaDataId;
    this.flvRecordingMetaDeltas = new LinkedList<FlvRecordingMetaDelta>();
    //this.flvRecordingId = flvRecordingId;
    this.scope = scope;
  }

  public Long getFlvRecordingMetaDataId() {
    return flvRecordingMetaDataId;
  }

  public void packetReceived(IBroadcastStream broadcastStream, IStreamPacket streampacket) {
    // TODO Auto-generated method stub
    try {
     
      if (this.isClosed) {
        //Already closed this One
        return;
      }
     
      if (this.isScreenData) {
        //Screen Recorder has No Audio
        if (streampacket.getDataType() == 8) {
          return;
        }
      } else {
        //Audio Recorder needs no Video
        if (streampacket.getDataType() == 9) {
          return;
        }
      }
     
      if (startTimeStamp == -1) {
        startTimeStamp = streampacket.getTimestamp();
      }
     
      if (streampacket.getTimestamp() <= 0) {
        log.warn("Negative TimeStamp");
        return;
      }
     
      IoBuffer data = streampacket.getData().asReadOnlyBuffer();
     
      if (data.limit() == 0) {
        return;
      }
     
      this.byteCount += data.limit();

      long deltaTime = 0;
     
      //log.debug("hasAudio :: "+streampacket.getDataType()); //8 == audio data
     
      if (writer == null) {
       
        File folder = new File(ScopeApplicationAdapter.webAppPath + File.separatorChar +
                  "streams" + File.separatorChar +
                  this.scope.getName());
       
        if (!folder.exists()) {
          folder.mkdir();
        }
       
        String flvName = ScopeApplicationAdapter.webAppPath + File.separatorChar +
                    "streams" + File.separatorChar +
                    this.scope.getName() + File.separatorChar +
                    this.streamName+".flv";
       
        file = new File(flvName);
       
        if (debug) {
         
          this.folderPath  = ScopeApplicationAdapter.webAppPath + File.separatorChar + file.getName().substring(0, file.getName().length()-4);
         
          File folder_debug = new File (folderPath);
          if (!folder_debug.exists()) {
            folder_debug.mkdir();
          }
        }
       
        init();
        //writer = new FLVWriter(,false);
        //writer.writeHeader();
      }
     
      if (streampacket.getDataType() == 8) {
       
        int timeStamp = streampacket.getTimestamp();
       
        this.lastStreamPacketTimeStamp = streampacket.getTimestamp();
       
        timeStamp -= startTimeStamp;
       
        if (lastTimeStamp == -1) {
          deltaTime = timeStamp;
        } else {
          deltaTime = timeStamp - lastTimeStamp;
        }
       
        lastTimeStamp = timeStamp;
       
        //log.debug("---- Is Audio Data :: "+streampacket.getTimestamp());
        //log.debug("---- Is Audio Length :: "+streampacket.getData().array().length);
       
        //log.debug("hasAudio :: "+streampacket.getTimestamp());
        //audioTs += streampacket.getTimestamp();
 
        //IoBuffer audioData = streampacket.getData().asReadOnlyBuffer();
        //byte[] data = SerializeUtils.ByteBufferToByteArray( audioData );
       
       
        //Try to fix missing packets, Standard packet Sizes are 46/47 ms long
       
        if (deltaTime > 55){
         
          FlvRecordingMetaDelta flvRecordingMetaDelta = new FlvRecordingMetaDelta();
         
          flvRecordingMetaDelta.setDeltaTime(deltaTime);
          flvRecordingMetaDelta.setFlvRecordingMetaDataId(this.flvRecordingMetaDataId);
          flvRecordingMetaDelta.setTimeStamp(timeStamp);
          flvRecordingMetaDelta.setIsEndPadding(false);
          flvRecordingMetaDelta.setDataLengthPacket(data.limit());
          flvRecordingMetaDelta.setReceivedAudioDataLength(this.byteCount);
          flvRecordingMetaDelta.setStartTime(this.startedSessionTimeDate);
         
         
          Date current_date = new Date();
          Long deltaTimeStamp = this.startedSessionTimeDate.getTime() - current_date.getTime();
         
          this.duration = Math.max(this.duration, timeStamp + this.writer.getOffset());
          flvRecordingMetaDelta.setDuration(this.duration);
         
          Long missingTime = deltaTimeStamp - timeStamp;
         
          flvRecordingMetaDelta.setMissingTime(missingTime);
         
          flvRecordingMetaDelta.setCurrentTime(current_date);
          flvRecordingMetaDelta.setDeltaTimeStamp(deltaTimeStamp);
          flvRecordingMetaDelta.setStartTimeStamp(startTimeStamp);
         
         
          this.flvRecordingMetaDeltas.add(flvRecordingMetaDelta);
         
          //Trying to simulate Packets, does not work, Packets must contains some decoded header Information
//          int numberOfMissingPackets = (int) Math.round(deltaTime/47);
//         
//          log.debug("deltaTime :: numberOfMissingPackets "+deltaTime+" :: "+numberOfMissingPackets);
//         
//          for (int i=0;i<numberOfMissingPackets;i++){
//           
//            ITag tag = new Tag();
//                 
//                  tag.setDataType(streampacket.getDataType());
//                 
//                  IoBuffer data = FLVWriterHelper.getAudioBuffer();
//     
//                  log.debug("write packet to :: "+timeStamp + (numberOfMissingPackets * 47));
//                 
//            tag.setBodySize(data.limit());
//            tag.setTimestamp(timeStamp + (numberOfMissingPackets * 47));
//            tag.setBody(data);
//           
//            //writer.writeTag(tag);
//           
//          }
         
        }
             
              ITag tag = new Tag();
              tag.setDataType(streampacket.getDataType());
             
              //log.debug("data.limit() :: "+data.limit());
        tag.setBodySize(data.limit());
        tag.setTimestamp(timeStamp);
        tag.setBody(data);
       
        //log.debug("duration: "+flvWriter.getDuration());
       
        if (debug) {
         
          String filePath = folderPath + File.separatorChar
              + "Packet"
              +"_t_"+tag.getTimestamp()
              +"_d_"+deltaTime
              +"_s_"+tag.getBodySize()
              +".flv";
         
          //File out = new File();
         
          FLVDebugWriter flvWriterDebug = new FLVDebugWriter( new File( filePath ), false);
         
          flvWriterDebug.writeBytesFromTag(streampacket.getData().asReadOnlyBuffer());

          flvWriterDebug.closeBytesFile();
         
        }

        writer.writeTag(tag);
 
      } else if (streampacket.getDataType() == 9) {
       
        //Video data is handled just without calculating deltas
        int timeStamp = streampacket.getTimestamp();
       
        timeStamp -= startTimeStamp;
       
        ITag tag = new Tag();
              tag.setDataType(streampacket.getDataType());
             
              //log.debug("data.limit() :: "+data.limit());
        tag.setBodySize(data.limit());
        tag.setTimestamp(timeStamp);
        tag.setBody(data);
       
        writer.writeTag(tag);
       
      }
     
      //log.debug("hasAudio :: "+broadcastStream.getCodecInfo().hasAudio());
     
      //log.debug("Audio codec Name :: "+broadcastStream.getCodecInfo().getAudioCodecName());
      //log.debug("Data Length "+streampacket.getData()
      //streampacket.getData()
     
      //broadcastStream.getProvider()
     
    } catch (IOException e) {
      log.error("[packetReceived]",e);
    } catch (Exception e) {
      log.error("[packetReceived]",e);
    }
  }
 
  /**

     * Initialization

     *

     * @throws IOException          I/O exception

     */

    private void init() throws IOException {

   
    IStreamableFileFactory factory = (IStreamableFileFactory) ScopeUtils

        .getScopeService(scope, IStreamableFileFactory.class,

            StreamableFileFactory.class);

    File folder = file.getParentFile();

    if (!folder.exists()) {

      if (!folder.mkdirs()) {

        throw new IOException("Could not create parent folder");

      }

    }

    if (!file.isFile()) {

      // Maybe the (previously existing) file has been deleted

      file.createNewFile();

    } else if (!file.canWrite()) {

      throw new IOException("The file is read-only");

    }

    IStreamableFileService service = factory.getService(file);

    IStreamableFile flv = service.getStreamableFile(file);

    writer = flv.getWriter();

  }
   
  public void closeStream() throws Exception {
    if (writer != null && !this.isClosed) {
      try {
       
        log.debug("#################### -start- closeStream ########################");
        log.debug("#################### -start- closeStream ########################");
        FLVWriter flvWriter = (FLVWriter) writer;
        //log.debug("duration: "+flvWriter.getDuration());
        //log.debug(writer.getClass().getName());
       
        writer.close();
       
        this.isClosed  = true;
       
        if (!this.isScreenData) {
         
          //We do not add any End Padding or count the gaps for the Screen Data,
          //cause there is no!
         
          long deltaRecordingTime = new Date().getTime() - this.startedSessionTimeDate.getTime();
          
          log.debug("lastTimeStamp :: "+this.lastTimeStamp);
          log.debug("lastStreamPacketTimeStamp :: "+this.lastStreamPacketTimeStamp);
          log.debug("deltaRecordingTime :: "+deltaRecordingTime);
         
          long deltaTimePaddingEnd = deltaRecordingTime - this.lastTimeStamp;
         
          log.debug("deltaTimePaddingEnd :: "+deltaTimePaddingEnd);
         
          FlvRecordingMetaDelta flvRecordingMetaDelta = new FlvRecordingMetaDelta();
         
          flvRecordingMetaDelta.setDeltaTime(deltaTimePaddingEnd);
          flvRecordingMetaDelta.setFlvRecordingMetaDataId(this.flvRecordingMetaDataId);
          flvRecordingMetaDelta.setTimeStamp(this.lastTimeStamp);
          flvRecordingMetaDelta.setIsEndPadding(true);
          flvRecordingMetaDelta.setDataLengthPacket(null);
          flvRecordingMetaDelta.setReceivedAudioDataLength(this.byteCount);
          flvRecordingMetaDelta.setStartTime(this.startedSessionTimeDate);
          flvRecordingMetaDelta.setCurrentTime(new Date());
         
          this.flvRecordingMetaDeltas.add(flvRecordingMetaDelta);
         
        }
       
        for (FlvRecordingMetaDelta flvRecordingMetaDeltaLoop : this.flvRecordingMetaDeltas) {
         
          FlvRecordingMetaDeltaDaoImpl.getInstance().addFlvRecordingMetaDelta(flvRecordingMetaDeltaLoop);
         
        }
       
      } catch (Exception err) {
        log.error("[closeStream]",err);
      }
      log.debug("#################### -end- closeStream ########################");
      log.debug("#################### -end- closeStream ########################");
    }
  }

  public void streamResetEvent() {
    // TODO Auto-generated method stub
   
  }
 
}
TOP

Related Classes of org.openmeetings.app.data.flvrecord.listener.StreamTranscodingListener

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.