自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

刷抖音看美腿中毒后,我決定做一款抖音App

開發(fā) 架構(gòu) 開發(fā)工具
當(dāng)下抖音非常火熱,你是不是也很心動(dòng)做一個(gè)類似的 App?

 當(dāng)下抖音非常火熱,你是不是也很心動(dòng)做一個(gè)類似的 App?

[[268595]]

 

短視頻內(nèi)容生產(chǎn)

優(yōu)質(zhì)短視頻內(nèi)容的產(chǎn)生依賴于短視頻的采集和特效編輯,這就要求在進(jìn)行抖音 App 開發(fā)時(shí),用到基礎(chǔ)的美顏、混音、濾鏡、變速、圖片視頻混剪、字幕等功能。

在這些功能基礎(chǔ)上,進(jìn)行預(yù)處理,結(jié)合 OpenGL、AI、AR 技術(shù),產(chǎn)生很多有趣的動(dòng)態(tài)貼紙玩法,使得短視頻內(nèi)容更具創(chuàng)意。

 

視頻錄制的大致實(shí)現(xiàn)流程是先由 Camera 、 AudioRecord 進(jìn)行最原始的相機(jī)畫面以及聲音的采集,然后將采集的數(shù)據(jù)進(jìn)行濾鏡、降噪等前處理,處理完成后由 MediaCodec 進(jìn)行硬件編碼,***采用 MediaMuxer 生成最終的 MP4 文件。

短視頻處理播放

視頻的處理和播放主要是視頻的清晰度、觀看流暢度方面的體驗(yàn)。在這方面來講,可以采用“窄帶高清”技術(shù),在節(jié)省碼率的同時(shí)能夠提供更加清晰的觀看體驗(yàn),經(jīng)過測(cè)試,同等視頻質(zhì)量下***可以節(jié)省 20-40% 帶寬。

除了帶寬之外,短視頻內(nèi)容的存儲(chǔ)和 CDN 優(yōu)化也尤為重要,通常我們需要上傳到云存儲(chǔ)服務(wù)器的內(nèi)容是短視頻內(nèi)容和封面內(nèi)容。

而 CDN 優(yōu)化帶給短視頻平臺(tái)的則是進(jìn)一步的短視頻***載入和循環(huán)播放方面的體驗(yàn)。

比如針對(duì)首播慢的問題,像阿里云播放器支持 QUIC 協(xié)議,基于 CDN 的調(diào)度,可以使短視頻***播放秒開的成功率達(dá)到 98%。

此外在循環(huán)播放時(shí)還可以邊播放邊緩存,用戶反復(fù)觀看某一短視頻時(shí)就不用耗費(fèi)流量了。

錄制視頻的方式

在 Android 系統(tǒng)當(dāng)中,如果需要一臺(tái) Android 設(shè)備來獲取到一個(gè) MP4 這樣的視頻文件的話,主流的方式一共與三種:

  • MediaRecorder
  • MediaCodec+MediaMuxer
  • FFmpeg

MediaRecorder:是 Android 系統(tǒng)直接提供給我們的錄制類,用于錄制音頻和視頻的一個(gè)類,簡(jiǎn)單方便。

它不需要理會(huì)中間錄制過程,結(jié)束錄制后可以直接得到音頻文件進(jìn)行播放,錄制的音頻文件是經(jīng)過壓縮的,需要設(shè)置編碼器,錄制的音頻文件可以用系統(tǒng)自帶的播放器播放。

優(yōu)點(diǎn):大部分以及集成,直接調(diào)用相關(guān)接口即可,代碼量小,簡(jiǎn)單穩(wěn)定;缺點(diǎn):無法實(shí)時(shí)處理音頻;輸出的音頻格式不是很多。

MediaCodec+MediaMuxer:MediaCodec 與 MediaMuxer 結(jié)合使用同樣能夠?qū)崿F(xiàn)錄制的功能。

MediaCodec 是 Android 提供的編解碼類,MediaMuxer 則是復(fù)用類(生成視頻文件)。

從易用性的角度上來說肯定不如 MediaRecorder,但是允許我們進(jìn)行更加靈活的操作,比如需要給錄制的視頻添加水印等各種效果。

