protected void initVideoFrameRate(Properties videoProperties) {
    int numerator =
        GetterUtil.getInteger(
            videoProperties.getProperty(
                PropsKeys.DL_FILE_ENTRY_PREVIEW_VIDEO_FRAME_RATE_NUMERATOR
                    + "["
                    + _videoContainer
                    + "]"));
    int denominator =
        GetterUtil.getInteger(
            videoProperties.getProperty(
                PropsKeys.DL_FILE_ENTRY_PREVIEW_VIDEO_FRAME_RATE_DENOMINATOR
                    + StringPool.OPEN_BRACKET
                    + _videoContainer
                    + StringPool.CLOSE_BRACKET));

    if ((numerator > 0) && (denominator > 0)) {
      _videoFrameRate = IRational.make(numerator, denominator);

      if (_log.isInfoEnabled()) {
        _log.info(
            "Default frame rate for "
                + _videoContainer
                + " configured to "
                + _videoFrameRate.getNumerator()
                + "/"
                + _videoFrameRate.getDenominator());
      }
    }
  }
  protected void initVideoFrameRateMap(Properties videoProperties) {
    _videoFrameRateMap = new HashMap<String, IRational>();

    for (String previewVideoContainer : _previewVideoContainers) {
      int numerator =
          GetterUtil.getInteger(
              videoProperties.getProperty(
                  PropsKeys.DL_FILE_ENTRY_PREVIEW_VIDEO_FRAME_RATE_NUMERATOR
                      + "["
                      + previewVideoContainer
                      + "]"));
      int denominator =
          GetterUtil.getInteger(
              videoProperties.getProperty(
                  PropsKeys.DL_FILE_ENTRY_PREVIEW_VIDEO_FRAME_RATE_DENOMINATOR
                      + StringPool.OPEN_BRACKET
                      + previewVideoContainer
                      + StringPool.CLOSE_BRACKET));

      if ((numerator > 0) && (denominator > 0)) {
        IRational iRational = IRational.make(numerator, denominator);

        _videoFrameRateMap.put(previewVideoContainer, iRational);

        if (_log.isInfoEnabled()) {
          _log.info(
              "Frame rate for "
                  + previewVideoContainer
                  + " set to "
                  + iRational.getNumerator()
                  + "/"
                  + iRational.getDenominator());
        }
      }
    }
  }
  protected void prepareVideo(
      IVideoResampler[] iVideoResamplers,
      IVideoPicture[] inputIVideoPictures,
      IVideoPicture[] outputIVideoPictures,
      IStreamCoder inputIStreamCoder,
      IStreamCoder[] outputIStreamCoders,
      IContainer outputIContainer,
      IStream[] outputIStreams,
      ICodec.Type inputICodecType,
      String outputURL,
      int index)
      throws Exception {

    IStream outputIStream = outputIContainer.addNewStream(index);

    outputIStreams[index] = outputIStream;

    IStreamCoder outputIStreamCoder = outputIStream.getStreamCoder();

    outputIStreamCoders[index] = outputIStreamCoder;

    int bitRate = inputIStreamCoder.getBitRate();

    if (_log.isInfoEnabled()) {
      _log.info("Original video bitrate " + bitRate);
    }

    if (bitRate == 0) {
      bitRate =
          GetterUtil.getInteger(_videoBitRateMap.get(_outputVideoFormat), _VIDEO_BIT_RATE_DEFAULT);
    } else if (bitRate > _VIDEO_BIT_RATE_MAX) {
      bitRate = _VIDEO_BIT_RATE_MAX;
    }

    if (_log.isInfoEnabled()) {
      _log.info("Modified video bitrate " + bitRate);
    }

    outputIStreamCoder.setBitRate(bitRate);

    ICodec iCodec = ICodec.guessEncodingCodec(null, null, outputURL, null, inputICodecType);

    if (_outputVideoFormat.equals("mp4")) {
      iCodec = ICodec.findEncodingCodec(ICodec.ID.CODEC_ID_H264);
    }

    if (iCodec == null) {
      throw new RuntimeException(
          "Unable to determine " + inputICodecType + " encoder for " + outputURL);
    }

    outputIStreamCoder.setCodec(iCodec);

    IRational iRational = inputIStreamCoder.getFrameRate();

    if (_log.isInfoEnabled()) {
      _log.info(
          "Original frame rate " + iRational.getNumerator() + "/" + iRational.getDenominator());
    }

    if (_videoFrameRateMap.containsKey(_outputVideoFormat)) {
      iRational = _videoFrameRateMap.get(_outputVideoFormat);
    }

    if (_log.isInfoEnabled()) {
      _log.info(
          "Modified frame rate " + iRational.getNumerator() + "/" + iRational.getDenominator());
    }

    outputIStreamCoder.setFrameRate(iRational);

    if (inputIStreamCoder.getHeight() <= 0) {
      throw new RuntimeException("Unable to determine height for " + _inputURL);
    }

    outputIStreamCoder.setHeight(_height);

    outputIStreamCoder.setPixelType(Type.YUV420P);
    outputIStreamCoder.setTimeBase(
        IRational.make(iRational.getDenominator(), iRational.getNumerator()));

    if (inputIStreamCoder.getWidth() <= 0) {
      throw new RuntimeException("Unable to determine width for " + _inputURL);
    }

    outputIStreamCoder.setWidth(_width);

    iVideoResamplers[index] =
        createIVideoResampler(inputIStreamCoder, outputIStreamCoder, _height, _width);

    inputIVideoPictures[index] =
        IVideoPicture.make(
            inputIStreamCoder.getPixelType(),
            inputIStreamCoder.getWidth(),
            inputIStreamCoder.getHeight());
    outputIVideoPictures[index] =
        IVideoPicture.make(
            outputIStreamCoder.getPixelType(),
            outputIStreamCoder.getWidth(),
            outputIStreamCoder.getHeight());

    ICodec.ID iCodecID = iCodec.getID();

    if (iCodecID.equals(ICodec.ID.CODEC_ID_H264)) {
      Configuration.configure(_ffpresetProperties, outputIStreamCoder);
    }
  }
  protected void prepareVideo(
      IVideoResampler[] iVideoResamplers,
      IVideoPicture[] inputIVideoPictures,
      IVideoPicture[] outputIVideoPictures,
      IStreamCoder inputIStreamCoder,
      IStreamCoder[] outputIStreamCoders,
      IContainer outputIContainer,
      IStream[] outputIStreams,
      ICodec.Type inputICodecType,
      String outputURL,
      int index)
      throws Exception {

    ICodec iCodec = getVideoEncodingICodec(inputICodecType, outputURL);

    if (iCodec == null) {
      throw new RuntimeException(
          "Unable to determine " + inputICodecType + " encoder for " + outputURL);
    }

    IStream outputIStream = outputIContainer.addNewStream(iCodec);

    outputIStreams[index] = outputIStream;

    IStreamCoder outputIStreamCoder = outputIStream.getStreamCoder();

    outputIStreamCoders[index] = outputIStreamCoder;

    int bitRate = inputIStreamCoder.getBitRate();

    if (_log.isInfoEnabled()) {
      _log.info("Original video bitrate " + bitRate);
    }

    bitRate = getVideoBitRate(bitRate);

    if (_log.isInfoEnabled()) {
      _log.info("Modified video bitrate " + bitRate);
    }

    outputIStreamCoder.setBitRate(bitRate);

    IRational iRational = inputIStreamCoder.getFrameRate();

    if (_log.isInfoEnabled()) {
      _log.info(
          "Original frame rate " + iRational.getNumerator() + "/" + iRational.getDenominator());
    }

    iRational = getVideoFrameRate(iRational);

    if (_log.isInfoEnabled()) {
      _log.info(
          "Modified frame rate " + iRational.getNumerator() + "/" + iRational.getDenominator());
    }

    outputIStreamCoder.setFrameRate(iRational);

    if (inputIStreamCoder.getHeight() <= 0) {
      throw new RuntimeException("Unable to determine height for " + _inputURL);
    }

    if (_height == 0) {
      _height = inputIStreamCoder.getHeight();
    }

    outputIStreamCoder.setHeight(_height);

    outputIStreamCoder.setPixelType(Type.YUV420P);
    outputIStreamCoder.setTimeBase(
        IRational.make(iRational.getDenominator(), iRational.getNumerator()));

    if (inputIStreamCoder.getWidth() <= 0) {
      throw new RuntimeException("Unable to determine width for " + _inputURL);
    }

    if (_width == 0) {
      _width = inputIStreamCoder.getWidth();
    }

    outputIStreamCoder.setWidth(_width);

    iVideoResamplers[index] =
        createIVideoResampler(inputIStreamCoder, outputIStreamCoder, _height, _width);

    inputIVideoPictures[index] =
        IVideoPicture.make(
            inputIStreamCoder.getPixelType(),
            inputIStreamCoder.getWidth(),
            inputIStreamCoder.getHeight());
    outputIVideoPictures[index] =
        IVideoPicture.make(
            outputIStreamCoder.getPixelType(),
            outputIStreamCoder.getWidth(),
            outputIStreamCoder.getHeight());

    ICodec.ID iCodecID = iCodec.getID();

    if (iCodecID.equals(ICodec.ID.CODEC_ID_H264)) {
      Configuration.configure(_ffpresetProperties, outputIStreamCoder);
    }
  }
  public void decode() {

    int success = videoStream.open();
    if (success < 0) {

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

    IAudioSamples decodeSamples = null;

    if (audioStream != null) {

      success = audioStream.open();
      if (success < 0) {

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

      decodeSamples = IAudioSamples.make(1024, audioStream.getChannels());
    }

    IVideoPicture decodePicture =
        IVideoPicture.make(
            videoStream.getPixelType(), videoStream.getWidth(), videoStream.getHeight());

    while (container.readNextPacket(packet) >= 0 && decodeMode != DecodeMode.STOP) {

      /** Find out if this stream has a starting timestamp */
      IStream stream = container.getStream(packet.getStreamIndex());
      long tsOffset = 0;
      if (stream.getStartTime() != Global.NO_PTS
          && stream.getStartTime() > 0
          && stream.getTimeBase() != null) {
        IRational defTimeBase = IRational.make(1, (int) Global.DEFAULT_PTS_PER_SECOND);
        tsOffset = defTimeBase.rescale(stream.getStartTime(), stream.getTimeBase());
      }

      /*
       * Now we have a packet, let's see if it belongs to our video stream
       */
      if (packet.getStreamIndex() == videoStreamIndex) {

        int offset = 0;
        while (offset < packet.getSize()) {
          /*
           * Now, we decode the video, checking for any errors.
           *
           */
          int bytesDecoded = videoStream.decodeVideo(decodePicture, packet, offset);
          if (bytesDecoded < 0) {

            throw new RuntimeException(
                "XUGGLER: error decoding video in: " + input.getLocation().getDecodedURL());
          }

          if (decodePicture.getTimeStamp() != Global.NO_PTS) {

            decodePicture.setTimeStamp(decodePicture.getTimeStamp() - tsOffset);
          }

          offset += bytesDecoded;
          /*
           * Some decoders will consume data in a packet, but will not be able to construct
           * a full video picture yet.  Therefore you should always check if you
           * got a complete picture from the decoder
           */
          if (decodePicture.isComplete()) {

            decodedPicture(decodePicture);
          }
        }

      } else if (audioStream != null
          && packet.getStreamIndex() == audioStreamIndex
          && decodeMode != DecodeMode.IGNORE_AUDIO) {

        /*
         * A packet can actually contain multiple sets of samples (or frames of samples
         * in audio-decoding speak).  So, we may need to call decode audio multiple
         * times at different offsets in the packet's data.  We capture that here.
         */
        int offset = 0;

        /*
         * Keep going until we've processed all data
         */
        while (offset < packet.getSize()) {
          int bytesDecoded = audioStream.decodeAudio(decodeSamples, packet, offset);
          if (bytesDecoded < 0) {
            break;
            // throw new RuntimeException("XUGGLER: got error decoding audio in: " +
            // inputVideoFile);

          }

          if (decodeSamples.getTimeStamp() != Global.NO_PTS) {

            decodeSamples.setTimeStamp(decodeSamples.getTimeStamp() - tsOffset);
          }

          offset += bytesDecoded;
          /*
           * Some decoder will consume data in a packet, but will not be able to construct
           * a full set of samples yet.  Therefore you should always check if you
           * got a complete set of samples from the decoder
           */
          if (decodeSamples.isComplete()) {

            decodedAudioSamples(decodeSamples);
          }
        }

      } else {

        /*
         * This packet isn't part of our video stream, so we just
         * silently drop it.
         */
        continue;
      }
    }
  }