SurfaceView播放视频作为拉伸视图

3
我正在使用mediaplayer.xml播放视频文件。
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/MainView"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#4d4d4d"
android:gravity="center"
android:keepScreenOn="true"
android:orientation="vertical" >

<SurfaceView
   android:id="@+id/surfaceView"
   android:layout_width="fill_parent"
   android:layout_height="wrap_content"
   android:layout_gravity="center"
   />

</LinearLayout>

以下是使用SurfaceView和MediaPlayer的MediaPlayerActivity类。
在纵向模式下播放视频时,视频似乎被拉伸了。我想把视频垂直居中播放,不占用整个屏幕,而在横向模式下则应该以全屏模式播放。
public class MediaPlayerActivity extends Activity implements OnCompletionListener,
OnErrorListener, OnInfoListener, OnBufferingUpdateListener,
OnPreparedListener, OnSeekCompleteListener, SurfaceHolder.Callback,
MediaController.MediaPlayerControl {

private MediaController controller;
Display currentDisplay;
private SurfaceView surfaceView;
private SurfaceHolder surfaceHolder;
private MediaPlayer mediaPlayer;

int videoWidth = 0;
int videoHeight = 0;
boolean readyToPlay = false;

private String streamingVideoUrl;

private ProgressDialog dialog;

public final  String TAG = "VIDEO_PLAYER";

@Override
protected void onCreate(Bundle savedInstanceState) {

    super.onCreate(savedInstanceState);
    Log.d(TAG,"Media player activity called ");
    setContentView(R.layout.mediaplayer);

    if(getIntent() != null ){
        streamingVideoUrl = getIntent().getStringExtra("stream_url"); 
    }

    surfaceView = (SurfaceView) findViewById(R.id.surfaceView);
    surfaceView.setOnClickListener(surViewClickListener);

    surfaceHolder = surfaceView.getHolder();

    surfaceHolder.addCallback(this);

    surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
    /*setVideoSize();*/
    try {
    mediaPlayer = new MediaPlayer();

    mediaPlayer.setOnCompletionListener(this);
    mediaPlayer.setOnErrorListener(this);
    mediaPlayer.setOnInfoListener(this);
    mediaPlayer.setOnPreparedListener(this);
    mediaPlayer.setOnSeekCompleteListener(this);


    mediaPlayer.setOnBufferingUpdateListener(this);
    mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
    //Log.d(TAG,"Returned by getDatasource :"+getDataSource(streamingVideoUrl));
        mediaPlayer.setDataSource(streamingVideoUrl);
    } catch (IllegalArgumentException e) {

        e.printStackTrace();
    } catch (SecurityException e) {

        e.printStackTrace();
    } catch (IllegalStateException e) {

        e.printStackTrace();
    } catch (IOException e) {

        e.printStackTrace();
    }

    catch(Exception e)
    {
        e.printStackTrace();
    }

    currentDisplay = getWindowManager().getDefaultDisplay();
    controller = new MediaController(this);

    dialog = new ProgressDialog(this);
    //dialog.setMessage("Preparing File to Streaming");
    dialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
    dialog.setCanceledOnTouchOutside(false);
    if(this!= null && !this.isFinishing()){

        dialog.show();
    }

    handler.postDelayed(r, 100);
}

/*private void setVideoSize() {


    try {
        // // Get the dimensions of the video
        int videoWidth = mediaPlayer.getVideoWidth();
        int videoHeight = mediaPlayer.getVideoHeight();
        float videoProportion = (float) videoWidth / (float) videoHeight;

        // Get the width of the screen
        int screenWidth = getWindowManager().getDefaultDisplay().getWidth();
        int screenHeight = getWindowManager().getDefaultDisplay().getHeight();
        float screenProportion = (float) screenWidth / (float) screenHeight;

        // Get the SurfaceView layout parameters
        android.view.ViewGroup.LayoutParams lp = surfaceView.getLayoutParams();
        if (videoProportion > screenProportion) {
            lp.width = screenWidth;
            lp.height = (int) ((float) screenWidth / videoProportion);
        } else {
            lp.width = (int) (videoProportion * (float) screenHeight);
            lp.height = screenHeight;
        }
        // Commit the layout parameters
        surfaceView.setLayoutParams(lp);
    } catch (Exception e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
}*/


/*//coded by Karthikeyan V
    //converting url to byte 
    private String getDataSource(String path) throws IOException {
        Log.d(TAG,"getDataSource called");
        if (!URLUtil.isNetworkUrl(path)) {
            return path;
        } else {
            URL url = new URL(path);
            URLConnection cn = url.openConnection();
            cn.connect();
            InputStream stream = cn.getInputStream();
            if (stream == null)
                throw new RuntimeException("stream is null");
            File temp = File.createTempFile("mediaplayertmp", "dat");
            temp.deleteOnExit();
            String tempPath = temp.getAbsolutePath();
            FileOutputStream out = new FileOutputStream(temp);
            byte buf[] = new byte[128];
            do {
                int numread = stream.read(buf);
                if (numread <= 0)
                    break;
                out.write(buf, 0, numread);
            } while (true);
            try {
                stream.close();
            } catch (IOException ex) {
                Log.e(TAG, "error: " + ex.getMessage(), ex);
            }
            Log.d(TAG,"temp path :"+tempPath);
            return tempPath;
        }
    }*/


@Override
public boolean canPause() {

    return true;
}

@Override
public boolean canSeekBackward() {

    return true;
}

@Override
public boolean canSeekForward() {

    return true;
}

@Override
public int getBufferPercentage() {

    return 0;
}

@Override
public int getCurrentPosition() {

    if(mediaPlayer !=null)
        return mediaPlayer.getCurrentPosition();
    else 
        return 0;
}

@Override
public int getDuration() {

    return mediaPlayer.getDuration();
}

@Override
public boolean isPlaying() {

    return mediaPlayer.isPlaying();
}

@Override
public void pause() {

    if (mediaPlayer != null) {
        if (mediaPlayer.isPlaying()) {
            mediaPlayer.pause();
        }
    }
}

@Override
public void seekTo(int pos) {

    mediaPlayer.seekTo(pos);
}

@Override
public void start() {

    mediaPlayer.start();
}

@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
        int height) {
    if(Constants.DEBUG)
        Log.v(TAG, "Media Flow surfaceChanged Called");
} 
@Override
public void surfaceCreated(SurfaceHolder holder) {

    if(Constants.DEBUG)
        Log.v(TAG, "Media Flow surfaceCreated Called");
    mediaPlayer.setDisplay(holder);

    try {
        mediaPlayer.prepareAsync();
    } catch (IllegalStateException e) {
        if(Constants.DEBUG)
            Log.v(TAG, "Media Flow IllegalStateException " + e.getMessage());
        finish();
    }

    if(Constants.DEBUG)
        Log.d(TAG, "Media Flow MediaPlayer Preparing");

}