優(yōu)點(diǎn): 與 MediaRecorder 一樣低功耗速度快,并且更加靈活;缺點(diǎn): 支持的格式有限,兼容性問題。

FFmpeg:FFmpeg(Fast forword mpeg,音視頻轉(zhuǎn)換器)是一個(gè)開源免費(fèi)跨平臺(tái)的視頻和音頻流方案,它提供了錄制/音視頻編解碼、轉(zhuǎn)換以及流化音視頻的完整解決方案。

主要的作用在于對(duì)多媒體數(shù)據(jù)進(jìn)行解協(xié)議、解封裝、解碼以及轉(zhuǎn)碼等操作。

優(yōu)點(diǎn):格式支持非常的強(qiáng),十分的靈活,功能強(qiáng)大,兼容性好;缺點(diǎn):C語言些的音視頻編解碼程序,使用起來不是很方便。

雖然從數(shù)據(jù)看來 FFmpeg 是***的,但是我們得首先排除這種,因?yàn)樗囊子眯允亲畈畹摹?/p>

其次,MediaRecorder 也是需要排除的,所以在這里我比較推薦 MediaCodec+MediaMuxer 這種方式。

 

編碼器參數(shù)

碼率:數(shù)據(jù)傳輸時(shí)單位時(shí)間傳送的數(shù)據(jù)位數(shù),KBPS:千位每秒。碼率和質(zhì)量成正比,也和文件體積成正比。碼率超過一定數(shù)值,對(duì)圖像的質(zhì)量沒有多大的影響。

幀數(shù):每秒顯示多少個(gè)畫面,F(xiàn)PS。

關(guān)鍵幀間隔:在 H.264 編碼中,編碼后輸出的壓縮圖像數(shù)據(jù)有多種,可以簡(jiǎn)單的分為關(guān)鍵幀和非關(guān)鍵幀。

關(guān)鍵幀能夠進(jìn)行獨(dú)立解碼,看成是一個(gè)圖像經(jīng)過壓縮的產(chǎn)物。而非關(guān)鍵幀包含了與其他幀的“差異”信息,也可以稱呼為“參考幀”,它的解碼需要參考關(guān)鍵幀才能夠解碼出一個(gè)圖像。非關(guān)鍵幀擁有更高的壓縮率。

MediaCodec+MediaMuxer 的使用

MediaMuxer 和 MediaCodec 這兩個(gè)類,它們的參考文:

  • http://developer.android.com/reference/android/media/MediaMuxer.html
  • http://developer.android.com/reference/android/media/MediaCodec.html

里邊有使用的框架。這個(gè)組合可以實(shí)現(xiàn)很多功能,比如音視頻文件的編輯(結(jié)合 MediaExtractor),用 OpenGL 繪制 Surface 并生成 MP4 文件,屏幕錄像以及類似 Camera App 里的錄像功能(雖然這個(gè)用 MediaRecorder 更合適)等。

它們一個(gè)是生成視頻,一個(gè)生成音頻,這里把它們結(jié)合一下,同時(shí)生成音頻和視頻。

基本框架和流程如下:

 

首先是錄音線程,主要參考 HWEncoderExperiments。通過 AudioRecord 類接收來自麥克風(fēng)的采樣數(shù)據(jù),然后丟給 Encoder 準(zhǔn)備編碼:

  1. AudioRecord audio_recorder;  
  2. audio_recorder = new AudioRecord(MediaRecorder.AudioSource.MIC,  
  3.  SAMPLE_RATE, CHANNEL_CONFIG, AUDIO_FORMAT, buffer_size);  
  4. // ...  
  5. audio_recorder.startRecording();  
  6. while (is_recording) {  
  7.  byte[] this_buffer = new byte[frame_buffer_size];  
  8.  read_result = audio_recorder.read(this_buffer, 0, frame_buffer_size); // read audio raw data  
  9.  // …  
  10.  presentationTimeStamp = System.nanoTime() / 1000;  
  11.  audioEncoder.offerAudioEncoder(this_buffer.clone(), presentationTimeStamp); // feed to audio encoder  
  12.  
  13. }  

