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
17package com.android.videoeditor.service;
18
19import java.util.List;
20
21import android.media.videoeditor.Effect;
22import android.media.videoeditor.MediaImageItem;
23import android.media.videoeditor.MediaItem;
24import android.media.videoeditor.MediaVideoItem;
25import android.media.videoeditor.Overlay;
26import android.media.videoeditor.WaveformData;
27
28
29/**
30 * This class represents a media item
31 */
32public class MovieMediaItem {
33    // The unique id of the media item
34    private final String mUniqueId;
35
36    // The transition type
37    private final Class<?> mType;
38
39    // The name of the file associated with the media item
40    private final String mFilename;
41
42    // The width and height
43    private final int mWidth;
44    private final int mHeight;
45
46    // The aspect ratio
47    private final int mAspectRatio;
48
49    // The duration of the entire media item (ignore trim boundaries)
50    private final long mDurationMs;
51
52    // Trimming boundaries
53    private final long mBeginBoundaryTimeMs;
54    private final long mEndBoundaryTimeMs;
55
56    // The rendering mode
57    private int mRenderingMode;
58
59    // The overlay applied to the media item
60    private MovieOverlay mOverlay;
61
62    // The effect applied to the media item
63    private MovieEffect mEffect;
64
65    // Begin and end transitions
66    private MovieTransition mBeginTransition;
67    private MovieTransition mEndTransition;
68
69    // The audio waveform data
70    private WaveformData mWaveformData;
71
72    // Sound control
73    private int mVolumePercent;
74    private boolean mMuted;
75
76    // Application values
77    private long mAppBeginBoundaryTimeMs, mAppEndBoundaryTimeMs;
78    private int mAppRenderingMode;
79    private int mAppVolumePercent;
80    private boolean mAppMuted;
81
82    /**
83     * Constructor
84     *
85     * @param mediaItem The media item
86     */
87    MovieMediaItem(MediaItem mediaItem) {
88        this(mediaItem, mediaItem.getBeginTransition() != null ? new MovieTransition(
89                mediaItem.getBeginTransition()) : null);
90    }
91
92    /**
93     * Constructor
94     *
95     * @param mediaItem The media item
96     * @param beginTransition The transition of the previous media item
97     */
98    MovieMediaItem(MediaItem mediaItem, MovieTransition beginTransition) {
99        mType = mediaItem.getClass();
100        mUniqueId = mediaItem.getId();
101        mFilename = mediaItem.getFilename();
102        mAppRenderingMode = mRenderingMode = mediaItem.getRenderingMode();
103        mAspectRatio = mediaItem.getAspectRatio();
104        mWidth = mediaItem.getWidth();
105        mHeight = mediaItem.getHeight();
106
107        mDurationMs = mediaItem.getDuration();
108        if (mediaItem instanceof MediaVideoItem) {
109            final MediaVideoItem videoMediaItem = ((MediaVideoItem)mediaItem);
110            mAppBeginBoundaryTimeMs = mBeginBoundaryTimeMs = videoMediaItem.getBoundaryBeginTime();
111            mAppEndBoundaryTimeMs = mEndBoundaryTimeMs = videoMediaItem.getBoundaryEndTime();
112            try {
113                mWaveformData = videoMediaItem.getWaveformData();
114            } catch (Exception ex) {
115                mWaveformData = null;
116            }
117            mAppVolumePercent = mVolumePercent = videoMediaItem.getVolume();
118            mAppMuted = mMuted = videoMediaItem.isMuted();
119        } else {
120            mAppBeginBoundaryTimeMs = mBeginBoundaryTimeMs = 0;
121            mAppEndBoundaryTimeMs = mEndBoundaryTimeMs = mediaItem.getTimelineDuration();
122            mWaveformData = null;
123            mAppVolumePercent = mVolumePercent = 0;
124            mAppMuted = mMuted = false;
125        }
126
127        final List<Overlay> overlays = mediaItem.getAllOverlays();
128        for (Overlay overlay : overlays) {
129            addOverlay(new MovieOverlay(overlay));
130        }
131
132        final List<Effect> effects = mediaItem.getAllEffects();
133        for (Effect effect : effects) {
134            addEffect(new MovieEffect(effect));
135        }
136
137        setBeginTransition(beginTransition);
138
139        if (mediaItem.getEndTransition() != null) {
140            setEndTransition(new MovieTransition(mediaItem.getEndTransition()));
141        }
142    }
143
144    /**
145     * @return true if this is an image media item
146     */
147    public boolean isImage() {
148        return MediaImageItem.class.equals(mType);
149    }
150
151    /**
152     * @return true if this is an image video clip item
153     */
154    public boolean isVideoClip() {
155        return MediaVideoItem.class.equals(mType);
156    }
157
158    /**
159     * @return The id of the media item
160     */
161    public String getId() {
162        return mUniqueId;
163    }
164
165    /**
166     * @return The media source file name
167     */
168    public String getFilename() {
169        return mFilename;
170    }
171
172    /**
173     * If aspect ratio of the MediaItem is different from the aspect ratio of
174     * the editor then this API controls the rendering mode.
175     *
176     * @param renderingMode rendering mode. It is one of:
177     *            {@link #RENDERING_MODE_BLACK_BORDER},
178     *            {@link #RENDERING_MODE_STRETCH}
179     */
180    void setRenderingMode(int renderingMode) {
181        mRenderingMode = renderingMode;
182    }
183
184    /**
185     * @return The rendering mode
186     */
187    int getRenderingMode() {
188        return mRenderingMode;
189    }
190
191    /**
192     * If aspect ratio of the MediaItem is different from the aspect ratio of
193     * the editor then this API controls the rendering mode.
194     *
195     * @param renderingMode rendering mode.
196     */
197    public void setAppRenderingMode(int renderingMode) {
198        mAppRenderingMode = renderingMode;
199    }
200
201    /**
202     * @return The rendering mode
203     */
204    public int getAppRenderingMode() {
205        return mAppRenderingMode;
206    }
207
208    /**
209     * Set the volume of this audio track as percentage of the volume in the
210     * original audio source file.
211     *
212     * @param volumePercent Percentage of the volume to apply. If it is set to
213     *            0, then volume becomes mute. It it is set to 100, then volume
214     *            is same as original volume. It it is set to 200, then volume
215     *            is doubled (provided that volume amplification is supported)
216     *
217     * @throws UnsupportedOperationException if volume amplification is
218     *             requested and is not supported.
219     */
220    void setVolume(int volumePercent) {
221        mVolumePercent = volumePercent;
222    }
223
224    /**
225     * Get the volume of the audio track as percentage of the volume in the
226     * original audio source file.
227     *
228     * @return The volume in percentage
229     */
230    int getVolume() {
231        return mVolumePercent;
232    }
233
234    /**
235     * Set the volume of this audio track as percentage of the volume in the
236     * original audio source file.
237     *
238     * @param volumePercent Percentage of the volume to apply. If it is set to
239     *            0, then volume becomes mute. It it is set to 100, then volume
240     *            is same as original volume. It it is set to 200, then volume
241     *            is doubled (provided that volume amplification is supported)
242     *
243     * @throws UnsupportedOperationException if volume amplification is
244     *             requested and is not supported.
245     */
246    public void setAppVolume(int volumePercent) {
247        mAppVolumePercent = volumePercent;
248    }
249
250    /**
251     * Get the volume of the audio track as percentage of the volume in the
252     * original audio source file.
253     *
254     * @return The volume in percentage
255     */
256    public int getAppVolume() {
257        return mAppVolumePercent;
258    }
259
260    /**
261     * @param muted true to mute the media item
262     */
263    void setMute(boolean muted) {
264        mMuted = muted;
265    }
266
267    /**
268     * @return true if the media item is muted
269     */
270    boolean isMuted() {
271        return mMuted;
272    }
273
274    /**
275     * @param muted true to mute the media item
276     */
277    public void setAppMute(boolean muted) {
278        mAppMuted = muted;
279    }
280
281    /**
282     * @return true if the media item is muted
283     */
284    public boolean isAppMuted() {
285        return mAppMuted;
286    }
287
288    /**
289     * @return The boundary begin time
290     */
291    long getBoundaryBeginTime() {
292        return mBeginBoundaryTimeMs;
293    }
294
295    /**
296     * @return The boundary end time
297     */
298    long getBoundaryEndTime() {
299        return mEndBoundaryTimeMs;
300    }
301
302    /**
303     * Sets the start and end marks for trimming a video media item.
304     *
305     * @param beginMs Start time in milliseconds. Set to 0 to extract from the
306     *            beginning
307     * @param endMs End time in milliseconds.
308     */
309    public void setAppExtractBoundaries(long beginMs, long endMs) {
310        mAppBeginBoundaryTimeMs = beginMs;
311        mAppEndBoundaryTimeMs = endMs;
312    }
313
314    /**
315     * @return The boundary begin time
316     */
317    public long getAppBoundaryBeginTime() {
318        return mAppBeginBoundaryTimeMs;
319    }
320
321    /**
322     * @return The boundary end time
323     */
324    public long getAppBoundaryEndTime() {
325        return mAppEndBoundaryTimeMs;
326    }
327
328    /**
329     * @return The timeline duration. This is the actual duration in the
330     *         timeline (trimmed duration)
331     */
332    public long getAppTimelineDuration() {
333        return mAppEndBoundaryTimeMs - mAppBeginBoundaryTimeMs;
334    }
335
336    /**
337     * @return The duration of the entire media item (ignore trim)
338     */
339    public long getDuration() {
340        return mDurationMs;
341    }
342
343    /**
344     * @return Get the width of the media item
345     */
346    public int getWidth() {
347        return mWidth;
348    }
349
350    /**
351     * @return Get the height of the media item
352     */
353    public int getHeight() {
354        return mHeight;
355    }
356
357    /**
358     * Get aspect ratio of the source media item.
359     *
360     * @return the aspect ratio as described in MediaProperties.
361     *         MediaProperties.ASPECT_RATIO_UNDEFINED if aspect ratio is not
362     *         supported as in MediaProperties
363     */
364    public int getAspectRatio() {
365        return mAspectRatio;
366    }
367
368    /**
369     * @param beginTransition Begin transition
370     */
371    void setBeginTransition(MovieTransition beginTransition) {
372        mBeginTransition = beginTransition;
373    }
374
375    /**
376     * @return The begin transition
377     */
378    public MovieTransition getBeginTransition() {
379        return mBeginTransition;
380    }
381
382    /**
383     * @param endTransition end transition
384     */
385    void setEndTransition(MovieTransition endTransition) {
386        mEndTransition = endTransition;
387    }
388
389    /**
390     * @return The end transition
391     */
392    public MovieTransition getEndTransition() {
393        return mEndTransition;
394    }
395
396    /**
397     * @return The overlay
398     */
399    public MovieOverlay getOverlay() {
400        return mOverlay;
401    }
402
403    /**
404     * Only one overlay is supported at this time
405     *
406     * @param overlay The overlay
407     */
408    void addOverlay(MovieOverlay overlay) {
409        if (mOverlay != null) {
410            throw new IllegalStateException("Overlay already set for media item: " + mUniqueId);
411        }
412        mOverlay = overlay;
413    }
414
415    /**
416     * @param overlayId The overlay id
417     */
418    void removeOverlay(String overlayId) {
419        if (mOverlay != null) {
420            if (!mOverlay.getId().equals(overlayId)) {
421                throw new IllegalStateException("Overlay does not match: " + mOverlay.getId() + " "
422                        + overlayId);
423            }
424            mOverlay = null;
425        }
426    }
427
428    /**
429     * @return The effect
430     */
431    public MovieEffect getEffect() {
432        return mEffect;
433    }
434
435    /**
436     * Only one effect is supported at this time
437     *
438     * @param effect The effect
439     */
440    void addEffect(MovieEffect effect) {
441        if (mEffect != null) {
442            throw new IllegalStateException("Effect already set for media item: " + mUniqueId);
443        }
444        mEffect = effect;
445    }
446
447    /**
448     * @param effectId The effect id
449     */
450    void removeEffect(String effectId) {
451        if (mEffect != null) {
452            if (!mEffect.getId().equals(effectId)) {
453                throw new IllegalStateException("Effect does not match: " + mEffect.getId() + " "
454                        + effectId);
455            }
456
457            mEffect = null;
458        }
459    }
460
461    /**
462     * @return waveform data
463     */
464    public WaveformData getWaveformData() {
465        return mWaveformData;
466    }
467
468    /**
469     * @param waveformData The waveform data
470     */
471    void setWaveformData(WaveformData waveformData) {
472        mWaveformData = waveformData;
473    }
474
475    /*
476     * {@inheritDoc}
477     */
478    @Override
479    public boolean equals(Object object) {
480        if (!(object instanceof MovieMediaItem)) {
481            return false;
482        }
483        return mUniqueId.equals(((MovieMediaItem)object).mUniqueId);
484    }
485
486    /*
487     * {@inheritDoc}
488     */
489    @Override
490    public int hashCode() {
491        return mUniqueId.hashCode();
492    }
493}
494