@Override
public void surfaceDestroyed(SurfaceHolder holder) {
    if(Constants.DEBUG)
        Log.v(TAG, "Media Flow surfaceDestroyed Called");
}


@Override
public void onSeekComplete(MediaPlayer mp) {
    if(Constants.DEBUG)
        Log.v(TAG, "Media Flow onSeekComplete Called");
}

@Override
public void onPrepared(MediaPlayer mp) {

    if(Constants.DEBUG)
        Log.v(TAG, "Media Flow onPrepared Called");

    // dismissProgressLoading();

    controller.setMediaPlayer(this);
    controller.setAnchorView(this.findViewById(R.id.MainView));
    controller.setEnabled(true);
    controller.show();
    mp.start();

}

@Override
public void onBufferingUpdate(MediaPlayer mp, int percent) {

    if(Constants.DEBUG)
        Log.v(TAG, "Media Flow MediaPlayer Buffering: " + percent + "%");
    dismissProgressLoading();
}

@Override
public boolean onInfo(MediaPlayer mp, int whatInfo, int extra) {
    // 
    dismissProgressLoading();

    if(Constants.DEBUG)
    {
        if (whatInfo == MediaPlayer.MEDIA_INFO_BAD_INTERLEAVING) {
            if(Constants.DEBUG)
                Log.v(TAG, "Media Flow Media Info, Media Info Bad Interleaving " + extra);
        } else if (whatInfo == MediaPlayer.MEDIA_INFO_NOT_SEEKABLE) {
            if(Constants.DEBUG)
                Log.v(TAG, "Media Flow Media Info, Media Info Not Seekable " + extra);
        } else if (whatInfo == MediaPlayer.MEDIA_INFO_UNKNOWN) {
            Log.v(TAG, "Media Flow Media Info, Media Info Unknown " + extra);
        } else if (whatInfo == MediaPlayer.MEDIA_INFO_VIDEO_TRACK_LAGGING) {
            Log.v(TAG, "Media Flow MediaInfo, Media Info Video Track Lagging " + extra);
        } else if (whatInfo == MediaPlayer.MEDIA_INFO_METADATA_UPDATE) {
            Log.v(TAG, "Media Flow MediaInfo, Media Info Metadata Update " + extra);
        }
    }

    return false;
}

