android!如何加快h264解码速度?352*288

nicnac 2011-02-26 02:43:17
我从论坛中到一个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();
}
}
问题可能对于高手不太难,我在线等一会啊~
谢了!
...全文
2807 39 打赏 收藏 转发到动态 举报
写回复
用AI写文章
39 条回复
切换为时间正序
请发表友善的回复…
发表回复
duhaihao 2013-03-21
  • 打赏
  • 举报
回复
现在也想利用这个代码做一些应用,速度我觉得还好,最大的问题是你们所说的bug,使用过程中不确定的崩溃报错,谁有解决方法,请帮忙提供一下,万分感谢。也可以私聊。企鹅 26560174
  • 打赏
  • 举报
回复
是的。有一个bug。
iammadeinchina4 2012-10-23
  • 打赏
  • 举报
回复
这个问题应该是机子性能的问题,我目前用的也是你这个库,用比较差的机子的话是会有两到三秒的延迟,用双核的机子的话差不多有不到一秒左右的延迟,但是现在问题是,这个库有问题,经常会崩掉,它里面的有一个是不能及时释放指针的好像,然后会造成一个 build fingerprinter的debug,程序崩溃,目前正在寻找硬解码方式来处理,不知道谁有没有好的办法。
Yikaikai 2012-05-30
  • 打赏
  • 举报
回复
问题解决了么?我也遇到这样的问题了。
nicnac 2012-05-30
  • 打赏
  • 举报
回复
[Quote=引用 33 楼 的回复:]

问题解决了么?我也遇到这样的问题了。
[/Quote]
没有,我后来干其他活了,这个就搁置了,有别人处理,我完全不知情呢~
nicnac 2012-05-30
  • 打赏
  • 举报
回复
[Quote=引用 33 楼 的回复:]

问题解决了么?我也遇到这样的问题了。
[/Quote]
没有,我后来干其他活了,这个就搁置了,有别人处理,我完全不知情呢~
nicnac 2012-05-30
  • 打赏
  • 举报
回复
[Quote=引用 33 楼 的回复:]

问题解决了么?我也遇到这样的问题了。
[/Quote]
没有,我后来干其他活了,这个就搁置了,有别人处理,我完全不知情呢~
tinystone 2012-03-01
  • 打赏
  • 举报
回复
肯定是因为你的模拟器,用真机。g7之类好一点的,肯定没问题。
veryitman 2011-11-02
  • 打赏
  • 举报
回复
解码库优化,不是一件简单事情。
手机上,一般使用小码流的。我的实时传输就没有问题!
fokman 2011-08-02
  • 打赏
  • 举报
回复
很明显你这个调用的是ffmeg的api,我估计是模拟器的原因,你到真机上跑一下看效果如何
along0612 2011-07-16
  • 打赏
  • 举报
回复
[Quote=引用 9 楼 jxxx2967 的回复:]
大哥,你在JAVA里做解码,然后构造BITMAP显示?不慢才怪呢!
做解码,最好用native代码。
[/Quote]
大哥,你怎么知道这是在java里做解码。主要的解码函数DecodeNal也是通过C的Native代码实现的。没贴出来。
模拟器上慢不代表真机上也慢,找个真机上试试不就知道了。
另外。352x288在手机上已经不算小了。QCIF 176x144的才叫小。还有320x240的
nicnac 2011-03-25
  • 打赏
  • 举报
回复
[Quote=引用 27 楼 jingnan623 的回复:]

兄弟 解决没有啊 我也遇到这样的问题了。硬件解码还要买硬件解码器啊?那还是软解吧
[/Quote]
软解码可以的,我师兄做出来了,我转做其他项目了,具体怎么做我也不清楚,但确定在真机上比在模拟器上跑的可快,在不加delay的情况下播放基本上是常速,所以还是慢,但比模拟器强多了,具体你研究下,可以搞出来的,要不android上岂不是开发不成播放器了,不可能的事情!呵呵~
jingnan623 2011-03-11
  • 打赏
  • 举报
