Потоковое видео не работает на Google TV в приложении для Android версии 3.1

Я новичок в разработке Android, и меня попросили создать приложение на Android для Google TV, которое будет показывать пользователю несколько каналов в прямом эфире и воспроизводить прямую трансляцию, когда пользователь выбирает один. Мне удалось это сделать, и он работает нормально. Я использовал MediaPlayer для воспроизведения своих потоков, и каналы воспроизводятся правильно БОЛЬШИНСТВО времени.

Я переопределил setOnErrorListener, чтобы знать, если что-то не так. Это улавливает большинство ошибок, если таковые имеются, и я завершаю() действия игрока после отображения правильного сообщения.

Сначала я показываю пользователю сообщение loading в индикаторе выполнения, пока поток готовится. i закрыть() индикатор выполнения и запустить() MediaPlayer после вызова слушателя setOnPreparedListener.

Я не могу запустить поток rtsp://. он зависает после того, как немного поиграл.

  1. Индикатор выполнения остается там, и приложение как бы зависает.
  2. Нажатие кнопки Назад на D-Pad также не работает.
  3. Я вообще не получаю ошибок в прослушивателе setOnErrorListener
  4. Я не могу закрыть приложение, так как всякий раз, когда я нажимаю на значок своего приложения, оно открывает ту же черную страницу «Загрузка» проигрывателя.

Используется Android 3.1 (API 12), и все URL-адреса потоков начинаются с rtsp://

Ниже приведен код файла xml/java:

ПРИМЕЧАНИЕ. Я скопировал и изменил файлы VideoPlayer.java и video_player.xml Пример MediaPlayer_Demo.

video_player.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:background="#000000">

    <SurfaceView android:id="@+id/surface"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent">
    </SurfaceView>
</LinearLayout>

Ошибочный VideoPlayer.Java выглядит следующим образом:

public class VideoPlayer 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 Bundle extras;
private boolean mIsVideoSizeKnown = false;
private boolean mIsVideoReadyToBePlayed = false;
ProgressDialog progressDialog;

/**
 * 
 * Called when the activity is first created.
 */
@Override
public void onCreate(Bundle icicle) {
    super.onCreate(icicle);
    requestWindowFeature(Window.FEATURE_NO_TITLE);
    setContentView(R.layout.video_player);

    this.extras = getIntent().getExtras();

    mPreview = (SurfaceView) findViewById(R.id.surface);
    holder = mPreview.getHolder();
    holder.addCallback(this);
    holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);

}

private void playVideo() {
    doCleanUp();
    try {

        this.progressDialog = ProgressDialog.show(this, "", "Loading...",
                true);

        // Check Internet Status
        if (!AppStatus.isInternetAvailable(this)) {
            showErrorToUser(getResources().getText(R.string.about_net)
                    .toString(),
                    "Internet connection is not available or Wi-Fi is not enabled.");
        } else {
            // Create a new media player and set the listeners
            String videoStreamUrl = extras.getString("streamUrl");

            if (videoStreamUrl != null) {
                mMediaPlayer = new MediaPlayer();
                mMediaPlayer.setDataSource(videoStreamUrl);
                mMediaPlayer.setDisplay(holder);
                mMediaPlayer.setOnBufferingUpdateListener(this);
                mMediaPlayer.setOnCompletionListener(this);
                mMediaPlayer.setOnPreparedListener(this);
                mMediaPlayer.setOnVideoSizeChangedListener(this);
                mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
                mMediaPlayer.setOnErrorListener(this);
                mMediaPlayer.prepareAsync();
            }
            else
            {
                showErrorToUser("Invalid Stream URI",
                        "The Video's URI is not valid. Please provide correct URI.");
            }
        }
    } catch (Exception e) {
        Log.e(TAG, "error: " + e.getMessage(), e);
        errorOccured();
    }
}

public void onBufferingUpdate(MediaPlayer arg0, int percent) {
    Log.d(TAG, "onBufferingUpdate percent:" + percent);

}

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");

}

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

public void surfaceCreated(SurfaceHolder holder) {
    Log.d(TAG, "surfaceCreated called");
    playVideo();
}

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

@Override
protected void onStop() {
    super.onStop();
    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");
    holder.setFixedSize(mVideoWidth, mVideoHeight);

    this.progressDialog.dismiss();

    mMediaPlayer.start();
}

public boolean onError(MediaPlayer arg0, int arg1, int arg2) {
    errorOccured();
    return true;
}

private void errorOccured() {
    UserMessage
            .showPopup(
                    this,
                    "Channel not available",
                    "We are sorry for the inconvenience but this channel is not available right now. Please try later.");
}

private void showErrorToUser(String title, String message) {
    // Hide Progress Bar
    this.progressDialog.dismiss();
    releaseMediaPlayer();
    doCleanUp();

    UserMessage.showPopup(this, title, message);
    }
}

Я создал классы UserMessage и AppStatus для ускорения разработки, я изучил их из SO. Эти классы хороши и, насколько я знаю и понимаю, не вызывают никаких ошибок. Я предоставляю их только для того, чтобы поделиться ими и лучше понять VideoPlayer.java.

Эти классы приведены ниже, чтобы ими мог пользоваться любой человек:

