Skip to content

Commit

Permalink
Optimized MovieFrame#renderFrame
Browse files Browse the repository at this point in the history
Reviewed By: oprisnik

Differential Revision: D8940188

fbshipit-source-id: de8186e95058214cbca263d53e50cc4d945c0490
  • Loading branch information
MrMannWood authored and facebook-github-bot committed Jul 21, 2018
1 parent 5d271f3 commit 2116559
Show file tree
Hide file tree
Showing 3 changed files with 67 additions and 29 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -33,15 +33,15 @@ public CloseableImage decode(
ImageDecodeOptions options) {

Movie movie = Movie.decodeStream(encodedImage.getInputStream());
MovieScaleHolder movieScaleHolder = new MovieScaleHolder(movie.width(), movie.height());
MovieDrawer drawer = new MovieDrawer(movie);

List<Integer> frameStartTimes = getMovieFrameStartTimes(movie);

MovieFrame[] frames = new MovieFrame[frameStartTimes.size()];
for (int i = 0, N = frameStartTimes.size(); i < N; i++) {
int frameStart = frameStartTimes.get(i);
int frameDuration = (i == N - 1 ? movie.duration() : frameStartTimes.get(i + 1)) - frameStart;
frames[i] = new MovieFrame(movie, movieScaleHolder, frameStart, frameDuration);
frames[i] = new MovieFrame(drawer, frameStart, frameDuration, movie.width(), movie.height());
}

return new CloseableAnimatedImage(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/*
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
package com.facebook.animated.giflite;

import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Movie;
import android.support.annotation.Nullable;

/**
* Pronounced Draw-er Draws frames of a {@link Movie} to a bitmap. All methods are synchronized, so
* can be used in parallel. The underlying {@link #mMovie} is not threadsafe, and should therefore
* not be accessed outside of {@link MovieDrawer}. Attempts to optimize work done by the drawing
* {@link Canvas} by detecting if the underlying {@link Bitmap} has changed.
*/
class MovieDrawer {

private final Movie mMovie;
private final MovieScaleHolder mScaleHolder;
private final Canvas mCanvas;

private @Nullable Bitmap mPreviousBitmap;

public MovieDrawer(Movie movie) {
mMovie = movie;
mScaleHolder = new MovieScaleHolder(movie.width(), movie.height());
mCanvas = new Canvas();
}

public synchronized void drawFrame(int movieTime, int w, int h, Bitmap bitmap) {
mMovie.setTime(movieTime);

if (mPreviousBitmap != null && mPreviousBitmap.isRecycled()) {
mPreviousBitmap = null;
}
if (mPreviousBitmap != bitmap) {
mPreviousBitmap = bitmap;
mCanvas.setBitmap(bitmap);
}

mScaleHolder.updateViewPort(w, h);

mCanvas.save();
mCanvas.scale(mScaleHolder.getScale(), mScaleHolder.getScale());
mMovie.draw(mCanvas, mScaleHolder.getLeft(), mScaleHolder.getTop());
mCanvas.restore();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,49 +8,35 @@
package com.facebook.animated.giflite;

import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Movie;
import android.support.annotation.Nullable;
import com.facebook.imagepipeline.animated.base.AnimatedImageFrame;

/**
* Simple wrapper for an animated image frame back by {@link Movie}. All {@link MovieFrame} for the
* same {@link MovieAnimatedImage} will be backed by the same {@link Movie} and can therefore not be
* used in parallel.
* Simple wrapper for an animated image frame back by {@link MovieDrawer}. All {@link MovieFrame}
* for the same {@link MovieAnimatedImage} will be backed by the same {@link MovieDrawer}.
*/
class MovieFrame implements AnimatedImageFrame {

private final Movie mMovie;
private final MovieScaleHolder mScaleHolder;
private final MovieDrawer mMovieDrawer;
private final int mFrameStart;
private final int mFrameDuration;
private @Nullable Canvas mCanvas;
private final int mFrameWidth;
private final int mFrameHeight;

public MovieFrame(Movie movie, MovieScaleHolder scaleHolder, int frameStart, int frameDuration) {
mMovie = movie;
mScaleHolder = scaleHolder;
public MovieFrame(
MovieDrawer movieDrawer, int frameStart, int frameDuration, int frameWidth, int frameHeight) {
mMovieDrawer = movieDrawer;
mFrameStart = frameStart;
mFrameDuration = frameDuration;
mFrameWidth = frameWidth;
mFrameHeight = frameHeight;
}

@Override
public void dispose() {}

@Override
public void renderFrame(int w, int h, Bitmap bitmap) {
mMovie.setTime(mFrameStart);

if (mCanvas == null) {
mCanvas = new Canvas(bitmap);
} else {
mCanvas.setBitmap(bitmap);
}

mScaleHolder.updateViewPort(w, h);
mCanvas.save();
mCanvas.scale(mScaleHolder.getScale(), mScaleHolder.getScale());
mMovie.draw(mCanvas, mScaleHolder.getLeft(), mScaleHolder.getTop());
mCanvas.restore();
mMovieDrawer.drawFrame(mFrameStart, w, h, bitmap);
}

@Override
Expand All @@ -60,12 +46,12 @@ public int getDurationMs() {

@Override
public int getWidth() {
return mMovie.width();
return mFrameWidth;
}

@Override
public int getHeight() {
return mMovie.height();
return mFrameHeight;
}

@Override
Expand Down

0 comments on commit 2116559

Please sign in to comment.