001/* 002 * Copyright (C) 2015 Zhang Rui <bbcallen@gmail.com> 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package com.baidu.cloud.media.player.misc; 018 019import android.annotation.TargetApi; 020import android.os.Build; 021import android.text.TextUtils; 022 023import java.util.HashMap; 024import java.util.Locale; 025import java.util.Map; 026 027import com.baidu.cloud.media.player.BDCloudMediaMeta; 028 029public class BDCloudMediaFormat implements IMediaFormat { 030 // Common 031 public static final String KEY_IJK_CODEC_LONG_NAME_UI = "ijk-codec-long-name-ui"; 032 public static final String KEY_IJK_CODEC_NAME_UI = "ijk-codec-name-ui"; 033 public static final String KEY_IJK_BIT_RATE_UI = "ijk-bit-rate-ui"; 034 035 // Video 036 public static final String KEY_IJK_CODEC_PROFILE_LEVEL_UI = "ijk-profile-level-ui"; 037 public static final String KEY_IJK_CODEC_PIXEL_FORMAT_UI = "ijk-pixel-format-ui"; 038 public static final String KEY_IJK_RESOLUTION_UI = "ijk-resolution-ui"; 039 public static final String KEY_IJK_FRAME_RATE_UI = "ijk-frame-rate-ui"; 040 041 // Audio 042 public static final String KEY_IJK_SAMPLE_RATE_UI = "ijk-sample-rate-ui"; 043 public static final String KEY_IJK_CHANNEL_UI = "ijk-channel-ui"; 044 045 // Codec 046 public static final String CODEC_NAME_H264 = "h264"; 047 048 public final BDCloudMediaMeta.BDCloudStreamMeta mMediaFormat; 049 050 public BDCloudMediaFormat(BDCloudMediaMeta.BDCloudStreamMeta streamMeta) { 051 mMediaFormat = streamMeta; 052 } 053 054 @TargetApi(Build.VERSION_CODES.JELLY_BEAN) 055 @Override 056 public int getInteger(String name) { 057 if (mMediaFormat == null) { 058 return 0; 059 } 060 061 return mMediaFormat.getInt(name); 062 } 063 064 @Override 065 public String getString(String name) { 066 if (mMediaFormat == null) { 067 return null; 068 } 069 070 if (sFormatterMap.containsKey(name)) { 071 Formatter formatter = sFormatterMap.get(name); 072 return formatter.format(this); 073 } 074 075 return mMediaFormat.getString(name); 076 } 077 078 // ------------------------- 079 // Formatter 080 // ------------------------- 081 082 private abstract static class Formatter { 083 public String format(BDCloudMediaFormat mediaFormat) { 084 String value = doFormat(mediaFormat); 085 if (TextUtils.isEmpty(value)) { 086 return getDefaultString(); 087 } 088 return value; 089 } 090 091 protected abstract String doFormat(BDCloudMediaFormat mediaFormat); 092 093 @SuppressWarnings("SameReturnValue") 094 protected String getDefaultString() { 095 return "N/A"; 096 } 097 } 098 099 private static final Map<String, Formatter> sFormatterMap = new HashMap<String, Formatter>(); 100 101 { 102 sFormatterMap.put(KEY_IJK_CODEC_LONG_NAME_UI, new Formatter() { 103 @Override 104 public String doFormat(BDCloudMediaFormat mediaFormat) { 105 return mMediaFormat.getString(BDCloudMediaMeta.IJKM_KEY_CODEC_LONG_NAME); 106 } 107 }); 108 sFormatterMap.put(KEY_IJK_CODEC_NAME_UI, new Formatter() { 109 @Override 110 public String doFormat(BDCloudMediaFormat mediaFormat) { 111 return mMediaFormat.getString(BDCloudMediaMeta.IJKM_KEY_CODEC_NAME); 112 } 113 }); 114 sFormatterMap.put(KEY_IJK_BIT_RATE_UI, new Formatter() { 115 @Override 116 protected String doFormat(BDCloudMediaFormat mediaFormat) { 117 int bitRate = mediaFormat.getInteger(BDCloudMediaMeta.IJKM_KEY_BITRATE); 118 if (bitRate <= 0) { 119 return null; 120 } else if (bitRate < 1000) { 121 return String.format(Locale.US, "%d bit/s", bitRate); 122 } else { 123 return String.format(Locale.US, "%d kb/s", bitRate / 1000); 124 } 125 } 126 }); 127 sFormatterMap.put(KEY_IJK_CODEC_PROFILE_LEVEL_UI, new Formatter() { 128 @Override 129 protected String doFormat(BDCloudMediaFormat mediaFormat) { 130 int profileIndex = mediaFormat.getInteger(BDCloudMediaMeta.IJKM_KEY_CODEC_PROFILE_ID); 131 String profile; 132 switch (profileIndex) { 133 case BDCloudMediaMeta.FF_PROFILE_H264_BASELINE: 134 profile = "Baseline"; 135 break; 136 case BDCloudMediaMeta.FF_PROFILE_H264_CONSTRAINED_BASELINE: 137 profile = "Constrained Baseline"; 138 break; 139 case BDCloudMediaMeta.FF_PROFILE_H264_MAIN: 140 profile = "Main"; 141 break; 142 case BDCloudMediaMeta.FF_PROFILE_H264_EXTENDED: 143 profile = "Extended"; 144 break; 145 case BDCloudMediaMeta.FF_PROFILE_H264_HIGH: 146 profile = "High"; 147 break; 148 case BDCloudMediaMeta.FF_PROFILE_H264_HIGH_10: 149 profile = "High 10"; 150 break; 151 case BDCloudMediaMeta.FF_PROFILE_H264_HIGH_10_INTRA: 152 profile = "High 10 Intra"; 153 break; 154 case BDCloudMediaMeta.FF_PROFILE_H264_HIGH_422: 155 profile = "High 4:2:2"; 156 break; 157 case BDCloudMediaMeta.FF_PROFILE_H264_HIGH_422_INTRA: 158 profile = "High 4:2:2 Intra"; 159 break; 160 case BDCloudMediaMeta.FF_PROFILE_H264_HIGH_444: 161 profile = "High 4:4:4"; 162 break; 163 case BDCloudMediaMeta.FF_PROFILE_H264_HIGH_444_PREDICTIVE: 164 profile = "High 4:4:4 Predictive"; 165 break; 166 case BDCloudMediaMeta.FF_PROFILE_H264_HIGH_444_INTRA: 167 profile = "High 4:4:4 Intra"; 168 break; 169 case BDCloudMediaMeta.FF_PROFILE_H264_CAVLC_444: 170 profile = "CAVLC 4:4:4"; 171 break; 172 default: 173 return null; 174 } 175 176 StringBuilder sb = new StringBuilder(); 177 sb.append(profile); 178 179 String codecName = mediaFormat.getString(BDCloudMediaMeta.IJKM_KEY_CODEC_NAME); 180 if (!TextUtils.isEmpty(codecName) && codecName.equalsIgnoreCase(CODEC_NAME_H264)) { 181 int level = mediaFormat.getInteger(BDCloudMediaMeta.IJKM_KEY_CODEC_LEVEL); 182 if (level < 10) { 183 return sb.toString(); 184 } 185 186 sb.append(" Profile Level "); 187 sb.append((level / 10) % 10); 188 if ((level % 10) != 0) { 189 sb.append("."); 190 sb.append(level % 10); 191 } 192 } 193 194 return sb.toString(); 195 } 196 }); 197 sFormatterMap.put(KEY_IJK_CODEC_PIXEL_FORMAT_UI, new Formatter() { 198 @Override 199 protected String doFormat(BDCloudMediaFormat mediaFormat) { 200 return mediaFormat.getString(BDCloudMediaMeta.IJKM_KEY_CODEC_PIXEL_FORMAT); 201 } 202 }); 203 sFormatterMap.put(KEY_IJK_RESOLUTION_UI, new Formatter() { 204 @Override 205 protected String doFormat(BDCloudMediaFormat mediaFormat) { 206 int width = mediaFormat.getInteger(KEY_WIDTH); 207 int height = mediaFormat.getInteger(KEY_HEIGHT); 208 int sarNum = mediaFormat.getInteger(BDCloudMediaMeta.IJKM_KEY_SAR_NUM); 209 int sarDen = mediaFormat.getInteger(BDCloudMediaMeta.IJKM_KEY_SAR_DEN); 210 211 if (width <= 0 || height <= 0) { 212 return null; 213 } else if (sarNum <= 0 || sarDen <= 0) { 214 return String.format(Locale.US, "%d x %d", width, height); 215 } else { 216 return String.format(Locale.US, "%d x %d [SAR %d:%d]", width, height, sarNum, sarDen); 217 } 218 } 219 }); 220 sFormatterMap.put(KEY_IJK_FRAME_RATE_UI, new Formatter() { 221 @Override 222 protected String doFormat(BDCloudMediaFormat mediaFormat) { 223 int fpsNum = mediaFormat.getInteger(BDCloudMediaMeta.IJKM_KEY_FPS_NUM); 224 int fpsDen = mediaFormat.getInteger(BDCloudMediaMeta.IJKM_KEY_FPS_DEN); 225 if (fpsNum <= 0 || fpsDen <= 0) { 226 return null; 227 } else { 228 return String.valueOf(((float) (fpsNum)) / fpsDen); 229 } 230 } 231 }); 232 sFormatterMap.put(KEY_IJK_SAMPLE_RATE_UI, new Formatter() { 233 @Override 234 protected String doFormat(BDCloudMediaFormat mediaFormat) { 235 int sampleRate = mediaFormat.getInteger(BDCloudMediaMeta.IJKM_KEY_SAMPLE_RATE); 236 if (sampleRate <= 0) { 237 return null; 238 } else { 239 return String.format(Locale.US, "%d Hz", sampleRate); 240 } 241 } 242 }); 243 sFormatterMap.put(KEY_IJK_CHANNEL_UI, new Formatter() { 244 @Override 245 protected String doFormat(BDCloudMediaFormat mediaFormat) { 246 int channelLayout = mediaFormat.getInteger(BDCloudMediaMeta.IJKM_KEY_CHANNEL_LAYOUT); 247 if (channelLayout <= 0) { 248 return null; 249 } else { 250 if (channelLayout == BDCloudMediaMeta.AV_CH_LAYOUT_MONO) { 251 return "mono"; 252 } else if (channelLayout == BDCloudMediaMeta.AV_CH_LAYOUT_STEREO) { 253 return "stereo"; 254 } else { 255 return String.format(Locale.US, "%x", channelLayout); 256 } 257 } 258 } 259 }); 260 } 261}