1、步骤
1.1、初始化MediaCodec
解码器类型(mime),视频宽度(width),视频高度(height),最大数据输入大小(max_input_size),csd-0,csd-1。
mediaFormat = MediaFormat.createVideoFormat(mime, width, height);
mediaFormat.setInteger(MediaFormat.KEY_WIDTH, width);
mediaFormat.setInteger(MediaFormat.KEY_HEIGHT, height);
mediaFormat.setLong(MediaFormat.KEY_MAX_INPUT_SIZE, width * height);
mediaFormat.setByteBuffer(“csd-0”, ByteBuffer.wrap(csd0)); //avCodecContext->extradata
mediaFormat.setByteBuffer("csd-1", ByteBuffer.wrap(csd1)); //avCodecContext->extradata
对于H.264来说,"csd-0"和"csd-1"分别对应sps和pps;对于AAC来说,"csd-0"对应ADTS。

1.2、MediaCodec开始解码
int inputBufferIndex = mediaCodec.dequeueInputBuffer(10);
if(inputBufferIndex >= 0)
{
ByteBuffer byteBuffer = mediaCodec.getInputBuffers()[inputBufferIndex];
byteBuffer.clear();
byteBuffer.put(bytes);
mediaCodec.queueInputBuffer(inputBufferIndex, 0, size, pts, 0);
}
int index = mediaCodec.dequeueOutputBuffer(info, 10);
while (index >= 0) {
mediaCodec.releaseOutputBuffer(index, true);
index = mediaCodec.dequeueOutputBuffer(info, 10);
}
size:avPacket->size, bytes :avPacket->data
2、实现
2.1、初始化MediaCodec
Java层:
/**
* 初始化MediaCodec
* @param codecName 解码器名称:h264、h265...
* @param width
* @param height
* @param csd_0
* @param csd_1
*/
public void onCallInitMediaCodec(String codecName,int width,int height,byte[] csd_0,byte[] csd_1){
try {
String mime = JfVideoSupUtil.findVideoCodecName(codecName);
mediaFormat = MediaFormat.createVideoFormat(mime,width,height);
mediaFormat.setInteger(MediaFormat.KEY_MAX_INPUT_SIZE,width * height);
mediaFormat.setByteBuffer("csd-0",ByteBuffer.wrap(csd_0));
mediaFormat.setByteBuffer("csd-1",ByteBuffer.wrap(csd_1));
JfLog.d("mediaFormat.toString() === " + mediaFormat.toString());
mediaCodec = MediaCodec.createDecoderByType(mime);
//mediaCodec.configure(mediaFormat,null,null,0);
} catch (IOException e) {
e.printStackTrace();
}
}
C++层调用:
end:
if (supMediaCodec){
video->codectype = CODEC_MEDIACODEC;
video->callJava->onCallInitMediaCodec(
codecName,
video->pVCodecCtx->width,
video->pVCodecCtx->height,
video->pVCodecCtx->extradata_size,
video->pVCodecCtx->extradata_size,
video->pVCodecCtx->extradata,
video->pVCodecCtx->extradata
);
}
2.2、MediaCodec开始解码
Java层:
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public void onCallDecodeAVPacket(int datasize, byte[] data){
if (surface != null && datasize > 0 && data != null) {
int inputBufferIndex = mediaCodec.dequeueInputBuffer(10);
if (inputBufferIndex >= 0) {//进队
//可能有好几个队列,按照索引,把队列中的bytebuffer拿出来
ByteBuffer byteBuffer = mediaCodec.getOutputBuffer(inputBufferIndex);
byteBuffer.clear();
byteBuffer.put(data);
mediaCodec.queueInputBuffer(inputBufferIndex,0,datasize,0,0);
}
int outputBufferIndex = mediaCodec.dequeueOutputBuffer(info,10);
while (outputBufferIndex >= 0) {
mediaCodec.releaseOutputBuffer(outputBufferIndex,true);
outputBufferIndex = mediaCodec.dequeueOutputBuffer(info,10);
}
}
}
C++层调用:
if (video->codectype == CODEC_MEDIACODEC){
LOGD("硬解码视频");
//送入AVPacket过滤
if (av_bsf_send_packet(video->abs_ctx,avPacket) != 0) {
av_packet_free(&avPacket);//AVPacket中的第一个参数,就是引用,减到0才真正释放
av_free(avPacket);
avPacket = NULL;
continue;
}
//接收过滤后的AVPacket
while (av_bsf_receive_packet(video->abs_ctx,avPacket) == 0){
LOGD("开始解码");
double diff = video->getFrameDiffTime(NULL,avPacket);
LOGD("DIFF IS %f",diff);
av_usleep(video->getDelayTime(diff) * 1000000);
video->callJava->onCallDecodeAVPacket(avPacket->size,avPacket->data);
av_packet_free(&avPacket);//AVPacket中的第一个参数,就是引用,减到0才真正释放
av_free(avPacket);
continue;
}
avPacket = NULL;
}
网友评论