无法在Android VideoView中播放h264流

问题描述 投票:2回答:2

我正在编写一个应用程序,它应该通过VideoView组件从Axis M7014视频编码器播放h.264流。我最初的意图是在mjpg传输协议上播放rtsp内容,但我对任何其他解决方案(与此视频编码器兼容)持开放态度。说到Axis支持,我发现通过Android原生组件可以播放的格式/协议唯一可能的安排应该是h.264而不是rtsp

这是负责播放视频的Activity的代码。我还添加了一个EditText来插入流URI和一个Button来启动视频:

package it.acme.tux.controllerview;

import android.media.MediaPlayer;
import android.net.Uri;
import android.os.Bundle;
import android.app.Activity;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.VideoView;

public class CameraActivity extends Activity {
    private boolean playing = false;
    private VideoView videoView;
    private EditText textUri;
    private Button buttonPlay;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_camera);
        getActionBar().setDisplayHomeAsUpEnabled(true);

        textUri = (EditText) findViewById(R.id.video_uri);
        videoView=(VideoView) findViewById(R.id.videoView);
        buttonPlay = (Button)findViewById(R.id.action_play);

        videoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
            @Override
            public void onPrepared(MediaPlayer mediaPlayer) {
                videoView.start();
                playing = true;
            }
        });

        videoView.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
            @Override
            public void onCompletion(MediaPlayer mediaPlayer) {
                playing = false;
            }
        });

        videoView.setOnErrorListener(new MediaPlayer.OnErrorListener() {
            @Override
            public boolean onError(MediaPlayer mediaPlayer, int i, int i1) {
                return false;
            }
        });
    }

    public void playVideo(View view)
    {
        if(!playing) {
            String uri = (String) textUri.getText();
            videoView.setVideoURI(Uri.parse(uri));
        }
        else {
            videoView.stopPlayback();
            playing = false;
        }
    }
}

这是布局文件:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context="it.acme.tux.controllerview.CameraActivity">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">

        <EditText
            android:id="@+id/video_uri"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/default_uri"
            android:textSize="12sp" />

        <Button
            android:id="@+id/action_play"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:onClick="playVideo"
            android:text="@string/action_play_title"
            android:textSize="12sp" />

    </LinearLayout>

    <VideoView
        android:id="@+id/videoView"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_gravity="center" />

</LinearLayout>

布局中使用的字符串:

<resources>
    <string name="action_play_title">Play</string>
    <string name="default_uri">http://192.168.10.101:8080/stream</string>
</resources>

据我所知,OnPreparedListener它从未被触发过OnCompletionListenerOnErrorListener。我读了我在那里找到的所有东西,我也读了MediaPlayer类文档没有运气(我采取的唯一好建议是一旦OnPreparedListener事件被解雇就开始视频播放)。

BTW当不可用时,我通过这种方式通过VLC模拟视频编码器流:

vlc.exe video.mp4 --repeat :sout=#transcode{vcodec=h264,vb=800,scale=Auto,acodec=none}:http{mux=ffmpeg{mux=flv},dst=:8080/stream} :sout-all :sout-keep

我很确定这个流是有效的,因为我能够从我用来测试我的应用程序的同一个Android手机中查看来自VLC的h.264流(当然还有外部查看器)。

哪里我错了?为什么OnPreparedListener事件永远不会被解雇?

我尝试了另一种方法,使用SurfaceView组件而不是VideoViewMediaPlayer SurfaceHolder实例,但我也没有运气。这是代码:

package it.acme.tux.test;

import android.media.MediaPlayer;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.widget.EditText;

import java.io.IOException;

