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