Android 实时视频编码—H.264硬编码

http://my.eoe.cn/682121/archive/1839.html

作者:changkai245发布于 03月21日访问(533)评论(0

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 核心代码
① MediaRecoder视频采集
视频采集采用了MediaRecorde录制方式,详见 “【流媒體】Android 实时视频采集—MediaRecoder录制 ”

② 在initiativeVideo中setOutputFile设置以流方式输出

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
        // 设置输出文件方式: 直接本地存储   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~");
        }

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

1
2
3
4
5
private void startRecording()
{
    Log.i(TAG, "##startRecording....");
    new Thread(this).start();            
}

run:

@Override
public void run()
{
Log.i(TAG, "##run....");

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
    // 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();
        }
    }        
    //
}

4 Ref/Related
1 http://blog.csdn.net/zblue78/article/details/6078040
2 http://blog.csdn.net/zblue78/article/details/6083374
3 http://www.docin.com/p-282454756.html
4 http://blog.csdn.net/qwertyuj/article/details/7029836
5 http://www.cnblogs.com/skyseraph/archive/2012/03/31/2427593.html
6 http://www.cnblogs.com/skyseraph/archive/2012/03/23/2415018.html
7 http://www.cnblogs.com/skyseraph/archive/2012/04/01/2429384.html

作者:skyseraph
出处:http://www.cnblogs.com/skyseraph/
Email/GTalk: zgzhaobo@gmail.com

声明:eoe文章著作权属于作者,受法律保护,转载时请务必以超链接形式附带如下信息

原文作者: changkai245

原文地址: http://my.eoe.cn/682121/archive/1839.html


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值