Android从图像列表制作动画视频
Posted
技术标签:
【中文标题】Android从图像列表制作动画视频【英文标题】:Android make animated video from list of images 【发布时间】:2012-05-04 07:26:59 【问题描述】:我想通过在两个图像之间应用过渡动画来从图像列表中制作动画视频。我在 SO 上发现了很多类似的问题,
android Screen capturing or make video from images
Android- How to make video using set of images from sd card?
所有类似的 SO 问题都建议为此使用动画,但是我们如何将动画图像存储到视频文件中?是否有任何 Android 库支持此功能以制作图像视频?
【问题讨论】:
你找到解决问题的方法了吗? 在这里写了一个可能的解决方案:***.com/a/64839777/878126 【参考方案1】:Android 不支持 AWT 的 BufferedBitmap 和 AWTUtil,即 Java SE。目前,带有 SequenceEncoder 的解决方案已经集成到 jcodec 的 Android 版本中。您可以从包 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 毫秒的视频。 SequenceEncoder 没有明显的自定义。 这可能是旧的,但有没有办法设置每个图像的持续时间? @morph85 encoder.encodeNativeFrame(this.fromBitmap(bitmap));需要很长时间(大约一分钟才能执行)。对此有何建议/解决方案?【参考方案2】:您可以使用名为 JCodec (http://jcodec.org) 的纯 Java 解决方案。这是一个 CORRECTED 简单的类,它使用 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();
【讨论】:
Android 不支持 BufferedImage 和 ImageIO以上是关于Android从图像列表制作动画视频的主要内容,如果未能解决你的问题,请参考以下文章
如何在xamarin android中将位图图像转换为gif?