/* * Copyright (C) 2007 Intel Corporation * Copyright (C) 2016 Florent Revest * Copyright (C) 2018 Paul Kocialkowski * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sub license, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice (including the * next paragraph) shall be included in all copies or substantial portions * of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. * IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "context.h" #include "config.h" #include "request.h" #include "surface.h" #include #include #include #include #include #include #include #include "utils.h" #include "v4l2.h" #include "autoconfig.h" VAStatus RequestCreateContext(VADriverContextP context, VAConfigID config_id, int picture_width, int picture_height, int flags, VASurfaceID *surfaces_ids, int surfaces_count, VAContextID *context_id) { struct request_data *driver_data = context->pDriverData; struct object_config *config_object; struct object_context *context_object = NULL; struct video_format *video_format; VASurfaceID *ids = NULL; VAContextID id; VAStatus status; unsigned int output_type, capture_type; int rc; video_format = driver_data->video_format; if (video_format == NULL) return VA_STATUS_ERROR_OPERATION_FAILED; output_type = v4l2_type_video_output(video_format->v4l2_mplane); capture_type = v4l2_type_video_capture(video_format->v4l2_mplane); config_object = CONFIG(driver_data, config_id); if (config_object == NULL) { status = VA_STATUS_ERROR_INVALID_CONFIG; goto error; } id = object_heap_allocate(&driver_data->context_heap); context_object = CONTEXT(driver_data, id); if (context_object == NULL) { status = VA_STATUS_ERROR_ALLOCATION_FAILED; goto error; } memset(&context_object->dpb, 0, sizeof(context_object->dpb)); /* * Initialize the OUTPUT (bitstream-input) buffer pool. Sized by * codec pipeline depth (4 H.264 frames in flight is sufficient * for current hantro/rkvdec scheduling); independent of caller- * supplied surfaces_count. Pool is owned by driver_data so it * outlives any single context destroy/recreate cycle. * * This replaces the prior per-surface OUTPUT loop, which (a) * created an empty queue when surfaces_count==0 (ffmpeg vaapi- * copy path) and (b) only populated surface->source_* for * surfaces present at vaCreateContext time, NULL-derefing on * surfaces created later. */ /* * iter6: pool size 16 gives comfortable headroom over typical H.264 * MaxDpbFrames (16) for any consumer that pipelines decode requests. * Each slot owns its own request_fd (REINIT'd per use). */ rc = request_pool_init(&driver_data->output_pool, driver_data->video_fd, driver_data->media_fd, output_type, 16); if (rc < 0) { status = VA_STATUS_ERROR_ALLOCATION_FAILED; goto error; } /* * The surface_ids array has been allocated by the caller and * we don't have any indication wrt its life time. Let's make sure * its life span is under our control. */ if (surfaces_count > 0) { ids = malloc(surfaces_count * sizeof(VASurfaceID)); if (ids == NULL) { status = VA_STATUS_ERROR_ALLOCATION_FAILED; goto error; } memcpy(ids, surfaces_ids, surfaces_count * sizeof(VASurfaceID)); } /* * Stateless H.264 device-wide controls. The kernel V4L2 stateless * framework requires DECODE_MODE and START_CODE be set on the * device fd (request_fd=-1) before VIDIOC_STREAMON; per-request * controls (SPS/PPS/etc.) attached to a request_fd come later. * * hantro-vpu via rockchip,rk3568-vpu DT compatible (covers RK3568 * and RK3566 — PineTab2 silicon — since they're close enough) * accepts only DECODE_MODE_FRAME_BASED. * START_CODE_ANNEX_B preserves leading 0x00000001 in the slice * payload that h264.c assembles. Errors here are not fatal: not * every backing driver supports both controls (e.g. cedrus may * default to SLICE_BASED without exposing DECODE_MODE). */ { struct v4l2_ext_control dev_ctrls[2] = { { .id = V4L2_CID_STATELESS_H264_DECODE_MODE, .value = V4L2_STATELESS_H264_DECODE_MODE_FRAME_BASED, }, { .id = V4L2_CID_STATELESS_H264_START_CODE, .value = V4L2_STATELESS_H264_START_CODE_ANNEX_B, }, }; (void)v4l2_set_controls(driver_data->video_fd, -1, dev_ctrls, 2); } /* * Mirror the ANNEX_B start-code mode set on the device above * into context_object->h264_start_code so picture.c:: * codec_store_buffer prepends 0x00 0x00 0x01 to each slice * payload it copies into the OUTPUT buffer. Without this, the * kernel — which we just told to expect ANNEX_B — sees a raw * NAL stream with no start codes, fails to find slice * boundaries, and emits a zeroed CAPTURE buffer (visually a * flat dark-green frame). * * h264_get_controls() exists for this purpose but is never * called in the current code path; the planned probe-then-set * commit will replace this hardcoded assignment with a runtime * read of the kernel's accepted START_CODE value. */ context_object->h264_start_code = true; rc = v4l2_set_stream(driver_data->video_fd, output_type, true); if (rc < 0) { status = VA_STATUS_ERROR_OPERATION_FAILED; goto error; } rc = v4l2_set_stream(driver_data->video_fd, capture_type, true); if (rc < 0) { status = VA_STATUS_ERROR_OPERATION_FAILED; goto error; } context_object->config_id = config_id; context_object->render_surface_id = VA_INVALID_ID; context_object->surfaces_ids = ids; context_object->surfaces_count = surfaces_count; context_object->picture_width = picture_width; context_object->picture_height = picture_height; context_object->flags = flags; *context_id = id; status = VA_STATUS_SUCCESS; goto complete; error: if (ids != NULL) free(ids); if (context_object != NULL) object_heap_free(&driver_data->context_heap, (struct object_base *)context_object); complete: return status; } VAStatus RequestDestroyContext(VADriverContextP context, VAContextID context_id) { struct request_data *driver_data = context->pDriverData; struct object_context *context_object; struct video_format *video_format; unsigned int output_type, capture_type; VAStatus status; int rc; video_format = driver_data->video_format; if (video_format == NULL) return VA_STATUS_ERROR_OPERATION_FAILED; output_type = v4l2_type_video_output(video_format->v4l2_mplane); capture_type = v4l2_type_video_capture(video_format->v4l2_mplane); context_object = CONTEXT(driver_data, context_id); if (context_object == NULL) return VA_STATUS_ERROR_INVALID_CONTEXT; rc = v4l2_set_stream(driver_data->video_fd, output_type, false); if (rc < 0) return VA_STATUS_ERROR_OPERATION_FAILED; rc = v4l2_set_stream(driver_data->video_fd, capture_type, false); if (rc < 0) return VA_STATUS_ERROR_OPERATION_FAILED; /* Buffers liberation */ status = RequestDestroySurfaces(context, context_object->surfaces_ids, context_object->surfaces_count); if (status != VA_STATUS_SUCCESS) return VA_STATUS_ERROR_OPERATION_FAILED; free(context_object->surfaces_ids); object_heap_free(&driver_data->context_heap, (struct object_base *)context_object); rc = v4l2_request_buffers(driver_data->video_fd, output_type, 0); if (rc < 0) return VA_STATUS_ERROR_OPERATION_FAILED; /* * Iter2 Fix 3: cap_pool owns the CAPTURE buffers' mmaps + any * outstanding our_export_fds. Tear it down (which also issues * REQBUFS(0) on CAPTURE), so the next CreateSurfaces2 cycle sees * a clean slate and rebuilds the pool at the new resolution. */ cap_pool_destroy(&driver_data->capture_pool, driver_data->video_fd, capture_type); /* * Iteration 2 Fix 1: the kernel CAPTURE format state is no longer * guaranteed after the dual REQBUFS(0). Invalidate the * LAST_OUTPUT_WIDTH/HEIGHT cache so the next CreateSurfaces2 will * unconditionally re-S_FMT on OUTPUT. Without this, multi-video * Firefox sessions on mozilla.org corrupted the next session's * CAPTURE format query (kernel returned 48x48 instead of the * cached "already 1920x1088"); the exported descriptor encoded * wrong pitch/offset. */ surface_reset_format_cache(driver_data); return VA_STATUS_SUCCESS; }