Подтвердить что ты не робот

Android WebView Воспроизведение видео HTML5/h.264/mp4, как попасть в MediaPlayer

У меня есть Activity, который является WebView. У меня внутри WebChromeClient. Внутри этого есть несколько обратных вызовов, которые предназначены для возврата MediaPlayer обработки битов видео. Например:

@Override
public void onPrepared(MediaPlayer mp) {
    Log.i(TAG, " -------------> onPrepared");
}

Они не срабатывают, когда я загружаю поток MP4 в WebView с помощью тегов HTML <video> (через инъекцию).

Когда я finish() активность, logcat сообщает об этом:

09-13 23:55:24.590: E/MediaPlayer(7949): mOnBufferingUpdateListener is null. Failed to send MEDIA_BUFFERING_UPDATE message.
09-13 23:55:24.680: E/MediaPlayer(7949): mOnBufferingUpdateListener is null. Failed to send MEDIA_BUFFERING_UPDATE message.
09-13 23:55:24.680: E/MediaPlayer(7949): mOnVideoSizeChangedListener is null. Failed to send MEDIA_SET_VIDEO_SIZE message.
09-13 23:55:25.675: E/MediaPlayer(7949): mOnBufferingUpdateListener is null. Failed to send MEDIA_BUFFERING_UPDATE message.
09-13 23:55:26.735: E/MediaPlayer(7949): mOnBufferingUpdateListener is null. Failed to send MEDIA_BUFFERING_UPDATE message.
09-13 23:55:27.755: E/MediaPlayer(7949): mOnBufferingUpdateListener is null. Failed to send MEDIA_BUFFERING_UPDATE message.
09-13 23:55:28.705: E/MediaPlayer(7949): mOnBufferingUpdateListener is null. Failed to send MEDIA_BUFFERING_UPDATE message.

Попробуй, как я могу, я не могу заставить его остановиться, хотя WebView очищается, а затем уничтожается. При загрузке видео с помощью тегов <video> я не знаю, как заставить WebChromeClient использовать конкретный MediaPlayer, который я создаю для него. Похоже, он решил использовать какой-то скрытый, который сообщает об этом выше. Есть ли способ найти MediaPlayer, созданный с помощью тега <video> на WebView?

- Update

Вот код для инициализации WebView:

        mWebView = new WebView(mContext);

        mWebView.getSettings().setJavaScriptEnabled(true);
        mWebView.getSettings().setPluginState(PluginState.OFF);
        mWebView.setVisibility(View.INVISIBLE);
        mWebView.getSettings().setDefaultZoom(WebSettings.ZoomDensity.FAR);
        mWebView.getSettings().setBuiltInZoomControls(false);
        mWebView.getSettings().setCacheMode(WebSettings.LOAD_NO_CACHE);
        mWebView.getSettings().setLoadWithOverviewMode(true);
        mWebView.getSettings().setUseWideViewPort(true);
        mWebView.clearHistory();
        mWebView.clearFormData();
        mWebView.clearCache(true);
        mWebView.getSettings().setAllowFileAccess(true);
        mWebView.getSettings().setUserAgentString("Android Mozilla/5.0 AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30");

        chrome = new MyWebChromeClient();
        mWebView.setWebChromeClient(chrome);

        wvc = new MyWebViewClient();
        mWebView.setWebViewClient(wvc);

        mDomain = "http://foo.bar.com";
        mWebView.requestFocus(View.FOCUS_DOWN);

        String meat = genMainHTML(R.raw.frame);

        mWebView.loadDataWithBaseURL(mDomain, meat, "text/html", "utf-8", null);

Код "frame" - это iframe для запуска некоторого видео (как Vimeo, так и YouTube, похоже, используют этот подход, по крайней мере). Я немного обрезал это, чтобы избежать рывков:

<!DOCTYPE html>
<html>
<head>
</head>
<body>
<div>
     <iframe src="-target.url.with.params-" frameborder="0" webkitAllowFullScreen mozallowfullscreen allowFullScreen>
     </iframe>
</div>
</body>
</html>

