门户网站是指,有哪个网站教人做美食,做网站 图片更好看,辽宁企业网站建设公司随着无纸化、智慧教室等场景的普及#xff0c;好多企业或者开发者开始寻求更高效稳定低延迟的RTMP同屏方案#xff0c;本文以大牛直播SDK(Github)的同屏demo#xff08;对应工程#xff1a;SmartServicePublisherV2#xff09;为例#xff0c;介绍下如何采集编码推送RTMP…随着无纸化、智慧教室等场景的普及好多企业或者开发者开始寻求更高效稳定低延迟的RTMP同屏方案本文以大牛直播SDK(Github)的同屏demo对应工程SmartServicePublisherV2为例介绍下如何采集编码推送RTMP数据到流媒体服务器。
系统要求Android 5.0及以上系统。
废话不多说上代码
获取screen windows宽高如需缩放按照一定的比例缩放即可 private void createScreenEnvironment() {sreenWindowWidth mWindowManager.getDefaultDisplay().getWidth();screenWindowHeight mWindowManager.getDefaultDisplay().getHeight();Log.i(TAG, screenWindowWidth: sreenWindowWidth ,screenWindowHeight: screenWindowHeight);if (sreenWindowWidth 800){if (screenResolution SCREEN_RESOLUTION_STANDARD){scale_rate SCALE_RATE_HALF;sreenWindowWidth align(sreenWindowWidth / 2, 16);screenWindowHeight align(screenWindowHeight / 2, 16);}else if(screenResolution SCREEN_RESOLUTION_LOW){scale_rate SCALE_RATE_TWO_FIFTHS;sreenWindowWidth align(sreenWindowWidth * 2 / 5, 16);}}Log.i(TAG, After adjust mWindowWidth: sreenWindowWidth , mWindowHeight: screenWindowHeight);int pf mWindowManager.getDefaultDisplay().getPixelFormat();Log.i(TAG, display format: pf);DisplayMetrics displayMetrics new DisplayMetrics();mWindowManager.getDefaultDisplay().getMetrics(displayMetrics);mScreenDensity displayMetrics.densityDpi;mImageReader ImageReader.newInstance(sreenWindowWidth,screenWindowHeight, 0x1, 6);mMediaProjectionManager (MediaProjectionManager) getSystemService(Context.MEDIA_PROJECTION_SERVICE);}
获取到image数据后传递到processScreenImage()处理 private void setupMediaProjection() {mMediaProjection mMediaProjectionManager.getMediaProjection(MainActivity.mResultCode, MainActivity.mResultData);}private void setupVirtualDisplay() {mVirtualDisplay mMediaProjection.createVirtualDisplay(ScreenCapture, sreenWindowWidth, screenWindowHeight,mScreenDensity,DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR,mImageReader.getSurface(), null, null);mImageReader.setOnImageAvailableListener(new ImageReader.OnImageAvailableListener() {Overridepublic void onImageAvailable(ImageReader reader) {Image image mImageReader.acquireLatestImage();if (image ! null) {processScreenImage(image);//image.close();}}}, null);}
数据放到image list里面 private void pushImage(Image image){if ( null image )return;final int image_list_max_count 1;LinkedListImage close_images null;synchronized (image_list_lock){if (image_list.size() image_list_max_count ){close_images new LinkedList();while ( image_list.size() image_list_max_count){close_images.add(image_list.poll());}}image_list.add(image);}if ( close_images ! null ){while( !close_images.isEmpty() ) {Image i close_images.poll();if ( i ! null ){i.close();//Log.i(PushImage, drop image);}}}}
调用大牛直播SDK的RTMP初始化和参数设置接口 libPublisher new SmartPublisherJniV2(); private void InitAndSetConfig() {//开始要不要采集音频或视频请自行设置publisherHandle libPublisher.SmartPublisherOpen(this.getApplicationContext(),audio_opt, video_opt, sreenWindowWidth,screenWindowHeight);if ( publisherHandle 0 ){return;}Log.i(TAG, publisherHandle publisherHandle);libPublisher.SetSmartPublisherEventCallbackV2(publisherHandle, new EventHandeV2());if(videoEncodeType 1){int h264HWKbps setHardwareEncoderKbps(true, sreenWindowWidth,screenWindowHeight);Log.i(TAG, h264HWKbps: h264HWKbps);int isSupportH264HWEncoder libPublisher.SetSmartPublisherVideoHWEncoder(publisherHandle, h264HWKbps);if (isSupportH264HWEncoder 0) {Log.i(TAG, Great, it supports h.264 hardware encoder!);}}else if (videoEncodeType 2){int hevcHWKbps setHardwareEncoderKbps(false, sreenWindowWidth,screenWindowHeight);Log.i(TAG, hevcHWKbps: hevcHWKbps);int isSupportHevcHWEncoder libPublisher.SetSmartPublisherVideoHevcHWEncoder(publisherHandle, hevcHWKbps);if (isSupportHevcHWEncoder 0) {Log.i(TAG, Great, it supports hevc hardware encoder!);}}if(is_sw_vbr_mode){int is_enable_vbr 1;int video_quality CalVideoQuality(sreenWindowWidth,screenWindowHeight, true);int vbr_max_bitrate CalVbrMaxKBitRate(sreenWindowWidth,screenWindowHeight);libPublisher.SmartPublisherSetSwVBRMode(publisherHandle, is_enable_vbr, video_quality, vbr_max_bitrate);}//音频相关可以参考SmartPublisher工程/*if (!is_speex){// set AAC encoderlibPublisher.SmartPublisherSetAudioCodecType(publisherHandle, 1);}else{// set Speex encoderlibPublisher.SmartPublisherSetAudioCodecType(publisherHandle, 2);libPublisher.SmartPublisherSetSpeexEncoderQuality(publisherHandle, 8);}libPublisher.SmartPublisherSetNoiseSuppression(publisherHandle, is_noise_suppression ? 1: 0);libPublisher.SmartPublisherSetAGC(publisherHandle, is_agc ? 1 : 0);*/// libPublisher.SmartPublisherSetClippingMode(publisherHandle, 0);//libPublisher.SmartPublisherSetSWVideoEncoderProfile(publisherHandle, sw_video_encoder_profile);//libPublisher.SmartPublisherSetSWVideoEncoderSpeed(publisherHandle, sw_video_encoder_speed);// libPublisher.SetRtmpPublishingType(publisherHandle, 0);libPublisher.SmartPublisherSetFPS(publisherHandle, 18); //帧率可调libPublisher.SmartPublisherSetGopInterval(publisherHandle, 18*3);//libPublisher.SmartPublisherSetSWVideoBitRate(publisherHandle, 1200, 2400); //针对软编码有效一般最大码率是平均码率的二倍libPublisher.SmartPublisherSetSWVideoEncoderSpeed(publisherHandle, 3);//libPublisher.SmartPublisherSaveImageFlag(publisherHandle, 1);}
初始化、参数设置后设置RTMP推送的URL并调用SartPublisher()接口开始推送 //如果同时推送和录像设置一次就可以InitAndSetConfig();if ( publisherHandle 0 ){stopScreenCapture();return;}if(push_type PUSH_TYPE_RTMP){String publishURL intent.getStringExtra(PUBLISHURL);Log.i(TAG, publishURL: publishURL);if (libPublisher.SmartPublisherSetURL(publisherHandle, publishURL) ! 0) {stopScreenCapture();Log.e(TAG, Failed to set publish stream URL..);if (publisherHandle ! 0) {if (libPublisher ! null) {libPublisher.SmartPublisherClose(publisherHandle);publisherHandle 0;}}return;}}//启动传递数据线程post_data_thread new Thread(new DataRunnable());Log.i(TAG, new post_data_thread..);is_post_data_thread_alive true;post_data_thread.start(); int startRet libPublisher.SmartPublisherStartPublisher(publisherHandle);if (startRet ! 0) {isPushingRtmp false;Log.e(TAG, Failed to start push rtmp stream..);return;}//如果同时推送和录像Audio启动一次就可以了CheckInitAudioRecorder();
开始推送后传递数据到底层SDK public class DataRunnable implements Runnable{private final static String TAG DataRunnable ;Overridepublic void run() {// TODO Auto-generated method stubLog.i(TAG, post data thread is running..);ByteBuffer last_buffer null;Image last_image null;long last_post_time System.currentTimeMillis();while (is_post_data_thread_alive){boolean is_skip false;/*synchronized (data_list_lock){if ( data_list.isEmpty()){if((System.currentTimeMillis() - last_post_time) frame_added_interval_setting){if(last_buffer ! null){Log.i(TAG, 补帧中..);}else{is_skip true;}}else{is_skip true;}}else{last_buffer data_list.get(0);data_list.remove(0);}}*/Image new_image popImage();if ( new_image null ){if((System.currentTimeMillis() - last_post_time) frame_added_interval_setting){if(last_image ! null){Log.i(TAG, 补帧中..);}else{is_skip true;}}else{is_skip true;}}else{if ( last_image ! null ){last_image.close();}last_image new_image;}if( is_skip ){// Log.i(OnScreenImage, is_skip);try {Thread.sleep(5); //休眠5ms} catch (InterruptedException e) {e.printStackTrace();}}else{//if( last_buffer ! null publisherHandle ! 0 (isPushing || isRecording || isRTSPPublisherRunning) )if( last_image ! null publisherHandle ! 0 (isPushingRtmp || isRecording || isRTSPPublisherRunning) ){long post_begin_time System.currentTimeMillis();final Image.Plane[] planes last_image.getPlanes();if ( planes ! null planes.length 0 ){libPublisher.SmartPublisherOnCaptureVideoRGBAData(publisherHandle, planes[0].getBuffer(), planes[0].getRowStride(),last_image.getWidth(), last_image.getHeight());}last_post_time System.currentTimeMillis();long post_cost_time last_post_time - post_begin_time;if ( post_cost_time 0 post_cost_time 10 ){try {Thread.sleep(10-post_cost_time);} catch (InterruptedException e) {e.printStackTrace();}}/*libPublisher.SmartPublisherOnCaptureVideoRGBAData(publisherHandle, last_buffer, row_stride_,width_, height_);*//*//实际裁剪比例可酌情自行调整int left 100;int cliped_left 0;int top 0;int cliped_top 0;int cliped_width width_;int cliped_height height_;if(scale_rate SCALE_RATE_HALF){cliped_left left / 2;cliped_top top / 2;//宽度裁剪后展示3/4比例cliped_width (width_ *3)/4;//高度不做裁剪cliped_height height_;}else if(scale_rate SCALE_RATE_TWO_FIFTHS){cliped_left left * 2 / 5;cliped_top top * 2 / 5;//宽度裁剪后展示3/4比例cliped_width (width_ *3)/4;//高度不做裁剪cliped_height height_;}if(cliped_width % 2 ! 0){cliped_width cliped_width 1;}if(cliped_height % 2 ! 0){cliped_height cliped_height 1;}if ( (cliped_left cliped_width) width_){Log.e(TAG, invalid cliped region settings, cliped_left: cliped_left cliped_width: cliped_width width: width_);return;}if ( (cliped_top cliped_height) height_){Log.e(TAG, invalid cliped region settings, cliped_top: cliped_top cliped_height: cliped_height height: height_);return;}//Log.i(TAG, clipLeft: cliped_left clipTop: cliped_top clipWidth: cliped_width clipHeight: cliped_height);libPublisher.SmartPublisherOnCaptureVideoClipedRGBAData(publisherHandle, last_buffer, row_stride_,width_, height_, cliped_left, cliped_top, cliped_width, cliped_height );*/// Log.i(TAG, post data: last_post_time cost: post_cost_time);}else{try {Thread.sleep(10);} catch (InterruptedException e) {e.printStackTrace();}}}}if ( last_image ! null){last_image.close();last_image null;}}}关闭采集推送 public void onDestroy() {// TODO Auto-generated method stubLog.i(TAG, Service stopped..);stopScreenCapture();clearAllImages();if( is_post_data_thread_alive post_data_thread ! null ){Log.i(TAG, onDestroy close post_data_thread);is_post_data_thread_alive false;try {post_data_thread.join();} catch (InterruptedException e) {e.printStackTrace();}post_data_thread null;Log.i(TAG, onDestroy post_data_thread closed--);}if (isPushingRtmp || isRecording || isRTSPPublisherRunning){if (audioRecord_ ! null) {Log.i(TAG, surfaceDestroyed, call StopRecording..);audioRecord_.Stop();if (audioRecordCallback_ ! null) {audioRecord_.RemoveCallback(audioRecordCallback_);audioRecordCallback_ null;}audioRecord_ null;}stopPush();isPushingRtmp false;stopRecorder();isRecording false;stopRtspPublisher();isRTSPPublisherRunning false;stopRtspService();isRTSPServiceRunning false;if (publisherHandle ! 0) {if (libPublisher ! null) {libPublisher.SmartPublisherClose(publisherHandle);publisherHandle 0;}}}libPublisher.UnInitRtspServer();super.onDestroy();}
以上就是Android平台数据采集、编码并推送的大概流程感兴趣的开发者可参考下。