UserMessage.Java

public class UserMessage {
public static void showPopup(final Activity activity, String title, String message) {

    View view = View.inflate(activity, R.layout.about, null);
    TextView textView = (TextView) view.findViewById(R.id.message);
    textView.setMovementMethod(LinkMovementMethod.getInstance());
    textView.setText(message);
    new AlertDialog.Builder(activity)
            .setTitle(title)
            .setView(view)
            .setPositiveButton("OK", new DialogInterface.OnClickListener() {
                public void onClick(DialogInterface dialog, int which) {
                    activity.finish();
                }
            }).show();
    }
}

AppStatus.Java

public class AppStatus {

public static boolean isInternetAvailable(Context context)  {               

    ConnectivityManager mgr = (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE);
    NetworkInfo netInfo = mgr.getActiveNetworkInfo();

    return (netInfo != null && netInfo.isConnected() && netInfo.isAvailable());
    }
}

Любая помощь приветствуется, так как я почти закончил работу над своим приложением.

Спасибо, что прочитали и подумали, даже если не смогли мне ответить.


person Aamir    schedule 10.01.2012    source источник
comment
Какой тип видео является потоком?   -  person Les Vogel - Google DevRel    schedule 11.01.2012
comment
ну, я не уверен в типе потока ... но все URL-адреса, которые я играю, начинаются с rtsp:// .. я где-то видел, что Android поддерживает этот формат   -  person Aamir    schedule 12.01.2012
comment
Он должен поддерживаться, но приложение не часто его использует. Flash использует его в основном. Во-первых, посмотрите, сможете ли вы воспроизвести видео на телефоне или планшете. Если это сработает, пришлите мне свой URL, и я посмотрю. команда google-tv-fishtank (at) googlegroups точка com   -  person Les Vogel - Google DevRel    schedule 13.01.2012
comment
Хорошо, я отправлю вам конкретную ссылку, когда она вызовет у меня проблему, так как у меня много ссылок, и я не уверен, какая из них вызывает проблему. Большое Вам спасибо   -  person Aamir    schedule 13.01.2012
comment
@Les ... я отправил электронное письмо с URL-адресом google-tv-fishtank-team (at) googlegroups dot com несколько дней назад .. не могли бы вы проверить его, поскольку это единственная причина, по которой мое приложение не установлено? Рынок..   -  person Aamir    schedule 20.01.2012
comment
Только что нашел, застрял в обзоре. Прости.   -  person Les Vogel - Google DevRel    schedule 21.01.2012


Ответы (1)


Ответ на вашу проблему заключается в том, что хотя мы и поддерживаем RTSP, это делается программно, а не аппаратно. Когда вам нужно масштабировать его, это тоже делается в программном обеспечении. Когда вы представляете довольно большой размер, такой как ваш, и его нужно масштабировать, он недорабатывает. Придайте поведению свое видение. MP4 - лучшее решение.

person Les Vogel - Google DevRel    schedule 26.01.2012
comment
Большое спасибо за ваши усилия.. Я очень ценю это.. Теперь я понимаю причину этой проблемы... Но не могли бы вы поподробнее рассказать о MP4?? так как он также может иметь кодек: H264 - MPEG-4 AVC (часть 10) (h264) .. который есть в наших потоках RTSP .. поэтому поток MP4 с тем же кодеком может не запускаться снова .... Мы используем Wowze Server для потоковой передачи .. можете ли вы указать мне лучший тип кодека/потока, который сервер Wowza может создавать для устройств Android?? - person Aamir; 27.01.2012
comment
Wowza говорит, что передает H.264. wowza.com/media-server Это должно работать очень хорошо. Если бы я собирал систему с нуля, я бы использовал HLS. Wowza говорит, что поддерживает это. - person Les Vogel - Google DevRel; 27.01.2012
comment
Ну, наш поток RTSP на самом деле H.264 ... но вы бы видели, что он вообще не работает ... я поговорю с нашим ответственным за потоковую передачу о HLS ... мы так долго ждали ... так что я думаю, что мы надо тоже попробовать..спасибо большое - person Aamir; 27.01.2012
comment
Я снова тебя беспокою.. но я не знаю, кого бы еще спросить об этом. Я пытался запустить HTTP Live Streaming (HLS), но он тоже не работает... вы можете проверить, заменив RTSP на HTTP и добавив /playlist.m3u8 к тому же URL-адресу, который я уже отправил вам. - person Aamir; 28.01.2012
comment
На следующей неделе посмотрю еще раз - скоро тоже будет обновление, которое должно помочь в этой области. Какую коробку вы используете для разработки? - person Les Vogel - Google DevRel; 28.01.2012
comment
Я не знаю, что вы имеете в виду под тем, какую коробку вы используете для разработки?.. но у нас есть Logitech Revue™ с Google TV™ (logitech.com/en-us/smartTV/revue), который я использую для тестирования своего приложения/видео. - person Aamir; 30.01.2012
comment
Сегодня я протестировал поток HLS, и он воспроизводился ... хотя я долго не мог его воспроизвести ... но он воспроизводится сейчас ... это потому, что наше устройство Logitech обновлено ?? - person Aamir; 31.01.2012