Внутри этого класса WebView существует этот класс:

private class MyWebViewClient extends WebViewClient {

    @Override
    public void onPageFinished(WebView view, String url) {
            super.onPageFinished(view, url);
            String injection = injectPageMonitor();
            if(injection != null && !injectionComplete) {
                // Log.i(TAG, " ---------------> Page Loaded . . .");
                view.loadUrl(injection);
                injectionComplete = true;
        }
    }

    @Override
    public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
            Log.d(TAG, "*** Error ["+description+"] ["+failingUrl+"]");
        Toast.makeText(mContext, description, Toast.LENGTH_SHORT).show();
    }

}

А также этот класс:

    private class MyWebChromeClient extends WebChromeClient implements MediaPlayer.OnInfoListener, MediaPlayer.OnSeekCompleteListener, MediaPlayer.OnErrorListener, MediaPlayer.OnVideoSizeChangedListener, MediaPlayer.OnCompletionListener, MediaPlayer.OnPreparedListener, MediaPlayer.OnBufferingUpdateListener {

       @Override
       public void onProgressChanged(WebView view, int progress) {
           //Log.e(TAG, " -------------> Progress Changed . . . . ["+progress+"] mWebView ["+mWebView+"] ["+view+"]");
           if(progress == 100) {
                               // Do something really interesting
           }  else  {
               updateBuffering(UPDATE_PERCENT_LAUNCH_EXTRACTOR + (progress / 2));
           }
       }

       @Override
       public boolean onConsoleMessage(ConsoleMessage cm) {
                       // Spit out lots of console messages here
           return(true);
       }
   }

И у меня есть все обычные подозреваемые, переопределенные, на случай, если мне повезет, и вы получите ответ от MediaPlayer:

        @Override
    public void onBufferingUpdate(MediaPlayer mp, int percent) {
        // Jump up and down because we got a mp!
                    // never happens, so no jumping
    }

В качестве побочной заметки я действительно копался, используя рефлексию, и таким образом получал MediaPlayer, но я всегда чувствую себя немного оочень после этого. И хотя у меня есть объект MediaPlayer, я не хочу просто его выпускать. Небольшое изучение исходного кода для МП предполагает, что ничего плохого не произойдет, но.,.

Это не происходит на каждом устройстве, я заметил. HTC, похоже, ведет себя лучше, чем Samsung, например ( "тот же" уровень OS/API - я не очень амбициозен, чтобы сравнить два дерева источников).

Поведение, указанное ниже, вызывает раздражение, но только для меня (кто наблюдает за выходом logcat. Для пользователя или приложения он, кажется, не имеет никакого эффекта. Мне просто не нравится, что я начинаю MediaPlayer экземпляр, заставляя его занято кэшировать, а затем (если/когда пользователь завершает мое приложение), оставляя там тупицу, которая висит там. На данный момент у меня много денег, связанных с терапией, и, похоже, это не помогает.

Спасибо заранее.

4b9b3361

Ответ 1

Невозможно получить доступ к MediaPlayer без отражения - WebViewClient и WebChromeClient не намеренно раскрывают его. И вы правильно говорите, что использование рефлексии может привести к нарушению вашего приложения или WebView, поскольку код может отличаться в разных версиях Android и даже между OEM-производителями.

Если вы хотите сделать это, вам нужно будет найти экземпляр HTML5VideoView, соответствующий вашему элементу видео. Этот объект создает и поддерживает экземпляр для MediaPlayer как "mPlayer". См. https://github.com/android/platform_frameworks_base/blob/jb-mr2-release/core/java/android/webkit/HTML5VideoView.java.

Ответ 2

в вашем классе

private class MyWebChromeClient extends WebChromeClient 
                                implements ..... MediaPlayer.onCompletion {
}

добавление

@Override
public void onCompletion(MediaPlayer mp) {
    // TODO Auto-generated method stub
    mp.release();           
}

избавляет меня от сообщений об ошибках после закрытия веб-просмотра.

Теперь, если бы я мог получить веб-просмотр для воспроизведения/потокового видео vimeo: (