20

UPDATE: Works on Emulator with Android Oreo (8.X). I have the possibility to do changes right to the android sources, so it would also help if someone knews what in the android sources I have to change or update to get this working (so I don't really need an Android 7 workaround for this. An update to Android 8 though is not possible.)

I'm having a SurfaceView inside a FrameLayout. The SurfaceView usually displays a video, for example purposes I'm actually drawing an image. The problem is, if I'm setting the size of the FrameLayout (or the SurfaceView) above 10.000 pixels in width, it gets cropped on the left side.

Tested on Android 7.1.1 (on a device and Emulator: Android TV (1080p) API 25

public class TestActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        //add surfaceview
        TestSurfaceView testSurfaceView = new TestSurfaceView(this);
        setContentView(testSurfaceView);

        //resize
        FrameLayout.LayoutParams bgParams = (FrameLayout.LayoutParams) testSurfaceView.getLayoutParams();

        //testcase full hd - working
        bgParams.width = 1920;

        //testcase 2 - working - each segment is 330px as 9900 / 1920 * 64 (default segment width) == 330
        //bgParams.width = 9900;

        //testcase 3 - working
        //bgParams.width = 10000;

        //testcase 4 - not working - each segment is 335px which is correct but first cell gets cropped by exactly 50px to the left
        //bgParams.width = 10050;

        bgParams.height = (int)Math.floor(bgParams.width * (9d/16d)); //16:9

        testSurfaceView.setX(0); //doesnt help

        /*
         Also the position counts into the 10000px limitation as you can see on following testcases
         */
        /*
        bgParams.width = 9900;
        bgParams.height = (int)Math.floor(bgParams.width * (9d/16d)); //16:9

        //works - as 9900 + 90 < 10000
        testSurfaceView.setX(90);

        //doesnt work, crops 50px to the left - 9900 + 150 -> 10050
        testSurfaceView.setX(150);
        */
    }
}

public class TestSurfaceView extends SurfaceView implements SurfaceHolder.Callback
{

public TestSurfaceView(TestActivity context) {
    super(context);

    SurfaceHolder holder = this.getHolder();
    holder.addCallback(this);
}

    @Override
    public void surfaceCreated(SurfaceHolder surfaceHolder)
    {
        //load bitmap from file
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inPreferredConfig = Bitmap.Config.ARGB_8888;
        Bitmap bitmap = BitmapFactory.decodeFile(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).getAbsolutePath() + "/testimg.png", options);

        Canvas c = surfaceHolder.lockCanvas();
        Rect rect = new Rect();
        rect.set(0,0, 1920, 1080); //image size

        Rect destRect = new Rect();
        destRect.set(0, 0, this.getWidth(), this.getHeight());

        //draw the image on the surface
        c.drawBitmap(bitmap, rect, destRect, null);
        surfaceHolder.unlockCanvasAndPost(c);
    }

@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {

}

@Override
public void surfaceDestroyed(SurfaceHolder holder) {

}
}

styles.xml - for the theme

<resources>

    <!-- Base application theme. -->
    <style name="AppTheme" parent="android:Theme.Material.Light.NoActionBar.Fullscreen">
        <!-- Customize your theme here. -->
    </style>

</resources>

The code above produces following output, which is correct.

1920px Test If I change the bgParams.width to 9600 - it scales up correctly and still displays starting from the left edge of the image:

9600px Test

But if I change the code to e.g. 10050, the image gets cropped by 50 pixels to the left.

10050px test

If I set:

destRect.set(50, 0, this.getWidth(), this.getHeight());

10050px test with pos 50px of image It gets displayed correctly, but as I can't do that for the MediaPlayer and it's super weird, I'm trying to find a good solution.

I also tried setting the sizes directly on the SurfaceView and instead of changing the LayoutParams, I tried setting scaleX and scaleY of the Framelayout but ended up with the same results.

(btw. opengl max texture size is about 16000px - setting it above the ~16000px results in a black screen and an exception, so that is not the cause of the problem)