這里也可以設(shè)置 AudioRecord 的回調(diào)(通過 setRecordPositionUpdateListener())來觸發(fā)音頻數(shù)據(jù)的讀取。

offerAudioEncoder() 里主要是把 Audio 采樣數(shù)據(jù)送入音頻 MediaCodec 的 InputBuffer 進(jìn)行編碼:

  1. ByteBuffer[] inputBuffers = mAudioEncoder.getInputBuffers();  
  2. int inputBufferIndex = mAudioEncoder.dequeueInputBuffer(-1);  
  3. if (inputBufferIndex >= 0) {  
  4.  ByteBuffer inputBuffer = inputBuffers[inputBufferIndex];  
  5.  inputBuffer.clear();  
  6.  inputBuffer.put(this_buffer);  
  7.  ...  
  8.  mAudioEncoder.queueInputBuffer(inputBufferIndex, 0, this_buffer.length, presentationTimeStamp, 0);  
  9. }  

下面,參考 Grafika-SoftInputSurfaceActivity,并加入音頻處理。主循環(huán)大體分四部分:

  1. try {  
  2.  // Part 1  
  3.  prepareEncoder(outputFile);  
  4.  ...  
  5.  // Part 2  
  6.  for (int i = 0; i < NUM_FRAMES; i++) {  
  7.  generateFrame(i);  
  8.  drainVideoEncoder(false);  
  9.  drainAudioEncoder(false);  
  10.  }  
  11.  // Part 3  
  12.  ...  
  13.  drainVideoEncoder(true);  
  14.  drainAudioEncoder(true);  
  15. } catch (IOException ioe) {  
  16.  throw new RuntimeException(ioe);  
  17. } finally {  
  18.  // Part 4  
  19.  releaseEncoder();  
  20. }  

第 1 部分是準(zhǔn)備工作,除了 Video 的 MediaCodec,這里還初始化了 Audio 的 MediaCodec:

  1. MediaFormat audioFormat = new MediaFormat();  
  2. audioFormat.setInteger(MediaFormat.KEY_SAMPLE_RATE, 44100);  
  3. audioFormat.setInteger(MediaFormat.KEY_CHANNEL_COUNT, 1);  
  4. ...  
  5. mAudioEncoder = MediaCodec.createEncoderByType(AUDIO_MIME_TYPE);  
  6. mAudioEncoder.configure(audioFormat, nullnull, MediaCodec.CONFIGURE_FLAG_ENCODE);  
  7. mAudioEncoder.start();  

第 2 部分進(jìn)入主循環(huán),App 在 Surface 上直接繪圖,由于這個(gè) Surface 是從 MediaCodec 中用 createInputSurface() 申請(qǐng)來的,所以畫完后不用顯式用 queueInputBuffer() 交給 Encoder。

drainVideoEncoder() 和 drainAudioEncoder() 分別將編碼好的音視頻從 Buffer 中拿出來(通過 dequeueOutputBuffer()),然后交由 MediaMuxer 進(jìn)行混合(通過 writeSampleData())。

注意音視頻通過 PTS(Presentation Time Stamp,決定了某一幀的音視頻數(shù)據(jù)何時(shí)顯示或播放)來同步,音頻的 time stamp 需在 AudioRecord 從 MIC 采集到數(shù)據(jù)時(shí)獲取并放到相應(yīng)的 bufferInfo 中。

視頻由于是在 Surface 上畫,因此直接用 dequeueOutputBuffer() 出來的 bufferInfo 中的就行,***將編碼好的數(shù)據(jù)送去 MediaMuxer 進(jìn)行多路混合。

注意這里 Muxer 要等把 audio track 和 video track 都加入了再開始。

MediaCodec 在一開始調(diào)用 dequeueOutputBuffer() 時(shí)會(huì)返回一次 INFO_OUTPUT_FORMAT_CHANGED消息。

我們只需在這里獲取該 MediaCodec 的 format,并注冊(cè)到 MediaMuxer 里。

接著判斷當(dāng)前 audio track 和 video track 是否都已就緒,如果是的話就啟動(dòng) Muxer。

