首页 > 代码库 > 视频直播技术(二):实时视频编码之H264硬编码

视频直播技术(二):实时视频编码之H264硬编码

1.硬编码 & 软编码

硬编码:通过Android系统自带的Camera录制视频,实际上调用的是底层的高清编码硬件模块,即显卡,不使用CPU,速度快

软编码:使用CPU进行编码,如常见C/C++代码,编译生成二进制文件,速度相对较慢。例如使用Android NDK编译H264生成so库,编写jni接口,再使用java调用so库。

2.硬编码过程和原理

过程:通过MediaRecoder采集视频,再将视频流映射到LocalSocket实现收发。

原理:详见【流媒體】H264—MP4格式及在MP4文件中提取H264的SPS、PPS及码流 和  “【流媒體】Android 实时视频采集—MediaRecoder录制 ” 

3.核心代码

a). MediaRecoder视频采集

视频采集采用了MediaRecorde录制方式,详见 “【流媒體】Android 实时视频采集—MediaRecoder录制 ”

b). initiativeVideosetOutputFile设置以流方式输出

// 设置输出文件方式: 直接本地存储   or LocalSocket远程输出        
if (bIfNativeORRemote == true) // Native
     lVideoFileFullPath = strRecVideoFilePath + String.valueOf(System.currentTimeMillis()) + lVideoFileFullPath;
     mRecVideoFile = new File(lVideoFileFullPath);
     // mMediaRecorder.setOutputFile(mRecVideoFile.getAbsolutePath());
     mMediaRecorder.setOutputFile(mRecVideoFile.getPath()); // called after set**Source before prepare
     Log.i(TAG, "start write into file~");
} else {
   // Remote
  mMediaRecorder.setOutputFile(sender.getFileDescriptor()); // 设置以流方式输出 Log.i(TAG, "start send into sender~");
}

c). startRecording

功能:通过这个函数方法启动线程实现视频流映射到LocalSocket,同时实现编码:

private void startRecording() {
        Log.i(TAG, "##startRecording....");
        new Thread(this).start();            
}

 

run 方法:

@Override
    public void run()
    {
        Log.i(TAG, "##run....");
        
        // defines
        DataInputStream dataInputStream = null;        
        int offSet=0,tmp=0,beLeft=0;

        try
        {
            dataInputStream = new DataInputStream(receiver.getInputStream());
        } catch (IOException e2)
        {
            // TODO Auto-generated catch block
            e2.printStackTrace();
        }    
        try
        {
            Thread.currentThread().sleep(500);
        } catch (InterruptedException e1)
        {
            e1.printStackTrace();
        }
        
        // ①方式一:通过查看预先录制的视频,需要跳过mdat前面32个字节(不同硬件平台不同!)
        try
        {            
            dataInputStream.read(h264frame, 0, 32); 
            Log.i(TAG, "read mdat from");
        } catch (IOException e1)
        {
            // TODO Auto-generated catch block
            e1.printStackTrace();
        }
        // ②方式二:自动化查找(待补充)
                

        try
        {
            h264FileOutputStream = new FileOutputStream("/sdcard/avss/h264.264");//264码流
            Log.i(TAG, "h264FileOutputStream");
        } catch (FileNotFoundException e)
        {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }    
        try
        {
            h264FileOutputStream.write(h264head);
            h264FileOutputStream.write(h264sps);
            h264FileOutputStream.write(h264head);
            h264FileOutputStream.write(h264pps);
            Log.i(TAG, "run-write SPS/PPS to file");
        } catch (IOException e1)
        {
            // TODO Auto-generated catch block
            e1.printStackTrace();
        }

        while (bIfRecInProcess && (!bIfNativeORRemote))
        {
            try
            {
                Log.i(TAG, "**while...");    
                int h264length = dataInputStream.readInt(); 
                Log.i(TAG, "h264length:"+h264length);
                tmp=0; offSet = 0; beLeft = 0;
                
                h264FileOutputStream.write(h264head);
                while (offSet < h264length)
                {
                    beLeft = h264length - offSet;
                    tmp = dataInputStream.read(h264frame, 0, READ_SIZE < beLeft ? READ_SIZE : beLeft);
                    Log.i(TAG, String.format("H264 %d,%d,%d", h264length, offSet, tmp));
                    offSet += tmp;
                    h264FileOutputStream.write(h264frame, 0, tmp);
                }
                
            } catch (Exception e)
            {
                // TODO: handle exception
                e.printStackTrace();
            }
        }        
        //
    }

 

视频直播技术(二):实时视频编码之H264硬编码