465 lines
15 KiB
Java
Executable File
465 lines
15 KiB
Java
Executable File
/*
|
|
* Copyright (C) 2010 The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
|
|
package android.media.videoeditor;
|
|
|
|
import java.io.File;
|
|
import java.io.FileNotFoundException;
|
|
import java.io.FileOutputStream;
|
|
import java.io.IOException;
|
|
import java.io.DataOutputStream;
|
|
import java.nio.ByteBuffer;
|
|
import java.nio.IntBuffer;
|
|
|
|
import android.graphics.Canvas;
|
|
import android.graphics.Paint;
|
|
import android.graphics.Rect;
|
|
import android.graphics.Bitmap;
|
|
import android.graphics.BitmapFactory;
|
|
import android.graphics.Bitmap.CompressFormat;
|
|
import android.util.Pair;
|
|
|
|
|
|
/**
|
|
* This class is used to overlay an image on top of a media item.
|
|
* {@hide}
|
|
*/
|
|
public class OverlayFrame extends Overlay {
|
|
/**
|
|
* Instance variables
|
|
*/
|
|
private Bitmap mBitmap;
|
|
private String mFilename;
|
|
private String mBitmapFileName;
|
|
|
|
private int mOFWidth;
|
|
private int mOFHeight;
|
|
|
|
/**
|
|
* resized RGB Image dimensions
|
|
*/
|
|
private int mResizedRGBWidth;
|
|
private int mResizedRGBHeight;
|
|
|
|
/**
|
|
* The resize paint
|
|
*/
|
|
private static final Paint sResizePaint = new Paint(Paint.FILTER_BITMAP_FLAG);
|
|
|
|
/**
|
|
* An object of this type cannot be instantiated by using the default
|
|
* constructor
|
|
*/
|
|
@SuppressWarnings("unused")
|
|
private OverlayFrame() {
|
|
this(null, null, (String)null, 0, 0);
|
|
}
|
|
|
|
/**
|
|
* Constructor for an OverlayFrame
|
|
*
|
|
* @param mediaItem The media item owner
|
|
* @param overlayId The overlay id
|
|
* @param bitmap The bitmap to be used as an overlay. The size of the
|
|
* bitmap must equal to the size of the media item to which it is
|
|
* added. The bitmap is typically a decoded PNG file.
|
|
* @param startTimeMs The overlay start time in milliseconds
|
|
* @param durationMs The overlay duration in milliseconds
|
|
*
|
|
* @throws IllegalArgumentException if the file type is not PNG or the
|
|
* startTimeMs and durationMs are incorrect.
|
|
*/
|
|
public OverlayFrame(MediaItem mediaItem, String overlayId, Bitmap bitmap,
|
|
long startTimeMs,long durationMs) {
|
|
super(mediaItem, overlayId, startTimeMs, durationMs);
|
|
mBitmap = bitmap;
|
|
mFilename = null;
|
|
mBitmapFileName = null;
|
|
mResizedRGBWidth = 0;
|
|
mResizedRGBHeight = 0;
|
|
}
|
|
|
|
/**
|
|
* Constructor for an OverlayFrame. This constructor can be used to
|
|
* restore the overlay after it was saved internally by the video editor.
|
|
*
|
|
* @param mediaItem The media item owner
|
|
* @param overlayId The overlay id
|
|
* @param filename The file name that contains the overlay.
|
|
* @param startTimeMs The overlay start time in milliseconds
|
|
* @param durationMs The overlay duration in milliseconds
|
|
*
|
|
* @throws IllegalArgumentException if the file type is not PNG or the
|
|
* startTimeMs and durationMs are incorrect.
|
|
*/
|
|
OverlayFrame(MediaItem mediaItem, String overlayId, String filename,
|
|
long startTimeMs,long durationMs) {
|
|
super(mediaItem, overlayId, startTimeMs, durationMs);
|
|
mBitmapFileName = filename;
|
|
mBitmap = BitmapFactory.decodeFile(mBitmapFileName);
|
|
mFilename = null;
|
|
mResizedRGBWidth = 0;
|
|
mResizedRGBHeight = 0;
|
|
}
|
|
|
|
/**
|
|
* Get the overlay bitmap.
|
|
*
|
|
* @return Get the overlay bitmap
|
|
*/
|
|
public Bitmap getBitmap() {
|
|
return mBitmap;
|
|
}
|
|
|
|
/**
|
|
* Get the overlay bitmap.
|
|
*
|
|
* @return Get the overlay bitmap as png file.
|
|
*/
|
|
String getBitmapImageFileName() {
|
|
return mBitmapFileName;
|
|
}
|
|
/**
|
|
* Set the overlay bitmap.
|
|
*
|
|
* @param bitmap The overlay bitmap.
|
|
*/
|
|
public void setBitmap(Bitmap bitmap) {
|
|
getMediaItem().getNativeContext().setGeneratePreview(true);
|
|
|
|
invalidate();
|
|
|
|
mBitmap = bitmap;
|
|
if (mFilename != null) {
|
|
/**
|
|
* Delete the file
|
|
*/
|
|
new File(mFilename).delete();
|
|
/**
|
|
* Invalidate the filename
|
|
*/
|
|
mFilename = null;
|
|
}
|
|
|
|
/**
|
|
* Invalidate the transitions if necessary
|
|
*/
|
|
getMediaItem().invalidateTransitions(mStartTimeMs, mDurationMs);
|
|
}
|
|
|
|
/**
|
|
* Get the file name of this overlay
|
|
*/
|
|
String getFilename() {
|
|
return mFilename;
|
|
}
|
|
|
|
/*
|
|
* Set the file name of this overlay
|
|
*/
|
|
void setFilename(String filename) {
|
|
mFilename = filename;
|
|
}
|
|
/**
|
|
* Save the overlay to the project folder
|
|
*
|
|
* @param path The path where the overlay will be saved
|
|
*
|
|
* @return The filename
|
|
* @throws FileNotFoundException if the bitmap cannot be saved
|
|
* @throws IOException if the bitmap file cannot be saved
|
|
*/
|
|
String save(String path) throws FileNotFoundException, IOException {
|
|
if (mFilename != null) {
|
|
return mFilename;
|
|
}
|
|
|
|
// Create the compressed PNG file
|
|
mBitmapFileName = path + "/" + "Overlay" + getId() + ".png";
|
|
if (!(new File(mBitmapFileName).exists())) {
|
|
final FileOutputStream out = new FileOutputStream (mBitmapFileName);
|
|
mBitmap.compress(CompressFormat.PNG, 100, out);
|
|
out.flush();
|
|
out.close();
|
|
}
|
|
|
|
mOFWidth = mBitmap.getWidth();
|
|
mOFHeight = mBitmap.getHeight();
|
|
|
|
mFilename = path + "/" + "Overlay" + getId() + ".rgb";
|
|
|
|
/* resize and save rgb as per project aspect ratio */
|
|
MediaArtistNativeHelper nativeHelper = (super.getMediaItem()).getNativeContext();
|
|
|
|
/* get height and width for story board aspect ratio */
|
|
final Pair<Integer, Integer> maxResolution;
|
|
final Pair<Integer, Integer>[] resolutions;
|
|
resolutions = MediaProperties.getSupportedResolutions(nativeHelper.nativeHelperGetAspectRatio());
|
|
|
|
// Get the highest resolution
|
|
maxResolution = resolutions[resolutions.length - 1];
|
|
|
|
/* Generate the rgb file with rendering mode */
|
|
generateOverlayWithRenderingMode (super.getMediaItem(), this,
|
|
maxResolution.second /* max Height */ ,
|
|
maxResolution.first /* max Width */);
|
|
|
|
return mFilename;
|
|
}
|
|
|
|
/**
|
|
* Get the OverlayFrame Height
|
|
*/
|
|
int getOverlayFrameHeight() {
|
|
return mOFHeight;
|
|
}
|
|
|
|
/**
|
|
* Get the OverlayFrame Width
|
|
*/
|
|
int getOverlayFrameWidth() {
|
|
return mOFWidth;
|
|
}
|
|
|
|
/*
|
|
* Set the OverlayFrame Height
|
|
*/
|
|
void setOverlayFrameHeight(int height) {
|
|
mOFHeight = height;
|
|
}
|
|
|
|
/*
|
|
* Set the OverlayFrame Width
|
|
*/
|
|
void setOverlayFrameWidth(int width) {
|
|
mOFWidth = width;
|
|
}
|
|
|
|
/*
|
|
* Set the resized RGB widht and height
|
|
*/
|
|
void setResizedRGBSize(int width, int height) {
|
|
mResizedRGBWidth = width;
|
|
mResizedRGBHeight = height;
|
|
}
|
|
|
|
/*
|
|
* Get the resized RGB Height
|
|
*/
|
|
int getResizedRGBSizeHeight() {
|
|
return mResizedRGBHeight;
|
|
}
|
|
|
|
/*
|
|
* Get the resized RGB Width
|
|
*/
|
|
int getResizedRGBSizeWidth() {
|
|
return mResizedRGBWidth;
|
|
}
|
|
|
|
|
|
/**
|
|
* Delete the overlay files
|
|
*/
|
|
void invalidate() {
|
|
if (mBitmap != null) {
|
|
mBitmap.recycle();
|
|
mBitmap = null;
|
|
}
|
|
|
|
if (mFilename != null) {
|
|
new File(mFilename).delete();
|
|
mFilename = null;
|
|
}
|
|
|
|
if (mBitmapFileName != null) {
|
|
new File(mBitmapFileName).delete();
|
|
mBitmapFileName = null;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Delete the overlay related files
|
|
*/
|
|
void invalidateGeneratedFiles() {
|
|
if (mFilename != null) {
|
|
new File(mFilename).delete();
|
|
mFilename = null;
|
|
}
|
|
|
|
if (mBitmapFileName != null) {
|
|
new File(mBitmapFileName).delete();
|
|
mBitmapFileName = null;
|
|
}
|
|
}
|
|
|
|
void generateOverlayWithRenderingMode (MediaItem mediaItemsList, OverlayFrame overlay, int height , int width)
|
|
throws FileNotFoundException, IOException {
|
|
|
|
final MediaItem t = mediaItemsList;
|
|
|
|
/* get the rendering mode */
|
|
int renderMode = t.getRenderingMode();
|
|
|
|
Bitmap overlayBitmap = ((OverlayFrame)overlay).getBitmap();
|
|
|
|
/*
|
|
* Check if the resize of Overlay is needed with rendering mode applied
|
|
* because of change in export dimensions
|
|
*/
|
|
int resizedRGBFileHeight = ((OverlayFrame)overlay).getResizedRGBSizeHeight();
|
|
int resizedRGBFileWidth = ((OverlayFrame)overlay).getResizedRGBSizeWidth();
|
|
|
|
/* Get original bitmap width if it is not resized */
|
|
if(resizedRGBFileWidth == 0) {
|
|
resizedRGBFileWidth = overlayBitmap.getWidth();
|
|
}
|
|
/* Get original bitmap height if it is not resized */
|
|
if(resizedRGBFileHeight == 0) {
|
|
resizedRGBFileHeight = overlayBitmap.getHeight();
|
|
}
|
|
|
|
if (resizedRGBFileWidth != width || resizedRGBFileHeight != height
|
|
|| (!(new File(((OverlayFrame)overlay).getFilename()).exists()))) {
|
|
/*
|
|
* Create the canvas bitmap
|
|
*/
|
|
final Bitmap destBitmap = Bitmap.createBitmap((int)width,
|
|
(int)height,
|
|
Bitmap.Config.ARGB_8888);
|
|
final Canvas overlayCanvas = new Canvas(destBitmap);
|
|
final Rect destRect;
|
|
final Rect srcRect;
|
|
|
|
switch (renderMode) {
|
|
case MediaItem.RENDERING_MODE_STRETCH: {
|
|
destRect = new Rect(0, 0, overlayCanvas.getWidth(),
|
|
overlayCanvas.getHeight());
|
|
srcRect = new Rect(0, 0, overlayBitmap.getWidth(),
|
|
overlayBitmap.getHeight());
|
|
break;
|
|
}
|
|
|
|
case MediaItem.RENDERING_MODE_BLACK_BORDER: {
|
|
int left, right, top, bottom;
|
|
float aROverlayImage, aRCanvas;
|
|
aROverlayImage = (float)(overlayBitmap.getWidth()) /
|
|
(float)(overlayBitmap.getHeight());
|
|
|
|
aRCanvas = (float)(overlayCanvas.getWidth()) /
|
|
(float)(overlayCanvas.getHeight());
|
|
|
|
if (aROverlayImage > aRCanvas) {
|
|
int newHeight = ((overlayCanvas.getWidth() * overlayBitmap.getHeight())
|
|
/ overlayBitmap.getWidth());
|
|
left = 0;
|
|
top = (overlayCanvas.getHeight() - newHeight) / 2;
|
|
right = overlayCanvas.getWidth();
|
|
bottom = top + newHeight;
|
|
} else {
|
|
int newWidth = ((overlayCanvas.getHeight() * overlayBitmap.getWidth())
|
|
/ overlayBitmap.getHeight());
|
|
left = (overlayCanvas.getWidth() - newWidth) / 2;
|
|
top = 0;
|
|
right = left + newWidth;
|
|
bottom = overlayCanvas.getHeight();
|
|
}
|
|
|
|
destRect = new Rect(left, top, right, bottom);
|
|
srcRect = new Rect(0, 0, overlayBitmap.getWidth(), overlayBitmap.getHeight());
|
|
break;
|
|
}
|
|
|
|
case MediaItem.RENDERING_MODE_CROPPING: {
|
|
// Calculate the source rect
|
|
int left, right, top, bottom;
|
|
float aROverlayImage, aRCanvas;
|
|
aROverlayImage = (float)(overlayBitmap.getWidth()) /
|
|
(float)(overlayBitmap.getHeight());
|
|
aRCanvas = (float)(overlayCanvas.getWidth()) /
|
|
(float)(overlayCanvas.getHeight());
|
|
if (aROverlayImage < aRCanvas) {
|
|
int newHeight = ((overlayBitmap.getWidth() * overlayCanvas.getHeight())
|
|
/ overlayCanvas.getWidth());
|
|
|
|
left = 0;
|
|
top = (overlayBitmap.getHeight() - newHeight) / 2;
|
|
right = overlayBitmap.getWidth();
|
|
bottom = top + newHeight;
|
|
} else {
|
|
int newWidth = ((overlayBitmap.getHeight() * overlayCanvas.getWidth())
|
|
/ overlayCanvas.getHeight());
|
|
left = (overlayBitmap.getWidth() - newWidth) / 2;
|
|
top = 0;
|
|
right = left + newWidth;
|
|
bottom = overlayBitmap.getHeight();
|
|
}
|
|
|
|
srcRect = new Rect(left, top, right, bottom);
|
|
destRect = new Rect(0, 0, overlayCanvas.getWidth(), overlayCanvas.getHeight());
|
|
break;
|
|
}
|
|
|
|
default: {
|
|
throw new IllegalStateException("Rendering mode: " + renderMode);
|
|
}
|
|
}
|
|
|
|
overlayCanvas.drawBitmap(overlayBitmap, srcRect, destRect, sResizePaint);
|
|
|
|
/*
|
|
* Write to the dest file
|
|
*/
|
|
String outFileName = ((OverlayFrame)overlay).getFilename();
|
|
|
|
/*
|
|
* Save the image to same rgb file
|
|
*/
|
|
if (outFileName != null) {
|
|
new File(outFileName).delete();
|
|
}
|
|
|
|
final FileOutputStream fl = new FileOutputStream(outFileName);
|
|
final DataOutputStream dos = new DataOutputStream(fl);
|
|
|
|
/*
|
|
* Populate the rgb file with bitmap data
|
|
*/
|
|
final int [] framingBuffer = new int[width];
|
|
ByteBuffer byteBuffer = ByteBuffer.allocate(framingBuffer.length * 4);
|
|
IntBuffer intBuffer;
|
|
|
|
byte[] array = byteBuffer.array();
|
|
int tmp = 0;
|
|
while(tmp < height) {
|
|
destBitmap.getPixels(framingBuffer,0,width,0,tmp,width,1);
|
|
intBuffer = byteBuffer.asIntBuffer();
|
|
intBuffer.put(framingBuffer,0,width);
|
|
dos.write(array);
|
|
tmp += 1;
|
|
}
|
|
fl.flush();
|
|
fl.close();
|
|
|
|
/*
|
|
* Set the resized RGB width and height
|
|
*/
|
|
((OverlayFrame)overlay).setResizedRGBSize(width, height);
|
|
}
|
|
}
|
|
}
|