目录结构:
自定义的RemoteView
public class RemoteView extends GLSurfaceView {
ViewCommon mViewCommon = new ViewCommon ();
public static final String TAG = "MyGLSurfaceView";
public RemoteView(Context context) {
this(context ,null);
}
public RemoteView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public void init(){
rotatedFrameWidth = 0;
rotatedFrameHeight = 0;
}
private int rotatedFrameWidth;
private int rotatedFrameHeight;
public void updateLayout(int newWitch ,int height){
if (rotatedFrameWidth == newWitch && rotatedFrameHeight == height){
return;
}
rotatedFrameWidth = newWitch;
rotatedFrameHeight = height;
post(new Runnable() {
@Override
public void run() {
requestLayout();
}
});
}
@Override
protected void onMeasure(int widthSpec, int heightSpec) {
super.onMeasure(widthSpec, heightSpec);
final Point size;
size = mViewCommon.measure(widthSpec, heightSpec, rotatedFrameWidth, rotatedFrameHeight);
setMeasuredDimension(size.x, size.y);
Log.d(TAG,widthSpec+","+heightSpec+","+rotatedFrameWidth+","+rotatedFrameHeight
+" "+size.x+","+size.y);
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
super.onLayout(changed, l, t, r, b);
Log.d(TAG,changed+" "+l+" "+t+" "+r+" "+b);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
}
}
activity中播放
public class MainActivity extends AppCompatActivity {
View playerButton;
public static final String TAG="MainActivity";
RemoteView remoteRender;
OpenGlInterface2Android pinterfaceOpenGL;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
playerButton = findViewById(R.id.player);
playerButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
playerButton.setEnabled(false);
new Thread(){
@Override
public void run() {
super.run();
try {
player();
} catch (Exception exception) {
exception.printStackTrace();
}
}
}.start();
}
});
remoteRender = findViewById(R.id.remote_view);
remoteRender.setEGLContextClientVersion ( 2 );
pinterfaceOpenGL = new OpenGlInterface2Android(remoteRender);
remoteRender.setRenderer(pinterfaceOpenGL);
remoteRender.setRenderMode ( GLSurfaceView.RENDERMODE_WHEN_DIRTY );
}
private void player() throws Exception {
File file = new File( getCacheDir(),"i420_1280x720_30fps.yuv");
if (!file.exists()) {
InputStream inputStream = getAssets().open("i420_1280x720_30fps.yuv");
file.createNewFile();
FileOutputStream fileOutputStream =new FileOutputStream(file);
byte[] buffer = new byte[1024];
int srcTotalLen=0;
int len=0;
while ((len = inputStream.read(buffer))>0){
fileOutputStream.write(buffer,0,len);
srcTotalLen+=len;
}
fileOutputStream.close();
Log.e(TAG,"src:"+srcTotalLen+" ,dest:"+file.length());
}else{
Log.e(TAG,"文件存在 file.length()");
}
int width=1280;
int height=720;
//yuv I420的数据是 1像素1个Y 4个Y共享1个uv,所以下面是乘以1.5
byte[] yuvBuffer = new byte[(int)(width*height*1.5)];
RandomAccessFile randomAccessFile = new RandomAccessFile(file ,"r");
int readYuvLen;
while ((readYuvLen = randomAccessFile.read(yuvBuffer))>0){
Log.e(TAG,"readYuvLen:"+readYuvLen);
pinterfaceOpenGL.resetYUVSize ( width,height,null );
remoteRender.updateLayout ( width,height );
if (readYuvLen ==yuvBuffer.length ){
pinterfaceOpenGL.rendererView ( yuvBuffer );
}else{
byte[] yuvBufferFlag = new byte[readYuvLen];
System.arraycopy(yuvBuffer,0,yuvBufferFlag,0,readYuvLen);
pinterfaceOpenGL.rendererView ( yuvBufferFlag );
}
Thread.sleep(500);
}
runOnUiThread(new Runnable() {
@Override
public void run() {
if (playerButton!=null)
playerButton.setEnabled(true);
}
});
}
}
主要的播放YUV数据的接口在
OpenGlInterface2Android.java中
没有分的可以加我的微信
wangcjx1234
demo地址:https://download.csdn.net/download/weixin_37699548/85555821