HEVC(H.265) encode

HEVC(H.265) encode

demo: https://github.com/wangzuxing/MyFFmpegH264H265YUVOpenGL

编码库: X265 — 编码符合高效率视频编码(HEVC/H.265)标准的视频的开源库

H.265/HEVC和H.264/AVC的编码架构相似:
帧内预测(intra prediction)、
帧间预测(inter prediction)、
转换(transform)、
量化(quantization)、
去区块滤波器(deblocking filter)、
熵编码(entropy coding)等模块

HEVC编码架构中,整体被分为了三个基本单位:编码单位(coding unit,CU)、预测单位(predict unit,PU) 和转换单位(transform unit,TU )。

编码单位:
H.265可以选择从最小的8x8到最大的64x64。
H.264宏块(macroblock/MB)大小都是固定的16x16像素

帧内预测模式:
H.265的支持33种方向,提供了更好的运动补偿处理和矢量预测方法
H.264只支持8种

压缩比率更高,编码视频质量更好:
相同的图象质量下,H.265编码的视频大小将减少大约39-44%。
在码率减少51-74%的情况下,H.265编码视频的质量能与H.264编码视频近似甚至更好,其本质上说是比预期的信噪比(PSNR)要好

Java端:
MainActivity0:

static {
        ...
        System.loadLibrary("myx265"); // x265以libx265.a文件形式集成到myx265库中
    }

    ...
    //x265
    public native boolean X265Start(String file);
    public native void X265Enc(byte[] array, int length); // camera preview data 经swapYV12toI420()函数转换成H.265编码器支持的I420视频格式
    public native void X265End();
    ... 

    /*
    packed formats:将Y、U、V值储存成Macro Pixels阵列,和RGB的存放方式类似。
    planar formats:将Y、U、V的三个份量分别存放在不同的矩阵中。
    COLOR_FormatYUV420Planar:    YUV420P I420
    COLOR_FormatYUV420SemiPlanar:   YUV420SP NV12
    YUV420P,Y,U,V三个分量都是平面格式,分为I420和YV12。I420格式和YV12格式的不同处在U平面和V平面的位置不同。在I420格式中,U平面紧跟在Y平面之后,然后才是V平面(即:YUV);但YV12则是相反(即:YVU)。
    YUV420SP, Y分量平面格式,UV打包格式, 即NV12。 NV12与NV21类似,U 和 V 交错排列,不同在于UV顺序。
    I420: YYYYYYYY UU VV    =>YUV420P
    YV12: YYYYYYYY VV UU    =>YUV420P
    NV12: YYYYYYYY UVUV     =>YUV420SP
    NV21: YYYYYYYY VUVU     =>YUV420SP
    */

    //yv12 =》 yuv420p : yvu -> yuv  
    private void swapYV12toI420(byte[] yv12bytes, byte[] i420bytes, int width, int height)   
    {        
        System.arraycopy(yv12bytes, 0, i420bytes, 0,width*height);  
        System.arraycopy(yv12bytes, width*height+width*height/4, i420bytes, width*height,width*height/4);  
        System.arraycopy(yv12bytes, width*height, i420bytes, width*height+width*height/4,width*height/4);    
    }

    //camera preview data
    @Override
    public void onPreviewFrame(byte[] data, Camera camera) {
         // TODO Auto-generated method stub
         swapYV12toI420(data, h264, width, height); //yvu -> yuv(H.265编码器只支持YUV视频格式输入)

     X265Enc(h264, 0);     
         camera.addCallbackBuffer(buf); 
    }

    @Override
    public void onClick(View v) {
        // TODO Auto-generated method stub
        Button btn = (Button)v;
        if(btn_id==0)
        {
            Log.i("Encoder", "                   onClick                    ");
            ...
            }else if(btnClick2 == btn){//x265(Encode)
                btn_id = 3;
                btn_id0= 3;
                File f = new File(Environment.getExternalStorageDirectory(), "H265_03f.h265");
                try {
                     if(!f.exists()){
                        f.createNewFile();
                     }
                } catch (IOException e) {
                     e.printStackTrace();
                }
                Log.i("Encoder", "X265Start = f.getPath() = "+f.getPath()+", f.getAbsolutePath() = "+f.getAbsolutePath()); 
                X265Start(f.getPath());
                myshow.setText("X265 Encode --> .h265");
                myshow.setBackgroundColor(Color.RED);
                btnClick2.setBackgroundColor(Color.MAGENTA);
                Log.i("Encoder", "--------------X265Start btnClick2--------------");
            }
            ...
        }else{
            Log.i("Encoder", "                   onClick release                   ");
            ...
            }else if(btnClick2 == btn && btn_id0==3){
                ...
                X265End();
                ...
                Log.i("Encoder", "--------------X265End btnClick2--------------");
            }
            ...
        }
    }

JNI端:
mp_x.cpp

#include <stdio.h>
#include <jni.h>
#include <malloc.h>
#include <string.h>
#include <android/log.h>
#include <string.h>

#include "x265.h"

#define LOG_TAG "libmp4"
#define LOGD(...) ((void)__android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__))
#define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__))
#define LOGW(...) ((void)__android_log_print(ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__))

