Android硬編驼卖、硬解h264

項(xiàng)目工程demo地址https://github.com/liluojun/PlayVideo

demo包含硬編解h264筏餐、libyuv裁剪圖像、opengles渲染yuv數(shù)據(jù)捂寿、ffmpeg解碼裸h264數(shù)據(jù)等功能口四,故僅供參考測(cè)試。

硬編碼首先設(shè)置編碼器

MediaFormat mediaFormat = MediaFormat.createVideoFormat("video/avc", width, height);

mediaFormat.setInteger(MediaFormat.KEY_COLOR_FORMAT, colorFormat);//色彩空間

mediaFormat.setInteger(MediaFormat.KEY_BIT_RATE, bitrate);//碼率

mediaFormat.setInteger(MediaFormat.KEY_FRAME_RATE, m_framerate);//幀率

mediaFormat.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 2);//I幀間隔

try {

mediaCodec = MediaCodec.createEncoderByType("video/avc");

} catch (Exception e) {

e.printStackTrace();

}

mediaCodec.configure(mediaFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);

mediaCodec.start();//啟動(dòng)編碼器

這塊基本是模板代碼秦陋,編碼器常用的參數(shù)都在這里蔓彩。

喂數(shù)據(jù)編碼,數(shù)據(jù)來(lái)源手機(jī)相機(jī)

public void encoder(byte[] input) {

if (isRuning) {

try {

if (input != null && input.length != 0) {

if (colorFormat <= 20) {

JavaToNativeMethod.getInstence().nv21ToI420(input, yuv420sp, m_width, m_height, yByte, uByte, vByte);

} else {

JavaToNativeMethod.getInstence().nv21ToNv12(input, yuv420sp, m_width, m_height, yByte, uByte, vByte);

}

}

if (!encode) {

return;

}

if (input != null && input.length != 0) {

try {

ByteBuffer[] inputBuffers = mediaCodec.getInputBuffers();

ByteBuffer[] outputBuffers = mediaCodec.getOutputBuffers();

int inputBufferIndex = mediaCodec.dequeueInputBuffer(-1);

Log.e("index", "" + inputBufferIndex);

if (inputBufferIndex >= 0) {

pts = computePresentationTime(generateIndex);

ByteBuffer inputBuffer = inputBuffers[inputBufferIndex];

inputBuffer.clear();

inputBuffer.put(input);

mediaCodec.queueInputBuffer(inputBufferIndex, 0, input.length, pts, 0);

generateIndex += 1;

} else {

return;

}

MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();

int outputBufferIndex = mediaCodec.dequeueOutputBuffer(bufferInfo, TIMEOUT_USEC);

while (outputBufferIndex >= 0) {

UiVideoData u = new UiVideoData();

ByteBuffer outputBuffer = outputBuffers[outputBufferIndex];

byte[] outData = new byte[bufferInfo.size];

outputBuffer.get(outData);

}

bufferInfo = null;

} catch (Exception e) {

Log.e("Encoder", "編碼錯(cuò)誤" + e.getMessage());

}

}

} catch (Exception e) {

e.printStackTrace();

}

}

}

轉(zhuǎn)換數(shù)據(jù)格式我使用的是Android手機(jī)默認(rèn)的nv21格式驳概,但是受到手機(jī)存儲(chǔ)yuv數(shù)據(jù)格式的限制故需要轉(zhuǎn)換格式赤嚼,格式轉(zhuǎn)換用的是libyuv庫(kù),代碼如下:

if (colorFormat <= 20) {

JavaToNativeMethod.getInstence().nv21ToI420(input, yuv420sp, m_width, m_height, yByte, uByte, vByte);

} else {

JavaToNativeMethod.getInstence().nv21ToNv12(input, yuv420sp, m_width, m_height, yByte, uByte, vByte);

}

編碼基本上是模板代碼在 outputBuffer.get(outData);這里outdata就是編碼后的數(shù)據(jù)了顺又。

關(guān)于sps與pps的獲雀洹:

if (spsPpsBuffer.getInt() == 0x00000001) {

byte[] mMediaHead = new byte[outData.length];

System.arraycopy(outData, 0, mMediaHead, 0, outData.length);

configbyte = outData;

mMediaHead = null;

outData = null;

break;

}

在編碼器啟動(dòng)后出的第一個(gè)數(shù)據(jù)就是sps與pps信息。

關(guān)于I幀的判斷:

(outData[4] & 0x1f) == 5

這里我采用的是上面的判定方式稚照,網(wǎng)上也有其他的判定方式如outData[4]==65||outData[4]==25之類的蹂空。

強(qiáng)制I幀有時(shí)候我們會(huì)遇到需要強(qiáng)行出一幀I幀的情況,只需要調(diào)用編碼器的flush()方法即可果录。

硬解碼首先也是設(shè)置解碼器

mediaformat = MediaFormat.createVideoFormat("video/avc", w, h);

mediaformat.setByteBuffer("csd-0", ByteBuffer.wrap(sps));//設(shè)置sps

mediaformat.setByteBuffer("csd-1", ByteBuffer.wrap(pps));//設(shè)置pps

mediaformat.setInteger(MediaFormat.KEY_FRAME_RATE, m_framerate);//幀率

mediaformat.setInteger(MediaFormat.KEY_BIT_RATE, 1024 * 1000);//碼率

mediaformat.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 2);//I幀間隔

mCodec.configure(mediaformat, null, null, 0);//注意第二個(gè)參數(shù)可以填入surface上枕,將解碼數(shù)據(jù)直接渲染,這里我用的自己的渲染故填null

mCodec.start();//啟動(dòng)解碼器

編解碼器的設(shè)置差不多雕憔,只是多了sps和pps的參數(shù)設(shè)定姿骏。

喂數(shù)據(jù)解碼

public void onFrame(UiVideoData uiVideoData) {

byte[] buf = uiVideoData._data;

ByteBuffer[] inputBuffers = mCodec.getInputBuffers();//MediaCodec在此ByteBuffer[]中獲取輸入數(shù)據(jù)

ByteBuffer[] outputBuffers = mCodec.getOutputBuffers(); // 解碼后的數(shù)據(jù)

int inputBufferIndex = mCodec.dequeueInputBuffer(100);//獲取輸入緩沖區(qū)的索引

if (inputBufferIndex >= 0) {

long pts = computePresentationTime(generateIndex);

ByteBuffer inputBuffer = inputBuffers[inputBufferIndex];

inputBuffer.clear();

inputBuffer.put(buf);//先獲取緩沖區(qū),再放入值

mCodec.queueInputBuffer(inputBufferIndex, 0, buf.length, pts, 0);//四個(gè)參數(shù)斤彼,第一個(gè)是輸入緩沖區(qū)的索引分瘦,第二個(gè)是放入的數(shù)據(jù)大小,第三個(gè)是時(shí)間戳琉苇,保證遞增就是

generateIndex += 1;

} else {

return;

}

MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();//用于描述解碼得到的byte[]數(shù)據(jù)的相關(guān)信息

int outputBufferIndex = mCodec.dequeueOutputBuffer(bufferInfo, 1000);//-1代表一直等待嘲玫,0表示不等待

Log.e(TAG, "outputBufferIndex=" + outputBufferIndex);

while (outputBufferIndex >= 0) {//大于等于0表示解碼器有數(shù)據(jù)輸出

ByteBuffer outputBuffer = outputBuffers[outputBufferIndex];

byte[] outData = new byte[bufferInfo.size];

outputBuffer.get(outData);//將Buffer內(nèi)的數(shù)據(jù)取出到字節(jié)數(shù)組中

mCodec.releaseOutputBuffer(outputBufferIndex, true);

outputBufferIndex = -1;

}

}

這里也基本是模板代碼 outputBuffer.get(outData)獲取到解碼后的數(shù)據(jù)然后就可以自己去渲染的。

