Codebase list kmscube / ca13617
gst-decoder.c: improve buffer_to_image() function * Make EGL image attribute specification code more generic, and not specific to certain pixel formats, implicitely gaining support for YUY2 * Better handling of gstbuffers with multiple memory blocks * Print out more information about the stream * Use the GST_VIDEO_INFO_* macros instead of directly accessing the GstVideoInfo fields; this is what the GStreamer documentation recommends Signed-off-by: Carlos Rafael Giani <dv@pseudoterminal.org> Carlos Rafael Giani authored 7 years ago Rob Clark committed 7 years ago
1 changed file(s) with 119 addition(s) and 77 deletion(s). Raw diff Collapse all Expand all
00 /*
11 * Copyright (c) 2017 Rob Clark <rclark@redhat.com>
2 * Copyright (c) 2017 Carlos Rafael Giani <dv@pseudoterminal.org>
23 *
34 * Permission is hereby granted, free of charge, to any person obtaining a
45 * copy of this software and associated documentation files (the "Software"),
4344
4445 #define MAX_NUM_PLANES 3
4546
47 inline static const char *
48 yesno(int yes)
49 {
50 return yes ? "yes" : "no";
51 }
52
4653 struct decoder {
4754 GMainLoop *loop;
4855 GstElement *pipeline;
98105 GST_ERROR("unknown format\n");
99106 return GST_PAD_PROBE_OK;
100107 }
101
102 GST_DEBUG("got: %ux%u@%4.4s\n", dec->info.width, dec->info.height,
103 (char *)&dec->format);
104108
105109 return GST_PAD_PROBE_OK;
106110 }
355359 struct { int fd, offset, stride; } planes[MAX_NUM_PLANES];
356360 GstVideoMeta *meta = gst_buffer_get_video_meta(buf);
357361 EGLImage image;
358 unsigned nmems = gst_buffer_n_memory(buf);
359 unsigned nplanes = (dec->format == DRM_FORMAT_YUV420) ? 3 : 2;
360 unsigned i;
361
362 if (nmems == nplanes) {
363 // XXX TODO..
364 } else if (nmems == 1) {
365 GstMemory *mem = gst_buffer_peek_memory(buf, 0);
366 int fd;
367
368 if (dec->frame == 0) {
369 printf("%s zero-copy\n", gst_is_dmabuf_memory(mem) ? "using" : "not");
362 guint nmems = gst_buffer_n_memory(buf);
363 guint nplanes = GST_VIDEO_INFO_N_PLANES(&(dec->info));
364 guint i;
365 guint width, height;
366 gboolean is_dmabuf_mem;
367 GstMemory *mem;
368 int dmabuf_fd = -1;
369
370 static const EGLint egl_dmabuf_plane_fd_attr[MAX_NUM_PLANES] = {
371 EGL_DMA_BUF_PLANE0_FD_EXT,
372 EGL_DMA_BUF_PLANE1_FD_EXT,
373 EGL_DMA_BUF_PLANE2_FD_EXT,
374 };
375 static const EGLint egl_dmabuf_plane_offset_attr[MAX_NUM_PLANES] = {
376 EGL_DMA_BUF_PLANE0_OFFSET_EXT,
377 EGL_DMA_BUF_PLANE1_OFFSET_EXT,
378 EGL_DMA_BUF_PLANE2_OFFSET_EXT,
379 };
380 static const EGLint egl_dmabuf_plane_pitch_attr[MAX_NUM_PLANES] = {
381 EGL_DMA_BUF_PLANE0_PITCH_EXT,
382 EGL_DMA_BUF_PLANE1_PITCH_EXT,
383 EGL_DMA_BUF_PLANE2_PITCH_EXT,
384 };
385
386 /* Query gst_is_dmabuf_memory() here, since the gstmemory
387 * block might get merged below by gst_buffer_map(), meaning
388 * that the mem pointer would become invalid */
389 mem = gst_buffer_peek_memory(buf, 0);
390 is_dmabuf_mem = gst_is_dmabuf_memory(mem);
391
392 if (nmems > 1) {
393 if (is_dmabuf_mem) {
394 /* this case currently is not defined */
395
396 GST_FIXME("gstbuffers with multiple memory blocks and DMABUF "
397 "memory currently are not supported");
398 return EGL_NO_IMAGE_KHR;
370399 }
371400
372 if (gst_is_dmabuf_memory(mem)) {
373 fd = dup(gst_dmabuf_memory_get_fd(mem));
374 } else {
375 GstMapInfo info;
376 gst_memory_map(mem, &info, GST_MAP_READ);
377 fd = buf_to_fd(dec->gbm, info.size, info.data);
378 gst_memory_unmap(mem, &info);
401 /* if this is not DMABUF memory, then the gst_buffer_map()
402 * call below will automatically merge the memory blocks
403 */
404 }
405
406 if (is_dmabuf_mem) {
407 dmabuf_fd = dup(gst_dmabuf_memory_get_fd(mem));
408 } else {
409 GstMapInfo map_info;
410 gst_buffer_map(buf, &map_info, GST_MAP_READ);
411 dmabuf_fd = buf_to_fd(dec->gbm, map_info.size, map_info.data);
412 gst_buffer_unmap(buf, &map_info);
413 }
414
415 if (dmabuf_fd < 0) {
416 GST_ERROR("could not obtain DMABUF FD");
417 return EGL_NO_IMAGE_KHR;
418 }
419
420 /* Usually, a videometa should be present, since by using the internal kmscube
421 * video_appsink element instead of the regular appsink, it is guaranteed that
422 * video meta support is declared in the video_appsink's allocation query.
423 * However, this assumes that upstream elements actually look at the allocation
424 * query's contents properly, or that they even send a query at all. If this
425 * is not the case, then upstream might decide to push frames without adding
426 * a meta. It can happen, and in this case, look at the video info data as
427 * a fallback (it is computed out of the input caps).
428 */
429 if (meta) {
430 for (i = 0; i < nplanes; i++) {
431 planes[i].fd = dmabuf_fd;
432 planes[i].offset = meta->offset[i];
433 planes[i].stride = meta->stride[i];
379434 }
380
381 // XXX why don't we get meta??
382 if (meta) {
383 for (i = 0; i < nplanes; i++) {
384 planes[i].fd = fd;
385 planes[i].offset = meta->offset[i];
386 planes[i].stride = meta->stride[i];
387 }
388 } else {
389 int offset = 0, stride = dec->info.width, height = dec->info.height;
390
391 for (i = 0; i < nplanes; i++) {
392
393 if (i == 1) {
394 height /= 2;
395 if (nplanes == 3)
396 stride /= 2;
397 }
398
399 planes[i].fd = fd;
400 planes[i].offset = offset;
401 planes[i].stride = stride;
402
403 offset += stride * height;
404 }
435 } else {
436 for (i = 0; i < nplanes; i++) {
437 planes[i].fd = dmabuf_fd;
438 planes[i].offset = GST_VIDEO_INFO_PLANE_OFFSET(&(dec->info), i);
439 planes[i].stride = GST_VIDEO_INFO_PLANE_STRIDE(&(dec->info), i);
405440 }
406441 }
407442
408 if (dec->format == DRM_FORMAT_NV12) {
409 const EGLint attr[] = {
410 EGL_WIDTH, dec->info.width,
411 EGL_HEIGHT, dec->info.height,
412 EGL_LINUX_DRM_FOURCC_EXT, dec->format,
413 EGL_DMA_BUF_PLANE0_FD_EXT, planes[0].fd,
414 EGL_DMA_BUF_PLANE0_OFFSET_EXT, planes[0].offset,
415 EGL_DMA_BUF_PLANE0_PITCH_EXT, planes[0].stride,
416 EGL_DMA_BUF_PLANE1_FD_EXT, planes[1].fd,
417 EGL_DMA_BUF_PLANE1_OFFSET_EXT, planes[1].offset,
418 EGL_DMA_BUF_PLANE1_PITCH_EXT, planes[1].stride,
419 EGL_NONE
443 width = GST_VIDEO_INFO_WIDTH(&(dec->info));
444 height = GST_VIDEO_INFO_HEIGHT(&(dec->info));
445
446 /* output some information at the beginning (= when the first frame is handled) */
447 if (dec->frame == 0) {
448 GstVideoFormat pixfmt;
449 const char *pixfmt_str;
450
451 pixfmt = GST_VIDEO_INFO_FORMAT(&(dec->info));
452 pixfmt_str = gst_video_format_to_string(pixfmt);
453
454 printf("===================================\n");
455 printf("GStreamer video stream information:\n");
456 printf(" size: %u x %u pixel\n", width, height);
457 printf(" pixel format: %s number of planes: %u\n", pixfmt_str, nplanes);
458 printf(" can use zero-copy: %s\n", yesno(is_dmabuf_mem));
459 printf(" video meta found: %s\n", yesno(meta != NULL));
460 printf("===================================\n");
461 }
462
463 {
464 /* Initialize the first 6 attributes with values that are
465 * plane invariant (width, height, format) */
466 EGLint attr[6 + 6*(MAX_NUM_PLANES) + 1] = {
467 EGL_WIDTH, width,
468 EGL_HEIGHT, height,
469 EGL_LINUX_DRM_FOURCC_EXT, dec->format
420470 };
421471
422 image = dec->egl->eglCreateImageKHR(dec->egl->display, EGL_NO_CONTEXT,
423 EGL_LINUX_DMA_BUF_EXT, NULL, attr);
424 } else {
425 const EGLint attr[] = {
426 EGL_WIDTH, dec->info.width,
427 EGL_HEIGHT, dec->info.height,
428 EGL_LINUX_DRM_FOURCC_EXT, dec->format,
429 EGL_DMA_BUF_PLANE0_FD_EXT, planes[0].fd,
430 EGL_DMA_BUF_PLANE0_OFFSET_EXT, planes[0].offset,
431 EGL_DMA_BUF_PLANE0_PITCH_EXT, planes[0].stride,
432 EGL_DMA_BUF_PLANE1_FD_EXT, planes[1].fd,
433 EGL_DMA_BUF_PLANE1_OFFSET_EXT, planes[1].offset,
434 EGL_DMA_BUF_PLANE1_PITCH_EXT, planes[1].stride,
435 EGL_DMA_BUF_PLANE2_FD_EXT, planes[2].fd,
436 EGL_DMA_BUF_PLANE2_OFFSET_EXT, planes[2].offset,
437 EGL_DMA_BUF_PLANE2_PITCH_EXT, planes[2].stride,
438 EGL_NONE
439 };
472 for (i = 0; i < nplanes; i++) {
473 attr[6 + 6*i + 0] = egl_dmabuf_plane_fd_attr[i];
474 attr[6 + 6*i + 1] = planes[i].fd;
475 attr[6 + 6*i + 2] = egl_dmabuf_plane_offset_attr[i];
476 attr[6 + 6*i + 3] = planes[i].offset;
477 attr[6 + 6*i + 4] = egl_dmabuf_plane_pitch_attr[i];
478 attr[6 + 6*i + 5] = planes[i].stride;
479 }
480
481 attr[6 + 6*nplanes] = EGL_NONE;
440482
441483 image = dec->egl->eglCreateImageKHR(dec->egl->display, EGL_NO_CONTEXT,
442484 EGL_LINUX_DMA_BUF_EXT, NULL, attr);