Concatenating Two Files

From Xugglewiki

Jump to: navigation, search

I've built a simple media file concatenator demonstration tool. The source code for this tool can be found here:

ConcatenateAudioAndVideo.java

The 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.

Using the Demo

The 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. The demo does NOT append together sub-sections of media files, nor does it re-sample media, and it only appends one audio stream and one video stream. That said these kinds of features should be fairly straightforward to add to the existing code.

The media parameters of the input files are hard coded into the demo:

   // 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 parameters happen match the test input file:

 fixtures/ucl_h264_aac.mp4

You will need to set those parameters to match your specific media files.


How it Works

The demo contains an IMediaTool called Concatenator. The follow steps are taken to build up the media tool chain and concatenate the files:

  1. create both input file readers
  2. create the concatenator which listens to both of the input readers
  3. create output writer which listens to the concatenator
  4. read input 1 till end of file
  5. read input 2 till end of file
  6. 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. Here is how it looks for audio samples:

   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));
   }

When the end of a file is reach, the absolute offset is increased by the amount of media in that file:

  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.
     }
   }

As noted above if your media files have more video in them then audio, then it will cause subsequent files audio and video to be out of sync by the difference. You will need to insert audio silence into that gap to eliminate the problem.

Personal tools