@Override
public boolean onError(MediaPlayer mp, int what, int extra) {
    // TODO Auto-generated method stub

    dismissProgressLoading();

    StringBuilder sb = new StringBuilder();
    sb.append("Media Player Error: ");
    switch (what) {
    case MediaPlayer.MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK:
        sb.append("Not Valid for Progressive Playback");
        break;
    case MediaPlayer.MEDIA_ERROR_SERVER_DIED:
        sb.append("Server Died");
        break;
    case MediaPlayer.MEDIA_ERROR_UNKNOWN:
        sb.append("Media Error Unknown");
        break;
    default:
        sb.append(" Non standard (");
        sb.append(what);
        sb.append(")");
    }
    //sb.append(" (" + what + ") ");
    sb.append(extra);

    showErrorDialog("Cannot play video", sb.toString());


    return true;
}

void dismissProgressLoading() {
    if (dialog != null && dialog.isShowing()) {
        dialog.dismiss();
    }
}

@Override
public void onCompletion(MediaPlayer mp) {
    if(Constants.DEBUG)
    Log.v(TAG, "Media Flow onCompletion Called");
    dismissProgressLoading();
    onBackPressed();
}


@Override
public void onBackPressed() {
    // TODO Auto-generated method stub
    super.onBackPressed();
}


final Runnable r = new Runnable() {
    public void run() {

        if (mediaPlayer != null) {
            if (mediaPlayer.isPlaying()
                    && mediaPlayer.getCurrentPosition() > 0) {
                if(Constants.DEBUG)
                Log.d(TAG, "isPlaying : " + mediaPlayer.isPlaying());
                if(Constants.DEBUG)
                Log.d(TAG,
                        "currentPosition : "
                                + mediaPlayer.getCurrentPosition());

                handler.sendEmptyMessage(0);
            } else {
                handler.postDelayed(this, 100);
            }
        }
    }
};

Handler handler = new Handler() {

    public void handleMessage(Message msg) {
        dismissProgressLoading();
    }

};

@Override
protected void onResume() {

    if(Constants.SHOULD_FINISH_APPLICATION)
        finish();
    super.onResume();
}

@Override
protected void onRestart() {        
    super.onRestart();

}

protected void onPause() {
    super.onPause();
    pause();
}

@Override
protected void onDestroy() {

    super.onDestroy();

    dismissProgressLoading();

    if (mediaPlayer != null) {
        mediaPlayer.stop();
        mediaPlayer.release();
        mediaPlayer = null;
    }
    if(controller !=null)
    {
        controller.hide();
    }
}

OnClickListener surViewClickListener = new OnClickListener() {

    @Override
    public void onClick(View v) {


        if (controller != null) {
            if (controller.isShowing()) {
                controller.hide();

            } else {
                controller.show();

            }
        }
    }
};

@SuppressWarnings("deprecation")
void showErrorDialog(String title, String message) {
    AlertDialog alertDialog = new AlertDialog.Builder(this).create();

    // Setting Dialog Title
    alertDialog.setTitle(title);

    // Setting Dialog Message
    alertDialog.setMessage(message);

    // Setting Icon to Dialog
    alertDialog.setIcon(android.R.drawable.ic_dialog_alert);

    // Setting OK Button
    alertDialog.setButton("OK", new DialogInterface.OnClickListener() {
        public void onClick(DialogInterface dialog, int which) {
            // Write your code here to execute after dialog closed

            dialog.dismiss();
            finish();
        }
    });


    // Showing Alert Message
    if(this!= null && !this.isFinishing()){
        alertDialog.show();
    }


}

}


你有没有找到解决这个问题的办法?我也遇到了同样的问题。我可以修复并预览,但是停止录制时会失败。 - Chris
@Chris 我使用了VideoView而不是SurfaceView。我不确定这是否是正确的解决方案。而且我还没有实现录制选项。 - Karthikeyan Ve
太棒了,谢谢你告诉我伙计!我还没有看过VideoView,一定值得研究。学习新东西总是好的。 - Chris
2个回答