#ifdef __cplusplus
extern "C" {
#endif

FILE *h265_file;
int ret;
x265_nal *pNals=NULL;
uint32_t iNal=0;
x265_param* pParam=NULL;
x265_encoder* pHandle=NULL;
x265_picture *pPic_in=NULL;
int y_size;
int y_size0;
int frame_num=0;
int csp=X265_CSP_I420;

unsigned char *yuv_buff;

JNIEXPORT bool JNICALL Java_com_example_mymp4v2h264_MainActivity0_X265Start
 (JNIEnv *env, jclass clz, jstring file_name)
{
    LOGI("              X265Start              ");
    int width=640,height=480;
    const char* h265_title = env->GetStringUTFChars(file_name, NULL);
    h265_file=fopen(h265_title,"w");
    if(!h265_file){
        LOGI("              Open File Error              ");
        return false;
    }
        pParam=x265_param_alloc();
        x265_param_default(pParam);
        pParam->bRepeatHeaders=1;//write sps,pps before keyframe
        pParam->internalCsp=csp;
        pParam->sourceWidth=width;
        pParam->sourceHeight=height;
        pParam->fpsNum=25;
        pParam->fpsDenom=1;
        //Init
        pHandle=x265_encoder_open(pParam);
        if(pHandle==NULL){
            LOGI("x265_encoder_open err\n");
            return false;
        }
        y_size0= pParam->sourceWidth * pParam->sourceHeight;
        y_size = (y_size0*3)/2;

        pPic_in = x265_picture_alloc();
        x265_picture_init(pParam,pPic_in);

        yuv_buff=(unsigned char *)malloc(y_size);
        //pPic_in->planes[0] = yuv_buff;
        //pPic_in->planes[1] = pPic_in->planes[0] + width * height;
        //pPic_in->planes[2] = pPic_in->planes[1] + width * height / 4;


        pPic_in->planes[0]=yuv_buff;
        pPic_in->planes[1]=yuv_buff+y_size0;
        pPic_in->planes[2]=yuv_buff+y_size0*5/4;

        pPic_in->stride[0]=width;
        pPic_in->stride[1]=width/2;
        pPic_in->stride[2]=width/2;

    LOGI("              X265Start end             ");
    env->ReleaseStringUTFChars(file_name, h265_title);
    return true;
}

JNIEXPORT void JNICALL Java_com_example_mymp4v2h264_MainActivity0_X265Enc
(JNIEnv *env, jclass clz, jbyteArray data, jint size)
{
    int j;
    uint8_t *buf = (uint8_t *)env->GetByteArrayElements(data, JNI_FALSE);
    memcpy(yuv_buff, buf, y_size);

    frame_num++;
    ret=x265_encoder_encode(pHandle,&pNals,&iNal,pPic_in,NULL);
    LOGI("Succeed encode %d frames, Nals = %d\n", frame_num, iNal);

    for(j=0;j<iNal;j++){
        fwrite(pNals[j].payload,1,pNals[j].sizeBytes,h265_file);
    }

    env->ReleaseByteArrayElements(data, (jbyte *)buf, 0);
}

JNIEXPORT void JNICALL Java_com_example_mymp4v2h264_MainActivity0_X265End
(JNIEnv *env, jclass clz)
{
    LOGI("              X265End              ");
    //Flush Decoder
        while(1){
            int j;
            static int kk = 0;
            ret=x265_encoder_encode(pHandle,&pNals,&iNal,NULL,NULL);
            if(ret<0){
                break;
            }
            LOGI("Flush 1 frame.\n");

            kk++;
            if(kk>=2){
                kk = 0;
                LOGI("Flush end.\n");
                break;
            }
            for(j=0;j<iNal;j++){
                fwrite(pNals[j].payload,1,pNals[j].sizeBytes,h265_file);
            }
        }

        x265_encoder_close(pHandle);
        x265_picture_free(pPic_in);
        x265_param_free(pParam);
        free(yuv_buff);
        fclose(h265_file);

        LOGI("              X265End              ");
}

#ifdef __cplusplus
}
#endif

Android.mk:

...

include $(CLEAR_VARS)
LOCAL_MODULE := x265
LOCAL_SRC_FILES := libx265.a  
include $(PREBUILT_STATIC_LIBRARY) 

include $(CLEAR_VARS)

LOCAL_C_INCLUDES += \
     $(LOCAL_PATH) \
     ...
     $(LOCAL_PATH)/x265 \
     $(LOCAL_PATH)/x265/common \
     $(LOCAL_PATH)/x265/encoder \
     $(LOCAL_PATH)/x265/compat \
     ...

LOCAL_SHARED_LIBRARIES := mp4v2 faac lame x264 rtmp ffmpeg live555 sdl 
LOCAL_STATIC_LIBRARIES += x265 de265
LOCAL_MODULE := myx265
LOCAL_SRC_FILES += mp.c mp_x.cpp streamer.cpp yuv.c dec265.cpp ./SDL/src/main/android/SDL_android_main.c
LOCAL_LDLIBS += -lGLESv1_CM -llog

include $(BUILD_SHARED_LIBRARY)
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值