Androidで外部メディアファイルのメタ情報を取得する


Androidでメディアファイルのメタ情報を取得するには、android.media.MediaMetadataRetrieverクラスを使います。

本ブログでは、Musicフォルダ（Environment.DIRECTORY_MUSIC）の中にある音楽ファイルのメタ情報を取得する場合について説明します。

## サンプルプログラム

まず、外部メディアファイルのメタ情報を取得するサンプルプログラムを載せておきます。

```java:MainActivity.java
private void getMediaMetadataInfo() {
	List<String> arMediaPath = new ArrayList<String>();

	// 外部メディアのパスを取得
	// getExternalStoragePublicDirectory deprecated in Android Q
	File fileDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MUSIC);

	String strPath = fileDir.getPath();
	File[] filePaths = new File(strPath).listFiles();
	if (filePaths != null) {
		for (File file : filePaths) {
			if (file.isFile()) {
				// ファイルパスを保存
				arMediaPath.add(strPath + "/" + file.getName());
			}
		}
	}

	// メタ情報を取得するためのクラス
	MediaMetadataRetriever mmr = new MediaMetadataRetriever();

	for (int i = 0; i < arMediaPath.size(); i++) {
		Log.v(TAG, "ファイルパス:" + arMediaPath.get(i));
		// ファイルパスをセット
		mmr.setDataSource(arMediaPath.get(i));

		// メタ情報を取得
		Log.v(TAG, "アルバム名:" + mmr.extractMetadata(MediaMetadataRetriever.METADATA_KEY_ALBUM));
		Log.v(TAG, "アーティスト名:" + mmr.extractMetadata(MediaMetadataRetriever.METADATA_KEY_ARTIST));
		Log.v(TAG, "ビットレート(bits/sec):" + mmr.extractMetadata(MediaMetadataRetriever.METADATA_KEY_BITRATE));
		Log.v(TAG, "作曲者:" + mmr.extractMetadata(MediaMetadataRetriever.METADATA_KEY_COMPOSER));
		Log.v(TAG, "再生時間(ms):" + mmr.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION));
		Log.v(TAG, "ジャンル:" + mmr.extractMetadata(MediaMetadataRetriever.METADATA_KEY_GENRE));
		Log.v(TAG, "MIMEタイプ:" + mmr.extractMetadata(MediaMetadataRetriever.METADATA_KEY_MIMETYPE));
		Log.v(TAG, "タイトル:" + mmr.extractMetadata(MediaMetadataRetriever.METADATA_KEY_TITLE));
		Log.v(TAG, "作成された年:" + mmr.extractMetadata(MediaMetadataRetriever.METADATA_KEY_YEAR));

		// アートワーク
		byte[] data = mmr.getEmbeddedPicture();
		if (data != null) {
			// ImageViewでアートワークを表示
//			ImageView imageView = findViewById(R.id.imageView);
//			imageView.setImageBitmap(BitmapFactory.decodeByteArray(data, 0, data.length));
		}
	}
}
```

### 解説

最初に、外部メディアのパスを取得します。

```java
	// getExternalStoragePublicDirectory deprecated in Android Q
	File fileDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MUSIC);
```

**【注意】 getExternalStoragePublicDirectory()は、Android Qでdeprecatedとなっています。**

指定したフォルダ（Environment.DIRECTORY_MUSIC）に含まれるファイルのリストを取得します。

```java
	String strPath = fileDir.getPath();
	File[] filePaths = new File(strPath).listFiles();
```

サンプルプログラムでは、ListViewで表示することを想定して、List<String>の配列arMediaPathにファイルパスの文字列を保存しています。

次に、メタ情報を取得するためのクラスMediaMetadataRetrieverを定義します。

```java
    MediaMetadataRetriever mmr = new MediaMetadataRetriever();
```

先ほどのファイルパスをセットします。

```java
        mmr.setDataSource(arMediaPath.get(i));
```

これで、各ファイルのメタ情報を取得することができます。詳細は、上のサンプルプログラムを参照してください。

### 再生

外部メディアファイルを再生するには、MediaPlayerを使用します。

```java
	private MediaPlayer mMediaPlayer = null;

	private void play(int iIndex) {
		try {
			mMediaPlayer = new MediaPlayer();
			// 音楽ファイルをMediaPlayerに設定
			mMediaPlayer.setDataSource(arMediaPath.get(iIndex));
			// 再生準備、再生可能状態になるまでブロック
			mMediaPlayer.prepare();
			// 再生
			mMediaPlayer.start();

		} catch (IOException e) {
			e.printStackTrace();
		}
	}
```

## パーミッション

Android OS 6.0以降の場合は、READ_EXTERNAL_STORAGEパーミッション経由で呼び出してください。

```xml:AndroidManifest.xml
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
```

```java:MainActivity.java
private static final int MY_PERMISSIONS_REQUEST_READ_EXTERNAL_STORAGE = 100;

private void checkPermission() {
	if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
		if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) {
			// Build.VERSION_CODES.M 以降でパーミッション許可済
			// put your code for Version>=Marshmallow
			getMediaMetadataInfo();

		} else {
			// 許可されていない時の処理
			if (shouldShowRequestPermissionRationale(Manifest.permission.READ_EXTERNAL_STORAGE)) {
				// ユーザーがPermissionを明示的に拒否された時 Permissionが必要な理由を表示して再度許可を求めたり、機能を無効にしたりする
				Toast.makeText(this, "App required access to external storage", Toast.LENGTH_SHORT).show();
			} else {
				// まだ許可を求める前の時、許可を求めるダイアログを表示

			}
			requestPermissions(new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, MY_PERMISSIONS_REQUEST_READ_EXTERNAL_STORAGE);
		}

	} else {
		// put your code for Version < Marshmallow
		getMediaMetadataInfo();
	}

}

@Override
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
	switch (requestCode) {
		case MY_PERMISSIONS_REQUEST_READ_EXTERNAL_STORAGE: {
			// If request is cancelled, the result arrays are empty.
			if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
				// 許可された場合の処理

				// permission was granted, yay! Do the
				// contacts-related task you need to do.

				getMediaMetadataInfo();

			} else {
				// 拒否された場合の処理

				// permission denied, boo! Disable the
				// functionality that depends on this permission.
			}
			return;
		}

		// other 'case' lines to check for other
		// permissions this app might request
	}
}
```