最纯粹的直播技术实战02Camera的处理以及推流Word格式文档下载.docx
- 文档编号:17995793
- 上传时间:2022-12-12
- 格式:DOCX
- 页数:30
- 大小:815.75KB
最纯粹的直播技术实战02Camera的处理以及推流Word格式文档下载.docx
《最纯粹的直播技术实战02Camera的处理以及推流Word格式文档下载.docx》由会员分享,可在线阅读,更多相关《最纯粹的直播技术实战02Camera的处理以及推流Word格式文档下载.docx(30页珍藏版)》请在冰豆网上搜索。
tools:
context="
com.xiaoxiao.live.MainActivity"
<
TextView
@+id/main_tv_info"
wrap_content"
visibility="
gone"
text="
HelloWorld!
"
/>
Button
@+id/main_bt_live"
我要直播"
@+id/main_bt_watch"
看直播"
/LinearLayout>
我们把上一次的测试TextView注释掉了,然后新建了一个LiveActivity来处理Camera以及推流,主要就是展示直播。
后续还会有看直播的处理,就要就是拉流以及视频的播放了
接下来就要在LiveActivity里面处理一下Camera的东西了,首先要在LiveActivity的layout里面添加一个SurfaceView
SurfaceView
@+id/live_sv_live"
因为不是拍照,所以Camera的处理就会显得比较的简单了,
packagecom.xiaoxiao.live;
importandroid.graphics.ImageFormat;
importandroid.hardware.Camera;
importandroid.os.Bundle;
importandroid.support.v7.app.AppCompatActivity;
importandroid.util.Log;
importandroid.view.Menu;
importandroid.view.MenuItem;
importandroid.view.SurfaceHolder;
importandroid.view.SurfaceView;
/**
*CreatedbyAdministratoron2017/2/20.
*/
publicclassLiveActivityextendsAppCompatActivityimplementsSurfaceHolder.Callback,Camera.PreviewCallback{
privateCameramCamera;
privateSurfaceViewmSurfaceView;
privateSurfaceHoldermSurfaceHolder;
privateintmCameraId=0;
privateintwidth=720;
privateintheight=480;
@Override
publicvoidonCreate(BundlesavedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_live);
mSurfaceView=(SurfaceView)findViewById(R.id.live_sv_live);
mSurfaceHolder=mSurfaceView.getHolder();
mSurfaceHolder.setFixedSize(width,height);
mSurfaceHolder.addCallback(this);
}
publicbooleanonCreateOptionsMenu(Menumenu){
getMenuInflater().inflate(R.menu.menu_live,menu);
returntrue;
publicbooleanonOptionsItemSelected(MenuItemitem){
if(item.getItemId()==R.id.checkable_menu){
booleanisChecked=item.isChecked();
Log.e("
LiveActivity"
"
checked:
"
+isChecked);
item.setChecked(!
isChecked);
mCameraId=1-mCameraId;
destroyCamera();
initCamera();
returnsuper.onOptionsItemSelected(item);
publicvoidonPreviewFrame(byte[]data,Cameracamera){
publicvoidsurfaceCreated(SurfaceHolderholder){
publicvoidsurfaceChanged(SurfaceHolderholder,intformat,intwidth,intheight){
publicvoidsurfaceDestroyed(SurfaceHolderholder){
privatevoidinitCamera(){
try{
mCamera=Camera.open(mCameraId);
mCamera.setPreviewDisplay(mSurfaceHolder);
Camera.Parametersparams=mCamera.getParameters();
//设置预览大小
params.setPreviewSize(width,height);
//设置生成的照片大小
params.setPictureSize(width,height);
params.setPreviewFormat(ImageFormat.NV21);
mCamera.setDisplayOrientation(90);
//params.setRotation(90);
/*List<
Camera.Size>
sizes=params.getSupportedPreviewSizes();
for(Camera.Sizes:
sizes){
s.width+"
X"
+s.height);
}*/
mCamera.setParameters(params);
mCamera.setPreviewCallback(this);
mCamera.startPreview();
}catch(Exceptione){
e.printStackTrace();
privatevoiddestroyCamera(){
if(mCamera==null){
return;
mCamera.setPreviewCallback(null);
mCamera.stopPreview();
mCamera.release();
mCamera=null;
}
我们通过menu来做了一个摄像头的切换功能,这样子就可以前摄像头直播或者后摄像头直播了。
到时会在onPreviewFrame里面获取到数据,然后交给jni进行一个编码的处理,然后就推流
那么这里就会有一个非常重要的知识点了:
我们通过setPreviewFormat方法把预览的数据(onPreviewFrame方法参数里面的data)的格式设置成了ImageFormat.NV21,一般来说,常用的格式是NV21或者YV12,因为这两种格式被所有的摄像头支持的,Android默认是会设置NV21的。
那么什么是NV21或YV12呢,其实这也是一种yuv格式的数据来的
上一篇文章我们已经说过了,就是通过把yuv通过编码,然后再封装就可以得到一个视频文件了,但我们还需要对这种yuv进行一定的处理,因为yuv也是有不同的各类的。
yuv通常分成两大格式,一种是planar:
把所有像素点的Y值全部存放在数组的最前面,然后再存放所有像素点的U值,最后再存放所有像素点的V值
还有一种就是packed:
它是依次存放每一个像素点的YUV值的
同时yuv还有不同的采样方式,一般主流的有三种:
YUV4:
4:
4每一个Y对应一组UV分量
2:
2每两个Y共用一组UV分量
0每四个Y共用一组UV分量
假设一张720X480的图片存储成yuv格式:
4Y=720*480U=V=720*480所以整个数组的大小就是720*480*3
2Y=720*480U=V=720*480/2所以整个数组的大小就是720*480*2
0Y=720*480U=V=720*480/4所以整个数组的大小就是720*480*1.5
NV21和YV12就是YUV4:
0这种采样格式的,而且我们到时用FFmpeg编码采用的格式一般是AV_PIX_FMT_YUV420P,都是YUV4:
0这种采样格式的
但还是有一些差别的
AV_PIX_FMT_YUV420P格式是planar,就是先存全部的Y再存全部的U再存全部的V,采样格式4:
0。
存储格式类似yyyyyyyyuuvv这样
NV21格式也是planar,采样格式也是4:
存储格式类似yyyyyyyyvuvu
YV12格式也是planar,采样格式也是4:
存储格式类似yyyyyyyyvvuu
从上面可以看到,我们需要用的格式和预览的格式还是有些差别的,所以我们到时要处理一下。
那么现在我们可以先把我们的Camera的功能给测试一下先的,看看能不能预览成功,但在运行前,还需要去AndroidManifest里面配置一下
如果Camera模块测试没有问题的话,我们就可以来写native方法了,首先在LiveActivity里面定义好几个native方法
/**
*初始化编码的一些东西,比如编码器等
*@paramwidth编码视频的宽
*@paramheight编码视频的高
*@return0成功小于0失败
privatenativeintstreamerInit(intwidth,intheight);
*对每一次预览的数据进行编码推流
*@paramdataNV21格式的数据
*@return0成功,小于0失败
privatenativeintstreamerHandle(byte[]data);
*把缓冲帧的数据清空
privatenativeintstreamerFlush();
*释放资源,比如编码器这些
privatenativeintstreamerRelease();
定义完成native方法后,我们先把LiveActivity里面的逻辑给处理一下先。
为了不影响UI线程(以后可能数据处理会有点多),我就使用了HandlerThread这个类来进行异步操作,先把类初始化
mHandlerThread=newHandlerThread("
liveHandlerThread"
);
mHandlerThread.start();
mHandler=newLiveHandler(this,mHandlerThread.getLooper());
LiveHandler是我定义在LiveActivity的静态内部类,用来进行异步操作的
privatestaticclassLiveHandlerextendsHandler{
privateWeakReference<
LiveActivity>
mActivity;
publicLiveHandler(LiveActivityactivity,Looperlooper){
super(looper);
mActivity=newWeakReference<
(activity);
publicvoidhandleMessage(Messagemsg){
super.handleMessage(msg);
LiveActivityactivity=mActivity.get();
if(activity==null){
switch(msg.what){
caseSTREAMER_INIT:
break;
caseSTREAMER_HANDLE:
Bundlebundle=msg.getData();
if(bundle!
=null){
byte[]data=bundle.getByteArray("
frame_data"
if(data!
=null&
&
data.length>
0){
activity.streamerHandle(data);
}else{
bytedatanull"
bundlenull"
caseSTREAMER_FLUSH:
activity.streamerFlush();
caseSTREAMER_RELEASE:
activity.streamerRelease();
LiveActivity里面的逻辑主要是一些细节的处理,完整的代码就下面那样:
importandroid.os.Handler;
importandroid.os.HandlerThread;
importandroid.os.Looper;
importandroid.os.Message;
importjava.lang.ref.WeakReference;
privatestaticfinalintSTREAMER_INIT=0;
privatestaticfinalintSTREAMER_HANDLE=1;
privatestaticfinalintSTREAMER_RELEASE=2;
privatestaticfinalintSTREAMER_FLUSH=3;
*判断有没有初始化成功,不成功不不进行后续的编码处理
privateintliveInitResult=-1;
*异步操作
privateHandlerThreadmHandlerThread;
privateLiveHandlermHandler;
*如果初始化成功,那就把数据发送到Handler,然后再调用native方法
if(liveInitResult==0&
data!
Messagemsg=Message.obtain();
Bundlebundle=newBundle();
bundle.putByteArray("
data);
msg.what=STREAMER_HANDLE;
msg.setData(bundle);
mHandler.sendMessage(msg);
*在surface创建的时候进行初始化,如果失败了,也是需要释放已经开辟了
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 纯粹 直播 技术 实战 02 Camera 处理 以及
![提示](https://static.bdocx.com/images/bang_tan.gif)