/* * 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.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.StringWriter; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Map; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import org.xmlpull.v1.XmlSerializer; import android.graphics.Bitmap; import android.graphics.Rect; import android.util.Log; import android.util.Xml; import android.view.Surface; import android.view.SurfaceHolder; /** * The VideoEditor implementation {@hide} */ public class VideoEditorImpl implements VideoEditor { /* * Logging */ private static final String TAG = "VideoEditorImpl"; /* * The project filename */ private static final String PROJECT_FILENAME = "videoeditor.xml"; /* * XML tags */ private static final String TAG_PROJECT = "project"; private static final String TAG_MEDIA_ITEMS = "media_items"; private static final String TAG_MEDIA_ITEM = "media_item"; private static final String TAG_TRANSITIONS = "transitions"; private static final String TAG_TRANSITION = "transition"; private static final String TAG_OVERLAYS = "overlays"; private static final String TAG_OVERLAY = "overlay"; private static final String TAG_OVERLAY_USER_ATTRIBUTES = "overlay_user_attributes"; private static final String TAG_EFFECTS = "effects"; private static final String TAG_EFFECT = "effect"; private static final String TAG_AUDIO_TRACKS = "audio_tracks"; private static final String TAG_AUDIO_TRACK = "audio_track"; private static final String ATTR_ID = "id"; private static final String ATTR_FILENAME = "filename"; private static final String ATTR_AUDIO_WAVEFORM_FILENAME = "waveform"; private static final String ATTR_RENDERING_MODE = "rendering_mode"; private static final String ATTR_ASPECT_RATIO = "aspect_ratio"; private static final String ATTR_REGENERATE_PCM = "regeneratePCMFlag"; private static final String ATTR_TYPE = "type"; private static final String ATTR_DURATION = "duration"; private static final String ATTR_START_TIME = "start_time"; private static final String ATTR_BEGIN_TIME = "begin_time"; private static final String ATTR_END_TIME = "end_time"; private static final String ATTR_VOLUME = "volume"; private static final String ATTR_BEHAVIOR = "behavior"; private static final String ATTR_DIRECTION = "direction"; private static final String ATTR_BLENDING = "blending"; private static final String ATTR_INVERT = "invert"; private static final String ATTR_MASK = "mask"; private static final String ATTR_BEFORE_MEDIA_ITEM_ID = "before_media_item"; private static final String ATTR_AFTER_MEDIA_ITEM_ID = "after_media_item"; private static final String ATTR_COLOR_EFFECT_TYPE = "color_type"; private static final String ATTR_COLOR_EFFECT_VALUE = "color_value"; private static final String ATTR_START_RECT_LEFT = "start_l"; private static final String ATTR_START_RECT_TOP = "start_t"; private static final String ATTR_START_RECT_RIGHT = "start_r"; private static final String ATTR_START_RECT_BOTTOM = "start_b"; private static final String ATTR_END_RECT_LEFT = "end_l"; private static final String ATTR_END_RECT_TOP = "end_t"; private static final String ATTR_END_RECT_RIGHT = "end_r"; private static final String ATTR_END_RECT_BOTTOM = "end_b"; private static final String ATTR_LOOP = "loop"; private static final String ATTR_MUTED = "muted"; private static final String ATTR_DUCK_ENABLED = "ducking_enabled"; private static final String ATTR_DUCK_THRESHOLD = "ducking_threshold"; private static final String ATTR_DUCKED_TRACK_VOLUME = "ducking_volume"; private static final String ATTR_GENERATED_IMAGE_CLIP = "generated_image_clip"; private static final String ATTR_IS_IMAGE_CLIP_GENERATED = "is_image_clip_generated"; private static final String ATTR_GENERATED_TRANSITION_CLIP = "generated_transition_clip"; private static final String ATTR_IS_TRANSITION_GENERATED = "is_transition_generated"; private static final String ATTR_OVERLAY_RGB_FILENAME = "overlay_rgb_filename"; private static final String ATTR_OVERLAY_FRAME_WIDTH = "overlay_frame_width"; private static final String ATTR_OVERLAY_FRAME_HEIGHT = "overlay_frame_height"; /* * Instance variables */ private long mDurationMs; private final String mProjectPath; private final List mMediaItems = new ArrayList(); private final List mAudioTracks = new ArrayList(); private final List mTransitions = new ArrayList(); private int mAspectRatio; /* * Private Object for calling native Methods via MediaArtistNativeHelper */ private MediaArtistNativeHelper mMANativeHelper; private boolean mPreviewInProgress = false; /** * Constructor * * @param projectPath - The path where the VideoEditor stores all files * related to the project */ public VideoEditorImpl(String projectPath) throws IOException { mMANativeHelper = new MediaArtistNativeHelper(projectPath, this); mProjectPath = projectPath; final File projectXml = new File(projectPath, PROJECT_FILENAME); if (projectXml.exists()) { try { load(); } catch (Exception ex) { ex.printStackTrace(); throw new IOException(ex.toString()); } } else { mAspectRatio = MediaProperties.ASPECT_RATIO_16_9; mDurationMs = 0; } } /* * @return The MediaArtistNativeHelper object */ MediaArtistNativeHelper getNativeContext() { return mMANativeHelper; } /* * {@inheritDoc} */ public synchronized void addAudioTrack(AudioTrack audioTrack) { if (audioTrack == null) { throw new IllegalArgumentException("Audio Track is null"); } if (mAudioTracks.size() == 1) { throw new IllegalArgumentException("No more tracks can be added"); } mMANativeHelper.setGeneratePreview(true); /* * Add the audio track to AudioTrack list */ mAudioTracks.add(audioTrack); /* * Form the audio PCM file path */ final String audioTrackPCMFilePath = String.format(mProjectPath + "/" + "AudioPcm" + audioTrack.getId() + ".pcm"); /* * Create PCM only if not generated in previous session */ if (new File(audioTrackPCMFilePath).exists()) { mMANativeHelper.setAudioflag(false); } } /* * {@inheritDoc} */ public synchronized void addMediaItem(MediaItem mediaItem) { /* * Validate Media Item */ if (mediaItem == null) { throw new IllegalArgumentException("Media item is null"); } /* * Add the Media item to MediaItem list */ if (mMediaItems.contains(mediaItem)) { throw new IllegalArgumentException("Media item already exists: " + mediaItem.getId()); } mMANativeHelper.setGeneratePreview(true); /* * Invalidate the end transition if necessary */ final int mediaItemsCount = mMediaItems.size(); if (mediaItemsCount > 0) { removeTransitionAfter(mediaItemsCount - 1); } /* * Add the new media item */ mMediaItems.add(mediaItem); computeTimelineDuration(); /* * Generate project thumbnail only from first media Item on storyboard */ if (mMediaItems.size() == 1) { generateProjectThumbnail(); } } /* * {@inheritDoc} */ public synchronized void addTransition(Transition transition) { if (transition == null) { throw new IllegalArgumentException("Null Transition"); } final MediaItem beforeMediaItem = transition.getBeforeMediaItem(); final MediaItem afterMediaItem = transition.getAfterMediaItem(); /* * Check if the MediaItems are in sequence */ if (mMediaItems == null) { throw new IllegalArgumentException("No media items are added"); } if ((afterMediaItem != null) && (beforeMediaItem != null)) { final int afterMediaItemIndex = mMediaItems.indexOf(afterMediaItem); final int beforeMediaItemIndex = mMediaItems.indexOf(beforeMediaItem); if ((afterMediaItemIndex == -1) || (beforeMediaItemIndex == -1)) { throw new IllegalArgumentException ("Either of the mediaItem is not found in the list"); } if (afterMediaItemIndex != (beforeMediaItemIndex - 1) ) { throw new IllegalArgumentException("MediaItems are not in sequence"); } } mMANativeHelper.setGeneratePreview(true); mTransitions.add(transition); /* * Cross reference the transitions */ if (afterMediaItem != null) { /* * If a transition already exists at the specified position then * invalidate it. */ if (afterMediaItem.getEndTransition() != null) { afterMediaItem.getEndTransition().invalidate(); mTransitions.remove(afterMediaItem.getEndTransition()); } afterMediaItem.setEndTransition(transition); } if (beforeMediaItem != null) { /* * If a transition already exists at the specified position then * invalidate it. */ if (beforeMediaItem.getBeginTransition() != null) { beforeMediaItem.getBeginTransition().invalidate(); mTransitions.remove(beforeMediaItem.getBeginTransition()); } beforeMediaItem.setBeginTransition(transition); } computeTimelineDuration(); } /* * {@inheritDoc} */ public void cancelExport(String filename) { if (mMANativeHelper != null && filename != null) { mMANativeHelper.stop(filename); } } /* * {@inheritDoc} */ public void export(String filename, int height, int bitrate, int audioCodec, int videoCodec, ExportProgressListener listener) throws IOException { switch (audioCodec) { case MediaProperties.ACODEC_AAC_LC: break; case MediaProperties.ACODEC_AMRNB: break; default: { String message = "Unsupported audio codec type " + audioCodec; throw new IllegalArgumentException(message); } } switch (videoCodec) { case MediaProperties.VCODEC_H263: break; case MediaProperties.VCODEC_H264BP: break; case MediaProperties.VCODEC_MPEG4: break; default: { String message = "Unsupported video codec type " + videoCodec; throw new IllegalArgumentException(message); } } export(filename, height, bitrate, listener); } /* * {@inheritDoc} */ public void export(String filename, int height, int bitrate, ExportProgressListener listener) throws IOException { if (filename == null) { throw new IllegalArgumentException("export: filename is null"); } final File tempPathFile = new File(filename); if (tempPathFile == null) { throw new IOException(filename + "can not be created"); } if (mMediaItems.size() == 0) { throw new IllegalStateException("No MediaItems added"); } switch (height) { case MediaProperties.HEIGHT_144: break; case MediaProperties.HEIGHT_360: break; case MediaProperties.HEIGHT_480: break; case MediaProperties.HEIGHT_720: break; default: { String message = "Unsupported height value " + height; throw new IllegalArgumentException(message); } } switch (bitrate) { case MediaProperties.BITRATE_28K: break; case MediaProperties.BITRATE_40K: break; case MediaProperties.BITRATE_64K: break; case MediaProperties.BITRATE_96K: break; case MediaProperties.BITRATE_128K: break; case MediaProperties.BITRATE_192K: break; case MediaProperties.BITRATE_256K: break; case MediaProperties.BITRATE_384K: break; case MediaProperties.BITRATE_512K: break; case MediaProperties.BITRATE_800K: break; case MediaProperties.BITRATE_2M: break; case MediaProperties.BITRATE_5M: break; case MediaProperties.BITRATE_8M: break; default: { final String message = "Unsupported bitrate value " + bitrate; throw new IllegalArgumentException(message); } } boolean semAcquireDone = false; try { mMANativeHelper.lock(); semAcquireDone = true; mMANativeHelper.export(filename, mProjectPath, height,bitrate, mMediaItems, mTransitions, mAudioTracks, listener); } catch (InterruptedException ex) { Log.e(TAG, "Sem acquire NOT successful in export"); } finally { if (semAcquireDone) { mMANativeHelper.unlock(); } } } /* * {@inheritDoc} */ public void generatePreview(MediaProcessingProgressListener listener) { boolean semAcquireDone = false; try { mMANativeHelper.lock(); semAcquireDone = true; if ((mMediaItems.size() > 0) || (mAudioTracks.size() > 0)) { mMANativeHelper.previewStoryBoard(mMediaItems, mTransitions, mAudioTracks, listener); } } catch (InterruptedException ex) { Log.e(TAG, "Sem acquire NOT successful in previewStoryBoard"); } finally { if (semAcquireDone) { mMANativeHelper.unlock(); } } } /* * {@inheritDoc} */ public List getAllAudioTracks() { return mAudioTracks; } /* * {@inheritDoc} */ public List getAllMediaItems() { return mMediaItems; } /* * {@inheritDoc} */ public List getAllTransitions() { return mTransitions; } /* * {@inheritDoc} */ public int getAspectRatio() { return mAspectRatio; } /* * {@inheritDoc} */ public AudioTrack getAudioTrack(String audioTrackId) { for (AudioTrack at : mAudioTracks) { if (at.getId().equals(audioTrackId)) { return at; } } return null; } /* * {@inheritDoc} */ public long getDuration() { /** * Since MediaImageItem can change duration we need to compute the * duration here */ computeTimelineDuration(); return mDurationMs; } /* * Force updates the timeline duration */ void updateTimelineDuration() { computeTimelineDuration(); } /* * {@inheritDoc} */ public synchronized MediaItem getMediaItem(String mediaItemId) { for (MediaItem mediaItem : mMediaItems) { if (mediaItem.getId().equals(mediaItemId)) { return mediaItem; } } return null; } /* * {@inheritDoc} */ public String getPath() { return mProjectPath; } /* * {@inheritDoc} */ public Transition getTransition(String transitionId) { for (Transition transition : mTransitions) { if (transition.getId().equals(transitionId)) { return transition; } } return null; } /* * {@inheritDoc} */ public synchronized void insertAudioTrack(AudioTrack audioTrack, String afterAudioTrackId) { if (mAudioTracks.size() == 1) { throw new IllegalArgumentException("No more tracks can be added"); } if (afterAudioTrackId == null) { mMANativeHelper.setGeneratePreview(true); mAudioTracks.add(0, audioTrack); } else { final int audioTrackCount = mAudioTracks.size(); for (int i = 0; i < audioTrackCount; i++) { AudioTrack at = mAudioTracks.get(i); if (at.getId().equals(afterAudioTrackId)) { mMANativeHelper.setGeneratePreview(true); mAudioTracks.add(i + 1, audioTrack); return; } } throw new IllegalArgumentException("AudioTrack not found: " + afterAudioTrackId); } } /* * {@inheritDoc} */ public synchronized void insertMediaItem(MediaItem mediaItem, String afterMediaItemId) { if (mMediaItems.contains(mediaItem)) { throw new IllegalArgumentException("Media item already exists: " + mediaItem.getId()); } if (afterMediaItemId == null) { mMANativeHelper.setGeneratePreview(true); if (mMediaItems.size() > 0) { /** * Invalidate the transition at the beginning of the timeline */ removeTransitionBefore(0); } mMediaItems.add(0, mediaItem); computeTimelineDuration(); generateProjectThumbnail(); } else { final int mediaItemCount = mMediaItems.size(); for (int i = 0; i < mediaItemCount; i++) { final MediaItem mi = mMediaItems.get(i); if (mi.getId().equals(afterMediaItemId)) { mMANativeHelper.setGeneratePreview(true); /** * Invalidate the transition at this position */ removeTransitionAfter(i); /** * Insert the new media item */ mMediaItems.add(i + 1, mediaItem); computeTimelineDuration(); return; } } throw new IllegalArgumentException("MediaItem not found: " + afterMediaItemId); } } /* * {@inheritDoc} */ public synchronized void moveAudioTrack(String audioTrackId, String afterAudioTrackId) { throw new IllegalStateException("Not supported"); } /* * {@inheritDoc} */ public synchronized void moveMediaItem(String mediaItemId, String afterMediaItemId) { final MediaItem moveMediaItem = removeMediaItem(mediaItemId,true); if (moveMediaItem == null) { throw new IllegalArgumentException("Target MediaItem not found: " + mediaItemId); } if (afterMediaItemId == null) { if (mMediaItems.size() > 0) { mMANativeHelper.setGeneratePreview(true); /** * Invalidate adjacent transitions at the insertion point */ removeTransitionBefore(0); /** * Insert the media item at the new position */ mMediaItems.add(0, moveMediaItem); computeTimelineDuration(); generateProjectThumbnail(); } else { throw new IllegalStateException("Cannot move media item (it is the only item)"); } } else { final int mediaItemCount = mMediaItems.size(); for (int i = 0; i < mediaItemCount; i++) { final MediaItem mi = mMediaItems.get(i); if (mi.getId().equals(afterMediaItemId)) { mMANativeHelper.setGeneratePreview(true); /** * Invalidate adjacent transitions at the insertion point */ removeTransitionAfter(i); /** * Insert the media item at the new position */ mMediaItems.add(i + 1, moveMediaItem); computeTimelineDuration(); return; } } throw new IllegalArgumentException("MediaItem not found: " + afterMediaItemId); } } /* * {@inheritDoc} */ public void release() { stopPreview(); mMediaItems.clear(); mAudioTracks.clear(); mTransitions.clear(); mMANativeHelper.releaseNativeHelper(); mMANativeHelper = null; } /* * {@inheritDoc} */ public synchronized void removeAllMediaItems() { mMANativeHelper.setGeneratePreview(true); mMediaItems.clear(); /** * Invalidate all transitions */ for (Transition transition : mTransitions) { transition.invalidate(); } mTransitions.clear(); mDurationMs = 0; /** * If a thumbnail already exists, then delete it */ if ((new File(mProjectPath + "/" + THUMBNAIL_FILENAME)).exists()) { (new File(mProjectPath + "/" + THUMBNAIL_FILENAME)).delete(); } } /* * {@inheritDoc} */ public synchronized AudioTrack removeAudioTrack(String audioTrackId) { final AudioTrack audioTrack = getAudioTrack(audioTrackId); if (audioTrack != null) { mMANativeHelper.setGeneratePreview(true); mAudioTracks.remove(audioTrack); audioTrack.invalidate(); mMANativeHelper.invalidatePcmFile(); mMANativeHelper.setAudioflag(true); } else { throw new IllegalArgumentException(" No more audio tracks"); } return audioTrack; } /* * {@inheritDoc} */ public synchronized MediaItem removeMediaItem(String mediaItemId) { final String firstItemString = mMediaItems.get(0).getId(); final MediaItem mediaItem = getMediaItem(mediaItemId); if (mediaItem != null) { mMANativeHelper.setGeneratePreview(true); /** * Remove the media item */ mMediaItems.remove(mediaItem); if (mediaItem instanceof MediaImageItem) { ((MediaImageItem)mediaItem).invalidate(); } final List overlays = mediaItem.getAllOverlays(); if (overlays.size() > 0) { for (Overlay overlay : overlays) { if (overlay instanceof OverlayFrame) { final OverlayFrame overlayFrame = (OverlayFrame)overlay; overlayFrame.invalidate(); } } } /** * Remove the adjacent transitions */ removeAdjacentTransitions(mediaItem); computeTimelineDuration(); } /** * If string equals first mediaItem, then * generate Project thumbnail */ if (firstItemString.equals(mediaItemId)) { generateProjectThumbnail(); } if (mediaItem instanceof MediaVideoItem) { /** * Delete the graph file */ ((MediaVideoItem)mediaItem).invalidate(); } return mediaItem; } private synchronized MediaItem removeMediaItem(String mediaItemId, boolean flag) { final String firstItemString = mMediaItems.get(0).getId(); final MediaItem mediaItem = getMediaItem(mediaItemId); if (mediaItem != null) { mMANativeHelper.setGeneratePreview(true); /** * Remove the media item */ mMediaItems.remove(mediaItem); /** * Remove the adjacent transitions */ removeAdjacentTransitions(mediaItem); computeTimelineDuration(); } /** * If string equals first mediaItem, then * generate Project thumbail */ if (firstItemString.equals(mediaItemId)) { generateProjectThumbnail(); } return mediaItem; } /* * {@inheritDoc} */ public synchronized Transition removeTransition(String transitionId) { final Transition transition = getTransition(transitionId); if (transition == null) { throw new IllegalStateException("Transition not found: " + transitionId); } mMANativeHelper.setGeneratePreview(true); /** * Remove the transition references */ final MediaItem afterMediaItem = transition.getAfterMediaItem(); if (afterMediaItem != null) { afterMediaItem.setEndTransition(null); } final MediaItem beforeMediaItem = transition.getBeforeMediaItem(); if (beforeMediaItem != null) { beforeMediaItem.setBeginTransition(null); } mTransitions.remove(transition); transition.invalidate(); computeTimelineDuration(); return transition; } /* * {@inheritDoc} */ public long renderPreviewFrame(SurfaceHolder surfaceHolder, long timeMs, OverlayData overlayData) { if (surfaceHolder == null) { throw new IllegalArgumentException("Surface Holder is null"); } final Surface surface = surfaceHolder.getSurface(); if (surface == null) { throw new IllegalArgumentException("Surface could not be retrieved from Surface holder"); } if (timeMs < 0) { throw new IllegalArgumentException("requested time not correct"); } else if (timeMs > mDurationMs) { throw new IllegalArgumentException("requested time more than duration"); } long result = 0; boolean semAcquireDone = false; try { mMANativeHelper.lock(); semAcquireDone = true; if (mMediaItems.size() > 0) { final Rect frame = surfaceHolder.getSurfaceFrame(); result = mMANativeHelper.renderPreviewFrame(surface, timeMs, frame.width(), frame.height(), overlayData); } else { result = 0; } } catch (InterruptedException ex) { Log.e(TAG, "Sem acquire NOT successful in renderPreviewFrame"); } finally { if (semAcquireDone) { mMANativeHelper.unlock(); } } Log.i("VE_IMPL","renderPreviewFrame <--"); return result; } /** * the project form XML */ private void load() throws FileNotFoundException, XmlPullParserException, IOException { final File file = new File(mProjectPath, PROJECT_FILENAME); /** * Load the metadata */ final FileInputStream fis = new FileInputStream(file); try { final XmlPullParser parser = Xml.newPullParser(); parser.setInput(fis, "UTF-8"); int eventType = parser.getEventType(); String name; MediaItem currentMediaItem = null; Overlay currentOverlay = null; while (eventType != XmlPullParser.END_DOCUMENT) { switch (eventType) { case XmlPullParser.START_TAG: { name = parser.getName(); if (TAG_PROJECT.equals(name)) { mAspectRatio = Integer.parseInt(parser.getAttributeValue("", ATTR_ASPECT_RATIO)); final boolean mRegenPCM = Boolean.parseBoolean(parser.getAttributeValue("", ATTR_REGENERATE_PCM)); mMANativeHelper.setAudioflag(mRegenPCM); } else if (TAG_MEDIA_ITEM.equals(name)) { final String mediaItemId = parser.getAttributeValue("", ATTR_ID); final String type = parser.getAttributeValue("", ATTR_TYPE); final String filename = parser.getAttributeValue("", ATTR_FILENAME); final int renderingMode = Integer.parseInt(parser.getAttributeValue("", ATTR_RENDERING_MODE)); if (MediaImageItem.class.getSimpleName().equals(type)) { final long durationMs = Long.parseLong(parser.getAttributeValue("", ATTR_DURATION)); currentMediaItem = new MediaImageItem(this, mediaItemId, filename, durationMs, renderingMode); } else if (MediaVideoItem.class.getSimpleName().equals(type)) { final long beginMs = Long.parseLong(parser.getAttributeValue("", ATTR_BEGIN_TIME)); final long endMs = Long.parseLong(parser.getAttributeValue("", ATTR_END_TIME)); final int volume = Integer.parseInt(parser.getAttributeValue("", ATTR_VOLUME)); final boolean muted = Boolean.parseBoolean(parser.getAttributeValue("", ATTR_MUTED)); final String audioWaveformFilename = parser.getAttributeValue("", ATTR_AUDIO_WAVEFORM_FILENAME); currentMediaItem = new MediaVideoItem(this, mediaItemId, filename, renderingMode, beginMs, endMs, volume, muted, audioWaveformFilename); final long beginTimeMs = Long.parseLong(parser.getAttributeValue("", ATTR_BEGIN_TIME)); final long endTimeMs = Long.parseLong(parser.getAttributeValue("", ATTR_END_TIME)); ((MediaVideoItem)currentMediaItem).setExtractBoundaries(beginTimeMs, endTimeMs); final int volumePercent = Integer.parseInt(parser.getAttributeValue("", ATTR_VOLUME)); ((MediaVideoItem)currentMediaItem).setVolume(volumePercent); } else { Log.e(TAG, "Unknown media item type: " + type); currentMediaItem = null; } if (currentMediaItem != null) { mMediaItems.add(currentMediaItem); } } else if (TAG_TRANSITION.equals(name)) { final Transition transition = parseTransition(parser); if (transition != null) { mTransitions.add(transition); } } else if (TAG_OVERLAY.equals(name)) { if (currentMediaItem != null) { currentOverlay = parseOverlay(parser, currentMediaItem); if (currentOverlay != null) { currentMediaItem.addOverlay(currentOverlay); } } } else if (TAG_OVERLAY_USER_ATTRIBUTES.equals(name)) { if (currentOverlay != null) { final int attributesCount = parser.getAttributeCount(); for (int i = 0; i < attributesCount; i++) { currentOverlay.setUserAttribute(parser.getAttributeName(i), parser.getAttributeValue(i)); } } } else if (TAG_EFFECT.equals(name)) { if (currentMediaItem != null) { final Effect effect = parseEffect(parser, currentMediaItem); if (effect != null) { currentMediaItem.addEffect(effect); } if (effect instanceof EffectKenBurns) { final boolean isImageClipGenerated = Boolean.parseBoolean(parser.getAttributeValue("", ATTR_IS_IMAGE_CLIP_GENERATED)); if(isImageClipGenerated) { String filename = parser.getAttributeValue("", ATTR_GENERATED_IMAGE_CLIP); if (new File(filename).exists() == true) { ((MediaImageItem)currentMediaItem). setGeneratedImageClip(filename); ((MediaImageItem)currentMediaItem). setRegenerateClip(false); } else { ((MediaImageItem)currentMediaItem). setGeneratedImageClip(null); ((MediaImageItem)currentMediaItem). setRegenerateClip(true); } } else { ((MediaImageItem)currentMediaItem). setGeneratedImageClip(null); ((MediaImageItem)currentMediaItem). setRegenerateClip(true); } } } } else if (TAG_AUDIO_TRACK.equals(name)) { final AudioTrack audioTrack = parseAudioTrack(parser); if (audioTrack != null) { addAudioTrack(audioTrack); } } break; } case XmlPullParser.END_TAG: { name = parser.getName(); if (TAG_MEDIA_ITEM.equals(name)) { currentMediaItem = null; } else if (TAG_OVERLAY.equals(name)) { currentOverlay = null; } break; } default: { break; } } eventType = parser.next(); } computeTimelineDuration(); } finally { if (fis != null) { fis.close(); } } } /** * Parse the transition * * @param parser The parser * @return The transition */ private Transition parseTransition(XmlPullParser parser) { final String transitionId = parser.getAttributeValue("", ATTR_ID); final String type = parser.getAttributeValue("", ATTR_TYPE); final long durationMs = Long.parseLong(parser.getAttributeValue("", ATTR_DURATION)); final int behavior = Integer.parseInt(parser.getAttributeValue("", ATTR_BEHAVIOR)); final boolean isTransitionGenerated; final String beforeMediaItemId = parser.getAttributeValue("", ATTR_BEFORE_MEDIA_ITEM_ID); final MediaItem beforeMediaItem; if (beforeMediaItemId != null) { beforeMediaItem = getMediaItem(beforeMediaItemId); } else { beforeMediaItem = null; } final String afterMediaItemId = parser.getAttributeValue("", ATTR_AFTER_MEDIA_ITEM_ID); final MediaItem afterMediaItem; if (afterMediaItemId != null) { afterMediaItem = getMediaItem(afterMediaItemId); } else { afterMediaItem = null; } final Transition transition; if (TransitionAlpha.class.getSimpleName().equals(type)) { final int blending = Integer.parseInt(parser.getAttributeValue("", ATTR_BLENDING)); final String maskFilename = parser.getAttributeValue("", ATTR_MASK); final boolean invert = Boolean.getBoolean(parser.getAttributeValue("", ATTR_INVERT)); transition = new TransitionAlpha(transitionId, afterMediaItem, beforeMediaItem, durationMs, behavior, maskFilename, blending, invert); } else if (TransitionCrossfade.class.getSimpleName().equals(type)) { transition = new TransitionCrossfade(transitionId, afterMediaItem, beforeMediaItem, durationMs, behavior); } else if (TransitionSliding.class.getSimpleName().equals(type)) { final int direction = Integer.parseInt(parser.getAttributeValue("", ATTR_DIRECTION)); transition = new TransitionSliding(transitionId, afterMediaItem, beforeMediaItem, durationMs, behavior, direction); } else if (TransitionFadeBlack.class.getSimpleName().equals(type)) { transition = new TransitionFadeBlack(transitionId, afterMediaItem, beforeMediaItem, durationMs, behavior); } else { transition = null; } if (beforeMediaItem != null) { beforeMediaItem.setBeginTransition(transition); } if (afterMediaItem != null) { afterMediaItem.setEndTransition(transition); } isTransitionGenerated = Boolean.parseBoolean(parser.getAttributeValue("", ATTR_IS_TRANSITION_GENERATED)); if (isTransitionGenerated == true) { final String transitionFile = parser.getAttributeValue("", ATTR_GENERATED_TRANSITION_CLIP); if (new File(transitionFile).exists()) { transition.setFilename(transitionFile); } else { transition.setFilename(null); } } return transition; } /** * Parse the overlay * * @param parser The parser * @param mediaItem The media item owner * * @return The overlay */ private Overlay parseOverlay(XmlPullParser parser, MediaItem mediaItem) { final String overlayId = parser.getAttributeValue("", ATTR_ID); final String type = parser.getAttributeValue("", ATTR_TYPE); final long durationMs = Long.parseLong(parser.getAttributeValue("", ATTR_DURATION)); final long startTimeMs = Long.parseLong(parser.getAttributeValue("", ATTR_BEGIN_TIME)); final Overlay overlay; if (OverlayFrame.class.getSimpleName().equals(type)) { final String filename = parser.getAttributeValue("", ATTR_FILENAME); overlay = new OverlayFrame(mediaItem, overlayId, filename, startTimeMs, durationMs); } else { overlay = null; } final String overlayRgbFileName = parser.getAttributeValue("", ATTR_OVERLAY_RGB_FILENAME); if (overlayRgbFileName != null) { ((OverlayFrame)overlay).setFilename(overlayRgbFileName); final int overlayFrameWidth = Integer.parseInt(parser.getAttributeValue("", ATTR_OVERLAY_FRAME_WIDTH)); final int overlayFrameHeight = Integer.parseInt(parser.getAttributeValue("", ATTR_OVERLAY_FRAME_HEIGHT)); ((OverlayFrame)overlay).setOverlayFrameWidth(overlayFrameWidth); ((OverlayFrame)overlay).setOverlayFrameHeight(overlayFrameHeight); } return overlay; } /** * Parse the effect * * @param parser The parser * @param mediaItem The media item owner * * @return The effect */ private Effect parseEffect(XmlPullParser parser, MediaItem mediaItem) { final String effectId = parser.getAttributeValue("", ATTR_ID); final String type = parser.getAttributeValue("", ATTR_TYPE); final long durationMs = Long.parseLong(parser.getAttributeValue("", ATTR_DURATION)); final long startTimeMs = Long.parseLong(parser.getAttributeValue("", ATTR_BEGIN_TIME)); final Effect effect; if (EffectColor.class.getSimpleName().equals(type)) { final int colorEffectType = Integer.parseInt(parser.getAttributeValue("", ATTR_COLOR_EFFECT_TYPE)); final int color; if (colorEffectType == EffectColor.TYPE_COLOR || colorEffectType == EffectColor.TYPE_GRADIENT) { color = Integer.parseInt(parser.getAttributeValue("", ATTR_COLOR_EFFECT_VALUE)); } else { color = 0; } effect = new EffectColor(mediaItem, effectId, startTimeMs, durationMs, colorEffectType, color); } else if (EffectKenBurns.class.getSimpleName().equals(type)) { final Rect startRect = new Rect( Integer.parseInt(parser.getAttributeValue("", ATTR_START_RECT_LEFT)), Integer.parseInt(parser.getAttributeValue("", ATTR_START_RECT_TOP)), Integer.parseInt(parser.getAttributeValue("", ATTR_START_RECT_RIGHT)), Integer.parseInt(parser.getAttributeValue("", ATTR_START_RECT_BOTTOM))); final Rect endRect = new Rect( Integer.parseInt(parser.getAttributeValue("", ATTR_END_RECT_LEFT)), Integer.parseInt(parser.getAttributeValue("", ATTR_END_RECT_TOP)), Integer.parseInt(parser.getAttributeValue("", ATTR_END_RECT_RIGHT)), Integer.parseInt(parser.getAttributeValue("", ATTR_END_RECT_BOTTOM))); effect = new EffectKenBurns(mediaItem, effectId, startRect, endRect, startTimeMs, durationMs); } else { effect = null; } return effect; } /** * Parse the audio track * * @param parser The parser * * @return The audio track */ private AudioTrack parseAudioTrack(XmlPullParser parser) { final String audioTrackId = parser.getAttributeValue("", ATTR_ID); final String filename = parser.getAttributeValue("", ATTR_FILENAME); final long startTimeMs = Long.parseLong(parser.getAttributeValue("", ATTR_START_TIME)); final long beginMs = Long.parseLong(parser.getAttributeValue("", ATTR_BEGIN_TIME)); final long endMs = Long.parseLong(parser.getAttributeValue("", ATTR_END_TIME)); final int volume = Integer.parseInt(parser.getAttributeValue("", ATTR_VOLUME)); final boolean muted = Boolean.parseBoolean(parser.getAttributeValue("", ATTR_MUTED)); final boolean loop = Boolean.parseBoolean(parser.getAttributeValue("", ATTR_LOOP)); final boolean duckingEnabled = Boolean.parseBoolean(parser.getAttributeValue("", ATTR_DUCK_ENABLED)); final int duckThreshold = Integer.parseInt(parser.getAttributeValue("", ATTR_DUCK_THRESHOLD)); final int duckedTrackVolume = Integer.parseInt(parser.getAttributeValue("", ATTR_DUCKED_TRACK_VOLUME)); final String waveformFilename = parser.getAttributeValue("", ATTR_AUDIO_WAVEFORM_FILENAME); try { final AudioTrack audioTrack = new AudioTrack(this, audioTrackId, filename, startTimeMs, beginMs, endMs, loop, volume, muted, duckingEnabled, duckThreshold, duckedTrackVolume, waveformFilename); return audioTrack; } catch (IOException ex) { return null; } } /* * {@inheritDoc} */ public void save() throws IOException { final XmlSerializer serializer = Xml.newSerializer(); final StringWriter writer = new StringWriter(); serializer.setOutput(writer); serializer.startDocument("UTF-8", true); serializer.startTag("", TAG_PROJECT); serializer.attribute("", ATTR_ASPECT_RATIO, Integer.toString(mAspectRatio)); serializer.attribute("", ATTR_REGENERATE_PCM, Boolean.toString(mMANativeHelper.getAudioflag())); serializer.startTag("", TAG_MEDIA_ITEMS); for (MediaItem mediaItem : mMediaItems) { serializer.startTag("", TAG_MEDIA_ITEM); serializer.attribute("", ATTR_ID, mediaItem.getId()); serializer.attribute("", ATTR_TYPE, mediaItem.getClass().getSimpleName()); serializer.attribute("", ATTR_FILENAME, mediaItem.getFilename()); serializer.attribute("", ATTR_RENDERING_MODE, Integer.toString( mediaItem.getRenderingMode())); if (mediaItem instanceof MediaVideoItem) { final MediaVideoItem mvi = (MediaVideoItem)mediaItem; serializer .attribute("", ATTR_BEGIN_TIME, Long.toString(mvi.getBoundaryBeginTime())); serializer.attribute("", ATTR_END_TIME, Long.toString(mvi.getBoundaryEndTime())); serializer.attribute("", ATTR_VOLUME, Integer.toString(mvi.getVolume())); serializer.attribute("", ATTR_MUTED, Boolean.toString(mvi.isMuted())); if (mvi.getAudioWaveformFilename() != null) { serializer.attribute("", ATTR_AUDIO_WAVEFORM_FILENAME, mvi.getAudioWaveformFilename()); } } else if (mediaItem instanceof MediaImageItem) { serializer.attribute("", ATTR_DURATION, Long.toString(mediaItem.getTimelineDuration())); } final List overlays = mediaItem.getAllOverlays(); if (overlays.size() > 0) { serializer.startTag("", TAG_OVERLAYS); for (Overlay overlay : overlays) { serializer.startTag("", TAG_OVERLAY); serializer.attribute("", ATTR_ID, overlay.getId()); serializer.attribute("", ATTR_TYPE, overlay.getClass().getSimpleName()); serializer.attribute("", ATTR_BEGIN_TIME, Long.toString(overlay.getStartTime())); serializer.attribute("", ATTR_DURATION, Long.toString(overlay.getDuration())); if (overlay instanceof OverlayFrame) { final OverlayFrame overlayFrame = (OverlayFrame)overlay; overlayFrame.save(getPath()); if (overlayFrame.getBitmapImageFileName() != null) { serializer.attribute("", ATTR_FILENAME, overlayFrame.getBitmapImageFileName()); } if (overlayFrame.getFilename() != null) { serializer.attribute("", ATTR_OVERLAY_RGB_FILENAME, overlayFrame.getFilename()); serializer.attribute("", ATTR_OVERLAY_FRAME_WIDTH, Integer.toString(overlayFrame.getOverlayFrameWidth())); serializer.attribute("", ATTR_OVERLAY_FRAME_HEIGHT, Integer.toString(overlayFrame.getOverlayFrameHeight())); } } /** * Save the user attributes */ serializer.startTag("", TAG_OVERLAY_USER_ATTRIBUTES); final Map userAttributes = overlay.getUserAttributes(); for (String name : userAttributes.keySet()) { final String value = userAttributes.get(name); if (value != null) { serializer.attribute("", name, value); } } serializer.endTag("", TAG_OVERLAY_USER_ATTRIBUTES); serializer.endTag("", TAG_OVERLAY); } serializer.endTag("", TAG_OVERLAYS); } final List effects = mediaItem.getAllEffects(); if (effects.size() > 0) { serializer.startTag("", TAG_EFFECTS); for (Effect effect : effects) { serializer.startTag("", TAG_EFFECT); serializer.attribute("", ATTR_ID, effect.getId()); serializer.attribute("", ATTR_TYPE, effect.getClass().getSimpleName()); serializer.attribute("", ATTR_BEGIN_TIME, Long.toString(effect.getStartTime())); serializer.attribute("", ATTR_DURATION, Long.toString(effect.getDuration())); if (effect instanceof EffectColor) { final EffectColor colorEffect = (EffectColor)effect; serializer.attribute("", ATTR_COLOR_EFFECT_TYPE, Integer.toString(colorEffect.getType())); if (colorEffect.getType() == EffectColor.TYPE_COLOR || colorEffect.getType() == EffectColor.TYPE_GRADIENT) { serializer.attribute("", ATTR_COLOR_EFFECT_VALUE, Integer.toString(colorEffect.getColor())); } } else if (effect instanceof EffectKenBurns) { final Rect startRect = ((EffectKenBurns)effect).getStartRect(); serializer.attribute("", ATTR_START_RECT_LEFT, Integer.toString(startRect.left)); serializer.attribute("", ATTR_START_RECT_TOP, Integer.toString(startRect.top)); serializer.attribute("", ATTR_START_RECT_RIGHT, Integer.toString(startRect.right)); serializer.attribute("", ATTR_START_RECT_BOTTOM, Integer.toString(startRect.bottom)); final Rect endRect = ((EffectKenBurns)effect).getEndRect(); serializer.attribute("", ATTR_END_RECT_LEFT, Integer.toString(endRect.left)); serializer.attribute("", ATTR_END_RECT_TOP, Integer.toString(endRect.top)); serializer.attribute("", ATTR_END_RECT_RIGHT, Integer.toString(endRect.right)); serializer.attribute("", ATTR_END_RECT_BOTTOM, Integer.toString(endRect.bottom)); final MediaItem mItem = effect.getMediaItem(); if(((MediaImageItem)mItem).getGeneratedImageClip() != null) { serializer.attribute("", ATTR_IS_IMAGE_CLIP_GENERATED,Boolean.toString(true)); serializer.attribute("", ATTR_GENERATED_IMAGE_CLIP, ((MediaImageItem)mItem).getGeneratedImageClip()); } else { serializer.attribute("", ATTR_IS_IMAGE_CLIP_GENERATED, Boolean.toString(false)); } } serializer.endTag("", TAG_EFFECT); } serializer.endTag("", TAG_EFFECTS); } serializer.endTag("", TAG_MEDIA_ITEM); } serializer.endTag("", TAG_MEDIA_ITEMS); serializer.startTag("", TAG_TRANSITIONS); for (Transition transition : mTransitions) { serializer.startTag("", TAG_TRANSITION); serializer.attribute("", ATTR_ID, transition.getId()); serializer.attribute("", ATTR_TYPE, transition.getClass().getSimpleName()); serializer.attribute("", ATTR_DURATION, Long.toString(transition.getDuration())); serializer.attribute("", ATTR_BEHAVIOR, Integer.toString(transition.getBehavior())); serializer.attribute("", ATTR_IS_TRANSITION_GENERATED, Boolean.toString(transition.isGenerated())); if (transition.isGenerated() == true) { serializer.attribute("", ATTR_GENERATED_TRANSITION_CLIP, transition.mFilename); } final MediaItem afterMediaItem = transition.getAfterMediaItem(); if (afterMediaItem != null) { serializer.attribute("", ATTR_AFTER_MEDIA_ITEM_ID, afterMediaItem.getId()); } final MediaItem beforeMediaItem = transition.getBeforeMediaItem(); if (beforeMediaItem != null) { serializer.attribute("", ATTR_BEFORE_MEDIA_ITEM_ID, beforeMediaItem.getId()); } if (transition instanceof TransitionSliding) { serializer.attribute("", ATTR_DIRECTION, Integer.toString(((TransitionSliding)transition).getDirection())); } else if (transition instanceof TransitionAlpha) { TransitionAlpha ta = (TransitionAlpha)transition; serializer.attribute("", ATTR_BLENDING, Integer.toString(ta.getBlendingPercent())); serializer.attribute("", ATTR_INVERT, Boolean.toString(ta.isInvert())); if (ta.getMaskFilename() != null) { serializer.attribute("", ATTR_MASK, ta.getMaskFilename()); } } serializer.endTag("", TAG_TRANSITION); } serializer.endTag("", TAG_TRANSITIONS); serializer.startTag("", TAG_AUDIO_TRACKS); for (AudioTrack at : mAudioTracks) { serializer.startTag("", TAG_AUDIO_TRACK); serializer.attribute("", ATTR_ID, at.getId()); serializer.attribute("", ATTR_FILENAME, at.getFilename()); serializer.attribute("", ATTR_START_TIME, Long.toString(at.getStartTime())); serializer.attribute("", ATTR_BEGIN_TIME, Long.toString(at.getBoundaryBeginTime())); serializer.attribute("", ATTR_END_TIME, Long.toString(at.getBoundaryEndTime())); serializer.attribute("", ATTR_VOLUME, Integer.toString(at.getVolume())); serializer.attribute("", ATTR_DUCK_ENABLED, Boolean.toString(at.isDuckingEnabled())); serializer.attribute("", ATTR_DUCKED_TRACK_VOLUME, Integer.toString(at.getDuckedTrackVolume())); serializer.attribute("", ATTR_DUCK_THRESHOLD, Integer.toString(at.getDuckingThreshhold())); serializer.attribute("", ATTR_MUTED, Boolean.toString(at.isMuted())); serializer.attribute("", ATTR_LOOP, Boolean.toString(at.isLooping())); if (at.getAudioWaveformFilename() != null) { serializer.attribute("", ATTR_AUDIO_WAVEFORM_FILENAME, at.getAudioWaveformFilename()); } serializer.endTag("", TAG_AUDIO_TRACK); } serializer.endTag("", TAG_AUDIO_TRACKS); serializer.endTag("", TAG_PROJECT); serializer.endDocument(); /** * Save the metadata XML file */ final FileOutputStream out = new FileOutputStream(new File(getPath(), PROJECT_FILENAME)); out.write(writer.toString().getBytes()); out.flush(); out.close(); } /* * {@inheritDoc} */ public void setAspectRatio(int aspectRatio) { mAspectRatio = aspectRatio; /** * Invalidate all transitions */ mMANativeHelper.setGeneratePreview(true); for (Transition transition : mTransitions) { transition.invalidate(); } } /* * {@inheritDoc} */ public void startPreview(SurfaceHolder surfaceHolder, long fromMs, long toMs, boolean loop, int callbackAfterFrameCount, PreviewProgressListener listener) { if (surfaceHolder == null) { throw new IllegalArgumentException(); } final Surface surface = surfaceHolder.getSurface(); if (surface == null) { throw new IllegalArgumentException("Surface could not be retrieved from surface holder"); } if (listener == null) { throw new IllegalArgumentException(); } if (fromMs >= mDurationMs) { throw new IllegalArgumentException("Requested time not correct"); } if (fromMs < 0) { throw new IllegalArgumentException("Requested time not correct"); } boolean semAcquireDone = false; try{ mMANativeHelper.lock(); semAcquireDone = true; if (mMediaItems.size() > 0) { mMANativeHelper.previewStoryBoard(mMediaItems, mTransitions, mAudioTracks, null); mMANativeHelper.doPreview(surface, fromMs, toMs, loop, callbackAfterFrameCount, listener); mPreviewInProgress = true; } /** * release on complete by calling stopPreview */ } catch (InterruptedException ex) { Log.e(TAG, "Sem acquire NOT successful in startPreview"); } catch (IllegalArgumentException ex) { Log.e(TAG, "Illegal Argument exception in do preview"); throw ex; } catch (IllegalStateException ex) { Log.e(TAG, "Illegal State exception in do preview"); throw ex; } catch (RuntimeException ex) { Log.e(TAG, "Runtime exception in do preview"); throw ex; } finally { if (semAcquireDone) { mMANativeHelper.unlock(); } } } /* * {@inheritDoc} */ public long stopPreview() { if (mPreviewInProgress) { long result = mMANativeHelper.stopPreview(); mPreviewInProgress = false; /** * release the sem acquired in startPreview */ mMANativeHelper.unlock(); return result; } else { return 0; } } /* * Remove transitions associated with the specified media item * * @param mediaItem The media item */ private void removeAdjacentTransitions(MediaItem mediaItem) { final Transition beginTransition = mediaItem.getBeginTransition(); if (beginTransition != null) { if (beginTransition.getAfterMediaItem() != null) { beginTransition.getAfterMediaItem().setEndTransition(null); } beginTransition.invalidate(); mTransitions.remove(beginTransition); } final Transition endTransition = mediaItem.getEndTransition(); if (endTransition != null) { if (endTransition.getBeforeMediaItem() != null) { endTransition.getBeforeMediaItem().setBeginTransition(null); } endTransition.invalidate(); mTransitions.remove(endTransition); } mediaItem.setBeginTransition(null); mediaItem.setEndTransition(null); } /** * Remove the transition before this media item * * @param index The media item index */ private void removeTransitionBefore(int index) { final MediaItem mediaItem = mMediaItems.get(index); final Iterator it = mTransitions.iterator(); while (it.hasNext()) { Transition t = it.next(); if (t.getBeforeMediaItem() == mediaItem) { mMANativeHelper.setGeneratePreview(true); it.remove(); t.invalidate(); mediaItem.setBeginTransition(null); if (index > 0) { mMediaItems.get(index - 1).setEndTransition(null); } break; } } } /** * Remove the transition after this media item * * @param mediaItem The media item */ private void removeTransitionAfter(int index) { final MediaItem mediaItem = mMediaItems.get(index); final Iterator it = mTransitions.iterator(); while (it.hasNext()) { Transition t = it.next(); if (t.getAfterMediaItem() == mediaItem) { mMANativeHelper.setGeneratePreview(true); it.remove(); t.invalidate(); mediaItem.setEndTransition(null); /** * Invalidate the reference in the next media item */ if (index < mMediaItems.size() - 1) { mMediaItems.get(index + 1).setBeginTransition(null); } break; } } } /** * Compute the duration */ private void computeTimelineDuration() { mDurationMs = 0; final int mediaItemsCount = mMediaItems.size(); for (int i = 0; i < mediaItemsCount; i++) { final MediaItem mediaItem = mMediaItems.get(i); mDurationMs += mediaItem.getTimelineDuration(); if (mediaItem.getEndTransition() != null) { if (i < mediaItemsCount - 1) { mDurationMs -= mediaItem.getEndTransition().getDuration(); } } } } /* * Generate the project thumbnail */ private void generateProjectThumbnail() { /* * If a thumbnail already exists, then delete it first */ if ((new File(mProjectPath + "/" + THUMBNAIL_FILENAME)).exists()) { (new File(mProjectPath + "/" + THUMBNAIL_FILENAME)).delete(); } /* * Generate a new thumbnail for the project from first media Item */ if (mMediaItems.size() > 0) { MediaItem mI = mMediaItems.get(0); /* * Lets initialize the width for default aspect ratio i.e 16:9 */ int height = 480; int width = 854; switch (mI.getAspectRatio()) { case MediaProperties.ASPECT_RATIO_3_2: width = 720; break; case MediaProperties.ASPECT_RATIO_4_3: width = 640; break; case MediaProperties.ASPECT_RATIO_5_3: width = 800; break; case MediaProperties.ASPECT_RATIO_11_9: width = 586; break; case MediaProperties.ASPECT_RATIO_16_9: case MediaProperties.ASPECT_RATIO_UNDEFINED: break; } Bitmap projectBitmap = null; try { projectBitmap = mI.getThumbnail(width, height, 500); } catch (IllegalArgumentException e) { throw new IllegalArgumentException ("Illegal argument error creating project thumbnail"); } catch (IOException e) { throw new IllegalArgumentException ("IO Error creating project thumbnail"); } try { FileOutputStream stream = new FileOutputStream(mProjectPath + "/" + THUMBNAIL_FILENAME); projectBitmap.compress(Bitmap.CompressFormat.JPEG, 100, stream); stream.flush(); stream.close(); } catch (IOException e) { throw new IllegalArgumentException ("Error creating project thumbnail"); } finally { projectBitmap.recycle(); } } } /** * Clears the preview surface * * @param surfaceHolder SurfaceHolder where the preview is rendered * and needs to be cleared. */ public void clearSurface(SurfaceHolder surfaceHolder) { if (surfaceHolder == null) { throw new IllegalArgumentException("Invalid surface holder"); } final Surface surface = surfaceHolder.getSurface(); if (surface == null) { throw new IllegalArgumentException("Surface could not be retrieved from surface holder"); } if (mMANativeHelper != null) { mMANativeHelper.clearPreviewSurface(surface); } else { Log.w(TAG, "Native helper was not ready!"); } } }