在Android上播放YUV视频

时间:2013-12-09 12:42:35

标签: android bitmap android-canvas yuv

我想在android上显示YUV视频 但是,我的项目只能显示视频的第一帧 我无法在当前状态下成功显示下一帧

以下是我的java代码:

public class SkiaView extends SurfaceView implements SurfaceHolder.Callback, Runnable
{
private SurfaceHolder holder=null;//******Version2******//
private static final String TAG = "skiademo";

private int mSampleId = 0;
// final Rect rect = new Rect(0, 0, 352, 288);  
final int width=352,height=288;

int FrameNum=0;

static 
{
    System.loadLibrary("SkiaDemo");
}

public native void renderHello(Canvas canvas, int FrameNum,Rect rect);
public native void renderText(Canvas canvas);
class Pixel
{
    byte Y,U,V;
};
private int[] YUV2RGB(byte [] YUV)
{
    Byte R,G,B;
    int y,x,i;
    int  [] argb = new int [width*height];
    byte [] Y= new byte[width*height];
    byte [] U= new byte[width*height];
    byte [] V= new byte[width*height];
    for(i=0;i<width*height;i++)
    {
        Y[i] =YUV[i];
        if(i==0)
        Log.d(TAG, "Y="+Y[i] +" YUV[i]=" +YUV[i]);
    }
    i=0;
    byte container;
    for(y=0;y<height/2;y++)
        for(x=0;x<width/2;x++)
    {
        container =YUV[i+width*height];
        U[y*2*width+x*2]=container;
        U[y*2*width+x*2+1]=container;
        U[(y*2+1)*width+x*2]=container;
        U[(y*2+1)*width+x*2+1]=container;
        i++;

    }

    i=0;
    for(y=0;y<height/2;y++)
        for(x=0;x<width/2;x++)
    {
        container =YUV[i+width*height+width*height/4];
        V[y*2*width+x*2]=container;
        V[y*2*width+x*2+1]=container;
        V[(y*2+1)*width+x*2]=container;
        V[(y*2+1)*width+x*2+1]=container;

    } 
    for(i=0;i<width*height;i++)
    {
        R=(byte) (Y[i]+128+1.4075*(V[i]+128-128));
        G=(byte) (Y[i]+128-0.3455*(U[i]+128-128)-0.7169*(V[i]+128-128));
        B=(byte) (Y[i]+128+1.7790*(U[i]-128+128));
        argb[i]=(0xff000000 + (B << 16) + (G << 8) + R);
        if(i==0)
        {
            Log.d(TAG, "Y="+Y[i]+" U="+U[i]+ " V= "+V[i]);
            Log.d(TAG, "R="+R+" G="+G+ "B= "+B+" argb="+argb[0]);
        }

    }

    //Bitmap bmp=Bitmap.createBitmap(width,height,Bitmap.Config.ARGB_8888);


    return argb;


   }
 private void readYUV(String src,byte[] YUV,int frame )
 {      
    int i;
    try {
        FileInputStream inFile = new FileInputStream(src);
        int filelength=inFile.available();
        Log.d(TAG, "frame="+frame+" start="+width*height*1.5*frame+" Length="+width*height*1.5 + "   Filelength="+filelength);
            //inFile.read(YUV, (int)(width*height*1.5*(frame-1)),(int)(width*height*1.5));      
        for(i=0;i<width*height*1.5;i++)
            YUV[i]=(byte) inFile.read();

        Log.d(TAG, " YUV[i]=" +YUV[0]);
            inFile.close();   
    } catch(FileNotFoundException fe) {
        System.out.println("There is no such file!");

    } catch(IOException ioe) {
        System.out.println("IO exception!");

    }

}

public SkiaView(Context context)//******Version2******//
{
       super(context);
       // TODO Auto-generated constructor stub
       holder=getHolder();
       holder.addCallback(this);
}

public void surfaceCreated(SurfaceHolder holder)//******Version2******//
{
       // TODO Auto-generated method stub
      new Thread(this).start();
}
private Bitmap Bytes2Bimap(byte[] b){
       if(b.length!=0){
       return BitmapFactory.decodeByteArray(b, 0, b.length);
       }
       else {
       return null;
       }
    }
private void render(Canvas canvas,int i) {


    canvas.drawColor(Color.BLACK);
    byte [] YUV = new byte[(int) (width*height*1.5)];
    int  [] rgb = new int [width*height];
    Bitmap bmp = Bitmap.createBitmap(width,height,Bitmap.Config.ARGB_8888);
    readYUV("/mnt/sdcard/out_352x288_P420_final.yuv",YUV,i);
    rgb=YUV2RGB(YUV);

    bmp.setPixels(rgb, 0, width, 0, 0, width, height);
    Log.d(TAG, "pixel="+bmp.getPixel(0, 0));
    canvas.drawBitmap(bmp, 0, 0, null);

}
@Override
public void run() {
    int i=0;
    while(true)
    {
        Canvas canvas = holder.lockCanvas();
        render(canvas,i);
        i++;
        if(i>=299)
        i=0;
        holder.unlockCanvasAndPost(canvas);
    }
}

public void surfaceChanged(SurfaceHolder holder, int format, int width,
        int height) {
    // TODO Auto-generated method stub

}
public void surfaceDestroyed(SurfaceHolder holder) {
    // TODO Auto-generated method stub

}


}

我也尝试打印每个帧的第一个像素 所有内容都是一样的 它应该不是那样的

希望任何人都可以给我答案

2 个答案:

答案 0 :(得分:1)

在readYUV()方法中,您似乎一遍又一遍地读取第一帧。每次打开到源文件的流时,它都从偏移量0开始。您需要使用FileInputStream.skip()方法来寻找每个帧的正确位置,或者将流指针保存在一个不变量的变量中。超出范围。你也应该在完成后关闭流。

答案 1 :(得分:1)

你没有在readYUV中寻求。它总是读取第一帧。

PS,如果图像很大,yuv2rgb可能成为瓶颈,尝试使用somr NEON优化版本。