有关视频裁剪我在前面一篇博客中只是做了简单的说明,主要涉及到的知识准备在这篇博客中拿出来说一下。有兴趣的可以fork我的视频裁剪的项目源码,一起学习进步。

Github:https://github.com/iknow4/Android-Video-Trimmer

视频裁剪页如下图所示:

图上面的视频播放用是VideoView来实现的,比较简单。我主要说说视频帧的读取和视频时间的选取。

视频帧的获取可以通过Android提供的MediaMetadataRetriever类来实现。

MediaMetadataRetriever mediaMetadataRetriever = new MediaMetadataRetriever();

mediaMetadataRetriever.setDataSource(context, videoUri);

在MediaMetadataRetriever类中会调用到media_jni的这个库中的setDataSource()方法,最终使得我们可以获取视频的meta data,meta data是非常丰富的,足足有26种,足够满足我们的需求了。

/**

* The metadata key to retrieve the numeric string describing the

* order of the audio data source on its original recording.

*/

public static final int METADATA_KEY_CD_TRACK_NUMBER = 0;

/**

* The metadata key to retrieve the information about the album title

* of the data source.

*/

public static final int METADATA_KEY_ALBUM = 1;

/**

* The metadata key to retrieve the information about the artist of

* the data source.

*/

public static final int METADATA_KEY_ARTIST = 2;

/**

* The metadata key to retrieve the information about the author of

* the data source.

*/

public static final int METADATA_KEY_AUTHOR = 3;

/**

* The metadata key to retrieve the information about the composer of

* the data source.

*/

public static final int METADATA_KEY_COMPOSER = 4;

/**

* The metadata key to retrieve the date when the data source was created

* or modified.

*/

public static final int METADATA_KEY_DATE = 5;

/**

* The metadata key to retrieve the content type or genre of the data

* source.

*/

public static final int METADATA_KEY_GENRE = 6;

/**

* The metadata key to retrieve the data source title.

*/

public static final int METADATA_KEY_TITLE = 7;

/**

* The metadata key to retrieve the year when the data source was created

* or modified.

*/

public static final int METADATA_KEY_YEAR = 8;

/**

* The metadata key to retrieve the playback duration of the data source.

*/

public static final int METADATA_KEY_DURATION = 9;

/**

* The metadata key to retrieve the number of tracks, such as audio, video,

* text, in the data source, such as a mp4 or 3gpp file.

*/

public static final int METADATA_KEY_NUM_TRACKS = 10;

/**

* The metadata key to retrieve the information of the writer (such as

* lyricist) of the data source.

*/

public static final int METADATA_KEY_WRITER = 11;

/**

* The metadata key to retrieve the mime type of the data source. Some

* example mime types include: "video/mp4", "audio/mp4", "audio/amr-wb",

* etc.

*/

public static final int METADATA_KEY_MIMETYPE = 12;

/**

* The metadata key to retrieve the information about the performers or

* artist associated with the data source.

*/

public static final int METADATA_KEY_ALBUMARTIST = 13;

/**

* The metadata key to retrieve the numberic string that describes which

* part of a set the audio data source comes from.

*/

public static final int METADATA_KEY_DISC_NUMBER = 14;

/**

* The metadata key to retrieve the music album compilation status.

*/

public static final int METADATA_KEY_COMPILATION = 15;

/**

* If this key exists the media contains audio content.

*/

public static final int METADATA_KEY_HAS_AUDIO = 16;

/**

* If this key exists the media contains video content.

*/

public static final int METADATA_KEY_HAS_VIDEO = 17;

/**

* If the media contains video, this key retrieves its width.

*/

public static final int METADATA_KEY_VIDEO_WIDTH = 18;

/**

* If the media contains video, this key retrieves its height.

*/

public static final int METADATA_KEY_VIDEO_HEIGHT = 19;

/**

* This key retrieves the average bitrate (in bits/sec), if available.

*/

public static final int METADATA_KEY_BITRATE = 20;

/**

* This key retrieves the language code of text tracks, if available.

* If multiple text tracks present, the return value will look like:

* "eng:chi"

* @hide

*/

