TextureRenderView.java 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370
  1. /*
  2. * Copyright (C) 2015 Bilibili
  3. * Copyright (C) 2015 Zhang Rui <bbcallen@gmail.com>
  4. *
  5. * Licensed under the Apache License, Version 2.0 (the "License");
  6. * you may not use this file except in compliance with the License.
  7. * You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. */
  17. package com.edufound.mobile.ijkplayer.media;
  18. import android.annotation.TargetApi;
  19. import android.content.Context;
  20. import android.graphics.SurfaceTexture;
  21. import android.os.Build;
  22. import android.support.annotation.NonNull;
  23. import android.support.annotation.Nullable;
  24. import android.util.AttributeSet;
  25. import android.util.Log;
  26. import android.view.Surface;
  27. import android.view.SurfaceHolder;
  28. import android.view.TextureView;
  29. import android.view.View;
  30. import android.view.accessibility.AccessibilityEvent;
  31. import android.view.accessibility.AccessibilityNodeInfo;
  32. import java.lang.ref.WeakReference;
  33. import java.util.Map;
  34. import java.util.concurrent.ConcurrentHashMap;
  35. import tv.danmaku.ijk.media.player.IMediaPlayer;
  36. import tv.danmaku.ijk.media.player.ISurfaceTextureHolder;
  37. import tv.danmaku.ijk.media.player.ISurfaceTextureHost;
  38. @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
  39. public class TextureRenderView extends TextureView implements IRenderView {
  40. private static final String TAG = "TextureRenderView";
  41. private MeasureHelper mMeasureHelper;
  42. public TextureRenderView(Context context) {
  43. super(context);
  44. initView(context);
  45. }
  46. public TextureRenderView(Context context, AttributeSet attrs) {
  47. super(context, attrs);
  48. initView(context);
  49. }
  50. public TextureRenderView(Context context, AttributeSet attrs, int defStyleAttr) {
  51. super(context, attrs, defStyleAttr);
  52. initView(context);
  53. }
  54. @TargetApi(Build.VERSION_CODES.LOLLIPOP)
  55. public TextureRenderView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
  56. super(context, attrs, defStyleAttr, defStyleRes);
  57. initView(context);
  58. }
  59. private void initView(Context context) {
  60. mMeasureHelper = new MeasureHelper(this);
  61. mSurfaceCallback = new SurfaceCallback(this);
  62. setSurfaceTextureListener(mSurfaceCallback);
  63. }
  64. @Override
  65. public View getView() {
  66. return this;
  67. }
  68. @Override
  69. public boolean shouldWaitForResize() {
  70. return false;
  71. }
  72. @Override
  73. protected void onDetachedFromWindow() {
  74. mSurfaceCallback.willDetachFromWindow();
  75. super.onDetachedFromWindow();
  76. mSurfaceCallback.didDetachFromWindow();
  77. }
  78. //--------------------
  79. // Layout & Measure
  80. //--------------------
  81. @Override
  82. public void setVideoSize(int videoWidth, int videoHeight) {
  83. if (videoWidth > 0 && videoHeight > 0) {
  84. mMeasureHelper.setVideoSize(videoWidth, videoHeight);
  85. requestLayout();
  86. }
  87. }
  88. @Override
  89. public void setVideoSampleAspectRatio(int videoSarNum, int videoSarDen) {
  90. if (videoSarNum > 0 && videoSarDen > 0) {
  91. mMeasureHelper.setVideoSampleAspectRatio(videoSarNum, videoSarDen);
  92. requestLayout();
  93. }
  94. }
  95. @Override
  96. public void setVideoRotation(int degree) {
  97. mMeasureHelper.setVideoRotation(degree);
  98. setRotation(degree);
  99. }
  100. @Override
  101. public void setAspectRatio(int aspectRatio) {
  102. mMeasureHelper.setAspectRatio(aspectRatio);
  103. requestLayout();
  104. }
  105. @Override
  106. protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
  107. mMeasureHelper.doMeasure(widthMeasureSpec, heightMeasureSpec);
  108. setMeasuredDimension(mMeasureHelper.getMeasuredWidth(), mMeasureHelper.getMeasuredHeight());
  109. }
  110. //--------------------
  111. // TextureViewHolder
  112. //--------------------
  113. public ISurfaceHolder getSurfaceHolder() {
  114. return new InternalSurfaceHolder(this, mSurfaceCallback.mSurfaceTexture, mSurfaceCallback);
  115. }
  116. private static final class InternalSurfaceHolder implements ISurfaceHolder {
  117. private TextureRenderView mTextureView;
  118. private SurfaceTexture mSurfaceTexture;
  119. private ISurfaceTextureHost mSurfaceTextureHost;
  120. public InternalSurfaceHolder(@NonNull TextureRenderView textureView,
  121. @Nullable SurfaceTexture surfaceTexture,
  122. @NonNull ISurfaceTextureHost surfaceTextureHost) {
  123. mTextureView = textureView;
  124. mSurfaceTexture = surfaceTexture;
  125. mSurfaceTextureHost = surfaceTextureHost;
  126. }
  127. @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
  128. public void bindToMediaPlayer(IMediaPlayer mp) {
  129. if (mp == null)
  130. return;
  131. if ((Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) &&
  132. (mp instanceof ISurfaceTextureHolder)) {
  133. ISurfaceTextureHolder textureHolder = (ISurfaceTextureHolder) mp;
  134. mTextureView.mSurfaceCallback.setOwnSurfaceTexture(false);
  135. SurfaceTexture surfaceTexture = textureHolder.getSurfaceTexture();
  136. if (surfaceTexture != null) {
  137. mTextureView.setSurfaceTexture(surfaceTexture);
  138. } else {
  139. textureHolder.setSurfaceTexture(mSurfaceTexture);
  140. textureHolder.setSurfaceTextureHost(mTextureView.mSurfaceCallback);
  141. }
  142. } else {
  143. mp.setSurface(openSurface());
  144. }
  145. }
  146. @NonNull
  147. @Override
  148. public IRenderView getRenderView() {
  149. return mTextureView;
  150. }
  151. @Nullable
  152. @Override
  153. public SurfaceHolder getSurfaceHolder() {
  154. return null;
  155. }
  156. @Nullable
  157. @Override
  158. public SurfaceTexture getSurfaceTexture() {
  159. return mSurfaceTexture;
  160. }
  161. @Nullable
  162. @Override
  163. public Surface openSurface() {
  164. if (mSurfaceTexture == null)
  165. return null;
  166. return new Surface(mSurfaceTexture);
  167. }
  168. }
  169. //-------------------------
  170. // SurfaceHolder.Callback
  171. //-------------------------
  172. @Override
  173. public void addRenderCallback(IRenderCallback callback) {
  174. mSurfaceCallback.addRenderCallback(callback);
  175. }
  176. @Override
  177. public void removeRenderCallback(IRenderCallback callback) {
  178. mSurfaceCallback.removeRenderCallback(callback);
  179. }
  180. private SurfaceCallback mSurfaceCallback;
  181. private static final class SurfaceCallback implements SurfaceTextureListener, ISurfaceTextureHost {
  182. private SurfaceTexture mSurfaceTexture;
  183. private boolean mIsFormatChanged;
  184. private int mWidth;
  185. private int mHeight;
  186. private boolean mOwnSurfaceTexture = true;
  187. private boolean mWillDetachFromWindow = false;
  188. private boolean mDidDetachFromWindow = false;
  189. private WeakReference<TextureRenderView> mWeakRenderView;
  190. private Map<IRenderCallback, Object> mRenderCallbackMap = new ConcurrentHashMap<IRenderCallback, Object>();
  191. public SurfaceCallback(@NonNull TextureRenderView renderView) {
  192. mWeakRenderView = new WeakReference<TextureRenderView>(renderView);
  193. }
  194. public void setOwnSurfaceTexture(boolean ownSurfaceTexture) {
  195. mOwnSurfaceTexture = ownSurfaceTexture;
  196. }
  197. public void addRenderCallback(@NonNull IRenderCallback callback) {
  198. mRenderCallbackMap.put(callback, callback);
  199. ISurfaceHolder surfaceHolder = null;
  200. if (mSurfaceTexture != null) {
  201. if (surfaceHolder == null)
  202. surfaceHolder = new InternalSurfaceHolder(mWeakRenderView.get(), mSurfaceTexture, this);
  203. callback.onSurfaceCreated(surfaceHolder, mWidth, mHeight);
  204. }
  205. if (mIsFormatChanged) {
  206. if (surfaceHolder == null)
  207. surfaceHolder = new InternalSurfaceHolder(mWeakRenderView.get(), mSurfaceTexture, this);
  208. callback.onSurfaceChanged(surfaceHolder, 0, mWidth, mHeight);
  209. }
  210. }
  211. public void removeRenderCallback(@NonNull IRenderCallback callback) {
  212. mRenderCallbackMap.remove(callback);
  213. }
  214. @Override
  215. public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
  216. mSurfaceTexture = surface;
  217. mIsFormatChanged = false;
  218. mWidth = 0;
  219. mHeight = 0;
  220. ISurfaceHolder surfaceHolder = new InternalSurfaceHolder(mWeakRenderView.get(), surface, this);
  221. for (IRenderCallback renderCallback : mRenderCallbackMap.keySet()) {
  222. renderCallback.onSurfaceCreated(surfaceHolder, 0, 0);
  223. }
  224. }
  225. @Override
  226. public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
  227. mSurfaceTexture = surface;
  228. mIsFormatChanged = true;
  229. mWidth = width;
  230. mHeight = height;
  231. ISurfaceHolder surfaceHolder = new InternalSurfaceHolder(mWeakRenderView.get(), surface, this);
  232. for (IRenderCallback renderCallback : mRenderCallbackMap.keySet()) {
  233. renderCallback.onSurfaceChanged(surfaceHolder, 0, width, height);
  234. }
  235. }
  236. @Override
  237. public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
  238. mSurfaceTexture = surface;
  239. mIsFormatChanged = false;
  240. mWidth = 0;
  241. mHeight = 0;
  242. ISurfaceHolder surfaceHolder = new InternalSurfaceHolder(mWeakRenderView.get(), surface, this);
  243. for (IRenderCallback renderCallback : mRenderCallbackMap.keySet()) {
  244. renderCallback.onSurfaceDestroyed(surfaceHolder);
  245. }
  246. Log.d(TAG, "onSurfaceTextureDestroyed: destroy: " + mOwnSurfaceTexture);
  247. return mOwnSurfaceTexture;
  248. }
  249. @Override
  250. public void onSurfaceTextureUpdated(SurfaceTexture surface) {
  251. }
  252. //-------------------------
  253. // ISurfaceTextureHost
  254. //-------------------------
  255. @Override
  256. public void releaseSurfaceTexture(SurfaceTexture surfaceTexture) {
  257. if (surfaceTexture == null) {
  258. Log.d(TAG, "releaseSurfaceTexture: null");
  259. } else if (mDidDetachFromWindow) {
  260. if (surfaceTexture != mSurfaceTexture) {
  261. Log.d(TAG, "releaseSurfaceTexture: didDetachFromWindow(): release different SurfaceTexture");
  262. surfaceTexture.release();
  263. } else if (!mOwnSurfaceTexture) {
  264. Log.d(TAG, "releaseSurfaceTexture: didDetachFromWindow(): release detached SurfaceTexture");
  265. surfaceTexture.release();
  266. } else {
  267. Log.d(TAG, "releaseSurfaceTexture: didDetachFromWindow(): already released by TextureView");
  268. }
  269. } else if (mWillDetachFromWindow) {
  270. if (surfaceTexture != mSurfaceTexture) {
  271. Log.d(TAG, "releaseSurfaceTexture: willDetachFromWindow(): release different SurfaceTexture");
  272. surfaceTexture.release();
  273. } else if (!mOwnSurfaceTexture) {
  274. Log.d(TAG, "releaseSurfaceTexture: willDetachFromWindow(): re-attach SurfaceTexture to TextureView");
  275. setOwnSurfaceTexture(true);
  276. } else {
  277. Log.d(TAG, "releaseSurfaceTexture: willDetachFromWindow(): will released by TextureView");
  278. }
  279. } else {
  280. if (surfaceTexture != mSurfaceTexture) {
  281. Log.d(TAG, "releaseSurfaceTexture: alive: release different SurfaceTexture");
  282. surfaceTexture.release();
  283. } else if (!mOwnSurfaceTexture) {
  284. Log.d(TAG, "releaseSurfaceTexture: alive: re-attach SurfaceTexture to TextureView");
  285. setOwnSurfaceTexture(true);
  286. } else {
  287. Log.d(TAG, "releaseSurfaceTexture: alive: will released by TextureView");
  288. }
  289. }
  290. }
  291. public void willDetachFromWindow() {
  292. Log.d(TAG, "willDetachFromWindow()");
  293. mWillDetachFromWindow = true;
  294. }
  295. public void didDetachFromWindow() {
  296. Log.d(TAG, "didDetachFromWindow()");
  297. mDidDetachFromWindow = true;
  298. }
  299. }
  300. //--------------------
  301. // Accessibility
  302. //--------------------
  303. @Override
  304. public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
  305. super.onInitializeAccessibilityEvent(event);
  306. event.setClassName(TextureRenderView.class.getName());
  307. }
  308. @Override
  309. public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
  310. super.onInitializeAccessibilityNodeInfo(info);
  311. info.setClassName(TextureRenderView.class.getName());
  312. }
  313. }