Skip to content

Commit 1f02dc9

Browse files
committed
HEVC 解码支持降级移除profile和level
1 parent f9dc7d1 commit 1f02dc9

3 files changed

Lines changed: 82 additions & 55 deletions

File tree

app/src/main/java/com/demo/mediacodec/MediaCodecUtils.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,7 @@ public static MediaFormat createOutputFormat(@NonNull Context ctx, @NonNull Uri
193193
if (config.fps > 0) {
194194
outputFormat.setInteger(MediaFormat.KEY_FRAME_RATE, config.fps);
195195
} else {
196-
outputFormat.setInteger(MediaFormat.KEY_FRAME_RATE, 25);
196+
outputFormat.setInteger(MediaFormat.KEY_FRAME_RATE, 30);
197197
}
198198
outputFormat.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 1);
199199
if (Build.VERSION.SDK_INT > 23 && isH265) {

app/src/main/java/com/demo/mediacodec/decode/DecodePlayActivity.java

Lines changed: 74 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import android.media.MediaExtractor;
66
import android.media.MediaFormat;
77
import android.net.Uri;
8+
import android.os.Build;
89
import android.os.Bundle;
910
import android.os.ParcelFileDescriptor;
1011
import android.os.SystemClock;
@@ -187,76 +188,95 @@ public void run() {
187188
}
188189
});
189190

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+
}
191211
if (TextUtils.isEmpty(codecName)) {
192212
log.append("没有找到解码器!").append("\n");
193213
setDebugLog(log.toString());
194-
} else {
195-
log.append("找到解码器:").append(codecName).append("\n");
196-
setDebugLog(log.toString());
214+
return;
215+
}
197216

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());
204219

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();
208226

209-
long startTime = System.nanoTime(); //ns
227+
ByteBuffer byteBuffer = ByteBuffer.allocate(maxCache);
228+
int sampleSize;
229+
MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
210230

211-
//不停读取轨道数据
212-
while ((sampleSize = mMediaExtractor.readSampleData(byteBuffer, 0)) > 0) {
213-
long sampleTime = mMediaExtractor.getSampleTime(); //us
231+
long startTime = System.nanoTime(); //ns
214232

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
225236

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+
}
238247

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);
245256
}
257+
//这里直接将解码后的数据刷到Surface即可
258+
decoder.releaseOutputBuffer(outIndex, true);
246259
}
247260

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;
253267
}
254-
log.append("解码完成,释放资源!").append("\n");
255-
setDebugLog(log.toString());
256-
} catch (IOException e) {
257-
e.printStackTrace();
258268
}
259269

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();
260280
}
261281
}
262282

app/src/main/java/com/demo/mediacodec/transcode/TranscodeRunner.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -381,6 +381,13 @@ private void prepareDecoder(VideoOutputConfig outputConfig, AtomicInteger hdrCou
381381
mOriVideoFormat.removeKey(MediaFormat.KEY_LEVEL);
382382
}
383383
codecName = MediaCodecUtils.findDecoderByFormat(mOriVideoFormat);
384+
} else if (MediaFormat.MIMETYPE_VIDEO_HEVC.equals(mOriVideoMime)) {
385+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
386+
//HEVC的话,尝试移除Profile和Level
387+
mOriVideoFormat.removeKey(MediaFormat.KEY_PROFILE);
388+
mOriVideoFormat.removeKey(MediaFormat.KEY_LEVEL);
389+
}
390+
codecName = MediaCodecUtils.findDecoderByFormat(mOriVideoFormat);
384391
} else {
385392
throw new RuntimeException("没有找到合适的解码器! videoFormat:" + mOriVideoFormat);
386393
}

0 commit comments

Comments
 (0)