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.File;
21import java.io.IOException;
22import java.lang.ref.SoftReference;
23import android.graphics.Bitmap;
24import android.media.videoeditor.MediaArtistNativeHelper.ClipSettings;
25import android.media.videoeditor.MediaArtistNativeHelper.Properties;
26import android.media.videoeditor.VideoEditorProfile;
27import android.view.Surface;
28import android.view.SurfaceHolder;
29
30/**
31 * This class represents a video clip item on the storyboard
32 * {@hide}
33 */
34public class MediaVideoItem extends MediaItem {
35
36    /**
37     *  Instance variables
38     */
39    private final int mWidth;
40    private final int mHeight;
41    private final int mAspectRatio;
42    private final int mFileType;
43    private final int mVideoType;
44    private final int mVideoProfile;
45    private final int mVideoLevel;
46    private final int mVideoBitrate;
47    private final long mDurationMs;
48    private final int mAudioBitrate;
49    private final int mFps;
50    private final int mAudioType;
51    private final int mAudioChannels;
52    private final int mAudioSamplingFrequency;
53    private long mBeginBoundaryTimeMs;
54    private long mEndBoundaryTimeMs;
55    private int mVolumePercentage;
56    private boolean mMuted;
57    private String mAudioWaveformFilename;
58    private MediaArtistNativeHelper mMANativeHelper;
59    private VideoEditorImpl mVideoEditor;
60    private final int mVideoRotationDegree;
61    /**
62     *  The audio waveform data
63     */
64    private SoftReference<WaveformData> mWaveformData;
65
66    /**
67     * An object of this type cannot be instantiated with a default constructor
68     */
69    @SuppressWarnings("unused")
70    private MediaVideoItem() throws IOException {
71        this(null, null, null, RENDERING_MODE_BLACK_BORDER);
72    }
73
74    /**
75     * Constructor
76     *
77     * @param editor The video editor reference
78     * @param mediaItemId The MediaItem id
79     * @param filename The image file name
80     * @param renderingMode The rendering mode
81     *
82     * @throws IOException if the file cannot be opened for reading
83     */
84    public MediaVideoItem(VideoEditor editor, String mediaItemId, String filename,
85            int renderingMode) throws IOException {
86        this(editor, mediaItemId, filename, renderingMode, 0, END_OF_FILE, 100, false, null);
87    }
88
89    /**
90     * Constructor
91     *
92     * @param editor The video editor reference
93     * @param mediaItemId The MediaItem id
94     * @param filename The image file name
95     * @param renderingMode The rendering mode
96     * @param beginMs Start time in milliseconds. Set to 0 to extract from the
97     *           beginning
98     * @param endMs End time in milliseconds. Set to {@link #END_OF_FILE} to
99     *           extract until the end
100     * @param volumePercent in %/. 100% means no change; 50% means half value, 200%
101     *            means double, 0% means silent.
102     * @param muted true if the audio is muted
103     * @param audioWaveformFilename The name of the audio waveform file
104     *
105     * @throws IOException if the file cannot be opened for reading
106     */
107    MediaVideoItem(VideoEditor editor, String mediaItemId, String filename,
108            int renderingMode, long beginMs, long endMs, int volumePercent, boolean muted,
109            String audioWaveformFilename)  throws IOException {
110        super(editor, mediaItemId, filename, renderingMode);
111
112        if (editor instanceof VideoEditorImpl) {
113            mMANativeHelper = ((VideoEditorImpl)editor).getNativeContext();
114            mVideoEditor = ((VideoEditorImpl)editor);
115        }
116
117        final Properties properties;
118        try {
119             properties = mMANativeHelper.getMediaProperties(filename);
120        } catch ( Exception e) {
121            throw new IllegalArgumentException(e.getMessage() + " : " + filename);
122        }
123
124        /** Check the platform specific maximum import resolution */
125        VideoEditorProfile veProfile = VideoEditorProfile.get();
126        if (veProfile == null) {
127            throw new RuntimeException("Can't get the video editor profile");
128        }
129        final int maxInputWidth = veProfile.maxInputVideoFrameWidth;
130        final int maxInputHeight = veProfile.maxInputVideoFrameHeight;
131        if ((properties.width > maxInputWidth) ||
132            (properties.height > maxInputHeight)) {
133            throw new IllegalArgumentException(
134                "Unsupported import resolution. Supported maximum width:" +
135                maxInputWidth + " height:" + maxInputHeight +
136                ", current width:" + properties.width +
137                " height:" + properties.height);
138        }
139        /** Check the platform specific maximum video profile and level */
140        if (!properties.profileSupported) {
141            throw new IllegalArgumentException(
142                "Unsupported video profile " + properties.profile);
143        }
144        if (!properties.levelSupported) {
145            throw new IllegalArgumentException(
146                "Unsupported video level " + properties.level);
147        }
148        switch (mMANativeHelper.getFileType(properties.fileType)) {
149            case MediaProperties.FILE_3GP:
150            case MediaProperties.FILE_MP4:
151            case MediaProperties.FILE_M4V:
152                break;
153
154            default:
155                throw new IllegalArgumentException("Unsupported Input File Type");
156        }
157
158        switch (mMANativeHelper.getVideoCodecType(properties.videoFormat)) {
159            case MediaProperties.VCODEC_H263:
160            case MediaProperties.VCODEC_H264:
161            case MediaProperties.VCODEC_MPEG4:
162                break;
163
164            default:
165                throw new IllegalArgumentException("Unsupported Video Codec Format in Input File");
166        }
167
168        mWidth = properties.width;
169        mHeight = properties.height;
170        mAspectRatio = mMANativeHelper.getAspectRatio(properties.width,
171                properties.height);
172        mFileType = mMANativeHelper.getFileType(properties.fileType);
173        mVideoType = mMANativeHelper.getVideoCodecType(properties.videoFormat);
174        mVideoProfile = properties.profile;
175        mVideoLevel = properties.level;
176        mDurationMs = properties.videoDuration;
177        mVideoBitrate = properties.videoBitrate;
178        mAudioBitrate = properties.audioBitrate;
179        mFps = (int)properties.averageFrameRate;
180        mAudioType = mMANativeHelper.getAudioCodecType(properties.audioFormat);
181        mAudioChannels = properties.audioChannels;
182        mAudioSamplingFrequency =  properties.audioSamplingFrequency;
183        mBeginBoundaryTimeMs = beginMs;
184        mEndBoundaryTimeMs = endMs == END_OF_FILE ? mDurationMs : endMs;
185        mVolumePercentage = volumePercent;
186        mMuted = muted;
187        mAudioWaveformFilename = audioWaveformFilename;
188        if (audioWaveformFilename != null) {
189            mWaveformData = new SoftReference<WaveformData>(
190                        new WaveformData(audioWaveformFilename));
191        } else {
192            mWaveformData = null;
193        }
194        mVideoRotationDegree = properties.videoRotation;
195    }
196
197    /**
198     * Sets the start and end marks for trimming a video media item.
199     * This method will adjust the duration of bounding transitions, effects
200     * and overlays if the current duration of the transactions become greater
201     * than the maximum allowable duration.
202     *
203     * @param beginMs Start time in milliseconds. Set to 0 to extract from the
204     *           beginning
205     * @param endMs End time in milliseconds. Set to {@link #END_OF_FILE} to
206     *           extract until the end
207     *
208     * @throws IllegalArgumentException if the start time is greater or equal than
209     *           end time, the end time is beyond the file duration, the start time
210     *           is negative
211     */
212    public void setExtractBoundaries(long beginMs, long endMs) {
213        if (beginMs > mDurationMs) {
214            throw new IllegalArgumentException("setExtractBoundaries: Invalid start time");
215        }
216
217        if (endMs > mDurationMs) {
218            throw new IllegalArgumentException("setExtractBoundaries: Invalid end time");
219        }
220
221        if ((endMs != -1) && (beginMs >= endMs) ) {
222            throw new IllegalArgumentException("setExtractBoundaries: Start time is greater than end time");
223        }
224
225        if ((beginMs < 0) || ((endMs != -1) && (endMs < 0))) {
226            throw new IllegalArgumentException("setExtractBoundaries: Start time or end time is negative");
227        }
228
229        mMANativeHelper.setGeneratePreview(true);
230
231        if (beginMs != mBeginBoundaryTimeMs) {
232            if (mBeginTransition != null) {
233                mBeginTransition.invalidate();
234            }
235        }
236
237        if (endMs != mEndBoundaryTimeMs) {
238            if (mEndTransition != null) {
239                mEndTransition.invalidate();
240            }
241        }
242
243        mBeginBoundaryTimeMs = beginMs;
244        mEndBoundaryTimeMs = endMs;
245        adjustTransitions();
246        mVideoEditor.updateTimelineDuration();
247        /**
248         *  Note that the start and duration of any effects and overlays are
249         *  not adjusted nor are they automatically removed if they fall
250         *  outside the new boundaries.
251         */
252    }
253
254    /**
255     * @return The boundary begin time
256     */
257    public long getBoundaryBeginTime() {
258        return mBeginBoundaryTimeMs;
259    }
260
261    /**
262     * @return The boundary end time
263     */
264    public long getBoundaryEndTime() {
265        return mEndBoundaryTimeMs;
266    }
267
268    /*
269     * {@inheritDoc}
270     */
271    @Override
272    public void addEffect(Effect effect) {
273        if (effect instanceof EffectKenBurns) {
274            throw new IllegalArgumentException("Ken Burns effects cannot be applied to MediaVideoItem");
275        }
276        super.addEffect(effect);
277    }
278
279    /*
280     * {@inheritDoc}
281     */
282    @Override
283    public Bitmap getThumbnail(int width, int height, long timeMs) {
284        if (timeMs > mDurationMs) {
285            throw new IllegalArgumentException("Time Exceeds duration");
286        }
287
288        if (timeMs < 0) {
289            throw new IllegalArgumentException("Invalid Time duration");
290        }
291
292        if ((width <= 0) || (height <= 0)) {
293            throw new IllegalArgumentException("Invalid Dimensions");
294        }
295
296        if (mVideoRotationDegree == 90 || mVideoRotationDegree == 270) {
297            int temp = width;
298            width = height;
299            height = temp;
300        }
301
302        return mMANativeHelper.getPixels(
303                getFilename(), width, height, timeMs, mVideoRotationDegree);
304    }
305
306    /*
307     * {@inheritDoc}
308     */
309    @Override
310    public void getThumbnailList(int width, int height,
311                                 long startMs, long endMs,
312                                 int thumbnailCount,
313                                 int[] indices,
314                                 GetThumbnailListCallback callback)
315                                 throws IOException {
316        if (startMs > endMs) {
317            throw new IllegalArgumentException("Start time is greater than end time");
318        }
319
320        if (endMs > mDurationMs) {
321            throw new IllegalArgumentException("End time is greater than file duration");
322        }
323
324        if ((height <= 0) || (width <= 0)) {
325            throw new IllegalArgumentException("Invalid dimension");
326        }
327
328        if (mVideoRotationDegree == 90 || mVideoRotationDegree == 270) {
329            int temp = width;
330            width = height;
331            height = temp;
332        }
333
334        mMANativeHelper.getPixelsList(getFilename(), width, height,
335                startMs, endMs, thumbnailCount, indices, callback,
336                mVideoRotationDegree);
337    }
338
339    /*
340     * {@inheritDoc}
341     */
342    @Override
343    void invalidateTransitions(long startTimeMs, long durationMs) {
344        /**
345         *  Check if the item overlaps with the beginning and end transitions
346         */
347        if (mBeginTransition != null) {
348            if (isOverlapping(startTimeMs, durationMs,
349                    mBeginBoundaryTimeMs, mBeginTransition.getDuration())) {
350                mBeginTransition.invalidate();
351            }
352        }
353
354        if (mEndTransition != null) {
355            final long transitionDurationMs = mEndTransition.getDuration();
356            if (isOverlapping(startTimeMs, durationMs,
357                    mEndBoundaryTimeMs - transitionDurationMs, transitionDurationMs)) {
358                mEndTransition.invalidate();
359            }
360        }
361    }
362
363    /*
364     * {@inheritDoc}
365     */
366    @Override
367    void invalidateTransitions(long oldStartTimeMs, long oldDurationMs, long newStartTimeMs,
368            long newDurationMs) {
369        /**
370         *  Check if the item overlaps with the beginning and end transitions
371         */
372        if (mBeginTransition != null) {
373            final long transitionDurationMs = mBeginTransition.getDuration();
374            final boolean oldOverlap = isOverlapping(oldStartTimeMs, oldDurationMs,
375                    mBeginBoundaryTimeMs, transitionDurationMs);
376            final boolean newOverlap = isOverlapping(newStartTimeMs, newDurationMs,
377                    mBeginBoundaryTimeMs, transitionDurationMs);
378            /**
379             * Invalidate transition if:
380             *
381             * 1. New item overlaps the transition, the old one did not
382             * 2. New item does not overlap the transition, the old one did
383             * 3. New and old item overlap the transition if begin or end
384             * time changed
385             */
386            if (newOverlap != oldOverlap) { // Overlap has changed
387                mBeginTransition.invalidate();
388            } else if (newOverlap) { // Both old and new overlap
389                if ((oldStartTimeMs != newStartTimeMs) ||
390                        !(oldStartTimeMs + oldDurationMs > transitionDurationMs &&
391                        newStartTimeMs + newDurationMs > transitionDurationMs)) {
392                    mBeginTransition.invalidate();
393                }
394            }
395        }
396
397        if (mEndTransition != null) {
398            final long transitionDurationMs = mEndTransition.getDuration();
399            final boolean oldOverlap = isOverlapping(oldStartTimeMs, oldDurationMs,
400                    mEndBoundaryTimeMs - transitionDurationMs, transitionDurationMs);
401            final boolean newOverlap = isOverlapping(newStartTimeMs, newDurationMs,
402                    mEndBoundaryTimeMs - transitionDurationMs, transitionDurationMs);
403            /**
404             * Invalidate transition if:
405             *
406             * 1. New item overlaps the transition, the old one did not
407             * 2. New item does not overlap the transition, the old one did
408             * 3. New and old item overlap the transition if begin or end
409             * time changed
410             */
411            if (newOverlap != oldOverlap) { // Overlap has changed
412                mEndTransition.invalidate();
413            } else if (newOverlap) { // Both old and new overlap
414                if ((oldStartTimeMs + oldDurationMs != newStartTimeMs + newDurationMs) ||
415                        ((oldStartTimeMs > mEndBoundaryTimeMs - transitionDurationMs) ||
416                        newStartTimeMs > mEndBoundaryTimeMs - transitionDurationMs)) {
417                    mEndTransition.invalidate();
418                }
419            }
420        }
421    }
422
423    /*
424     * {@inheritDoc}
425     */
426    @Override
427    public int getAspectRatio() {
428        return mAspectRatio;
429    }
430
431    /*
432     * {@inheritDoc}
433     */
434    @Override
435    public int getFileType() {
436        return mFileType;
437    }
438
439    /*
440     * {@inheritDoc}
441     */
442    @Override
443    public int getWidth() {
444        if (mVideoRotationDegree == 90 ||
445             mVideoRotationDegree == 270) {
446            return mHeight;
447        } else {
448            return mWidth;
449        }
450    }
451
452    /*
453     * {@inheritDoc}
454     */
455    @Override
456    public int getHeight() {
457        if (mVideoRotationDegree == 90 ||
458             mVideoRotationDegree == 270) {
459            return mWidth;
460        } else {
461            return mHeight;
462        }
463    }
464
465    /*
466     * {@inheritDoc}
467     */
468    @Override
469    public long getDuration() {
470        return mDurationMs;
471    }
472
473    /*
474     * {@inheritDoc}
475     */
476    @Override
477    public long getTimelineDuration() {
478        return mEndBoundaryTimeMs - mBeginBoundaryTimeMs;
479    }
480
481    /**
482     * Render a frame according to the playback (in the native aspect ratio) for
483     * the specified media item. All effects and overlays applied to the media
484     * item are ignored. The extract boundaries are also ignored. This method
485     * can be used to playback frames when implementing trimming functionality.
486     *
487     * @param surfaceHolder SurfaceHolder used by the application
488     * @param timeMs time corresponding to the frame to display (relative to the
489     *            the beginning of the media item).
490     * @return The accurate time stamp of the frame that is rendered .
491     * @throws IllegalStateException if a playback, preview or an export is
492     *             already in progress
493     * @throws IllegalArgumentException if time is negative or greater than the
494     *             media item duration
495     */
496    public long renderFrame(SurfaceHolder surfaceHolder, long timeMs) {
497        if (surfaceHolder == null) {
498            throw new IllegalArgumentException("Surface Holder is null");
499        }
500
501        if (timeMs > mDurationMs || timeMs < 0) {
502            throw new IllegalArgumentException("requested time not correct");
503        }
504
505        final Surface surface = surfaceHolder.getSurface();
506        if (surface == null) {
507            throw new RuntimeException("Surface could not be retrieved from Surface holder");
508        }
509
510        if (mFilename != null) {
511            return mMANativeHelper.renderMediaItemPreviewFrame(surface,
512                    mFilename,timeMs,mWidth,mHeight);
513        } else {
514            return 0;
515        }
516    }
517
518
519    /**
520     * This API allows to generate a file containing the sample volume levels of
521     * the Audio track of this media item. This function may take significant
522     * time and is blocking. The file can be retrieved using
523     * getAudioWaveformFilename().
524     *
525     * @param listener The progress listener
526     *
527     * @throws IOException if the output file cannot be created
528     * @throws IllegalArgumentException if the mediaItem does not have a valid
529     *             Audio track
530     */
531    public void extractAudioWaveform(ExtractAudioWaveformProgressListener listener)
532        throws IOException {
533        int frameDuration = 0;
534        int sampleCount = 0;
535        final String projectPath = mMANativeHelper.getProjectPath();
536        /**
537         *  Waveform file does not exist
538         */
539        if (mAudioWaveformFilename == null ) {
540            /**
541             * Since audioWaveformFilename will not be supplied,it is  generated
542             */
543            String mAudioWaveFileName = null;
544
545            mAudioWaveFileName =
546                String.format(projectPath + "/" + "audioWaveformFile-"+ getId() + ".dat");
547            /**
548             * Logic to get frame duration = (no. of frames per sample * 1000)/
549             * sampling frequency
550             */
551            if (mMANativeHelper.getAudioCodecType(mAudioType) ==
552                MediaProperties.ACODEC_AMRNB ) {
553                frameDuration = (MediaProperties.SAMPLES_PER_FRAME_AMRNB*1000)/
554                MediaProperties.DEFAULT_SAMPLING_FREQUENCY;
555                sampleCount = MediaProperties.SAMPLES_PER_FRAME_AMRNB;
556            } else if (mMANativeHelper.getAudioCodecType(mAudioType) ==
557                MediaProperties.ACODEC_AMRWB ) {
558                frameDuration = (MediaProperties.SAMPLES_PER_FRAME_AMRWB * 1000)/
559                MediaProperties.DEFAULT_SAMPLING_FREQUENCY;
560                sampleCount = MediaProperties.SAMPLES_PER_FRAME_AMRWB;
561            } else if (mMANativeHelper.getAudioCodecType(mAudioType) ==
562                MediaProperties.ACODEC_AAC_LC ) {
563                frameDuration = (MediaProperties.SAMPLES_PER_FRAME_AAC * 1000)/
564                MediaProperties.DEFAULT_SAMPLING_FREQUENCY;
565                sampleCount = MediaProperties.SAMPLES_PER_FRAME_AAC;
566            }
567
568            mMANativeHelper.generateAudioGraph( getId(),
569                    mFilename,
570                    mAudioWaveFileName,
571                    frameDuration,
572                    MediaProperties.DEFAULT_CHANNEL_COUNT,
573                    sampleCount,
574                    listener,
575                    true);
576            /**
577             * Record the generated file name
578             */
579            mAudioWaveformFilename = mAudioWaveFileName;
580        }
581        mWaveformData =
582            new SoftReference<WaveformData>(new WaveformData(mAudioWaveformFilename));
583    }
584
585    /**
586     * Get the audio waveform file name if {@link #extractAudioWaveform()} was
587     * successful. The file format is as following:
588     * <ul>
589     *  <li>first 4 bytes provide the number of samples for each value, as big-endian signed</li>
590     *  <li>4 following bytes is the total number of values in the file, as big-endian signed</li>
591     *  <li>all values follow as bytes Name is unique.</li>
592     *</ul>
593     * @return the name of the file, null if the file has not been computed or
594     *         if there is no Audio track in the mediaItem
595     */
596    String getAudioWaveformFilename() {
597        return mAudioWaveformFilename;
598    }
599
600    /**
601     * Invalidate the AudioWaveform File
602     */
603    void invalidate() {
604        if (mAudioWaveformFilename != null) {
605            new File(mAudioWaveformFilename).delete();
606            mAudioWaveformFilename = null;
607        }
608    }
609
610    /**
611     * @return The waveform data
612     */
613    public WaveformData getWaveformData() throws IOException {
614        if (mWaveformData == null) {
615            return null;
616        }
617
618        WaveformData waveformData = mWaveformData.get();
619        if (waveformData != null) {
620            return waveformData;
621        } else if (mAudioWaveformFilename != null) {
622            try {
623                waveformData = new WaveformData(mAudioWaveformFilename);
624            } catch(IOException e) {
625                throw e;
626            }
627            mWaveformData = new SoftReference<WaveformData>(waveformData);
628            return waveformData;
629        } else {
630            return null;
631        }
632    }
633
634    /**
635     * Set volume of the Audio track of this mediaItem
636     *
637     * @param volumePercent in %/. 100% means no change; 50% means half value, 200%
638     *            means double, 0% means silent.
639     * @throws UsupportedOperationException if volume value is not supported
640     */
641    public void setVolume(int volumePercent) {
642        if ((volumePercent <0) || (volumePercent >100)) {
643            throw new IllegalArgumentException("Invalid volume");
644        }
645
646        mVolumePercentage = volumePercent;
647    }
648
649    /**
650     * Get the volume value of the audio track as percentage. Call of this
651     * method before calling setVolume will always return 100%
652     *
653     * @return the volume in percentage
654     */
655    public int getVolume() {
656        return mVolumePercentage;
657    }
658
659    /**
660     * @param muted true to mute the media item
661     */
662    public void setMute(boolean muted) {
663        mMANativeHelper.setGeneratePreview(true);
664        mMuted = muted;
665        if (mBeginTransition != null) {
666            mBeginTransition.invalidate();
667        }
668        if (mEndTransition != null) {
669            mEndTransition.invalidate();
670        }
671    }
672
673    /**
674     * @return true if the media item is muted
675     */
676    public boolean isMuted() {
677        return mMuted;
678    }
679
680    /**
681     * @return The video type
682     */
683    public int getVideoType() {
684        return mVideoType;
685    }
686
687    /**
688     * @return The video profile
689     */
690    public int getVideoProfile() {
691        return mVideoProfile;
692    }
693
694    /**
695     * @return The video profile
696     */
697    public int getVideoLevel() {
698        return mVideoLevel;
699    }
700
701    /**
702     * @return The video bitrate
703     */
704    public int getVideoBitrate() {
705        return mVideoBitrate;
706    }
707
708    /**
709     * @return The audio bitrate
710     */
711    public int getAudioBitrate() {
712        return mAudioBitrate;
713    }
714
715    /**
716     * @return The number of frames per second
717     */
718    public int getFps() {
719        return mFps;
720    }
721
722    /**
723     * @return The audio codec
724     */
725    public int getAudioType() {
726        return mAudioType;
727    }
728
729    /**
730     * @return The number of audio channels
731     */
732    public int getAudioChannels() {
733        return mAudioChannels;
734    }
735
736    /**
737     * @return The audio sample frequency
738     */
739    public int getAudioSamplingFrequency() {
740        return mAudioSamplingFrequency;
741    }
742
743    /**
744     * @return The Video media item properties in ClipSettings class object
745     * {@link android.media.videoeditor.MediaArtistNativeHelper.ClipSettings}
746     */
747    ClipSettings getVideoClipProperties() {
748        ClipSettings clipSettings = new ClipSettings();
749        clipSettings.clipPath = getFilename();
750        clipSettings.fileType = mMANativeHelper.getMediaItemFileType(getFileType());
751        clipSettings.beginCutTime = (int)getBoundaryBeginTime();
752        clipSettings.endCutTime = (int)getBoundaryEndTime();
753        clipSettings.mediaRendering = mMANativeHelper.getMediaItemRenderingMode(getRenderingMode());
754        clipSettings.rotationDegree = mVideoRotationDegree;
755
756        return clipSettings;
757    }
758}
759