Play YUV video on Android

1.5k views Asked by At

I want to show the YUV video on the android However, my project can only display first frame of the video I cannot display next frame successfully in current state

the following is my java code:

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

}


}

also I try to print every frames first pixel all the content is the same It shouldn't be like that

Hope a anyone can give me the answer

2

There are 2 answers

1
BitBank On BEST ANSWER

It appears that in your readYUV() method, you're reading the first frame over and over. Each time you open a stream to the source file, it starts at offset 0. You need to use the FileInputStream.skip() method to seek to the correct spot for each frame or keep the stream pointer in a variable which doesn't go out of scope. You also should close the stream when finished.

1
pinxue On

You didn't seek in readYUV. It always read the first frame.

PS, the yuv2rgb can be bottleneck if image is large, try somr NEON optimzed version.