Java 无法在Android VideoView中播放h264流

Java 无法在Android VideoView中播放h264流,java,android,android-mediaplayer,h.264,android-videoview,Java,Android,Android Mediaplayer,H.264,Android Videoview,我正在编写一个应用程序,它应该通过VideoView组件从Axis M7014视频编码器播放h.264流。 我的初衷是通过rtsp传输协议播放mjpg内容,但我愿意接受任何其他解决方案(与此视频编码器兼容)。 在与Axis支持人员交谈时,我发现通过Android本地组件播放格式/协议的唯一可能安排应该是h.264overrtsp 这是负责播放视频的活动的代码。 我还放置了一个EditText来插入流URI,以及一个按钮来启动视频: package it.acme.tux.controllervi

我正在编写一个应用程序,它应该通过
VideoView
组件从Axis M7014视频编码器播放h.264流。 我的初衷是通过
rtsp
传输协议播放
mjpg
内容,但我愿意接受任何其他解决方案(与此视频编码器兼容)。 在与Axis支持人员交谈时,我发现通过Android本地组件播放格式/协议的唯一可能安排应该是
h.264
over
rtsp

这是负责播放视频的
活动的代码。
我还放置了一个
EditText
来插入流URI,以及一个
按钮来启动视频:

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>
我很确定这条流是有效的,因为我可以从我用来测试我的应用程序的同一部Android手机上查看VLC的
h.264
流(当然是通过外部查看器)

我错在哪里?为什么从未触发OnPreparedListener
事件

我还尝试了另一种方法,使用
SurfaceView
组件代替
VideoView
MediaPlayer
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流

致以最良好的祝愿,
迈克

使用exoplayer。它支持更多的视频格式。

我已经将rtsp与wowza一起使用。有几种方法可以让您知道

试试它一次,让我知道如果你有问题。如果你的流在vlc工作良好,然后与应用程序端的问题。如果这些方法不起作用,请尝试使用不同的手机。它也对你有帮助

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();
                }
            });
        }
    });
startActivity(new Intent(Intent.ACTION_VIEW,
                Uri.parse("rtsp://184.72.239.149:8554/vid.mp4")));
2。尝试直接使用手机播放器

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();
                }
            });
        }
    });
startActivity(new Intent(Intent.ACTION_VIEW,
                Uri.parse("rtsp://184.72.239.149:8554/vid.mp4")));
3。第三种方法是尝试在应用程序中使用自定义播放器使用此库。

第1步。将其添加到渐变中

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" />

希望这能帮助您解决问题。感谢ExoPlayer支持H.264 AVC编解码器流。这是解决办法。 首先,您必须在Build.Gradle(模块应用程序)文件中指定ExoPlayer的依赖项,请记住,我使用的是ExoPlayer的2.8.0版本

implementation 'com.google.android.exoplayer:exoplayer-core:2.8.0'
implementation 'com.google.android.exoplayer:exoplayer-ui:2.8.0'
在XML文件中,创建要在其中播放视频的ExoPlayer的PlayerView容器

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 
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"
tools:context=".MainActivity">
    <com.google.android.exoplayer2.ui.PlayerView
    android:id="@+id/playerView"
    android:layout_width="0dp"
    android:layout_height="0dp"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toTopOf="parent"> 
    </com.google.android.exoplayer2.ui.PlayerView>
</androidx.constraintlayout.widget.ConstraintLayout>

有什么信息/警告吗?@Myszsoda没有。但也许我没能测试它。您有什么建议吗?我想您确实调用了playVideo(该视图毫无意义),因此mediaPlayer应该在Logcat中返回一些内容。最近,我还尝试使用
SurfaceView
(而不是
VideoView
)组件和
mediaPlayer
实例,但运气不佳(再次).@Myszsoda
playVIdeo
是通过
action\u play
按钮的
onClick
事件启动的。我不知道是否可以在没有
View
参数的情况下声明事件处理程序。无论如何,在未来我可能需要这个参数来区分哪个小部件触发了事件(假设我会添加更多按钮等)库在任何地方都有效,问题是它是否支持您的Android设备三星Galaxy Player。。。在
http
上使用
h.264
效果非常好,但它不支持
mjpg
rtsp
协议。似乎android不支持扩展Ep它不支持我希望exoPlayer有一个这种格式/协议的扩展。
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 
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"
tools:context=".MainActivity">
    <com.google.android.exoplayer2.ui.PlayerView
    android:id="@+id/playerView"
    android:layout_width="0dp"
    android:layout_height="0dp"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toTopOf="parent"> 
    </com.google.android.exoplayer2.ui.PlayerView>
</androidx.constraintlayout.widget.ConstraintLayout>
public class MainActivity extends AppCompatActivity {

    PlayerView playerView;
    SimpleExoPlayer simpleExoPlayer;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        playerView=findViewById(R.id.playerView);
    }

    @Override
    protected void onStart() {
        playerView = findViewById(R.id.playerView);
        simpleExoPlayer= ExoPlayerFactory.newSimpleInstance(this,new DefaultTrackSelector());
        DefaultDataSourceFactory defaultDataSourceFactory=new DefaultDataSourceFactory(this, Util.getUserAgent(this,"YourApplicationName"));
        simpleExoPlayer.setPlayWhenReady(true);
        ExtractorMediaSource extractorMediaSource=new ExtractorMediaSource.Factory(defaultDataSourceFactory).createMediaSource(RawResourceDataSource.buildRawResourceUri(R.raw.video));
        simpleExoPlayer.prepare(extractorMediaSource);
        playerView.setPlayer(simpleExoPlayer);

        super.onStart();
    }

    @Override
    protected void onStop() {
        playerView.setPlayer(null);
        simpleExoPlayer.release();
        simpleExoPlayer=null;
        super.onStop();
    }
}