VideoRenderSurfaceView is this even possible?

  ... the case you feel the need for a new feature or want to submit one.

VideoRenderSurfaceView is this even possible?

Postby CyberCod » Tue Apr 16, 2013 6:20 pm

I have tried to merge the android VideoView with Andengine's RenderSurfaceView.

The idea is that it would be nice to be able to play videos for cutscenes inside the same activity as Andengine... for the purposes of hiding load times and not boring the pants off the player.

I'm kind of just hacking away at this poorly, so if anyone can take a look and help me get this working, I'll be happy to share the finished code. Maybe Nicolas Gramlich will make it a new official extension!


As both VideoView and RenderSurfaceView are extensions of SurfaceView, I just started out by dumping all the methods and whatnot from VideoView into an extension of RenderSurfaceView.

I'm still studying the whole mess, but if it is familiar to you, dear reader, and you can shed some light, then I most graciously welcome you to do so.

Syntax: [ Download ] [ Hide ]
Using java Syntax Highlighting
  1. package com.mybeta;
  2.  
  3. import org.andengine.opengl.view.RenderSurfaceView;
  4.  
  5. import android.content.Context;
  6.  
  7. import android.annotation.SuppressLint;
  8. import android.app.AlertDialog;
  9. import android.content.Context;
  10. import android.content.DialogInterface;
  11. import android.content.Intent;
  12. import android.content.res.Resources;
  13. import android.media.AudioManager;
  14. import android.media.MediaPlayer;
  15. //import android.media.Metadata;
  16. import android.media.MediaPlayer.OnCompletionListener;
  17. import android.media.MediaPlayer.OnErrorListener;
  18. import android.net.Uri;
  19. import android.util.AttributeSet;
  20. import android.util.Log;
  21. import android.view.KeyEvent;
  22. import android.view.MotionEvent;
  23. import android.view.SurfaceHolder;
  24. import android.view.SurfaceView;
  25. import android.view.View;
  26. import android.widget.MediaController;
  27. import android.widget.MediaController.MediaPlayerControl;
  28.  
  29. import java.io.IOException;
  30. import java.util.Map;
  31.  
  32.  
  33.  
  34. public class VideoRenderSurfaceView extends RenderSurfaceView implements MediaPlayerControl{
  35.  
  36.        
  37.  
  38.     private String TAG = "VideoView";
  39.     // settable by the client
  40.     private Uri         mUri;
  41.     private Map<String, String> mHeaders;
  42.     private int         mDuration;
  43.  
  44.     // all possible internal states
  45.     private static final int STATE_ERROR              = -1;
  46.     private static final int STATE_IDLE               = 0;
  47.     private static final int STATE_PREPARING          = 1;
  48.     private static final int STATE_PREPARED           = 2;
  49.     private static final int STATE_PLAYING            = 3;
  50.     private static final int STATE_PAUSED             = 4;
  51.     private static final int STATE_PLAYBACK_COMPLETED = 5;
  52.     private static final int STATE_SUSPEND            = 6;
  53.     private static final int STATE_RESUME             = 7;
  54.     private static final int STATE_SUSPEND_UNSUPPORTED = 8;
  55.  
  56.     // mCurrentState is a VideoView object's current state.
  57.     // mTargetState is the state that a method caller intends to reach.
  58.     // For instance, regardless the VideoView object's current state,
  59.     // calling pause() intends to bring the object to a target state
  60.     // of STATE_PAUSED.
  61.     private int mCurrentState = STATE_IDLE;
  62.     private int mTargetState  = STATE_IDLE;
  63.  
  64.     // All the stuff we need for playing and showing a video
  65.     private SurfaceHolder mSurfaceHolder = null;
  66.     private MediaPlayer mMediaPlayer = null;
  67.     private int         mVideoWidth;
  68.     private int         mVideoHeight;
  69.     private int         mSurfaceWidth;
  70.     private int         mSurfaceHeight;
  71.     private MediaController mMediaController;
  72.     private OnCompletionListener mOnCompletionListener;
  73.     private MediaPlayer.OnPreparedListener mOnPreparedListener;
  74.     private int         mCurrentBufferPercentage;
  75.     private OnErrorListener mOnErrorListener;
  76.     private int         mSeekWhenPrepared;  // recording the seek position while preparing
  77.     private boolean     mCanPause;
  78.     private boolean     mCanSeekBack;
  79.     private boolean     mCanSeekForward;
  80.     private int         mStateWhenSuspended;  //state before calling suspend()
  81.         private Context mContext;
  82.  
  83.     public VideoRenderSurfaceView(Context context) {
  84.         super(context);
  85.         mContext = context;
  86.         initVideoView();
  87.        
  88.     }
  89.  
  90.     public VideoRenderSurfaceView(Context context, AttributeSet attrs) {
  91.         this(context, attrs, 0);
  92.         mContext = context;
  93.         initVideoView();
  94.     }
  95.  
  96.     public VideoRenderSurfaceView(Context context, AttributeSet attrs, int defStyle) {
  97.         super(context);
  98.         mContext = context;
  99.         initVideoView();
  100.     }
  101.  
  102.     @Override
  103.     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
  104.         //Log.i("@@@@", "onMeasure");
  105.         int width = getDefaultSize(mVideoWidth, widthMeasureSpec);
  106.         int height = getDefaultSize(mVideoHeight, heightMeasureSpec);
  107.         if (mVideoWidth > 0 && mVideoHeight > 0) {
  108.             if ( mVideoWidth * height  > width * mVideoHeight ) {
  109.                 //Log.i("@@@", "image too tall, correcting");
  110.                 height = width * mVideoHeight / mVideoWidth;
  111.             } else if ( mVideoWidth * height  < width * mVideoHeight ) {
  112.                 //Log.i("@@@", "image too wide, correcting");
  113.                 width = height * mVideoWidth / mVideoHeight;
  114.             } else {
  115.                 //Log.i("@@@", "aspect ratio is correct: " +
  116.                         //width+"/"+height+"="+
  117.                         //mVideoWidth+"/"+mVideoHeight);
  118.             }
  119.         }
  120.         //Log.i("@@@@@@@@@@", "setting size: " + width + 'x' + height);
  121.         setMeasuredDimension(width, height);
  122.     }
  123.  
  124.     public int resolveAdjustedSize(int desiredSize, int measureSpec) {
  125.         int result = desiredSize;
  126.         int specMode = MeasureSpec.getMode(measureSpec);
  127.         int specSize =  MeasureSpec.getSize(measureSpec);
  128.  
  129.         switch (specMode) {
  130.             case MeasureSpec.UNSPECIFIED:
  131.                 /* Parent says we can be as big as we want. Just don't be larger
  132.                  * than max size imposed on ourselves.
  133.                  */
  134.                 result = desiredSize;
  135.                 break;
  136.  
  137.             case MeasureSpec.AT_MOST:
  138.                 /* Parent says we can be as big as we want, up to specSize.
  139.                  * Don't be larger than specSize, and don't be larger than
  140.                  * the max size imposed on ourselves.
  141.                  */
  142.                 result = Math.min(desiredSize, specSize);
  143.                 break;
  144.  
  145.             case MeasureSpec.EXACTLY:
  146.                 // No choice. Do what we are told.
  147.                 result = specSize;
  148.                 break;
  149.         }
  150.         return result;
  151. }
  152.  
  153.     private void initVideoView() {
  154.         mVideoWidth = 0;
  155.         mVideoHeight = 0;
  156.         getHolder().addCallback(mSHCallback);
  157.         getHolder().setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
  158.         setFocusable(true);
  159.         setFocusableInTouchMode(true);
  160.         requestFocus();
  161.         mCurrentState = STATE_IDLE;
  162.         mTargetState  = STATE_IDLE;
  163.     }
  164.  
  165.     public void setVideoPath(String path) {
  166.         setVideoURI(Uri.parse(path));
  167.     }
  168.  
  169.     public void setVideoURI(Uri uri) {
  170.         setVideoURI(uri, null);
  171.     }
  172.  
  173.     /**
  174.      * @hide
  175.      */
  176.     public void setVideoURI(Uri uri, Map<String, String> headers) {
  177.         mUri = uri;
  178.         mHeaders = headers;
  179.         mSeekWhenPrepared = 0;
  180.         openVideo();
  181.         requestLayout();
  182.         invalidate();
  183.     }
  184.  
  185.     public void stopPlayback() {
  186.         if (mMediaPlayer != null) {
  187.             mMediaPlayer.stop();
  188.             mMediaPlayer.release();
  189.             mMediaPlayer = null;
  190.             mCurrentState = STATE_IDLE;
  191.             mTargetState  = STATE_IDLE;
  192.         }
  193.     }
  194.  
  195.     @SuppressLint("NewApi")
  196.         private void openVideo() {
  197.         if (mUri == null || mSurfaceHolder == null) {
  198.             // not ready for playback just yet, will try again later
  199.             return;
  200.         }
  201.         // Tell the music playback service to pause
  202.         // TODO: these constants need to be published somewhere in the framework.
  203.         Intent i = new Intent("com.android.music.musicservicecommand");
  204.         i.putExtra("command", "pause");
  205.         mContext.sendBroadcast(i);
  206.  
  207.         // we shouldn't clear the target state, because somebody might have
  208.         // called start() previously
  209.         release(false);
  210.         try {
  211.             mMediaPlayer = new MediaPlayer();
  212.             mMediaPlayer.setOnPreparedListener(mPreparedListener);
  213.             mMediaPlayer.setOnVideoSizeChangedListener(mSizeChangedListener);
  214.             mDuration = -1;
  215.             mMediaPlayer.setOnCompletionListener(mCompletionListener);
  216.             mMediaPlayer.setOnErrorListener(mErrorListener);
  217.             mMediaPlayer.setOnBufferingUpdateListener(mBufferingUpdateListener);
  218.             mCurrentBufferPercentage = 0;
  219.             mMediaPlayer.setDataSource(mContext, mUri, mHeaders);
  220.             mMediaPlayer.setDisplay(mSurfaceHolder);
  221.             mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
  222.             mMediaPlayer.setScreenOnWhilePlaying(true);
  223.             mMediaPlayer.prepareAsync();
  224.             // we don't set the target state here either, but preserve the
  225.             // target state that was there before.
  226.             mCurrentState = STATE_PREPARING;
  227.             attachMediaController();
  228.         } catch (IOException ex) {
  229.             Log.w(TAG, "Unable to open content: " + mUri, ex);
  230.             mCurrentState = STATE_ERROR;
  231.             mTargetState = STATE_ERROR;
  232.             mErrorListener.onError(mMediaPlayer, MediaPlayer.MEDIA_ERROR_UNKNOWN, 0);
  233.             return;
  234.         } catch (IllegalArgumentException ex) {
  235.             Log.w(TAG, "Unable to open content: " + mUri, ex);
  236.             mCurrentState = STATE_ERROR;
  237.             mTargetState = STATE_ERROR;
  238.             mErrorListener.onError(mMediaPlayer, MediaPlayer.MEDIA_ERROR_UNKNOWN, 0);
  239.             return;
  240.         }
  241.     }
  242.  
  243.     public void setMediaController(MediaController controller) {
  244.         if (mMediaController != null) {
  245.             mMediaController.hide();
  246.         }
  247.         mMediaController = controller;
  248.         attachMediaController();
  249.     }
  250.  
  251.     private void attachMediaController() {
  252.         if (mMediaPlayer != null && mMediaController != null) {
  253.             mMediaController.setMediaPlayer(this);
  254.             View anchorView = this.getParent() instanceof View ?
  255.                     (View)this.getParent() : this;
  256.             mMediaController.setAnchorView(anchorView);
  257.             mMediaController.setEnabled(isInPlaybackState());
  258.         }
  259.     }
  260.  
  261.     MediaPlayer.OnVideoSizeChangedListener mSizeChangedListener =
  262.         new MediaPlayer.OnVideoSizeChangedListener() {
  263.             public void onVideoSizeChanged(MediaPlayer mp, int width, int height) {
  264.                 mVideoWidth = mp.getVideoWidth();
  265.                 mVideoHeight = mp.getVideoHeight();
  266.                 if (mVideoWidth != 0 && mVideoHeight != 0) {
  267.                     getHolder().setFixedSize(mVideoWidth, mVideoHeight);
  268.                 }
  269.             }
  270.     };
  271.  
  272.     MediaPlayer.OnPreparedListener mPreparedListener = new MediaPlayer.OnPreparedListener() {
  273.         public void onPrepared(MediaPlayer mp) {
  274.             mCurrentState = STATE_PREPARED;
  275.  
  276.             // Get the capabilities of the player for this stream
  277.  
  278.                 mCanPause = mCanSeekBack = mCanSeekForward = true;
  279.  
  280.             if (mOnPreparedListener != null) {
  281.                 mOnPreparedListener.onPrepared(mMediaPlayer);
  282.             }
  283.             if (mMediaController != null) {
  284.                 mMediaController.setEnabled(true);
  285.             }
  286.             mVideoWidth = mp.getVideoWidth();
  287.             mVideoHeight = mp.getVideoHeight();
  288.  
  289.             int seekToPosition = mSeekWhenPrepared;  // mSeekWhenPrepared may be changed after seekTo() call
  290.             if (seekToPosition != 0) {
  291.                 seekTo(seekToPosition);
  292.             }
  293.             if (mVideoWidth != 0 && mVideoHeight != 0) {
  294.                 //Log.i("@@@@", "video size: " + mVideoWidth +"/"+ mVideoHeight);
  295.                 getHolder().setFixedSize(mVideoWidth, mVideoHeight);
  296.                 if (mSurfaceWidth == mVideoWidth && mSurfaceHeight == mVideoHeight) {
  297.                     // We didn't actually change the size (it was already at the size
  298.                     // we need), so we won't get a "surface changed" callback, so
  299.                     // start the video here instead of in the callback.
  300.                     if (mTargetState == STATE_PLAYING) {
  301.                         start();
  302.                         if (mMediaController != null) {
  303.                             mMediaController.show();
  304.                         }
  305.                     } else if (!isPlaying() &&
  306.                                (seekToPosition != 0 || getCurrentPosition() > 0)) {
  307.                        if (mMediaController != null) {
  308.                            // Show the media controls when we're paused into a video and make 'em stick.
  309.                            mMediaController.show(0);
  310.                        }
  311.                    }
  312.                 }
  313.             } else {
  314.                 // We don't know the video size yet, but should start anyway.
  315.                 // The video size might be reported to us later.
  316.                 if (mTargetState == STATE_PLAYING) {
  317.                     start();
  318.                 }
  319.             }
  320.         }
  321.     };
  322.  
  323.     private MediaPlayer.OnCompletionListener mCompletionListener =
  324.         new MediaPlayer.OnCompletionListener() {
  325.         public void onCompletion(MediaPlayer mp) {
  326.             mCurrentState = STATE_PLAYBACK_COMPLETED;
  327.             mTargetState = STATE_PLAYBACK_COMPLETED;
  328.             if (mMediaController != null) {
  329.                 mMediaController.hide();
  330.             }
  331.             if (mOnCompletionListener != null) {
  332.                 mOnCompletionListener.onCompletion(mMediaPlayer);
  333.             }
  334.         }
  335.     };
  336.  
  337.     private MediaPlayer.OnErrorListener mErrorListener =
  338.         new MediaPlayer.OnErrorListener() {
  339.         public boolean onError(MediaPlayer mp, int framework_err, int impl_err) {
  340.             Log.d(TAG, "Error: " + framework_err + "," + impl_err);
  341.             mCurrentState = STATE_ERROR;
  342.             mTargetState = STATE_ERROR;
  343.             if (mMediaController != null) {
  344.                 mMediaController.hide();
  345.             }
  346.  
  347.             /* If an error handler has been supplied, use it and finish. */
  348.             if (mOnErrorListener != null) {
  349.                 if (mOnErrorListener.onError(mMediaPlayer, framework_err, impl_err)) {
  350.                     return true;
  351.                 }
  352.             }
  353.  
  354.          
  355.             return true;
  356.         }
  357.     };
  358.  
  359.     private MediaPlayer.OnBufferingUpdateListener mBufferingUpdateListener =
  360.         new MediaPlayer.OnBufferingUpdateListener() {
  361.         public void onBufferingUpdate(MediaPlayer mp, int percent) {
  362.             mCurrentBufferPercentage = percent;
  363.         }
  364.     };
  365.  
  366.     /**
  367.      * Register a callback to be invoked when the media file
  368.      * is loaded and ready to go.
  369.      *
  370.      * @param l The callback that will be run
  371.      */
  372.     public void setOnPreparedListener(MediaPlayer.OnPreparedListener l)
  373.     {
  374.         mOnPreparedListener = l;
  375.     }
  376.  
  377.     /**
  378.      * Register a callback to be invoked when the end of a media file
  379.      * has been reached during playback.
  380.      *
  381.      * @param l The callback that will be run
  382.      */
  383.     public void setOnCompletionListener(OnCompletionListener l)
  384.     {
  385.         mOnCompletionListener = l;
  386.     }
  387.  
  388.     /**
  389.      * Register a callback to be invoked when an error occurs
  390.      * during playback or setup.  If no listener is specified,
  391.      * or if the listener returned false, VideoView will inform
  392.      * the user of any errors.
  393.      *
  394.      * @param l The callback that will be run
  395.      */
  396.     public void setOnErrorListener(OnErrorListener l)
  397.     {
  398.         mOnErrorListener = l;
  399.     }
  400.  
  401.     SurfaceHolder.Callback mSHCallback = new SurfaceHolder.Callback()
  402.     {
  403.         public void surfaceChanged(SurfaceHolder holder, int format,
  404.                                     int w, int h)
  405.         {
  406.             mSurfaceWidth = w;
  407.             mSurfaceHeight = h;
  408.             boolean isValidState =  (mTargetState == STATE_PLAYING);
  409.             boolean hasValidSize = (mVideoWidth == w && mVideoHeight == h);
  410.             if (mMediaPlayer != null && isValidState && hasValidSize) {
  411.                 if (mSeekWhenPrepared != 0) {
  412.                     seekTo(mSeekWhenPrepared);
  413.                 }
  414.                 start();
  415.                 if (mMediaController != null) {
  416.                     if (mMediaController.isShowing()) {
  417.                         // ensure the controller will get repositioned later
  418.                         mMediaController.hide();
  419.                     }
  420.                     mMediaController.show();
  421.                 }
  422.             }
  423.         }
  424.  
  425.         public void surfaceCreated(SurfaceHolder holder)
  426.         {
  427.             mSurfaceHolder = holder;
  428.             //resume() was called before surfaceCreated()
  429.             if (mMediaPlayer != null && mCurrentState == STATE_SUSPEND
  430.                    && mTargetState == STATE_RESUME) {
  431.                 mMediaPlayer.setDisplay(mSurfaceHolder);
  432.                 resume();
  433.             } else {
  434.                 openVideo();
  435.             }
  436.         }
  437.  
  438.         public void surfaceDestroyed(SurfaceHolder holder)
  439.         {
  440.             // after we return from this we can't use the surface any more
  441.             mSurfaceHolder = null;
  442.             if (mMediaController != null) mMediaController.hide();
  443.             if (mCurrentState != STATE_SUSPEND) {
  444.                 release(true);
  445.             }
  446.         }
  447.     };
  448.  
  449.     /*
  450.      * release the media player in any state
  451.      */
  452.     private void release(boolean cleartargetstate) {
  453.         if (mMediaPlayer != null) {
  454.             mMediaPlayer.reset();
  455.             mMediaPlayer.release();
  456.             mMediaPlayer = null;
  457.             mCurrentState = STATE_IDLE;
  458.             if (cleartargetstate) {
  459.                 mTargetState  = STATE_IDLE;
  460.             }
  461.         }
  462.     }
  463.  
  464.     @Override
  465.     public boolean onTouchEvent(MotionEvent ev) {
  466.         if (isInPlaybackState() && mMediaController != null) {
  467.             toggleMediaControlsVisiblity();
  468.         }
  469.         return false;
  470.     }
  471.  
  472.     @Override
  473.     public boolean onTrackballEvent(MotionEvent ev) {
  474.         if (isInPlaybackState() && mMediaController != null) {
  475.             toggleMediaControlsVisiblity();
  476.         }
  477.         return false;
  478.     }
  479.  
  480.     @Override
  481.     public boolean onKeyDown(int keyCode, KeyEvent event)
  482.     {
  483.         boolean isKeyCodeSupported = keyCode != KeyEvent.KEYCODE_BACK &&
  484.                                      keyCode != KeyEvent.KEYCODE_VOLUME_UP &&
  485.                                      keyCode != KeyEvent.KEYCODE_VOLUME_DOWN &&
  486.                                      keyCode != KeyEvent.KEYCODE_MENU &&
  487.                                      keyCode != KeyEvent.KEYCODE_CALL &&
  488.                                      keyCode != KeyEvent.KEYCODE_ENDCALL;
  489.         if (isInPlaybackState() && isKeyCodeSupported && mMediaController != null) {
  490.             if (keyCode == KeyEvent.KEYCODE_HEADSETHOOK ||
  491.                     keyCode == KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE) {
  492.                 if (mMediaPlayer.isPlaying()) {
  493.                     pause();
  494.                     mMediaController.show();
  495.                 } else {
  496.                     start();
  497.                     mMediaController.hide();
  498.                 }
  499.                 return true;
  500.             } else if (keyCode == KeyEvent.KEYCODE_MEDIA_STOP
  501.                     && mMediaPlayer.isPlaying()) {
  502.                 pause();
  503.                 mMediaController.show();
  504.             } else {
  505.                 toggleMediaControlsVisiblity();
  506.             }
  507.         }
  508.  
  509.         return super.onKeyDown(keyCode, event);
  510.     }
  511.  
  512.     private void toggleMediaControlsVisiblity() {
  513.         if (mMediaController.isShowing()) {
  514.             mMediaController.hide();
  515.         } else {
  516.             mMediaController.show();
  517.         }
  518.     }
  519.  
  520.     public void start() {
  521.         if (isInPlaybackState()) {
  522.             mMediaPlayer.start();
  523.             mCurrentState = STATE_PLAYING;
  524.         }
  525.         mTargetState = STATE_PLAYING;
  526.     }
  527.  
  528.     public void pause() {
  529.         if (isInPlaybackState()) {
  530.             if (mMediaPlayer.isPlaying()) {
  531.                 mMediaPlayer.pause();
  532.                 mCurrentState = STATE_PAUSED;
  533.             }
  534.         }
  535.         mTargetState = STATE_PAUSED;
  536.     }
  537.  
  538.  
  539.  
  540.     public void resume() {
  541.    
  542.             openVideo();
  543.    
  544.     }
  545.  
  546.    // cache duration as mDuration for faster access
  547.     public int getDuration() {
  548.         if (isInPlaybackState()) {
  549.             if (mDuration > 0) {
  550.                 return mDuration;
  551.             }
  552.             mDuration = mMediaPlayer.getDuration();
  553.             return mDuration;
  554.         }
  555.         mDuration = -1;
  556.         return mDuration;
  557.     }
  558.  
  559.     public int getCurrentPosition() {
  560.         if (isInPlaybackState()) {
  561.             return mMediaPlayer.getCurrentPosition();
  562.         }
  563.         return 0;
  564.     }
  565.  
  566.     public void seekTo(int msec) {
  567.         if (isInPlaybackState()) {
  568.             mMediaPlayer.seekTo(msec);
  569.             mSeekWhenPrepared = 0;
  570.         } else {
  571.             mSeekWhenPrepared = msec;
  572.         }
  573.     }
  574.  
  575.     public boolean isPlaying() {
  576.         return isInPlaybackState() && mMediaPlayer.isPlaying();
  577.     }
  578.  
  579.     public int getBufferPercentage() {
  580.         if (mMediaPlayer != null) {
  581.             return mCurrentBufferPercentage;
  582.         }
  583.         return 0;
  584.     }
  585.  
  586.     private boolean isInPlaybackState() {
  587.         return (mMediaPlayer != null &&
  588.                 mCurrentState != STATE_ERROR &&
  589.                 mCurrentState != STATE_IDLE &&
  590.                 mCurrentState != STATE_PREPARING);
  591.     }
  592.  
  593.     public boolean canPause() {
  594.         return mCanPause;
  595.     }
  596.  
  597.     public boolean canSeekBackward() {
  598.         return mCanSeekBack;
  599.     }
  600.  
  601.     public boolean canSeekForward() {
  602.         return mCanSeekForward;
  603.     }
  604.  
  605.        
  606. }
  607.  
  608.  
  609.  
  610.  
Parsed in 0.041 seconds, using GeSHi 1.0.8.4
Intense one vs many martial arts combat!
check out Stickman Vs Infinite Ninjas on Google Play
https://play.google.com/store/apps/details?id=com.smiths.free
CyberCod
 
Posts: 77
Joined: Fri Apr 20, 2012 8:24 pm

Re: VideoRenderSurfaceView is this even possible?

Postby gubano » Fri Jul 05, 2013 7:23 pm

Dear CyberCod, how did it go with the implementation in order to play videos for cutscenes inside the same activity as Andengine? Were you able to play video in the same activity?

best regards
gubano
 
Posts: 1
Joined: Fri Jul 05, 2013 4:34 pm


Return to Features

Who is online

Users browsing this forum: No registered users and 7 guests