上一篇写了分段录制和合并视频,这一篇则是选择视频,然后截断视频。
1、从sdcard中找到视频资源;
2、分析视频,拿到你需要的帧数当你的图片。(我的是根据参数来算的多少秒1帧的图片,一般是1秒1帧来显示图片)
3、给个 可拉动 控件来选择截断区域 。(我的是基本参数是最少5秒。最大15秒。如需修改,只需改(MIN_TIME,MAX_TIME)这2个参数则以)
先上图:
咱们来看代码,首先是选择视频的:
package com.example.shipin;import java.util.ArrayList;import android.annotation.SuppressLint;import android.content.ContentResolver;import android.content.Context;import android.content.Intent;import android.database.Cursor;import android.graphics.Bitmap;import android.media.ThumbnailUtils;import android.net.Uri;import android.os.Bundle;import android.os.Handler;import android.os.Message;import android.provider.MediaStore;import android.view.LayoutInflater;import android.view.View;import android.view.View.OnClickListener;import android.view.ViewGroup;import android.widget.AdapterView;import android.widget.AdapterView.OnItemClickListener;import android.widget.BaseAdapter;import android.widget.GridView;import android.widget.ImageView;import android.widget.RelativeLayout.LayoutParams;import android.widget.TextView;public class VideoNewSelectActivity extends BaseActivity { /** 图片展示器 */ private GridView gridview; /** 图片适配器 */ private ViewNewSelectAdapter adapter; /** 数据集 */ private ArrayList<ViewNewSelectBean> list; private ImageView img_back; /** 显示图片的宽 */ private int width; @Override protected int getContentViewId() { return R.layout.activity_video_new_select; } @SuppressWarnings("deprecation") @Override protected void findViews() { img_back = (ImageView) findViewById(R.id.video_new_img_back); gridview = (GridView) findViewById(R.id.video_new_select_gridview); width = (getWindowManager().getDefaultDisplay().getWidth() - DisplayUtil.dip2px(VideoNewSelectActivity.this, 60)) / 3; } @Override protected void init() { list = new ArrayList<ViewNewSelectBean>(); adapter = new ViewNewSelectAdapter(list, width, VideoNewSelectActivity.this); gridview.setAdapter(adapter); getList(); } @Override protected void widgetListener() { img_back.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { finish(); } }); gridview.setOnItemClickListener(new OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { Bundle bundle = new Bundle(); bundle.putSerializable("serializable", list.get(position)); Intent intent = new Intent(VideoNewSelectActivity.this, VideoNewCutActivity.class); intent.putExtras(bundle); startActivity(intent); } }); } private Handler handler = new Handler() { public void handleMessage(android.os.Message msg) { if (msg.what == 1) { adapter.notifyDataSetChanged(); } }; }; /** * 获取数据 * * @version 1.0 * @createTime 2015年6月16日,下午6:14:09 * @updateTime 2015年6月16日,下午6:14:09 * @createAuthor WangYuWen * @updateAuthor WangYuWen * @updateInfo (此处输入修改内容,若无修改可不写.) * */ private void getList() { new Thread(new Runnable() { @Override public void run() { // 若为图片则为MediaStore.Images.Media.EXTERNAL_CONTENT_URI; Uri originalUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI; ContentResolver cr = getContentResolver(); Cursor cursor = cr.query(originalUri, null, null, null, null); if (cursor == null) { return; } while (cursor.moveToNext()) { ViewNewSelectBean bean = new ViewNewSelectBean(); bean.set_id(cursor.getLong(cursor.getColumnIndex("_ID"))); bean.setName(cursor.getString(cursor.getColumnIndex("_display_name")));// 视频名字 bean.setPath(cursor.getString(cursor.getColumnIndex("_data")));// 路径 bean.setWidth(cursor.getInt(cursor.getColumnIndex("width")));// 视频宽 bean.setHeight(cursor.getInt(cursor.getColumnIndex("height")));// 视频高 bean.setDuration(cursor.getLong(cursor.getColumnIndex("duration")));// 时长 list.add(bean); } Message message = handler.obtainMessage(); message.what = 1; handler.sendMessage(message); // /data/data/com.android.providers.media/databases/external.db // {5dd10730} 数据库位置 } }).start(); } private class ViewNewSelectAdapter extends BaseAdapter { private Context context; /** 数据集 */ private ArrayList<ViewNewSelectBean> list; /** 图片宽 */ private int width; public ViewNewSelectAdapter(ArrayList<ViewNewSelectBean> list, int width, Context context) { this.list = list; this.width = width; this.context = context; } @Override public int getCount() { return list.size(); } @Override public Object getItem(int position) { return list.get(position); } @Override public long getItemId(int position) { return position; } @SuppressLint("InflateParams") @Override public View getView(int position, View convertView, ViewGroup parent) { final ViewHolder viewHolder; final ViewNewSelectBean bean = list.get(position); if (convertView == null) { viewHolder = new ViewHolder(); convertView = LayoutInflater.from(context).inflate(R.layout.item_video_new_select_gridview, null); viewHolder.txt = (TextView) convertView.findViewById(R.id.item_video_new_select_txt_time); viewHolder.img = (ImageView) convertView.findViewById(R.id.item_video_new_select_img); convertView.setTag(viewHolder); } else { viewHolder = (ViewHolder) convertView.getTag(); } LayoutParams layoutParams = (LayoutParams) viewHolder.img.getLayoutParams(); layoutParams.width = width; layoutParams.height = width; viewHolder.img.setLayoutParams(layoutParams); // 获取图片 Bitmap bitmap = getVideoThumbnail(bean.getPath(), width, width, MediaStore.Images.Thumbnails.MICRO_KIND); if (bitmap != null) { // 设置图片 viewHolder.img.setImageBitmap(bitmap); } // 设置时长 viewHolder.txt.setText(String.format("时长:%1$s s", bean.getDuration() / 1000)); return convertView; } /** * 获取视频的缩略图 * 先通过ThumbnailUtils来创建一个视频的缩略图,然后再利用ThumbnailUtils来生成指定大小的缩略图。 * 如果想要的缩略图的宽和高都小于MICRO_KIND,则类型要使用MICRO_KIND作为kind的值,这样会节省内存。 * * @param videoPath * 视频的路径 * @param width * 指定输出视频缩略图的宽度 * @param height * 指定输出视频缩略图的高度度 * @param kind * 参照MediaStore.Images. * Thumbnails类中的常量MINI_KIND和MICRO_KIND。 * 其中,MINI_KIND: 512 x 384,MICRO_KIND: 96 x 96 * @return 指定大小的视频缩略图 */ private Bitmap getVideoThumbnail(String videoPath, int width, int height, int kind) { Bitmap bitmap = null; // 获取视频的缩略图 bitmap = ThumbnailUtils.createVideoThumbnail(videoPath, kind); bitmap = ThumbnailUtils.extractThumbnail(bitmap, width, height, ThumbnailUtils.OPTIONS_RECYCLE_INPUT); return bitmap; } private class ViewHolder { private ImageView img; private TextView txt; } }}
看到选择之后就到重点部分了,视频截断。首先得从上个activity拿到视频的数据bean,然后通过视频路径,分析视频,通过自己设置的需要多少帧一张的图片来进行取图片。取完图片则是通过android的新控件RecyclerView来进行显示,听说RecyclerView是Listview的升级版(支持横向和竖向)。我还需要他滚动的距离来进行计算切断的位置。RecyclerView貌似拿不到滚动距离,所以咱们得自己计算了(通过拿到当前滑到的position*view的宽度-view距左边的距离就得到滚动距离了),还有个矩形框来进行拉动选择截断大小哦。好了咱们来看代码吧(代码注释量还是比较大的,应该都懂,不懂留言给我一一解答):
package com.example.shipin;import java.io.File;import java.io.FileOutputStream;import java.io.IOException;import java.util.ArrayList;import android.annotation.SuppressLint;import android.content.Intent;import android.graphics.Bitmap;import android.graphics.Bitmap.CompressFormat;import android.media.MediaMetadataRetriever;import android.media.MediaPlayer;import android.media.MediaPlayer.OnCompletionListener;import android.os.Environment;import android.os.Handler;import android.os.Message;import android.support.v7.widget.LinearLayoutManager;import android.view.MotionEvent;import android.view.View;import android.view.View.OnClickListener;import android.view.View.OnTouchListener;import android.widget.Button;import android.widget.ImageView;import android.widget.RelativeLayout;import android.widget.TextView;import android.widget.RelativeLayout.LayoutParams;import android.widget.VideoView;import com.example.shipin.MyRecyclerView.OnItemScrollChangeListener;import com.example.shipin.VideoNewCutAdapter.MyItemClickListener;public class VideoNewCutActivity extends BaseActivity { /**返回*/ private ImageView img_back; /**确认*/ private TextView txt_enter; /** 视频bean */ private ViewNewSelectBean bean; /** 横向listview */ private MyRecyclerView recyclerView; /** 封面图按钮 */ private ImageView img_bg; /** 阴影色块left */ private ImageView img_left; /** 阴影色块right */ private ImageView img_right; /** 显示时间 */ private TextView txt_time; /** 封面容器 */ private RelativeLayout relative; /** 进度条 */ private RelativeLayout relative1; /** 视频播放 */ private VideoView videoView; /** 数据集 */ private ArrayList<String> list; /** 列表适配器 */ private VideoNewCutAdapter adapter; /** 屏幕宽度 */ private int width; /** 临时保存文件路径 */ private String savePath; /** 最少多少秒 */ public static final int MIN_TIME = 5000; /** 最大多少秒 */ public static final int MAX_TIME = 15000; /** 屏幕中1像素占有多少毫秒 */ private float picture = 0; /** 多少秒一帧 */ private float second_Z; /** 是否中断线性 */ private boolean isThread = false; /** 左边拖动按钮 */ private Button txt_left; /** 右边拖动按钮 */ private Button txt_right; /** 按下时X抽坐标 */ private float DownX; /** 拖动条容器 */ private LayoutParams layoutParams_progress; /** 阴影背景容器 */ private LayoutParams layoutParams_yin; /** 拖动条的宽度 */ private int width_progress = 0; /** 拖动条的间距 */ private int Margin_progress = 0; /** 阴影框的宽度 */ private int width1_progress = 0; /** 不能超过右边多少 */ private int right_margin = 0; /** 所有图片长度 */ private int img_widthAll = 0; /** 最少保留的多少秒长度 */ private int last_length = 0; /** 左边啦了多少 */ private int left_lenth = 0; /** 滚动的长度 */ private int Scroll_lenth = 0; /** 路径 */ private String Ppath = Environment.getExternalStorageDirectory().getAbsolutePath() + "/videoTest/Image/"; @Override protected int getContentViewId() { return R.layout.activity_video_new_cut; } @SuppressWarnings("deprecation") @Override protected void findViews() { img_back = (ImageView) findViewById(R.id.video_new_img_back); txt_enter = (TextView) findViewById(R.id.video_new_txt_enter); recyclerView = (MyRecyclerView) findViewById(R.id.recyclerview_horizontal); videoView = (VideoView) findViewById(R.id.video_new_cut_videoview); img_bg = (ImageView) findViewById(R.id.video_new_cut_img_bg); img_left = (ImageView) findViewById(R.id.video_new_cut_img_left); img_right = (ImageView) findViewById(R.id.video_new_cut_img_right); relative = (RelativeLayout) findViewById(R.id.video_new_cut_relative); txt_time = (TextView) findViewById(R.id.video_new_cut_txt_time); relative1 = (RelativeLayout) findViewById(R.id.video_new_cut_relative1); txt_left = (Button) findViewById(R.id.video_new_cut_txt_left); txt_right = (Button) findViewById(R.id.video_new_cut_txt_right); width = getWindowManager().getDefaultDisplay().getWidth(); LayoutParams layoutParams = (LayoutParams) relative.getLayoutParams(); layoutParams.width = width; layoutParams.height = width; relative.setLayoutParams(layoutParams); // 创建一个线性布局管理器 LinearLayoutManager layoutManager = new LinearLayoutManager(this); layoutManager.setOrientation(LinearLayoutManager.HORIZONTAL); // 设置布局管理器 recyclerView.setLayoutManager(layoutManager); list = new ArrayList<String>(); adapter = new VideoNewCutAdapter(list); } @Override protected void initGetData() { super.initGetData(); if (getIntent().getExtras() != null) { bean = (ViewNewSelectBean) getIntent().getExtras().getSerializable("serializable"); } } @Override protected void init() { // 创建文件夹 File file = new File(Ppath); if (!file.exists()) { file.mkdir(); } recyclerView.setAdapter(adapter); videoView.setVideoPath(bean.getPath()); videoView.requestFocus(); /** 一个屏幕1像素是多少毫秒 13.88888 */ picture = (float) MAX_TIME / (float) width; /** 1.66666 */ second_Z = (float) MAX_TIME / 1000f / ((float) width / (float) DisplayUtil.dip2px(VideoNewCutActivity.this, 60)); getBitmapsFromVideo(bean.getPath(), (int) bean.getDuration()); } private Handler handler = new Handler() { public void handleMessage(android.os.Message msg) { if (msg.what == 1) { adapter.notifyItemInserted(msg.arg1); if (msg.arg1 == 0) { sendVideo(DisplayUtil.dip2px(VideoNewCutActivity.this, 60)); } } else if (msg.what == 2) { img_widthAll = (int) (msg.arg1 * 1000 / picture); last_length = (int) (MIN_TIME / picture); if (img_widthAll < width) { right_margin = width - img_widthAll; LayoutParams layoutParams_right = (LayoutParams) img_right.getLayoutParams(); layoutParams_right.width = width - img_widthAll; img_right.setLayoutParams(layoutParams_right); layoutParams_progress = (LayoutParams) relative1.getLayoutParams(); layoutParams_progress.width = img_widthAll; layoutParams_progress.rightMargin = width - img_widthAll; relative1.setLayoutParams(layoutParams_progress); txt_time.setText(msg.arg1 + ".0 s"); } else { img_widthAll = width; layoutParams_progress = (LayoutParams) relative1.getLayoutParams(); layoutParams_progress.width = width; relative1.setLayoutParams(layoutParams_progress); txt_time.setText((MAX_TIME / 1000) + ".0 s"); } } }; }; /** * 获取视频帧图片 * * @version 1.0 * @createTime 2015年6月17日,上午11:49:54 * @updateTime 2015年6月17日,上午11:49:54 * @createAuthor WangYuWen * @updateAuthor WangYuWen * @updateInfo (此处输入修改内容,若无修改可不写.) * * @param dataPath * @param lenth */ public void getBitmapsFromVideo(final String dataPath, final int lenth) { new Thread(new Runnable() { @SuppressLint("NewApi") @Override public void run() { MediaMetadataRetriever retriever = new MediaMetadataRetriever(); retriever.setDataSource(dataPath); // 取得视频的长度(单位为秒) int seconds = lenth / 1000; Message message = handler.obtainMessage(); message.what = 2; message.arg1 = seconds; handler.sendMessage(message); Bitmap bitmap; // 得到每一秒时刻的bitmap比如第一秒,第二秒 int index = 0; for (float f = second_Z; f <= (float) seconds; f += second_Z) { if (isThread) { return; } bitmap = retriever.getFrameAtTime((long) (f * 1000 * 1000), MediaMetadataRetriever.OPTION_CLOSEST_SYNC); String path = Ppath + System.currentTimeMillis() + ".jpg"; FileOutputStream fos = null; try { fos = new FileOutputStream(path); bitmap.compress(CompressFormat.JPEG, 80, fos); fos.close(); list.add(path); Message message1 = handler.obtainMessage(); message1.what = 1; message1.arg1 = index; handler.sendMessage(message1); index++; } catch (Exception e) { e.printStackTrace(); } } } }).start(); } @Override protected void widgetListener() { /** 列表点击事件 */ adapter.setOnClickListener(new MyItemClickListener() { @Override public void onItemClick(View view, int position) { sendVideo((position + 1) * view.getWidth()); } }); /** 返回 */ img_back.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { finish(); } }); /** 完成 */ txt_enter.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { handler.post(runnable3); } }); /** 播放 */ relative.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { if (videoView.isPlaying()) { img_bg.setVisibility(View.VISIBLE); videoView.pause(); handler.removeCallbacks(runnable); } else { videoView.setVisibility(View.VISIBLE); img_bg.setVisibility(View.GONE); videoView.start(); layoutParams_progress = (LayoutParams) relative1.getLayoutParams(); // 会误差 200-800毫秒 handler.postDelayed(runnable, (long) (layoutParams_progress.width * picture) + 500); } } }); /** 左边拖动按钮 */ txt_left.setOnTouchListener(new OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: DownX = event.getRawX(); layoutParams_progress = (LayoutParams) relative1.getLayoutParams(); layoutParams_yin = (LayoutParams) img_left.getLayoutParams(); width_progress = layoutParams_progress.width; Margin_progress = layoutParams_progress.leftMargin; width1_progress = layoutParams_yin.width; break; case MotionEvent.ACTION_MOVE: LeftMoveLayout(event.getRawX() - DownX, event.getRawX()); break; case MotionEvent.ACTION_UP: sendVideo(); layoutParams_progress = null; layoutParams_yin = null; break; default: break; } return false; } }); /** 右边拖动按钮 */ txt_right.setOnTouchListener(new OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: DownX = event.getRawX(); layoutParams_progress = (LayoutParams) relative1.getLayoutParams(); layoutParams_yin = (LayoutParams) img_right.getLayoutParams(); width_progress = layoutParams_progress.width; Margin_progress = layoutParams_progress.rightMargin; width1_progress = layoutParams_yin.width; break; case MotionEvent.ACTION_MOVE: RightMoveLayout(DownX - event.getRawX()); break; case MotionEvent.ACTION_UP: layoutParams_progress = null; layoutParams_yin = null; break; default: break; } return false; } }); /** 视频播放完回调 */ videoView.setOnCompletionListener(new OnCompletionListener() { @Override public void onCompletion(MediaPlayer mp) { img_bg.setVisibility(View.VISIBLE); handler.removeCallbacks(runnable); } }); /** 滚动监听 */ recyclerView.setOnItemScrollChangeListener(new OnItemScrollChangeListener() { @Override public void onChange(View view, int position) { Scroll_lenth = position * view.getWidth() - view.getLeft(); if (Scroll_lenth <= 0) { Scroll_lenth = 0; }// sendVideo();//打开注释就是边滑动变更新视图 } @Override public void onChangeState(int state) { if (state == 0) {// 静止情况时候才调用 sendVideo(); } } }); } private Runnable runnable3 = new Runnable() { @Override public void run() { try { layoutParams_progress = (LayoutParams) relative1.getLayoutParams(); savePath = Ppath + System.currentTimeMillis() + ".mp4"; FUckTest.startTrim(new File(bean.getPath()), new File(savePath), (long) ((Scroll_lenth + left_lenth) * picture), (long) ((Scroll_lenth + left_lenth + layoutParams_progress.width) * picture)); Intent it = new Intent(VideoNewCutActivity.this,VideoActivity.class); it.putExtra("path", savePath); startActivity(it); } catch (IOException e) { e.printStackTrace(); } } }; /** * 向右边啦 * * @version 1.0 * @createTime 2015年6月18日,上午9:44:32 * @updateTime 2015年6月18日,上午9:44:32 * @createAuthor WangYuWen * @updateAuthor WangYuWen * @updateInfo (此处输入修改内容,若无修改可不写.) * * @param MoveX */ private void LeftMoveLayout(float MoveX, float X) { if (layoutParams_progress != null && layoutParams_yin != null) { if (Margin_progress + (int) MoveX > 0 && width_progress - (int) MoveX > last_length) { layoutParams_progress.width = width_progress - (int) MoveX; layoutParams_progress.leftMargin = Margin_progress + (int) MoveX; layoutParams_yin.width = width1_progress + (int) MoveX; relative1.setLayoutParams(layoutParams_progress); img_left.setLayoutParams(layoutParams_yin); txt_time.setText((float) (Math.round((layoutParams_progress.width * picture / 1000) * 10)) / 10 + " s"); left_lenth = layoutParams_yin.width; } } } /** * 向左边拉 * * @version 1.0 * @createTime 2015年6月18日,上午9:45:16 * @updateTime 2015年6月18日,上午9:45:16 * @createAuthor WangYuWen * @updateAuthor WangYuWen * @updateInfo (此处输入修改内容,若无修改可不写.) * * @param MoveX */ private void RightMoveLayout(float MoveX) { if (layoutParams_progress != null && layoutParams_yin != null) { if (Margin_progress + (int) MoveX > right_margin && width_progress - (int) MoveX > last_length) { layoutParams_progress.width = width_progress - (int) MoveX; layoutParams_progress.rightMargin = Margin_progress + (int) MoveX; layoutParams_yin.width = width1_progress + (int) MoveX; txt_time.setText((float) (Math.round((layoutParams_progress.width * picture / 1000) * 10)) / 10 + " s"); relative1.setLayoutParams(layoutParams_progress); img_right.setLayoutParams(layoutParams_yin); } } } private Runnable runnable = new Runnable() { @Override public void run() { if (!img_bg.isShown()) { img_bg.setVisibility(View.VISIBLE); } if (videoView.isPlaying()) { videoView.pause(); } } }; /** * 移动起始播放位置 * * @version 1.0 * @createTime 2015年6月18日,下午2:34:31 * @updateTime 2015年6月18日,下午2:34:31 * @createAuthor WangYuWen * @updateAuthor WangYuWen * @updateInfo (此处输入修改内容,若无修改可不写.) * * @param proSlide */ private void sendVideo() { if (!videoView.isShown()) { videoView.setVisibility(View.VISIBLE); } if (videoView.isPlaying()) { videoView.pause(); } if (!img_bg.isShown()) { img_bg.setVisibility(View.VISIBLE); } handler.removeCallbacks(runnable); videoView.seekTo((int) ((Scroll_lenth + left_lenth) * picture)); } /** * 移动起始播放位置 * * @version 1.0 * @createTime 2015年6月18日,下午6:09:50 * @updateTime 2015年6月18日,下午6:09:50 * @createAuthor WangYuWen * @updateAuthor WangYuWen * @updateInfo (此处输入修改内容,若无修改可不写.) * * @param lenth * 长度 */ private void sendVideo(int lenth) { if (!videoView.isShown()) { videoView.setVisibility(View.VISIBLE); } if (videoView.isPlaying()) { videoView.pause(); } if (!img_bg.isShown()) { img_bg.setVisibility(View.VISIBLE); } handler.removeCallbacks(runnable); videoView.seekTo((int) (lenth * picture)); } @Override protected void onDestroy() { super.onDestroy(); isThread = true; deleteFile(); } /** * 退出时删除临时文件 * * @version 1.0 * @createTime 2015年6月17日,下午1:58:52 * @updateTime 2015年6月17日,下午1:58:52 * @createAuthor WangYuWen * @updateAuthor WangYuWen * @updateInfo (此处输入修改内容,若无修改可不写.) * */ private void deleteFile() { for (int i = 0; i < list.size(); i++) { File file = new File(list.get(i)); if (file.exists()) { file.delete(); } } }}
现在是自定义RecyclerView:
package com.utoow.diver.view;import android.content.Context;import android.support.v7.widget.RecyclerView;import android.support.v7.widget.RecyclerView.OnScrollListener;import android.util.AttributeSet;import android.view.View;public class MyRecyclerView extends RecyclerView implements OnScrollListener { /**记录当前第一个View*/ private View mCurrentView; private OnItemScrollChangeListener mItemScrollChangeListener; public void setOnItemScrollChangeListener(OnItemScrollChangeListener mItemScrollChangeListener) { this.mItemScrollChangeListener = mItemScrollChangeListener; } public interface OnItemScrollChangeListener { void onChange(View view, int position); void onChangeState(int state); } public MyRecyclerView(Context context, AttributeSet attrs) { super(context, attrs); this.setOnScrollListener(this); } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { super.onLayout(changed, l, t, r, b); } @Override public void onScrollStateChanged(int arg0) { if (mItemScrollChangeListener != null) { mItemScrollChangeListener.onChangeState(arg0); } } /** * 滚动时,判断当前第一个View是否发生变化,发生才回调 * * @version 1.0 * @createTime 2015年6月20日,下午4:14:30 * @updateTime 2015年6月20日,下午4:14:30 * @createAuthor WangYuWen * @updateAuthor WangYuWen * @updateInfo (此处输入修改内容,若无修改可不写.) * * @param arg0 * @param arg1 */ @Override public void onScrolled(int arg0, int arg1) { mCurrentView = getChildAt(0); if (mItemScrollChangeListener != null && mCurrentView != null) { mItemScrollChangeListener.onChange(mCurrentView, getChildPosition(mCurrentView)); } }}
最后再把视频截断和视频合并的工具类贴出来:
package com.example.shipin;import java.io.File;import java.io.FileOutputStream;import java.io.IOException;import java.io.RandomAccessFile;import java.nio.channels.FileChannel;import java.util.Arrays;import java.util.LinkedList;import java.util.List;import com.coremedia.iso.boxes.Container;import com.coremedia.iso.boxes.TimeToSampleBox;import com.googlecode.mp4parser.authoring.Movie;import com.googlecode.mp4parser.authoring.Track;import com.googlecode.mp4parser.authoring.builder.DefaultMp4Builder;import com.googlecode.mp4parser.authoring.container.mp4.MovieCreator;import com.googlecode.mp4parser.authoring.tracks.AppendTrack;import com.googlecode.mp4parser.authoring.tracks.CroppedTrack;public class FUckTest { public static void startTrim(File src, File dst, long start, long end) throws IOException { Movie movie = MovieCreator.build(src.getAbsolutePath()); // 删除所有跟踪我们将创建新的跟踪从旧 List<Track> tracks = movie.getTracks(); movie.setTracks(new LinkedList<Track>()); double startTime = start / 1000; double endTime = end / 1000; boolean timeCorrected = false; // 我们试图找到一个样品同步跟踪。因为我们只能开始解码在这样一个样品我们应该确保新的片段的开始就是这样的一个框架 for (Track track : tracks) { if (track.getSyncSamples() != null && track.getSyncSamples().length > 0) { if (timeCorrected) { // 这个异常可能是假阳性,以防我们有多个与同步跟踪样品在相同的位置。比如一部电影包含多个品质相同的视频(微软平滑流媒体文件) throw new RuntimeException("The startTime has already been corrected by another track with SyncSample. Not Supported."); } startTime = correctTimeToSyncSample(track, startTime, false);// true endTime = correctTimeToSyncSample(track, endTime, true);// false timeCorrected = true; } } for (Track track : tracks) { long currentSample = 0; double currentTime = 0; long startSample = -1; long endSample = -1; for (int i = 0; i < track.getDecodingTimeEntries().size(); i++) { TimeToSampleBox.Entry entry = track.getDecodingTimeEntries().get(i); for (int j = 0; j < entry.getCount(); j++) { // entry.getDelta()的数量当前样本覆盖。 if (currentTime <= startTime) { // 目前的样品仍然在新的开始时间之前 startSample = currentSample; } if (currentTime <= endTime) { // 当前样本后,新的开始时间和仍在新endtime前 endSample = currentSample; } else { // 目前样品结束后出现的视频 break; } currentTime += (double) entry.getDelta() / (double) track.getTrackMetaData().getTimescale(); currentSample++; } } movie.addTrack(new CroppedTrack(track, startSample, endSample)); // break;//取消注释,只截视频不截音频 } Container container = new DefaultMp4Builder().build(movie); if (!dst.exists()) { dst.createNewFile(); } FileOutputStream fos = new FileOutputStream(dst); FileChannel fc = fos.getChannel(); container.writeContainer(fc); fc.close(); fos.close(); } /** * 视频拼接, * * @version 1.0 * @createTime 2015年6月10日,下午5:12:15 * @updateTime 2015年6月10日,下午5:12:15 * @createAuthor WangYuWen * @updateAuthor WangYuWen * @updateInfo (此处输入修改内容,若无修改可不写.) * * @param videos * 视频文件数据。《路径》 * @param desName * 合并之后的文件名 * @param pro * @throws IOException */ public static void appendVideo(String[] videos, String desName) throws IOException { Movie[] inMovies = new Movie[videos.length]; int index = 0; for (String video : videos) { inMovies[index] = MovieCreator.build(video); index++; } List<Track> videoTracks = new LinkedList<Track>(); List<Track> audioTracks = new LinkedList<Track>(); for (Movie m : inMovies) { for (Track t : m.getTracks()) { if (t.getHandler().equals("soun")) { audioTracks.add(t); } if (t.getHandler().equals("vide")) { videoTracks.add(t); } } } Movie result = new Movie(); if (audioTracks.size() > 0) { result.addTrack(new AppendTrack(audioTracks.toArray(new Track[audioTracks.size()]))); } if (videoTracks.size() > 0) { result.addTrack(new AppendTrack(videoTracks.toArray(new Track[videoTracks.size()]))); } Container out = new DefaultMp4Builder().build(result); FileChannel fc = new RandomAccessFile(String.format(desName), "rw").getChannel(); out.writeContainer(fc); fc.close(); } protected static long getDuration(Track track) { long duration = 0; for (TimeToSampleBox.Entry entry : track.getDecodingTimeEntries()) { duration += entry.getCount() * entry.getDelta(); } return duration; } private static double correctTimeToSyncSample(Track track, double cutHere, boolean next) { double[] timeOfSyncSamples = new double[track.getSyncSamples().length]; long currentSample = 0; double currentTime = 0; for (int i = 0; i < track.getDecodingTimeEntries().size(); i++) { TimeToSampleBox.Entry entry = track.getDecodingTimeEntries().get(i); for (int j = 0; j < entry.getCount(); j++) { if (Arrays.binarySearch(track.getSyncSamples(), currentSample + 1) >= 0) { // 样品总是从1开始,但我们从零因此+ 1开始 timeOfSyncSamples[Arrays.binarySearch(track.getSyncSamples(), currentSample + 1)] = currentTime; } currentTime += (double) entry.getDelta() / (double) track.getTrackMetaData().getTimescale(); currentSample++; } } double previous = 0; for (double timeOfSyncSample : timeOfSyncSamples) { if (timeOfSyncSample > cutHere) { if (next) { return timeOfSyncSample; } else { return previous; } } previous = timeOfSyncSample; } return timeOfSyncSamples[timeOfSyncSamples.length - 1]; }}
好了,代码比较长,如果有不懂可以留言。(还有就是有的视频文件比较大就算切断了之后也有30多M,如果说这用到项目中肯定需要上传到服务器的肯定是不行的,需要的你们可以自己去研究下压缩视频,一般需要用到ffmgep这个c库来进行压缩,顺便说下ffmpeg这个c库真的很不错很成熟值得研究)!
最后就是:
希望大家多多关注我的博客,多多支持我。
如有好意见或更好的方式欢迎留言谈论。
尊重原创转载请注明:(http://blog.csdn.net/u013895206) !
下面是地址传送门:
http://download.csdn.net/detail/u013895206/8850751
版权声明:本文为博主原创文章,未经博主允许不得转载。