如何在Android上快速显示yuv数据
\u5982\u4f55\u5728Android\u4e0a\u5feb\u901f\u663e\u793ayuv\u6570\u636e\u6700\u8fd1\u5728\u641eAndroid\u65b9\u9762\u7684\u89c6\u9891\u5904\u7406\u5f00\u53d1\uff0c\u89e3\u7801\u51fa\u6765\u7684\u90fd\u662fYUV420\u683c\u5f0f\u7684\u6570\u636e\uff0c\u5982\u4f55\u5728surface\u4e0a\u9ad8\u6548\u663e\u793a\u51fa\u6765\uff0c\u9887\u8d39\u4e86\u4e00\u70b9\u5468\u6298\uff0c\u73b0\u5728\u603b\u7ed3\u4e00\u4e0b\u3002
\u601d\u8def1\uff1a\u5728java\u4e2d\u5c06Surface\u6307\u9488\u4f20\u9012\u5230jni\u5c42\uff0clock\u4e4b\u540e\u5c31\u53ef\u4ee5\u83b7\u5f97SurfaceInfo\uff0c\u8fdb\u800c\u53d6\u5f97\u8981\u663e\u793a\u7684surface\u683c\u5f0f\u3001\u9ad8\u5ea6\u3001\u5bbd\u5ea6\uff0c\u57282.2/2.3\u7248\u672c\uff0csurface\u7684Format\u4e00\u822c\u90fd\u662fRGB565\u683c\u5f0f\uff0c\u53ea\u7528\u505a\u4e00\u4e2a\u989c\u8272\u7a7a\u95f4\u7684\u8f6c\u6362\uff0cscaler\u5c31\u53ef\u4ee5\u5c06yuv\u6570\u636e\u663e\u793a\u51fa\u6765\u3002
\u989c\u8272\u7a7a\u95f4\u8f6c\u6362\u548cScaler\u7b97\u662f\u6bd4\u8f83\u8017\u65f6\u7684\u64cd\u4f5c\u4e86\u3002\u5982\u4f55\u63d0\u9ad8\u6548\u7387\uff0cscaler\u6700\u597d\u80fd\u4ea4\u7ed9android\u7684\u5e95\u5c42\u51fd\u6570\u53bb\u505a\uff0c\u5982\u679c\u6709gpu\u7684\uff0c\u5e95\u5c42\u51fd\u6570\u76f4\u63a5\u4f1a\u5229\u7528gpu\uff0c\u6548\u7387\u975e\u5e38\u9ad8\uff0c\u53c8\u4e0d\u5360\u7528cpu\u8d44\u6e90\u3002
\u601d\u8def2\uff1a
\u53c2\u8003framework\u4e2d\u7684AwesomePlayer\uff0c\u91cc\u9762\u5229\u7528AwesomeLocalRenderer/AwesomeRemoteRenderer\u6765\u5b9e\u73b0\u89e3\u7801\u51fa\u6765\u7684\u6570\u636e\u663e\u793a\uff0c\u8fd9\u4e2a\u6548\u7387\u5e94\u8be5\u975e\u5e38\u9ad8\uff0c\u4f46\u662f\u5e73\u53f0\u7684\u5173\u8054\u6027\u4f1a\u589e\u52a0\u5f88\u591a\u3002
\u8c03\u7528\u63a5\u53e3\u6bd4\u8f83\u7b80\u5355\uff0c
\u9996\u5148\u521b\u5efa\u4e00\u4e2arender\uff0c
mVideoRenderer = new AwesomeRemoteRenderer(
mClient.interface()->createRenderer(
mISurface, component,
(OMX_COLOR_FORMATTYPE)format,
decodedWidth, decodedHeight,
mVideoWidth, mVideoHeight,
rotationDegrees));
\u76f4\u63a5\u8c03\u7528render\u51fd\u6570\u5c31\u53ef\u4ee5\u663e\u793a\u4e86\u3002
virtual void render(MediaBuffer *buffer) {
void *id;
if (buffer->meta_data()->findPointer(kKeyBufferID, &id)) {
mTarget->render((IOMX::buffer_id)id);
}
}
\u5176\u5b83\u7684\u53c2\u6570\u90fd\u5f88\u5bb9\u6613\u83b7\u5f97\uff0c\u5173\u952e\u662fbuffer_id \u600e\u4e48\u83b7\u5f97\uff1fOMXCodec.cpp\u4e2d\u6709\u76f8\u5173\u7684\u53ef\u4ee5\u53c2\u8003\u3002
\u5b9e\u9645\u7684\u6548\u679c\u5728\u6211\u7684S510E\u4e0a\u8dd1\uff0c\u6548\u7387\u975e\u5e38\u9ad8\uff0c\u51e0\u4e4e\u4e0d\u5360\u7528\u4e3b\u63a7cpu\u8d44\u6e90\uff0c\u5f88\u53ef\u80fd\u90fd\u4ea4\u7ed9dsp\u548cgpu\u53bb\u641e\u4e86\u3002
\u601d\u8def3\uff1a
\u53c2\u8003 camera\u7684\u65b9\u5f0f\u3002\u7531\u4e8e\u5728\u7b2c2\u6b65\u5df2\u7ecf\u53d6\u5f97\u4e86\u975e\u5e38\u597d\u7684\u6548\u679c\uff0c\u7b14\u8005\u6ca1\u6709\u505a\u6df1\u5165\u7814\u7a76\u3002
\u5176\u5b9eandroid\u91cc\u9762\u5b9a\u4e49\u7684\u6709overlay\u7684\u63a5\u53e3\uff0c\u5982\u679c\u4f60\u7684\u786c\u4ef6\u652f\u6301\u7684\u8bdd\uff0c\u5e94\u8be5\u53ef\u4ee5\u76f4\u63a5\u8c03\u7528\u663e\u793a\u3002\u4f46\u662f\u597d\u50cf\u6ca1\u6709\u5f00\u653eoverlay\u7684\u501f\u53e3\u7ed9java\u5c42\uff0c\u6240\u4ee5\u4f60\u5e94\u8be5\u53ea\u80fd\u5728framework\u5c42\u8c03\u7528overlay\u6765\u663e\u793a\u4f60\u7684\u89e3\u7801\u540e\u7684\u56fe\u50cf\u3002\u5177\u4f53\u7684\u4f8b\u5b50\uff0c\u4f60\u53ef\u4ee5\u53c2\u8003\u4e00\u4e0bcamera \u7684\u5b9e\u73b0\uff0c\u505apre-view\u7684\u65f6\u5019\u5c31\u662f\u8c03\u7528\u7684overlay\u76f4\u63a5\u663e\u793a\u7684\u3002
最近在搞Android方面的视频处理开发,解码出来的都是YUV420格式的数据,如何在surface上高效显示出来,颇费了一点周折,现在总结一下。思路1:在java中将Surface指针传递到jni层,lock之后就可以获得SurfaceInfo,进而取得要显示的surface格式、高度、宽度,在2.2/2.3版本,surface的Format一般都是RGB565格式,只用做一个颜色空间的转换,scaler就可以将yuv数据显示出来。
颜色空间转换和Scaler算是比较耗时的操作了。如何提高效率,scaler最好能交给android的底层函数去做,如果有gpu的,底层函数直接会利用gpu,效率非常高,又不占用cpu资源。
思路2:
参考framework中的AwesomePlayer,里面利用AwesomeLocalRenderer/AwesomeRemoteRenderer来实现解码出来的数据显示,这个效率应该非常高,但是平台的关联性会增加很多。
调用接口比较简单,
首先创建一个render,
mVideoRenderer = new AwesomeRemoteRenderer(
mClient.interface()->createRenderer(
mISurface, component,
(OMX_COLOR_FORMATTYPE)format,
decodedWidth, decodedHeight,
mVideoWidth, mVideoHeight,
rotationDegrees));
直接调用render函数就可以显示了。
virtual void render(MediaBuffer *buffer) {
void *id;
if (buffer->meta_data()->findPointer(kKeyBufferID, &id)) {
mTarget->render((IOMX::buffer_id)id);
}
}
其它的参数都很容易获得,关键是buffer_id 怎么获得?OMXCodec.cpp中有相关的可以参考。
实际的效果在我的S510E上跑,效率非常高,几乎不占用主控cpu资源,很可能都交给dsp和gpu去搞了。
思路3:
参考 camera的方式。由于在第2步已经取得了非常好的效果,笔者没有做深入研究。
绛旓細Android鎵嬫満涓鎬庝箞灏嗘棩鏈熻瀹鏄剧ず鍦ㄦ闈笂 1.鍦ㄦ闈㈢┖鐧藉闀挎寜钀ゅ箷锛屽嚭鐜颁竴涓夊崟鍒楄〃锛岄夋嫨鈥滆绐楀皬閮ㄤ欢鈥濓紝鐒跺悗鍦ㄩ噷闈㈠氨鍙互鎵惧埌浣犳嫋鎺夌殑鏃堕棿灏忛儴浠朵簡锛岀偣涓嬪氨鍙互鎶婂畠鍐嶅姞鍒版闈 2.杩蹇嵎鈥>閫夋嫨鏃堕棿鎷夊埌涓棿浣嶇疆 鏃ユ湡鏃堕棿鏄剧ず鍦ㄦ闈笂 鏂板鏃堕棿鎴栧ぉ姘斿伐鍏峰氨鍙互鏄剧ず鏃堕棿鍜屽ぉ姘旇祫璁簡銆 璇风敤...
绛旓細闇瑕佸悜launcher鍙戦佸垱寤烘闈蹇嵎鐨勫箍鎾紝鍛婅瘔android绯荤粺鍒涘缓妗岄潰鍥炬爣銆傚叿浣撳疄鐜版柟寮忥細1.瑕佸湪鎵嬫満妗岄潰涓婃坊鍔犲揩鎹锋柟寮忥紝棣栧厛闇瑕佸湪manifest涓坊鍔犳潈闄愩<!-- 娣诲姞蹇嵎鏂瑰紡 --> <uses-permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT" /> <!-- 绉婚櫎蹇嵎鏂瑰紡 --> <uses-...
绛旓細鎬濊矾锛氬畾鏃+闅愯棌鎸夐挳 瀹氭椂鐨勬柟妗堟湁涓夌锛1銆丠andler+Thread 2銆丠andler绫昏嚜甯︾殑postDelyed 3銆丠andler+Timer+TimerTask 杩欓噷鎺ㄨ崘浣跨敤绗簩绉嶆柟寮忔瘮杈冨疄鐢ㄧ畝鍗 handler.postDelayed(runnable, 10000); //10绉掑悗鎵цrunnable 鐨剅un鏂规硶Handler handler = new Handler(); Runnable runnable = new Runnable...
绛旓細鎹垜鎵鐭ワ紝windowmanager鎮诞绐楀彲浠ュ疄鐜颁綘鐨勯渶姹傦紝浣嗕粬鏄剧ず鐨勪笉鏄綘鏁翠釜搴旂敤锛屽彧鏄竴涓獀iew
绛旓細瑕佸皢鎵嬫満澶╂皵鏀惧埌妗岄潰涓鏄剧ず锛屽叿浣撴楠ゅ洜鎵嬫満绯荤粺鍜岀増鏈屽紓锛屼絾涓鑸祦绋嬪ぇ鑷村涓嬶細1. **Android绯荤粺**锛- 闀挎寜鎵嬫満妗岄潰鐨勭┖鐧藉尯鍩燂紝杩涘叆妗岄潰缂栬緫鐘舵併- 鍦ㄥ脊鍑虹殑閫夐」涓壘鍒扳滃皬閮ㄤ欢鈥濇垨鈥滅獥鍙e皬宸ュ叿鈥濈瓑绫讳技閫夐」銆- 婊戝姩灞忓箷锛屾壘鍒板ぉ姘斿皬閮ㄤ欢锛岄夋嫨鍠滄鐨勬牱寮忥紙閬垮厤閫夋嫨甯︽湁琛ㄦ牸鎴栧浘鐗囩殑鏍峰紡锛夈- 灏...
绛旓細鏉ヨ幏鍙朩indowManager銆備娇鐢╓indowManager鍙互鍦ㄥ叾浠栧簲鐢ㄦ渶涓婂眰锛岀敋鑷虫墜鏈烘闈㈡渶涓婂眰鏄剧ず绐楀彛銆傝皟鐢ㄧ殑鏄疻indowManager缁ф壙鑷熀绫荤殑addView鏂规硶鍜宺emoveView鏂规硶鏉ユ樉绀哄拰闅愯棌绐楀彛銆傚叿浣撹鍚庨潰鐨勫疄渚嬨 鍙︼細API 17鎺ㄥ嚭浜哖resentation锛屽畠灏嗚嚜鍔ㄨ幏鍙杁isplay鐨凜ontext鍜學indowManager锛屽彲浠ユ柟渚垮湴鍦ㄥ彟涓涓猟isplay涓婃樉绀绐楀彛銆
绛旓細鐐瑰嚮璁剧疆锛岃繘鍏ユ墜鏈鸿缃傚湪璁剧疆涓紝鎵惧埌鈥滃鑸爮鍙互闅愯棌鈥濈殑璁剧疆椤癸紝灏嗗叾寮鍚傚紑鍚悗锛岀珛鍗崇敓鏁堬紝鐐瑰嚮杩斿洖銆傚彲浠ュ彂鐜板鑸爮宸﹁竟澶氫簡涓涓猇褰㈢殑闅愯棌鎸夐挳銆傜偣鍑诲畠鍗冲彲闅愯棌瀵艰埅鏍忋傞殣钘忓悗鐨勬晥鏋溿傚鏋滈渶瑕佽瀵艰埅鏍忓啀娆″嚭鐜帮紝鍙渶鍦ㄥ睆骞曞簳閮紝鍚戜笂婊戝姩 鍚戜笂婊戝姩涔嬪悗锛屽鑸爮灏卞啀娆鏄剧ず鍑烘潵銆俬ttp://jingyan....
绛旓細閫氳繃涓涓畝鍗曠殑绀轰緥涓姝ユ浠嬬粛濡備綍鍦ˋndroid搴旂敤涓娇鐢ㄧ櫨搴﹀湴鍥綼pi銆1锛変笅杞界櫨搴﹀湴鍥剧Щ鍔ㄧ増API(Android)寮鍙戝寘 瑕佸湪Android搴旂敤涓娇鐢ㄧ櫨搴﹀湴鍥続PI锛屽氨闇瑕佸湪宸ョ▼涓紩鐢ㄧ櫨搴﹀湴鍥続PI寮鍙戝寘锛岃繖涓紑鍙戝寘鍖呭惈涓や釜鏂囦欢锛歜aidumapapi.jar鍜宭ibBMapApiEngine.so銆備笅杞藉湴鍧锛歨ttp://dev.baidu.com/wiki/static/imap/...
绛旓細姣曠珶鏄櫄鎷熸満锛屽緢澶氬姛鑳芥槸鏃犳硶瀹炵幇鐨勩傜晫闈篃浼氬瓨鍦ㄧ己闄风殑銆傚挨鍏舵槸鍏充簬鎵撶數璇濓紝鍙戠煭淇$殑鍔熻兘銆傝櫄鎷熸満鍦ㄨ繖鏂归潰鏄緢涓嶆垚鐔熺殑銆傝繕鏈夊氨鏄紝鐜板湪鐨勮櫄鎷熸満瀵瑰ぇ澶氭暟搴旂敤绋嬪簭鏀寔鐨勪篃涓嶆槸寰堝畬缇庛傛瘯绔熷铏氭嫙鏈烘劅鍏磋叮鐨勪汉涓嶆槸寰堝锛屽紑鍙戣櫄鎷熸満鐨勪汉姣旇緝灏戯紝鑳藉姏鏈夐檺銆傜瓑鍒板ぇ澶氭暟浜哄叧娉ㄨ櫄鎷熸満鐨勬椂鍊欙紝寮鍙戣呬篃浼...
绛旓細浠绘剰Activity寮瑰嚭瀵硅瘽妗,閭d綘鍙互鐢╯ervice 鏈嶅姟涓脊鍑轰竴涓叏灞鐨勪互涓嬫槸浠g爜123456789101112131415AlertDialog.Builder builder = new AlertDialog.Builder(this);builder.setIcon(R.drawable.ic);builder.setTitle("鏍囬");builder.setMessage("鎻愮ず鏂囧瓧");builder.setPositiveButton(R.string.btn_update, new On...