public static final int METADATA_KEY_TIMED_TEXT_LANGUAGES = 21;

/**

* If this key exists the media is drm-protected.

* @hide

*/

public static final int METADATA_KEY_IS_DRM = 22;

/**

* This key retrieves the location information, if available.

* The location should be specified according to ISO-6709 standard, under

* a mp4/3gp box "@xyz". Location with longitude of -90 degrees and latitude

* of 180 degrees will be retrieved as "-90.0000+180.0000", for instance.

*/

public static final int METADATA_KEY_LOCATION = 23;

/**

* This key retrieves the video rotation angle in degrees, if available.

* The video rotation angle may be 0, 90, 180, or 270 degrees.

*/

public static final int METADATA_KEY_VIDEO_ROTATION = 24;

/**

* This key retrieves the original capture framerate, if it's

* available. The capture framerate will be a floating point

* number.

*/

public static final int METADATA_KEY_CAPTURE_FRAMERATE = 25;

// Add more here...

了解这些meta 信息,就可以知道一个视频所能给我们提供的信息有哪些了。

在这里,我们是要获取视频的帧(Frame),帧其实就是图片,一帧可能会有N多张图片组成。通过调用MediaMetadataRetriever类中的getFrameAtTime()获取视频的帧的Bitmap。

/**

* Call this method after setDataSource(). This method finds a

* representative frame close to the given time position by considering

* the given option if possible, and returns it as a bitmap. This is

* useful for generating a thumbnail for an input data source or just

* obtain and display a frame at the given time position.

*

* @param timeUs The time position where the frame will be retrieved.

* When retrieving the frame at the given time position, there is no

* guarantee that the data source has a frame located at the position.

* When this happens, a frame nearby will be returned. If timeUs is

* negative, time position and option will ignored, and any frame

* that the implementation considers as representative may be returned.

*

* @param option a hint on how the frame is found. Use

* {@link #OPTION_PREVIOUS_SYNC} if one wants to retrieve a sync frame

* that has a timestamp earlier than or the same as timeUs. Use

* {@link #OPTION_NEXT_SYNC} if one wants to retrieve a sync frame

* that has a timestamp later than or the same as timeUs. Use

* {@link #OPTION_CLOSEST_SYNC} if one wants to retrieve a sync frame

* that has a timestamp closest to or the same as timeUs. Use

* {@link #OPTION_CLOSEST} if one wants to retrieve a frame that may

* or may not be a sync frame but is closest to or the same as timeUs.

* {@link #OPTION_CLOSEST} often has larger performance overhead compared

* to the other options if there is no sync frame located at timeUs.

*

* @return A Bitmap containing a representative video frame, which

* can be null, if such a frame cannot be retrieved.

*/

public Bitmap getFrameAtTime(long timeUs, int option) {

if (option < OPTION_PREVIOUS_SYNC ||

option > OPTION_CLOSEST) {

throw new IllegalArgumentException("Unsupported option: " + option);

}

return _getFrameAtTime(timeUs, option);

}

这里有两个参数:

timeUs 表示每一帧的开始时间位置,给定的时间的帧不一定存在,但是系统会将临近的一帧返回给我们。

option 参数表示获取帧的方式

以下是我调用的代码块,代码块是放在单独的线程中执行的。

try {

MediaMetadataRetriever mediaMetadataRetriever = new MediaMetadataRetriever();

mediaMetadataRetriever.setDataSource(context, videoUri);

// Retrieve media data use microsecond

long videoLengthInMs = Long.parseLong(mediaMetadataRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION)) * 1000;

long numThumbs = videoLengthInMs < one_frame_time ? 1 : (videoLengthInMs / one_frame_time);

final long interval = videoLengthInMs / numThumbs;

//每次截取到3帧之后上报

