protected ICodec getVideoEncodingICodec(ICodec.Type inputICodecType, String outputURL) {

    IContainerFormat iContainerFormat = _outputIContainer.getContainerFormat();

    String outputFormat = iContainerFormat.getOutputFormatShortName();

    if (outputFormat.equals("mp4")) {
      return ICodec.findEncodingCodec(ICodec.ID.CODEC_ID_H264);
    } else {
      return ICodec.guessEncodingCodec(null, null, outputURL, null, inputICodecType);
    }
  }
  @Override
  protected ICodec getAudioEncodingICodec(IContainer outputIContainer) {
    IContainerFormat iContainerFormat = outputIContainer.getContainerFormat();

    String outputFormat = iContainerFormat.getOutputFormatShortName();

    if (outputFormat.equals("ogg")) {
      return ICodec.findEncodingCodec(ICodec.ID.CODEC_ID_VORBIS);
    }

    return super.getAudioEncodingICodec(outputIContainer);
  }
  @Override
  protected int getAudioEncodingChannels(IContainer outputIContainer, int channels) {

    IContainerFormat iContainerFormat = outputIContainer.getContainerFormat();

    String outputFormat = iContainerFormat.getOutputFormatShortName();

    if (outputFormat.equals("ogg")) {
      return 2;
    }

    return super.getAudioEncodingChannels(outputIContainer, channels);
  }
  public void open(VirtualInputFile input) {

    close();

    this.input = input;

    container = IContainer.make();
    format = IContainerFormat.make();
    packet = IPacket.make();

    // open the input video file
    int success = container.open(input, format, true, true);
    /*		int success = -1;

    		try {
    			RandomAccessFile f = new RandomAccessFile("j:/grey.avi", "r");
    			success = container.open(f, Type.READ, format);

    		} catch (FileNotFoundException e) {
    			// TODO Auto-generated catch block
    			e.printStackTrace();
    		}
    */

    if (success < 0) {

      throw new RuntimeException(
          "XUGGLER DECODER: could not open input: " + input.getLocation().getDecodedURL());
    }

    for (int streamIndex = 0; streamIndex < container.getNumStreams(); streamIndex++) {

      IStreamCoder coder = container.getStream(streamIndex).getStreamCoder();

      switch (coder.getCodecType()) {
        case CODEC_TYPE_VIDEO:
          {
            videoStream = coder;
            videoStreamIndex = streamIndex;
            break;
          }
        case CODEC_TYPE_AUDIO:
          {
            audioStream = coder;
            audioStreamIndex = streamIndex;
            break;
          }
        default:
          {
            break;
          }
      }
    }

    setDecodeMode(DecodeMode.NORMAL);
  }
  private void analyzeTransportStream(HLSMediaFile file, String tsURL) {
    System.out.println(tsURL);
    IContainer container = IContainer.make();
    IContainerFormat format = IContainerFormat.make();
    format.setInputFormat(".ts");

    int returnCode = container.open(tsURL, IContainer.Type.READ, format);
    if (returnCode >= 0) {

      BigDecimal bitRate = BigDecimal.valueOf(container.getBitRate());
      BigDecimal duration = BigDecimal.valueOf(container.getDuration());
      BigDecimal inSeconds = duration.divide(BigDecimal.valueOf(1000000));
      System.out.println(bitRate);
      System.out.println(inSeconds.toString());
      TransportStreamFileInfo tsFileInfo = new TransportStreamFileInfo();
      tsFileInfo.setDuration(inSeconds);
      tsFileInfo.setCalculatedBitRate(bitRate);
      tsFileInfo.setFileName(tsURL);
      file.addTsFiles(tsFileInfo);
    }
    container.close();
  }
  protected void doConvert() throws Exception {
    _inputIContainer = IContainer.make();
    _outputIContainer = IContainer.make();

    openContainer(_inputIContainer, _inputURL, false);
    openContainer(_outputIContainer, _outputURL, true);

    int inputStreamsCount = _inputIContainer.getNumStreams();

    if (inputStreamsCount < 0) {
      throw new RuntimeException("Input URL does not have any streams");
    }

    IContainerFormat iContainerFormat = _outputIContainer.getContainerFormat();

    _outputVideoFormat = iContainerFormat.getOutputFormatShortName();

    IAudioResampler[] iAudioResamplers = new IAudioResampler[inputStreamsCount];
    IVideoResampler[] iVideoResamplers = new IVideoResampler[inputStreamsCount];

    IAudioSamples[] inputIAudioSamples = new IAudioSamples[inputStreamsCount];
    IAudioSamples[] outputIAudioSamples = new IAudioSamples[inputStreamsCount];

    IVideoPicture[] inputIVideoPictures = new IVideoPicture[inputStreamsCount];
    IVideoPicture[] outputIVideoPictures = new IVideoPicture[inputStreamsCount];

    IStream[] outputIStreams = new IStream[inputStreamsCount];

    IStreamCoder[] inputIStreamCoders = new IStreamCoder[inputStreamsCount];
    IStreamCoder[] outputIStreamCoders = new IStreamCoder[inputStreamsCount];

    for (int i = 0; i < inputStreamsCount; i++) {
      IStream inputIStream = _inputIContainer.getStream(i);

      IStreamCoder inputIStreamCoder = inputIStream.getStreamCoder();

      inputIStreamCoders[i] = inputIStreamCoder;

      ICodec.Type inputICodecType = inputIStreamCoder.getCodecType();

      if (inputICodecType == ICodec.Type.CODEC_TYPE_AUDIO) {
        prepareAudio(
            iAudioResamplers,
            inputIAudioSamples,
            outputIAudioSamples,
            inputIStreamCoder,
            outputIStreamCoders,
            _outputIContainer,
            outputIStreams,
            inputICodecType,
            _outputURL,
            i);
      } else if (inputICodecType == ICodec.Type.CODEC_TYPE_VIDEO) {
        prepareVideo(
            iVideoResamplers,
            inputIVideoPictures,
            outputIVideoPictures,
            inputIStreamCoder,
            outputIStreamCoders,
            _outputIContainer,
            outputIStreams,
            inputICodecType,
            _outputURL,
            i);
      }

      openStreamCoder(inputIStreamCoders[i]);
      openStreamCoder(outputIStreamCoders[i]);
    }

    if (_outputIContainer.writeHeader() < 0) {
      throw new RuntimeException("Unable to write container header");
    }

    boolean keyPacketFound = false;
    int nonKeyAfterKeyCount = 0;
    boolean onlyDecodeKeyPackets = false;
    int previousPacketSize = -1;

    IPacket inputIPacket = IPacket.make();
    IPacket outputIPacket = IPacket.make();

    while (_inputIContainer.readNextPacket(inputIPacket) == 0) {
      if (_log.isDebugEnabled()) {
        _log.debug("Current packet size " + inputIPacket.getSize());
      }

      int streamIndex = inputIPacket.getStreamIndex();

      IStreamCoder inputIStreamCoder = inputIStreamCoders[streamIndex];
      IStreamCoder outputIStreamCoder = outputIStreamCoders[streamIndex];

      if (outputIStreamCoder == null) {
        continue;
      }

      IStream iStream = _inputIContainer.getStream(streamIndex);

      long timeStampOffset = getStreamTimeStampOffset(iStream);

      if (inputIStreamCoder.getCodecType() == ICodec.Type.CODEC_TYPE_AUDIO) {

        decodeAudio(
            iAudioResamplers[streamIndex],
            inputIAudioSamples[streamIndex],
            outputIAudioSamples[streamIndex],
            inputIPacket,
            outputIPacket,
            inputIStreamCoder,
            outputIStreamCoder,
            _outputIContainer,
            inputIPacket.getSize(),
            previousPacketSize,
            streamIndex,
            timeStampOffset);
      } else if (inputIStreamCoder.getCodecType() == ICodec.Type.CODEC_TYPE_VIDEO) {

        keyPacketFound = isKeyPacketFound(inputIPacket, keyPacketFound);

        nonKeyAfterKeyCount =
            countNonKeyAfterKey(inputIPacket, keyPacketFound, nonKeyAfterKeyCount);

        if (isStartDecoding(
            inputIPacket,
            inputIStreamCoder,
            keyPacketFound,
            nonKeyAfterKeyCount,
            onlyDecodeKeyPackets)) {

          int value =
              decodeVideo(
                  iVideoResamplers[streamIndex],
                  inputIVideoPictures[streamIndex],
                  outputIVideoPictures[streamIndex],
                  inputIPacket,
                  outputIPacket,
                  inputIStreamCoder,
                  outputIStreamCoder,
                  _outputIContainer,
                  null,
                  null,
                  0,
                  0,
                  timeStampOffset);

          if (value <= 0) {
            if (inputIPacket.isKey()) {
              throw new RuntimeException("Unable to decode video stream " + streamIndex);
            }

            onlyDecodeKeyPackets = true;

            continue;
          }
        } else {
          if (_log.isDebugEnabled()) {
            _log.debug("Do not decode video stream " + streamIndex);
          }
        }
      }

      previousPacketSize = inputIPacket.getSize();
    }

    flush(outputIStreamCoders, _outputIContainer);

    if (_outputIContainer.writeTrailer() < 0) {
      throw new RuntimeException("Unable to write trailer to output file");
    }

    cleanUp(iAudioResamplers, iVideoResamplers);
    cleanUp(inputIAudioSamples, outputIAudioSamples);
    cleanUp(inputIVideoPictures, outputIVideoPictures);
    cleanUp(inputIStreamCoders, outputIStreamCoders);
    cleanUp(inputIPacket, outputIPacket);
  }
  /**
   * The playSong method is responsible for opening a Xuggler container to play song at provided
   * location.
   *
   * @param songURL The location of the song to play (local file path or url)
   */
  public void playSong(String songURL) {

    IContainer container = IContainer.make();

    IContainerFormat format = IContainerFormat.make();

    // Stream format must currently be mp3
    format.setInputFormat("mp3");

    //		int s = container.setInputBufferLength(6270);
    //
    //		if(s < 0){
    //			logger.warn("Input buffer was not set to desired length");
    //		}

    // Probe size value must be >50 for some reason. Native libraries throw an exception if it's
    // <50. Measured in bytes.
    if (container.setProperty("probesize", 50) < 0) {
      logger.warn("Probe size not set for input container.");
    }

    if (container.setProperty("analyzeduration", 1) < 0) {
      logger.warn("Analyze duration not changed for input container.");
    }

    container.setFlag(IContainer.Flags.FLAG_NONBLOCK, true);

    if (container.open(songURL, Type.READ, format, true, false) < 0) {
      throw new IllegalArgumentException("stream not found");
    }

    int numStreams = container.getNumStreams();

    // long streamRec = System.currentTimeMillis();

    logger.info("Number of Audio streams detected {}", numStreams);

    IPacket packet = IPacket.make();
    IStream stream = null;
    IStreamCoder audioCoder = null;

    Map<Integer, IStreamCoder> knownStreams = new HashMap<Integer, IStreamCoder>();

    long previousValue = 0;

    while (container.readNextPacket(packet) >= 0 && alive) {

      if (packet.isComplete()) {

        if (knownStreams.get(packet.getStreamIndex()) == null) {
          container.queryStreamMetaData(); // This method tends to take awhile when reading a stream
          stream = container.getStream(packet.getStreamIndex());
          knownStreams.put(packet.getStreamIndex(), stream.getStreamCoder());

          audioCoder = knownStreams.get(packet.getStreamIndex());

          audioCoder.setTimeBase(stream.getTimeBase());
        }

        if (!audioCoder.isOpen()) {
          if (audioCoder.open(null, null) < 0) {
            throw new RuntimeException("could not open audio decoder for container");
          }

          openSound(audioCoder);

          // System.out.println("Opening sound  " + (System.currentTimeMillis() - streamRec));
        }

        // System.err.println(audioCoder.getNumDroppedFrames());

        int offset = 0;

        IAudioSamples samples = IAudioSamples.make(1024, audioCoder.getChannels());

        while (offset < packet.getSize() && alive) {

          // Wait until the state is playing
          while (state != PlayBack_State.PLAYING) {

            if (state == PlayBack_State.TEARDOWN) {
              break;
            } else {
              try {
                synchronized (LOCK_OBJECT) {
                  // mLine.drain();
                  mLine.flush();
                  mLine.stop();

                  LOCK_OBJECT.wait();

                  mLine.start();
                }
              } catch (InterruptedException e) {
                logger.error("", e);
              }
            }
          }

          int bytesDecoded = audioCoder.decodeAudio(samples, packet, offset);

          if (bytesDecoded < 0) {
            logger.warn("Error occurred decoding audio");
            break;
            // throw new RuntimeException("got error decoding audio");
          }

          offset += bytesDecoded;

          if (samples.isComplete() && alive) {
            playJavaSound(samples);
          }

          // Send the time stamp to the GUI for updating the progress bar
          long newValue = (long) (packet.getTimeStamp() * packet.getTimeBase().getValue());

          // Update GUI every second that the stream is playing
          if (newValue > previousValue) {
            callback.notifyGUISongProgress(newValue);
            callback.isStreaming(true);
            previousValue = newValue;

            if (newValue == streamInfo.getSongDuration()) {
              alive = false;
            }
          }
        }
      }
    }

    closeJavaSound();

    if (audioCoder != null) {
      audioCoder.close();
      audioCoder = null;
    }
    if (container != null) {
      container.close();
      container = null;
    }
  }