|
5 | 5 | import android.media.MediaExtractor; |
6 | 6 | import android.media.MediaFormat; |
7 | 7 | import android.net.Uri; |
| 8 | +import android.os.Build; |
8 | 9 | import android.os.Bundle; |
9 | 10 | import android.os.ParcelFileDescriptor; |
10 | 11 | import android.os.SystemClock; |
@@ -187,76 +188,95 @@ public void run() { |
187 | 188 | } |
188 | 189 | }); |
189 | 190 |
|
190 | | - String codecName = MediaCodecUtils.findDecoderByFormat(mVideoFormat, false); |
| 191 | + String codecName = MediaCodecUtils.findDecoderByFormat(mVideoFormat); |
| 192 | + if (TextUtils.isEmpty(codecName)) { |
| 193 | + if (MediaFormat.MIMETYPE_VIDEO_DOLBY_VISION.equals(mime)) { |
| 194 | + //如果是杜比视界,那么尝试用HEVC的解码器去解 |
| 195 | + mVideoFormat.setString(MediaFormat.KEY_MIME, MediaFormat.MIMETYPE_VIDEO_HEVC); |
| 196 | + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { |
| 197 | + //因为杜比视界的profile和level是单独的,这里降级到HEVC的话,Profile和Level也要移除,否则还是会找不到解码器 |
| 198 | + mVideoFormat.removeKey(MediaFormat.KEY_PROFILE); |
| 199 | + mVideoFormat.removeKey(MediaFormat.KEY_LEVEL); |
| 200 | + } |
| 201 | + codecName = MediaCodecUtils.findDecoderByFormat(mVideoFormat); |
| 202 | + } else if (MediaFormat.MIMETYPE_VIDEO_HEVC.equals(mime)) { |
| 203 | + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { |
| 204 | + //HEVC的话,尝试移除Profile和Level |
| 205 | + mVideoFormat.removeKey(MediaFormat.KEY_PROFILE); |
| 206 | + mVideoFormat.removeKey(MediaFormat.KEY_LEVEL); |
| 207 | + } |
| 208 | + codecName = MediaCodecUtils.findDecoderByFormat(mVideoFormat); |
| 209 | + } |
| 210 | + } |
191 | 211 | if (TextUtils.isEmpty(codecName)) { |
192 | 212 | log.append("没有找到解码器!").append("\n"); |
193 | 213 | setDebugLog(log.toString()); |
194 | | - } else { |
195 | | - log.append("找到解码器:").append(codecName).append("\n"); |
196 | | - setDebugLog(log.toString()); |
| 214 | + return; |
| 215 | + } |
197 | 216 |
|
198 | | - try { |
199 | | - //以同步模式进行解码 |
200 | | - MediaCodec decoder = MediaCodec.createByCodecName(codecName); |
201 | | - mMediaCodec = decoder; |
202 | | - decoder.configure(mVideoFormat, mSurfaceView.getHolder().getSurface(), null, 0); |
203 | | - decoder.start(); |
| 217 | + log.append("找到解码器:").append(codecName).append("\n"); |
| 218 | + setDebugLog(log.toString()); |
204 | 219 |
|
205 | | - ByteBuffer byteBuffer = ByteBuffer.allocate(maxCache); |
206 | | - int sampleSize; |
207 | | - MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo(); |
| 220 | + try { |
| 221 | + //以同步模式进行解码 |
| 222 | + MediaCodec decoder = MediaCodec.createByCodecName(codecName); |
| 223 | + mMediaCodec = decoder; |
| 224 | + decoder.configure(mVideoFormat, mSurfaceView.getHolder().getSurface(), null, 0); |
| 225 | + decoder.start(); |
208 | 226 |
|
209 | | - long startTime = System.nanoTime(); //ns |
| 227 | + ByteBuffer byteBuffer = ByteBuffer.allocate(maxCache); |
| 228 | + int sampleSize; |
| 229 | + MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo(); |
210 | 230 |
|
211 | | - //不停读取轨道数据 |
212 | | - while ((sampleSize = mMediaExtractor.readSampleData(byteBuffer, 0)) > 0) { |
213 | | - long sampleTime = mMediaExtractor.getSampleTime(); //us |
| 231 | + long startTime = System.nanoTime(); //ns |
214 | 232 |
|
215 | | - //从decoder中取出输入缓冲队列 |
216 | | - int index = decoder.dequeueInputBuffer(10 * 1000L); |
217 | | - if (index > -1) { |
218 | | - ByteBuffer inputBuffer = decoder.getInputBuffer(index); |
219 | | - //将从轨道读取的数据,填充进输入缓冲中 |
220 | | - inputBuffer.clear(); |
221 | | - inputBuffer.put(byteBuffer); |
222 | | - //将输入缓冲还给解码器 |
223 | | - decoder.queueInputBuffer(index, 0, sampleSize, sampleTime, 0); |
224 | | - } |
| 233 | + //不停读取轨道数据 |
| 234 | + while ((sampleSize = mMediaExtractor.readSampleData(byteBuffer, 0)) > 0) { |
| 235 | + long sampleTime = mMediaExtractor.getSampleTime(); //us |
225 | 236 |
|
226 | | - //从解码器中处理解码后的数据 |
227 | | - int outIndex = decoder.dequeueOutputBuffer(bufferInfo, 10 * 1000L); |
228 | | - if (outIndex == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) { |
229 | | - //do nothing |
230 | | - } else if (outIndex > -1) { |
231 | | - //检查是否到了渲染时间,没到的话sleep到渲染时间 |
232 | | - if (System.nanoTime() - startTime < bufferInfo.presentationTimeUs * 1000L) { |
233 | | - SystemClock.sleep((bufferInfo.presentationTimeUs - (System.nanoTime() - startTime) / 1000) / 1000); |
234 | | - } |
235 | | - //这里直接将解码后的数据刷到Surface即可 |
236 | | - decoder.releaseOutputBuffer(outIndex, true); |
237 | | - } |
| 237 | + //从decoder中取出输入缓冲队列 |
| 238 | + int index = decoder.dequeueInputBuffer(10 * 1000L); |
| 239 | + if (index > -1) { |
| 240 | + ByteBuffer inputBuffer = decoder.getInputBuffer(index); |
| 241 | + //将从轨道读取的数据,填充进输入缓冲中 |
| 242 | + inputBuffer.clear(); |
| 243 | + inputBuffer.put(byteBuffer); |
| 244 | + //将输入缓冲还给解码器 |
| 245 | + decoder.queueInputBuffer(index, 0, sampleSize, sampleTime, 0); |
| 246 | + } |
238 | 247 |
|
239 | | - //获取接下来的轨道数据 |
240 | | - boolean hasNext = mMediaExtractor.advance(); |
241 | | - if (hasNext) { |
242 | | - byteBuffer.clear(); |
243 | | - } else { |
244 | | - break; |
| 248 | + //从解码器中处理解码后的数据 |
| 249 | + int outIndex = decoder.dequeueOutputBuffer(bufferInfo, 10 * 1000L); |
| 250 | + if (outIndex == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) { |
| 251 | + //do nothing |
| 252 | + } else if (outIndex > -1) { |
| 253 | + //检查是否到了渲染时间,没到的话sleep到渲染时间 |
| 254 | + if (System.nanoTime() - startTime < bufferInfo.presentationTimeUs * 1000L) { |
| 255 | + SystemClock.sleep((bufferInfo.presentationTimeUs - (System.nanoTime() - startTime) / 1000) / 1000); |
245 | 256 | } |
| 257 | + //这里直接将解码后的数据刷到Surface即可 |
| 258 | + decoder.releaseOutputBuffer(outIndex, true); |
246 | 259 | } |
247 | 260 |
|
248 | | - if (mMediaCodec != null) { |
249 | | - mMediaCodec.release(); |
250 | | - } |
251 | | - if (mMediaExtractor != null) { |
252 | | - mMediaExtractor.release(); |
| 261 | + //获取接下来的轨道数据 |
| 262 | + boolean hasNext = mMediaExtractor.advance(); |
| 263 | + if (hasNext) { |
| 264 | + byteBuffer.clear(); |
| 265 | + } else { |
| 266 | + break; |
253 | 267 | } |
254 | | - log.append("解码完成,释放资源!").append("\n"); |
255 | | - setDebugLog(log.toString()); |
256 | | - } catch (IOException e) { |
257 | | - e.printStackTrace(); |
258 | 268 | } |
259 | 269 |
|
| 270 | + if (mMediaCodec != null) { |
| 271 | + mMediaCodec.release(); |
| 272 | + } |
| 273 | + if (mMediaExtractor != null) { |
| 274 | + mMediaExtractor.release(); |
| 275 | + } |
| 276 | + log.append("解码完成,释放资源!").append("\n"); |
| 277 | + setDebugLog(log.toString()); |
| 278 | + } catch (IOException e) { |
| 279 | + e.printStackTrace(); |
260 | 280 | } |
261 | 281 | } |
262 | 282 |
|
|
0 commit comments