小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

RTMP推流組件EasyRTMP實(shí)現(xiàn)內(nèi)網(wǎng)攝像頭RTSP拉流轉(zhuǎn)碼RTMP推流到RTMP服務(wù)器之Android版屏幕推流方法及其注意點(diǎn)

 印度阿三17 2019-09-11

Real Time Messaging Protocol(RTMP)即實(shí)時消息傳輸協(xié)議,是 Adobe 公司開發(fā)的一個基于 TCP 的應(yīng)用層協(xié)議,目前國內(nèi)的視頻云服務(wù)都是以 RTMP 為主要推流協(xié)議。

關(guān)于RTMP推流組件

EasyRTMP是一套調(diào)用簡單、功能完善、運(yùn)行高效穩(wěn)定的RTMP推流功能組件,經(jīng)過多年客戶實(shí)戰(zhàn)和線上運(yùn)行打造,支持RTMP推送斷線重連、環(huán)形緩沖、智能丟幀、網(wǎng)絡(luò)事件回調(diào),支持Windows、Linux、ARM、Android、iOS平臺,支持市面上絕大部分的RTMP流媒體服務(wù)器,能夠完美應(yīng)用于各種行業(yè)的直播需求,手機(jī)直播、桌面直播、攝像機(jī)直播、課堂直播等方面。結(jié)合EasyDSS流媒體服務(wù)器,為開發(fā)者提供專業(yè)、穩(wěn)定的直播推流、轉(zhuǎn)碼、分發(fā)服務(wù),全面滿足低超低延遲、超高畫質(zhì)、超大并發(fā)訪問量的要求。

EasyRTMP

EasyRTMP-Android介紹屏幕推流及其注意點(diǎn)

解決問題

1、錄屏

VirtualDisplay類代表一個虛擬顯示器,需要調(diào)用DisplayManager 類的 createVirtualDisplay()方法,將虛擬顯示器的內(nèi)容渲染在一個Surface控件上,當(dāng)進(jìn)程終止時虛擬顯示器會被自動的釋放,并且所有的Window都會被強(qiáng)制移除。當(dāng)不再使用時,需要調(diào)用release() 方法來釋放資源。

1)獲取MediaProjectionManager實(shí)例

	mMpmngr = (MediaProjectionManager) getApplicationContext()
					.getSystemService(MEDIA_PROJECTION_SERVICE);

2)在Android 6.0后,Android需要動態(tài)獲取權(quán)限,若沒有權(quán)限,則不啟用該service:

	if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
		if (!Settings.canDrawOverlays(this)) {
			return;
		}
	}

3)MediaProjection是Android5.0后才開放的屏幕采集接口,通過系統(tǒng)級服務(wù)MediaProjectionManager進(jìn)行管理。

if (mMpj == null) {
		mMpj = mMpmngr.getMediaProjection(StreamActivity.mResultCode, 
												StreamActivity.mResultIntent);
		StreamActivity.mResultCode = 0;
		StreamActivity.mResultIntent = null;
	}

4)通過MediaProjection對象的createVirtualDisplay方法,拿到VirtureDisplay對象,拿這個對象的時候,需要把Surface對象傳進(jìn)去,Surface是由MediaCodec獲得。

	mVirtualDisplay = mMpj.createVirtualDisplay(
	                "record_screen",
	                windowWidth,
	                windowHeight,
	                screenDensity,
	                DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR | DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC | DisplayManager.VIRTUAL_DISPLAY_FLAG_PRESENTATION,
	                mSurface,
	                null,
	                null);

2、編碼及推流

使用Android硬編碼MediaCodec,將VirtualDisplay獲取到的視頻數(shù)據(jù)編碼后通過EasyRTMP推送出去。

1)初始化MediaCodec,同時獲取Surface對象,并啟動編碼器

	mMediaCodec = MediaCodec.createByCodecName(ci.mName);
	MediaFormat mediaFormat = MediaFormat.createVideoFormat("video/avc", 
												windowWidth, windowHeight);
	mediaFormat.setInteger(MediaFormat.KEY_BIT_RATE, bitrate);
	mediaFormat.setInteger(MediaFormat.KEY_FRAME_RATE, 15);
	mediaFormat.setInteger(MediaFormat.KEY_COLOR_FORMAT, 
					MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface);
	mediaFormat.setInteger(MediaFormat.KEY_REPEAT_PREVIOUS_FRAME_AFTER, 
					20000000);
	mediaFormat.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 1);
	mediaFormat.setInteger(MediaFormat.KEY_CHANNEL_COUNT, 1);
	mMediaCodec.configure(mediaFormat, null, null, 
							MediaCodec.CONFIGURE_FLAG_ENCODE);
	// 獲取Surface對象
	mSurface = mMediaCodec.createInputSurface();
	mMediaCodec.start();

2)音頻編碼的工作直接使用AudioStream,

	final AudioStream audioStream = 
		AudioStream.getInstance(EasyApplication.getEasyApplication(), 
	SPUtil.getEnableAudio(EasyApplication.getEasyApplication()));

3)啟動編碼線程,不停的將獲取的音頻幀和視頻幀,編碼并推流。詳情見代碼注釋:

	// 啟動線程,
	mPushThread.start();
	// 初始化推流器
	mEasyPusher = new EasyRTMP(mHevc ? EasyRTMP.VIDEO_CODEC_H265 : 
								EasyRTMP.VIDEO_CODEC_H264, RTMP_KEY);
	// 視頻的硬編碼
	ByteBuffer outputBuffer;
	if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
		outputBuffer = mMediaCodec.getOutputBuffer(outputBufferIndex);
	} else {
		outputBuffer = outputBuffers[outputBufferIndex];
	}
	outputBuffer.position(bufferInfo.offset);
	outputBuffer.limit(bufferInfo.offset   bufferInfo.size);
	try {
		boolean sync = false;
		if ((bufferInfo.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) != 0) {
			sync = (bufferInfo.flags&MediaCodec.BUFFER_FLAG_SYNC_FRAME)!=0;
			if (!sync) {
				byte[] temp = new byte[bufferInfo.size];
				outputBuffer.get(temp);
				mPpsSps = temp;
				continue;
			} else {
				mPpsSps = new byte[0];
			}
		}
		sync |= (bufferInfo.flags & MediaCodec.BUFFER_FLAG_SYNC_FRAME) != 0;
		int len = mPpsSps.length   bufferInfo.size;
		if (len > h264.length) {
			h264 = new byte[len];
		}
		
	// 將編碼后的視頻數(shù)據(jù)發(fā)送出去
	if (sync) {
		System.arraycopy(mPpsSps, 0, h264, 0, mPpsSps.length);
		outputBuffer.get(h264, mPpsSps.length, bufferInfo.size);
		mEasyPusher.push(h264, 0, mPpsSps.length   bufferInfo.size, bufferInfo.presentationTimeUs / 1000, 2);
	} else {
		outputBuffer.get(h264, 0, bufferInfo.size);
		mEasyPusher.push(h264, 0, bufferInfo.size, 		bufferInfo.presentationTimeUs / 1000, 1);
	}
來源:https://www./content-4-448351.html

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多