Monday 3 December 2012

Xuggler

Posted by Naveen Katiyar On 04:13 2 comments
  • Merging Two Video Files

    For merging two video files in java,we are using xuggler api.This api is platform depend so we need to include different jar windows and linux.

    For windows: xuggle-xuggler-5.4.jar
    For Linux:xuggle-xuggler-arch-i686-pc-linux-gnu.jar  & xuggle-xuggler-noarch-5.4.jar

    Download these from http://www.xuggle.com/xuggler/

    The below code produces an output file which contains two input files concatenated together. For example, this code would be used to pre-pend or post-pend commercial to an existing video.

    The code perform the concatenation, both files need to have the same audio and video parameters: height, width, channels, sample rate, etc. The demo code appends two files, but more files may be appended trivially.


    // video parameters
    
       final int videoStreamIndex = 0;
       final int videoStreamId = 0;
       final int width = 480;
       final int height = 360;
    
       // audio parameters
    
       final int audioStreamIndex = 1;
       final int audioStreamId = 0;
       final int channelCount = 2;
       final int sampleRate = 44100; // Hz
     
     The two video files should have same audio and video parameters..
     
     

    The demo contains an IMediaTool called Concatenator. The follow steps are taken to build up the media tool chain and concatenate the files:
  • create both input file readers
  • create the concatenator which listens to both of the input readers
  • create output writer which listens to the concatenator
  • read input 1 till end of file
  • read input 2 till end of file
  • close the writer
The Concatenator receives all events from the input readers, but is clever enough to only pass onVideoPicture() and onAudioSamples() events to the writer. All other events are withheld from the writer. When audio and video from a reader reaches the concatenator, the timestamp on the media is adjusted forward to the correct absolute time of the output file.
 
 
The source code is given below: 


package mypack:
import static java.lang.System.out;

import com.xuggle.mediatool.IMediaReader;
import com.xuggle.mediatool.IMediaViewer;
import com.xuggle.mediatool.IMediaWriter;
import com.xuggle.mediatool.MediaToolAdapter;
import com.xuggle.mediatool.ToolFactory;
import com.xuggle.mediatool.event.AudioSamplesEvent;
import com.xuggle.mediatool.event.IAddStreamEvent;
import com.xuggle.mediatool.event.IAudioSamplesEvent;
import com.xuggle.mediatool.event.ICloseCoderEvent;
import com.xuggle.mediatool.event.ICloseEvent;
import com.xuggle.mediatool.event.IOpenCoderEvent;
import com.xuggle.mediatool.event.IOpenEvent;
import com.xuggle.mediatool.event.IVideoPictureEvent;
import com.xuggle.mediatool.event.VideoPictureEvent;
import com.xuggle.xuggler.IAudioSamples;
import com.xuggle.xuggler.IVideoPicture;
//import com.xuggle.mediatool.IMediaReader;

/**
 * A very simple media transcoder which uses {@link IMediaReader}, {@link
 * IMediaWriter} and {@link IMediaViewer}.
 */

public class MergingVideos
{
  /**
   * Concatenate two files.
   *
   * @param args 3 strings; an input file 1, input file 2, and an output file.
   */
 
  public static void main(String[] args)
  {
  
   String file1="/home/naveen/workspace/video/s2.mp4";//change accordingly
      String file2="/home/naveen/workspace/video/s3.mp4";//change accordingly
  // String file3="/home/naveen/workspace/video/s4.mp4";
  // String mergefile = "/home/naveen/workspace/converted/threefile.mp4";
      String mergefile = "/home/naveen/workspace/converted/twofile.mp4";//change accordingly
  // concatenateThreeFiles(file1,file2,file3,mergefile);
      concatenate(file1,file2,mergefile);
   
  }
  
  
  public static void concatenateThreeFiles(String sourceUrl1, String sourceUrl2,String sourceUrl3,String destinationUrl)
  {
   System.out.println("transcoding starts");
   
   //video parameters
   final int videoStreamIndex = 0;
   final int videoStreamId = 0;
   final int width = 480 ;
   final int height = 272;
   
   //audio parameters
      
   final int audioStreamIndex = 1;
   final int audioStreamId = 0;
   final int channelCount = 2;
   final int sampleRate = 44100; //Hz
   
   IMediaReader reader1 = ToolFactory.makeReader(sourceUrl1);
   IMediaReader reader2 = ToolFactory.makeReader(sourceUrl2);
   IMediaReader reader3 = ToolFactory.makeReader(sourceUrl3);
   
   MediaConcatenator concatenator = new MediaConcatenator(audioStreamIndex,videoStreamIndex);
   reader1.addListener(concatenator);
   reader2.addListener(concatenator);
   reader3.addListener(concatenator);
   
   IMediaWriter writer = ToolFactory.makeWriter(destinationUrl);
   concatenator.addListener(writer);
   writer.addVideoStream(videoStreamIndex, videoStreamId, width,height);
   writer.addAudioStream(audioStreamIndex, audioStreamId, channelCount, sampleRate);
   
   while(reader1.readPacket() == null);
   
   while(reader2.readPacket() == null);
   
   while(reader3.readPacket() == null);
   
    writer.close();
   System.out.println("finished merging");
  }
 
  
  
  

