mpeg2decoder: Fix multiplication wraparound

The GstMpeg2Picture system_frame_number is guint32, constant 1000 is guint32,
GstV4l2CodecMpeg2Dec *_ref_ts multiplication result is u64 .

```
u64 result = (u32)((u32)system_frame_number * (u32)1000);
```
behaves the same as
```
u64 result = (u32)(((u32)system_frame_number * (u32)1000) & 0xffffffff);
```

so in case `system_frame_number > 4294967295 / 1000`, the `result` will
wrap around. Since the `result` is really used as a cookie used to look
up V4L2 buffers related to the currently decoded frame, this wraparound
leads to visible corruption during MPEG2 decoding. At 30 FPS this occurs
after cca. 40 hours of playback .

Fix this by changing the 1000 from u32 to u64, i.e.:
```
u64 result = (u64)((u32)system_frame_number * (u64)1000ULL);
```
this way, the wraparound is prevented and the correct cookie is used.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/5850>
This commit is contained in:
Marek Vasut 2023-12-09 16:26:22 +01:00
parent 763bf9fe62
commit 2122cf512a

View file

@ -577,8 +577,8 @@ gst_v4l2_codec_mpeg2_dec_start_picture (GstMpeg2Decoder * decoder,
/* *INDENT-OFF* */
self->v4l2_picture = (struct v4l2_ctrl_mpeg2_picture) {
.backward_ref_ts = next_picture ? next_picture->system_frame_number * 1000 : GST_CLOCK_TIME_NONE,
.forward_ref_ts = prev_picture ? prev_picture->system_frame_number * 1000 : GST_CLOCK_TIME_NONE,
.backward_ref_ts = next_picture ? next_picture->system_frame_number * G_GUINT64_CONSTANT (1000) : GST_CLOCK_TIME_NONE,
.forward_ref_ts = prev_picture ? prev_picture->system_frame_number * G_GUINT64_CONSTANT (1000) : GST_CLOCK_TIME_NONE,
.intra_dc_precision = slice->pic_ext ? slice->pic_ext->intra_dc_precision : 0,
.flags = (slice->pic_ext && slice->pic_ext->top_field_first ? V4L2_MPEG2_PIC_FLAG_TOP_FIELD_FIRST : 0) |
(slice->pic_ext && slice->pic_ext->frame_pred_frame_dct ? V4L2_MPEG2_PIC_FLAG_FRAME_PRED_DCT : 0 ) |