public class MainActivity extends AppCompatActivity implements
        SurfaceHolder.Callback,
        MediaPlayer.OnPreparedListener,
        MediaPlayer.OnInfoListener,
        MediaPlayer.OnErrorListener,
        MediaPlayer.OnCompletionListener
{
    private MediaPlayer mediaPlayer;
    private SurfaceView videoView;
    private SurfaceHolder surfaceHolder;
    boolean play = false;
    private EditText textUri;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        videoView = (SurfaceView)findViewById(R.id.videoView);
        textUri = (EditText)findViewById(R.id.textUri);

        surfaceHolder = videoView.getHolder();
        surfaceHolder.addCallback(this);

        mediaPlayer = new MediaPlayer();

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

    @Override
    protected void onPause() {
        super.onPause();
        mediaPlayer.release();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        mediaPlayer.release();
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width,
                               int height) {
    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        mediaPlayer.setDisplay(holder);
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
    }

    void playAction(View view){
        try {
            String source = textUri.getText().toString();
            Log.d("MainActivity"  , "Playing: " + source);
            mediaPlayer.setDataSource(source);
            mediaPlayer.prepareAsync();
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        } catch (IllegalStateException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void onCompletion(MediaPlayer mediaPlayer) {
        Log.d("MainActivity"  , "Completed");
        play = false;
    }

    @Override
    public boolean onError(MediaPlayer mediaPlayer, int i, int i1) {
        Log.d("MainActivity"  , String.format("Info %d/%d", i, i1));
        return false;
    }

    @Override
    public boolean onInfo(MediaPlayer mediaPlayer, int i, int i1) {
        Log.d("MainActivity"  , String.format("Info %d/%d", i, i1));
        return false;
    }

    @Override
    public void onPrepared(MediaPlayer mediaPlayer) {
        Log.d("MainActivity"  , "Prepared");
        mediaPlayer.start();
        play = true;
    }
}

我从中获得的唯一数据是从prepareAsync到视频的start发生的更详细的进展(最终没有导致错误,但都没有显示任何视频)。在这种情况下,OnPreparedListener事件似乎被解雇:

12-18 15:44:51.320 14445-14445/it.acme.tux.test V/MediaPlayer: setVideoSurfaceTexture
12-18 15:44:51.320 14445-14445/it.acme.tux.test V/MediaPlayer: prepareAsync
12-18 15:44:51.323 14445-14522/it.acme.tux.test V/MediaPlayer: message received msg=200, ext1=701, ext2=0
12-18 15:44:51.323 14445-14522/it.acme.tux.test W/MediaPlayer: info/warning (701, 0)
12-18 15:44:51.323 14445-14522/it.acme.tux.test V/MediaPlayer: callback application
12-18 15:44:51.323 14445-14522/it.acme.tux.test V/MediaPlayer: back from callback
12-18 15:44:51.330 14445-14445/it.acme.tux.test D/MainActivity: Info: 701 / 0
12-18 15:44:51.333 14445-14445/it.acme.tux.test V/MediaPlayer-JNI: getCurrentPosition: 0 (msec)
12-18 15:44:51.636 14445-14457/it.acme.tux.test V/MediaPlayer: message received msg=200, ext1=10972, ext2=0
12-18 15:44:51.636 14445-14457/it.acme.tux.test W/MediaPlayer: info/warning (10972, 0)
12-18 15:44:51.636 14445-14457/it.acme.tux.test V/MediaPlayer: callback application
12-18 15:44:51.636 14445-14457/it.acme.tux.test V/MediaPlayer: back from callback
12-18 15:44:51.637 14445-14445/it.acme.tux.test D/MainActivity: Info: 10972 / 0
12-18 15:44:51.638 14445-14522/it.acme.tux.test V/MediaPlayer: message received msg=5, ext1=0, ext2=0
12-18 15:44:51.638 14445-14522/it.acme.tux.test V/MediaPlayer: New video size 0 x 0
12-18 15:44:51.638 14445-14522/it.acme.tux.test V/MediaPlayer: callback application
12-18 15:44:51.639 14445-14522/it.acme.tux.test V/MediaPlayer: back from callback
12-18 15:44:58.645 14445-14458/it.acme.tux.test V/MediaPlayer: message received msg=200, ext1=702, ext2=0
12-18 15:44:58.645 14445-14458/it.acme.tux.test W/MediaPlayer: info/warning (702, 0)
12-18 15:44:58.645 14445-14458/it.acme.tux.test V/MediaPlayer: callback application
12-18 15:44:58.646 14445-14445/it.acme.tux.test D/MainActivity: Info: 702 / 0
12-18 15:44:58.647 14445-14458/it.acme.tux.test V/MediaPlayer: back from callback
12-18 15:44:58.647 14445-14445/it.acme.tux.test V/MediaPlayer-JNI: getCurrentPosition: 0 (msec)
12-18 15:44:59.645 14445-14458/it.acme.tux.test V/MediaPlayer: message received msg=1, ext1=0, ext2=0
12-18 15:44:59.645 14445-14458/it.acme.tux.test V/MediaPlayer: prepared
12-18 15:44:59.645 14445-14458/it.acme.tux.test V/MediaPlayer: callback application
12-18 15:44:59.646 14445-14445/it.acme.tux.test D/MediaPlayer: setSubtitleAnchor in MediaPlayer
12-18 15:44:59.647 14445-14458/it.acme.tux.test V/MediaPlayer: back from callback
12-18 15:44:59.652 14445-14445/it.acme.tux.test V/MediaPlayer: invoke 68
12-18 15:44:59.659 14445-14445/it.acme.tux.test D/MainActivity: Prepared
12-18 15:44:59.659 14445-14445/it.acme.tux.test V/MediaPlayer-JNI: start
12-18 15:44:59.659 14445-14445/it.acme.tux.test V/MediaPlayer: start

我也尝试使用这个uri:

rtsp://184.72.239.149/vod/mp4:BigBuckBunny_175k.mov

这当然是h.264流过rtsp

总结我的要求,我需要一个帮助来解决这个问题。为什么没有播放视频?

有第三方组件可以播放h.264流(Android Dev Studio 3.0.1兼容)吗?我该如何播放MJPEG流?

最好的问候,迈克

java android android-mediaplayer h.264 android-videoview
2个回答
2
投票

我已经使用rtsp和wowza.Few方式我会告诉你

尝试一次,如果你有问题让我知道。如果你在vlc中的流媒体工作正常,那么app方面的问题。如果这些方法不起作用,请尝试使用不同的手机。它也可以帮到你。

1.尝试使用videoview

vvVideoPlay = (VideoView) findViewById(R.id.vvVideoPlay);
MediaController mediaController = new MediaController(this);

String videoUrl = "rtsp://184.72.239.149:8554/vid.mp4";

    mediaController.setAnchorView(vvVideoPlay);
    Uri uri = Uri.parse(videoUrl);
    vvVideoPlay.setVideoURI(uri);
    vvVideoPlay.setMediaController(mediaController);
    vvVideoPlay.requestFocus();

    vvVideoPlay.setOnPreparedListener(new OnPreparedListener() {

        @Override
        public void onPrepared(MediaPlayer mp) {

            mp.start();
            pdialog.dismiss();
            mp.setOnVideoSizeChangedListener(new OnVideoSizeChangedListener() {

                @Override
                public void onVideoSizeChanged(MediaPlayer mp, int width, int height) {

                    mp.start();
                }
            });
        }
    });

2.尝试直接使用手机播放器

startActivity(new Intent(Intent.ACTION_VIEW,
                Uri.parse("rtsp://184.72.239.149:8554/vid.mp4")));

3.第三种方法尝试在您的应用中使用自定义播放器使用此库。

步骤1。将它添加到您的gradle中

compile "fm.jiecao:jiecaovideoplayer:4.7.0"

第2步。将其添加为xml布局中的视频播放。

<fm.jiecao.jcvideoplayer_lib.JCVideoPlayerStandard
    android:id="@+id/videoPlayer"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />

步骤3.从这里检查如何在您的班级中使用此库,

public class PlayVideoActivity extends BaseActivity {

@BindView(R.id.videoPlayer)
JCVideoPlayerStandard mVideoPlayer;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    restoreFromIntent(getIntent());
}

@Override
public int getLayout() {
    return R.layout.activity_play_video;
}


// get video path from intent and play the video here
private void restoreFromIntent(Intent intent) {

    mVideoPlayer.setUp("rtsp://184.72.239.149:8554/vid.mp4"
            , JCVideoPlayerStandard.SCREEN_LAYOUT_LIST, "");
}

@Override
public void onBackPressed() {
    if (JCVideoPlayer.backPress()) {
        return;
    }
    super.onBackPressed();
}

@Override
protected void onPause() {
    super.onPause();
    JCVideoPlayer.releaseAllVideos();
}
}

希望这能帮助你解决问题。谢谢


1
投票

使用exoplayer。它支持更多格式的视频。 https://github.com/google/ExoPlayer

© www.soinside.com 2019 - 2024. All rights reserved.