  /**
   * Concatenate two source files into one destination file.
   *
   * @param sourceUrl1 the file which will appear first in the output
   * @param sourceUrl2 the file which will appear second in the output
   * @param destinationUrl the file which will be produced
   */

  public static void concatenate(String sourceUrl1, String sourceUrl2,String destinationUrl)
  {
    out.printf("transcode %s + %s -> %s\n", sourceUrl1, sourceUrl2,
      destinationUrl);

    //////////////////////////////////////////////////////////////////////
    //                                                                  //
    // NOTE: be sure that the audio and video parameters match those of //
    // your input media                                                 //
    //                                                                  //
    //////////////////////////////////////////////////////////////////////

    // video parameters

    final int videoStreamIndex = 0;
    final int videoStreamId = 0;
    final int width = 480;
    final int height = 272;

    

    // audio parameters

    //commented by vivek
    final int audioStreamIndex = 1;
    final int audioStreamId = 0;
    final int channelCount = 2;
    final int sampleRate = 44100; // Hz

    // create the first media reader

    IMediaReader reader1 = ToolFactory.makeReader(sourceUrl1);

    // create the second media reader

    IMediaReader reader2 = ToolFactory.makeReader(sourceUrl2);

    // create the media concatenator

    MediaConcatenator concatenator = new MediaConcatenator(audioStreamIndex,
      videoStreamIndex);

    // concatenator listens to both readers

    reader1.addListener(concatenator);
    reader2.addListener(concatenator);

    // create the media writer which listens to the concatenator

    IMediaWriter writer = ToolFactory.makeWriter(destinationUrl);
    concatenator.addListener(writer);

    // add the video stream

    writer.addVideoStream(videoStreamIndex, videoStreamId, width, height);

    // add the audio stream

    writer.addAudioStream(audioStreamIndex, audioStreamId, channelCount,
      sampleRate);

    // read packets from the first source file until done

    while (reader1.readPacket() == null)
      ;

    // read packets from the second source file until done

    while (reader2.readPacket() == null)
      ;

    // close the writer

    writer.close();
    System.out.println("finish");
  }
 
  static class MediaConcatenator extends MediaToolAdapter
  {
    // the current offset
   
    private long mOffset = 0;
   
    // the next video timestamp
   
    private long mNextVideo = 0;
   
    // the next audio timestamp
   
    private long mNextAudio = 0;

    // the index of the audio stream
   
    private final int mAudoStreamIndex;
   
    // the index of the video stream
   
    private final int mVideoStreamIndex;
   
    /**
     * Create a concatenator.
     *
     * @param audioStreamIndex index of audio stream
     * @param videoStreamIndex index of video stream
     */
   
    public MediaConcatenator(int audioStreamIndex, int videoStreamIndex)
    {
      mAudoStreamIndex = audioStreamIndex;
      mVideoStreamIndex = videoStreamIndex;
    }
   
    public void onAudioSamples(IAudioSamplesEvent event)
    {
      IAudioSamples samples = event.getAudioSamples();
     
      // set the new time stamp to the original plus the offset established
      // for this media file

      long newTimeStamp = samples.getTimeStamp() + mOffset;

      // keep track of predicted time of the next audio samples, if the end
      // of the media file is encountered, then the offset will be adjusted
      // to this time.

      mNextAudio = samples.getNextPts();

      // set the new timestamp on audio samples

      samples.setTimeStamp(newTimeStamp);

      // create a new audio samples event with the one true audio stream
      // index

      super.onAudioSamples(new AudioSamplesEvent(this, samples,
        mAudoStreamIndex));
    }

