MediaPlayer 播放声音但不播放视频

Posted

技术标签:

【中文标题】MediaPlayer 播放声音但不播放视频【英文标题】:MediaPlayer playing sound but not video 【发布时间】:2014-01-15 14:02:47 【问题描述】:

我正在尝试使用 SurfaceView 播放来自 android 的视频。

我可以加载视频,声音可以正常播放,但我看不到视频。

这是我的活动:

public class VideoTest extends Activity implements OnBufferingUpdateListener, OnCompletionListener, OnPreparedListener, OnVideoSizeChangedListener, SurfaceHolder.Callback, OnErrorListener 

    private static final String TAG = "MediaPlayerDemo";
    private int mVideoWidth;
    private int mVideoHeight;
    private MediaPlayer mMediaPlayer;
    private SurfaceView mPreview;
    private SurfaceHolder holder;
    private String path;
    private Bundle extras;
    public static final String MEDIA = "media";
    private static final int LOCAL_AUDIO = 1;
    public static final int STREAM_AUDIO = 2;
    private static final int RESOURCES_AUDIO = 3;
    private static final int LOCAL_VIDEO = 4;
    public static final int STREAM_VIDEO = 5;
    private boolean mIsVideoSizeKnown = false;
    private boolean mIsVideoReadyToBePlayed = false;
    private RelativeLayout layout;

    /**
     *
     * Called when the activity is first created.
     */
    @Override
    public void onCreate(Bundle icicle) 
        super.onCreate(icicle);

        mPreview = new SurfaceView(this);
        holder = mPreview.getHolder();
        holder.addCallback(this);
        holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
        extras = getIntent().getExtras();

        mPreview.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));

        layout = new RelativeLayout(this);
        layout.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.FILL_PARENT));
        layout.addView(mPreview, 0);

        setContentView(layout);

    

    private void playVideo(Integer Media) 
        doCleanUp();
        try 
            mMediaPlayer = MediaPlayer.create(this, R.raw.video);
            mMediaPlayer.setDisplay(holder);

            mMediaPlayer.setOnBufferingUpdateListener(this);
            mMediaPlayer.setOnCompletionListener(this);
            mMediaPlayer.setOnPreparedListener(this);
            mMediaPlayer.setOnVideoSizeChangedListener(this);
            mMediaPlayer.setOnErrorListener(this);

            mMediaPlayer.setAudiostreamType(AudioManager.STREAM_MUSIC);

         catch (Exception e) 
            Log.e(TAG, "error: " + e.getMessage(), e);
        
    

    public void onBufferingUpdate(MediaPlayer arg0, int percent) 
        Log.d(TAG, "onBufferingUpdate percent:" + percent + " pos : " + mMediaPlayer.getCurrentPosition() + " / " + mMediaPlayer.getDuration());
        if (mMediaPlayer.isPlaying()) 
            Log.d(TAG, "Playing");
         else 
            mMediaPlayer.start();
        
    

    public void onCompletion(MediaPlayer arg0) 
        Log.d(TAG, "onCompletion called");
    

    public void onVideoSizeChanged(MediaPlayer mp, int width, int height) 
        Log.v(TAG, "onVideoSizeChanged called");
        if (width == 0 || height == 0) 
            Log.e(TAG, "invalid video width(" + width + ") or height(" + height
                    + ")");
            return;
        
        mIsVideoSizeKnown = true;
        mVideoWidth = width;
        mVideoHeight = height;
        if (mIsVideoReadyToBePlayed && mIsVideoSizeKnown) 
            startVideoPlayback();
        
    

    public void onPrepared(MediaPlayer mediaplayer) 
        Log.d(TAG, "onPrepared called");
        mIsVideoReadyToBePlayed = true;
        if (mIsVideoReadyToBePlayed && mIsVideoSizeKnown) 
            startVideoPlayback();
        
    

    public void surfaceChanged(SurfaceHolder surfaceholder, int i, int j, int k) 
        Log.d(TAG, "surfaceChanged called. Width : " + j + ", height : " + k);
        holder = surfaceholder;
        mMediaPlayer.setDisplay(holder);
        mIsVideoSizeKnown = true;
        mVideoWidth = j;
        mVideoHeight = k;
        if (mIsVideoReadyToBePlayed && mIsVideoSizeKnown) 
            startVideoPlayback();
        
    

    public void surfaceDestroyed(SurfaceHolder surfaceholder) 
        Log.d(TAG, "surfaceDestroyed called");
    

    public void surfaceCreated(SurfaceHolder holder) 
        Log.d(TAG, "surfaceCreated called");
        playVideo(extras.getInt(MEDIA));

    

    @Override
    protected void onPause() 
        super.onPause();
        releaseMediaPlayer();
        doCleanUp();
    

    @Override
    protected void onDestroy() 
        super.onDestroy();
        releaseMediaPlayer();
        doCleanUp();
    

    private void releaseMediaPlayer() 
        if (mMediaPlayer != null) 
            mMediaPlayer.release();
            mMediaPlayer = null;
        
    

    private void doCleanUp() 
        mVideoWidth = 0;
        mVideoHeight = 0;
        mIsVideoReadyToBePlayed = false;
        mIsVideoSizeKnown = false;
    

    private void startVideoPlayback() 
        Log.v(TAG, "startVideoPlayback " + mVideoWidth + "x" + mVideoHeight);

        int width = mPreview.getWidth();
        int height = mPreview.getHeight();
        float boxWidth = width;
        float boxHeight = height;

        float videoWidth = mMediaPlayer.getVideoWidth();
        float videoHeight = mMediaPlayer.getVideoHeight();

        Log.i(TAG, String.format("startVideoPlayback @ video %dx%d - box %dx%d", (int) videoWidth, (int) videoHeight, width, height));

        float wr = boxWidth / videoWidth;
        float hr = boxHeight / videoHeight;
        float ar = videoWidth / videoHeight;

        if (wr > hr) 
            width = (int) (boxHeight * ar);
         else 
            height = (int) (boxWidth / ar);
        

        Log.i(TAG, String.format("Scaled to %dx%d", width, height));

        holder.setFixedSize(width, height);
        mMediaPlayer.start();
    

    public boolean onError(MediaPlayer arg0, int arg1, int arg2) 
        Log.e(TAG, "ERROR called : " + arg1 + ", " + arg2);
        return false;
    

