1/*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17
18package android.media.videoeditor;
19
20import java.io.IOException;
21import java.util.List;
22import java.util.concurrent.CancellationException;
23import android.graphics.Bitmap;
24import android.graphics.Color;
25import android.graphics.Canvas;
26import android.graphics.Paint;
27import android.graphics.Rect;
28import android.view.SurfaceHolder;
29
30/**
31 * This is the interface implemented by classes which provide video editing
32 * functionality. The VideoEditor implementation class manages all input and
33 * output files. Unless specifically mentioned, methods are blocking. A typical
34 * editing session may consist of the following sequence of operations:
35 *
36 * <ul>
37 *  <li>Add a set of MediaItems</li>
38 *  <li>Apply a set of Transitions between MediaItems</li>
39 *  <li>Add Effects and Overlays to media items</li>
40 *  <li>Preview the movie at any time</li>
41 *  <li>Save the VideoEditor implementation class internal state</li>
42 *  <li>Release the VideoEditor implementation class instance by invoking
43 * {@link #release()}
44 * </ul>
45 * The internal VideoEditor state consists of the following elements:
46 * <ul>
47 *  <li>Ordered & trimmed MediaItems</li>
48 *  <li>Transition video clips</li>
49 *  <li>Overlays</li>
50 *  <li>Effects</li>
51 *  <li>Audio waveform for the background audio and MediaItems</li>
52 *  <li>Project thumbnail</li>
53 *  <li>Last exported movie.</li>
54 *  <li>Other project specific data such as the current aspect ratio.</li>
55 * </ul>
56 * {@hide}
57 */
58public interface VideoEditor {
59    /**
60     *  The file name of the project thumbnail
61     */
62    public static final String THUMBNAIL_FILENAME = "thumbnail.jpg";
63
64    /**
65     *  Use this value instead of the specific end of the storyboard timeline
66     *  value.
67     */
68    public final static int DURATION_OF_STORYBOARD = -1;
69
70    /**
71     *  Maximum supported file size
72     */
73    public static final long MAX_SUPPORTED_FILE_SIZE = 2147483648L;
74
75    /**
76     * This listener interface is used by the VideoEditor to emit preview
77     * progress notifications. This callback should be invoked after the number
78     * of frames specified by
79     * {@link #startPreview(SurfaceHolder surfaceHolder, long fromMs,
80     *           int callbackAfterFrameCount, PreviewProgressListener listener)}
81     */
82    public interface PreviewProgressListener {
83        /**
84         * This method notifies the listener of the current time position while
85         * previewing a project.
86         *
87         * @param videoEditor The VideoEditor instance
88         * @param timeMs The current preview position (expressed in milliseconds
89         *        since the beginning of the storyboard timeline).
90         * @param overlayData The overlay data (null if the overlay data
91         *      is unchanged)
92         */
93        public void onProgress(VideoEditor videoEditor, long timeMs,
94                               OverlayData overlayData);
95        /**
96         * This method notifies the listener when the preview is started
97         * previewing a project.
98         *
99         * @param videoEditor The VideoEditor instance
100         */
101        public void onStart(VideoEditor videoEditor);
102
103        /**
104         * This method notifies the listener when the preview is stopped
105         * previewing a project.
106         *
107         * @param videoEditor The VideoEditor instance
108         */
109        public void onStop(VideoEditor videoEditor);
110
111        /**
112         * This method notifies the listener when error has occurred during
113         * previewing a project.
114         *
115         * @param videoEditor The VideoEditor instance
116         * @param error The error that has occurred
117         * FIXME: We should pass well-defined error code to the application;
118         * but for now, we just pass whatever error code reported by the native layer.
119         */
120        public void onError(VideoEditor videoEditor, int error);
121    }
122
123    /**
124     * This listener interface is used by the VideoEditor to emit export status
125     * notifications.
126     * {@link #export(String filename, ExportProgressListener listener,
127     *                int height, int bitrate)}
128     */
129    public interface ExportProgressListener {
130        /**
131         * This method notifies the listener of the progress status of a export
132         * operation.
133         *
134         * @param videoEditor The VideoEditor instance
135         * @param filename The name of the file which is in the process of being
136         *        exported.
137         * @param progress The progress in %. At the beginning of the export,
138         *        this value is set to 0; at the end, the value is set to 100.
139         */
140        public void onProgress(VideoEditor videoEditor, String filename,
141                              int progress);
142    }
143
144    public interface MediaProcessingProgressListener {
145        /**
146         *  Values used for the action parameter
147         */
148        public static final int ACTION_ENCODE = 1;
149        public static final int ACTION_DECODE = 2;
150
151        /**
152         * This method notifies the listener of the progress status of
153         * processing a media object such as a Transition, AudioTrack & Kenburns
154         * This method may be called maximum 100 times for one operation.
155         *
156         * @param object The object that is being processed such as a Transition
157         *               or AudioTrack
158         * @param action The type of processing being performed
159         * @param progress The progress in %. At the beginning of the operation,
160         *          this value is set to 0; at the end, the value is set to 100.
161         */
162        public void onProgress(Object item, int action, int progress);
163    }
164
165    /**
166     * The overlay data
167     */
168    public static final class OverlayData {
169        // Instance variables
170        private Bitmap mOverlayBitmap;
171        private int mRenderingMode;
172        private boolean mClear;
173        private static final Paint sResizePaint = new Paint(Paint.FILTER_BITMAP_FLAG);
174
175        /**
176         * Default constructor
177         */
178        public OverlayData() {
179            mOverlayBitmap = null;
180            mRenderingMode = MediaArtistNativeHelper.MediaRendering.BLACK_BORDERS;
181            mClear = false;
182        }
183
184        /**
185         * Releases the bitmap
186         */
187        public void release() {
188            if (mOverlayBitmap != null) {
189                mOverlayBitmap.recycle();
190                mOverlayBitmap = null;
191            }
192        }
193
194        /**
195         * Check if the overlay needs to be rendered
196         *
197         * @return true if rendering is needed
198         */
199        public boolean needsRendering() {
200            return (mClear || mOverlayBitmap != null);
201        }
202
203        /**
204         * Store the overlay data
205         *
206         * @param overlayBitmap The overlay bitmap
207         * @param renderingMode The rendering mode
208         */
209        void set(Bitmap overlayBitmap, int renderingMode) {
210            mOverlayBitmap = overlayBitmap;
211            mRenderingMode = renderingMode;
212            mClear = false;
213        }
214
215        /**
216         * Clear the overlay
217         */
218        void setClear() {
219            mClear = true;
220        }
221
222        /**
223        * Render the overlay by either clearing it or by
224        * rendering the overlay bitmap with the specified
225        * rendering mode
226        *
227        * @param destBitmap The destination bitmap
228        */
229        public void renderOverlay(Bitmap destBitmap) {
230            if (mClear) {
231                destBitmap.eraseColor(Color.TRANSPARENT);
232            } else if (mOverlayBitmap != null) {
233                final Canvas overlayCanvas = new Canvas(destBitmap);
234                final Rect destRect;
235                final Rect srcRect;
236                switch (mRenderingMode) {
237                    case MediaArtistNativeHelper.MediaRendering.RESIZING: {
238                        destRect = new Rect(0, 0, overlayCanvas.getWidth(),
239                                                 overlayCanvas.getHeight());
240                        srcRect = new Rect(0, 0, mOverlayBitmap.getWidth(),
241                                                 mOverlayBitmap.getHeight());
242                        break;
243                    }
244
245                    case MediaArtistNativeHelper.MediaRendering.BLACK_BORDERS: {
246                        int left, right, top, bottom;
247                        float aROverlayImage, aRCanvas;
248                        aROverlayImage = (float)(mOverlayBitmap.getWidth()) /
249                                         (float)(mOverlayBitmap.getHeight());
250
251                        aRCanvas = (float)(overlayCanvas.getWidth()) /
252                                         (float)(overlayCanvas.getHeight());
253
254                        if (aROverlayImage > aRCanvas) {
255                            int newHeight = ((overlayCanvas.getWidth() * mOverlayBitmap.getHeight())
256                                             / mOverlayBitmap.getWidth());
257                            left = 0;
258                            top  = (overlayCanvas.getHeight() - newHeight) / 2;
259                            right = overlayCanvas.getWidth();
260                            bottom = top + newHeight;
261                        } else {
262                            int newWidth = ((overlayCanvas.getHeight() * mOverlayBitmap.getWidth())
263                                                / mOverlayBitmap.getHeight());
264                            left = (overlayCanvas.getWidth() - newWidth) / 2;
265                            top  = 0;
266                            right = left + newWidth;
267                            bottom = overlayCanvas.getHeight();
268                        }
269
270                        destRect = new Rect(left, top, right, bottom);
271                        srcRect = new Rect(0, 0, mOverlayBitmap.getWidth(), mOverlayBitmap.getHeight());
272                        break;
273                    }
274
275                    case MediaArtistNativeHelper.MediaRendering.CROPPING: {
276                        // Calculate the source rect
277                        int left, right, top, bottom;
278                        float aROverlayImage, aRCanvas;
279                        aROverlayImage = (float)(mOverlayBitmap.getWidth()) /
280                                         (float)(mOverlayBitmap.getHeight());
281                        aRCanvas = (float)(overlayCanvas.getWidth()) /
282                                        (float)(overlayCanvas.getHeight());
283                        if (aROverlayImage < aRCanvas) {
284                            int newHeight = ((mOverlayBitmap.getWidth() * overlayCanvas.getHeight())
285                                       / overlayCanvas.getWidth());
286
287                            left = 0;
288                            top  = (mOverlayBitmap.getHeight() - newHeight) / 2;
289                            right = mOverlayBitmap.getWidth();
290                            bottom = top + newHeight;
291                        } else {
292                            int newWidth = ((mOverlayBitmap.getHeight() * overlayCanvas.getWidth())
293                                        / overlayCanvas.getHeight());
294                            left = (mOverlayBitmap.getWidth() - newWidth) / 2;
295                            top  = 0;
296                            right = left + newWidth;
297                            bottom = mOverlayBitmap.getHeight();
298                        }
299
300                        srcRect = new Rect(left, top, right, bottom);
301                        destRect = new Rect(0, 0, overlayCanvas.getWidth(), overlayCanvas.getHeight());
302                        break;
303                    }
304
305                    default: {
306                        throw new IllegalStateException("Rendering mode: " + mRenderingMode);
307                    }
308                }
309
310                destBitmap.eraseColor(Color.TRANSPARENT);
311                overlayCanvas.drawBitmap(mOverlayBitmap, srcRect, destRect, sResizePaint);
312
313                mOverlayBitmap.recycle();
314            }
315        }
316    }
317
318    /**
319     * @return The path where the VideoEditor stores all files related to the
320     *         project
321     */
322    public String getPath();
323
324    /**
325     * This method releases all in-memory resources used by the VideoEditor
326     * instance. All pending operations such as preview, export and extract
327     * audio waveform must be canceled.
328     */
329    public void release();
330
331    /**
332     * Persist the current internal state of VideoEditor to the project path.
333     * The VideoEditor state may be restored by invoking the
334     * {@link VideoEditorFactory#load(String)} method. This method does not
335     * release the internal in-memory state of the VideoEditor. To release
336     * the in-memory state of the VideoEditor the {@link #release()} method
337     * must be invoked.
338     *
339     * Pending transition generations must be allowed to complete before the
340     * state is saved.
341     * Pending audio waveform generations must be allowed to complete.
342     * Pending export operations must be allowed to continue.
343     *
344     * @throws IOException if the internal state cannot be saved to project file
345     */
346    public void save() throws IOException;
347
348    /**
349     * Create the output movie based on all media items added and the applied
350     * storyboard items. This method can take a long time to execute and is
351     * blocking. The application will receive progress notifications via the
352     * ExportProgressListener. Specific implementations may not support multiple
353     * simultaneous export operations. Note that invoking methods which would
354     * change the contents of the output movie throw an IllegalStateException
355     * while an export operation is pending.
356     *
357     * The audio and video codecs are automatically selected by the underlying
358     * implementation.
359     *
360     * @param filename The output file name (including the full path)
361     * @param height The height of the output video file. The supported values
362     *        for height are described in the MediaProperties class, for
363     *        example: HEIGHT_480. The width will be automatically computed
364     *        according to the aspect ratio provided by
365     *        {@link #setAspectRatio(int)}
366     * @param bitrate The bitrate of the output video file. This is approximate
367     *        value for the output movie. Supported bitrate values are
368     *        described in the MediaProperties class for example: BITRATE_384K
369     * @param listener The listener for progress notifications. Use null if
370     *        export progress notifications are not needed.
371     *
372     * @throws IllegalArgumentException if height or bitrate are not supported
373     *        or if the audio or video codecs are not supported
374     * @throws IOException if output file cannot be created
375     * @throws IllegalStateException if a preview or an export is in progress or
376     *        if no MediaItem has been added
377     * @throws CancellationException if export is canceled by calling
378     *        {@link #cancelExport()}
379     * @throws UnsupportOperationException if multiple simultaneous export() are
380     *        not allowed
381     */
382    public void export(String filename, int height, int bitrate,
383                       ExportProgressListener listener)
384                       throws IOException;
385
386    /**
387     * Create the output movie based on all media items added and the applied
388     * storyboard items. This method can take a long time to execute and is
389     * blocking. The application will receive progress notifications via the
390     * ExportProgressListener. Specific implementations may not support multiple
391     * simultaneous export operations. Note that invoking methods which would
392     * change the contents of the output movie throw an IllegalStateException
393     * while an export operation is pending.
394     *
395     * @param filename The output file name (including the full path)
396     * @param height The height of the output video file. The supported values
397     *        for height are described in the MediaProperties class, for
398     *        example: HEIGHT_480. The width will be automatically computed
399     *        according to the aspect ratio provided by
400     *        {@link #setAspectRatio(int)}
401     * @param bitrate The bitrate of the output video file. This is approximate
402     *        value for the output movie. Supported bitrate values are
403     *        described in the MediaProperties class for example: BITRATE_384K
404     * @param audioCodec The audio codec to be used for the export. The audio
405     *        codec values are defined in the MediaProperties class (e.g.
406     *        ACODEC_AAC_LC). Note that not all audio codec types are
407     *        supported for export purposes.
408     * @param videoCodec The video codec to be used for the export. The video
409     *        codec values are defined in the MediaProperties class (e.g.
410     *        VCODEC_H264). Note that not all video codec types are
411     *        supported for export purposes.
412     * @param listener The listener for progress notifications. Use null if
413     *        export progress notifications are not needed.
414     *
415     * @throws IllegalArgumentException if height or bitrate are not supported
416     *        or if the audio or video codecs are not supported
417     * @throws IOException if output file cannot be created
418     * @throws IllegalStateException if a preview or an export is in progress or
419     *        if no MediaItem has been added
420     * @throws CancellationException if export is cancelled by calling
421     *        {@link #cancelExport()}
422     * @throws UnsupportOperationException if multiple simultaneous export() are
423     *        not allowed
424     */
425    public void export(String filename, int height, int bitrate, int audioCodec,
426                       int videoCodec, ExportProgressListener listener)
427                       throws IOException;
428
429    /**
430     * Cancel the running export operation. This method blocks until the export
431     * is cancelled and the exported file (if any) is deleted. If the export
432     * completed by the time this method is invoked, the export file will be
433     * deleted.
434     *
435     * @param filename The filename which identifies the export operation to be
436     *            canceled.
437     **/
438    public void cancelExport(String filename);
439
440    /**
441     * Add a media item at the end of the storyboard.
442     *
443     * @param mediaItem The media item object to add
444     *
445     * @throws IllegalStateException if a preview or an export is in progress or
446     *        if the media item id is not unique across all the media items
447     *        added.
448     */
449    public void addMediaItem(MediaItem mediaItem);
450
451    /**
452     * Insert a media item after the media item with the specified id.
453     *
454     * @param mediaItem The media item object to insert
455     * @param afterMediaItemId Insert the mediaItem after the media item
456     *        identified by this id. If this parameter is null, the media
457     *        item is inserted at the beginning of the timeline.
458     *
459     * @throws IllegalStateException if a preview or an export is in progress
460     * @throws IllegalArgumentException if media item with the specified id does
461     *        not exist (null is a valid value) or if the media item id is
462     *        not unique across all the media items added.
463     */
464    public void insertMediaItem(MediaItem mediaItem, String afterMediaItemId);
465
466    /**
467     * Move a media item after the media item with the specified id.
468     *
469     * Note: The project thumbnail is regenerated if the media item is or
470     * becomes the first media item in the storyboard timeline.
471     *
472     * @param mediaItemId The id of the media item to move
473     * @param afterMediaItemId Move the media item identified by mediaItemId
474     *        after the media item identified by this parameter. If this
475     *        parameter is null, the media item is moved at the beginning of
476     *        the timeline.
477     *
478     * @throws IllegalStateException if a preview or an export is in progress
479     * @throws IllegalArgumentException if one of media item ids is invalid
480     *        (null is a valid value)
481     */
482    public void moveMediaItem(String mediaItemId, String afterMediaItemId);
483
484    /**
485     * Remove the media item with the specified id. If there are transitions
486     * before or after this media item, then this/these transition(s) are
487     * removed from the storyboard. If the extraction of the audio waveform is
488     * in progress, the extraction is canceled and the file is deleted.
489     *
490     * Effects and overlays associated with the media item will also be removed.
491     *
492     * Note: The project thumbnail is regenerated if the media item which is
493     * removed is the first media item in the storyboard or if the media item is
494     * the only one in the storyboard. If the media item is the only one in the
495     * storyboard, the project thumbnail will be set to a black frame and the
496     * aspect ratio will revert to the default aspect ratio and this method is
497     * equivalent to removeAllMediaItems() in this case.
498     *
499     * @param mediaItemId The unique id of the media item to be removed
500     *
501     * @return The media item that was removed
502     *
503     * @throws IllegalStateException if a preview or an export is in progress
504     * @throws IllegalArgumentException if media item with the specified id does
505     *        not exist
506     */
507    public MediaItem removeMediaItem(String mediaItemId);
508
509    /**
510     * Remove all media items in the storyboard. All effects, overlays and all
511     * transitions are also removed.
512     *
513     * Note: The project thumbnail will be set to a black frame and the aspect
514     * ratio will revert to the default aspect ratio.
515     *
516     * @throws IllegalStateException if a preview or an export is in progress
517     */
518    public void removeAllMediaItems();
519
520    /**
521     * Get the list of media items in the order in which it they appear in the
522     * storyboard timeline.
523     *
524     * Note that if any media item source files are no longer
525     * accessible, this method will still provide the full list of media items.
526     *
527     * @return The list of media items. If no media item exist an empty list
528     *        will be returned.
529     */
530    public List<MediaItem> getAllMediaItems();
531
532    /**
533     * Find the media item with the specified id
534     *
535     * @param mediaItemId The media item id
536     *
537     * @return The media item with the specified id (null if it does not exist)
538     */
539    public MediaItem getMediaItem(String mediaItemId);
540
541    /**
542     * Add a transition between the media items specified by the transition.
543     * If a transition existed at the same position it is invalidated and then
544     * the transition is replaced. Note that the new transition video clip is
545     * not automatically generated by this method. The
546     * {@link Transition#generate()} method must be invoked to generate
547     * the transition video clip.
548     *
549     * Note that the TransitionAtEnd and TransitionAtStart are special kinds
550     * that can not be applied between two media items.
551     *
552     * A crossfade audio transition will be automatically applied regardless of
553     * the video transition.
554     *
555     * @param transition The transition to apply
556     *
557     * @throws IllegalStateException if a preview or an export is in progress
558     * @throws IllegalArgumentException if the transition duration is larger
559     *        than the smallest duration of the two media item files or if
560     *        the two media items specified in the transition are not
561     *        adjacent
562     */
563    public void addTransition(Transition transition);
564
565    /**
566     * Remove the transition with the specified id.
567     *
568     * @param transitionId The id of the transition to be removed
569     *
570     * @return The transition that was removed
571     *
572     * @throws IllegalStateException if a preview or an export is in progress
573     * @throws IllegalArgumentException if transition with the specified id does
574     *        not exist
575     */
576    public Transition removeTransition(String transitionId);
577
578    /**
579     * Get the list of transitions
580     *
581     * @return The list of transitions. If no transitions exist an empty list
582     *        will be returned.
583     */
584    public List<Transition> getAllTransitions();
585
586    /**
587     * Find the transition with the specified transition id.
588     *
589     * @param transitionId The transition id
590     *
591     * @return The transition
592     */
593    public Transition getTransition(String transitionId);
594
595    /**
596     * Add the specified AudioTrack to the storyboard. Note: Specific
597     * implementations may support a limited number of audio tracks (e.g. only
598     * one audio track)
599     *
600     * @param audioTrack The AudioTrack to add
601     *
602     * @throws UnsupportedOperationException if the implementation supports a
603     *        limited number of audio tracks.
604     * @throws IllegalArgumentException if media item is not unique across all
605     *        the audio tracks already added.
606     */
607    public void addAudioTrack(AudioTrack audioTrack);
608
609    /**
610     * Insert an audio track after the audio track with the specified id. Use
611     * addAudioTrack to add an audio track at the end of the storyboard
612     * timeline.
613     *
614     * @param audioTrack The audio track object to insert
615     * @param afterAudioTrackId Insert the audio track after the audio track
616     *        identified by this parameter. If this parameter is null the
617     *        audio track is added at the beginning of the timeline.
618     *
619     * @throws IllegalStateException if a preview or an export is in progress
620     * @throws IllegalArgumentException if media item with the specified id does
621     *        not exist (null is a valid value). if media item is not unique
622     *        across all the audio tracks already added.
623     * @throws UnsupportedOperationException if the implementation supports a
624     *        limited number of audio tracks
625     */
626    public void insertAudioTrack(AudioTrack audioTrack, String afterAudioTrackId);
627
628    /**
629     * Move an AudioTrack after the AudioTrack with the specified id.
630     *
631     * @param audioTrackId The id of the AudioTrack to move
632     * @param afterAudioTrackId Move the AudioTrack identified by audioTrackId
633     *        after the AudioTrack identified by this parameter. If this
634     *        parameter is null the audio track is added at the beginning of
635     *        the timeline.
636     *
637     * @throws IllegalStateException if a preview or an export is in progress
638     * @throws IllegalArgumentException if one of media item ids is invalid
639     *        (null is a valid value)
640     */
641    public void moveAudioTrack(String audioTrackId, String afterAudioTrackId);
642
643    /**
644     * Remove the audio track with the specified id. If the extraction of the
645     * audio waveform is in progress, the extraction is canceled and the file is
646     * deleted.
647     *
648     * @param audioTrackId The id of the audio track to be removed
649     *
650     * @return The audio track that was removed
651     * @throws IllegalStateException if a preview or an export is in progress
652     */
653    public AudioTrack removeAudioTrack(String audioTrackId);
654
655    /**
656     * Get the list of AudioTracks in order in which they appear in the
657     * storyboard.
658     *
659     * Note that if any AudioTrack source files are not accessible anymore,
660     * this method will still provide the full list of audio tracks.
661     *
662     * @return The list of AudioTracks. If no audio tracks exist an empty list
663     *        will be returned.
664     */
665    public List<AudioTrack> getAllAudioTracks();
666
667    /**
668     * Find the AudioTrack with the specified id
669     *
670     * @param audioTrackId The AudioTrack id
671     *
672     * @return The AudioTrack with the specified id (null if it does not exist)
673     */
674    public AudioTrack getAudioTrack(String audioTrackId);
675
676    /**
677     * Set the aspect ratio used in the preview and the export movie.
678     *
679     * The default aspect ratio is ASPECTRATIO_16_9 (16:9).
680     *
681     * @param aspectRatio to apply. If aspectRatio is the same as the current
682     *        aspect ratio, then this function just returns. The supported
683     *        aspect ratio are defined in the MediaProperties class for
684     *        example: ASPECTRATIO_16_9
685     *
686     * @throws IllegalStateException if a preview or an export is in progress
687     * @throws IllegalArgumentException if aspect ratio is not supported
688     */
689    public void setAspectRatio(int aspectRatio);
690
691    /**
692     * Get current aspect ratio.
693     *
694     * @return The aspect ratio as described in MediaProperties
695     */
696    public int getAspectRatio();
697
698    /**
699     * Get the preview (and output movie) duration.
700     *
701     * @return The duration of the preview (and output movie)
702     */
703    public long getDuration();
704
705    /**
706     * Render a frame according to the preview aspect ratio and activating all
707     * storyboard items relative to the specified time.
708     *
709     * @param surfaceHolder SurfaceHolder used by the application
710     * @param timeMs time corresponding to the frame to display
711     * @param overlayData The overlay data
712     *
713     * @return The accurate time stamp of the frame that is rendered.
714     *
715     * @throws IllegalStateException if a preview or an export is already in
716     *        progress
717     * @throws IllegalArgumentException if time is negative or beyond the
718     *        preview duration
719     */
720    public long renderPreviewFrame(SurfaceHolder surfaceHolder, long timeMs,
721            OverlayData overlayData);
722
723    /**
724     * This method must be called after any changes made to the storyboard
725     * and before startPreview is called. Note that this method may block for an
726     * extensive period of time.
727     */
728    public void generatePreview(MediaProcessingProgressListener listener);
729
730    /**
731     * Start the preview of all the storyboard items applied on all MediaItems
732     * This method does not block (does not wait for the preview to complete).
733     * The PreviewProgressListener allows to track the progress at the time
734     * interval determined by the callbackAfterFrameCount parameter. The
735     * SurfaceHolder has to be created and ready for use before calling this
736     * method. The method is a no-op if there are no MediaItems in the
737     * storyboard.
738     *
739     * @param surfaceHolder SurfaceHolder where the preview is rendered.
740     * @param fromMs The time (relative to the timeline) at which the preview
741     *        will start
742     * @param toMs The time (relative to the timeline) at which the preview will
743     *        stop. Use -1 to play to the end of the timeline
744     * @param loop true if the preview should be looped once it reaches the end
745     * @param callbackAfterFrameCount The listener interface should be invoked
746     *        after the number of frames specified by this parameter.
747     * @param listener The listener which will be notified of the preview
748     *        progress
749     *
750     * @throws IllegalArgumentException if fromMs is beyond the preview duration
751     * @throws IllegalStateException if a preview or an export is already in
752     *        progress
753     */
754    public void startPreview(SurfaceHolder surfaceHolder, long fromMs, long toMs,
755                             boolean loop,int callbackAfterFrameCount,
756                             PreviewProgressListener listener);
757
758    /**
759     * Stop the current preview. This method blocks until ongoing preview is
760     * stopped. Ignored if there is no preview running.
761     *
762     * @return The accurate current time when stop is effective expressed in
763     *        milliseconds
764     */
765    public long stopPreview();
766
767    /**
768     * Clears the preview surface
769     *
770     * @param surfaceHolder SurfaceHolder where the preview is rendered
771     * and needs to be cleared.
772     */
773    public void clearSurface(SurfaceHolder surfaceHolder);
774}
775