    public void onVideoPicture(IVideoPictureEvent event)
    {
      IVideoPicture picture = event.getMediaData();
      long originalTimeStamp = picture.getTimeStamp();

      // set the new time stamp to the original plus the offset established
      // for this media file

      long newTimeStamp = originalTimeStamp + mOffset;

      // keep track of predicted time of the next video picture, if the end
      // of the media file is encountered, then the offset will be adjusted
      // to this this time.
      //
      // You'll note in the audio samples listener above we used
      // a method called getNextPts().  Video pictures don't have
      // a similar method because frame-rates can be variable, so
      // we don't now.  The minimum thing we do know though (since
      // all media containers require media to have monotonically
      // increasing time stamps), is that the next video timestamp
      // should be at least one tick ahead.  So, we fake it.
     
      mNextVideo = originalTimeStamp + 1;

      // set the new timestamp on video samples

      picture.setTimeStamp(newTimeStamp);

      // create a new video picture event with the one true video stream
      // index

      super.onVideoPicture(new VideoPictureEvent(this, picture,
        mVideoStreamIndex));
    }
   
    public void onClose(ICloseEvent event)
    {
      // update the offset by the larger of the next expected audio or video
      // frame time

      mOffset = Math.max(mNextVideo, mNextAudio);

      if (mNextAudio < mNextVideo)
      {
        // In this case we know that there is more video in the
        // last file that we read than audio. Technically you
        // should pad the audio in the output file with enough
        // samples to fill that gap, as many media players (e.g.
        // Quicktime, Microsoft Media Player, MPlayer) actually
        // ignore audio time stamps and just play audio sequentially.
        // If you don't pad, in those players it may look like
        // audio and video is getting out of sync.

        // However kiddies, this is demo code, so that code
        // is left as an exercise for the readers. As a hint,
        // see the IAudioSamples.defaultPtsToSamples(...) methods.
      }
    }

    public void onAddStream(IAddStreamEvent event)
    {
      // overridden to ensure that add stream events are not passed down
      // the tool chain to the writer, which could cause problems
    }

    public void onOpen(IOpenEvent event)
    {
      // overridden to ensure that open events are not passed down the tool
      // chain to the writer, which could cause problems
    }

    public void onOpenCoder(IOpenCoderEvent event)
    {
      // overridden to ensure that open coder events are not passed down the
      // tool chain to the writer, which could cause problems
    }

    public void onCloseCoder(ICloseCoderEvent event)
    {
      // overridden to ensure that close coder events are not passed down the
      // tool chain to the writer, which could cause problems
    }
  }
}

2 comments:

Ismail Sunni said...

Can you give me a hint to split a video to several files using Xuggler?

I've googled more than a week and tried many tutorial, but I got nothing or error.

Thanks

Unknown said...

how to merge the multiple videos into single video using xuggler

I am getting an error when i am run the above code


Exception in thread "main" java.lang.RuntimeException: failed to encode video
at com.xuggle.mediatool.MediaWriter.encodeVideo(MediaWriter.java:764)
at com.xuggle.mediatool.MediaWriter.encodeVideo(MediaWriter.java:783)
at com.xuggle.mediatool.MediaWriter.onVideoPicture(MediaWriter.java:1434)
at com.xuggle.mediatool.AMediaToolMixin.onVideoPicture(AMediaToolMixin.java:166)
at com.xuggle.mediatool.MediaToolAdapter.onVideoPicture(MediaToolAdapter.java:169)
at com.expertite.content.media.MergingVideos$MediaConcatenator.onVideoPicture(MergingVideos.java:317)
at com.xuggle.mediatool.AMediaToolMixin.onVideoPicture(AMediaToolMixin.java:166)
at com.xuggle.mediatool.MediaReader.dispatchVideoPicture(MediaReader.java:610)
at com.xuggle.mediatool.MediaReader.decodeVideo(MediaReader.java:519)
at com.xuggle.mediatool.MediaReader.readPacket(MediaReader.java:475)
at com.expertite.content.media.MergingVideos.concatenate(MergingVideos.java:197)
at com.expertite.content.media.MergingVideos.main(MergingVideos.java:46)