onVideoSizeChanged 函数从未被调用,但onPreparedsurfaceChanged 被调用。 于是调用了startVideoPlayback函数,但是视频的宽高都是0。

我的视频正在播放,我可以听到声音,但屏幕上没有显示任何内容。 我还尝试为SurfaceHolder 对象的setFixedSize 函数提供原始宽度和高度,但我仍然没有显示任何内容。

你能帮帮我吗? 我使用的是 Android 8

编辑

这是我从资源中播放视频时的日志:

WARN    info/warning (1, 35)
WARN    info/warning (1, 44)
DEBUG   Duration : 101248
DEBUG   surfaceChanged called. Width : 480, height : 270
INFO    Info (1,35)
INFO    Info (1,44)
DEBUG   onPrepared called
VERBOSE startVideoPlayback 480x270
INFO    startVideoPlayback @ video 0x0 - box 480x270
INFO    Scaled to 480x0
DEBUG   surfaceDestroyed called

编辑 2

我尝试了另一个视频,它可以正常工作。

以下是“不工作”视频的规格:

容器:MP4 - QuickTime 速率:2 340 Kbps 格式:H.264/MPEG-4-AVC 尺寸:1280*640 纵横比像素:未定义 图像比例:2.000 编码配置文件:Baseline@L3.1

以下是工作视频的规格:

容器:MP4 - QuickTime 速率:537 Kbps 格式:H.264/MPEG-4-AVC 尺寸:640*360 纵横比像素:未定义 图像比例:16:9 编码配置文件:Baseline@L3.0

你知道第一个视频有什么问题吗?

【问题讨论】:

logcat 是否显示错误? @Nfear 我编辑了我的问题以添加日志。我只有一些警告,但我不知道它们是什么意思 实际上它正在使用另一个视频,我更新了我的问题。你知道为什么第一个视频不起作用(使用相同的编码) 我也遇到过同样的问题。原因是您尝试播放的视频超出了屏幕的尺寸。当我做一些测试时,我侥幸发现了这一点。为了解决这个问题,我不得不改用MediaCodec API,这样无论分辨率如何,视频都可以播放。我的直觉是由于视频的大小。当您更改第二个视频的分辨率时,它可以正常工作,因为它可以舒适地放在屏幕上。 【参考方案1】:

一些尝试:

1) 你应该在你的 playVideo 方法中调用 mMediaPlayer.prepareAsync() 吗?

2) 尝试删除 onPrepared 中的 if 语句

3) 我会调用 holder.setSizeFromLayout();然后是来自 onPrepared 回调(而不是 onBufferingUpdate)的 mMediaPlayer.start()。

【讨论】:

1) 应用程序崩溃是因为构造函数已经调用了 prepare。 2-3) 我的 OnPrepare 只调用了 setSizeFromLayout 并开始。视频正在开始,但屏幕上仍然没有显示任何内容 @FabienHenon 我认为你指定了错误的纵横比,检查一下

以上是关于MediaPlayer 播放声音但不播放视频的主要内容,如果未能解决你的问题,请参考以下文章

Html 视频播放器播放声音但不播放视频

MediaPlayer音乐播放器上一首下一首播放停止自动下一首进度条

Flowplayer flash 组件播放声音但不播放视频

在 mediaplayer 中播放的 Android webview 视频

一个 Android MediaPlayer 对象一次播放多个声音

Qt qml MediaPlayer/Video 仅再现声音(无视频)