package org.jcodec.common;
 
import java.io.File; 
import java.io.IOException; 
import java.nio.ByteBuffer; 
import java.util.concurrent.Callable; 
import java.util.concurrent.PriorityBlockingQueue; 
import java.util.concurrent.RunnableFuture; 
import java.util.concurrent.ThreadPoolExecutor; 
import java.util.concurrent.TimeUnit; 
 
import org.jcodec.codecs.h264.H264Decoder; 
import org.jcodec.codecs.mpeg12.MPEGDecoder; 
import org.jcodec.codecs.ppm.PPMEncoder; 
import org.jcodec.codecs.prores.ProresDecoder; 
import org.jcodec.common.model.ColorSpace; 
import org.jcodec.common.model.Picture; 
import org.jcodec.common.tools.MathUtil; 
import org.jcodec.containers.mp4.demuxer.MP4Demuxer; 
import org.jcodec.containers.mps.MPSDemuxer; 
import org.jcodec.containers.mps.MTSDemuxer; 
import org.jcodec.scale.ColorUtil; 
import org.jcodec.scale.Transform; 
 
/**
 * This class is part of JCodec ( www.jcodec.org ) This software is distributed 
 * under FreeBSD License 
 *  
 * @author The JCodec project 
 *  
 */
 
public class JCodecUtil { 
 
    private static final VideoDecoder[] knownDecoders = new VideoDecoder[] { new ProresDecoder(), new MPEGDecoder(), 
            new H264Decoder() }; 
 
    public enum Format { 
        MOV, MPEG_PS, MPEG_TS 
    } 
 
    public static Format detectFormat(File f) throws IOException { 
        return detectFormat(NIOUtils.fetchFrom(f, 200 * 1024)); 
    } 
 
    public static Format detectFormat(ByteBuffer b) { 
        int movScore = MP4Demuxer.probe(b.duplicate()); 
        int psScore = MPSDemuxer.probe(b.duplicate()); 
        int tsScore = MTSDemuxer.probe(b.duplicate()); 
 
        if (movScore == 0 && psScore == 0 && tsScore == 0
            return null
 
        return movScore > psScore ? (movScore > tsScore ? Format.MOV : Format.MPEG_TS) 
                : (psScore > tsScore ? Format.MPEG_PS : Format.MPEG_TS); 
    } 
 
    public static VideoDecoder detectDecoder(ByteBuffer b) { 
        int maxProbe = 0
        VideoDecoder selected = null
        for (VideoDecoder vd : knownDecoders) { 
            int probe = vd.probe(b); 
            if (probe > maxProbe) { 
                selected = vd; 
                maxProbe = probe; 
            } 
        } 
        return selected; 
    } 
 
    public static VideoDecoder getVideoDecoder(String fourcc) { 
        if ("apch".equals(fourcc) || "apcs".equals(fourcc) || "apco".equals(fourcc) || "apcn".equals(fourcc) 
                || "ap4h".equals(fourcc)) 
            return new ProresDecoder(); 
        else if ("m2v1".equals(fourcc)) 
            return new MPEGDecoder(); 
        else 
            return null
    } 
 
    public static void savePictureAsPPM(Picture pic, File file) throws IOException { 
        Transform transform = ColorUtil.getTransform(pic.getColor(), ColorSpace.RGB); 
        Picture rgb = Picture.create(pic.getWidth(), pic.getHeight(), ColorSpace.RGB); 
        transform.transform(pic, rgb); 
        NIOUtils.writeTo(new PPMEncoder().encodeFrame(rgb), file); 
    } 
 
    public static byte[] asciiString(String fourcc) { 
        char[] ch = fourcc.toCharArray(); 
        byte[] result = new byte[ch.length]; 
        for (int i = 0; i < ch.length; i++) { 
            result[i] = (byte) ch[i]; 
        } 
        return result; 
    } 
 
    public static void writeBER32(ByteBuffer buffer, int value) { 
        buffer.put((byte) ((value >> 21) | 0x80)); 
        buffer.put((byte) ((value >> 14) | 0x80)); 
        buffer.put((byte) ((value >> 7) | 0x80)); 
        buffer.put((byte) (value & 0x7F)); 
    } 
     
    public static void writeBER32Var(ByteBuffer bb, int value) { 
        for (int i = 0, bits = MathUtil.log2(value); i < 4 && bits > 0; i++) { 
            bits -= 7
            int out = value >> bits; 
            if(bits > 0
                out |= 0x80
            bb.put((byte)out); 
        } 
    } 
 
    public static int readBER32(ByteBuffer input) { 
        int size = 0
        for (int i = 0; i < 4; i++) { 
            byte b = input.get(); 
            size = (size << 7) | (b & 0x7f); 
            if (((b & 0xff) >> 7) == 0
                break
        } 
        return size; 
    } 
 
    public static int[] getAsIntArray(ByteBuffer yuv, int size) { 
        byte[] b = new byte[size]; 
        int[] result = new int[size]; 
        yuv.get(b); 
        for (int i = 0; i < b.length; i++) { 
            result[i] = b[i] & 0xff
        } 
        return result; 
    } 
 
    public static ThreadPoolExecutor getPriorityExecutor(int nThreads) { 
        return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, 
                new PriorityBlockingQueue<Runnable>(10, PriorityFuture.COMP)) { 
 
            protected <T> RunnableFuture<T> newTaskFor(Callable<T> callable) { 
                RunnableFuture<T> newTaskFor = super.newTaskFor(callable); 
                return new PriorityFuture<T>(newTaskFor, ((PriorityCallable<T>) callable).getPriority()); 
            } 
        }; 
    } 
 
    public static String removeExtension(String name) { 
        if(name == null
            return null
        return name.replaceAll("\\.[^\\.]+$"""); 
    } 
}