for (long i = 0; i < numThumbs; ++i) {

Bitmap bitmap = mediaMetadataRetriever.getFrameAtTime(i * interval, MediaMetadataRetriever.OPTION_CLOSEST_SYNC);

try {

bitmap = Bitmap.createScaledBitmap(bitmap, thumb_Width, thumb_Height, false);

} catch (Exception e) {

e.printStackTrace();

}

thumbnailList.add(bitmap);

if (thumbnailList.size() == 3) {

callback.onSingleCallback((ArrayList) thumbnailList.clone(), (int) interval);

thumbnailList.clear();

}

}

if (thumbnailList.size() > 0) {

callback.onSingleCallback((ArrayList) thumbnailList.clone(), (int) interval);

thumbnailList.clear();

}

mediaMetadataRetriever.release();

} catch (final Throwable e) {

Thread.getDefaultUncaughtExceptionHandler().uncaughtException(Thread.currentThread(), e);

}

子线程会在每截取到三帧之后将数据上报给主线程,主线程拿到数据之后会进行ui的更新操作,将bitmap显示出来。

当视频源时间比较长的时候,我们会截取到很多帧图片,所以需要将帧图片可以左右滑动。项目中用到的控件是:VideoThumbHorizontalListView (可水平滚动的ListView)

videoThumbListView.setOnScrollStateChangedListener(new VideoThumbHorizontalListView.OnScrollStateChangedListener({

@Override

public void onScrollStateChanged(ScrollState scrollState, int scrollDirection) {

if (videoThumbListView.getCurrentX() == 0)

return;

switch (scrollState) {

case SCROLL_STATE_FLING:

case SCROLL_STATE_IDLE:

case SCROLL_STATE_TOUCH_SCROLL:

if (scrolledOffset < 0) {

mScrolledOffset = mScrolledOffset - Math.abs(scrolledOffset);

if (mScrolledOffset <= 0)

mScrolledOffset = 0;

} else {

if(PixToTime(mScrolledOffset + SCREEN_WIDTH) <= mDuration)//根据时间来判断还是否可以向左滚动

mScrolledOffset = mScrolledOffset + scrolledOffset;

}

onVideoReset();

onSeekThumbs(0, mScrolledOffset + leftThumbValue);

onSeekThumbs(1, mScrolledOffset + rightThumbValue);

mRangeSeekBarView.invalidate();

break;

}

} );

我会去监听水平ListView的左右滚动事件,以获取它的滚动距离,从而算出并显示当前截取到的视频时间的长度。这里我们需要将视频总长度与屏幕的宽度做一个计算,形成一个映射关系,这是一个比较麻烦的事情,处理不好,会导致在ListView滚动过程中时间显示不准确的问题,哈哈,我的项目就存在着这样的bug。

这个项目只是一个粗糙的项目,页面上会存在一些小问题,不过可以拿来简单的学习一下。

欢迎有兴趣的同学star和fork。

Github:https://github.com/iknow4/Android-Video-Trimmer

Thanks for reading. To help others please click ❤ to recommend this article if you found it helpful.

android mp4 画面裁剪,说说Android的视频裁剪(二)相关推荐

  1. android mp4 画面裁剪,Android视频时长裁剪

    大家好,我是程序员kenney,今天给大家介绍一下如何在Android里面实现视频时长的裁剪. 首先我们要知道视频是由一帧一帧的数据构成的,每一帧都有一个时间戳,这个时间戳就是我们在做视频编码的时候, ...

  2. php封装多段mp4,解决ffmpeg将多段视频裁剪拼接后卡顿现象

    合并 将下载的ts流名称按照顺序记录在一个txt文件中,然后使用命令 ffmpeg.exe -f concat -i ./your.txt -c copy ./output.mkv ffmpeg.ex ...

  3. android启动画面白屏,Android app启动时黑屏或者白屏的原因及解决办法

    1.产生原因 其实显示黑屏或者白屏实属正常,这是因为还没加载到布局文件,就已经显示了window窗口背景,黑屏白屏就是window窗口背景. 示例: 2.解决办法 通过设置设置Style (1)设置背 ...

  4. android+系统画面恢复,坚持Android系统恢复?轻松修复它

    第3部分.安卓系统恢复?如何一键修复? 有时在系统恢复过程中,该过程可能会出现故障,您将丢失设备上的数据,使其无法使用.但是,解决此问题的另一个解决方案是使用dr.fone修复工具修复您的设备. 修复 ...

  5. 短视频生产利器!视频裁剪之横屏转竖屏新技术,出自腾讯多媒体实验室

    腾讯多媒体技术专栏 伴随手机等智能设备的广泛使用以及短视频平台的兴起,越来越多的"竖屏"视频开始占据人们的视野.目前,许多"竖屏"视频仍是由16:9等宽高比的& ...

  6. Android 3分钟一个库搞定视频替换音频 视频合成 视频裁剪(高仿剪映)

    几种框架的比较: https://www.zhihu.com/question/278431860 方法一(Fail) 利用MediaMux实现音视频的合成. 效果:可以实现音视频的合并,利用Andr ...

  7. Android 使用 mp4parser 做视频裁剪

    做音视频时我们很多时候需要做音视频裁剪,本文介绍使用开源库 mp4parser 做裁剪. 视频合并请见我的另外一篇博客<Android 使用 mp4parser 做视频拼接合并> 使用时先 ...

  8. android 视频录制尺寸裁剪,galleryfinal 实现Android图片单选/多选、拍照、裁剪、压缩。视频选择和录制。...

    RxGalleryFinal是一个android图片/视频文件选择器.其支持多选.单选.拍摄和裁剪,主题可自定义,无强制绑定第三方图片加载器. 1.首先加入权限 2.在module gradle中项目 ...

  9. android可以剪辑代码的控件,Android 仿抖音视频裁剪范围选择控件,支持本地视频和网络视频...

    实现后效果:由于是在模拟器上跑的背面的封面列表加载不出来,实际效果请真机运行 image.png 具体代码如下: 绘制上层滑动控件部分 package com.cj.customwidget.widg ...

  10. Android 基于MediaCodec开发抖音短视频录制(壹)

    前言 当一个Android开发者玩抖音玩疯了之后,就会绞尽脑汁思考自己是否也能开发出一款相同的APP来呢? 滴,滴滴! 本篇文章将介绍自己总结的短视频录制的相关内容,主要分为三个部分: 摄像头内容录制 ...

最新文章

  1. 关于RotatedRect与getRotationMatrix2D 的角度问题
  2. IdentityServer4 配置负载均衡
  3. 设计模式原则之依赖倒置原则
  4. python3中numpy函数tile的用法
  5. while(1); 作用
  6. 牛客练习赛19 E和F(签到就走系列)托米的饮料+托米搭积木
  7. 1251 括号(递归小练)
  8. java class load 类加载
  9. kafka 日志相关配置
  10. 带有返回值的装饰器_如何使用带有工厂功能的装饰器
  11. 微课|中学生可以这样学Python(例3.2):今天是今年的第几天
  12. OC继承以及实例变量修饰符
  13. Spring-context-ApplicationContext/AbstractApplicationContext
  14. Selenium 调用IEDriverServer打开IE浏览器
  15. 关于引用lightbox源码
  16. java动态编译无法导包_java动态编译整个项目,解决jar包找不到问题.doc
  17. c++中 . 和 - 的区别
  18. 【修真院WEB小课堂】 angular js中的依赖注入是什么?
  19. 安利几个翻译照片的好用软件
  20. 什么?你还没妹子?教你如何借助Python俘获女孩子芳心

热门文章

  1. oracle 同义词public,oracle中private同义词跟public同义词
  2. 下载软件时的X86和X64的区别
  3. SQL Server各版本
  4. 头部姿态估计:《Fine-Grained Head Pose Estimation Without Keypoints》
  5. 辽宁等保测评机构项目测评收费价格标准参考
  6. 《数据结构》实验二 线性表的实验
  7. 在火狐浏览器打开xpath_元素定位工具:火狐浏览器Try Xpath插件
  8. 正则表达式小Tips
  9. 为什么我怎么也理解不了波粒二象性,是因为智商不够吗?
  10. android root工具排行榜,可root任何机?史上最强安卓root工具出炉