前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >mediacodec解码ffmpeg AvPacket

mediacodec解码ffmpeg AvPacket

作者头像
曾大稳
发布2018-09-11 10:32:36
1.7K0
发布2018-09-11 10:32:36
举报
文章被收录于专栏:曾大稳的博客
初始化MediaCodec
代码语言:javascript
复制

private MediaFormat mediaFormat;
private MediaCodec mediaCodec;
private MediaCodec.BufferInfo info;
private Surface surface;//这个是OpenGL渲染的Surface

/**
 * 初始化MediaCodec
 *
 * @param codecName
 * @param width
 * @param height
 * @param csd_0
 * @param csd_1
 */
public void initMediaCodec(String codecName, int width, int height, byte[] csd_0, byte[] csd_1) {
        try {
          if (surface != null) {
                String mime = VideoSupportUtil.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));
                MyLog.d(mediaFormat.toString());
                mediaCodec = MediaCodec.createDecoderByType(mime);
                info = new MediaCodec.BufferInfo();
                if(mediaCodec == null) {
                    MyLog.d("craete mediaCodec wrong");
                    return;
                }
                mediaCodec.configure(mediaFormat, surface, null, 0);
                mediaCodec.start();
          }
        } catch (Exception e) {
            e.printStackTrace();
        }
    } 
}

VideoSupportUtil.java

代码语言:javascript
复制


import android.media.MediaCodecList;

import java.util.HashMap;
import java.util.Map;

public class VideoSupportUtil {

    private static Map<String, String> codecMap = new HashMap<>();
    static {
        codecMap.put("h264", "video/avc");
    }

    public static String findVideoCodecName(String ffcodename){
        if(codecMap.containsKey(ffcodename))
        {
            return codecMap.get(ffcodename);
        }
        return "";
    }

    public static boolean isSupportCodec(String ffcodecname){
        boolean supportvideo = false;
        int count = MediaCodecList.getCodecCount();
        for(int i = 0; i < count; i++){
            String[] tyeps = MediaCodecList.getCodecInfoAt(i).getSupportedTypes();
            for(int j = 0; j < tyeps.length; j++){
                if(tyeps[j].equals(findVideoCodecName(ffcodecname))){
                    supportvideo = true;
                    break;
                }
            }
            if(supportvideo){
                break;
            }
        }
        return supportvideo;
    }
}

c++层:

代码语言:javascript
复制



const char* codecName = ((const AVCodec*)avCodecContext->codec)->name;
onCallInitMediacodec(
                codecName,
                avCodecContext->width,
                avCodecContext->height,
                avCodecContext->extradata_size,
                avCodecContext->extradata_size,
                avCodecContext->extradata,
                avCodecContext->extradata
        );

//获取jmid_initmediacodec
jclass  jlz = jniEnv->GetObjectClass(jobj);
jmethodID jmid_initmediacodec = env->GetMethodID(jlz, "initMediaCodec", "(Ljava/lang/String;II[B[B)V");

//在子线程
void onCallInitMediacodec(const char* mime, int width, int height, int csd0_size, int csd1_size, uint8_t *csd_0, uint8_t *csd_1) {

    JNIEnv *jniEnv;
    if(javaVM->AttachCurrentThread(&jniEnv, 0) != JNI_OK)
    {
        if(LOG_DEBUG)
        {
            LOGE("call onCallComplete worng");
        }
    }

    jstring type = jniEnv->NewStringUTF(mime);
    jbyteArray csd0 = jniEnv->NewByteArray(csd0_size);
    jniEnv->SetByteArrayRegion(csd0, 0, csd0_size, reinterpret_cast<const jbyte *>(csd_0));
    jbyteArray csd1 = jniEnv->NewByteArray(csd1_size);
    jniEnv->SetByteArrayRegion(csd1, 0, csd1_size, reinterpret_cast<const jbyte *>(csd_1));

    jniEnv->CallVoidMethod(jobj, jmid_initmediacodec, type, width, height, csd0, csd1);

    jniEnv->DeleteLocalRef(csd0);
    jniEnv->DeleteLocalRef(csd1);
    jniEnv->DeleteLocalRef(type);
    javaVM->DetachCurrentThread();

}
解码AvPacket数据
代码语言:javascript
复制
public void decodeAVPacket(int datasize, byte[] data) {
    if (surface != null && datasize > 0 && data != null) {
        int intputBufferIndex = mediaCodec.dequeueInputBuffer(10);
        if (intputBufferIndex >= 0) {
            ByteBuffer byteBuffer = mediaCodec.getOutputBuffers()[intputBufferIndex];
            byteBuffer.clear();
            byteBuffer.put(data);
            mediaCodec.queueInputBuffer(intputBufferIndex, 0, datasize, 0, 0);
        }
        //这里拿到outputBufferIndex然后就可以获取到数据,这里会通过surface达到渲染
        int outputBufferIndex = mediaCodec.dequeueOutputBuffer(info, 10);
        while (outputBufferIndex >= 0) {
            mediaCodec.releaseOutputBuffer(outputBufferIndex, true);
            outputBufferIndex = mediaCodec.dequeueOutputBuffer(info, 10);
        }
    }
}

c++层回调decodeAVPacket

代码语言:javascript
复制
datasize = avPacket->size;
data = avPacket->data;//jni这里需要把uint8_t转为jbyteArray,类似初始化那
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2018-07-16,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 初始化MediaCodec
  • 解码AvPacket数据
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档