總結(jié)來說,drainVideoEncoder() 的主邏輯大致如下,drainAudioEncoder 也是類似的,只是把 video 的 MediaCodec 換成 audio 的 MediaCodec 即可:

  1. while(true) {  
  2.  int encoderStatus = mVideoEncoder.dequeueOutputBuffer(mBufferInfo, TIMEOUT_USEC);  
  3.  if (encoderStatus == MediaCodec.INFO_TRY_AGAIN_LATER) {  
  4.  ...  
  5.  } else if (encoderStatus == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) {  
  6.  encoderOutputBuffers = mVideoEncoder.getOutputBuffers();  
  7.  } else if (encoderStatus == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {  
  8.  MediaFormat newFormat = mAudioEncoder.getOutputFormat();  
  9.  mAudioTrackIndex = mMuxer.addTrack(newFormat);  
  10.  mNumTracksAdded++;  
  11.  if (mNumTracksAdded == TOTAL_NUM_TRACKS) {  
  12.  mMuxer.start();  
  13.  }  
  14.  } else if (encoderStatus < 0) {  
  15.  ...  
  16.  } else {  
  17.  ByteBuffer encodedData = encoderOutputBuffers[encoderStatus];  
  18.  ...  
  19.  if (mBufferInfo.size != 0) {  
  20.  mMuxer.writeSampleData(mVideoTrackIndex, encodedData, mBufferInfo);  
  21.  }  
  22.  mVideoEncoder.releaseOutputBuffer(encoderStatus, false);  
  23.  if ((mBufferInfo.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {  
  24.  break;  
  25.  }  
  26.  }  
  27.  
  28. }  

第 3 部分是結(jié)束錄制,發(fā)送 EOS 信息,這樣在 drainVideoEncoder() 和 drainAudioEncoder 中就可以根據(jù) EOS 退出內(nèi)循環(huán)。

第 4 部分為清理工作。把 audio 和 video 的 MediaCodec,MediaCodec 用的 Surface 及 MediaMuxer 對(duì)象釋放。

***幾點(diǎn)注意:

  • 在 AndroidManifest.xml 里加上錄音權(quán)限,否則創(chuàng)建 AudioRecord 對(duì)象時(shí)鐵定失敗。
  • 音視頻通過 PTS 同步,兩個(gè)的單位要一致。
  • MediaMuxer 的使用要按照 Constructor->addTrack->start->writeSampleData->Stop 的順序。如果既有音頻又有視頻,在 Stop 前兩個(gè)都要 writeSampleData() 過。

總結(jié)

以上就是抖音類 App 的部分內(nèi)容,其中的步驟和過程是我親自實(shí)踐過的,按照上述的過程應(yīng)該都可以正常運(yùn)行,寫這一篇文章花了很多時(shí)間,希望所有看了這篇文章的朋友們都能夠有一定的收獲。

 

 

責(zé)任編輯:武曉燕 來源: 51CTO博客
相關(guān)推薦

2021-06-28 05:19:32

抖音電腦

2022-01-22 07:44:12

抖音PC 版電腦刷抖音

2020-07-13 11:20:21

Python開發(fā)工具

2020-10-27 09:33:39

抖音印度移動(dòng)應(yīng)用

2022-06-06 12:19:08

抖音功耗優(yōu)化Android 應(yīng)用

2020-12-02 09:42:42

PythonApp抖音視頻

2019-03-07 15:04:37

抖音快手同城

2020-08-06 10:09:08

抖音木馬安全隱私

2024-06-13 17:10:16

2020-09-26 22:30:18

開源技術(shù) 數(shù)據(jù)

2021-04-29 05:58:20

微信搖一搖抖音

2019-02-20 10:02:52

抖音小程序音躍球球

2018-06-05 10:54:06

2020-10-12 19:06:06

微信直播快手

2020-12-25 18:40:07

微信支付寶APP

2022-07-20 22:55:39

直播OOM抖動(dòng)

2024-12-25 15:42:39

視頻數(shù)據(jù)實(shí)時(shí)直播

2024-03-12 17:13:51

2022-08-10 08:41:01

Feed 容器維護(hù)管理
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)