How to save Lottie Animation as Video (.mp4) and GIF (.gif) in Android ?
See original GitHub issueis that another way to save Lottie animation in android?
i have sued the below code but video proper not save.
private static final String MIME_TYPE = "video/avc";
private static final int WIDTH = 640;
private static final int HEIGHT = 640;
private static final int BIT_RATE = 40000;
private static final int FRAMES_PER_SECOND = 1;
private static final int IFRAME_INTERVAL = 5;
private static final int NUM_FRAMES = 8;
// "live" state during recording
private MediaCodec.BufferInfo mBufferInfo;
private MediaCodec mEncoder;
private MediaMuxer mMuxer;
private Surface mInputSurface;
private int mTrackIndex;
private boolean mMuxerStarted;
private long mFakePts;
LottieDrawable drawable = new LottieDrawable();
try {
LottieTask<LottieComposition> composition = LottieCompositionFactory
.fromAsset(this, "text.json")
.addListener(new LottieListener<LottieComposition>() {
@Override
public void onResult(LottieComposition result) {
drawable.setComposition(result);
}
});
} catch (Exception e) {
Log.e(TAG, "onCreate: ", e);
}
// Be VERY BAD and do the whole thing during onCreate().
Log.i(TAG, "Generating movie...");
String str = FileUtils.getSaveVideoDirPath();
Log.i(TAG, "onClick: " + str);
if (new File(str).exists()) {
Log.i(TAG, "onClick: EXISTS");
try {
File file = new File(str, "Demo_123.mp4");
Log.i(TAG, "onClick: " + file.getAbsolutePath());
generateMovie(file);
textUser.setText("Success");
Log.i(TAG, "Movie generation complete");
} catch (Exception ex) {
Log.e(TAG, "Movie generation FAILED", ex);
textUser.setText("Failed");
}
}
private void generateMovie(File outputFile) {
try {
prepareEncoder(outputFile);
for (int i = 0; i < drawable.getMaxFrame(); i++) {
drainEncoder(false);
Log.i(TAG, "generateMovie: " + i);
drawable.setFrame(i);
generateFrame(drawable);
}
drainEncoder(true);
} catch (IOException ioe) {
throw new RuntimeException(ioe);
} finally {
releaseEncoder();
}
}
public void generateFrame(Drawable lottieDrawable) {
drainEncoder(false);
final Canvas canvas = mInputSurface.lockCanvas(null);
try {
lottieDrawable.draw(canvas);
} finally {
mInputSurface.unlockCanvasAndPost(canvas);
}
}
/**
* Prepares the video encoder, muxer, and an input surface.
*/
private void prepareEncoder(File outputFile) throws IOException {
mBufferInfo = new BufferInfo();
MediaFormat format = MediaFormat.createVideoFormat(MIME_TYPE, WIDTH, HEIGHT);
// Set some properties. Failing to specify some of these can cause the MediaCodec
// configure() call to throw an unhelpful exception.
format.setInteger(MediaFormat.KEY_COLOR_FORMAT,
CodecCapabilities.COLOR_FormatSurface);
format.setInteger(MediaFormat.KEY_BIT_RATE, BIT_RATE);
format.setInteger(MediaFormat.KEY_FRAME_RATE, FRAMES_PER_SECOND);
format.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, IFRAME_INTERVAL);
if (VERBOSE) Log.d(TAG, "format: " + format);
// Create a MediaCodec encoder, and configure it with our format. Get a Surface
// we can use for input and wrap it with a class that handles the EGL work.
mEncoder = MediaCodec.createEncoderByType(MIME_TYPE);
mEncoder.configure(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
if (VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN_MR2) {
mInputSurface = mEncoder.createInputSurface();
}
mEncoder.start();
// Create a MediaMuxer. We can't add the video track and start() the muxer here,
// because our MediaFormat doesn't have the Magic Goodies. These can only be
// obtained from the encoder after it has started processing data.
//
// We're not actually interested in multiplexing audio. We just want to convert
// the raw H.264 elementary stream we get from MediaCodec into a .mp4 file.
if (VERBOSE) Log.d(TAG, "output will go to " + outputFile);
if (VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN_MR2) {
mMuxer = new MediaMuxer(outputFile.toString(),
OutputFormat.MUXER_OUTPUT_MPEG_4);
}
mTrackIndex = -1;
mMuxerStarted = false;
}
/**
* Releases encoder resources. May be called after partial / failed initialization.
*/
private void releaseEncoder() {
if (VERBOSE) Log.d(TAG, "releasing encoder objects");
if (mEncoder != null) {
mEncoder.stop();
mEncoder.release();
mEncoder = null;
}
if (mInputSurface != null) {
mInputSurface.release();
mInputSurface = null;
}
if (mMuxer != null) {
if (VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN_MR2) {
mMuxer.stop();
mMuxer.release();
}
mMuxer = null;
}
}
/**
* Extracts all pending data from the encoder.
* <p>
* If endOfStream is not set, this returns when there is no more data to drain. If it
* is set, we send EOS to the encoder, and then iterate until we see EOS on the output.
* Calling this with endOfStream set should be done once, right before stopping the muxer.
*/
private void drainEncoder(boolean endOfStream) {
final int TIMEOUT_USEC = 10000;
if (VERBOSE) Log.d(TAG, "drainEncoder(" + endOfStream + ")");
if (endOfStream) {
if (VERBOSE) Log.d(TAG, "sending EOS to encoder");
if (VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN_MR2) {
mEncoder.signalEndOfInputStream();
}
}
ByteBuffer[] encoderOutputBuffers = mEncoder.getOutputBuffers();
while (true) {
int encoderStatus = mEncoder.dequeueOutputBuffer(mBufferInfo, TIMEOUT_USEC);
if (encoderStatus == MediaCodec.INFO_TRY_AGAIN_LATER) {
// no output available yet
if (!endOfStream) {
break; // out of while
} else {
if (VERBOSE) Log.d(TAG, "no output available, spinning to await EOS");
}
} else if (encoderStatus == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) {
// not expected for an encoder
encoderOutputBuffers = mEncoder.getOutputBuffers();
} else if (encoderStatus == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
// should happen before receiving buffers, and should only happen once
if (mMuxerStarted) {
throw new RuntimeException("format changed twice");
}
MediaFormat newFormat = mEncoder.getOutputFormat();
Log.d(TAG, "encoder output format changed: " + newFormat);
// now that we have the Magic Goodies, start the muxer
if (VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN_MR2) {
mTrackIndex = mMuxer.addTrack(newFormat);
mMuxer.start();
}
mMuxerStarted = true;
} else if (encoderStatus < 0) {
Log.w(TAG, "unexpected result from encoder.dequeueOutputBuffer: " +
encoderStatus);
// let's ignore it
} else {
ByteBuffer encodedData = encoderOutputBuffers[encoderStatus];
if (encodedData == null) {
throw new RuntimeException("encoderOutputBuffer " + encoderStatus +
" was null");
}
if ((mBufferInfo.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) != 0) {
// The codec config data was pulled out and fed to the muxer when we got
// the INFO_OUTPUT_FORMAT_CHANGED status. Ignore it.
if (VERBOSE) Log.d(TAG, "ignoring BUFFER_FLAG_CODEC_CONFIG");
mBufferInfo.size = 0;
}
if (mBufferInfo.size != 0) {
if (!mMuxerStarted) {
throw new RuntimeException("muxer hasn't started");
}
// adjust the ByteBuffer values to match BufferInfo
encodedData.position(mBufferInfo.offset);
encodedData.limit(mBufferInfo.offset + mBufferInfo.size);
mBufferInfo.presentationTimeUs = mFakePts;
mFakePts += 1000000L / FRAMES_PER_SECOND;
if (VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN_MR2) {
mMuxer.writeSampleData(mTrackIndex, encodedData, mBufferInfo);
}
if (VERBOSE) Log.d(TAG, "sent " + mBufferInfo.size + " bytes to muxer");
}
mEncoder.releaseOutputBuffer(encoderStatus, false);
if ((mBufferInfo.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
if (!endOfStream) {
Log.w(TAG, "reached end of stream unexpectedly");
} else {
if (VERBOSE) Log.d(TAG, "end of stream reached");
}
break; // out of while
}
}
}
}
Issue Analytics
- State:
- Created 4 years ago
- Reactions:1
- Comments:9
Top Results From Across the Web
How to save/export a lottie animation as a video file
Here's a list of what I've tried: How to save Lottie Animation as Video (.mp4) and GIF (.gif) in Android? I tried with...
Read more >How to generate videos using Lottie in Android - Medium
This class is quite simple, and gets to be something like: First of all we should scale manually our Lottie animation so it...
Read more >How to add Lottie Animation in an Android app - GeeksforGeeks
Approach: Step 1: Add this dependency into the App level gradle module of the project and then sync the gradle with the project....
Read more >Convert Lottie to GIF - LottieFiles
Convert your Lottie Animations to GIF ... LottieFiles is by Design Barn Inc. ... We care about your data, and we'd love to...
Read more >Videos/GIF/Lottie - Anima Documentation
How To Embed Videos / GIFs / Lottie · Select the layer that will become the video, GIF, Lottie animation · Under the...
Read more >Top Related Medium Post
No results found
Top Related StackOverflow Question
No results found
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start FreeTop Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found
Top GitHub Comments
@axitasavani @gpeal hello i found solution of lottie animation convert to mp4 step 1: load animation in LottieAnimationView Step 2 : get duration of LottieAnimationView after set resorce Example: LottieAnimationView.getDuration(); step 3: LottieAnimationView.setDrawingCacheEnabled(true); step 4: use value animator and put duration of animation
Example: i = 0; ValueAnimator animator = ValueAnimator.ofFloat(0f, 1f).setDuration(duration); animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { Log.e(“progress”, “progress”); animationView.setProgress((Float) animation.getAnimatedValue()); //here you can get bitmap of every time; Bitmap bitmap = animationView.getDrawingCache(); StaticUtils.saveBitmap(MainActivity.this, bitmap, i); i++; } }); animator.start(); animator.addListener(new Animator.AnimatorListener() { @Override public void onAnimationStart(Animator animation) {
step 5:you can see in above example onAnimationUpdate method using getDrawingCache method get bitmap and save in one folder
step 6:now you have multiple images there you can just make video from image using ffmpeg and generate mp4 file
thank you
we can use in flutter