Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

media: vicodec: Add support for stateless decoder.

Implement a stateless decoder for the new node.

Signed-off-by: Dafna Hirschfeld <dafna3@gmail.com>
Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
[hverkuil-cisco@xs4all.nl: add 'return 0;' before default case in vicodec_try_ctrl()]
Signed-off-by: Mauro Carvalho Chehab <mchehab+samsung@kernel.org>

authored by

Dafna Hirschfeld and committed by
Mauro Carvalho Chehab
997deb81 fde649b4

+264 -24
+1
drivers/media/platform/vicodec/codec-v4l2-fwht.h
··· 44 44 struct fwht_raw_frame ref_frame; 45 45 struct fwht_cframe_hdr header; 46 46 u8 *compressed_frame; 47 + u64 ref_frame_ts; 47 48 }; 48 49 49 50 const struct v4l2_fwht_pixfmt_info *v4l2_fwht_find_pixfmt(u32 pixelformat);
+263 -24
drivers/media/platform/vicodec/vicodec-core.c
··· 213 213 return true; 214 214 } 215 215 216 + static bool validate_stateless_params_flags(const struct v4l2_ctrl_fwht_params *params, 217 + const struct v4l2_fwht_pixfmt_info *cur_info) 218 + { 219 + unsigned int width_div = 220 + (params->flags & FWHT_FL_CHROMA_FULL_WIDTH) ? 1 : 2; 221 + unsigned int height_div = 222 + (params->flags & FWHT_FL_CHROMA_FULL_HEIGHT) ? 1 : 2; 223 + unsigned int components_num = 3; 224 + unsigned int pixenc = 0; 225 + 226 + if (params->version < 3) 227 + return false; 228 + 229 + components_num = 1 + ((params->flags & FWHT_FL_COMPONENTS_NUM_MSK) >> 230 + FWHT_FL_COMPONENTS_NUM_OFFSET); 231 + pixenc = (params->flags & FWHT_FL_PIXENC_MSK); 232 + if (v4l2_fwht_validate_fmt(cur_info, width_div, height_div, 233 + components_num, pixenc)) 234 + return true; 235 + return false; 236 + } 237 + 238 + 239 + static void update_state_from_header(struct vicodec_ctx *ctx) 240 + { 241 + const struct fwht_cframe_hdr *p_hdr = &ctx->state.header; 242 + 243 + ctx->state.visible_width = ntohl(p_hdr->width); 244 + ctx->state.visible_height = ntohl(p_hdr->height); 245 + ctx->state.colorspace = ntohl(p_hdr->colorspace); 246 + ctx->state.xfer_func = ntohl(p_hdr->xfer_func); 247 + ctx->state.ycbcr_enc = ntohl(p_hdr->ycbcr_enc); 248 + ctx->state.quantization = ntohl(p_hdr->quantization); 249 + } 250 + 216 251 static int device_process(struct vicodec_ctx *ctx, 217 252 struct vb2_v4l2_buffer *src_vb, 218 253 struct vb2_v4l2_buffer *dst_vb) ··· 255 220 struct vicodec_dev *dev = ctx->dev; 256 221 struct v4l2_fwht_state *state = &ctx->state; 257 222 u8 *p_src, *p_dst; 258 - int ret; 223 + int ret = 0; 259 224 260 - if (ctx->is_enc) 225 + if (ctx->is_enc || ctx->is_stateless) 261 226 p_src = vb2_plane_vaddr(&src_vb->vb2_buf, 0); 262 227 else 263 228 p_src = state->compressed_frame; 229 + 230 + if (ctx->is_stateless) { 231 + struct media_request *src_req = src_vb->vb2_buf.req_obj.req; 232 + 233 + ret = v4l2_ctrl_request_setup(src_req, &ctx->hdl); 234 + if (ret) 235 + return ret; 236 + update_state_from_header(ctx); 237 + 238 + ctx->state.header.size = 239 + htonl(vb2_get_plane_payload(&src_vb->vb2_buf, 0)); 240 + /* 241 + * set the reference buffer from the reference timestamp 242 + * only if this is a P-frame 243 + */ 244 + if (!(ntohl(ctx->state.header.flags) & FWHT_FL_I_FRAME)) { 245 + struct vb2_buffer *ref_vb2_buf; 246 + int ref_buf_idx; 247 + struct vb2_queue *vq_cap = 248 + v4l2_m2m_get_vq(ctx->fh.m2m_ctx, 249 + V4L2_BUF_TYPE_VIDEO_CAPTURE); 250 + 251 + ref_buf_idx = vb2_find_timestamp(vq_cap, 252 + ctx->state.ref_frame_ts, 0); 253 + if (ref_buf_idx < 0) 254 + return -EINVAL; 255 + 256 + ref_vb2_buf = vq_cap->bufs[ref_buf_idx]; 257 + if (ref_vb2_buf->state == VB2_BUF_STATE_ERROR) 258 + ret = -EINVAL; 259 + ctx->state.ref_frame.buf = 260 + vb2_plane_vaddr(ref_vb2_buf, 0); 261 + } else { 262 + ctx->state.ref_frame.buf = NULL; 263 + } 264 + } 264 265 p_dst = vb2_plane_vaddr(&dst_vb->vb2_buf, 0); 265 266 if (!p_src || !p_dst) { 266 267 v4l2_err(&dev->v4l2_dev, ··· 325 254 ret = v4l2_fwht_decode(state, p_src, p_dst); 326 255 if (ret < 0) 327 256 return ret; 328 - copy_cap_to_ref(p_dst, ctx->state.info, &ctx->state); 257 + if (!ctx->is_stateless) 258 + copy_cap_to_ref(p_dst, ctx->state.info, &ctx->state); 329 259 330 260 vb2_set_plane_payload(&dst_vb->vb2_buf, 0, q_dst->sizeimage); 331 261 } 332 - return 0; 262 + return ret; 333 263 } 334 264 335 265 /* ··· 405 333 struct vb2_v4l2_buffer *src_buf, *dst_buf; 406 334 struct vicodec_q_data *q_src, *q_dst; 407 335 u32 state; 336 + struct media_request *src_req; 337 + 408 338 409 339 src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); 410 340 dst_buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); 341 + src_req = src_buf->vb2_buf.req_obj.req; 342 + 411 343 q_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); 412 344 q_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); 413 345 ··· 430 354 dst_buf->flags |= V4L2_BUF_FLAG_LAST; 431 355 v4l2_event_queue_fh(&ctx->fh, &eos_event); 432 356 } 433 - if (ctx->is_enc) { 357 + if (ctx->is_enc || ctx->is_stateless) { 434 358 src_buf->sequence = q_src->sequence++; 435 359 src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); 436 360 v4l2_m2m_buf_done(src_buf, state); ··· 442 366 ctx->comp_has_next_frame = false; 443 367 } 444 368 v4l2_m2m_buf_done(dst_buf, state); 369 + if (ctx->is_stateless && src_req) 370 + v4l2_ctrl_request_complete(src_req, &ctx->hdl); 371 + 445 372 ctx->comp_size = 0; 446 373 ctx->header_size = 0; 447 374 ctx->comp_magic_cnt = 0; ··· 523 444 unsigned int hdr_width_div = (flags & FWHT_FL_CHROMA_FULL_WIDTH) ? 1 : 2; 524 445 unsigned int hdr_height_div = (flags & FWHT_FL_CHROMA_FULL_HEIGHT) ? 1 : 2; 525 446 447 + /* 448 + * This function should not be used by a stateless codec since 449 + * it changes values in q_data that are not request specific 450 + */ 451 + WARN_ON(ctx->is_stateless); 452 + 526 453 q_dst->info = info; 527 454 q_dst->visible_width = ntohl(p_hdr->width); 528 455 q_dst->visible_height = ntohl(p_hdr->height); ··· 581 496 582 497 if (ctx->source_changed) 583 498 return 0; 584 - if (ctx->is_enc || ctx->comp_has_frame) 499 + if (ctx->is_stateless || ctx->is_enc || ctx->comp_has_frame) 585 500 return 1; 586 501 587 502 restart: ··· 1339 1254 return 0; 1340 1255 } 1341 1256 1257 + static int vicodec_buf_out_validate(struct vb2_buffer *vb) 1258 + { 1259 + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); 1260 + 1261 + vbuf->field = V4L2_FIELD_NONE; 1262 + return 0; 1263 + } 1264 + 1342 1265 static int vicodec_buf_prepare(struct vb2_buffer *vb) 1343 1266 { 1344 1267 struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); ··· 1410 1317 } 1411 1318 1412 1319 /* 1413 - * source change event is relevant only for the decoder 1320 + * source change event is relevant only for the stateful decoder 1414 1321 * in the compressed stream 1415 1322 */ 1416 - if (ctx->is_enc || !V4L2_TYPE_IS_OUTPUT(vb->vb2_queue->type)) { 1323 + if (ctx->is_stateless || ctx->is_enc || 1324 + !V4L2_TYPE_IS_OUTPUT(vb->vb2_queue->type)) { 1417 1325 v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf); 1418 1326 return; 1419 1327 } ··· 1462 1368 vbuf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); 1463 1369 if (vbuf == NULL) 1464 1370 return; 1371 + v4l2_ctrl_request_complete(vbuf->vb2_buf.req_obj.req, 1372 + &ctx->hdl); 1465 1373 spin_lock(ctx->lock); 1466 1374 v4l2_m2m_buf_done(vbuf, state); 1467 1375 spin_unlock(ctx->lock); 1468 1376 } 1377 + } 1378 + 1379 + static unsigned int total_frame_size(struct vicodec_q_data *q_data) 1380 + { 1381 + unsigned int size; 1382 + unsigned int chroma_div; 1383 + 1384 + if (!q_data->info) { 1385 + WARN_ON(1); 1386 + return 0; 1387 + } 1388 + size = q_data->coded_width * q_data->coded_height; 1389 + chroma_div = q_data->info->width_div * q_data->info->height_div; 1390 + 1391 + if (q_data->info->components_num == 4) 1392 + return 2 * size + 2 * (size / chroma_div); 1393 + else if (q_data->info->components_num == 3) 1394 + return size + 2 * (size / chroma_div); 1395 + return size; 1469 1396 } 1470 1397 1471 1398 static int vicodec_start_streaming(struct vb2_queue *q, ··· 1499 1384 unsigned int size = q_data->coded_width * q_data->coded_height; 1500 1385 unsigned int chroma_div; 1501 1386 unsigned int total_planes_size; 1502 - u8 *new_comp_frame; 1387 + u8 *new_comp_frame = NULL; 1503 1388 1504 1389 if (!info) 1505 1390 return -EINVAL; ··· 1522 1407 vicodec_return_bufs(q, VB2_BUF_STATE_QUEUED); 1523 1408 return -EINVAL; 1524 1409 } 1525 - if (info->components_num == 4) 1526 - total_planes_size = 2 * size + 2 * (size / chroma_div); 1527 - else if (info->components_num == 3) 1528 - total_planes_size = size + 2 * (size / chroma_div); 1529 - else 1530 - total_planes_size = size; 1410 + total_planes_size = total_frame_size(q_data); 1411 + ctx->comp_max_size = total_planes_size; 1531 1412 1532 1413 state->visible_width = q_data->visible_width; 1533 1414 state->visible_height = q_data->visible_height; ··· 1532 1421 state->stride = q_data->coded_width * 1533 1422 info->bytesperline_mult; 1534 1423 1424 + if (ctx->is_stateless) { 1425 + state->ref_stride = state->stride; 1426 + return 0; 1427 + } 1535 1428 state->ref_stride = q_data->coded_width * info->luma_alpha_step; 1429 + 1536 1430 state->ref_frame.buf = kvmalloc(total_planes_size, GFP_KERNEL); 1537 1431 state->ref_frame.luma = state->ref_frame.buf; 1538 - ctx->comp_max_size = total_planes_size; 1539 1432 new_comp_frame = kvmalloc(ctx->comp_max_size, GFP_KERNEL); 1540 1433 1541 1434 if (!state->ref_frame.luma || !new_comp_frame) { ··· 1587 1472 1588 1473 if ((!V4L2_TYPE_IS_OUTPUT(q->type) && !ctx->is_enc) || 1589 1474 (V4L2_TYPE_IS_OUTPUT(q->type) && ctx->is_enc)) { 1590 - kvfree(ctx->state.ref_frame.buf); 1475 + if (!ctx->is_stateless) 1476 + kvfree(ctx->state.ref_frame.buf); 1591 1477 ctx->state.ref_frame.buf = NULL; 1592 1478 ctx->state.ref_frame.luma = NULL; 1593 1479 ctx->comp_max_size = 0; ··· 1604 1488 } 1605 1489 } 1606 1490 1491 + static void vicodec_buf_request_complete(struct vb2_buffer *vb) 1492 + { 1493 + struct vicodec_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); 1494 + 1495 + v4l2_ctrl_request_complete(vb->req_obj.req, &ctx->hdl); 1496 + } 1497 + 1498 + 1607 1499 static const struct vb2_ops vicodec_qops = { 1608 - .queue_setup = vicodec_queue_setup, 1609 - .buf_prepare = vicodec_buf_prepare, 1610 - .buf_queue = vicodec_buf_queue, 1611 - .start_streaming = vicodec_start_streaming, 1612 - .stop_streaming = vicodec_stop_streaming, 1613 - .wait_prepare = vb2_ops_wait_prepare, 1614 - .wait_finish = vb2_ops_wait_finish, 1500 + .queue_setup = vicodec_queue_setup, 1501 + .buf_out_validate = vicodec_buf_out_validate, 1502 + .buf_prepare = vicodec_buf_prepare, 1503 + .buf_queue = vicodec_buf_queue, 1504 + .buf_request_complete = vicodec_buf_request_complete, 1505 + .start_streaming = vicodec_start_streaming, 1506 + .stop_streaming = vicodec_stop_streaming, 1507 + .wait_prepare = vb2_ops_wait_prepare, 1508 + .wait_finish = vb2_ops_wait_finish, 1615 1509 }; 1616 1510 1617 1511 static int queue_init(void *priv, struct vb2_queue *src_vq, ··· 1665 1539 return vb2_queue_init(dst_vq); 1666 1540 } 1667 1541 1542 + static int vicodec_try_ctrl(struct v4l2_ctrl *ctrl) 1543 + { 1544 + struct vicodec_ctx *ctx = container_of(ctrl->handler, 1545 + struct vicodec_ctx, hdl); 1546 + const struct v4l2_ctrl_fwht_params *params; 1547 + struct vicodec_q_data *q_dst = get_q_data(ctx, 1548 + V4L2_BUF_TYPE_VIDEO_CAPTURE); 1549 + 1550 + switch (ctrl->id) { 1551 + case V4L2_CID_MPEG_VIDEO_FWHT_PARAMS: 1552 + if (!q_dst->info) 1553 + return -EINVAL; 1554 + params = ctrl->p_new.p_fwht_params; 1555 + if (params->width > q_dst->coded_width || 1556 + params->width < MIN_WIDTH || 1557 + params->height > q_dst->coded_height || 1558 + params->height < MIN_HEIGHT) 1559 + return -EINVAL; 1560 + if (!validate_by_version(params->flags, params->version)) 1561 + return -EINVAL; 1562 + if (!validate_stateless_params_flags(params, q_dst->info)) 1563 + return -EINVAL; 1564 + return 0; 1565 + default: 1566 + return 0; 1567 + } 1568 + return 0; 1569 + } 1570 + 1571 + static void update_header_from_stateless_params(struct vicodec_ctx *ctx, 1572 + const struct v4l2_ctrl_fwht_params *params) 1573 + { 1574 + struct fwht_cframe_hdr *p_hdr = &ctx->state.header; 1575 + 1576 + p_hdr->magic1 = FWHT_MAGIC1; 1577 + p_hdr->magic2 = FWHT_MAGIC2; 1578 + p_hdr->version = htonl(params->version); 1579 + p_hdr->width = htonl(params->width); 1580 + p_hdr->height = htonl(params->height); 1581 + p_hdr->flags = htonl(params->flags); 1582 + p_hdr->colorspace = htonl(params->colorspace); 1583 + p_hdr->xfer_func = htonl(params->xfer_func); 1584 + p_hdr->ycbcr_enc = htonl(params->ycbcr_enc); 1585 + p_hdr->quantization = htonl(params->quantization); 1586 + } 1587 + 1668 1588 static int vicodec_s_ctrl(struct v4l2_ctrl *ctrl) 1669 1589 { 1670 1590 struct vicodec_ctx *ctx = container_of(ctrl->handler, 1671 1591 struct vicodec_ctx, hdl); 1592 + const struct v4l2_ctrl_fwht_params *params; 1672 1593 1673 1594 switch (ctrl->id) { 1674 1595 case V4L2_CID_MPEG_VIDEO_GOP_SIZE: ··· 1727 1554 case V4L2_CID_FWHT_P_FRAME_QP: 1728 1555 ctx->state.p_frame_qp = ctrl->val; 1729 1556 return 0; 1557 + case V4L2_CID_MPEG_VIDEO_FWHT_PARAMS: 1558 + params = ctrl->p_new.p_fwht_params; 1559 + update_header_from_stateless_params(ctx, params); 1560 + ctx->state.ref_frame_ts = params->backward_ref_ts; 1561 + return 0; 1730 1562 } 1731 1563 return -EINVAL; 1732 1564 } 1733 1565 1734 1566 static const struct v4l2_ctrl_ops vicodec_ctrl_ops = { 1735 1567 .s_ctrl = vicodec_s_ctrl, 1568 + .try_ctrl = vicodec_try_ctrl, 1736 1569 }; 1737 1570 1738 1571 static const struct v4l2_ctrl_config vicodec_ctrl_stateless_state = { 1572 + .ops = &vicodec_ctrl_ops, 1739 1573 .id = V4L2_CID_MPEG_VIDEO_FWHT_PARAMS, 1740 1574 .elem_size = sizeof(struct v4l2_ctrl_fwht_params), 1741 1575 }; ··· 1867 1687 return 0; 1868 1688 } 1869 1689 1690 + static int vicodec_request_validate(struct media_request *req) 1691 + { 1692 + struct media_request_object *obj; 1693 + struct v4l2_ctrl_handler *parent_hdl, *hdl; 1694 + struct vicodec_ctx *ctx = NULL; 1695 + struct v4l2_ctrl *ctrl; 1696 + unsigned int count; 1697 + 1698 + list_for_each_entry(obj, &req->objects, list) { 1699 + struct vb2_buffer *vb; 1700 + 1701 + if (vb2_request_object_is_buffer(obj)) { 1702 + vb = container_of(obj, struct vb2_buffer, req_obj); 1703 + ctx = vb2_get_drv_priv(vb->vb2_queue); 1704 + 1705 + break; 1706 + } 1707 + } 1708 + 1709 + if (!ctx) { 1710 + pr_err("No buffer was provided with the request\n"); 1711 + return -ENOENT; 1712 + } 1713 + 1714 + count = vb2_request_buffer_cnt(req); 1715 + if (!count) { 1716 + v4l2_info(&ctx->dev->v4l2_dev, 1717 + "No buffer was provided with the request\n"); 1718 + return -ENOENT; 1719 + } else if (count > 1) { 1720 + v4l2_info(&ctx->dev->v4l2_dev, 1721 + "More than one buffer was provided with the request\n"); 1722 + return -EINVAL; 1723 + } 1724 + 1725 + parent_hdl = &ctx->hdl; 1726 + 1727 + hdl = v4l2_ctrl_request_hdl_find(req, parent_hdl); 1728 + if (!hdl) { 1729 + v4l2_info(&ctx->dev->v4l2_dev, "Missing codec control\n"); 1730 + return -ENOENT; 1731 + } 1732 + ctrl = v4l2_ctrl_request_hdl_ctrl_find(hdl, 1733 + vicodec_ctrl_stateless_state.id); 1734 + if (!ctrl) { 1735 + v4l2_info(&ctx->dev->v4l2_dev, 1736 + "Missing required codec control\n"); 1737 + return -ENOENT; 1738 + } 1739 + 1740 + return vb2_request_validate(req); 1741 + } 1742 + 1870 1743 static const struct v4l2_file_operations vicodec_fops = { 1871 1744 .owner = THIS_MODULE, 1872 1745 .open = vicodec_open, ··· 1936 1703 .ioctl_ops = &vicodec_ioctl_ops, 1937 1704 .minor = -1, 1938 1705 .release = video_device_release_empty, 1706 + }; 1707 + 1708 + static const struct media_device_ops vicodec_m2m_media_ops = { 1709 + .req_validate = vicodec_request_validate, 1710 + .req_queue = v4l2_m2m_request_queue, 1939 1711 }; 1940 1712 1941 1713 static const struct v4l2_m2m_ops m2m_ops = { ··· 2009 1771 strscpy(dev->mdev.bus_info, "platform:vicodec", 2010 1772 sizeof(dev->mdev.bus_info)); 2011 1773 media_device_init(&dev->mdev); 1774 + dev->mdev.ops = &vicodec_m2m_media_ops; 2012 1775 dev->v4l2_dev.mdev = &dev->mdev; 2013 1776 #endif 2014 1777