javavideo-encodingxugglexuggler

How to re-code a movie file with Xuggler


This must be a very stupid question, but how does one recode with Xuggler? Simplified I have:

IMediaReader reader = ToolFactory.makeReader(sourceUrl);      
IMediaWriter writer = ToolFactory.makeWriter(url, reader);

MediaSegmenterWriter writerListener = new MediaSegmenterWriter();
writer.open();
while (reader.readPacket() == null)
   do {
     } 
while(false);

Now, I want to recode the file in the reader to another bitrate and resolution. How do I do that? On creating the writer I have tried to add IMediaStreams with a copy of the original coder with the necessary changes, but that does not work:

    int numStreams = reader.getContainer().getNumStreams();
    for(int i = 0; i < numStreams; i++)
    {
        final IStream stream = reader.getContainer().getStream(i);
        final IStreamCoder coder = stream.getStreamCoder();

        IStreamCoder newCoder = IStreamCoder.make(IStreamCoder.Direction.ENCODING, coder);
        if(newCoder == null ){
            continue;
        }
        writer.getContainer().addNewStream(i);

        int streams = writer.getContainer().getNumStreams();
        System.out.println("Current amount of streams in writer: " + streams);

        System.out.println("Coder: " + coder.toString());
        if (coderSetting != null && newCoder != null){
            if (newCoder.getCodecType().equals(ICodec.Type.CODEC_TYPE_VIDEO)) {
                newCoder.setWidth(320);
                newCoder.setHeight(240);                   
            } 
            IStream outputStream = writer.getContainer().getStream(i);
            outputStream.setStreamCoder(newCoder);
            newCoder.open();
          }
    }

But this just gives the same result as leaving the code out (e.g. 1920x1080 from original)

Also tried to add a listener to the writer and replace the coder, but either got an error (coder already opened_ or no effect. (on onOpen, onAddStream, onOpenCoder))

I looked for tutorials, but non seem to do this simple operation.

Any help would be REALLY appreciated!!!


Solution

  • In order to resize the content as well as recode you need to create a MediaToolAdapter like:

    private static class MediaResizer extends MediaToolAdapter {
        private IVideoResampler videoResampler = null;
        private int mediaHeight;
        private int mediaWidth;
    
        public MediaResizer (int aHight, int aWidth) {
            mediaWidth = aWidth;
            mediaHeight = aHeight;
        }
    
        @Override
        public void onVideoPicture(IVideoPictureEvent event) {
            // In case of audio only, do not re-size as it is not needed
            if(job.role == MediaRole.MediaRoleEnum.LS_AUDIO) super.onVideoPicture(event);
    
            IVideoPicture pic = event.getPicture();
    
            if (videoResampler == null) {
                videoResampler = IVideoResampler.make(job.getCoderSettings().width, job.getCoderSettings().height, pic.getPixelType(), pic.getWidth(), pic.getHeight(), pic.getPixelType());
            }
    
            IVideoPicture out = IVideoPicture.make(pic.getPixelType(), mediaWidth, mediaHeight);
            videoResampler.resample(out, pic);
    
            IVideoPictureEvent asc = new VideoPictureEvent(event.getSource(), out, event.getStreamIndex());
            super.onVideoPicture(asc);
    
            out.delete();
        }
    
    }
    

    You add this as a listener to your reader, and then your writer to you resized. It should be something like:

     IMediaReader reader = ToolFactory.makeReader(sourceUrl);
     MediaResizer resizer = new MediaResizer(job);
     IMediaWriter currentWriter = ToolFactory.makeWriter(destinationDir, reader);
    
     reader.addListener(resizer);
     resizer.addListener(currentWriter);