6

Quiero hacer un video animado de la lista de imágenes mediante la aplicación de animación de transición entre dos imágenes. He encontrado muchas preguntas similares sobre SO como,Android hacer un video animado de la lista de imágenes

Android Screen capturing or make video from images

Android- How to make video using set of images from sd card?

Todo similares SO preguntas sugieren que utiliza la animación para eso, pero ¿cómo podemos almacenar imágenes animadas que a archivo de vídeo? ¿Existe alguna biblioteca de Android que admita esta función para hacer videos de imágenes?

Cualquier ayuda es apreciada ... !!! Gracias de antemano

+1

¿encuentra la manera de hacer su pregunta? –

Respuesta

1

Puede utilizar una solución java pura llamada JCodec (http://jcodec.org). He aquí una clase simple CORREGIDOque lo hace usando JCodec API de bajo nivel:

public class SequenceEncoder { 
    private SeekableByteChannel ch; 
    private Picture toEncode; 
    private RgbToYuv420 transform; 
    private H264Encoder encoder; 
    private ArrayList<ByteBuffer> spsList; 
    private ArrayList<ByteBuffer> ppsList; 
    private CompressedTrack outTrack; 
    private ByteBuffer _out; 
    private int frameNo; 
    private MP4Muxer muxer; 

    public SequenceEncoder(File out) throws IOException { 
     this.ch = NIOUtils.writableFileChannel(out); 

     // Transform to convert between RGB and YUV 
     transform = new RgbToYuv420(0, 0); 

     // Muxer that will store the encoded frames 
     muxer = new MP4Muxer(ch, Brand.MP4); 

     // Add video track to muxer 
     outTrack = muxer.addTrackForCompressed(TrackType.VIDEO, 25); 

     // Allocate a buffer big enough to hold output frames 
     _out = ByteBuffer.allocate(1920 * 1080 * 6); 

     // Create an instance of encoder 
     encoder = new H264Encoder(); 

     // Encoder extra data (SPS, PPS) to be stored in a special place of 
     // MP4 
     spsList = new ArrayList<ByteBuffer>(); 
     ppsList = new ArrayList<ByteBuffer>(); 

    } 

    public void encodeImage(BufferedImage bi) throws IOException { 
     if (toEncode == null) { 
      toEncode = Picture.create(bi.getWidth(), bi.getHeight(), ColorSpace.YUV420); 
     } 

     // Perform conversion 
     for (int i = 0; i < 3; i++) 
      Arrays.fill(toEncode.getData()[i], 0); 
     transform.transform(AWTUtil.fromBufferedImage(bi), toEncode); 

     // Encode image into H.264 frame, the result is stored in '_out' buffer 
     _out.clear(); 
     ByteBuffer result = encoder.encodeFrame(_out, toEncode); 

     // Based on the frame above form correct MP4 packet 
     spsList.clear(); 
     ppsList.clear(); 
     H264Utils.encodeMOVPacket(result, spsList, ppsList); 

     // Add packet to video track 
     outTrack.addFrame(new MP4Packet(result, frameNo, 25, 1, frameNo, true, null, frameNo, 0)); 

     frameNo++; 
    } 

    public void finish() throws IOException { 
     // Push saved SPS/PPS to a special storage in MP4 
     outTrack.addSampleEntry(H264Utils.createMOVSampleEntry(spsList, ppsList)); 

     // Write MP4 header and finalize recording 
     muxer.writeHeader(); 
     NIOUtils.closeQuietly(ch); 
    } 

    public static void main(String[] args) throws IOException { 
     SequenceEncoder encoder = new SequenceEncoder(new File("video.mp4")); 
     for (int i = 1; i < 100; i++) { 
      BufferedImage bi = ImageIO.read(new File(String.format("folder/img%08d.png", i))); 
      encoder.encodeImage(bi); 
     } 
     encoder.finish(); 
    } 
} 
+9

BufferedImage e ImageIO no son compatibles con Android –

6

Android no son compatibles para BufferedBitmap de AWT ni AWTUtil, es decir para Java SE. Actualmente, la solución con SequenceEncoder se ha integrado en la versión de Android de jcodec. Puede usarlo desde el paquete org.jcodec.api.SequenceEncoder.

Aquí está la solución para la generación de archivos MP4 de la serie de mapas de bits utilizando jcodec:

try { 
    File file = this.GetSDPathToFile("", "output.mp4"); 
    SequenceEncoder encoder = new SequenceEncoder(file); 

    // only 5 frames in total 
    for (int i = 1; i <= 5; i++) { 
     // getting bitmap from drawable path 
     int bitmapResId = this.getResources().getIdentifier("image" + i, "drawable", this.getPackageName()); 
     Bitmap bitmap = this.getBitmapFromResources(this.getResources(), bitmapResId); 
     encoder.encodeNativeFrame(this.fromBitmap(bitmap)); 
    } 
    encoder.finish(); 
} catch (IOException e) { 
    e.printStackTrace(); 
} 

// get full SD path 
File GetSDPathToFile(String filePatho, String fileName) { 
    File extBaseDir = Environment.getExternalStorageDirectory(); 
    if (filePatho == null || filePatho.length() == 0 || filePatho.charAt(0) != '/') 
     filePatho = "/" + filePatho; 
    makeDirectory(filePatho); 
    File file = new File(extBaseDir.getAbsoluteFile() + filePatho); 
    return new File(file.getAbsolutePath() + "/" + fileName);// file; 
} 

// convert from Bitmap to Picture (jcodec native structure) 
public Picture fromBitmap(Bitmap src) { 
    Picture dst = Picture.create((int)src.getWidth(), (int)src.getHeight(), ColorSpace.RGB); 
    fromBitmap(src, dst); 
    return dst; 
} 

public void fromBitmap(Bitmap src, Picture dst) { 
    int[] dstData = dst.getPlaneData(0); 
    int[] packed = new int[src.getWidth() * src.getHeight()]; 

    src.getPixels(packed, 0, src.getWidth(), 0, 0, src.getWidth(), src.getHeight()); 

    for (int i = 0, srcOff = 0, dstOff = 0; i < src.getHeight(); i++) { 
     for (int j = 0; j < src.getWidth(); j++, srcOff++, dstOff += 3) { 
      int rgb = packed[srcOff]; 
      dstData[dstOff]  = (rgb >> 16) & 0xff; 
      dstData[dstOff + 1] = (rgb >> 8) & 0xff; 
      dstData[dstOff + 2] = rgb & 0xff; 
     } 
    } 
} 

En caso de que necesite cambiar los fps, es posible personalizar el SequenceEncoder.

+1

¿Qué afecta la duración del video y cómo podríamos definirlo en este caso? Mi código generó (creo) un video de 1 fotograma. –

+1

Y un (creo) video de 1 ms. –

+0

No hay una personalización aparente para SequenceEncoder. – mradzinski

Cuestiones relacionadas