Add more check of H264 slice param to avoid GPU hang caused by the incorrect parameter
authorZhao Yakui <yakui.zhao@intel.com>
Wed, 23 Jul 2014 05:46:17 +0000 (13:46 +0800)
committerZhao, Yakui <yakui.zhao@intel.com>
Wed, 23 Jul 2014 07:58:45 +0000 (15:58 +0800)
This is to fix the GPU hang in https://bugs.freedesktop.org/show_bug.cgi?id=76363

V1->V2: Use the new check based on Haihao's comment. Discard the current frame with the error
slice_param instead of smart fix. In such case it can prompt that the error slice_param
can be fixed by the upper-middle.

Signed-off-by: Zhao Yakui <yakui.zhao@intel.com>
Tested-by: ValdikSS <iam@valdikss.org.ru>
Reviewed-by: Xiang Haihao <haihao.xiang@intel.com>
(cherry picked from commit 04202281135149a13a32dfb8a902debfac1331fe)

src/i965_decoder_utils.c

index 0539e08..546285e 100644 (file)
@@ -754,6 +754,8 @@ intel_decoder_check_avc_parameter(VADriverContextP ctx,
     VAStatus va_status;
     struct object_surface *obj_surface;        
     int i;
+    VASliceParameterBufferH264 *slice_param, *next_slice_param, *next_slice_group_param;
+    int j;
 
     assert(!(pic_param->CurrPic.flags & VA_PICTURE_H264_INVALID));
     assert(pic_param->CurrPic.picture_id != VA_INVALID_SURFACE);
@@ -802,6 +804,37 @@ intel_decoder_check_avc_parameter(VADriverContextP ctx,
         }
         decode_state->reference_objects[i] = obj_surface;
     }
+
+    for (j = 0; j < decode_state->num_slice_params; j++) {
+        assert(decode_state->slice_params && decode_state->slice_params[j]->buffer);
+        slice_param = (VASliceParameterBufferH264 *)decode_state->slice_params[j]->buffer;
+
+        if (j == decode_state->num_slice_params - 1)
+            next_slice_group_param = NULL;
+        else
+            next_slice_group_param = (VASliceParameterBufferH264 *)decode_state->slice_params[j + 1]->buffer;
+
+        for (i = 0; i < decode_state->slice_params[j]->num_elements; i++) {
+
+            if (i < decode_state->slice_params[j]->num_elements - 1)
+                next_slice_param = slice_param + 1;
+            else
+                next_slice_param = next_slice_group_param;
+
+            if (next_slice_param != NULL) {
+                /* If the mb position of next_slice is less than or equal to the current slice,
+                 * discard the current frame.
+                 */
+                if (next_slice_param->first_mb_in_slice <= slice_param->first_mb_in_slice) {
+                    next_slice_param = NULL;
+                    WARN_ONCE("!!!incorrect slice_param. The first_mb_in_slice of next_slice is less"
+                               " than or equal to that in current slice\n");
+                    goto error;
+                }
+            }
+        }
+    }
+
     return VA_STATUS_SUCCESS;
 
 error: