Bram
Bram

Reputation: 1

custom code vlc on android - no video

I've almost got a successfully working code sample of vlc for android. I've been using the VideoPlayerActivity as an example.

Currently I have the surface displayed through the surfacehandler and I see a black video image background box (SurfaceView). I also have working audio. However for some reason I cannot get any video. Logcat says the following continuously:

yuv_rgb_neon: can't get video picture.

I think it's a very small issue in my code. I've tried virtually anything I can think of but I can't get it to work.

Can anyone point me in the right direction perhaps?

this is the core libvlc code i use: I think something is wrong with the init context parameter, but I can't seem to find out what it is. (I have the same surface handler as the original VideoPlayerActivity located in org.videloan.vlc.gui.video)


 mLibVLC = LibVLC.getInstance();
 mLibVLC.setIomx(false);
 mLibVLC.setSubtitlesEncoding("");
 mLibVLC.setTimeStretching(false);
 mLibVLC.setFrameSkip(true);
 mLibVLC.setChroma("RV16");
 mLibVLC.setVerboseMode(true);
 mLibVLC.setAout(-1);
 mLibVLC.setDeblocking(0);
 mLibVLC.setNetworkCaching(0);
 mLibVLC.init(this.getApplicationContext());

Full code snippet:

 /* VideoPlayerActivity.java */

 package com.example.mp2;

 import java.lang.reflect.Method;

 import org.videolan.libvlc.EventHandler;
 import org.videolan.libvlc.IVideoPlayer;
 import org.videolan.libvlc.LibVLC;
 import org.videolan.libvlc.LibVlcException;
 import org.videolan.vlc.Util;
 import org.videolan.vlc.WeakHandler;

 import android.annotation.TargetApi;
 import android.app.Activity;
 import android.content.Context;
 import android.content.pm.ActivityInfo;
 import android.content.res.Configuration;
 import android.graphics.ImageFormat;
 import android.graphics.PixelFormat;
 import android.os.Build;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Message;
 import android.util.Log;
 import android.view.Display;
 import android.view.Surface;
 import android.view.SurfaceHolder;
 import android.view.SurfaceHolder.Callback;
 import android.view.SurfaceView;
 import android.view.View.OnSystemUiVisibilityChangeListener;
 import android.view.ViewGroup.LayoutParams;
 import android.view.WindowManager;
 import android.widget.FrameLayout;

 public class VideoPlayerActivity extends Activity implements IVideoPlayer {

    public final static String TAG = "VLC/VideoPlayerActivity";

    // Internal intent identifier to distinguish between internal launch and
    // external intent.

    private SurfaceView mSurface;
    private SurfaceHolder mSurfaceHolder;
    private FrameLayout mSurfaceFrame;
    private LibVLC mLibVLC;
    private String mLocation;

    private static final int SURFACE_BEST_FIT = 0;
    private static final int SURFACE_FIT_HORIZONTAL = 1;
    private static final int SURFACE_FIT_VERTICAL = 2;
    private static final int SURFACE_FILL = 3;
    private static final int SURFACE_16_9 = 4;
    private static final int SURFACE_4_3 = 5;
    private static final int SURFACE_ORIGINAL = 6;
    private int mCurrentSize = SURFACE_BEST_FIT;

    /** Overlay */
    private static final int SURFACE_SIZE = 3;

    // size of the video
    private int mVideoHeight;
    private int mVideoWidth;
    private int mVideoVisibleHeight;
    private int mVideoVisibleWidth;
    private int mSarNum;
    private int mSarDen;

    private static VideoPlayerActivity context;

    public static VideoPlayerActivity getContext() {
        return context;
    }

    /**
     * Used to store a selected subtitle; see onActivityResult. It is possible
     * to have multiple custom subs in one session (just like desktop VLC allows
     * you as well.)
     */@Override@TargetApi(Build.VERSION_CODES.HONEYCOMB)
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.player);
        if (Util.isICSOrLater()) getWindow().getDecorView().findViewById(android.R.id.content).setOnSystemUiVisibilityChangeListener(new OnSystemUiVisibilityChangeListener() {@Override
            public void onSystemUiVisibilityChange(int visibility) {
                setSurfaceSize(mVideoWidth, mVideoHeight, mVideoVisibleWidth, mVideoVisibleHeight, mSarNum, mSarDen);
            }
        });

        mSurface = (SurfaceView) findViewById(R.id.player_surface);
        mSurfaceHolder = mSurface.getHolder();
        mSurfaceFrame = (FrameLayout) findViewById(R.id.player_surface_frame);
        String chroma = "RV16";
        context = this;
        if (Util.isGingerbreadOrLater() && chroma.equals("YV12")) {
            mSurfaceHolder.setFormat(ImageFormat.YV12);
        } else if (chroma.equals("RV16")) {
            mSurfaceHolder.setFormat(PixelFormat.RGB_565);
        } else {
            mSurfaceHolder.setFormat(PixelFormat.RGBX_8888);
        }
        mSurfaceHolder.addCallback(mSurfaceCallback);

        try {
            mLibVLC = LibVLC.getInstance();
            mLibVLC.setIomx(false);
            mLibVLC.setSubtitlesEncoding("");
            mLibVLC.setTimeStretching(false);
            mLibVLC.setFrameSkip(true);
            mLibVLC.setChroma("RV16");
            mLibVLC.setVerboseMode(true);
            mLibVLC.setAout(-1);
            mLibVLC.setDeblocking(0);
            mLibVLC.setNetworkCaching(0);
            mLibVLC.init(this.getApplicationContext());
        } catch (LibVlcException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        EventHandler em = EventHandler.getInstance();
        em.addHandler(eventHandler);
    }

    @Override
    protected void onStart() {
        super.onStart();
    }

    @Override
    protected void onPause() {
        super.onPause();

        mLibVLC.stop();

        mSurface.setKeepScreenOn(false);

    }

    @Override
    protected void onStop() {
        super.onStop();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (mLibVLC != null) {
            mLibVLC.stop();
        }

    }

    @Override
    protected void onResume() {
        super.onResume();
        load();
    }

    private final Handler eventHandler = new VideoPlayerEventHandler(this);

    private static class VideoPlayerEventHandler extends WeakHandler < VideoPlayerActivity > {
        public VideoPlayerEventHandler(VideoPlayerActivity owner) {
            super(owner);
        }

        @Override
        public void handleMessage(Message msg) {
            VideoPlayerActivity activity = getOwner();
            if (activity == null) return;

            switch (msg.getData().getInt("event")) {
                case EventHandler.MediaPlayerPlaying:
                    Log.i(TAG, "MediaPlayerPlaying");
                    // activity.setESTracks();

                    // activity.setESTracks();
                    break;
                case EventHandler.MediaPlayerPaused:
                    Log.i(TAG, "MediaPlayerPaused");
                    break;
                case EventHandler.MediaPlayerStopped:
                    Log.i(TAG, "MediaPlayerStopped");
                    break;
                case EventHandler.MediaPlayerEndReached:
                    Log.i(TAG, "MediaPlayerEndReached");
                    // activity.endReached();
                    break;
                case EventHandler.MediaPlayerVout:
                    // activity.handleVout(msg);
                    break;
                case EventHandler.MediaPlayerPositionChanged:
                    // don't spam the logs
                    break;
                case EventHandler.MediaPlayerEncounteredError:
                    Log.i(TAG, "MediaPlayerEncounteredError");
                    // activity.encounteredError();
                    break;
                default:
                    Log.e(TAG, String.format("Event not handled (0x%x)", msg.getData().getInt("event")));
                    break;
            }
            // activity.updateOverlayPausePlay();
        }

    };

    private final Handler mHandler = new VideoPlayerHandler(this);

    private static class VideoPlayerHandler extends WeakHandler < VideoPlayerActivity > {
        public VideoPlayerHandler(VideoPlayerActivity owner) {
            super(owner);
        }

        @Override
        public void handleMessage(Message msg) {
            VideoPlayerActivity activity = getOwner();
            if (activity == null) // WeakReference could be GC'ed early
            return;

            switch (msg.what) {
                case SURFACE_SIZE:
                    activity.changeSurfaceSize();
                    break;
            }
        }
    };

    @Override
    public void setSurfaceSize(int width, int height, int visible_width, int visible_height, int sar_num, int sar_den) {
        if (width * height == 0) return;

        // store video size
        mVideoHeight = height;
        mVideoWidth = width;
        mVideoVisibleHeight = visible_height;
        mVideoVisibleWidth = visible_width;
        mSarNum = sar_num;
        mSarDen = sar_den;
        Message msg = mHandler.obtainMessage(SURFACE_SIZE);
        mHandler.sendMessage(msg);
    }

    private void changeSurfaceSize() {
        // get screen size
        int dw = getWindow().getDecorView().getWidth();
        int dh = getWindow().getDecorView().getHeight();

        // getWindow().getDecorView() doesn't always take orientation into
        // account, we have to correct the values
        boolean isPortrait = getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT;
        if (dw > dh && isPortrait || dw < dh && !isPortrait) {
            int d = dw;
            dw = dh;
            dh = d;
        }

        // sanity check
        if (dw * dh == 0 || mVideoWidth * mVideoHeight == 0) {
            Log.e(TAG, "Invalid surface size");
            return;
        }

        // compute the aspect ratio
        double ar, vw;
        double density = (double) mSarNum / (double) mSarDen;
        if (density == 1.0) {
            /* No indication about the density, assuming 1:1 */
            vw = mVideoVisibleWidth;
            ar = (double) mVideoVisibleWidth / (double) mVideoVisibleHeight;
        } else {
            /* Use the specified aspect ratio */
            vw = mVideoVisibleWidth * density;
            ar = vw / mVideoVisibleHeight;
        }

        // compute the display aspect ratio
        double dar = (double) dw / (double) dh;

        switch (mCurrentSize) {
            case SURFACE_BEST_FIT:
                if (dar < ar) dh = (int)(dw / ar);
                else dw = (int)(dh * ar);
                break;
            case SURFACE_FIT_HORIZONTAL:
                dh = (int)(dw / ar);
                break;
            case SURFACE_FIT_VERTICAL:
                dw = (int)(dh * ar);
                break;
            case SURFACE_FILL:
                break;
            case SURFACE_16_9:
                ar = 16.0 / 9.0;
                if (dar < ar) dh = (int)(dw / ar);
                else dw = (int)(dh * ar);
                break;
            case SURFACE_4_3:
                ar = 4.0 / 3.0;
                if (dar < ar) dh = (int)(dw / ar);
                else dw = (int)(dh * ar);
                break;
            case SURFACE_ORIGINAL:
                dh = mVideoVisibleHeight;
                dw = (int) vw;
                break;
        }

        // force surface buffer size
        // mSurfaceHolder.setFixedSize(mVideoWidth, mVideoHeight);

        // set display size
        LayoutParams lp = mSurface.getLayoutParams();
        lp.width = dw * mVideoWidth / mVideoVisibleWidth;
        lp.height = dh * mVideoHeight / mVideoVisibleHeight;
        mSurface.setLayoutParams(lp);

        // set frame size (crop if necessary)
        lp = mSurfaceFrame.getLayoutParams();
        lp.width = dw;
        lp.height = dh;
        mSurfaceFrame.setLayoutParams(lp);

        mSurface.invalidate();
    }

    private final SurfaceHolder.Callback mSurfaceCallback = new Callback() {@Override
        public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
            if (format == PixelFormat.RGBX_8888) Log.d(TAG, "Pixel format is RGBX_8888");
            else if (format == PixelFormat.RGB_565) Log.d(TAG, "Pixel format is RGB_565");
            else if (format == ImageFormat.YV12) Log.d(TAG, "Pixel format is YV12");
            else Log.d(TAG, "Pixel format is other/unknown");
            mLibVLC.attachSurface(holder.getSurface(), VideoPlayerActivity.this, width, height);
        }

        @Override
        public void surfaceCreated(SurfaceHolder holder) {}

        @Override
        public void surfaceDestroyed(SurfaceHolder holder) {
            mLibVLC.detachSurface();
        }
    };

    /**
     * External extras: - position (long) - position of the video to start with
     * (in ms)
     */
    private void load() {
        mLocation = "file:///sdcard/fam.mp4";
        mSurface.setKeepScreenOn(true);

        // MediaList mediaList = new MediaList(mLibVLC);
        // mLibVLC.setMediaList();
        mLibVLC.readMedia(mLocation, false);
        mLibVLC.setTime(0);
        mLibVLC.play();
    }

    @SuppressWarnings("deprecation")
    private int getScreenRotation() {
        WindowManager wm = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
        Display display = wm.getDefaultDisplay();
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.FROYO
        /*
         * Android 2.2
         * has
         * getRotation
         */
        ) {
            try {
                Method m = display.getClass().getDeclaredMethod("getRotation");
                return (Integer) m.invoke(display);
            } catch (Exception e) {
                return Surface.ROTATION_0;
            }
        } else {
            return display.getOrientation();
        }
    }

    @TargetApi(Build.VERSION_CODES.GINGERBREAD)
    private int getScreenOrientation() {
        WindowManager wm = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
        Display display = wm.getDefaultDisplay();
        int rot = getScreenRotation();
        /*
         * Since getRotation() returns the screen's "natural" orientation, which
         * is not guaranteed to be SCREEN_ORIENTATION_PORTRAIT, we have to
         * invert the SCREEN_ORIENTATION value if it is "naturally" landscape.
         */@SuppressWarnings("deprecation")
        boolean defaultWide = display.getWidth() > display.getHeight();
        if (rot == Surface.ROTATION_90 || rot == Surface.ROTATION_270) defaultWide = !defaultWide;
        if (defaultWide) {
            switch (rot) {
                case Surface.ROTATION_0:
                    return ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
                case Surface.ROTATION_90:
                    return ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
                case Surface.ROTATION_180:
                    // SCREEN_ORIENTATION_REVERSE_PORTRAIT only available since API
                    // Level 9+
                    return (Build.VERSION.SDK_INT >= Build.VERSION_CODES.FROYO ? ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE : ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
                case Surface.ROTATION_270:
                    // SCREEN_ORIENTATION_REVERSE_LANDSCAPE only available since API
                    // Level 9+
                    return (Build.VERSION.SDK_INT >= Build.VERSION_CODES.FROYO ? ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT : ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
                default:
                    return 0;
            }
        } else {
            switch (rot) {
                case Surface.ROTATION_0:
                    return ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
                case Surface.ROTATION_90:
                    return ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
                case Surface.ROTATION_180:
                    // SCREEN_ORIENTATION_REVERSE_PORTRAIT only available since API
                    // Level 9+
                    return (Build.VERSION.SDK_INT >= Build.VERSION_CODES.FROYO ? ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT : ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
                case Surface.ROTATION_270:
                    // SCREEN_ORIENTATION_REVERSE_LANDSCAPE only available since API
                    // Level 9+
                    return (Build.VERSION.SDK_INT >= Build.VERSION_CODES.FROYO ? ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE : ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
                default:
                    return 0;
            }
        }
    }

 }

Upvotes: 0

Views: 5091

Answers (1)

gareoke
gareoke

Reputation: 746

When troubleshooting VLC for Android you'll find a lot of helpful information in their forums:

VLC for Android VideoLAN Forums

You are missing two options before initializing mLibVLC. They are:

mLibVLC.setHardwareAcceleration(LibVLC.HW_ACCELERATION_FULL); mLibVLC.eventVideoPlayerActivityCreated(Boolean.TRUE);

Without these, your video will not show up or you'll show a green screen in your SurfaceView. So in the onCreate of your VLC activity, to have video properly show, you can have something like the below (granted your SurfaceView is set to the correct size) :

mSurfaceView = (SurfaceView) findViewById(R.id.player_surface);
mSurfaceHolder = mSurfaceView.getHolder();

mSurfaceFrame = (FrameLayout) findViewById(R.id.player_surface_frame);
mMediaUrl = getIntent().getExtras().getString("videoUrl");

try {
    mLibVLC = LibVLC.getInstance();
    mLibVLC.setAout(mLibVLC.AOUT_AUDIOTRACK);
    mLibVLC.setVout(mLibVLC.VOUT_ANDROID_SURFACE);
    mLibVLC.setHardwareAcceleration(LibVLC.HW_ACCELERATION_FULL);
    mLibVLC.eventVideoPlayerActivityCreated(Boolean.TRUE);

    mLibVLC.init(getApplicationContext());
} catch (LibVlcException e){
    Log.e(TAG, e.toString());
}

mSurfaceHolder.addCallback(mSurfaceCallback);
mSurface = mSurfaceHolder.getSurface();

mLibVLC.attachSurface(mSurface, VideoVLCActivity.this);
mLibVLC.playMRL(mMediaUrl);

Sidenote, anyone can use the following in their build.gradle instead of compling and inc vlc libraries themselves:

compile "de.mrmaffen:vlc-android-sdk:1.0.3"

Upvotes: 2

Related Questions