6

我想通過在兩幅圖像之間應用過渡動畫從圖像列表製作動畫視頻。我發現SO許多類似的問題,Android根據圖像列表製作動畫視頻

Android Screen capturing or make video from images

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

所有相似的,所以問題建議使用動畫,但是我們怎麼能存儲動畫圖像,視頻文件?有沒有任何Android庫支持這個工具來製作圖像視頻?

任何幫助表示讚賞... !!! 預先感謝

+1

你是否找到了解決問題的方法? – 2016-12-11 06:05:51

回答

1

您可以使用名爲JCodec的純Java解決方案(http://jcodec.org)。這裏有一個糾正簡單的類,它是使用JCodec低級別的API:

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

Android中不支持BufferedImage和ImageIO – 2015-03-19 10:37:51

6

的Android沒有爲AWT的BufferedBitmap也不AWTUtil支持,這是Java SE。目前,SequenceEncoder的解決方案已經集成到jcodec的Android版本中。你可以在package org.jcodec.api.SequenceEncoder中使用它。

下面是使用jcodec從一系列的位圖的生成MP4文件的解決方案:

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

如果您需要更改fps,您可以自定義SequenceEncoder。

+1

影響視頻持續時間的因素是什麼?在這種情況下我們如何定義它?我的代碼生成(我認爲)一個1幀的視頻。 – 2014-08-25 13:01:24

+1

和(我認爲)1毫秒的視頻。 – 2014-08-25 13:15:11

+0

SequenceEncoder沒有明顯的定製。 – mradzinski 2015-01-12 23:04:07