ennuicastr / libavjs-webcodecs-polyfill

A polyfill for the WebCodecs API. No, really.
82 stars 8 forks source link

RangeError in createImageBitmap #21

Closed jimmyn closed 1 year ago

jimmyn commented 1 year ago

I'm facing issues with some videos in createImageBitmap function. It seems that the frame has more data that can fit into Uint8ClampedArray of the ImageData with the given size.

Uncaught (in promise) RangeError: offset is out of bounds
    at Uint8ClampedArray.set (<anonymous>)
    at rendering.ts:365:24

The error happens here - https://github.com/ennuicastr/libavjs-webcodecs-polyfill/blob/master/src/rendering.ts#L375 It only happens in some videos, not all of them.

You can find the code example to reproduce the issue here - https://github.com/jimmyn/libavjs-webcodecs

I tried to truncate the last chunk of data, it fixes the error, but logically the frame appears corrupted.

I get the frame like this:

{
    "format": "I420",
    "codedWidth": 722,
    "codedHeight": 1280,
    "visibleRect": {
        "x": 0,
        "y": 0,
        "width": 722,
        "height": 1280,
        "top": 0,
        "right": 722,
        "bottom": 1280,
        "left": 0
    },
    "displayWidth": 722,
    "displayHeight": 1280,
    "_nonSquarePixels": false,
    "timestamp": 2413000,
    "_layout": [
        {
            "offset": 0,
            "stride": 722
        },
        {
            "offset": 924160,
            "stride": 361
        },
        {
            "offset": 1155200,
            "stride": 361
        }
    ],
    "_data": null
}

The sum of data of each plane in my example is 3727360, but the frameData.data.length is 722 1280 4 = 3696640

I'd appreciate any help here.

Yahweasel commented 1 year ago

This is a bug I could've sworn I fixed, but apparently I didn't.

The data coming out of libav has a stride length per row that can be different than the actual amount of data in each row, and this is incorrectly conflating the two. This will need correction...

Yahweasel commented 1 year ago

Turns out I fixed it on the input side but not the output side. This should be fixed in 19818ba6a, but I'd appreciate testing.

jimmyn commented 1 year ago

@Yahweasel thanks, I've got the idea, seems it should be image.codedWidth * 4, not just image.codedWidth. It works!