zoukankan      html  css  js  c++  java
  • 【流媒體】Android 实时视频采集—MediaRecoder录制


    【流媒體】Android 实时视频采集—MediaRecoder录制

    SkySeraph Mar 31st 2012

    Email:skyseraph00@163.com 

    流媒体系列: http://skyseraph.com/2012/04/11/Media/流媒体专题/ 

    0 啰嗦

      本篇的存在只是为系列的连贯性,其实在前面系列博文中对MediaRecoder已有用到,详见前面Android系列博文Android(19)


    1 概述

      通过Android的MediaRecorder,在SetoutputFile函数中绑定LocalSocket实现


    2 知识点

    ① MediaRecoder使用

      参考 【Android學習專題】多媒體篇:MediaRecorder 实现录音机

    ② LocalSocket使用

      在手机中实现数据的边发送边接收。

    详细参考:http://api.apkbus.com/reference/android/net/LocalSocket.html

    http://api.apkbus.com/reference/android/net/LocalServerSocket.html


    3 核心源码

    ① SurfaceView相关

      参考 【流媒體】Android 实时视频采集—Camera预览采集 和 【Android學習專題】多媒體篇:MediaRecorder 实现录音机

    ② Init LocalSocket

        private void initLocalSocket()
    {
    receiver = new LocalSocket();
    try
    {
    lss = new LocalServerSocket("H264");
    receiver.connect(new LocalSocketAddress("H264"));
    receiver.setReceiveBufferSize(500000);
    receiver.setSendBufferSize(500000);
    sender = lss.accept();
    sender.setReceiveBufferSize(500000);
    sender.setSendBufferSize(500000);
    } catch (IOException e1)
    {
    e1.printStackTrace();
    Log.e("", "localSocket error:" + e1.getMessage());
    }
    }

    ③ MediaRecorder相关

    参考【Android學習專題】多媒體篇:MediaRecoder 实现录像机  和 【Android學習專題】多媒體篇:MediaRecorder 实现录音机

    另附initiativeVideo核心模块

    private boolean initializeVideo()
    {
    try
    {
    Log.i(TAG,"##initializeVideo....");
    // 〇state: Initial 实例化MediaRecorder对象
    if (mSurfaceView == null)
    {
    Log.e(TAG,"mSurfaceView is null in initializeVideo");
    return false;
    }
    if(mMediaRecorder == null)
    mMediaRecorder = new MediaRecorder();
    else
    mMediaRecorder.reset();

    // 〇state: Initial=>Initialized
    // set audio source as Microphone, video source as camera
    // specified before settings Recording-parameters or encoders,called only before setOutputFormat
    mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
    //mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);

    // 〇state: Initialized=>DataSourceConfigured
    // 设置錄製視頻输出格式
    // THREE_GPP: 3gp格式,H263视频ARM音频编码
    // MPEG-4: MPEG4 media file format
    // RAW_AMR: 只支持音频且音频编码要求为AMR_NB
    // AMR_NB:
    // ARM_MB:
    // Default:
    // 3gp or mp4
    //Android支持的音频编解码仅为AMR_NB;支持的视频编解码仅为H263,H264只支持解码;支持对JPEG编解码;输出格式仅支持.3gp和.mp4
    String lVideoFileFullPath;
    lVideoFileFullPath = ".3gp"; //.mp4
    mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
    //mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
    Log.i(TAG, "Video:Current container format: "+"3GP\n");

    // 设置視頻/音频文件的编码:AAC/AMR_NB/AMR_MB/Default
    // video: H.263, MP4-SP, or H.264
    mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
    //mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H263);
    //mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.MPEG_4_SP);
    Log.i(TAG, "Video:Current encoding format: "+"H264\n");

    // audio: AMR-NB
    //mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);

    // 设置视频录制的分辨率。必须放在设置编码和格式的后面,否则报错
    //mMediaRecorder.setVideoSize(176, 144);
    mMediaRecorder.setVideoSize(320, 240);
    //mMediaRecorder.setVideoSize(720, 480);
    Log.i(TAG, "Video:Current Video Size: "+"320*240\n");

    // 设置录制的视频帧率。必须放在设置编码和格式的后面,否则报错
    mMediaRecorder.setVideoFrameRate(FRAME_RATE);

    // 预览
    mMediaRecorder.setPreviewDisplay(mSurfaceHolder.getSurface());

    // 设置输出文件方式: 直接本地存储 or LocalSocket远程输出
    if(bIfNativeORRemote) //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~");
    }

    //
    mMediaRecorder.setMaxDuration(0);//called after setOutputFile before prepare,if zero or negation,disables the limit
    mMediaRecorder.setMaxFileSize(0);//called after setOutputFile before prepare,if zero or negation,disables the limit
    try
    {
    mMediaRecorder.setOnInfoListener(this);
    mMediaRecorder.setOnErrorListener(this);
    // 〇state: DataSourceConfigured => prepared
    mMediaRecorder.prepare();
    // 〇state: prepared => recording
    mMediaRecorder.start();
    bIfRecInProcess = true;
    Log.i(TAG, "initializeVideo Start!");
    } catch (Exception e)
    {
    releaseMediaRecorder();
    finish();
    e.printStackTrace();
    }
    return true;
    } catch (Exception e)
    {
    // TODO: handle exception
    e.printStackTrace();
    return false;
    }
    }

    Refs/Related

       见文中链接


    作者:skyseraph
    出处:http://www.cnblogs.com/skyseraph/
    更多精彩请直接访问SkySeraph个人站点:http://skyseraph.com//
    Email/GTalk: zgzhaobo@gmail.com
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

  • 相关阅读:
    【转】逆向工程:让我们剥开软件的坚果
    分散/聚集IO(scatter/gather)及iovec结构体
    C10K并发连接_转
    AVL平衡二叉树
    软中断
    应用层timer_如何序列化timer
    应用层timer_libc_posix timer
    linux/unix 段错误捕获_转
    C/C++捕获段错误,打印出错的具体位置(精确到哪一行)_转
    linux内存查看及释放
  • 原文地址:https://www.cnblogs.com/skyseraph/p/2427593.html
Copyright © 2011-2022 走看看