隨筆 - 312, 文章 - 14, 評(píng)論 - 1393, 引用 - 0
          數(shù)據(jù)加載中……

          流媒體程序開發(fā)之:H264解碼器移植到OPhone

          1.   移植目標(biāo)
                 將H.264解碼器移植到OPhone操作系統(tǒng)之上(NDK+C),并寫一個(gè)測(cè)試程序(OPhoneSDK+Java)測(cè)試解碼庫(kù)是否正常運(yùn)行,下面是解碼時(shí)的截圖:


                  OPhone的模擬器和Mobile的模擬器一樣是模擬ARM指令的,不像Symbian模擬器一樣執(zhí)行的是本地代碼,所以在模擬器上模擬出來的效率會(huì)比 真實(shí)手機(jī)上的效率要低,之前這款解碼器已經(jīng)優(yōu)化到在nokia 6600(相當(dāng)?shù)投说囊豢钍謾C(jī),CPU主頻才120Hz)上做到在線播放。
           

          2. 面向人群
                 本文面向有一定的手機(jī)應(yīng)用開發(fā)經(jīng)驗(yàn)(例如:S60/Mobile/MTK)和有一定的跨手機(jī)平臺(tái)移植經(jīng)驗(yàn)的人員,幫助她們了解一個(gè)企業(yè)的核心庫(kù)(C/C++)是怎么移植到OPhone之上的。
           

          3. 假定前提
          1)熟悉Java/C/C++語(yǔ)言;
          2)熟悉Java的JNI技術(shù);
          3)有一定的跨手機(jī)平臺(tái)移植經(jīng)驗(yàn);
          4)有一套可供移植的源代碼庫(kù),這里以H.264解碼庫(kù)為例,為了保護(hù)我們的知識(shí)版權(quán),這里只能夠公開頭文件:
            

          1. #ifndef __H264DECODE_H__  
          2. #define __H264DECODE_H__  
          3.   
          4. #if defined(__SYMBIAN32__)  //S602rd/3rd/UIQ  
          5.     #include <e32base.h>  
          6.     #include <libc"stdio.h>  
          7.     #include <libc"stdlib.h>  
          8.     #include <libc"string.h>  
          9. #else                       //Windows/Mobile/MTK/OPhone  
          10.     #include <stdio.h>  
          11.     #include <stdlib.h>  
          12.     #include <string.h>  
          13. #endif  
          14.   
          15. class H264Decode  
          16. {  
          17. public:  
          18.     /***************************************************************************/  
          19.     /* 構(gòu)造解碼器                                                        */  
          20.     /* @return H264Decode解碼器實(shí)例                                      */  
          21.     /***************************************************************************/  
          22.     static H264Decode *H264DecodeConstruct();  
          23.     /***************************************************************************/  
          24.     /* 解碼一幀                                                     */  
          25.     /* @pInBuffer   指向H264的視頻流                                      */  
          26.     /* @iInSize H264視頻流的大小                                      */  
          27.     /* @pOutBuffer  解碼后的視頻視頻                                        */  
          28.     /* @iOutSize    解碼后的視頻大小                                        */  
          29.     /* @return      已解碼的H264視頻流的尺寸                              */  
          30.     /***************************************************************************/  
          31.     int DecodeOneFrame(unsigned char *pInBuffer,unsigned int iInSize,unsigned char *pOutBuffer,unsigned int &iOutSize);  
          32.     ~H264Decode();  
          33. };  
          34. #endif  // __H264DECODE_H__  

                你不用熟悉OPhone平臺(tái),一切從零開始,因?yàn)樵诖酥埃乙膊皇煜ぁ?br />  

          4.  開發(fā)環(huán)境(請(qǐng)參考: http://www.ophonesdn.com/documentation/)
           

          5.  移植過程

          5.1 移植流程

          5.2 封裝Java接口

                  在“假定前提”中提到了要移植的函數(shù),接下來會(huì)編寫這些 函數(shù)的Java Native Interface。

          1. package ophone.streaming.video.h264;  
          2.   
          3. import java.nio.ByteBuffer;  
          4.   
          5. public class H264decode {  
          6.       
          7. //H264解碼庫(kù)指針,因?yàn)镴ava沒有指針一說,所以這里用一個(gè)32位的數(shù)來存放指針的值  
          8.     private long H264decode = 0;  
          9.       
          10.     static{     
          11.         System.loadLibrary("H264Decode");  
          12.     }  
          13.   
          14.     public H264decode() {  
          15.         this.H264decode = Initialize();  
          16.     }  
          17.       
          18.     public void Cleanup() {  
          19.         Destroy(H264decode);  
          20.     }  
          21.       
          22.     public int DecodeOneFrame(ByteBuffer pInBuffer,ByteBuffer pOutBuffer) {  
          23.         return DecodeOneFrame(H264decode, pInBuffer, pOutBuffer);  
          24.     }  
          25.   
          26.     private native static int DecodeOneFrame(long H264decode,ByteBuffer pInBuffer,ByteBuffer pOutBuffer);  
          27.     private native static long Initialize();  
          28.     private native static void Destroy(long H264decode);  
          29. }  


                   這塊沒什么好說的,就是按照H264解碼庫(kù)的函數(shù),封裝的一層接口,如果你熟悉Java JNI,會(huì)發(fā)現(xiàn)原來是這么類似。這里插入一句:我一直認(rèn)為技術(shù)都是相通的,底層的技術(shù)就那么幾種,學(xué)懂了,其它技術(shù)都是一通百通。

          5.3 使用C實(shí)現(xiàn)本地方法

          5.3.1生成頭文件

                  使用javah命令生成JNI頭文件,這里需要注意是class路徑不是源代碼的路徑,并且要加上包名:

                  這里生成了一個(gè)ophone_streaming_video_h264_H264decode.h,我們打開來看看:

          1. #include <jni.h>  
          2.   
          3. #ifndef _Included_ophone_streaming_video_h264_H264decode  
          4. #define _Included_ophone_streaming_video_h264_H264decode  
          5. #ifdef __cplusplus  
          6. extern "C" {  
          7. #endif  
          8.   
          9. JNIEXPORT jint JNICALL Java_ophone_streaming_video_h264_H264decode_DecodeOneFrame  
          10.   (JNIEnv *, jclass, jlong, jobject, jobject);  
          11.   
          12. JNIEXPORT jlong JNICALL Java_ophone_streaming_video_h264_H264decode_Initialize  
          13.   (JNIEnv *, jclass);  
          14.   
          15. JNIEXPORT void JNICALL Java_ophone_streaming_video_h264_H264decode_Destroy  
          16.   (JNIEnv *, jclass, jlong);  
          17.   
          18. #ifdef __cplusplus  
          19. }  
          20. #endif  
          21. #endif  

          5.3.2 實(shí)現(xiàn)本地方法

                  之前已經(jīng)生成了JNI頭文件,接下來只需要實(shí)現(xiàn)這個(gè)頭文件的幾個(gè)導(dǎo)出函數(shù),這里以H264解碼器的實(shí)現(xiàn)為例:

          1. #include "ophone_streaming_video_h264_H264decode.h"  
          2. #include "H264Decode.h"  
          3.   
          4. JNIEXPORT jint JNICALL Java_ophone_streaming_video_h264_H264decode_DecodeOneFrame  
          5.   (JNIEnv * env, jclass obj, jlong decode, jobject pInBuffer, jobject pOutBuffer) {  
          6.   
          7.     H264Decode *pDecode = (H264Decode *)decode;  
          8.     unsigned char *In = NULL;unsigned char *Out = NULL;  
          9.     unsigned int InPosition = 0;unsigned int InRemaining = 0;unsigned int InSize = 0;  
          10.     unsigned int OutSize = 0;  
          11.     jint DecodeSize = -1;  
          12.   
          13.     jbyte *InJbyte = 0;  
          14.     jbyte *OutJbyte = 0;  
          15.   
          16.     jbyteArray InByteArrary = 0;  
          17.     jbyteArray OutByteArrary = 0;  
          18.   
          19.     //獲取Input/Out ByteBuffer相關(guān)屬性  
          20.     {  
          21.         //Input  
          22.         {  
          23.             jclass ByteBufferClass = env->GetObjectClass(pInBuffer);  
          24.             jmethodID PositionMethodId = env->GetMethodID(ByteBufferClass,"position","()I");  
          25.             jmethodID RemainingMethodId = env->GetMethodID(ByteBufferClass,"remaining","()I");  
          26.             jmethodID ArraryMethodId = env->GetMethodID(ByteBufferClass,"array","()[B");  
          27.               
          28.             InPosition = env->CallIntMethod(pInBuffer,PositionMethodId);  
          29.             InRemaining = env->CallIntMethod(pInBuffer,RemainingMethodId);  
          30.             InSize = InPosition + InRemaining;  
          31.               
          32.             InByteArrary = (jbyteArray)env->CallObjectMethod(pInBuffer,ArraryMethodId);  
          33.           
          34.             InJbyte = env->GetByteArrayElements(InByteArrary,0);  
          35.               
          36.             In = (unsigned char*)InJbyte + InPosition;  
          37.         }  
          38.   
          39.         //Output  
          40.         {  
          41.             jclass ByteBufferClass = env->GetObjectClass(pOutBuffer);  
          42.             jmethodID ArraryMethodId = env->GetMethodID(ByteBufferClass,"array","()[B");  
          43.             jmethodID ClearMethodId = env->GetMethodID(ByteBufferClass,"clear","()Ljava/nio/Buffer;");  
          44.               
          45.             //清理輸出緩存區(qū)  
          46.             env->CallObjectMethod(pOutBuffer,ClearMethodId);  
          47.   
          48.             OutByteArrary = (jbyteArray)env->CallObjectMethod(pOutBuffer,ArraryMethodId);  
          49.             OutJbyte = env->GetByteArrayElements(OutByteArrary,0);  
          50.   
          51.             Out = (unsigned char*)OutJbyte;  
          52.         }  
          53.     }  
          54.   
          55.     //解碼  
          56.     DecodeSize = pDecode->DecodeOneFrame(In,InRemaining,Out,OutSize);  
          57.   
          58.     //設(shè)置Input/Output ByteBuffer相關(guān)屬性  
          59.     {  
          60.         //Input  
          61.         {  
          62.             jclass ByteBufferClass = env->GetObjectClass(pInBuffer);  
          63.             jmethodID SetPositionMethodId = env->GetMethodID(ByteBufferClass,"position","(I)Ljava/nio/Buffer;");  
          64.               
          65.             //設(shè)置輸入緩沖區(qū)偏移  
          66.             env->CallObjectMethod(pInBuffer,SetPositionMethodId,InPosition + DecodeSize);  
          67.         }  
          68.   
          69.         //Output  
          70.         {  
          71.             jclass ByteBufferClass = env->GetObjectClass(pOutBuffer);  
          72.             jmethodID SetPositionMethodId = env->GetMethodID(ByteBufferClass,"position","(I)Ljava/nio/Buffer;");  
          73.   
          74.             //設(shè)置輸出緩沖區(qū)偏移  
          75.             env->CallObjectMethod(pOutBuffer,SetPositionMethodId,OutSize);  
          76.         }  
          77.     }  
          78.   
          79.     //清理  
          80.     env->ReleaseByteArrayElements(InByteArrary,InJbyte,0);  
          81.     env->ReleaseByteArrayElements(OutByteArrary,OutJbyte,0);  
          82.   
          83.     return DecodeSize;  
          84. }  
          85.   
          86. JNIEXPORT jlong JNICALL Java_ophone_streaming_video_h264_H264decode_Initialize  
          87.   (JNIEnv * env, jclass obj) {  
          88.   
          89.     H264Decode *pDecode = H264Decode::H264DecodeConstruct();  
          90.     return (jlong)pDecode;  
          91. }  
          92.   
          93. JNIEXPORT void JNICALL Java_ophone_streaming_video_h264_H264decode_Destroy  
          94.   (JNIEnv * env, jclass obj, jlong decode) {  
          95.   
          96.     H264Decode *pDecode = (H264Decode *)decode;  
          97.     if (pDecode)  
          98.     {  
          99.         delete pDecode;  
          100.         pDecode = NULL;  
          101.     }  
          102. }  

           5.3.3 編譯本地方法

                  接下來,只需要把用C實(shí)現(xiàn)的本地方法編譯為動(dòng)態(tài)鏈接庫(kù),如果之前你用于移植的那個(gè)庫(kù)曾經(jīng)移植到Symbian上過,那么編譯會(huì)相當(dāng)簡(jiǎn)單,因?yàn)镹DK的編譯器和Symbian的編譯器一樣,都是采用GCC做交叉編譯器。

                  首先,需要在$NDK"apps目錄下,創(chuàng)建一個(gè)項(xiàng)目目錄,這里創(chuàng)建了一個(gè)H264Decode目錄,在H264Decode目錄中,創(chuàng)建一個(gè)Android.mk文件:
           

          1. APP_PROJECT_PATH := $(call my-dir)  
          2. APP_MODULES      := H264Decode  


                 接下來,需要在$NDK"source目錄下,創(chuàng)建源代碼目錄(這里的目錄名要和上面創(chuàng)建的項(xiàng)目目錄文件名相同),這里創(chuàng)建一個(gè)H264Decode目錄,然后把之前生成的JNI頭文件和你實(shí)現(xiàn)的本地方法相關(guān)頭文件和源代碼,都拷貝到   這個(gè)目錄下面。

                    然后,我們編輯Android.mk文件:

          1. LOCAL_PATH := $(call my-dir)  
          2. include $(CLEAR_VARS)  
          3. LOCAL_MODULE    := H264Decode  
          4. LOCAL_SRC_FILES := common.c cabac.c utils.c golomb.c mpegvideo.c mem.c imgconvert.c h264decode.cpp h264.c dsputil.c ophone_streaming_video_h264_H264decode.cpp  
          5. include $(BUILD_SHARED_LIBRARY)  


                  關(guān)于Android.mk文件中,各個(gè)字段的解釋,可以參考$NDK"doc下的《OPHONE-MK.TXT》和《OVERVIEW.TXT》,里面有詳細(xì)的介紹。

                  最后,我們啟動(dòng)Cygwin,開始編譯:

                 如果你看到了Install:**,這說明你的庫(kù)已經(jīng)編譯好了。

                 FAQ 2:
                 如果編譯遇到下面錯(cuò)誤,怎么辦?

          1. error: redefinition of typedef 'int8_t'  

             需要注釋掉你的代碼中“typedef signed char  int8_t;”,如果你的代碼之前是已經(jīng)移植到了Mobile/Symbian上的話,很有可能遇到這個(gè)問題。
                 

          5.4 編寫庫(kù)測(cè)試程序

              用Eclipse創(chuàng)建一個(gè)OPhone工程,在入口類中輸入如下代碼:

          1. /**    
          2.  * @author ophone 
          3.  * @email 3751624@qq.com 
          4.  */  
          5.   
          6. package ophone.streaming.video.h264;  
          7.   
          8. import java.io.File;  
          9. import java.io.FileInputStream;  
          10. import java.io.InputStream;  
          11. import java.nio.ByteBuffer;  
          12. import OPhone.app.Activity;  
          13. import OPhone.graphics.BitmapFactory;  
          14. import OPhone.os.Bundle;  
          15. import OPhone.os.Handler;  
          16. import OPhone.os.Message;  
          17. import OPhone.widget.ImageView;  
          18. import OPhone.widget.TextView;  
          19.   
          20. public class H264Example extends Activity {  
          21.       
          22.     private static final int VideoWidth = 352;  
          23.     private static final int VideoHeight = 288;  
          24.       
          25.     private ImageView ImageLayout = null;  
          26.     private TextView FPSLayout = null;  
          27.     private H264decode Decode = null;  
          28.     private Handler H = null;  
          29.     private byte[] Buffer = null;  
          30.       
          31.     private int DecodeCount = 0;  
          32.     private long StartTime = 0;  
          33.   
          34.     public void onCreate(Bundle savedInstanceState) {  
          35.           
          36.         super.onCreate(savedInstanceState);  
          37.         setContentView(R.layout.main);  
          38.           
          39.         ImageLayout = (ImageView) findViewById(R.id.ImageView);  
          40.         FPSLayout = (TextView) findViewById(R.id.TextView);  
          41.         Decode = new H264decode();  
          42.           
          43.         StartTime = System.currentTimeMillis();  
          44.           
          45.         new Thread(new Runnable(){  
          46.             public void run() {  
          47.                 StartDecode();  
          48.             }  
          49.         }).start();  
          50.           
          51.         H = new Handler(){  
          52.             public void handleMessage(Message msg) {  
          53.                 ImageLayout.invalidate();  
          54.                 ImageLayout.setImageBitmap(BitmapFactory.decodeByteArray(Buffer, 0, Buffer.length));  
          55.                   
          56.                 long Time = (System.currentTimeMillis()-StartTime)/1000;  
          57.                 if(Time > 0){  
          58.                     FPSLayout.setText("花費(fèi)時(shí)間:" + Time + "秒  解碼幀數(shù):" + DecodeCount + "  FPS:" + (DecodeCount/Time) );  
          59.                 }  
          60.             }  
          61.         };  
          62.     }  
          63.       
          64.     private void StartDecode(){  
          65.           
          66.         File h264file = new File("/tmp/Demo.264");  
          67.         InputStream h264stream = null;  
          68.         try {  
          69.               
          70.             h264stream = new FileInputStream(h264file);  
          71.             ByteBuffer pInBuffer = ByteBuffer.allocate(51200);//分配50k的緩存  
          72.             ByteBuffer pRGBBuffer = ByteBuffer.allocate(VideoWidth*VideoHeight*3);  
          73.               
          74.             while (h264stream.read(pInBuffer.array(), pInBuffer.position(), pInBuffer.remaining()) >= 0) {  
          75.                   
          76.                 pInBuffer.position(0);  
          77.                 do{  
          78.                     int DecodeLength = Decode.DecodeOneFrame(pInBuffer, pRGBBuffer);  
          79.                       
          80.                     //如果解碼成功,把解碼出來的圖片顯示出來  
          81.                     if(DecodeLength > 0 && pRGBBuffer.position() > 0){  
          82.                           
          83.                         //轉(zhuǎn)換RGB字節(jié)為BMP  
          84.                         BMPImage bmp = new BMPImage(pRGBBuffer.array(),VideoWidth,VideoHeight);  
          85.                         Buffer = bmp.getByte();  
          86.               
          87.                         H.sendMessage(H.obtainMessage());  
          88.   
          89.                         Thread.sleep(1);  
          90.                         DecodeCount ++;  
          91.                     }  
          92.                       
          93.                 }while(pInBuffer.remaining() > 10240);//確保緩存區(qū)里面的數(shù)據(jù)始終大于10k  
          94.                   
          95.                 //清理已解碼緩沖區(qū)  
          96.                 int Remaining = pInBuffer.remaining();  
          97.                 System.arraycopy(pInBuffer.array(), pInBuffer.position(), pInBuffer.array(), 0, Remaining);  
          98.                 pInBuffer.position(Remaining);  
          99.             }  
          100.               
          101.         } catch (Exception e1) {  
          102.             e1.printStackTrace();  
          103.         } finally {  
          104.             try{h264stream.close();} catch(Exception e){}  
          105.         }  
          106.           
          107.     }  
          108.   
          109.     protected void onDestroy() {  
          110.         super.onDestroy();  
          111.         Decode.Cleanup();  
          112.     }  
          113. }  

                BMPImage是一個(gè)工具類,主要用于把RGB序列,轉(zhuǎn)換為BMP圖象用于顯示:

          1. @author ophone  
          2.  * @email 3751624@qq.com  
          3. */  
          4.   
          5. package ophone.streaming.video.h264;  
          6.   
          7. import java.nio.ByteBuffer;  
          8.   
          9. public class BMPImage {  
          10.   
          11.     // --- 私有常量  
          12.     private final static int BITMAPFILEHEADER_SIZE = 14;  
          13.     private final static int BITMAPINFOHEADER_SIZE = 40;  
          14.   
          15.     // --- 位圖文件標(biāo)頭  
          16.     private byte bfType[] = { 'B', 'M' };  
          17.     private int bfSize = 0;  
          18.     private int bfReserved1 = 0;  
          19.     private int bfReserved2 = 0;  
          20.     private int bfOffBits = BITMAPFILEHEADER_SIZE + BITMAPINFOHEADER_SIZE;  
          21.   
          22.     // --- 位圖信息標(biāo)頭  
          23.     private int biSize = BITMAPINFOHEADER_SIZE;  
          24.     private int biWidth = 176;  
          25.     private int biHeight = 144;  
          26.     private int biPlanes = 1;  
          27.     private int biBitCount = 24;  
          28.     private int biCompression = 0;  
          29.     private int biSizeImage = biWidth*biHeight*3;  
          30.     private int biXPelsPerMeter = 0x0;  
          31.     private int biYPelsPerMeter = 0x0;  
          32.     private int biClrUsed = 0;  
          33.     private int biClrImportant = 0;  
          34.       
          35.     ByteBuffer bmpBuffer = null;  
          36.       
          37.     public BMPImage(byte[] Data,int Width,int Height){  
          38.         biWidth = Width;  
          39.         biHeight = Height;  
          40.           
          41.         biSizeImage = biWidth*biHeight*3;  
          42.         bfSize = BITMAPFILEHEADER_SIZE + BITMAPINFOHEADER_SIZE + biWidth*biHeight*3;  
          43.         bmpBuffer = ByteBuffer.allocate(BITMAPFILEHEADER_SIZE + BITMAPINFOHEADER_SIZE + biWidth*biHeight*3);  
          44.           
          45.         writeBitmapFileHeader();  
          46.         writeBitmapInfoHeader();  
          47.         bmpBuffer.put(Data);  
          48.     }  
          49.       
          50.     public byte[] getByte(){  
          51.         return bmpBuffer.array();  
          52.     }  
          53.       
          54.     private byte[] intToWord(int parValue) {  
          55.   
          56.         byte retValue[] = new byte[2];  
          57.   
          58.         retValue[0] = (byte) (parValue & 0x00FF);  
          59.         retValue[1] = (byte) ((parValue >> 8) & 0x00FF);  
          60.   
          61.         return (retValue);  
          62.     }  
          63.   
          64.     private byte[] intToDWord(int parValue) {  
          65.   
          66.         byte retValue[] = new byte[4];  
          67.   
          68.         retValue[0] = (byte) (parValue & 0x00FF);  
          69.         retValue[1] = (byte) ((parValue >> 8) & 0x000000FF);  
          70.         retValue[2] = (byte) ((parValue >> 16) & 0x000000FF);  
          71.         retValue[3] = (byte) ((parValue >> 24) & 0x000000FF);  
          72.   
          73.         return (retValue);  
          74.   
          75.     }  
          76.       
          77.     private void writeBitmapFileHeader () {  
          78.           
          79.         bmpBuffer.put(bfType);  
          80.         bmpBuffer.put(intToDWord (bfSize));  
          81.         bmpBuffer.put(intToWord (bfReserved1));  
          82.         bmpBuffer.put(intToWord (bfReserved2));  
          83.         bmpBuffer.put(intToDWord (bfOffBits));  
          84.           
          85.     }  
          86.       
          87.     private void writeBitmapInfoHeader () {  
          88.           
          89.         bmpBuffer.put(intToDWord (biSize));      
          90.         bmpBuffer.put(intToDWord (biWidth));      
          91.         bmpBuffer.put(intToDWord (biHeight));      
          92.         bmpBuffer.put(intToWord (biPlanes));      
          93.         bmpBuffer.put(intToWord (biBitCount));      
          94.         bmpBuffer.put(intToDWord (biCompression));      
          95.         bmpBuffer.put(intToDWord (biSizeImage));      
          96.         bmpBuffer.put(intToDWord (biXPelsPerMeter));      
          97.         bmpBuffer.put(intToDWord (biYPelsPerMeter));      
          98.         bmpBuffer.put(intToDWord (biClrUsed));      
          99.         bmpBuffer.put(intToDWord (biClrImportant));   
          100.           
          101.     }  
          102. }  


                   測(cè)試程序完整工程在此暫不提供。

          5.5集成測(cè)試

                  集成測(cè)試有兩點(diǎn)需要注意,在運(yùn)行程序前,需要把動(dòng)態(tài)庫(kù)復(fù)制到模擬器的/system/lib目錄下面,還需要把需要解碼的視頻傳到模擬器的/tmp目錄下。
                 這里要明確的是,OPhone和Symbian的模擬器都做的太不人性化了,Symbian復(fù)制一個(gè)文件到模擬器中,要進(jìn)一堆很深的目錄,OPhone的 更惱火,需要敲命令把文件傳遞到模擬器里,說實(shí)話,僅在這點(diǎn)上,Mobile的模擬器做的還是非常人性化的。
                 命令:

          1. PATH=D:"OPhone"OPhone SDK"tools"  
          2. adb.exe remount  
          3. adb.exe push D:"Eclipse"workspace"H264Example"libs"armeabi"libH264Decode.so /system/lib  
          4. adb.exe push D:"Eclipse"workspace"H264Example"Demo.264 /tmp  
          5. pause  


                這里解釋一下abd push命令:
                adb push <本地文件路徑> <遠(yuǎn)程文件路徑>    - 復(fù)制文件或者目錄到模擬器
                在Eclipse中,啟動(dòng)庫(kù)測(cè)試程序,得到畫面如下:
           

                  FAQ 3:

                  模擬器黑屏怎么辦?
                  這可能是由于模擬器啟動(dòng)速度比較慢所引起的,所以需要多等一會(huì)。希望下個(gè)版本能夠改進(jìn)。

          原文地址:http://www.ophonesdn.com/article/show/45;jsessionid=306BD3BE92F43DC693BEB09B0234B036





          Android開發(fā)完全講義(第2版)(本書版權(quán)已輸出到臺(tái)灣)

          http://product.dangdang.com/product.aspx?product_id=22741502



          Android高薪之路:Android程序員面試寶典 http://book.360buy.com/10970314.html


          新浪微博:http://t.sina.com.cn/androidguy   昵稱:李寧_Lining

          posted on 2009-09-20 17:54 銀河使者 閱讀(2641) 評(píng)論(1)  編輯  收藏 所屬分類: java 原創(chuàng)移動(dòng)(mobile)

          評(píng)論

          # re: 流媒體程序開發(fā)之:H264解碼器移植到OPhone  回復(fù)  更多評(píng)論   

          不錯(cuò)啊,頂一個(gè)
          2009-09-21 10:43 | xing
          主站蜘蛛池模板: 阿克陶县| 阜阳市| 柘城县| 台湾省| 镇江市| 富川| 霍州市| 河池市| 扎兰屯市| 海南省| 遂昌县| 政和县| 岳阳县| 文昌市| 琼海市| 周宁县| 台州市| 铜梁县| 永安市| 辽宁省| 保山市| 郑州市| 屏南县| 车致| 五华县| 龙游县| 文山县| 兴城市| 垫江县| 津南区| 古丈县| 昭苏县| 普陀区| 宣汉县| 青海省| 达拉特旗| 赣州市| 资溪县| 开阳县| 和硕县| 保定市|