本文由陸業聰分享,原題“一文掌握直播技術:實時音視頻采集、編碼、傳輸與播放”,本文進行了排版和內容優化。
1、引言
從游戲、教育、電商到娛樂,直播技術的應用場景無處不在。隨著移動端的網速越來越快,直播技術的普及和發展將更加迅速。
本文詳細介紹了Android端直播技術的全貌,涵蓋了從實時音視頻采集、編碼、傳輸到解碼與播放的各個環節。文章還探討了直播中音視頻同步、編解碼器選擇、傳輸協議以及直播延遲優化等關鍵問題。希望本文能為你提供有關Andriod端直播技術的深入理解和實踐指導。
2、系列文章
本文是系列文章中的第 11 篇,本系列總目錄如下:
3、知識準備
音視頻技術的門檻一直以來都相對較高,如果你對音視頻相關技術的理論知識了解不多,建議務必優先閱讀這幾篇零基礎音視頻入門文章:
- 《零基礎,史上最通俗視頻編碼技術入門》
- 《愛奇藝技術分享:輕松詼諧,講解視頻編解碼技術的過去、現在和將來》
- 《零基礎入門:實時音視頻技術基礎知識全面盤點》
- 《快速掌握11個視頻技術相關的基礎概念》
另外兩篇入門提納式的文章也可以一并閱讀:
- 《寫給小白的實時音視頻技術入門提綱》
- 《福利貼:最全實時音視頻開發要用到的開源工程匯總》
以上資料學習完成后,再回頭來閱讀本篇效果會更好一點。
4、實時音視頻采集
4.1音視頻采集設備與API
在 Android 設備中,音視頻的采集主要依賴于攝像頭和麥克風這兩個硬件設備。攝像頭負責圖像的采集,麥克風則負責音頻的采集。
為了調用這兩個設備,Android 提供了 Camera API 和 AudioRecord API。通過這兩個 API,我們可以方便地控制設備,獲取音視頻數據。
以下是具體實踐步驟。
1)使用 Camera 或 Camera2 API 來調用攝像頭:
// Camera API
Camera camera = Camera.open();
Camera.Parameters parameters = camera.getParameters();
parameters.setPreviewSize(width, height);
camera.setParameters(parameters);
camera.setPreviewCallback(previewCallback);
camera.startPreview();
// Camera2 API
CameraManager cameraManager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);
String cameraId = cameraManager.getCameraIdList()[0];
CameraCharacteristics characteristics = cameraManager.getCameraCharacteristics(cameraId);
StreamConfigurationMap map = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
Size[] previewSizes = map.getOutputSizes(SurfaceTexture.class);
// 選擇合適的預覽尺寸
cameraManager.openCamera(cameraId, stateCallback, null);
2)使用 AudioRecord API 來調用麥克風:
int bufferSize = AudioRecord.getMinBufferSize(sampleRate, channelConfig, audioFormat);
AudioRecord audioRecord = new AudioRecord(MediaRecorder.AudioSource.MIC, sampleRate, channelConfig, audioFormat, bufferSize);
audioRecord.startRecording();
4.2音視頻采集參數設置
音視頻采集的質量和流暢度,很大程度上取決于采集參數的設置。這些參數包括分辨率、幀率和碼率等。
具體是:
- 1)分辨率:決定了圖像的清晰度。高分辨率可以得到更清晰的圖像,但也會增加數據量,可能導致網絡傳輸壓力增大;
- 2)幀率:決定了視頻的流暢度。高幀率可以得到更流暢的視頻,但同樣會增加數據量;
- 3)碼率:決定了音視頻數據的壓縮程度。高碼率可以得到更高質量的音視頻,但也會增加數據量。
在設置音視頻采集參數時,需要根據網絡狀況和設備性能,做出合適的折衷。
以下是具體實踐步驟。
1)設置攝像頭的分辨率和幀率:
Camera.Parameters parameters = camera.getParameters();
parameters.setPreviewSize(width, height);
parameters.setPreviewFrameRate(frameRate);
camera.setParameters(parameters);
2)設置 AudioRecord 的采樣率、聲道數和音頻格式:
int sampleRate = 44100;
int channelConfig = AudioFormat.CHANNEL_IN_MONO;
int audioFormat = AudioFormat.ENCODING_PCM_16BIT;
4.3音視頻同步與時間戳處理
在直播中,音視頻同步是一個重要的問題。
為了實現同步,我們需要為每幀音視頻數據添加時間戳。時間戳記錄了數據的采集時間,可以用來調整播放順序,保證音視頻的同步。在解碼和播放時,播放器會根據時間戳,正確地排列和播放音視頻數據。
為了處理視頻幀數據和時間戳,我們需要將采集到的音視頻幀數據和對應的時間戳封裝成一個數據結構,然后將這個結構傳遞給編碼器和傳輸模塊。
以下是一個簡單的處理方法。
1)首先,定義一個數據結構來保存音視頻幀數據和時間戳:
public class FrameData {
public byte[] data;
public long timestamp;
public FrameData(byte[] data, long timestamp) {
this.data = data;
this.timestamp = timestamp;
}
}
2)在攝像頭的預覽回調中添加時間戳:
camera.setPreviewCallback(new Camera.PreviewCallback() {
@Override
public void onPreviewFrame(byte[] data, Camera camera) {
long timestamp = System.nanoTime();
// 處理視頻幀數據和時間戳
FrameData frameData = new FrameData(data, timestamp);
// 將 frameData 傳遞給編碼器和傳輸模塊
}
});
3)在 AudioRecord 的錄音循環中添加時間戳:
while (isRecording) {
long timestamp = System.nanoTime();
int bytesRead = audioRecord.read(buffer, 0, bufferSize);
// 處理音頻幀數據和時間戳
FrameData frameData = new FrameData(Arrays.copyOf(buffer, bytesRead), timestamp);
// 將 frameData 傳遞給編碼器和傳輸模塊
}
4)在編碼器和傳輸模塊中,根據FrameData對象的時間戳來處理音視頻幀數據。
例如,在編碼時,將時間戳作為編碼后的音視頻數據的顯示時間;在傳輸時,根據時間戳來調整發送順序和發送速度。
這樣,在解碼和播放時,播放器可以根據時間戳正確地排列和播放音視頻數據,實現同步。
5、音頻編碼
5.1音頻編碼格式對比
常見的音頻編碼格式有 AAC 和 Opus 等。AAC 具有較高的編碼效率,而 Opus 則在實時通信中表現更優。
具體是:
- 1)AAC編碼格式:適用于非實時通信領域,如音樂、廣播、視頻等,具有較高的編碼效率和廣泛的設備兼容性,但在實時通信中的延遲優化較弱;
- 2)Opus編碼格式:適用于實時通信領域,如VoIP、在線會議、游戲語音等,具有高音質、低延遲和強網絡適應性,但設備兼容性相對不如AAC。
5.2在Android中實現音頻編碼
在 Android 中實現音頻編碼,可以使用 Android 提供的 MediaCodec 類。MediaCodec 支持多種音頻編碼格式,如 AAC 和 Opus 等。要選擇合適的編碼格式,可以參考以下步驟。
1)創建一個 MediaCodec 編碼器實例:
MediaCodec audioEncoder = MediaCodec.createEncoderByType(MediaFormat.MIMETYPE_AUDIO_AAC);
2)配置編碼器參數:
MediaFormat audioFormat = MediaFormat.createAudioFormat(MediaFormat.MIMETYPE_AUDIO_AAC, sampleRate, channelCount);
audioFormat.setInteger(MediaFormat.KEY_BIT_RATE, bitRate);
audioFormat.setInteger(MediaFormat.KEY_AAC_PROFILE, MediaCodecInfo.CodecProfileLevel.AACObjectLC);
audioEncoder.configure(audioFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
3)開始編碼:
audioEncoder.start();
6、視頻編碼
6.1視頻編碼格式對比
常見的視頻編碼格式有 H.264、H.265 和 VP8 等。H.264 是當前最常用的編碼格式,而 H.265 和 VP8 則在特定場景下有更好的性能。
具體是:
- 1)H.264編碼格式:適用于視頻會議、網絡直播、視頻分享等場景,具有較高的壓縮效率和廣泛的設備兼容性,但壓縮效率相比H.265較低;
- 2)H.265編碼格式:適用于4K、8K超高清視頻、虛擬現實等需要高分辨率和高畫質的場景,具有極高的壓縮效率,但編解碼復雜度高,需要更強的計算能力,且設備兼容性相對不如H.264;
- 3)VP8編碼格式:適用于網絡視頻通話、在線視頻服務等對開源和免費有要求的場景,延遲低,適合實時通信,但壓縮效率和視頻質量不如H.264和H.265,且設備兼容性較差。
6.2 在Android中實現視頻編碼
在 Android 中實現視頻編碼,同樣可以使用 MediaCodec 類。要選擇合適的編碼格式,可以參考以下步驟。
1)創建一個 MediaCodec 編碼器實例:
MediaCodec videoEncoder = MediaCodec.createEncoderByType(MediaFormat.MIMETYPE_VIDEO_AVC);
2)配置編碼器參數:
MediaFormat videoFormat = MediaFormat.createVideoFormat(MediaFormat.MIMETYPE_VIDEO_AVC, width, height);
videoFormat.setInteger(MediaFormat.KEY_BIT_RATE, bitRate);
videoFormat.setInteger(MediaFormat.KEY_FRAME_RATE, frameRate);
videoFormat.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, iFrameInterval);
videoEncoder.configure(videoFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
3)開始編碼:
videoEncoder.start();
7、硬件編碼與軟件編碼的選擇與優缺點
硬件編碼利用 GPU 進行編碼,性能更高,但兼容性較差;軟件編碼則兼容性更好,但性能較低。在實際應用中,需要根據設備性能和需求進行選擇。
在 Android 中,MediaCodec 類會根據設備性能和需求自動選擇硬件編碼器或軟件編碼器。要強制使用硬件編碼器或軟件編碼器,可以在創建 MediaCodec 實例時,指定編碼器名稱。
例如,要使用硬件 H.264 編碼器,可以使用以下代碼:
MediaCodec videoEncoder = MediaCodec.createByCodecName("OMX.google.h264.encoder");
8、傳輸協議
9、音視頻解碼與播放
9.1音視頻解碼器的選擇與性能優化
解碼器的選擇會影響播放質量和性能。通常,硬件解碼器性能更高,但兼容性較差;軟件解碼器兼容性較好,但性能較低。在實際應用中,需要根據設備性能和需求進行選擇。
在 Android 中,解碼器的選擇可以通過 MediaCodec 類來實現。MediaCodec 支持硬件解碼和軟件解碼,通常情況下,它會根據設備性能和需求自動選擇解碼器。
9.2音視頻渲染與同步策略
在渲染音視頻時,需要保證音視頻同步。可以通過校準時間戳或者調整播放速度等方法實現同步。
在 Android 中,音視頻的渲染可以通過 SurfaceView 或 TextureView 來實現。為了保證音視頻同步,可以在渲染每幀數據時,根據時間戳來調整渲染速度。
以下是具體實踐步驟。
1)創建一個 SurfaceView 或 TextureView:
SurfaceView surfaceView = new SurfaceView(context);
// 或
TextureView textureView = new TextureView(context);
2)在解碼每幀數據時,根據時間戳來調整渲染速度:
long presentationTimeUs = bufferInfo.presentationTimeUs;
long delayUs = presentationTimeUs - System.nanoTime() / 1000;
if (delayUs > 0) {
Thread.sleep(delayUs / 1000);
}
decoder.releaseOutputBuffer(outputBufferIndex, true);
9.3播放器的緩沖與自適應碼率調整
為了應對網絡波動,播放器需要設置合適的緩沖策略。自適應碼率調整則可以根據網絡狀況動態調整視頻質量,以保證流暢度。
在 Android 中,播放器的緩沖策略可以通過 MediaPlayer 或 ExoPlayer 的 API 來設置。自適應碼率調整則可以通過 ExoPlayer 的 TrackSelection API 來實現。
以下是具體實踐步驟。
1)設置播放器的緩沖策略:
MediaPlayer mediaPlayer = new MediaPlayer();
mediaPlayer.setBufferingUpdateListener(new MediaPlayer.OnBufferingUpdateListener() {
@Override
public void onBufferingUpdate(MediaPlayer mp, int percent) {
// 更新緩沖進度
}
});
// 或
ExoPlayer exoPlayer = new SimpleExoPlayer.Builder(context).build();
exoPlayer.setBufferedPositionUpdateListener(new ExoPlayer.BufferedPositionUpdateListener() {
@Override
public void onBufferedPositionUpdate(long bufferedPosition) {
// 更新緩沖進度
}
});
2)設置自適應碼率調整:
TrackSelection.Factory trackSelectionFactory = new AdaptiveTrackSelection.Factory();
DefaultTrackSelector trackSelector = new DefaultTrackSelector(context, trackSelectionFactory);
ExoPlayer exoPlayer = new SimpleExoPlayer.Builder(context).setTrackSelector(trackSelector).build();
10、直播架構概述
10.1直播架構圖
以下是直播架構圖:
解釋一下:
- 1)推流端:需要實現音視頻采集、編碼、傳輸等功能。關鍵組件包括采集模塊、編碼器、傳輸模塊等;
- 2)服務器端:負責接收、轉發和存儲音視頻數據。關鍵組件包括負載均衡、轉碼、錄制等功能模塊;
- 3)拉流端:需要實現音視頻解碼、渲染和播放等功能。關鍵組件包括解碼器、渲染模塊、播放器等。
10.2直播延遲與優化策略
直播延遲會影響用戶體驗。通過優化采集、編碼、傳輸、解碼等環節,可以降低延遲,提高實時性。
直播延遲優化策略有:
- 1)優化采集模塊:提高采集效率,減少數據處理時間;
- 2)優化編碼器:選擇性能更高的編碼器,減少編碼時間;
- 3)優化傳輸模塊:優化網絡傳輸策略,如使用更快的傳輸協議、提高網絡帶寬等;
- 4)優化解碼器:選擇性能更高的解碼器,減少解碼時間;
- 5)優化渲染模塊和播放器:提高渲染效率,減少播放延遲。
11、本文小結
本文介紹了直播技術的全貌,涉及實時音視頻采集到播放的各個環節。
以下是一個簡化的直播流程圖:
直播流程包括以下幾個關鍵環節:
- 1)實時音視頻采集:通過攝像頭和麥克風采集音視頻數據,并進行參數設置和同步處理;
- 2)音視頻編碼:將采集到的音視頻數據進行編碼,以便進行傳輸。選擇合適的編碼器和編碼格式,如AAC、Opus、H.264、H.265和VP8等;
- 3)傳輸協議:選擇合適的傳輸協議,如RTMP、HLS和WebRTC等,以保證音視頻數據的實時傳輸;
- 4)服務器處理:服務器接收、轉發和存儲音視頻數據,進行負載均衡、轉碼和錄制等處理;
- 5)音視頻解碼與播放:將接收到的音視頻數據進行解碼、渲染和播放,實現音視頻同步和延遲優化。
在實際應用中,需要根據需求和場景選擇合適的技術和策略,以實現高質量、低延遲的直播體驗。
12、參考資料
[1] 詳解音頻編解碼的原理、演進和應用選型
[2] 零基礎,史上最通俗視頻編碼技術入門
[3] 理解實時音視頻聊天中的延時問題一篇就夠
[4] 淺談開發實時視頻直播平臺的技術要點
[5] 福利貼:最全實時音視頻開發要用到的開源工程匯總
[6] 愛奇藝技術分享:輕松詼諧,講解視頻編解碼技術的過去、現在和將來
[7] 零基礎入門:實時音視頻技術基礎知識全面盤點
[8] 實時音視頻面視必備:快速掌握11個視頻技術相關的基礎概念
[9] 理論聯系實際:實現一個簡單地基于html]5的實時視頻直播
[10] 實時視頻直播客戶端技術盤點:Native、html]5、WebRTC、微信小程序
[11] Android直播入門實踐:動手搭建一套簡單的直播系統
[12] 視頻直播技術干貨:一文讀懂主流視頻直播系統的推拉流架構、傳輸協議等
[13] 零基礎入門:基于開源WebRTC,從0到1實現實時音視頻聊天功能
[14] 實時音視頻入門學習:開源工程WebRTC的技術原理和使用淺析
[15] 實時音視頻開發理論必備:如何省流量?視頻高度壓縮背后的預測技術
[16] 萬字長文詳解QQ Linux端實時音視頻背后的跨平臺實踐
(本文已同步發布于:http://www.52im.net/thread-4714-1-1.html)