Android:关于mediacodec编码camera yuv数据帧率过低的问题

来源:互联网 发布:mac怎么输入法 编辑:程序博客网 时间:2024/05/21 19:32

网上有很多android平台关于mediacodec编码yuv数据为H264数据出现帧率过低的问题

主要是

while (isRuning) {中有
NV21ToNV12(input,yuv420sp,m_width,m_height);
这样一段代码,其实大部分博客里面都是直接在java层处理的
代码如下:
private void NV21ToNV12(byte[] nv21,byte[] nv12,int width,int height){    if(nv21 == null || nv12 == null)return;    int framesize = width*height;    int i = 0,j = 0;    System.arraycopy(nv21, 0, nv12, 0, framesize);    for(i = 0; i < framesize; i++){        nv12[i] = nv21[i];    }    for (j = 0; j < framesize/2; j+=2)    {        nv12[framesize + j-1] = nv21[j+framesize];    }    for (j = 0; j < framesize/2; j+=2)    {        nv12[framesize + j] = nv21[j+framesize-1];    }}
测试机器:三星note5的机器上测试了一下 这个过程一般要消耗70-100ms
在cameracallback的回调获取的buffer是  30fps
最终编码出来的数据 只有10fps
说明处理一帧数据一般消耗100ms。而处理 NV21ToNV12 的过程就花了大部分时间
优化1:用JNI调用底层来处理啊,这一部分优化后发现话费的时间在30-50ms之间。
优化2:
 System.arraycopy(nv21, 0, nv12, 0, framesize);    for(i = 0; i < framesize; i++){        nv12[i] = nv21[i];    }
这部分代码发现重复了,本来直接把nv21的前framesize中的内容copy到nv12中,而这里等于重复了两次的。
可以把
   for(i = 0; i < framesize; i++){        nv12[i] = nv21[i];    }
这部分代码去掉
发现优化后的结果,这部分花费的时间在10-30ms之间。

再次编码帧率基本稳定在30fps左右的

最终代码如下:
java层的调用方法:
jni_handle_nv21_to_nv12(input,yuv420sp,m_width,m_height);
底层的具体实现:
JNIEXPORT jbyteArray JNICALLJava_com_example_lyc_sampleffpeg_VideoPlayer_jni_1handle_1nv21_1to_1nv12(JNIEnv *env, jclass type,                                                                         jbyteArray input_,                                                                         jbyteArray yuv420sp_,                                                                         jint m_width,                                                                         jint m_height) {    jbyte *input = env->GetByteArrayElements(input_, NULL);    jbyte *yuv420sp = env->GetByteArrayElements(yuv420sp_, NULL);    int framesize = m_width*m_height;    int i = 0,j = 0;    memcpy(yuv420sp, input, framesize);    for (j = 0; j < framesize/2; j+=2)    {        yuv420sp[framesize + j-1] = input[j+framesize];    }    for (j = 0; j < framesize/2; j+=2)    {        yuv420sp[framesize + j] = input[j+framesize-1];    }    // TODO    jbyteArray it = env->NewByteArray(framesize * 3 / 2);    env->SetByteArrayRegion(it, 0, framesize * 3 / 2 , yuv420sp);    env->ReleaseByteArrayElements(input_, input, 0);    env->ReleaseByteArrayElements(yuv420sp_, yuv420sp, 0);    return  it;}
----------------------------------------分割线------------------------------------
发现目前还是不能满足我现在的处理速度的
其实这个处理 就是在uv的数据调换位置的 ,其实就是一个交换数值的算法的。根本不用进行memcpy
代码如下:
JNIEXPORT jbyteArray JNICALLJava_com_example_lyc_sampleffpeg_VideoPlayer_jni_1handle_1nv21_1to_1nv12(JNIEnv *env, jclass type,                                                                         jbyteArray input_,                                                                         jint m_width,                                                                         jint m_height) {    jbyte *input = env->GetByteArrayElements(input_, NULL);    int framesize = m_width*m_height;    int i = 0,j = 0;    jbyte  temp;    for (j = 0; j < framesize/2; j+=2)    {        temp = input[ j + framesize - 1];        input[framesize + j - 1 ] =input[ j + framesize];        input[ j + framesize ] = temp;    }    jbyteArray it = env->NewByteArray(framesize * 3 / 2);    env->SetByteArrayRegion(it, 0, framesize * 3 / 2 , input);    env->ReleaseByteArrayElements(input_, input, 0);    return  it;}


0 0
原创粉丝点击