/*
javac -cp xuggle-xuggler-5.4.jar Transcoder.java
java  -cp xuggle-xuggler-5.4.jar:./:slf4j-api-1.6.4.jar Transcoder

http://whaticode.com/2010/04/30/use-java-to-convert-any-media-type-to-flv-with-xuggler-part-2/
*/
package zall.util.test;

import java.io.File;
import javax.imageio.ImageIO;
import java.io.IOException;

import com.xuggle.mediatool.IMediaReader;
import com.xuggle.mediatool.IMediaWriter;
import com.xuggle.mediatool.MediaToolAdapter;
import com.xuggle.mediatool.ToolFactory;
import com.xuggle.mediatool.event.IAddStreamEvent;
import com.xuggle.mediatool.event.AudioSamplesEvent;
import com.xuggle.mediatool.event.IAudioSamplesEvent;
import com.xuggle.mediatool.event.IVideoPictureEvent;
import com.xuggle.mediatool.event.VideoPictureEvent;
import com.xuggle.xuggler.ICodec;
import com.xuggle.xuggler.IStreamCoder;
import com.xuggle.xuggler.IVideoPicture;
import com.xuggle.xuggler.IVideoResampler;
import com.xuggle.xuggler.IAudioSamples;
import com.xuggle.xuggler.IAudioResampler;
import com.xuggle.xuggler.video.IConverter;
import com.xuggle.xuggler.video.ConverterFactory;


public class Transcoder {
	public static void main(String[] args){
		File originalFile = new File( "test2.mp4" );
		File mediumFile = new File( "test2_medium.mp4" );
		File smallFile = new File( "test2_small.png" );

        //ConvertVideo tmp = new ConvertVideo(originalFile, mediumFile);
        //tmp.run();
        //return;
        
		///////////// Start Transcoding
		// create a media reader
		IMediaReader reader = ToolFactory.makeReader( originalFile.getPath() );
		reader.addListener(new FrameGrabListener(reader, smallFile, 0.2));
        reader.addListener(new ProgressListener(reader));
        
		VideoTranscoderListener converter = new VideoTranscoderListener(480, 270);
		reader.addListener(converter);
		
		// create a media writer
		IMediaWriter writer = ToolFactory.makeWriter(mediumFile.getPath(), reader);
		converter.addListener(writer);

		// create a media viewer with stats enabled for debugging
		// add a viewer to the reader, to see the decoded media
		//IMediaViewer mediaViewer = ToolFactory.makeViewer(true);
		//reader.addListener(mediaViewer);
		//writer.addListener(mediaViewer);

		// read and decode packets from the source file and
		// and dispatch decoded audio and video to the writer
		while (reader.readPacket() == null);

		// Incomplete transcoding
		if( reader.isOpen() ){
			System.out.println("Transcoding incomplete, removing incomplete files!");
			reader.close();
			mediumFile.delete();
			smallFile.delete();
		}

		System.out.println("\n\nDone!");
        
	}
}

class VideoTranscoderListener extends MediaToolAdapter{
	private int width;
	private int height;

	public VideoTranscoderListener(int width, int height) { 
        this.width = width;
        this.height = height;
    }

	private IVideoResampler videoResampler = null;
	private IAudioResampler audioResampler = null;
   
	@Override
	public void onAddStream(IAddStreamEvent event) {
		int streamIndex = event.getStreamIndex();
		IStreamCoder streamCoder = event.getSource().getContainer().getStream(streamIndex).getStreamCoder();
		if (streamCoder.getCodecType() == ICodec.Type.CODEC_TYPE_AUDIO) {
			streamCoder.setSampleRate( 44100 );
            //streamCoder.setCodec( ICodec.ID.CODEC_ID_AAC );
			//streamCoder.setBitRate( 128 );
		} 
        else if (streamCoder.getCodecType() == ICodec.Type.CODEC_TYPE_VIDEO) {
            streamCoder.setWidth( width );
			streamCoder.setHeight( height );

			//streamCoder.setCodec(ICodec.findEncodingCodec( ICodec.ID.CODEC_ID_H264 ));
			//streamCoder.setBitRate( 800000 );
            /*
			int retval = Configuration.configure("/usr/local/xuggler/share/ffmpeg/libx264-superfast.ffpreset", streamCoder);
			if (retval<0)
				throw new RuntimeException("cound not cofigure coder from preset file");
			*/
		}
		super.onAddStream(event);
	}