注:Android硬編硬解受限于設(shè)備并不保證所有設(shè)備都能運(yùn)行成功并扇。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末去团,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子穷蛹,更是在濱河造成了極大的恐慌土陪,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,110評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件肴熏,死亡現(xiàn)場(chǎng)離奇詭異鬼雀,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)蛙吏,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,443評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門源哩,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)鞋吉,“玉大人,你說(shuō)我怎么就攤上這事励烦∥阶牛” “怎么了?”我有些...
    開封第一講書人閱讀 165,474評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵坛掠,是天一觀的道長(zhǎng)赊锚。 經(jīng)常有香客問(wèn)我,道長(zhǎng)屉栓,這世上最難降的妖魔是什么改抡? 我笑而不...
    開封第一講書人閱讀 58,881評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮系瓢,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘句灌。我一直安慰自己夷陋,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,902評(píng)論 6 392
  • 文/花漫 我一把揭開白布胰锌。 她就那樣靜靜地躺著骗绕,像睡著了一般。 火紅的嫁衣襯著肌膚如雪资昧。 梳的紋絲不亂的頭發(fā)上酬土,一...
    開封第一講書人閱讀 51,698評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死州藕,一個(gè)胖子當(dāng)著我的面吹牛驶赏,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播黎茎,決...
    沈念sama閱讀 40,418評(píng)論 3 419
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了虎眨?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,332評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤镶摘,失蹤者是張志新(化名)和其女友劉穎嗽桩,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體凄敢,經(jīng)...
    沈念sama閱讀 45,796評(píng)論 1 316
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡碌冶,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,968評(píng)論 3 337
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了贡未。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片种樱。...
    茶點(diǎn)故事閱讀 40,110評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡蒙袍,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出嫩挤,到底是詐尸還是另有隱情害幅,我是刑警寧澤,帶...
    沈念sama閱讀 35,792評(píng)論 5 346
  • 正文 年R本政府宣布岂昭,位于F島的核電站以现,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏约啊。R本人自食惡果不足惜邑遏,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,455評(píng)論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望恰矩。 院中可真熱鬧记盒,春花似錦、人聲如沸外傅。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,003評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)萎胰。三九已至碾盟,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間技竟,已是汗流浹背冰肴。 一陣腳步聲響...
    開封第一講書人閱讀 33,130評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留榔组,地道東北人熙尉。 一個(gè)月前我還...
    沈念sama閱讀 48,348評(píng)論 3 373
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像瓷患,于是被迫代替她去往敵國(guó)和親骡尽。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,047評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容

  • 3擅编、使用 MediaCodec創(chuàng)建之后攀细,需要通過(guò)start()方法進(jìn)行開啟。MediaCodec有輸入緩沖區(qū)隊(duì)列和...
    韓瞅瞅閱讀 1,307評(píng)論 0 1
  • 打包 視音頻在傳輸過(guò)程中需要定義相應(yīng)的格式爱态,這樣傳輸?shù)綄?duì)端的時(shí)候才能正確地被解析出來(lái)谭贪。 1、HTTP-FLV We...
    韓瞅瞅閱讀 1,640評(píng)論 2 5
  • 原文:https://developer.android.com/reference/android/media/...
    thebestofrocky閱讀 6,078評(píng)論 0 6
  • 三月二日晨锦担。 半個(gè)月亮在南天懸著俭识,猶如老天正側(cè)著一只耳朵,諦聽(tīng)微山湖的動(dòng)靜洞渔。 這是微山湖中的獨(dú)山湖套媚。難得的晴朗終于...
    孔孟之鄉(xiāng)閱讀 771評(píng)論 0 0
  • 昨天缚态,跟同學(xué)網(wǎng)上聊天,他現(xiàn)在在一家初創(chuàng)公司上班堤瘤,這個(gè)公司是做微型超聲設(shè)備的玫芦,后來(lái)就聊到微型超聲怎么才能做好,他們已...
    翁翁yeah閱讀 314評(píng)論 0 1