6
handleAspectRatio() {
    int surfaceView_Width = surfaceView.getWidth();
    int surfaceView_Height = surfaceView.getHeight();

    float video_Width = mediaPlayer.getVideoWidth();
    float video_Height = mediaPlayer.getVideoHeight();

    float ratio_width = surfaceView_Width/video_Width;
    float ratio_height = surfaceView_Height/video_Height;
    float aspectratio = video_Width/video_Height;

    LayoutParams layoutParams = surfaceView.getLayoutParams();

    if (ratio_width > ratio_height){
        layoutParams.width = (int) (surfaceView_Height * aspectratio);
        layoutParams.height = surfaceView_Height;
    }else{
        layoutParams.width = surfaceView_Width;
        layoutParams.height = (int) (surfaceView_Width / aspectratio);
    }

    surfaceView.setLayoutParams(layoutParams);
}

在调用上面的函数之前,请调用该函数。
mediaPlayer.start();

3

我遇到了同样的问题,在研究了API 23中VideoView源代码后,我发现了一个好方法。这是我的解决方案,我们可以创建一个自定义SurfaceView并重写onMeasure(),然后你就可以使用VideoSurfaceView来播放视频。

public class VideoSurfaceView extends SurfaceView implements MediaPlayer.OnVideoSizeChangedListener {
    private int mVideoWidth;
    private int mVideoHeight;

    public VideoSurfaceView(Context context) {
        super(context);
    }

    public VideoSurfaceView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public VideoSurfaceView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    /**
     * Set video size.
     *
     * @see MediaPlayer#getVideoWidth()
     * @see MediaPlayer#getVideoHeight()
     */
    public void setVideoSize(int videoWidth, int videoHeight) {
        mVideoWidth = videoWidth;
        mVideoHeight = videoHeight;
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        //Log.i("@@@@", "onMeasure(" + MeasureSpec.toString(widthMeasureSpec) + ", "
        //        + MeasureSpec.toString(heightMeasureSpec) + ")");

        int width = getDefaultSize(mVideoWidth, widthMeasureSpec);
        int height = getDefaultSize(mVideoHeight, heightMeasureSpec);
        if (mVideoWidth > 0 && mVideoHeight > 0) {

            int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);
            int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec);
            int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);
            int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec);

            if (widthSpecMode == MeasureSpec.EXACTLY && heightSpecMode == MeasureSpec.EXACTLY) {
                // the size is fixed
                width = widthSpecSize;
                height = heightSpecSize;

                // for compatibility, we adjust size based on aspect ratio
                if (mVideoWidth * height < width * mVideoHeight) {
                    //Log.i("@@@", "image too wide, correcting");
                    width = height * mVideoWidth / mVideoHeight;
                } else if (mVideoWidth * height > width * mVideoHeight) {
                    //Log.i("@@@", "image too tall, correcting");
                    height = width * mVideoHeight / mVideoWidth;
                }
            } else if (widthSpecMode == MeasureSpec.EXACTLY) {
                // only the width is fixed, adjust the height to match aspect ratio if possible
                width = widthSpecSize;
                height = width * mVideoHeight / mVideoWidth;
                if (heightSpecMode == MeasureSpec.AT_MOST && height > heightSpecSize) {
                    // couldn't match aspect ratio within the constraints
                    height = heightSpecSize;
                }
            } else if (heightSpecMode == MeasureSpec.EXACTLY) {
                // only the height is fixed, adjust the width to match aspect ratio if possible
                height = heightSpecSize;
                width = height * mVideoWidth / mVideoHeight;
                if (widthSpecMode == MeasureSpec.AT_MOST && width > widthSpecSize) {
                    // couldn't match aspect ratio within the constraints
                    width = widthSpecSize;
                }
            } else {
                // neither the width nor the height are fixed, try to use actual video size
                width = mVideoWidth;
                height = mVideoHeight;
                if (heightSpecMode == MeasureSpec.AT_MOST && height > heightSpecSize) {
                    // too tall, decrease both width and height
                    height = heightSpecSize;
                    width = height * mVideoWidth / mVideoHeight;
                }
                if (widthSpecMode == MeasureSpec.AT_MOST && width > widthSpecSize) {
                    // too wide, decrease both width and height
                    width = widthSpecSize;
                    height = width * mVideoHeight / mVideoWidth;
                }
            }
        } else {
            // no size yet, just adopt the given spec sizes
        }
        setMeasuredDimension(width, height);
    }

    @Override
    public void onVideoSizeChanged(MediaPlayer mp, int width, int height) {
        mVideoWidth = mp.getVideoWidth();
        mVideoHeight = mp.getVideoHeight();
        if (mVideoWidth != 0 && mVideoHeight != 0) {
            getHolder().setFixedSize(mVideoWidth, mVideoHeight);
            requestLayout();
        }
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接