	@Override
	public void onVideoPicture(IVideoPictureEvent event) {
		IVideoPicture pic = event.getPicture();
		if (videoResampler == null) {
			videoResampler = IVideoResampler.make(width, height, pic.getPixelType(), pic.getWidth(), pic.getHeight(), pic.getPixelType());
		}
		IVideoPicture out = IVideoPicture.make(pic.getPixelType(), width, height);
		videoResampler.resample(out, pic);

		IVideoPictureEvent asc = new VideoPictureEvent(event.getSource(), out, event.getStreamIndex());
		super.onVideoPicture(asc);
		out.delete();
	}

	@Override
	public void onAudioSamples(IAudioSamplesEvent event) {
		IAudioSamples samples = event.getAudioSamples();
		if (audioResampler == null) {
			audioResampler = IAudioResampler.make(2, samples.getChannels(), 44100, samples.getSampleRate());
		}
		if (event.getAudioSamples().getNumSamples() > 0) {
			IAudioSamples out = IAudioSamples.make(samples.getNumSamples(), samples.getChannels());
			audioResampler.resample(out, samples, samples.getNumSamples());

			AudioSamplesEvent asc = new AudioSamplesEvent(event.getSource(), out, event.getStreamIndex());
			super.onAudioSamples(asc);
			out.delete();
		}
	}

}

class ProgressListener extends MediaToolAdapter {
	private long currentLength;
	private long totalLength;
	private int progress = -1;

	public ProgressListener(IMediaReader reader) {
        if( !reader.isOpen() )
            reader.open(); // read container
		this.totalLength = reader.getContainer().getDuration();
	}

	@Override
	public void onVideoPicture(IVideoPictureEvent event) {
		currentLength = event.getTimeStamp();
        
		if( (int)(100*getProgress()) != progress ){
			progress = (int)(100*getProgress());
			System.out.print("\n"+(int)(100*getProgress())+"% ");			
		}
		else System.out.print(".");
	}

	public long getProcessedLength(){
		return currentLength;
	}

	public long getTotalLength(){
		return totalLength;
	}

	public double getProgress(){
        if(totalLength > 0)
            return ((double)currentLength/totalLength);
        return 0;
	}
}

class FrameGrabListener extends MediaToolAdapter {
	private long totalLength;
	private long grabAt;
	private File outputFile;
    
	public FrameGrabListener(IMediaReader reader, File outputFile, double at) {
		if( !reader.isOpen() )
            reader.open(); // read container
		this.totalLength = reader.getContainer().getDuration();
		this.outputFile = outputFile;
        setAtProgress(at);
	}

	@Override
	public void onVideoPicture(IVideoPictureEvent event) {
		try{
			long currentLength = event.getTimeStamp();
			
			if( grabAt > 0 && currentLength > grabAt ){
				System.out.println("\nScreanshoot!!!");
				
				ConverterFactory.Type mConverterType = ConverterFactory.findRegisteredConverter(
						ConverterFactory.XUGGLER_BGR_24);
				IConverter mVideoConverter = ConverterFactory.createConverter(
						mConverterType.getDescriptor(), 
						event.getPicture());
				
				ImageIO.write(
							mVideoConverter.toImage(event.getPicture()), 
							"png", 
							outputFile);
				grabAt = -1;
			}
		}catch(IOException e){
			e.printStackTrace();
		}
	}

	public void setAtProgress(double procent){
		grabAt = (long)(totalLength * procent);
	}
}

