blob: d159df26363705f9b6b7538c2a859a37c35267f2 [file] [log] [blame]
/*
* 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);
overlayCanvas.setBitmap(null);
/*
* 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);
}
}
}