Update: Posted all sources. Anyway here is the complete android studio project: WeTransfer project download link

Daniel Z.
  • 2,988
  • 2
  • 19
  • 23
  • Removing the FrameLayout backgroundFrame and setting the SurfaceView as the contentview didnt solve the problem. Setting a simple ImageView as content and stretching that one > 10000 in width works, though. – Daniel Z. Jan 08 '19 at 15:38
  • Can you post your test project (including the picture you use) so I can try to reproduce the problem without copy-pasting all the stuff? – Divers Jan 09 '19 at 16:00
  • @Divers added the source files to the end of my post. The image (for others) is the first one in my post. In the source files the image is in the res folder res/raw/testimg.png. Also the SurfaceView code changed a bit to load the img from resource and not the file system – Daniel Z. Jan 10 '19 at 07:29
  • Replace FrameLayout with some other layout like RelativeLayout or LinearLayout. This should fix the problem. – Rishabh Sagar Mar 08 '19 at 12:22
  • @RishabhSagar Hey, tried both - both end up with the same result. Left-side cut off – Daniel Z. Mar 08 '19 at 12:54
  • @DanielZiegler I would like to see the source code, can you add it again? – Rishabh Sagar Mar 08 '19 at 13:28
  • @RishabhSagar Here is the source code: https://wetransfer.com/downloads/eb3cb8a4dd26617f9ee87bd6177dbd0a20190311072030/c0c7a7 – Daniel Z. Mar 11 '19 at 07:21
  • @DanielZiegler, Thanks. – Rishabh Sagar Mar 11 '19 at 08:33
  • If the problem only occurs for a width > 10000 shouldn't this workaround do the trick? destRect.set(((this.getWidth()>10000) ? this.getWidth() - 10000 : 0), 0, this.getWidth(), this.getHeight); – Giorgio Bertolotti Mar 12 '19 at 16:46
  • @GiorgioBertolotti Ive done this (see my question above). Problem with this is that I cant do that for the mediaplayer element. Thanks anyway :)! – Daniel Z. Mar 13 '19 at 06:50
  • Ah sorry I forgot that detail, I'll try to think something later :) – Giorgio Bertolotti Mar 13 '19 at 07:06
  • fwiw I fired up the demo app on a couple of emulators: Android TV 1080p API 25 and others, but I was unable to get any display above a width of 8192. At 8193, I see "E/Layer: dimensions too large 8193 x 4608" followed by "E/SurfaceFlinger: createNormalLayer() failed (Invalid argument)" in logcat (Android 7.1.1). A width of 8192 shows what you expect. This issue may be something peculiar to your environment. – Cheticamp Mar 14 '19 at 11:57
  • Technically speaking, what screen resolution can support 10000 pixels? – Alex.F Mar 15 '19 at 07:56
  • @Alex.F Not one screen - but put some side by side and you get the >10000pxs. Ofc there are other options like splitting the video into multiple parts but we'd prefer the one-video-scaling way. – Daniel Z. Mar 18 '19 at 06:36
  • @Cheticamp So it was totally black? Thats super weird. Never had that problems - even on the real-device running android x86 (tested with different full-hd screens). It just behaves the same as in the emulator. Only had problems with thing goes black above ~16.000px. Maybe your opengl max texture size is somehow lower? – Daniel Z. Mar 18 '19 at 07:21
  • @DanielZiegler Yes, totally black at 8193 and above with the noted error. – Cheticamp Mar 18 '19 at 10:47
  • @Cheticamp Think your opengl max texture size is just lower. If you still want to recreate the problem I could do the resizing with scaling and add the code. This 'bypasses' the opengl limitation but also fails > 10.000px – Daniel Z. Mar 19 '19 at 08:46
  • I'd be curious but don't think I am going to be able to identify the problem or a work-around. Someone may find it useful. – Cheticamp Mar 19 '19 at 11:53

0 Answers0