4

I have been trying for a long time to render a video on a "Surface" class using MediaPlayer class. It was playing audio, but not the video. Everywhere I search, people talk about SurfaceView and SurfaceHolder but I have only a Surface object. How to crack this blocker?

This is how I tried,

public class SampleVideoPlayer{

private Uri mUrl;
private Surface mSurface;
private MediaPlayer mMediaPlayer;
private Context mContext;

public SampleVideoPlayer(Context context, String url, Surface surface){
    mUrl = Uri.parse(url);
    mSurface = surface;
    mMediaPlayer = new MediaPlayer();
    mContext = context;
}

public void playVideo() throws IOException {
        mMediaPlayer.setDataSource(mContext, mUrl);
        mMediaPlayer.setSurface(mSurface);
        mMediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener(){
            @Override
            public void onPrepared(MediaPlayer mediaPlayer) {
                mediaPlayer.start();
            }
        });
        mMediaPlayer.prepareAsync();
}

}

Adding the Session Object I am passing,

public class MyTvSession extends TvInputService.Session implements Handler.Callback {

Context mContext;
String vidUrl;
Surface mSurface;
SampleVideoPlayer player = null;
SampleMediaPlayer mediaPlayer;

public MyTvSession(Context context){
    super(context);
    ChannelXmlReader reader = new ChannelXmlReader(context);
    ArrayList<Channel> channels = reader.ReadXml();
    mContext = context;
    vidUrl = channels.get(0).url;
}
@Override
public boolean handleMessage(Message message) {
    Log.d("HANDLE MESSAGE", message.toString());
    return true;
}

@Override
public void onRelease() {

}

@Override
public boolean onSetSurface(Surface surface) {
    if(surface != null)
        Log.d("NOT NULL from SESSION", "NOTNULL");
    mSurface = surface;
    return true;
}

@Override
public void onSurfaceChanged(int format, int width, int height) {
    super.onSurfaceChanged(format, width, height);
    if(mediaPlayer != null)
        mediaPlayer.mMediaPlayer.setSurface(mSurface);

    Log.d("ONSURFACECHANGED", "Event");
}



@Override
public void onSetStreamVolume(float v) {

}

@Override
public boolean onTune(Uri uri) {
    Log.d("TUNING CHANNEL", uri.toString());
    try {
        mediaPlayer = new SampleMediaPlayer(mContext, vidUrl, mSurface);
        mediaPlayer.playVideo();
    }catch(Exception e){
        Log.d("MPEXCEPTION", Log.getStackTraceString(e));
    }
    return true;
}

@Override
public void onSetCaptionEnabled(boolean b) {

}

}

Prasanna Sundar
  • 1,650
  • 1
  • 11
  • 16

2 Answers2

2

The Surface class is a thin wrapper around a buffer list shared with the backing surfaceflinger process, which is responsible for rendering to the display.

You can get one of these using the SurfaceView and its SurfaceHolder, which are tied to the lifecycle of the view. So be sure to get it after being called back when the surface has been created.

Alternatively, you can use a SurfaceTexture which is created using your own custom OpenGL context. With this approach you can render using your own OpenGL code or even pass it off to the media engine for rendering. You can also get a SurfaceTexture tied to the view subsystem by using TextureView (but like SurfaceView you'll need to use it at the appropriate time in its lifecycle.)

Larry Schiefer
  • 15,687
  • 2
  • 27
  • 33
  • thanks for the answer! but still, can you help me solve my problem? TvInputFramework gives me a "Surface" object over which I can draw videos. I used MediaPlayer and set its surface to play video over it. But I can hear only audio content and can't see any visual content. – Prasanna Sundar Aug 08 '16 at 12:53
  • How did you get the backing `Surface` from the TV input layer? – Larry Schiefer Aug 08 '16 at 13:11
  • TvInputManager will call my implementation of `onSetSurface(Surface surface)` and that is how I get the backing Surface object. – Prasanna Sundar Aug 08 '16 at 13:47
  • Are you sure the app is actually providing your service session with a valid surface? – Larry Schiefer Aug 08 '16 at 14:33
  • yes i am sure! it is not null and it was able to play audio of the track and I could see a frame of the video whenever I try to force close the app – Prasanna Sundar Aug 08 '16 at 14:56
  • Check to see if the overlay is enabled or not as well as whether the layout dimensions have been set for the session. – Larry Schiefer Aug 08 '16 at 15:07
  • CHecked everything possible, Larry! I still can't seem to find what I am missing! Adding more code to the above – Prasanna Sundar Aug 08 '16 at 16:56
  • Interesting from the `MediaPlayer.setSurface()` documentation: "... A null surface will result in only the audio track being played..." You may want to check that you are getting an actual `Surface` object and not `null`. – Larry Schiefer Aug 08 '16 at 18:52
1

I have exactly the same problem. But it only happens on Philips TV. The same code runs fine on every other Android TV devices. The surface I get in onSetSurface is valid, sound is playing, but picture is black. When I close the app, the video is visible for a second. It seems to be in the background.

cyberdelic
  • 21
  • 2