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