Home | History | Annotate | Download | only in videoeditor
      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 
     18 package android.media.videoeditor;
     19 
     20 import java.io.File;
     21 import java.io.IOException;
     22 import java.lang.ref.SoftReference;
     23 import android.graphics.Bitmap;
     24 import android.media.videoeditor.MediaArtistNativeHelper.ClipSettings;
     25 import android.media.videoeditor.MediaArtistNativeHelper.Properties;
     26 import android.media.videoeditor.VideoEditorProfile;
     27 import android.view.Surface;
     28 import android.view.SurfaceHolder;
     29 
     30 /**
     31  * This class represents a video clip item on the storyboard
     32  * {@hide}
     33  */
     34 public 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