MediaCodec硬編碼成H264視訊流
android提供了一個強大的編解碼類MediaCodec,可以實現對視訊資料的編解碼,下面講一下如何對原始視訊資料硬編碼成h264格式的流
MediaCodec提供兩種方式的輸入,一種是將資料寫入它的輸入緩衝佇列裡,一種是讓MediaCodec建立一個輸入Surface,MediaCodec會自動從這個輸入Surface中讀取資料,因為我做的是錄製螢幕的需求,所以我是使用一個Surface輸入資料給MediaCodec。MediaCodec編碼出來的頭兩幀是特殊的,分別是sps 和 pps這兩幀在解碼時要用來配置解碼器用的。下面貼出編碼器程式碼,這裡我做的是視訊實時編碼傳輸,所以編碼後的資料我使用socket傳送的,大家主要還是看看編碼部分的程式碼就好了:
package com.seewo.seewoair.coder;
/**
* @author zhangsutao
* @file VideoCodec.java
* @brief 視訊編解碼器基類
* @date 2016/8/7
*/
public interface VideoCodec {
String MIME_TYPE = "video/avc";
int VIDEO_FRAME_PER_SECOND = 15;
int VIDEO_I_FRAME_INTERVAL = 5;
int VIDEO_BITRATE = 500 * 8 * 1000;
}
/** * @author zhangsutao * @file VideoEncoder.java * @brief 視訊編碼器 * @date 2016/7/29 */ public class VideoEncoder implements VideoCodec { private Worker mWorker; private MediaProjection mMediaProjection; private VirtualDisplay mVirtualDisplay; private Client mClient; //寫入本地的流,在除錯的時候使用 private DataOutputStream mOutput; private final boolean isDebug=true; private final String TAG="VideoEncoder"; private byte[] mFrameByte; public VideoEncoder(MediaProjection mediaProjection,Client client) { mClient=client; mMediaProjection=mediaProjection; if(isDebug){ try { mOutput=new DataOutputStream(new FileOutputStream(new File("/sdcard/h264encode")));; } catch (FileNotFoundException e) { e.printStackTrace(); } } } protected void onSurfaceCreated(Surface surface, int mWidth, int mHeight) { //將螢幕資料與surface進行關聯 mVirtualDisplay = mMediaProjection.createVirtualDisplay("-display", mWidth, mHeight, 1, DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC, surface, null, null); } protected void onSurfaceDestroyed(Surface surface) { mVirtualDisplay.release(); surface.release(); } public void start() { if (mWorker == null) { mWorker = new Worker(); mWorker.setRunning(true); mWorker.start(); } } public void stop() { if (mWorker != null) { mWorker.setRunning(false); mWorker = null; } if(mClient!=null){ if(!mClient.hasRelease()){ mClient.release(); } } } private class Worker extends Thread { private MediaCodec.BufferInfo mBufferInfo; private MediaCodec mCodec; private volatile boolean isRunning; private Surface mSurface; private final long mTimeoutUsec; private int mWidth; private int mHeight; public Worker() { mBufferInfo = new MediaCodec.BufferInfo(); mTimeoutUsec = 10000l; } public void setRunning(boolean running) { isRunning = running; } protected void onEncodedSample(MediaCodec.BufferInfo info, ByteBuffer data) { if(mFrameByte==null||mFrameByte.length<info.size){ mFrameByte=new byte[info.size]; } data.get(mFrameByte,0,info.size); boolean isSuccess1=mClient.sendInt(info.size); boolean isSuccess2=mClient.send(mFrameByte,0,info.size); Log.d(TAG,"sending success:"+isSuccess1+" "+isSuccess2); if(!(isSuccess1&&isSuccess2)){ isRunning=false; mClient.release(); } //在debug時在本地寫一份 if(isDebug){ try { mOutput.writeInt(info.size); mOutput.write(mFrameByte,0,info.size); } catch (IOException e) { e.printStackTrace(); } } } @Override public void run() { if(!prepare()){ isRunning=false; } while (isRunning) { encode(); } release(); } void encode() { if (!isRunning) { //編碼結束,傳送結束訊號,讓surface不在提供資料 mCodec.signalEndOfInputStream(); } int status = mCodec.dequeueOutputBuffer(mBufferInfo, mTimeoutUsec); if (status == MediaCodec.INFO_TRY_AGAIN_LATER) { return; } else if (status >= 0) { ByteBuffer data = mCodec.getOutputBuffer(status); if (data != null) { final int endOfStream = mBufferInfo.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM; //傳遞編碼資料 if (endOfStream == 0) { onEncodedSample(mBufferInfo, data); } // 一定要記得釋放 mCodec.releaseOutputBuffer(status, false); if (endOfStream == MediaCodec.BUFFER_FLAG_END_OF_STREAM){ return; } } } } private void release() { onSurfaceDestroyed(mSurface); if(mCodec!=null){ mCodec.stop(); mCodec.release(); } if(mOutput!=null){ try { mOutput.close(); } catch (IOException e) { e.printStackTrace(); } } } private boolean prepare() { // configure video output mWidth= SpUtils.readInt(Constans.KEY_DEVICE_WIDTH,-1); mHeight=SpUtils.readInt(Constans.KEY_DEVICE_HEIGHT,-1); if(mWidth==-1||mHeight==-1){ return false; } mClient.connectToServer(); //傳送寬高 boolean isSuccess1=mClient.sendInt(mWidth); boolean isSuccess2=mClient.sendInt(mHeight); if(!(isSuccess1&&isSuccess2)){ isRunning=false; mClient.release(); } MediaFormat format = MediaFormat.createVideoFormat(MIME_TYPE, mWidth, mHeight); format.setInteger(MediaFormat.KEY_COLOR_FORMAT, MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface); format.setInteger(MediaFormat.KEY_BIT_RATE, VIDEO_BITRATE); format.setInteger(MediaFormat.KEY_FRAME_RATE, VIDEO_FRAME_PER_SECOND); format.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL,VIDEO_I_FRAME_INTERVAL); format.setInteger(MediaFormat.KEY_REPEAT_PREVIOUS_FRAME_AFTER,40); try { mCodec = MediaCodec.createEncoderByType(MIME_TYPE); } catch (IOException e) { e.printStackTrace(); return false; } mCodec.configure(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE); //建立關聯的輸入surface mSurface = mCodec.createInputSurface(); mCodec.start(); onSurfaceCreated(mSurface,mWidth,mHeight); return true; } } }
相關推薦
MediaCodec硬編碼成H264視訊流
android提供了一個強大的編解碼類MediaCodec,可以實現對視訊資料的編解碼,下面講一下如何對原始視訊資料硬編碼成h264格式的流 MediaCodec提供兩種方式的輸入,一種是將資料寫入它的輸入緩衝佇列裡,一種是讓MediaCodec建立一個輸入Surface
Android使用MediaCodec硬解碼播放H264格式視訊檔案
前些時間,通過各種搜尋加請教了好幾個同行的朋友,在他們的指點下實現: RTSP+H264實時視訊播放播放及把實時視訊流儲存到手機SD卡中,再對儲存的H264格式檔案進行播放等基本功能。 非常感謝這些朋友的無私幫忙,在實現功能的同時,我也把他們提供的一
YUV資料流編碼成H264
自己使用ffmpeg進行編碼,在網上搜索到了雷霄驊大神,他的部落格內幾乎全是關於ffmpeg的,內容很全面,不過ffmpeg更新很快,他部落格上的有些程式碼,不太適合了。 但是,他提供了更新後的程式碼,自己使用的是如下的程式碼例子,地址在最後面。 檔案中有兩個例子,我都實驗
【Android】Android Camera實時資料採集及通過MediaCodec硬編碼編碼資料的流程
// video device. private Camera camera; private MediaCodec vencoder; private MediaCodecInfo vmci; private MediaCodec.BufferInfo vebi; private byte[] vbuff
android硬編碼h264資料,並使用rtp推送資料流,實現一個簡單的直播-MediaCodec(一)
寫在前面:我並非專業做流媒體的coder,對流媒體行業無比崇拜,只是做了幾年安卓車載ROM,對安卓AV開發算是略懂。本篇部落格是我對MediaCodec編解碼和rtp推流的一次嘗試,希望能給有需要的朋友一些細微的幫助,不喜勿噴,如果有不對的地方希望大神指正共
Android 利用MediaCodec 實現硬編碼 h264
本篇文章記錄一下,Android呼叫mediacodec編碼camera回掉的YUV資料為h264的方法。 由於公司需要,軟編碼(X264)由於手機效能的瓶頸,已不能滿足要求,所以決定使用硬編碼。其實硬編碼最早用過MediaRecord,但是不能直接得到h2
ios 視頻流H264硬編碼---分解LFLiveKit
header count enable api osc center dealloc using 默認 #import "LFHardwareVideoEncoder.h" #import <VideoToolbox/VideoToolbox.h> @int
H264視訊編碼成MP4檔案
最近需要將H264視訊編碼成MP4格式。研究了一下,一種方法是採用ffmpeg庫,可以先將H264檔案解碼,再編碼生成MP4檔案,但這種方式效率較低,10M的視訊可能需要幾秒鐘才能完成。另一種方式根據MP4檔案協議直接將H264包封裝成MP4格式,由於是直接
1小時學會:最簡單的iOS直播推流(七)h264/aac 硬編碼
最簡單的iOS 推流程式碼,視訊捕獲,軟編碼(faac,x264),硬編碼(aac,h264),美顏,flv編碼,rtmp協議,陸續更新程式碼解析,你想學的知識這裡都有,願意懂直播技術的同學快來看!! 前面已經介紹瞭如何從硬體裝置獲取到音視
iOS h264硬編碼
從這裡抄過來的:https://github.com/LevyGG/iOS-H.264-hareware-encode-and-decode/blob/master/VTDemoOniPad/H264HwEncoderImpl.h #import<Founda
Android手機的h264硬編碼測試
網上原始碼進行點小改動, 程式碼如下: /** * oppo r7s(android 4.4.4)測試通過, 紅米3(android 5.1.1)測試未通過 * @author Administrator */ @SuppressLint("NewApi") pub
嵌入式 視頻編碼(H264)hi3518
過程 abs rbsp 狀態 hive pty xheditor dev 錯誤碼 這幾天在編寫視頻錄制模塊,所以,閑暇之余,又粗粗的整理了一下,主要是API,以備不時之用 攝像頭獲取的模擬信號通過經芯片處理(我們使用的是CX25825),將模擬信號轉成數字信號
【GPU編解碼】GPU硬編碼
cuda 說明 閱讀 cnblogs itl href ble con info 【GPU編解碼】GPU硬編碼 一、OpenCV中的硬編碼 OpenCV2.4.6中,已實現利用GPU進行寫視頻,編碼過程由cv::gpu::VideoWriter_GPU完成,其示例程序如
H.264硬編碼&硬解碼
firefly rk3288 h.264編解碼 開源硬件 網絡攝像頭 Firefly-RK3288擁有強大的VPU(視像處理器),能夠流暢實現720P和1080P視頻的H.264編解碼;而H.264的壓縮率更高,可以更大程度更小視頻的空間占用。 詳細看視頻演示 1. 演示介紹基於Firef
iOS平臺上音頻編碼成aac
AudioConverter pcm aac 硬編碼 小程之前介紹解碼aac時,曾經使用了fadd,並且有提到,如果想編碼成aac格式,可以使用facc、fdk-aac等,但使用fdk-aac等編碼方式,都是軟編碼,在cpu的消耗上會明顯大於硬件編碼。 硬編碼的優勢是可以用硬件芯片集成的功能,
Fortify漏洞之Dynamic Code Evaluation: Code Injection(動態腳本註入)和 Password Management: Hardcoded Password(密碼硬編碼)
mys info 用戶輸入 strong 獲取 center 連接數 密碼 new 繼續對Fortify的漏洞進行總結,本篇主要針對 Dynamic Code Evaluation: Code Injection(動態腳本註入) 和 Password Manageme
基於FFmpeg-4.0 SDK的PCM編碼成AAC
1. 初始化 AVCodecContext *m_avctx; AVCodec *m_codec; /* Init ffmpeg log */ ffmpeg_log_callback pcb_log = l
PS流解複用成H264和音訊流(ES提取)
技術在於交流、溝通,轉載請註明出處並保持作品的完整性。 原文:https://blog.csdn.net/hiwubihe/article/details/80759142 [本系列相關文章] H264和音訊流打包成PS流 (MPEG2-PS
硬編碼與軟編碼
硬編碼:就是將資料直接寫入到程式碼中進行編譯開發,比如在沒有mybatits前,將sql語句寫入到jdbc程式碼裡,在比如純jsp開發的過程中,將前端的html程式碼與java程式碼耦合,這都是應編碼,如果要發生更改的問題,就需要更改原始碼,如果是C/S開發,就直接一位這,客戶端的軟體需
使用MediaCodec硬解碼h.265視訊及音訊進行播放
h.265這個視訊是很多播放器不支援的,就算是bilibili開源的ijkplayer也不能直接播放,需要自己去重新編譯 才可以支援。 這裡通過這個demo來演示一下如何硬解碼視訊,播放h.265視訊,其實編碼的視訊同樣道理。 視訊的播放主要在surfaceView中顯示,而解碼