多媒体——视频——从视频库中选取视频
从视频库中选取视频
系统自带的相册既保存图片又保存视频,这意味着用户能够从中选择已有的视频。
打开视频库之前,需要指定数据类型为视频,相关代码代码示例如下:
Intent intent = new Intent(Intent.ACTION_GET_CONTENT); // 创建一个内容获取动作的意图(准备跳到系统视频库)
intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true); // 是否允许多选
intent.setType("video/*"); // 类型为视频
startActivityForResult(intent, CHOOSE_CODE); // 打开系统视频库
============================================================================================================
布局:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal"> <Button android:id="@+id/btn_choose" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:text="打开视频库选取视频" android:textColor="@color/black" android:textSize="16sp" /> <Button android:id="@+id/btn_combine" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:text="录像或从视频库选取" android:textColor="@color/black" android:textSize="16sp" /> </LinearLayout> <TextView android:id="@+id/tv_video" android:layout_width="match_parent" android:layout_height="wrap_content" android:paddingLeft="5dp" android:textColor="@color/black" android:textSize="17sp" /> <RelativeLayout android:id="@+id/rl_video" android:layout_width="match_parent" android:layout_height="300dp" android:visibility="gone"> <ImageView android:id="@+id/iv_video" android:layout_width="match_parent" android:layout_height="match_parent" android:scaleType="fitCenter" /> <ImageView android:layout_width="match_parent" android:layout_height="match_parent" android:scaleType="fitCenter" android:src="@drawable/play_video" /> </RelativeLayout> </LinearLayout>
MediaUtil
package com.example.myapplication.util; import android.annotation.SuppressLint; import android.content.Context; import android.graphics.Bitmap; import android.media.MediaMetadataRetriever; import android.net.Uri; import android.os.Environment; import android.util.Log; import java.io.File; @SuppressLint("DefaultLocale") public class MediaUtil { private final static String TAG = "MediaUtil"; // 格式化播放时长(mm:ss) public static String formatDuration(int milliseconds) { int seconds = milliseconds / 1000; int hour = seconds / 3600; int minute = seconds / 60; int second = seconds % 60; String str; if (hour > 0) { str = String.format("%02d:%02d:%02d", hour, minute, second); } else { str = String.format("%02d:%02d", minute, second); } return str; } // 获得音视频文件的缓存路径 public static String getRecordFilePath(Context context, String dir_name, String extend_name) { String path = ""; File recordDir = new File(context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS).toString() + "/" + dir_name + "/"); if (!recordDir.exists()) { recordDir.mkdirs(); } try { File recordFile = File.createTempFile(DateUtil.getNowDateTime(), extend_name, recordDir); path = recordFile.getAbsolutePath(); Log.d(TAG, "dir_name=" + dir_name + ", extend_name=" + extend_name + ", path=" + path); } catch (Exception e) { e.printStackTrace(); } return path; } // 获取视频文件中的某帧图片 public static Bitmap getOneFrame(Context ctx, Uri uri) { MediaMetadataRetriever retriever = new MediaMetadataRetriever(); retriever.setDataSource(ctx, uri); // 获得视频的播放时长,大于1秒的取第1秒处的帧图,不足1秒的取第0秒处的帧图 String duration = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION); Log.d(TAG, "duration="+duration); int pos = (Integer.parseInt(duration)/1000)>1 ? 1 : 0; // 获取指定时间的帧图,注意getFrameAtTime方法的时间单位是微秒 return retriever.getFrameAtTime(pos * 1000 * 1000); } }
FileUtil
package com.example.myapplication.util; import android.content.Context; import android.database.Cursor; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.net.Uri; import android.os.Build; import android.provider.MediaStore; import android.util.Log; import androidx.core.content.FileProvider; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.InputStream; import java.io.OutputStream; public class FileUtil { private final static String TAG = "FileUtil"; // 把字符串保存到指定路径的文本文件 public static void saveText(String path, String txt) { // 根据指定的文件路径构建文件输出流对象 try (FileOutputStream fos = new FileOutputStream(path)) { fos.write(txt.getBytes()); // 把字符串写入文件输出流 } catch (Exception e) { e.printStackTrace(); } } // 从指定路径的文本文件中读取内容字符串 public static String openText(String path) { String readStr = ""; // 根据指定的文件路径构建文件输入流对象 try (FileInputStream fis = new FileInputStream(path)) { byte[] b = new byte[fis.available()]; fis.read(b); // 从文件输入流读取字节数组 readStr = new String(b); // 把字节数组转换为字符串 } catch (Exception e) { e.printStackTrace(); } return readStr; // 返回文本文件中的文本字符串 } // 把位图数据保存到指定路径的图片文件 public static void saveImage(String path, Bitmap bitmap) { // 根据指定的文件路径构建文件输出流对象 try (FileOutputStream fos = new FileOutputStream(path)) { // 把位图数据压缩到文件输出流中 bitmap.compress(Bitmap.CompressFormat.JPEG, 80, fos); } catch (Exception e) { e.printStackTrace(); } } // 从指定路径的图片文件中读取位图数据 public static Bitmap openImage(String path) { Bitmap bitmap = null; // 声明一个位图对象 // 根据指定的文件路径构建文件输入流对象 try (FileInputStream fis = new FileInputStream(path)) { // 从文件输入流中解码位图数据 bitmap = BitmapFactory.decodeStream(fis); } catch (Exception e) { e.printStackTrace(); } return bitmap; // 返回图片文件中的位图数据 } // 检查文件是否存在,以及文件路径是否合法 public static boolean checkFileUri(Context ctx, String path) { boolean result = true; File file = new File(path); if (!file.exists() || !file.isFile() || file.length() <= 0) { result = false; } try { Uri uri = Uri.parse(path); // 根据指定路径创建一个Uri对象 // 兼容Android7.0,把访问文件的Uri方式改为FileProvider if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { // // 通过FileProvider获得文件的Uri访问方式 // uri = FileProvider.getUriForFile(ctx, // ctx.getPackageName()+".fileProvider", new File(path)); } } catch (Exception e) // 该路径可能不存在 { e.printStackTrace(); result = false; } return result; } // 把指定uri保存为存储卡文件 public static void saveFileFromUri(Context ctx, Uri src, String dest) { try (InputStream is = ctx.getContentResolver().openInputStream(src); OutputStream os = new FileOutputStream(dest);) { int byteCount = 0; byte[] bytes = new byte[8096]; while ((byteCount = is.read(bytes)) != -1){ os.write(bytes, 0, byteCount); } } catch (Exception e) { e.printStackTrace(); } } // 从content://media/external/file/这样的Uri中获取文件路径 public static String getPathFromContentUri(Context context, Uri uri) { String path = uri.toString(); if (path.startsWith("content://")) { String[] proj = new String[]{ // 媒体库的字段名称数组 MediaStore.Video.Media._ID, // 编号 MediaStore.Video.Media.TITLE, // 标题 MediaStore.Video.Media.SIZE, // 文件大小 MediaStore.Video.Media.MIME_TYPE, // 文件类型 MediaStore.Video.Media.DATA // 文件大小 }; try (Cursor cursor = context.getContentResolver().query(uri, proj, null, null, null)) { cursor.moveToFirst(); // 把游标移动到开头 if (cursor.getString(4) != null) { path = cursor.getString(4); } Log.d(TAG, cursor.getLong(0) + " " + cursor.getString(1) + " " + cursor.getLong(2) + " " + cursor.getString(3) + " " + cursor.getString(4)); } catch (Exception e) { e.printStackTrace(); } } return path; } }
主代码:
package com.example.myapplication; import android.content.ClipData; import android.content.Intent; import android.graphics.Bitmap; import android.net.Uri; import android.os.Bundle; import android.provider.MediaStore; import android.view.View; import android.widget.ImageView; import android.widget.RelativeLayout; import android.widget.TextView; import androidx.appcompat.app.AppCompatActivity; import com.example.myapplication.util.FileUtil; import com.example.myapplication.util.MediaUtil; public class MainActivity extends AppCompatActivity implements View.OnClickListener { private final static String TAG = "VideoChooseActivity"; private int CHOOSE_CODE = 3; // 只在视频库挑选图片的请求码 private int COMBINE_CODE = 4; // 既可录像获得现场视频、也可在视频库挑选已有视频的请求码 private TextView tv_video; private RelativeLayout rl_video; private ImageView iv_video; private Uri mVideoUri; // 视频文件的路径对象 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); tv_video = findViewById(R.id.tv_video); rl_video = findViewById(R.id.rl_video); iv_video = findViewById(R.id.iv_video); findViewById(R.id.btn_choose).setOnClickListener(this); findViewById(R.id.btn_combine).setOnClickListener(this); findViewById(R.id.rl_video).setOnClickListener(this); } @Override public void onClick(View v) { if (v.getId() == R.id.btn_choose) { // 创建一个内容获取动作的意图(准备跳到系统视频库) Intent intent = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI); intent.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, "video/*"); startActivityForResult(intent, CHOOSE_CODE); // 打开系统视频库 } else if (v.getId() == R.id.btn_combine) { openSelectDialog(); // 打开选择对话框(要录像还是去视频库) } else if (v.getId() == R.id.rl_video) { String realPath = FileUtil.getPathFromContentUri(this, mVideoUri); // 创建一个内容获取动作的意图(准备跳到系统播放器) Intent intent = new Intent(Intent.ACTION_VIEW); intent.setDataAndType(Uri.parse(realPath), "video/*"); // 类型为视频 startActivity(intent); // 打开系统的视频播放器 } } @Override protected void onActivityResult(int requestCode, int resultCode, Intent intent) { super.onActivityResult(requestCode, resultCode, intent); if (resultCode==RESULT_OK && requestCode==CHOOSE_CODE) // 从视频库回来 { if (intent.getData() != null) // 选择一个视频 { Uri uri = intent.getData(); // 获得已选择视频的路径对象 showVideoFrame(uri); // 显示视频的某帧图片 } else if (intent.getClipData() != null) // 选择多个视频 { ClipData videos = intent.getClipData(); // 获取剪切板数据 if (videos.getItemCount() > 0) // 至少选择了一个文件 { Uri uri = videos.getItemAt(0).getUri(); // 取第一个视频 showVideoFrame(uri); // 显示视频的某帧图片 } } } if (resultCode==RESULT_OK && requestCode==COMBINE_CODE) // 从混合选择对话框回来 { if (intent.getData() != null) // 录像或者从视频库选择一个视频 { Uri uri = intent.getData(); // 获得已选择视频的路径对象 showVideoFrame(uri); // 显示视频的某帧图片 } } } // 打开选择对话框(要录像还是去视频库) private void openSelectDialog() { // 声明摄像机的录像行为 Intent recordIntent = new Intent(MediaStore.ACTION_VIDEO_CAPTURE); Intent[] intentArray = new Intent[] { recordIntent }; // 声明视频库的打开行为 Intent videoIntent = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI); videoIntent.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, "video/*"); // 弹出含摄像机和视频库在内的列表对话框 Intent chooserIntent = new Intent(Intent.ACTION_CHOOSER); chooserIntent.putExtra(Intent.EXTRA_TITLE, "请录像或选择视频"); chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, intentArray); chooserIntent.putExtra(Intent.EXTRA_INTENT, videoIntent); // 在页面底部弹出多种选择方式的列表对话框 startActivityForResult(Intent.createChooser(chooserIntent, "选择视频"), COMBINE_CODE); } // 显示视频的某帧图片 private void showVideoFrame(Uri uri) { mVideoUri = uri; tv_video.setText("你选中的视频地址为:"+uri.toString()); rl_video.setVisibility(View.VISIBLE); // 获取视频文件的某帧图片 Bitmap bitmap = MediaUtil.getOneFrame(this, uri); iv_video.setImageBitmap(bitmap); // 设置图像视图的位图对象 } }