package tv.danmaku.ijk.media.player; import android.os.Bundle; import android.text.TextUtils; import java.util.ArrayList; import java.util.Locale; @SuppressWarnings("SameParameterValue") public class IjkMediaMeta { // media meta public static final String IJKM_KEY_FORMAT = "format"; public static final String IJKM_KEY_DURATION_US = "duration_us"; public static final String IJKM_KEY_START_US = "start_us"; public static final String IJKM_KEY_BITRATE = "bitrate"; public static final String IJKM_KEY_VIDEO_STREAM = "video"; public static final String IJKM_KEY_AUDIO_STREAM = "audio"; // stream meta public static final String IJKM_KEY_TYPE = "type"; public static final String IJKM_VAL_TYPE__VIDEO = "video"; public static final String IJKM_VAL_TYPE__AUDIO = "audio"; public static final String IJKM_VAL_TYPE__UNKNOWN = "unknown"; public static final String IJKM_KEY_LANGUAGE = "language"; public static final String IJKM_KEY_CODEC_NAME = "codec_name"; public static final String IJKM_KEY_CODEC_PROFILE = "codec_profile"; public static final String IJKM_KEY_CODEC_LEVEL = "codec_level"; public static final String IJKM_KEY_CODEC_LONG_NAME = "codec_long_name"; public static final String IJKM_KEY_CODEC_PIXEL_FORMAT = "codec_pixel_format"; // stream: video public static final String IJKM_KEY_WIDTH = "width"; public static final String IJKM_KEY_HEIGHT = "height"; public static final String IJKM_KEY_FPS_NUM = "fps_num"; public static final String IJKM_KEY_FPS_DEN = "fps_den"; public static final String IJKM_KEY_TBR_NUM = "tbr_num"; public static final String IJKM_KEY_TBR_DEN = "tbr_den"; public static final String IJKM_KEY_SAR_NUM = "sar_num"; public static final String IJKM_KEY_SAR_DEN = "sar_den"; // stream: audio public static final String IJKM_KEY_SAMPLE_RATE = "sample_rate"; public static final String IJKM_KEY_CHANNEL_LAYOUT = "channel_layout"; public static final String IJKM_KEY_STREAMS = "streams"; public static final long AV_CH_FRONT_LEFT = 0x00000001; public static final long AV_CH_FRONT_RIGHT = 0x00000002; public static final long AV_CH_FRONT_CENTER = 0x00000004; public static final long AV_CH_LOW_FREQUENCY = 0x00000008; public static final long AV_CH_BACK_LEFT = 0x00000010; public static final long AV_CH_BACK_RIGHT = 0x00000020; public static final long AV_CH_FRONT_LEFT_OF_CENTER = 0x00000040; public static final long AV_CH_FRONT_RIGHT_OF_CENTER = 0x00000080; public static final long AV_CH_BACK_CENTER = 0x00000100; public static final long AV_CH_SIDE_LEFT = 0x00000200; public static final long AV_CH_SIDE_RIGHT = 0x00000400; public static final long AV_CH_TOP_CENTER = 0x00000800; public static final long AV_CH_TOP_FRONT_LEFT = 0x00001000; public static final long AV_CH_TOP_FRONT_CENTER = 0x00002000; public static final long AV_CH_TOP_FRONT_RIGHT = 0x00004000; public static final long AV_CH_TOP_BACK_LEFT = 0x00008000; public static final long AV_CH_TOP_BACK_CENTER = 0x00010000; public static final long AV_CH_TOP_BACK_RIGHT = 0x00020000; public static final long AV_CH_STEREO_LEFT = 0x20000000; public static final long AV_CH_STEREO_RIGHT = 0x40000000; public static final long AV_CH_WIDE_LEFT = 0x0000000080000000L; public static final long AV_CH_WIDE_RIGHT = 0x0000000100000000L; public static final long AV_CH_SURROUND_DIRECT_LEFT = 0x0000000200000000L; public static final long AV_CH_SURROUND_DIRECT_RIGHT = 0x0000000400000000L; public static final long AV_CH_LOW_FREQUENCY_2 = 0x0000000800000000L; public static final long AV_CH_LAYOUT_MONO = (AV_CH_FRONT_CENTER); public static final long AV_CH_LAYOUT_STEREO = (AV_CH_FRONT_LEFT | AV_CH_FRONT_RIGHT); public static final long AV_CH_LAYOUT_2POINT1 = (AV_CH_LAYOUT_STEREO | AV_CH_LOW_FREQUENCY); public static final long AV_CH_LAYOUT_2_1 = (AV_CH_LAYOUT_STEREO | AV_CH_BACK_CENTER); public static final long AV_CH_LAYOUT_SURROUND = (AV_CH_LAYOUT_STEREO | AV_CH_FRONT_CENTER); public static final long AV_CH_LAYOUT_3POINT1 = (AV_CH_LAYOUT_SURROUND | AV_CH_LOW_FREQUENCY); public static final long AV_CH_LAYOUT_4POINT0 = (AV_CH_LAYOUT_SURROUND | AV_CH_BACK_CENTER); public static final long AV_CH_LAYOUT_4POINT1 = (AV_CH_LAYOUT_4POINT0 | AV_CH_LOW_FREQUENCY); public static final long AV_CH_LAYOUT_2_2 = (AV_CH_LAYOUT_STEREO | AV_CH_SIDE_LEFT | AV_CH_SIDE_RIGHT); public static final long AV_CH_LAYOUT_QUAD = (AV_CH_LAYOUT_STEREO | AV_CH_BACK_LEFT | AV_CH_BACK_RIGHT); public static final long AV_CH_LAYOUT_5POINT0 = (AV_CH_LAYOUT_SURROUND | AV_CH_SIDE_LEFT | AV_CH_SIDE_RIGHT); public static final long AV_CH_LAYOUT_5POINT1 = (AV_CH_LAYOUT_5POINT0 | AV_CH_LOW_FREQUENCY); public static final long AV_CH_LAYOUT_5POINT0_BACK = (AV_CH_LAYOUT_SURROUND | AV_CH_BACK_LEFT | AV_CH_BACK_RIGHT); public static final long AV_CH_LAYOUT_5POINT1_BACK = (AV_CH_LAYOUT_5POINT0_BACK | AV_CH_LOW_FREQUENCY); public static final long AV_CH_LAYOUT_6POINT0 = (AV_CH_LAYOUT_5POINT0 | AV_CH_BACK_CENTER); public static final long AV_CH_LAYOUT_6POINT0_FRONT = (AV_CH_LAYOUT_2_2 | AV_CH_FRONT_LEFT_OF_CENTER | AV_CH_FRONT_RIGHT_OF_CENTER); public static final long AV_CH_LAYOUT_HEXAGONAL = (AV_CH_LAYOUT_5POINT0_BACK | AV_CH_BACK_CENTER); public static final long AV_CH_LAYOUT_6POINT1 = (AV_CH_LAYOUT_5POINT1 | AV_CH_BACK_CENTER); public static final long AV_CH_LAYOUT_6POINT1_BACK = (AV_CH_LAYOUT_5POINT1_BACK | AV_CH_BACK_CENTER); public static final long AV_CH_LAYOUT_6POINT1_FRONT = (AV_CH_LAYOUT_6POINT0_FRONT | AV_CH_LOW_FREQUENCY); public static final long AV_CH_LAYOUT_7POINT0 = (AV_CH_LAYOUT_5POINT0 | AV_CH_BACK_LEFT | AV_CH_BACK_RIGHT); public static final long AV_CH_LAYOUT_7POINT0_FRONT = (AV_CH_LAYOUT_5POINT0 | AV_CH_FRONT_LEFT_OF_CENTER | AV_CH_FRONT_RIGHT_OF_CENTER); public static final long AV_CH_LAYOUT_7POINT1 = (AV_CH_LAYOUT_5POINT1 | AV_CH_BACK_LEFT | AV_CH_BACK_RIGHT); public static final long AV_CH_LAYOUT_7POINT1_WIDE = (AV_CH_LAYOUT_5POINT1 | AV_CH_FRONT_LEFT_OF_CENTER | AV_CH_FRONT_RIGHT_OF_CENTER); public static final long AV_CH_LAYOUT_7POINT1_WIDE_BACK = (AV_CH_LAYOUT_5POINT1_BACK | AV_CH_FRONT_LEFT_OF_CENTER | AV_CH_FRONT_RIGHT_OF_CENTER); public static final long AV_CH_LAYOUT_OCTAGONAL = (AV_CH_LAYOUT_5POINT0 | AV_CH_BACK_LEFT | AV_CH_BACK_CENTER | AV_CH_BACK_RIGHT); public static final long AV_CH_LAYOUT_STEREO_DOWNMIX = (AV_CH_STEREO_LEFT | AV_CH_STEREO_RIGHT); public Bundle mMediaMeta; public String mFormat; public long mDurationUS; public long mStartUS; public long mBitrate; public final ArrayList<IjkStreamMeta> mStreams = new ArrayList<IjkStreamMeta>(); public IjkStreamMeta mVideoStream; public IjkStreamMeta mAudioStream; public String getString(String key) { return mMediaMeta.getString(key); } public int getInt(String key) { return getInt(key, 0); } public int getInt(String key, int defaultValue) { String value = getString(key); if (TextUtils.isEmpty(value)) return defaultValue; try { return Integer.parseInt(value); } catch (NumberFormatException e) { return defaultValue; } } public long getLong(String key) { return getLong(key, 0); } public long getLong(String key, long defaultValue) { String value = getString(key); if (TextUtils.isEmpty(value)) return defaultValue; try { return Long.parseLong(value); } catch (NumberFormatException e) { return defaultValue; } } public ArrayList<Bundle> getParcelableArrayList(String key) { return mMediaMeta.getParcelableArrayList(key); } public String getDurationInline() { long duration = mDurationUS + 5000; long secs = duration / 1000000; long mins = secs / 60; secs %= 60; long hours = mins / 60; mins %= 60; return String.format(Locale.US, "%02d:%02d:%02d", hours, mins, secs); } public static IjkMediaMeta parse(Bundle mediaMeta) { if (mediaMeta == null) return null; IjkMediaMeta meta = new IjkMediaMeta(); meta.mMediaMeta = mediaMeta; meta.mFormat = meta.getString(IJKM_KEY_FORMAT); meta.mDurationUS = meta.getLong(IJKM_KEY_DURATION_US); meta.mStartUS = meta.getLong(IJKM_KEY_START_US); meta.mBitrate = meta.getLong(IJKM_KEY_BITRATE); int videoStreamIndex = meta.getInt(IJKM_KEY_VIDEO_STREAM, -1); int audioStreamIndex = meta.getInt(IJKM_KEY_AUDIO_STREAM, -1); ArrayList<Bundle> streams = meta .getParcelableArrayList(IJKM_KEY_STREAMS); if (streams == null) return meta; int index = -1; for (Bundle streamBundle : streams) { index++; if (streamBundle == null) { continue; } IjkStreamMeta streamMeta = new IjkStreamMeta(index); streamMeta.mMeta = streamBundle; streamMeta.mType = streamMeta.getString(IJKM_KEY_TYPE); streamMeta.mLanguage = streamMeta.getString(IJKM_KEY_LANGUAGE); if (TextUtils.isEmpty(streamMeta.mType)) continue; streamMeta.mCodecName = streamMeta.getString(IJKM_KEY_CODEC_NAME); streamMeta.mCodecProfile = streamMeta .getString(IJKM_KEY_CODEC_PROFILE); streamMeta.mCodecLongName = streamMeta .getString(IJKM_KEY_CODEC_LONG_NAME); streamMeta.mBitrate = streamMeta.getInt(IJKM_KEY_BITRATE); if (streamMeta.mType.equalsIgnoreCase(IJKM_VAL_TYPE__VIDEO)) { streamMeta.mWidth = streamMeta.getInt(IJKM_KEY_WIDTH); streamMeta.mHeight = streamMeta.getInt(IJKM_KEY_HEIGHT); streamMeta.mFpsNum = streamMeta.getInt(IJKM_KEY_FPS_NUM); streamMeta.mFpsDen = streamMeta.getInt(IJKM_KEY_FPS_DEN); streamMeta.mTbrNum = streamMeta.getInt(IJKM_KEY_TBR_NUM); streamMeta.mTbrDen = streamMeta.getInt(IJKM_KEY_TBR_DEN); streamMeta.mSarNum = streamMeta.getInt(IJKM_KEY_SAR_NUM); streamMeta.mSarDen = streamMeta.getInt(IJKM_KEY_SAR_DEN); if (videoStreamIndex == index) { meta.mVideoStream = streamMeta; } } else if (streamMeta.mType.equalsIgnoreCase(IJKM_VAL_TYPE__AUDIO)) { streamMeta.mSampleRate = streamMeta .getInt(IJKM_KEY_SAMPLE_RATE); streamMeta.mChannelLayout = streamMeta .getLong(IJKM_KEY_CHANNEL_LAYOUT); if (audioStreamIndex == index) { meta.mAudioStream = streamMeta; } } meta.mStreams.add(streamMeta); } return meta; } public static class IjkStreamMeta { public Bundle mMeta; public final int mIndex; public String mType; public String mLanguage; // common public String mCodecName; public String mCodecProfile; public String mCodecLongName; public long mBitrate; // video public int mWidth; public int mHeight; public int mFpsNum; public int mFpsDen; public int mTbrNum; public int mTbrDen; public int mSarNum; public int mSarDen; // audio public int mSampleRate; public long mChannelLayout; public IjkStreamMeta(int index) { mIndex = index; } public String getString(String key) { return mMeta.getString(key); } public int getInt(String key) { return getInt(key, 0); } public int getInt(String key, int defaultValue) { String value = getString(key); if (TextUtils.isEmpty(value)) return defaultValue; try { return Integer.parseInt(value); } catch (NumberFormatException e) { return defaultValue; } } public long getLong(String key) { return getLong(key, 0); } public long getLong(String key, long defaultValue) { String value = getString(key); if (TextUtils.isEmpty(value)) return defaultValue; try { return Long.parseLong(value); } catch (NumberFormatException e) { return defaultValue; } } public String getCodecLongNameInline() { if (!TextUtils.isEmpty(mCodecLongName)) { return mCodecLongName; } else if (!TextUtils.isEmpty(mCodecName)) { return mCodecName; } else { return "N/A"; } } public String getCodecShortNameInline() { if (!TextUtils.isEmpty(mCodecName)) { return mCodecName; } else { return "N/A"; } } public String getResolutionInline() { if (mWidth <= 0 || mHeight <= 0) { return "N/A"; } else if (mSarNum <= 0 || mSarDen <= 0) { return String.format(Locale.US, "%d x %d", mWidth, mHeight); } else { return String.format(Locale.US, "%d x %d [SAR %d:%d]", mWidth, mHeight, mSarNum, mSarDen); } } public String getFpsInline() { if (mFpsNum <= 0 || mFpsDen <= 0) { return "N/A"; } else { return String.valueOf(((float) (mFpsNum)) / mFpsDen); } } public String getBitrateInline() { if (mBitrate <= 0) { return "N/A"; } else if (mBitrate < 1000) { return String.format(Locale.US, "%d bit/s", mBitrate); } else { return String.format(Locale.US, "%d kb/s", mBitrate / 1000); } } public String getSampleRateInline() { if (mSampleRate <= 0) { return "N/A"; } else { return String.format(Locale.US, "%d Hz", mSampleRate); } } public String getChannelLayoutInline() { if (mChannelLayout <= 0) { return "N/A"; } else { if (mChannelLayout == AV_CH_LAYOUT_MONO) { return "mono"; } else if (mChannelLayout == AV_CH_LAYOUT_STEREO) { return "stereo"; } else { return String.format(Locale.US, "%x", mChannelLayout); } } } } }