我从论坛中到一个android上的h264解码器,但解码速度很慢,图像也不大,只有352*288,播放出来完全是慢动作
请问大侠们,如何提高速度啊!!!
源码如下!
package h264.com;import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Matrix;//////////////////////////////////////////////////////////////////
import android.graphics.Paint;
import android.graphics.Bitmap.Config;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
public class H264Android extends Activity {//有关窗口的各种事宜都在Activity中声明 VView vv;
@Override
public void onCreate(Bundle savedInstanceState) {//建立并显示一个窗口
super.onCreate(savedInstanceState);
vv = new VView(this);
setContentView(vv);
}
// Menu item Ids
public static final int PLAY_ID = Menu.FIRST;
public static final int EXIT_ID = Menu.FIRST + 1; @Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
menu.add(0, PLAY_ID, 0, R.string.play);
menu.add(0, EXIT_ID, 1, R.string.exit); return true;
} @Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case PLAY_ID:
{
// 此处设定不同分辨率的码流文件
String file = "/sdcard/352x288.h264"; //352x288.264"; //240x320.264";
vv.PlayVideo(file);
return true;
}
case EXIT_ID:
{
finish();
return true;
}
}
return super.onOptionsItemSelected(item);
}
}//至此,对窗口的各种说明都完成class VView extends View implements Runnable{
Bitmap mBitQQ = null;
Paint mPaint = null;
Bitmap mSCBitmap = null;
Matrix matrix = new Matrix(); ////////////////////////////////////////////////////////////////////////////
int width = 352; // 此处设定不同的分辨率
int height = 288; byte [] mPixel = new byte[width*height*2];//创建一个字符串mPixel,单位为byte,个数为width*height*2
ByteBuffer buffer = ByteBuffer.wrap( mPixel );//将mPixel中的元素打包在Buffer中
Bitmap VideoBit = Bitmap.createBitmap(width, height, Config.RGB_565); //以参数所要求的格式创建一个bitmap
int mTrans=0x0F0F0F0F;
String PathFileName;
public native int InitDecoder(int width, int height);
public native int UninitDecoder();
public native int DecoderNal(byte[] in, int insize, byte[] out);
static {
System.loadLibrary("H264Android");
}
public VView(Context context) {//构造函数
super(context);
setFocusable(true);//使当前视图focused
int i = mPixel.length;
for(i=0; i<mPixel.length; i++)
{
mPixel[i]=(byte)0x00;//将mPixel中每个元素初始化为零
}
}
public void PlayVideo(String file)//这是VView的核心!
{
PathFileName = file; new Thread(this).start();//Thread构造器需要一个Runnable对象,使用start初始化,然后调用runnable的run方法!
}
@Override protected void onDraw(Canvas canvas) {
super.onDraw(canvas);//在画布上画图
//Bitmap VideoBit = Bitmap.createBitmap(width, height, Config.RGB_565);//.ARGB_8888); 在这面建Bitmap,视频播放更慢,貌似每三帧间还有暂停~
VideoBit.copyPixelsFromBuffer(buffer);//makeBuffer(data565, N));将buffer中的像素复制进VideoBit,但buffer中的像素并不变。
matrix.postScale(1,1); ///////////////////////////////////////////////////////////////////////////
matrix.setRotate(90,120,130); //////////////////////////////////////////////////////////////////// canvas.drawBitmap(VideoBit, 0, 0, null); //在画布上绘制指定的bitmap
}
int MergeBuffer(byte[] NalBuf, int NalBufUsed, byte[] SockBuf, int SockBufUsed, int SockRemain)
//将SockBuf中从第(SockBufUsed+1)元素到第(SockBufUsed+SockRemain)个元素add到NalBuf中,返回SockRemain
{
int i=0;
byte Temp; for(i=0; i<SockRemain; i++)
{
Temp =SockBuf[i+SockBufUsed];
NalBuf[i+NalBufUsed]=Temp;//将剩余的Sock中SockRemain个像素全部都存NalBuf[]中,从NalBuf[NalBufUsed]接着存~ mTrans <<= 8;//左移八位
mTrans |= Temp;//和Temp各位相或 if(mTrans == 1) // 找到一个开始byte ??
{
i++;
break;
}
} return i;
}
public void run()
{ InputStream is = null;
FileInputStream fileIS=null;
int iTemp=0;
int nalLen;
boolean bFirst=true;
boolean bFindPPS=true;
int bytesRead=0;
int NalBufUsed=0;
int SockBufUsed=0;
byte [] NalBuf = new byte[40980]; // 40k个元素
byte [] SockBuf = new byte[2048];//2k个元素
try
{
fileIS = new FileInputStream(PathFileName);//将文件PathFileName读入该流中
}
catch(IOException e)
{
return ;
}
InitDecoder(width, height); //根据宽高度初始化解码器
while (!Thread.currentThread().isInterrupted()) //若当前进程没有被打断,便执行
{
try
{
bytesRead = fileIS.read(SockBuf, 0, 2048);//从流fileIS中读取2048个byte到SockBuf中,显然将其写满了,返回实际读取数
//bytesRead = fileIS.read(SockBuf, 0, 2048);
// if(bytesRead<=0)
// break;
}
catch (IOException e) {}
if(bytesRead<=0)
break;
SockBufUsed =0;
while(bytesRead-SockBufUsed>0)//若SockBuff中所存byte数,大于SockBufUsed数
{
nalLen = MergeBuffer(NalBuf, NalBufUsed, SockBuf, SockBufUsed, bytesRead-SockBufUsed);
NalBufUsed+= nalLen;
SockBufUsed+= nalLen;
while(mTrans == 1)
{
mTrans = 0xFFFFFFFF; if(bFirst==true) // the first start flag
{
bFirst = false;
}
else // a complete NAL data, include 0x00000001 trail.
{
if(bFindPPS==true) // true
{
if( (NalBuf[4]&0x1F) == 7 )
{
bFindPPS = false;
}
else
{
NalBuf[0]=0;
NalBuf[1]=0;
NalBuf[2]=0;
NalBuf[3]=1;
NalBufUsed=4;
break;
}
}
// decode nal
iTemp=DecoderNal(NalBuf, NalBufUsed-4, mPixel);
if(iTemp>0)
postInvalidate(); //使用postInvalidate可以直接在线程中更新界面 // postInvalidate();
} NalBuf[0]=0;
NalBuf[1]=0;
NalBuf[2]=0;
NalBuf[3]=1;
NalBufUsed=4;
}
}
}
try{
if(fileIS!=null)
fileIS.close();
if(is!=null)
is.close();
}
catch (IOException e) {
e.printStackTrace();
}
UninitDecoder();
}
}
问题可能对于高手不太难,我在线等一会啊~
谢了!
请问大侠们,如何提高速度啊!!!
源码如下!
package h264.com;import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Matrix;//////////////////////////////////////////////////////////////////
import android.graphics.Paint;
import android.graphics.Bitmap.Config;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
public class H264Android extends Activity {//有关窗口的各种事宜都在Activity中声明 VView vv;
@Override
public void onCreate(Bundle savedInstanceState) {//建立并显示一个窗口
super.onCreate(savedInstanceState);
vv = new VView(this);
setContentView(vv);
}
// Menu item Ids
public static final int PLAY_ID = Menu.FIRST;
public static final int EXIT_ID = Menu.FIRST + 1; @Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
menu.add(0, PLAY_ID, 0, R.string.play);
menu.add(0, EXIT_ID, 1, R.string.exit); return true;
} @Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case PLAY_ID:
{
// 此处设定不同分辨率的码流文件
String file = "/sdcard/352x288.h264"; //352x288.264"; //240x320.264";
vv.PlayVideo(file);
return true;
}
case EXIT_ID:
{
finish();
return true;
}
}
return super.onOptionsItemSelected(item);
}
}//至此,对窗口的各种说明都完成class VView extends View implements Runnable{
Bitmap mBitQQ = null;
Paint mPaint = null;
Bitmap mSCBitmap = null;
Matrix matrix = new Matrix(); ////////////////////////////////////////////////////////////////////////////
int width = 352; // 此处设定不同的分辨率
int height = 288; byte [] mPixel = new byte[width*height*2];//创建一个字符串mPixel,单位为byte,个数为width*height*2
ByteBuffer buffer = ByteBuffer.wrap( mPixel );//将mPixel中的元素打包在Buffer中
Bitmap VideoBit = Bitmap.createBitmap(width, height, Config.RGB_565); //以参数所要求的格式创建一个bitmap
int mTrans=0x0F0F0F0F;
String PathFileName;
public native int InitDecoder(int width, int height);
public native int UninitDecoder();
public native int DecoderNal(byte[] in, int insize, byte[] out);
static {
System.loadLibrary("H264Android");
}
public VView(Context context) {//构造函数
super(context);
setFocusable(true);//使当前视图focused
int i = mPixel.length;
for(i=0; i<mPixel.length; i++)
{
mPixel[i]=(byte)0x00;//将mPixel中每个元素初始化为零
}
}
public void PlayVideo(String file)//这是VView的核心!
{
PathFileName = file; new Thread(this).start();//Thread构造器需要一个Runnable对象,使用start初始化,然后调用runnable的run方法!
}
@Override protected void onDraw(Canvas canvas) {
super.onDraw(canvas);//在画布上画图
//Bitmap VideoBit = Bitmap.createBitmap(width, height, Config.RGB_565);//.ARGB_8888); 在这面建Bitmap,视频播放更慢,貌似每三帧间还有暂停~
VideoBit.copyPixelsFromBuffer(buffer);//makeBuffer(data565, N));将buffer中的像素复制进VideoBit,但buffer中的像素并不变。
matrix.postScale(1,1); ///////////////////////////////////////////////////////////////////////////
matrix.setRotate(90,120,130); //////////////////////////////////////////////////////////////////// canvas.drawBitmap(VideoBit, 0, 0, null); //在画布上绘制指定的bitmap
}
int MergeBuffer(byte[] NalBuf, int NalBufUsed, byte[] SockBuf, int SockBufUsed, int SockRemain)
//将SockBuf中从第(SockBufUsed+1)元素到第(SockBufUsed+SockRemain)个元素add到NalBuf中,返回SockRemain
{
int i=0;
byte Temp; for(i=0; i<SockRemain; i++)
{
Temp =SockBuf[i+SockBufUsed];
NalBuf[i+NalBufUsed]=Temp;//将剩余的Sock中SockRemain个像素全部都存NalBuf[]中,从NalBuf[NalBufUsed]接着存~ mTrans <<= 8;//左移八位
mTrans |= Temp;//和Temp各位相或 if(mTrans == 1) // 找到一个开始byte ??
{
i++;
break;
}
} return i;
}
public void run()
{ InputStream is = null;
FileInputStream fileIS=null;
int iTemp=0;
int nalLen;
boolean bFirst=true;
boolean bFindPPS=true;
int bytesRead=0;
int NalBufUsed=0;
int SockBufUsed=0;
byte [] NalBuf = new byte[40980]; // 40k个元素
byte [] SockBuf = new byte[2048];//2k个元素
try
{
fileIS = new FileInputStream(PathFileName);//将文件PathFileName读入该流中
}
catch(IOException e)
{
return ;
}
InitDecoder(width, height); //根据宽高度初始化解码器
while (!Thread.currentThread().isInterrupted()) //若当前进程没有被打断,便执行
{
try
{
bytesRead = fileIS.read(SockBuf, 0, 2048);//从流fileIS中读取2048个byte到SockBuf中,显然将其写满了,返回实际读取数
//bytesRead = fileIS.read(SockBuf, 0, 2048);
// if(bytesRead<=0)
// break;
}
catch (IOException e) {}
if(bytesRead<=0)
break;
SockBufUsed =0;
while(bytesRead-SockBufUsed>0)//若SockBuff中所存byte数,大于SockBufUsed数
{
nalLen = MergeBuffer(NalBuf, NalBufUsed, SockBuf, SockBufUsed, bytesRead-SockBufUsed);
NalBufUsed+= nalLen;
SockBufUsed+= nalLen;
while(mTrans == 1)
{
mTrans = 0xFFFFFFFF; if(bFirst==true) // the first start flag
{
bFirst = false;
}
else // a complete NAL data, include 0x00000001 trail.
{
if(bFindPPS==true) // true
{
if( (NalBuf[4]&0x1F) == 7 )
{
bFindPPS = false;
}
else
{
NalBuf[0]=0;
NalBuf[1]=0;
NalBuf[2]=0;
NalBuf[3]=1;
NalBufUsed=4;
break;
}
}
// decode nal
iTemp=DecoderNal(NalBuf, NalBufUsed-4, mPixel);
if(iTemp>0)
postInvalidate(); //使用postInvalidate可以直接在线程中更新界面 // postInvalidate();
} NalBuf[0]=0;
NalBuf[1]=0;
NalBuf[2]=0;
NalBuf[3]=1;
NalBufUsed=4;
}
}
}
try{
if(fileIS!=null)
fileIS.close();
if(is!=null)
is.close();
}
catch (IOException e) {
e.printStackTrace();
}
UninitDecoder();
}
}
问题可能对于高手不太难,我在线等一会啊~
谢了!
用的不会是emulator吧
做解码,最好用native代码。
2.按照9楼说的,用native c语言实现解码,在java中调用native函数
关注ing
public native int InitDecoder(int width, int height);
public native int UninitDecoder();
public native int DecoderNal(byte[] in, int insize, byte[] out);
都是用的natve,难道其他的buffer转换,构造bitmap等都应该用native?
模拟器上慢不代表真机上也慢,找个真机上试试不就知道了。
另外。352x288在手机上已经不算小了。QCIF 176x144的才叫小。还有320x240的