diff options
23 files changed, 387 insertions, 72 deletions
diff --git a/addons/resource.language.en_gb/resources/strings.po b/addons/resource.language.en_gb/resources/strings.po index df3ed141a1..fa1f48432b 100644 --- a/addons/resource.language.en_gb/resources/strings.po +++ b/addons/resource.language.en_gb/resources/strings.po @@ -6530,7 +6530,10 @@ msgctxt "#13439" msgid "Allow hardware acceleration - MediaCodec" msgstr "" -#empty string with id 13440 +#: system/settings/settings.xml +msgctxt "#13440" +msgid "Allow hardware acceleration - MediaCodec (Surface)" +msgstr "" #: system/settings/settings.xml msgctxt "#13441" diff --git a/configure.ac b/configure.ac index fd5ab126ff..a86ddd94b7 100644 --- a/configure.ac +++ b/configure.ac @@ -2429,6 +2429,8 @@ OUTPUT_FILES="Makefile \ tools/android/packaging/xbmc/src/org/xbmc/kodi/XBMCOnFrameAvailableListener.java \ tools/android/packaging/xbmc/src/org/xbmc/kodi/XBMCSettingsContentObserver.java \ tools/android/packaging/xbmc/src/org/xbmc/kodi/XBMCOnAudioFocusChangeListener.java \ + tools/android/packaging/xbmc/src/org/xbmc/kodi/XBMCVideoView.java \ + tools/android/packaging/xbmc/activity_main.xml \ tools/android/packaging/xbmc/strings.xml \ addons/xbmc.addon/addon.xml" diff --git a/system/settings/android.xml b/system/settings/android.xml index a3067620ce..1c5341b47b 100644 --- a/system/settings/android.xml +++ b/system/settings/android.xml @@ -19,6 +19,15 @@ </updates> <control type="toggle" /> </setting> + <setting id="videoplayer.usemediacodecsurface" type="boolean" label="13440" help="36544"> + <visible>HAS_MEDIACODEC</visible> + <level>2</level> + <default>true</default> + <updates> + <update type="change" /> + </updates> + <control type="toggle" /> + </setting> <setting id="videoplayer.usemediacodec" type="boolean" label="13439" help="36544"> <visible>HAS_MEDIACODEC</visible> <level>2</level> diff --git a/tools/android/packaging/Makefile.in b/tools/android/packaging/Makefile.in index 0effde17bd..2e6a78858c 100644 --- a/tools/android/packaging/Makefile.in +++ b/tools/android/packaging/Makefile.in @@ -113,6 +113,7 @@ res: cp -fp media/drawable-xxhdpi/ic_launcher.png xbmc/res/drawable-xxhdpi/ic_launcher.png cp -fp media/drawable-xhdpi/banner.png xbmc/res/drawable-xhdpi/banner.png cp xbmc/strings.xml xbmc/res/values/ + cp xbmc/activity_main.xml xbmc/res/layout/ mkdir -p tmp/res; $(AAPT) c -S xbmc/res -C tmp/res; cp -r -n xbmc/res tmp/ || true $(AAPT) p -f -I $(SDKROOT)/platforms/$(SDK_PLATFORM)/android.jar -S tmp/res/ -M xbmc/AndroidManifest.xml -F images/@APP_NAME_LC@app-debug-skeleton.apk -J xbmc/src @rm -rf tmp/ diff --git a/tools/android/packaging/xbmc/activity_main.xml.in b/tools/android/packaging/xbmc/activity_main.xml.in new file mode 100644 index 0000000000..eb5003d519 --- /dev/null +++ b/tools/android/packaging/xbmc/activity_main.xml.in @@ -0,0 +1,14 @@ +<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/VideoLayout" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:background="@android:color/transparent" > + + <org.xbmc.@APP_NAME_LC@.XBMCVideoView + android:id="@+id/VideoView1" + android:layout_width="fill_parent" + android:layout_height="fill_parent" + android:background="@android:color/transparent" /> + +</RelativeLayout> + diff --git a/tools/android/packaging/xbmc/src/org/xbmc/kodi/Main.java.in b/tools/android/packaging/xbmc/src/org/xbmc/kodi/Main.java.in index 3ea0399452..8b1848396a 100644 --- a/tools/android/packaging/xbmc/src/org/xbmc/kodi/Main.java.in +++ b/tools/android/packaging/xbmc/src/org/xbmc/kodi/Main.java.in @@ -6,24 +6,64 @@ import android.media.AudioManager; import android.os.Bundle; import android.util.Log; import android.view.View; +import android.view.Surface; +import android.widget.RelativeLayout; +import android.graphics.Color; import android.graphics.PixelFormat; import android.os.Handler; +import org.xbmc.@APP_NAME_LC@.XBMCVideoView; -public class Main extends NativeActivity +public class Main extends NativeActivity { + private static final String TAG = "@APP_NAME_LC@"; + private XBMCSettingsContentObserver mSettingsContentObserver; - private View thisView; + private XBMCVideoView mVideoView = null; + private RelativeLayout mVideoLayout = null; + private View thisView = null; private Handler handler = new Handler(); native void _onNewIntent(Intent intent); - public Main() + public Main() { super(); } + public Surface getVideoViewSurface() + { + return mVideoView.getSurface(); + } + + public void setVideoViewSurfaceRect(final int left, final int top, final int right, final int bottom) + { + runOnUiThread(new Runnable() + { + @Override + public void run() + { + android.widget.RelativeLayout.LayoutParams mp = new android.widget.RelativeLayout.LayoutParams(mVideoView.getLayoutParams()); + mp.setMargins(left, top, mVideoLayout.getWidth() - right, mVideoLayout.getHeight() - bottom); + mVideoView.setLayoutParams(mp); + mVideoView.requestLayout(); + } + }); + } + + public void clearVideoView() + { + runOnUiThread(new Runnable() + { + @Override + public void run() + { + mVideoView.clearSurface(); + } + }); + } + @Override - public void onCreate(Bundle savedInstanceState) + public void onCreate(Bundle savedInstanceState) { // The dynamic linker on droid is a mess. // Depending on version, it might not be able to properly resolve @@ -36,8 +76,15 @@ public class Main extends NativeActivity System.loadLibrary("@APP_NAME_LC@"); super.onCreate(savedInstanceState); + getWindow().setFormat(PixelFormat.TRANSPARENT); + + setContentView(R.layout.activity_main); + mVideoView = (XBMCVideoView)findViewById(R.id.VideoView1); + mVideoView.getHolder().setFormat(PixelFormat.TRANSPARENT); + mVideoLayout = (RelativeLayout) findViewById(R.id.VideoLayout); + setVolumeControlStream(AudioManager.STREAM_MUSIC); - + mSettingsContentObserver = new XBMCSettingsContentObserver(this, new Handler()); getApplicationContext().getContentResolver().registerContentObserver(android.provider.Settings.System.CONTENT_URI, true, mSettingsContentObserver ); diff --git a/tools/android/packaging/xbmc/src/org/xbmc/kodi/XBMCVideoView.java.in b/tools/android/packaging/xbmc/src/org/xbmc/kodi/XBMCVideoView.java.in new file mode 100644 index 0000000000..432a7cdb01 --- /dev/null +++ b/tools/android/packaging/xbmc/src/org/xbmc/kodi/XBMCVideoView.java.in @@ -0,0 +1,120 @@ +package org.xbmc.@APP_NAME_LC@; + +import javax.microedition.khronos.egl.EGL10; +import javax.microedition.khronos.egl.EGLConfig; +import javax.microedition.khronos.egl.EGLContext; +import javax.microedition.khronos.egl.EGLDisplay; +import javax.microedition.khronos.egl.EGLSurface; + +import android.R.bool; +import android.opengl.GLES20; +import android.util.AttributeSet; +import android.util.Log; +import android.view.Surface; +import android.view.SurfaceHolder; +import android.view.SurfaceView; +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Color; + +public class XBMCVideoView extends SurfaceView implements + SurfaceHolder.Callback +{ + private static final String TAG = "XBMCVideoPlayView"; + public boolean mHasHolder = false; + + public XBMCVideoView(Context context) + { + super(context); + getHolder().addCallback(this); + } + + public XBMCVideoView(Context context, AttributeSet attrs) + { + this(context, attrs, 0); + getHolder().addCallback(this); + } + + public XBMCVideoView(Context context, AttributeSet attrs, int defStyle) + { + super(context, attrs, defStyle); + getHolder().addCallback(this); + } + + /** + * Clears the playback surface to black. + */ + public void clearSurface() + { + // Have to go EGL to allow reuse of surface + + final int EGL_OPENGL_ES2_BIT = 4; + final int EGL_CONTEXT_CLIENT_VERSION = 0x3098; + + EGL10 egl = (EGL10) EGLContext.getEGL(); + EGLDisplay display = egl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY); + egl.eglInitialize(display, null); + + int[] attribList = + { EGL10.EGL_RED_SIZE, 8, EGL10.EGL_GREEN_SIZE, 8, EGL10.EGL_BLUE_SIZE, 8, + EGL10.EGL_ALPHA_SIZE, 8, EGL10.EGL_RENDERABLE_TYPE, + EGL_OPENGL_ES2_BIT, EGL10.EGL_NONE, 0, // placeholder for + // recordable [@-3] + EGL10.EGL_NONE }; + EGLConfig[] configs = new EGLConfig[1]; + int[] numConfigs = new int[1]; + egl.eglChooseConfig(display, attribList, configs, configs.length, + numConfigs); + EGLConfig config = configs[0]; + EGLContext context = egl.eglCreateContext(display, config, + EGL10.EGL_NO_CONTEXT, new int[] + { EGL_CONTEXT_CLIENT_VERSION, 2, EGL10.EGL_NONE }); + EGLSurface eglSurface = egl.eglCreateWindowSurface(display, config, + this, new int[] + { EGL10.EGL_NONE }); + + egl.eglMakeCurrent(display, eglSurface, eglSurface, context); + GLES20.glClearColor(0.0f, 0.0f, 0.0f, 0.0f); + GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT); + egl.eglSwapBuffers(display, eglSurface); + egl.eglDestroySurface(display, eglSurface); + egl.eglMakeCurrent(display, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_SURFACE, + EGL10.EGL_NO_CONTEXT); + egl.eglDestroyContext(display, context); + egl.eglTerminate(display); + } + + public Surface getSurface() + { + if (!mHasHolder) + { + return null; + } else + { + Log.d(TAG, "getSurface() = " + getHolder().getSurface()); + return getHolder().getSurface(); + } + } + + @Override + public void surfaceCreated(SurfaceHolder holder) + { + Log.d(TAG, "Created"); + mHasHolder = true; + } + + @Override + public void surfaceChanged(SurfaceHolder holder, int format, int width, + int height) + { + Log.d(TAG, "Changed, format:" + format + ", width:" + width + + ", height:" + height); + } + + @Override + public void surfaceDestroyed(SurfaceHolder holder) + { + Log.d(TAG, "Destroyed"); + mHasHolder = false; + } +} diff --git a/xbmc/android/activity/JNIMainActivity.cpp b/xbmc/android/activity/JNIMainActivity.cpp index 322b2e4a22..1074d0124b 100644 --- a/xbmc/android/activity/JNIMainActivity.cpp +++ b/xbmc/android/activity/JNIMainActivity.cpp @@ -76,3 +76,20 @@ void CJNIMainActivity::_onAudioFocusChange(JNIEnv *env, jobject context, jint fo m_appInstance->onAudioFocusChange(focusChange); } +CJNISurface CJNIMainActivity::getVideoViewSurface() +{ + return call_method<jhobject>(m_context, + "getVideoViewSurface", "()Landroid/view/Surface;"); +} + +void CJNIMainActivity::clearVideoView() +{ + call_method<void>(m_context, + "clearVideoView", "()V"); +} + +void CJNIMainActivity::setVideoViewSurfaceRect(int l, int t, int r, int b) +{ + call_method<void>(m_context, + "setVideoViewSurfaceRect", "(IIII)V", l, t, r, b); +} diff --git a/xbmc/android/activity/JNIMainActivity.h b/xbmc/android/activity/JNIMainActivity.h index 848b354800..300ea81af7 100644 --- a/xbmc/android/activity/JNIMainActivity.h +++ b/xbmc/android/activity/JNIMainActivity.h @@ -37,6 +37,10 @@ public: static void _callNative(JNIEnv *env, jobject context, jlong funcAddr, jlong variantAddr); static void runNativeOnUiThread(void (*callback)(CVariant *), CVariant *variant); + CJNISurface getVideoViewSurface(); + void clearVideoView(); + void setVideoViewSurfaceRect(int l, int t, int r, int b); + private: static CJNIMainActivity *m_appInstance; diff --git a/xbmc/android/jni/Surface.cpp b/xbmc/android/jni/Surface.cpp index 59a8a253e4..c91b0d8a47 100644 --- a/xbmc/android/jni/Surface.cpp +++ b/xbmc/android/jni/Surface.cpp @@ -41,6 +41,10 @@ void CJNISurface::PopulateStaticFields() ROTATION_270= get_static_field<int>(clazz, "ROTATION_270"); } +CJNISurface::CJNISurface() + : CJNIBase(CJNISurface::m_classname) +{ +} CJNISurface::CJNISurface(const CJNISurfaceTexture &surfaceTexture) : CJNIBase(m_classname) { diff --git a/xbmc/android/jni/Surface.h b/xbmc/android/jni/Surface.h index 2259807405..85fc1b8efb 100644 --- a/xbmc/android/jni/Surface.h +++ b/xbmc/android/jni/Surface.h @@ -25,6 +25,7 @@ class CJNISurfaceTexture; class CJNISurface : public CJNIBase { public: + CJNISurface(); CJNISurface(const CJNISurfaceTexture &surfaceTexture); CJNISurface(const jni::jhobject &object) : CJNIBase(object) {}; ~CJNISurface() {}; diff --git a/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp b/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp index d398d13b8a..af063416a8 100644 --- a/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp +++ b/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp @@ -594,6 +594,44 @@ void CLinuxRendererGLES::RenderUpdateVideo(bool clear, DWORD flags, DWORD alpha) return; } +#ifdef TARGET_ANDROID + else if (m_renderMethod & RENDER_MEDIACODECSURFACE) + { + CDVDMediaCodecInfo *mci = m_buffers[m_iYV12RenderBuffer].mediacodec; + if (mci) + { + // this hack is needed to get the 2D mode of a 3D movie going + RENDER_STEREO_MODE stereo_mode = g_graphicsContext.GetStereoMode(); + if (stereo_mode) + g_graphicsContext.SetStereoView(RENDER_STEREO_VIEW_LEFT); + + ManageDisplay(); + + if (stereo_mode) + g_graphicsContext.SetStereoView(RENDER_STEREO_VIEW_OFF); + + CRect dstRect(m_destRect); + CRect srcRect(m_sourceRect); + switch (stereo_mode) + { + case RENDER_STEREO_MODE_SPLIT_HORIZONTAL: + dstRect.y2 *= 2.0; + srcRect.y2 *= 2.0; + break; + + case RENDER_STEREO_MODE_SPLIT_VERTICAL: + dstRect.x2 *= 2.0; + srcRect.x2 *= 2.0; + break; + + default: + break; + } + + mci->RenderUpdate(srcRect, dstRect); + } + } +#endif #ifdef HAS_IMXVPU else if (m_renderMethod & RENDER_IMXMAP) { @@ -722,6 +760,7 @@ unsigned int CLinuxRendererGLES::PreInit() #endif #if defined(TARGET_ANDROID) m_formats.push_back(RENDER_FMT_MEDIACODEC); + m_formats.push_back(RENDER_FMT_MEDIACODECSURFACE); #endif #ifdef HAS_IMXVPU m_formats.push_back(RENDER_FMT_IMXMAP); @@ -828,6 +867,12 @@ void CLinuxRendererGLES::LoadShaders(int field) m_renderMethod = RENDER_MEDIACODEC; break; } + else if (m_format == RENDER_FMT_MEDIACODECSURFACE) + { + CLog::Log(LOGNOTICE, "GL: Using MediaCodec (Surface) render method"); + m_renderMethod = RENDER_MEDIACODECSURFACE; + break; + } else if (m_format == RENDER_FMT_IMXMAP) { CLog::Log(LOGNOTICE, "GL: Using IMXMAP render method"); @@ -902,7 +947,7 @@ void CLinuxRendererGLES::LoadShaders(int field) m_textureCreate = &CLinuxRendererGLES::CreateCVRefTexture; m_textureDelete = &CLinuxRendererGLES::DeleteCVRefTexture; } - else if (m_format == RENDER_FMT_BYPASS) + else if (m_format == RENDER_FMT_BYPASS || m_format == RENDER_FMT_MEDIACODECSURFACE) { m_textureUpload = &CLinuxRendererGLES::UploadBYPASSTexture; m_textureCreate = &CLinuxRendererGLES::CreateBYPASSTexture; @@ -1043,6 +1088,8 @@ void CLinuxRendererGLES::ReleaseBuffer(int idx) SAFE_RELEASE(buf.mediacodec); } } + if ( m_renderMethod & RENDER_MEDIACODECSURFACE ) + SAFE_RELEASE(buf.mediacodec); #endif #ifdef HAS_IMXVPU if (m_renderMethod & RENDER_IMXMAP) @@ -1053,7 +1100,7 @@ void CLinuxRendererGLES::ReleaseBuffer(int idx) void CLinuxRendererGLES::Render(DWORD flags, int index) { // If rendered directly by the hardware - if (m_renderMethod & RENDER_BYPASS) + if (m_renderMethod & RENDER_BYPASS || m_renderMethod & RENDER_MEDIACODECSURFACE) return; // obtain current field, if interlaced @@ -1836,7 +1883,7 @@ bool CLinuxRendererGLES::RenderCapture(CRenderCapture* capture) return false; // If rendered directly by the hardware - if (m_renderMethod & RENDER_BYPASS) + if (m_renderMethod & RENDER_BYPASS || m_renderMethod & RENDER_MEDIACODECSURFACE) { capture->BeginRender(); capture->EndRender(); @@ -2926,6 +2973,9 @@ bool CLinuxRendererGLES::Supports(EINTERLACEMETHOD method) return false; } + if(m_renderMethod & RENDER_MEDIACODECSURFACE) + return false; + if(m_renderMethod & RENDER_CVREF) return false; @@ -2967,6 +3017,9 @@ bool CLinuxRendererGLES::Supports(ESCALINGMETHOD method) if(m_renderMethod & RENDER_IMXMAP) return false; + if (m_renderMethod & RENDER_MEDIACODECSURFACE) + return false; + if(method == VS_SCALINGMETHOD_NEAREST || method == VS_SCALINGMETHOD_LINEAR) return true; @@ -2994,6 +3047,9 @@ EINTERLACEMETHOD CLinuxRendererGLES::AutoInterlaceMethod() if(m_renderMethod & RENDER_MEDIACODEC) return VS_INTERLACEMETHOD_RENDER_BOB_INVERTED; + if(m_renderMethod & RENDER_MEDIACODECSURFACE) + return VS_INTERLACEMETHOD_NONE; + if(m_renderMethod & RENDER_CVREF) return VS_INTERLACEMETHOD_NONE; @@ -3015,7 +3071,8 @@ CRenderInfo CLinuxRendererGLES::GetRenderInfo() if(m_format == RENDER_FMT_OMXEGL || m_format == RENDER_FMT_CVBREF || m_format == RENDER_FMT_EGLIMG || - m_format == RENDER_FMT_MEDIACODEC) + m_format == RENDER_FMT_MEDIACODEC || + m_format == RENDER_FMT_MEDIACODECSURFACE) info.optimal_buffer_size = 2; else if(m_format == RENDER_FMT_IMXMAP) { @@ -3114,7 +3171,7 @@ void CLinuxRendererGLES::AddProcessor(CDVDVideoCodecIMXBuffer *buffer, int index bool CLinuxRendererGLES::IsGuiLayer() { - if (m_format == RENDER_FMT_BYPASS || m_format == RENDER_FMT_IMXMAP) + if (m_format == RENDER_FMT_BYPASS || m_format == RENDER_FMT_IMXMAP || m_format == RENDER_FMT_MEDIACODECSURFACE) return false; else return true; diff --git a/xbmc/cores/VideoRenderers/LinuxRendererGLES.h b/xbmc/cores/VideoRenderers/LinuxRendererGLES.h index 2d803d5f44..77bbb579f3 100644 --- a/xbmc/cores/VideoRenderers/LinuxRendererGLES.h +++ b/xbmc/cores/VideoRenderers/LinuxRendererGLES.h @@ -93,7 +93,8 @@ enum RenderMethod RENDER_BYPASS = 0x100, RENDER_EGLIMG = 0x200, RENDER_MEDIACODEC = 0x400, - RENDER_IMXMAP = 0x800 + RENDER_MEDIACODECSURFACE = 0x800, + RENDER_IMXMAP = 0x1000 }; enum RenderQuality diff --git a/xbmc/cores/VideoRenderers/RenderFormats.h b/xbmc/cores/VideoRenderers/RenderFormats.h index 97634c278c..c6329ff7f6 100644 --- a/xbmc/cores/VideoRenderers/RenderFormats.h +++ b/xbmc/cores/VideoRenderers/RenderFormats.h @@ -40,6 +40,7 @@ enum ERenderFormat { RENDER_FMT_BYPASS, RENDER_FMT_EGLIMG, RENDER_FMT_MEDIACODEC, + RENDER_FMT_MEDIACODECSURFACE, RENDER_FMT_IMXMAP, RENDER_FMT_MMAL, }; diff --git a/xbmc/cores/VideoRenderers/RenderManager.cpp b/xbmc/cores/VideoRenderers/RenderManager.cpp index 24edf5a92e..7a99ac4beb 100644 --- a/xbmc/cores/VideoRenderers/RenderManager.cpp +++ b/xbmc/cores/VideoRenderers/RenderManager.cpp @@ -1018,7 +1018,7 @@ int CXBMCRenderManager::AddVideoPicture(DVDVideoPicture& pic) m_pRenderer->AddProcessor(pic.stf, pic.eglimg, index); #endif #if defined(TARGET_ANDROID) - else if(pic.format == RENDER_FMT_MEDIACODEC) + else if(pic.format == RENDER_FMT_MEDIACODEC || pic.format == RENDER_FMT_MEDIACODECSURFACE) m_pRenderer->AddProcessor(pic.mediacodec, index); #endif #ifdef HAS_IMXVPU diff --git a/xbmc/cores/dvdplayer/DVDCodecs/DVDFactoryCodec.cpp b/xbmc/cores/dvdplayer/DVDCodecs/DVDFactoryCodec.cpp index 3c16ec349a..84e9ef1700 100644 --- a/xbmc/cores/dvdplayer/DVDCodecs/DVDFactoryCodec.cpp +++ b/xbmc/cores/dvdplayer/DVDCodecs/DVDFactoryCodec.cpp @@ -263,6 +263,22 @@ CDVDVideoCodec* CDVDFactoryCodec::CreateVideoCodec(CDVDStreamInfo &hint, const C #endif #if defined(TARGET_ANDROID) + if (!hint.software && CSettings::GetInstance().GetBool(CSettings::SETTING_VIDEOPLAYER_USEMEDIACODECSURFACE)) + { + switch(hint.codec) + { + case AV_CODEC_ID_MPEG4: + case AV_CODEC_ID_MSMPEG4V2: + case AV_CODEC_ID_MSMPEG4V3: + // Avoid h/w decoder for SD; Those files might use features + // not supported and can easily be soft-decoded + if (hint.width <= 800) + break; + default: + CLog::Log(LOGINFO, "MediaCodec (Surface) Video Decoder..."); + if ( (pCodec = OpenCodec(new CDVDVideoCodecAndroidMediaCodec(true), hint, options)) ) return pCodec; + } + } if (!hint.software && CSettings::GetInstance().GetBool(CSettings::SETTING_VIDEOPLAYER_USEMEDIACODEC)) { switch(hint.codec) @@ -276,7 +292,7 @@ CDVDVideoCodec* CDVDFactoryCodec::CreateVideoCodec(CDVDStreamInfo &hint, const C break; default: CLog::Log(LOGINFO, "MediaCodec Video Decoder..."); - if ( (pCodec = OpenCodec(new CDVDVideoCodecAndroidMediaCodec(), hint, options)) ) return pCodec; + if ( (pCodec = OpenCodec(new CDVDVideoCodecAndroidMediaCodec(false), hint, options)) ) return pCodec; } } #endif diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecAndroidMediaCodec.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecAndroidMediaCodec.cpp index 7953d66df2..3ef826550a 100644 --- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecAndroidMediaCodec.cpp +++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecAndroidMediaCodec.cpp @@ -36,6 +36,9 @@ #include "utils/CPUInfo.h" #include "utils/log.h" #include "settings/AdvancedSettings.h" +#include "android/activity/XBMCApp.h" +#include "cores/VideoRenderers/RenderManager.h" +#include "cores/VideoRenderers/RenderFlags.h" #include "android/jni/ByteBuffer.h" #include "android/jni/MediaCodec.h" @@ -172,10 +175,7 @@ CDVDMediaCodecInfo::CDVDMediaCodecInfo( { // paranoid checks assert(m_index >= 0); - assert(m_texture > 0); assert(m_codec != NULL); - assert(m_surfacetexture != NULL); - assert(m_frameready != NULL); } CDVDMediaCodecInfo::~CDVDMediaCodecInfo() @@ -220,7 +220,8 @@ void CDVDMediaCodecInfo::ReleaseOutputBuffer(bool render) // then wait for rendered frame to become avaliable. if (render) - m_frameready->Reset(); + if (m_frameready) + m_frameready->Reset(); m_codec->releaseOutputBuffer(m_index, render); m_isReleased = true; @@ -295,15 +296,35 @@ void CDVDMediaCodecInfo::UpdateTexImage() } } +void CDVDMediaCodecInfo::RenderUpdate(const CRect &SrcRect, const CRect &DestRect) +{ + CSingleLock lock(m_section); + + static CRect cur_rect; + + if (!m_valid) + return; + + if (DestRect != cur_rect) + { + CXBMCApp::get()->setVideoViewSurfaceRect(DestRect.x1, DestRect.y1, DestRect.x2, DestRect.y2); + cur_rect = DestRect; + } + + ReleaseOutputBuffer(true); +} + + /*****************************************************************************/ /*****************************************************************************/ -CDVDVideoCodecAndroidMediaCodec::CDVDVideoCodecAndroidMediaCodec() +CDVDVideoCodecAndroidMediaCodec::CDVDVideoCodecAndroidMediaCodec(bool surface_render) : m_formatname("mediacodec") , m_opened(false) , m_surface(NULL) , m_textureId(0) , m_bitstream(NULL) , m_render_sw(false) +, m_render_surface(surface_render) { memset(&m_videobuffer, 0x00, sizeof(DVDVideoPicture)); memset(&m_demux_pkt, 0, sizeof(m_demux_pkt)); @@ -450,6 +471,9 @@ bool CDVDVideoCodecAndroidMediaCodec::Open(CDVDStreamInfo &hints, CDVDCodecOptio break; } + if (m_render_surface) + m_formatname += "(S)"; + // CJNIMediaCodec::createDecoderByXXX doesn't handle errors nicely, // it crashes if the codec isn't found. This is fixed in latest AOSP, // but not in current 4.1 devices. So 1st search for a matching codec, then create it. @@ -522,6 +546,7 @@ bool CDVDVideoCodecAndroidMediaCodec::Open(CDVDStreamInfo &hints, CDVDCodecOptio SAFE_DELETE(m_bitstream); return false; } + m_render_surface = false; } // setup a YUV420P DVDVideoPicture buffer. @@ -562,6 +587,8 @@ void CDVDVideoCodecAndroidMediaCodec::Dispose() m_opened = false; + g_renderManager.RegisterRenderUpdateCallBack((const void*)NULL, NULL); + // release any retained demux packets if (m_demux_pkt.pData) free(m_demux_pkt.pData); @@ -593,6 +620,8 @@ void CDVDVideoCodecAndroidMediaCodec::Dispose() xbmc_jnienv()->ExceptionClear(); } ReleaseSurfaceTexture(); + if (m_render_surface) + CXBMCApp::get()->clearVideoView(); SAFE_DELETE(m_bitstream); } @@ -801,7 +830,7 @@ bool CDVDVideoCodecAndroidMediaCodec::GetPicture(DVDVideoPicture* pDvdVideoPictu bool CDVDVideoCodecAndroidMediaCodec::ClearPicture(DVDVideoPicture* pDvdVideoPicture) { - if (pDvdVideoPicture->format == RENDER_FMT_MEDIACODEC) + if (pDvdVideoPicture->format == RENDER_FMT_MEDIACODEC || pDvdVideoPicture->format == RENDER_FMT_MEDIACODECSURFACE) SAFE_RELEASE(pDvdVideoPicture->mediacodec); memset(pDvdVideoPicture, 0x00, sizeof(DVDVideoPicture)); @@ -843,7 +872,10 @@ void CDVDVideoCodecAndroidMediaCodec::FlushInternal() return; for (size_t i = 0; i < m_inflight.size(); i++) + { m_inflight[i]->Validate(false); + m_inflight[i]->Release(); + } m_inflight.clear(); for (size_t i = 0; i < m_output.size(); i++) @@ -885,6 +917,8 @@ bool CDVDVideoCodecAndroidMediaCodec::ConfigureMediaCodec(void) } InitSurfaceTexture(); + if (m_render_surface) + m_videosurface = CXBMCApp::get()->getVideoViewSurface(); // configure and start the codec. // use the MediaFormat that we have setup. @@ -901,12 +935,16 @@ bool CDVDVideoCodecAndroidMediaCodec::ConfigureMediaCodec(void) } else { - m_codec->configure(mediaformat, *m_surface, crypto, flags); + if (m_render_surface) + m_codec->configure(mediaformat, m_videosurface, crypto, flags); + else + m_codec->configure(mediaformat, *m_surface, crypto, flags); } // always, check/clear jni exceptions. if (xbmc_jnienv()->ExceptionCheck()) { CLog::Log(LOGERROR, "CDVDVideoCodecAndroidMediaCodec::ExceptionCheck: configure"); + xbmc_jnienv()->ExceptionDescribe(); xbmc_jnienv()->ExceptionClear(); return false; } @@ -917,6 +955,7 @@ bool CDVDVideoCodecAndroidMediaCodec::ConfigureMediaCodec(void) if (xbmc_jnienv()->ExceptionCheck()) { CLog::Log(LOGERROR, "CDVDVideoCodecAndroidMediaCodec::ExceptionCheck: start"); + xbmc_jnienv()->ExceptionDescribe(); xbmc_jnienv()->ExceptionClear(); return false; } @@ -932,7 +971,7 @@ int CDVDVideoCodecAndroidMediaCodec::GetOutputPicture(void) { int rtn = 0; - int64_t timeout_us = 1000; + int64_t timeout_us = 10000; CJNIMediaCodecBufferInfo bufferInfo; int index = m_codec->dequeueOutputBuffer(bufferInfo, timeout_us); if (xbmc_jnienv()->ExceptionCheck()) @@ -1137,8 +1176,16 @@ void CDVDVideoCodecAndroidMediaCodec::ConfigureOutputFormat(CJNIMediaFormat* med if (!m_render_sw) { - CLog::Log(LOGDEBUG, "CDVDVideoCodecAndroidMediaCodec:: Direct Surface Rendering"); - m_videobuffer.format = RENDER_FMT_MEDIACODEC; + if (m_render_surface) + { + CLog::Log(LOGDEBUG, "CDVDVideoCodecAndroidMediaCodec:: Multi-Surface Rendering"); + m_videobuffer.format = RENDER_FMT_MEDIACODECSURFACE; + } + else + { + CLog::Log(LOGDEBUG, "CDVDVideoCodecAndroidMediaCodec:: Direct Surface Rendering"); + m_videobuffer.format = RENDER_FMT_MEDIACODEC; + } } else { @@ -1305,7 +1352,7 @@ void CDVDVideoCodecAndroidMediaCodec::CallbackInitSurfaceTexture(void *userdata) void CDVDVideoCodecAndroidMediaCodec::InitSurfaceTexture(void) { - if (m_render_sw) + if (m_render_sw || m_render_surface) return; // We MUST create the GLES texture on the main thread @@ -1348,7 +1395,7 @@ void CDVDVideoCodecAndroidMediaCodec::InitSurfaceTexture(void) void CDVDVideoCodecAndroidMediaCodec::ReleaseSurfaceTexture(void) { - if (m_render_sw) + if (m_render_sw || m_render_surface) return; // it is safe to delete here even though these items diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecAndroidMediaCodec.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecAndroidMediaCodec.h index 82da3f9c72..c320a84495 100644 --- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecAndroidMediaCodec.h +++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecAndroidMediaCodec.h @@ -28,6 +28,8 @@ #include "DVDStreamInfo.h" #include "threads/Thread.h" #include "threads/SingleLock.h" +#include "android/jni/Surface.h" +#include "guilib/Geometry.h" class CJNISurface; class CJNISurfaceTexture; @@ -66,6 +68,7 @@ public: int GetTextureID() const; void GetTransformMatrix(float *textureMatrix); void UpdateTexImage(); + void RenderUpdate(const CRect &SrcRect, const CRect &DestRect); private: // private because we are reference counted @@ -88,7 +91,7 @@ private: class CDVDVideoCodecAndroidMediaCodec : public CDVDVideoCodec { public: - CDVDVideoCodecAndroidMediaCodec(); + CDVDVideoCodecAndroidMediaCodec(bool surface_render = false); virtual ~CDVDVideoCodecAndroidMediaCodec(); // required overrides @@ -101,7 +104,7 @@ public: virtual void SetDropState(bool bDrop); virtual int GetDataSize(void); virtual double GetTimeSize(void); - virtual const char* GetName(void) { return m_formatname; } + virtual const char* GetName(void) { return m_formatname.c_str(); } virtual unsigned GetAllowedReferences(); protected: @@ -119,12 +122,13 @@ protected: std::string m_mime; std::string m_codecname; int m_colorFormat; - const char *m_formatname; + std::string m_formatname; bool m_opened; bool m_drop; CJNISurface *m_surface; unsigned int m_textureId; + CJNISurface m_videosurface; // we need these as shared_ptr because CDVDVideoCodecAndroidMediaCodec // will get deleted before CLinuxRendererGLES is shut down and // CLinuxRendererGLES refs them via CDVDMediaCodecInfo. @@ -141,6 +145,7 @@ protected: DVDVideoPicture m_videobuffer; bool m_render_sw; + bool m_render_surface; int m_src_offset[4]; int m_src_stride[4]; }; diff --git a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp index 87cfb78158..379c54153c 100644 --- a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp +++ b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp @@ -928,6 +928,7 @@ static std::string GetRenderFormatName(ERenderFormat format) case RENDER_FMT_EGLIMG: return "EGLIMG"; case RENDER_FMT_BYPASS: return "BYPASS"; case RENDER_FMT_MEDIACODEC:return "MEDIACODEC"; + case RENDER_FMT_MEDIACODECSURFACE:return "MEDIACODECSURFACE"; case RENDER_FMT_IMXMAP: return "IMXMAP"; case RENDER_FMT_MMAL: return "MMAL"; case RENDER_FMT_NONE: return "NONE"; diff --git a/xbmc/settings/Settings.cpp b/xbmc/settings/Settings.cpp index 904c54bbab..aeed0b17d2 100644 --- a/xbmc/settings/Settings.cpp +++ b/xbmc/settings/Settings.cpp @@ -161,6 +161,7 @@ const std::string CSettings::SETTING_VIDEOPLAYER_RENDERMETHOD = "videoplayer.ren const std::string CSettings::SETTING_VIDEOPLAYER_HQSCALERS = "videoplayer.hqscalers"; const std::string CSettings::SETTING_VIDEOPLAYER_USEAMCODEC = "videoplayer.useamcodec"; const std::string CSettings::SETTING_VIDEOPLAYER_USEMEDIACODEC = "videoplayer.usemediacodec"; +const std::string CSettings::SETTING_VIDEOPLAYER_USEMEDIACODECSURFACE = "videoplayer.usemediacodecsurface"; const std::string CSettings::SETTING_VIDEOPLAYER_USEVDPAU = "videoplayer.usevdpau"; const std::string CSettings::SETTING_VIDEOPLAYER_USEVDPAUMIXER = "videoplayer.usevdpaumixer"; const std::string CSettings::SETTING_VIDEOPLAYER_USEVDPAUMPEG2 = "videoplayer.usevdpaumpeg2"; @@ -1098,6 +1099,7 @@ void CSettings::InitializeISettingCallbacks() settingSet.insert(CSettings::SETTING_VIDEOSCREEN_TESTPATTERN); settingSet.insert(CSettings::SETTING_VIDEOPLAYER_USEAMCODEC); settingSet.insert(CSettings::SETTING_VIDEOPLAYER_USEMEDIACODEC); + settingSet.insert(CSettings::SETTING_VIDEOPLAYER_USEMEDIACODECSURFACE); m_settingsManager->RegisterCallback(&g_application, settingSet); settingSet.clear(); diff --git a/xbmc/settings/Settings.h b/xbmc/settings/Settings.h index c1f09e0eae..415ed3b869 100644 --- a/xbmc/settings/Settings.h +++ b/xbmc/settings/Settings.h @@ -117,6 +117,7 @@ public: static const std::string SETTING_VIDEOPLAYER_HQSCALERS; static const std::string SETTING_VIDEOPLAYER_USEAMCODEC; static const std::string SETTING_VIDEOPLAYER_USEMEDIACODEC; + static const std::string SETTING_VIDEOPLAYER_USEMEDIACODECSURFACE; static const std::string SETTING_VIDEOPLAYER_USEVDPAU; static const std::string SETTING_VIDEOPLAYER_USEVDPAUMIXER; static const std::string SETTING_VIDEOPLAYER_USEVDPAUMPEG2; diff --git a/xbmc/windowing/egl/EGLNativeTypeAndroid.cpp b/xbmc/windowing/egl/EGLNativeTypeAndroid.cpp index b90d4fbfa6..5f9de94972 100644 --- a/xbmc/windowing/egl/EGLNativeTypeAndroid.cpp +++ b/xbmc/windowing/egl/EGLNativeTypeAndroid.cpp @@ -35,7 +35,6 @@ #include "android/jni/System.h" CEGLNativeTypeAndroid::CEGLNativeTypeAndroid() - : m_width(0), m_height(0) { } @@ -67,29 +66,6 @@ static bool DeviceCanUseDisplaysize(const std::string &name) void CEGLNativeTypeAndroid::Initialize() { std::string displaySize; - m_width = m_height = 0; - - // FIXME: Temporary shield specific hack to obtain HDMI resolution - // Remove and use New Android M API - if (DeviceCanUseDisplaysize(CJNIBuild::DEVICE)) - displaySize = CJNISystemProperties::get("sys.display-size", ""); - - // Override with xmbc_properties if present - std::string customdisplaySize = CJNISystem::getProperty("xbmc.display-size", ""); - if (!customdisplaySize.empty()) - displaySize = customdisplaySize; - - if (!displaySize.empty()) - { - CLog::Log(LOGDEBUG, "CEGLNativeTypeAndroid: display-size: %s", displaySize.c_str()); - std::vector<std::string> aSize = StringUtils::Split(displaySize, "x"); - if (aSize.size() == 2) - { - m_width = StringUtils::IsInteger(aSize[0]) ? atoi(aSize[0].c_str()) : 0; - m_height = StringUtils::IsInteger(aSize[1]) ? atoi(aSize[1].c_str()) : 0; - } - } - return; } void CEGLNativeTypeAndroid::Destroy() @@ -170,18 +146,10 @@ bool CEGLNativeTypeAndroid::GetNativeResolution(RESOLUTION_INFO *res) const if (!nativeWindow) return false; - if (!m_width || !m_height) - { - ANativeWindow_acquire(*nativeWindow); - res->iWidth = ANativeWindow_getWidth(*nativeWindow); - res->iHeight= ANativeWindow_getHeight(*nativeWindow); - ANativeWindow_release(*nativeWindow); - } - else - { - res->iWidth = m_width; - res->iHeight = m_height; - } + ANativeWindow_acquire(*nativeWindow); + res->iWidth = ANativeWindow_getWidth(*nativeWindow); + res->iHeight= ANativeWindow_getHeight(*nativeWindow); + ANativeWindow_release(*nativeWindow); res->fRefreshRate = currentRefreshRate(); res->dwFlags= D3DPRESENTFLAG_PROGRESSIVE; @@ -199,9 +167,7 @@ bool CEGLNativeTypeAndroid::GetNativeResolution(RESOLUTION_INFO *res) const bool CEGLNativeTypeAndroid::SetNativeResolution(const RESOLUTION_INFO &res) { - CLog::Log(LOGDEBUG, "CEGLNativeTypeAndroid: SetNativeResolution: %dx%d", m_width, m_height); - if (m_width && m_height) - CXBMCApp::SetBuffersGeometry(m_width, m_height, 0); + CLog::Log(LOGNOTICE, "CEGLNativeTypeAndroid: Switching to resolution: %s", res.strMode.c_str()); if (abs(currentRefreshRate() - res.fRefreshRate) > 0.0001) CXBMCApp::SetRefreshRate(res.fRefreshRate); diff --git a/xbmc/windowing/egl/EGLNativeTypeAndroid.h b/xbmc/windowing/egl/EGLNativeTypeAndroid.h index 8c99c1df23..f26215d8cd 100644 --- a/xbmc/windowing/egl/EGLNativeTypeAndroid.h +++ b/xbmc/windowing/egl/EGLNativeTypeAndroid.h @@ -46,8 +46,4 @@ public: virtual bool GetPreferredResolution(RESOLUTION_INFO *res) const; virtual bool ShowWindow(bool show); - -protected: - int m_width; - int m_height; }; |