方式一(不符合要求)
使用MediaMetadataRetriever获取METADATA_KEY_DATE值;
result: 在Android华为9.0手机获取的到值,不过对应不上视频的拍摄时间(1904 UTC),在vivo6.0手机上没获取到;
查看了media_jni的一些cpp文件的代码,依然没法解决问题
方式二(不符合要求)
使用CursorLoader去获取,得到的也是null
private void loadVideoToShowInfo() {
    CursorLoader cursorLoader = new CursorLoader(
        this,MediaStore.Files.getContentUri("external"),new String[]{MediaStore.Video.VideoColumns.DATA,
        MediaStore.Video.VideoColumns.MIME_TYPE,MediaStore.Video.VideoColumns.DISPLAY_NAME,
        MediaStore.Video.VideoColumns.DATE_TAKEN,MediaStore.Video.VideoColumns.DATE_MODIFIED,
        MediaStore.Video.VideoColumns.DATE_ADDED,MediaStore.Video.VideoColumns.TITLE,BaseColumns._ID},
        MediaStore.Files.FileColumns.MEDIA_TYPE + "="+ MediaStore.Files.FileColumns.MEDIA_TYPE_VIDEO,
        null, MediaStore.Video.VideoColumns.DATE_MODIFIED);
    final Cursor cursor = cursorLoader.loadInBackground();
    if (cursor == null) {return;}
    AsyncTask.execute(new Runnable() {
        @Override
        public void run() {
            if (cursor.moveToFirst()) {
                do {Log.d(TAG,
                        new MediaVideoEntity(
	cursor.getString(cursor.getColumnIndex(MediaStore.Video.VideoColumns.DATE_ADDED)),
	cursor.getString(cursor.getColumnIndex(MediaStore.Video.VideoColumns.DATA)),
    cursor.getString(cursor.getColumnIndex(MediaStore.Video.VideoColumns.TITLE)),
	cursor.getString(cursor.getColumnIndex(MediaStore.Video.VideoColumns.DATE_TAKEN)),
	cursor.getString(cursor.getColumnIndex(MediaStore.Video.VideoColumns.DATE_MODIFIED))
                            ).toString());
                } while (cursor.moveToNext());
            cursor.close();
方式三(符合要求)
使用开源类FFmpegMediaMetadataRetriever读取METADATA_KEY_CREATION_TIME的值;
result:能得到正常的拍摄时间(第一次创建视频的时间)
build.gradle里加上:
implementation 'com.github.wseemann:FFmpegMediaMetadataRetriever:1.0.14'
private long getMetaCreationTimeFromVideo(String filePath) {
    FFmpegMediaMetadataRetriever fFmpegMediaMetadataRetriever = new FFmpegMediaMetadataRetriever();
    String creationTime = null;
    try {
        fFmpegMediaMetadataRetriever.setDataSource(filePath);
        creationTime = fFmpegMediaMetadataRetriever.extractMetadata(
        FFmpegMediaMetadataRetriever.METADATA_KEY_CREATION_TIME);
    } catch (Exception e) {
        Log.e(TAG, "FFmpegMediaMetadataRetriever.exception:" + e.toString());
    } finally {
        fFmpegMediaMetadataRetriever.release();
 

总结: MediaMetadataRetriever和FFmpegMediaMetadataRetriever的JNI层应该是不一样的

二、读取文件的第一次creationTime(需要Api26及26+)

在这里插入图片描述
需要Android系统8及以上(Api 26、26+)

 private void getCreationTimeFromImage() {
        String path = Environment.getExternalStorageDirectory().getPath() + "/tieba/熊猫头.jpg";
        BasicFileAttributes attr = null;
        try {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                attr = Files.readAttributes(new File(path).toPath(),
                        BasicFileAttributes.class);
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                Log.d(TAG, "BasicFileAttributes ->creationTime: " + attr.creationTime());
                Log.d(TAG, "BasicFileAttributes ->lastModifiedTime: " + attr.lastModifiedTime());
        } catch (IOException e) {
            Log.e(TAG, "BasicFileAttributes - failed:" + e.toString());

以上是本人的一些拙见,如大兄弟有更好的方法,希望不吝赐教,谢谢

一、Android读取视频metadata的拍摄时间方式一(不符合要求)使用MediaMetadataRetriever获取METADATA_KEY_DATE值;result: 在Android华为9.0手机获取的到值,不过对应不上视频的拍摄时间(1904 UTC),在vivo6.0手机上没获取到;查看了media_jni的一些cpp文件的代码,依然没法解决问题方式二(不符合要求)使... 内建TypeScript定义 在使用此库之前 MusicBrainz要求通过填写。通过传递appName , appVersion , appMail musicbrainz-api可以解决此问题。 提交元数据 如果您打算使用此模块提交元数据,请确保您遵守。 导入模块JavaScript示例,如何导入'musicbrainz-api: const MusicBrainzApi = require ( 'musicbrainz-api' ) . MusicBrainzApi ; const mbApi = new MusicBrainzApi ( { appName $ git clone https://github.com/autumnchris/file-metadata-api.git $ cd file-metadata-api $ npm install $ npm start 转到http://localhost:3000 。
Clouseau: Blockchain-based Data Integrity for HDFS Clusters resource:2021 IEEE 37th International Conference on Data Engineering (ICDE) 一些关键概念: 1.HDFS 2.authentication与authorization的区别,前者是身份认证,后者是授权 3.matadata,元数据,简单来说就是描述数据的数据,比如数据的属性、存储位置、摘要等等 研究背景:
获取文件 File media = new File(ConfigSingleton.getInstance().getExternalMartianVideoDir()); if (media.isDirectory()){ File[] files=media.listFiles(); for (int i=0;i<file...
//选择图片、视频、音频第三方图片选择器,glide 4.5.0将代替glide:3.7.0,需修改写法 implementation 'com.github.LuckSiege.PictureSelector:picture_library:v2.2.3' 相关代码: pr...
  在Android里获取视频的信息主要依靠MediaMetadataRetriever实现 获取最佳视频预览图 所谓的最佳就是MediaMetadataRetriever自己计算的
修改文件相关日期 ​ 下载exiftool.exe 软件,并在相应文件下编辑*.bat文件内容如下: exiftool.exe “-FileCreateDate=2022:02:10 10:55:45” “C:\Users\Administrator\Desktop\ExifTool\VID_20220210_120445.mp4” exiftool.exe “-CreateDate=2022:02:10 10:55:45” “C:\Users\Administrator\Desktop\Exi
我们讲多媒体,涉及到的最多的就是MP4文件和MP3文件了,但是我们对这两个文件的格式了解多少呢,它的由有哪些部分部分组成呢?它的核心部件是哪些?它哪些部分是供解码器去解析的呢?带着这些疑问,我们首先来探索下MP4文件。 我们首先用MP4Info这个工具来看下MP4的大貌: 从上图我们可以看到MP4文件中的所有数据都装在box中,也就是说MP4文件由若干个box组成,每个box有类型和
import android.media.MediaCodec; import android.media.MediaCodecInfo; import android.media.MediaFormat; import android.media.MediaExtractor; import android.media.MediaMetadataRetriever; import android.media.MediaPlayer; import android.net.Uri; import android.os.Bundle; import android.os.Environment; import android.os.Handler; import android.os.Looper; import android.os.Message; import android.support.v7.app.AppCompatActivity; import android.util.Log; import android.view.Surface; import android.view.SurfaceHolder; import android.view.SurfaceView; import java.io.IOException; import java.nio.ByteBuffer; public class MainActivity extends AppCompatActivity implements SurfaceHolder.Callback, Runnable { private static final String TAG = "MainActivity"; private static final String VIDEO_PATH = "rtsp://192.168.1.1:554/stream"; private static final int MSG_START_PLAY = 0; private static final int MSG_STOP_PLAY = 1; private static final int MSG_PLAY_FRAME = 2; private SurfaceView mSurfaceView; private SurfaceHolder mSurfaceHolder; private MediaPlayer mMediaPlayer; private MediaCodec mMediaCodec; private MediaExtractor mMediaExtractor; private ByteBuffer[] mInputBuffers; private ByteBuffer[] mOutputBuffers; private MediaFormat mMediaFormat; private int mVideoTrackIndex; private boolean mIsPlaying = false; private boolean mIsCodecConfigured = false; private long mStartTime; private long mDuration; private int mFrameIndex = 0; private Handler mPlayHandler = new Handler(Looper.getMainLooper()) { @Override public void handleMessage(Message msg) { switch (msg.what) { case MSG_START_PLAY: startPlay(); break; case MSG_STOP_PLAY: stopPlay(); break; case MSG_PLAY_FRAME: playFrame(); break; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mSurfaceView = findViewById(R.id.surface_view); mSurfaceHolder = mSurfaceView.getHolder(); mSurfaceHolder.addCallback(this); @Override public void surfaceCreated(SurfaceHolder surfaceHolder) { mPlayHandler.sendEmptyMessage(MSG_START_PLAY); @Override public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i1, int i2) { @Override public void surfaceDestroyed(SurfaceHolder surfaceHolder) { mPlayHandler.sendEmptyMessage(MSG_STOP_PLAY); @Override public void run() { while (mIsPlaying) { playFrame(); private void startPlay() { try { mMediaPlayer = new MediaPlayer(); mMediaPlayer.setDataSource(getApplicationContext(), Uri.parse(VIDEO_PATH)); mMediaPlayer.setSurface(mSurfaceHolder.getSurface()); mMediaPlayer.prepareAsync(); mMediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() { @Override public void onPrepared(MediaPlayer mediaPlayer) { mIsPlaying = true; mStartTime = System.currentTimeMillis(); mDuration = mediaPlayer.getDuration(); mediaPlayer.start(); new Thread(MainActivity.this).start(); } catch (IOException e) { e.printStackTrace(); private void stopPlay() { mIsPlaying = false; mMediaPlayer.release(); mMediaCodec.stop(); mMediaCodec.release(); private void playFrame() { if (mMediaExtractor == null) { mMediaExtractor = new MediaExtractor(); try { mMediaExtractor.setDataSource(VIDEO_PATH); } catch (IOException e) { e.printStackTrace(); mVideoTrackIndex = -1; for (int i = 0; i < mMediaExtractor.getTrackCount(); i++) { MediaFormat format = mMediaExtractor.getTrackFormat(i); String mime = format.getString(MediaFormat.KEY_MIME); if (mime.startsWith("video/")) { mVideoTrackIndex = i; mMediaFormat = format; break; mMediaExtractor.selectTrack(mVideoTrackIndex); try { mMediaCodec = MediaCodec.createDecoderByType(mMediaFormat.getString(MediaFormat.KEY_MIME)); mMediaCodec.configure(mMediaFormat, mSurfaceHolder.getSurface(), null, 0); mMediaCodec.start(); mInputBuffers = mMediaCodec.getInputBuffers(); mOutputBuffers = mMediaCodec.getOutputBuffers(); } catch (IOException e) { e.printStackTrace(); int inputBufferIndex = mMediaCodec.dequeueInputBuffer(10000); if (inputBufferIndex >= 0) { ByteBuffer inputBuffer = mInputBuffers[inputBufferIndex]; int sampleSize = mMediaExtractor.readSampleData(inputBuffer, 0); if (sampleSize < 0) { mMediaCodec.queueInputBuffer(inputBufferIndex, 0, 0, 0, MediaCodec.BUFFER_FLAG_END_OF_STREAM); } else { mMediaCodec.queueInputBuffer(inputBufferIndex, 0, sampleSize, mMediaExtractor.getSampleTime(), 0); mMediaExtractor.advance(); MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo(); int outputBufferIndex = mMediaCodec.dequeueOutputBuffer(bufferInfo, 10000); if (outputBufferIndex >= 0) { if (!mIsCodecConfigured) { mMediaCodec.releaseOutputBuffer(outputBufferIndex, false); mIsCodecConfigured = true; } else { while (bufferInfo.presentationTimeUs / 1000 > System.currentTimeMillis() - mStartTime) { try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); mMediaCodec.releaseOutputBuffer(outputBufferIndex, true); if (mFrameIndex == 0) { MediaMetadataRetriever retriever = new MediaMetadataRetriever(); retriever.setDataSource(VIDEO_PATH); String rotationString = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_ROTATION); int rotation = Integer.parseInt(rotationString); if (rotation == 90 || rotation == 270) { mMediaFormat.setInteger(MediaFormat.KEY_WIDTH, mMediaFormat.getInteger(MediaFormat.KEY_HEIGHT)); mMediaFormat.setInteger(MediaFormat.KEY_HEIGHT, mMediaFormat.getInteger(MediaFormat.KEY_WIDTH)); mFrameIndex++; } else if (outputBufferIndex == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) { if (!mIsCodecConfigured) { mMediaCodec.releaseOutputBuffer(outputBufferIndex, false); mIsCodecConfigured = true; } else { MediaFormat format = mMediaCodec.getOutputFormat(); if (mFrameIndex == 0) { String rotationString = format.getString(MediaFormat.KEY_ROTATION); int rotation = Integer.parseInt(rotationString); if (rotation == 90 || rotation == 270) { format.setInteger(MediaFormat.KEY_WIDTH, format.getInteger(MediaFormat.KEY_HEIGHT)); format.setInteger(MediaFormat.KEY_HEIGHT, format.getInteger(MediaFormat.KEY_WIDTH)); mMediaCodec.releaseOutputBuffer(outputBufferIndex, false); 这个代码会通过RTSP流读取视频流并且可以提前每一帧画面。如果你要使用这个代码,需要将VIDEO_PATH替换为你的RTSP流地址。