回复
兄弟 解决没有啊 我也遇到这样的问题了。硬件解码还要买硬件解码器啊?那还是软解吧
sepac 2011-03-02
  • 打赏
  • 举报
回复
我也想知道,如何集成硬解码????
华亭真人 2011-03-02
  • 打赏
  • 举报
回复
[Quote=引用 25 楼 sepac 的回复:]
我也想知道,如何集成硬解码????
[/Quote]

这个要去买硬件解码器。。。
nicnac 2011-03-01
  • 打赏
  • 举报
回复
[Quote=引用 21 楼 votzapomni 的回复:]
JNI调用,虽然是本地的,但解码用的还是软件解码,接口函数背后是算法,没有使用硬件加速的缘故
[/Quote]
如何实现硬件加速!
nicnac 2011-03-01
  • 打赏
  • 举报
回复
[Quote=引用 18 楼 mjh1021 的回复:]
楼主这个代码是调用的一个ffmpeg中的h264移植到android的native代码,播352*288的是会卡,可能是模拟器的缘故吧。
[/Quote]
您试过了?确实会卡,如何实现硬解码啊?
nicnac 2011-03-01
  • 打赏
  • 举报
回复
[Quote=引用 21 楼 votzapomni 的回复:]
JNI调用,虽然是本地的,但解码用的还是软件解码,接口函数背后是算法,没有使用硬件加速的缘故
[/Quote]
请问如何实现硬解码,能稍微讲一下么?
votzapomni 2011-03-01
  • 打赏
  • 举报
回复
JNI调用,虽然是本地的,但解码用的还是软件解码,接口函数背后是算法,没有使用硬件加速的缘故
nicnac 2011-03-01
  • 打赏
  • 举报
回复
[Quote=引用 9 楼 jxxx2967 的回复:]
大哥,你在JAVA里做解码,然后构造BITMAP显示?不慢才怪呢!
做解码,最好用native代码。
[/Quote]
大哥,我的关键解码函数
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?
加载更多回复(18)
自己利用业余优化了一个h264解码器,只使用在armv6架构的android2.3版本的手机上, 优化的内容是:完全用汇编重写了解码h264的预测算法、IDCT算法、反量化算法、MC算法、loop_filter算法。 我的测试: 手机:C8650,配置:CPU:MSM7627-600MHZ,RAM:512M,android2.3.6 测试结果(baseline,mainline,highline解码速度相差不是很大): 352*288H264视频:完全流畅播放 512*288H264视频:每秒播放20--25帧 704*576的H264视频:每秒播放20帧左右 1280*544的H264视频:每秒解码12-15帧,播放8--9帧(主要是YUV420转rgb565这里太浪费时间,还在优化中) 1280*720的H264视频:每秒解码13-16帧,播放8--10帧(也是YUV420转rgb565这里浪费时间), 测试结果:1280*544和1280*720的视频文件中,我的解码器要远远优于市面上的mobo播放器,开讯播放器等播放器的解码播放速度。 你如果要测试,则:需要您的手机CPU是armv6架构的,并且支持vfpv3。 视频条件: 视频采样点是8位,完全符合H264编码的视频文件(打包成多媒体格式也可以),采样格式是YUV420。(因为一直从事安防行业,就只按照安防的通用格式来) 下一步的计划是:利用ARM的vfp协处理器汇编指令,争取把YUV420转RGB565的转换速度优化到 稍后上传一些一些测试文件,欢迎下载测试(可点击我的名字,查找),谢谢 我会一直在H264解码算法这块进行优化,不做播放器,只做高性能的H264解码器,如果您有兴趣,希望和我联系:sno_guo#163.com 谢谢

80,351

社区成员

发帖
与我相关
我的任务
社区描述
移动平台 Android
androidandroid-studioandroidx 技术论坛(原bbs)
社区管理员
  • Android
  • yechaoa
  • 失落夏天
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