0001-gst-Add-support-for-DMA_DRM-explicit-modifiers.patch 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940
  1. From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
  2. From: Robert Mader <robert.mader@collabora.com>
  3. Date: Fri, 2 Feb 2024 02:20:29 +0100
  4. Subject: [PATCH] gst: Add support for DMA_DRM / explicit modifiers
  5. Gstreamer 1.24 added and largely switched to a new, modifier aware
  6. DMABuf API. Unfortunately that breaks the existing DMABuf support in the
  7. PW Gst element.
  8. Add support for the new API.
  9. ---
  10. meson.build | 8 +
  11. src/gst/gstpipewireformat.c | 521 +++++++++++++++++++++++++-----------
  12. src/gst/gstpipewireformat.h | 4 +-
  13. src/gst/gstpipewiresink.c | 2 +-
  14. src/gst/gstpipewiresrc.c | 46 +++-
  15. src/gst/gstpipewiresrc.h | 5 +
  16. 6 files changed, 417 insertions(+), 169 deletions(-)
  17. diff --git a/meson.build b/meson.build
  18. index 0ea256e9bcbb..61cfa3eac325 100644
  19. --- a/meson.build
  20. +++ b/meson.build
  21. @@ -361,26 +361,34 @@ gst_deps_def = {
  22. }
  23. gst_dep = []
  24. +gst_dma_drm_found = false
  25. foreach depname, kwargs: gst_deps_def
  26. dep = dependency(depname, required: gst_option, kwargs: kwargs)
  27. summary({depname: dep.found()}, bool_yn: true, section: 'GStreamer modules')
  28. if not dep.found()
  29. # Beware, there's logic below depending on the array clear here!
  30. gst_dep = []
  31. if get_option('gstreamer-device-provider').enabled()
  32. error('`gstreamer-device-provider` is enabled but `@0@` was not found.'.format(depname))
  33. endif
  34. break
  35. endif
  36. gst_dep += [dep]
  37. +
  38. + if depname == 'gstreamer-allocators-1.0' and dep.version().version_compare('>= 1.23.1')
  39. + gst_dma_drm_found = true
  40. + endif
  41. endforeach
  42. # This code relies on the array being empty if any dependency was not found
  43. gst_dp_found = gst_dep.length() > 0
  44. summary({'gstreamer-device-provider': gst_dp_found}, bool_yn: true, section: 'Backend')
  45. cdata.set('HAVE_GSTREAMER_DEVICE_PROVIDER', get_option('gstreamer-device-provider').allowed())
  46. +summary({'gstreamer DMA_DRM support': gst_dma_drm_found}, bool_yn: true, section: 'Backend')
  47. +cdata.set('HAVE_GSTREAMER_DMA_DRM', gst_dma_drm_found)
  48. +
  49. webrtc_dep = dependency('webrtc-audio-processing-1',
  50. version : ['>= 1.2' ],
  51. required : false)
  52. diff --git a/src/gst/gstpipewireformat.c b/src/gst/gstpipewireformat.c
  53. index b16f7b1cf002..ff1752a06565 100644
  54. --- a/src/gst/gstpipewireformat.c
  55. +++ b/src/gst/gstpipewireformat.c
  56. @@ -2,21 +2,27 @@
  57. /* SPDX-FileCopyrightText: Copyright © 2018 Wim Taymans */
  58. /* SPDX-License-Identifier: MIT */
  59. +#include "config.h"
  60. +
  61. #include <stdio.h>
  62. #include <gst/gst.h>
  63. #include <gst/allocators/gstdmabuf.h>
  64. #include <gst/video/video.h>
  65. #include <gst/audio/audio.h>
  66. #include <spa/utils/string.h>
  67. #include <spa/utils/type.h>
  68. #include <spa/param/video/format-utils.h>
  69. #include <spa/param/audio/format-utils.h>
  70. -#include <spa/pod/builder.h>
  71. +#include <spa/pod/dynamic.h>
  72. #include "gstpipewireformat.h"
  73. +#ifndef DRM_FORMAT_INVALID
  74. +#define DRM_FORMAT_INVALID 0
  75. +#endif
  76. +
  77. #ifndef DRM_FORMAT_MOD_INVALID
  78. #define DRM_FORMAT_MOD_INVALID ((1ULL << 56) - 1)
  79. #endif
  80. @@ -169,9 +175,7 @@ static const uint32_t audio_format_map[] = {
  81. };
  82. typedef struct {
  83. - struct spa_pod_builder b;
  84. const struct media_type *type;
  85. - uint32_t id;
  86. const GstCapsFeatures *cf;
  87. const GstStructure *cs;
  88. GPtrArray *array;
  89. @@ -358,89 +362,221 @@ get_range_type2 (const GValue *v1, const GValue *v2)
  90. return SPA_CHOICE_Range;
  91. }
  92. -static gboolean
  93. -handle_video_fields (ConvertData *d)
  94. +static void
  95. +add_limits (struct spa_pod_dynamic_builder *b, ConvertData *d)
  96. {
  97. - const GValue *value, *value2;
  98. - int i;
  99. struct spa_pod_choice *choice;
  100. struct spa_pod_frame f;
  101. + const GValue *value, *value2;
  102. + int i;
  103. - value = gst_structure_get_value (d->cs, "format");
  104. - if (value) {
  105. - const char *v;
  106. - int idx;
  107. - for (i = 0; (v = get_nth_string (value, i)); i++) {
  108. - if (i == 0) {
  109. - spa_pod_builder_prop (&d->b, SPA_FORMAT_VIDEO_format, 0);
  110. - spa_pod_builder_push_choice(&d->b, &f, get_range_type (value), 0);
  111. - }
  112. -
  113. - idx = gst_video_format_from_string (v);
  114. - if (idx != GST_VIDEO_FORMAT_UNKNOWN && idx < (int)SPA_N_ELEMENTS (video_format_map))
  115. - spa_pod_builder_id (&d->b, video_format_map[idx]);
  116. - }
  117. - if (i > 0) {
  118. - choice = spa_pod_builder_pop(&d->b, &f);
  119. - if (i == 1)
  120. - choice->body.type = SPA_CHOICE_None;
  121. - }
  122. - }
  123. value = gst_structure_get_value (d->cs, "width");
  124. value2 = gst_structure_get_value (d->cs, "height");
  125. if (value && value2) {
  126. struct spa_rectangle v;
  127. for (i = 0; get_nth_rectangle (value, value2, i, &v); i++) {
  128. if (i == 0) {
  129. - spa_pod_builder_prop (&d->b, SPA_FORMAT_VIDEO_size, 0);
  130. - spa_pod_builder_push_choice(&d->b, &f, get_range_type2 (value, value2), 0);
  131. + spa_pod_builder_prop (&b->b, SPA_FORMAT_VIDEO_size, 0);
  132. + spa_pod_builder_push_choice(&b->b, &f, get_range_type2 (value, value2), 0);
  133. }
  134. - spa_pod_builder_rectangle (&d->b, v.width, v.height);
  135. + spa_pod_builder_rectangle (&b->b, v.width, v.height);
  136. }
  137. if (i > 0) {
  138. - choice = spa_pod_builder_pop(&d->b, &f);
  139. + choice = spa_pod_builder_pop(&b->b, &f);
  140. if (i == 1)
  141. choice->body.type = SPA_CHOICE_None;
  142. }
  143. }
  144. value = gst_structure_get_value (d->cs, "framerate");
  145. if (value) {
  146. struct spa_fraction v;
  147. for (i = 0; get_nth_fraction (value, i, &v); i++) {
  148. if (i == 0) {
  149. - spa_pod_builder_prop (&d->b, SPA_FORMAT_VIDEO_framerate, 0);
  150. - spa_pod_builder_push_choice(&d->b, &f, get_range_type (value), 0);
  151. + spa_pod_builder_prop (&b->b, SPA_FORMAT_VIDEO_framerate, 0);
  152. + spa_pod_builder_push_choice(&b->b, &f, get_range_type (value), 0);
  153. }
  154. - spa_pod_builder_fraction (&d->b, v.num, v.denom);
  155. + spa_pod_builder_fraction (&b->b, v.num, v.denom);
  156. }
  157. if (i > 0) {
  158. - choice = spa_pod_builder_pop(&d->b, &f);
  159. + choice = spa_pod_builder_pop(&b->b, &f);
  160. if (i == 1)
  161. choice->body.type = SPA_CHOICE_None;
  162. }
  163. }
  164. value = gst_structure_get_value (d->cs, "max-framerate");
  165. if (value) {
  166. struct spa_fraction v;
  167. for (i = 0; get_nth_fraction (value, i, &v); i++) {
  168. if (i == 0) {
  169. - spa_pod_builder_prop (&d->b, SPA_FORMAT_VIDEO_maxFramerate, 0);
  170. - spa_pod_builder_push_choice(&d->b, &f, get_range_type (value), 0);
  171. + spa_pod_builder_prop (&b->b, SPA_FORMAT_VIDEO_maxFramerate, 0);
  172. + spa_pod_builder_push_choice(&b->b, &f, get_range_type (value), 0);
  173. }
  174. - spa_pod_builder_fraction (&d->b, v.num, v.denom);
  175. + spa_pod_builder_fraction (&b->b, v.num, v.denom);
  176. }
  177. if (i > 0) {
  178. - choice = spa_pod_builder_pop(&d->b, &f);
  179. + choice = spa_pod_builder_pop(&b->b, &f);
  180. if (i == 1)
  181. choice->body.type = SPA_CHOICE_None;
  182. }
  183. }
  184. - return TRUE;
  185. +}
  186. +
  187. +static void
  188. +add_video_format (gpointer format_ptr,
  189. + gpointer modifiers_ptr,
  190. + gpointer user_data)
  191. +{
  192. + uint32_t format = GPOINTER_TO_UINT (format_ptr);
  193. + GHashTable *modifiers = modifiers_ptr;
  194. + ConvertData *d = user_data;
  195. + struct spa_pod_dynamic_builder b;
  196. + struct spa_pod_frame f;
  197. +
  198. + spa_pod_dynamic_builder_init (&b, NULL, 0, 1024);
  199. +
  200. + spa_pod_builder_push_object (&b.b, &f, SPA_TYPE_OBJECT_Format, SPA_PARAM_EnumFormat);
  201. +
  202. + spa_pod_builder_prop (&b.b, SPA_FORMAT_mediaType, 0);
  203. + spa_pod_builder_id(&b.b, d->type->media_type);
  204. +
  205. + spa_pod_builder_prop (&b.b, SPA_FORMAT_mediaSubtype, 0);
  206. + spa_pod_builder_id(&b.b, d->type->media_subtype);
  207. +
  208. + spa_pod_builder_prop (&b.b, SPA_FORMAT_VIDEO_format, 0);
  209. + spa_pod_builder_id (&b.b, format);
  210. +
  211. + if (g_hash_table_size (modifiers) > 0) {
  212. + GHashTableIter iter;
  213. + gpointer key, value;
  214. +
  215. + g_hash_table_iter_init (&iter, modifiers);
  216. + if (g_hash_table_size (modifiers) > 1) {
  217. + struct spa_pod_frame f2;
  218. +
  219. + spa_pod_builder_prop (&b.b, SPA_FORMAT_VIDEO_modifier,
  220. + (SPA_POD_PROP_FLAG_MANDATORY | SPA_POD_PROP_FLAG_DONT_FIXATE));
  221. + spa_pod_builder_push_choice (&b.b, &f2, SPA_CHOICE_Enum, 0);
  222. + g_hash_table_iter_next (&iter, &key, &value);
  223. + spa_pod_builder_long (&b.b, (uint64_t) key);
  224. + do {
  225. + spa_pod_builder_long (&b.b, (uint64_t) key);
  226. + } while (g_hash_table_iter_next (&iter, &key, &value));
  227. + spa_pod_builder_pop (&b.b, &f2);
  228. + } else {
  229. + g_hash_table_iter_next (&iter, &key, &value);
  230. + spa_pod_builder_prop (&b.b, SPA_FORMAT_VIDEO_modifier,
  231. + SPA_POD_PROP_FLAG_MANDATORY);
  232. + spa_pod_builder_long (&b.b, (uint64_t) key);
  233. + }
  234. + }
  235. +
  236. + add_limits (&b, d);
  237. +
  238. + g_ptr_array_add (d->array, spa_pod_builder_pop (&b.b, &f));
  239. +}
  240. +
  241. +static void
  242. +handle_video_fields (ConvertData *d)
  243. +{
  244. + g_autoptr (GHashTable) formats = NULL;
  245. + const GValue *value;
  246. + gboolean dmabuf_caps;
  247. + int i;
  248. +
  249. + formats = g_hash_table_new_full (NULL, NULL, NULL,
  250. + (GDestroyNotify) g_hash_table_unref);
  251. + dmabuf_caps = (d->cf &&
  252. + gst_caps_features_contains (d->cf,
  253. + GST_CAPS_FEATURE_MEMORY_DMABUF));
  254. +
  255. + value = gst_structure_get_value (d->cs, "format");
  256. + if (value) {
  257. + const char *v;
  258. +
  259. + for (i = 0; (v = get_nth_string (value, i)); i++) {
  260. + int idx;
  261. +
  262. + idx = gst_video_format_from_string (v);
  263. +#ifdef HAVE_GSTREAMER_DMA_DRM
  264. + if (dmabuf_caps && idx == GST_VIDEO_FORMAT_DMA_DRM) {
  265. + const GValue *value2;
  266. +
  267. + value2 = gst_structure_get_value (d->cs, "drm-format");
  268. + if (value2) {
  269. + const char *v2;
  270. + int j;
  271. +
  272. + for (j = 0; (v2 = get_nth_string (value2, j)); j++) {
  273. + uint32_t fourcc;
  274. + uint64_t mod;
  275. + int idx2;
  276. +
  277. + fourcc = gst_video_dma_drm_fourcc_from_string (v2, &mod);
  278. + idx2 = gst_video_dma_drm_fourcc_to_format (fourcc);
  279. +
  280. + if (idx2 != GST_VIDEO_FORMAT_UNKNOWN &&
  281. + idx2 < (int)SPA_N_ELEMENTS (video_format_map)) {
  282. + GHashTable *modifiers =
  283. + g_hash_table_lookup (formats,
  284. + GINT_TO_POINTER (video_format_map[idx2]));
  285. + if (!modifiers) {
  286. + modifiers = g_hash_table_new (NULL, NULL);
  287. + g_hash_table_insert (formats,
  288. + GINT_TO_POINTER (video_format_map[idx2]),
  289. + modifiers);
  290. + }
  291. +
  292. + g_hash_table_add (modifiers, GINT_TO_POINTER (mod));
  293. + }
  294. + }
  295. + }
  296. + } else
  297. +#endif
  298. + if (idx != GST_VIDEO_FORMAT_UNKNOWN &&
  299. + idx < (int)SPA_N_ELEMENTS (video_format_map)) {
  300. + GHashTable *modifiers =
  301. + g_hash_table_lookup (formats,
  302. + GINT_TO_POINTER (video_format_map[idx]));
  303. + if (!modifiers) {
  304. + modifiers = g_hash_table_new (NULL, NULL);
  305. + g_hash_table_insert (formats,
  306. + GINT_TO_POINTER (video_format_map[idx]),
  307. + modifiers);
  308. + }
  309. +
  310. + if (dmabuf_caps) {
  311. + g_hash_table_add (modifiers, GINT_TO_POINTER (DRM_FORMAT_MOD_LINEAR));
  312. + g_hash_table_add (modifiers, GINT_TO_POINTER (DRM_FORMAT_MOD_INVALID));
  313. + }
  314. + }
  315. + }
  316. + }
  317. +
  318. + if (g_hash_table_size (formats) > 0) {
  319. + g_hash_table_foreach (formats, add_video_format, d);
  320. + } else if (!dmabuf_caps) {
  321. + struct spa_pod_dynamic_builder b;
  322. + struct spa_pod_frame f;
  323. +
  324. + spa_pod_dynamic_builder_init (&b, NULL, 0, 1024);
  325. +
  326. + spa_pod_builder_push_object (&b.b, &f, SPA_TYPE_OBJECT_Format, SPA_PARAM_EnumFormat);
  327. +
  328. + spa_pod_builder_prop (&b.b, SPA_FORMAT_mediaType, 0);
  329. + spa_pod_builder_id(&b.b, d->type->media_type);
  330. +
  331. + spa_pod_builder_prop (&b.b, SPA_FORMAT_mediaSubtype, 0);
  332. + spa_pod_builder_id(&b.b, d->type->media_subtype);
  333. +
  334. + add_limits (&b, d);
  335. +
  336. + g_ptr_array_add (d->array, spa_pod_builder_pop (&b.b, &f));
  337. + }
  338. }
  339. static void
  340. @@ -481,237 +617,207 @@ set_default_channels (struct spa_pod_builder *b, uint32_t channels)
  341. SPA_POD_Array(sizeof(uint32_t), SPA_TYPE_Id, channels, position), 0);
  342. }
  343. -static gboolean
  344. +static void
  345. handle_audio_fields (ConvertData *d)
  346. {
  347. const GValue *value;
  348. + struct spa_pod_dynamic_builder b;
  349. struct spa_pod_choice *choice;
  350. - struct spa_pod_frame f;
  351. + struct spa_pod_frame f, f0;
  352. int i = 0;
  353. + spa_pod_dynamic_builder_init (&b, NULL, 0, 1024);
  354. +
  355. + spa_pod_builder_push_object (&b.b, &f0, SPA_TYPE_OBJECT_Format,
  356. + SPA_PARAM_EnumFormat);
  357. +
  358. + spa_pod_builder_prop (&b.b, SPA_FORMAT_mediaType, 0);
  359. + spa_pod_builder_id(&b.b, d->type->media_type);
  360. +
  361. + spa_pod_builder_prop (&b.b, SPA_FORMAT_mediaSubtype, 0);
  362. + spa_pod_builder_id(&b.b, d->type->media_subtype);
  363. +
  364. value = gst_structure_get_value (d->cs, "format");
  365. if (value) {
  366. const char *v;
  367. int idx;
  368. for (i = 0; (v = get_nth_string (value, i)); i++) {
  369. if (i == 0) {
  370. - spa_pod_builder_prop (&d->b, SPA_FORMAT_AUDIO_format, 0);
  371. - spa_pod_builder_push_choice(&d->b, &f, get_range_type (value), 0);
  372. + spa_pod_builder_prop (&b.b, SPA_FORMAT_AUDIO_format, 0);
  373. + spa_pod_builder_push_choice(&b.b, &f, get_range_type (value), 0);
  374. }
  375. idx = gst_audio_format_from_string (v);
  376. if (idx < (int)SPA_N_ELEMENTS (audio_format_map))
  377. - spa_pod_builder_id (&d->b, audio_format_map[idx]);
  378. + spa_pod_builder_id (&b.b, audio_format_map[idx]);
  379. }
  380. if (i > 0) {
  381. - choice = spa_pod_builder_pop(&d->b, &f);
  382. + choice = spa_pod_builder_pop(&b.b, &f);
  383. if (i == 1)
  384. choice->body.type = SPA_CHOICE_None;
  385. }
  386. } else if (strcmp(d->type->name, "audio/x-mulaw") == 0) {
  387. - spa_pod_builder_prop (&d->b, SPA_FORMAT_AUDIO_format, 0);
  388. - spa_pod_builder_id (&d->b, SPA_AUDIO_FORMAT_ULAW);
  389. + spa_pod_builder_prop (&b.b, SPA_FORMAT_AUDIO_format, 0);
  390. + spa_pod_builder_id (&b.b, SPA_AUDIO_FORMAT_ULAW);
  391. } else if (strcmp(d->type->name, "audio/x-alaw") == 0) {
  392. - spa_pod_builder_prop (&d->b, SPA_FORMAT_AUDIO_format, 0);
  393. - spa_pod_builder_id (&d->b, SPA_AUDIO_FORMAT_ALAW);
  394. + spa_pod_builder_prop (&b.b, SPA_FORMAT_AUDIO_format, 0);
  395. + spa_pod_builder_id (&b.b, SPA_AUDIO_FORMAT_ALAW);
  396. } else if (strcmp(d->type->name, "audio/mpeg") == 0) {
  397. - spa_pod_builder_prop (&d->b, SPA_FORMAT_AUDIO_format, 0);
  398. - spa_pod_builder_id (&d->b, SPA_AUDIO_FORMAT_ENCODED);
  399. + spa_pod_builder_prop (&b.b, SPA_FORMAT_AUDIO_format, 0);
  400. + spa_pod_builder_id (&b.b, SPA_AUDIO_FORMAT_ENCODED);
  401. } else if (strcmp(d->type->name, "audio/x-flac") == 0) {
  402. - spa_pod_builder_prop (&d->b, SPA_FORMAT_AUDIO_format, 0);
  403. - spa_pod_builder_id (&d->b, SPA_AUDIO_FORMAT_ENCODED);
  404. + spa_pod_builder_prop (&b.b, SPA_FORMAT_AUDIO_format, 0);
  405. + spa_pod_builder_id (&b.b, SPA_AUDIO_FORMAT_ENCODED);
  406. }
  407. #if 0
  408. value = gst_structure_get_value (d->cs, "layout");
  409. if (value) {
  410. const char *v;
  411. for (i = 0; (v = get_nth_string (value, i)); i++) {
  412. enum spa_audio_layout layout;
  413. if (spa_streq(v, "interleaved"))
  414. layout = SPA_AUDIO_LAYOUT_INTERLEAVED;
  415. else if (spa_streq(v, "non-interleaved"))
  416. layout = SPA_AUDIO_LAYOUT_NON_INTERLEAVED;
  417. else
  418. break;
  419. if (i == 0) {
  420. - spa_pod_builder_prop (&d->b, SPA_FORMAT_AUDIO_layout, 0);
  421. - spa_pod_builder_push_choice(&d->b, &f, get_range_type (value), 0);
  422. + spa_pod_builder_prop (&b.b, SPA_FORMAT_AUDIO_layout, 0);
  423. + spa_pod_builder_push_choice(&b.b, &f, get_range_type (value), 0);
  424. }
  425. - spa_pod_builder_id (&d->b, layout);
  426. + spa_pod_builder_id (&b.b, layout);
  427. }
  428. if (i > 0) {
  429. - choice = spa_pod_builder_pop(&d->b, &f);
  430. + choice = spa_pod_builder_pop(&b.b, &f);
  431. if (i == 1)
  432. choice->body.type = SPA_CHOICE_None;
  433. }
  434. }
  435. #endif
  436. value = gst_structure_get_value (d->cs, "rate");
  437. if (value) {
  438. int v;
  439. for (i = 0; get_nth_int (value, i, &v); i++) {
  440. if (i == 0) {
  441. - spa_pod_builder_prop (&d->b, SPA_FORMAT_AUDIO_rate, 0);
  442. - spa_pod_builder_push_choice(&d->b, &f, get_range_type (value), 0);
  443. + spa_pod_builder_prop (&b.b, SPA_FORMAT_AUDIO_rate, 0);
  444. + spa_pod_builder_push_choice(&b.b, &f, get_range_type (value), 0);
  445. }
  446. - spa_pod_builder_int (&d->b, v);
  447. + spa_pod_builder_int (&b.b, v);
  448. }
  449. if (i > 0) {
  450. - choice = spa_pod_builder_pop(&d->b, &f);
  451. + choice = spa_pod_builder_pop(&b.b, &f);
  452. if (i == 1)
  453. choice->body.type = SPA_CHOICE_None;
  454. }
  455. }
  456. value = gst_structure_get_value (d->cs, "channels");
  457. if (value) {
  458. int v;
  459. for (i = 0; get_nth_int (value, i, &v); i++) {
  460. if (i == 0) {
  461. - spa_pod_builder_prop (&d->b, SPA_FORMAT_AUDIO_channels, 0);
  462. - spa_pod_builder_push_choice(&d->b, &f, get_range_type (value), 0);
  463. + spa_pod_builder_prop (&b.b, SPA_FORMAT_AUDIO_channels, 0);
  464. + spa_pod_builder_push_choice(&b.b, &f, get_range_type (value), 0);
  465. }
  466. - spa_pod_builder_int (&d->b, v);
  467. + spa_pod_builder_int (&b.b, v);
  468. }
  469. if (i > 0) {
  470. - choice = spa_pod_builder_pop(&d->b, &f);
  471. + choice = spa_pod_builder_pop(&b.b, &f);
  472. if (i == 1) {
  473. choice->body.type = SPA_CHOICE_None;
  474. - set_default_channels (&d->b, v);
  475. + set_default_channels (&b.b, v);
  476. }
  477. }
  478. }
  479. - return TRUE;
  480. +
  481. + g_ptr_array_add (d->array, spa_pod_builder_pop (&b.b, &f0));
  482. }
  483. -static int
  484. -builder_overflow (void *event_data, uint32_t size)
  485. +static void
  486. +handle_fields (ConvertData *d)
  487. {
  488. - struct spa_pod_builder *b = event_data;
  489. - b->size = SPA_ROUND_UP_N (size, 512);
  490. - b->data = realloc (b->data, b->size);
  491. - if (b->data == NULL)
  492. - return -errno;
  493. - return 0;
  494. -}
  495. -
  496. -static const struct spa_pod_builder_callbacks builder_callbacks = {
  497. - SPA_VERSION_POD_BUILDER_CALLBACKS,
  498. - .overflow = builder_overflow
  499. -};
  500. -
  501. -static struct spa_pod *
  502. -convert_1 (ConvertData *d)
  503. -{
  504. - struct spa_pod_frame f;
  505. -
  506. if (!(d->type = find_media_types (gst_structure_get_name (d->cs))))
  507. - return NULL;
  508. -
  509. - spa_pod_builder_set_callbacks(&d->b, &builder_callbacks, &d->b);
  510. -
  511. - spa_pod_builder_push_object (&d->b, &f, SPA_TYPE_OBJECT_Format, d->id);
  512. -
  513. - spa_pod_builder_prop (&d->b, SPA_FORMAT_mediaType, 0);
  514. - spa_pod_builder_id(&d->b, d->type->media_type);
  515. -
  516. - spa_pod_builder_prop (&d->b, SPA_FORMAT_mediaSubtype, 0);
  517. - spa_pod_builder_id(&d->b, d->type->media_subtype);
  518. -
  519. - if (d->cf && gst_caps_features_contains (d->cf, GST_CAPS_FEATURE_MEMORY_DMABUF)) {
  520. - struct spa_pod_frame f2;
  521. -
  522. - spa_pod_builder_prop (&d->b, SPA_FORMAT_VIDEO_modifier,
  523. - (SPA_POD_PROP_FLAG_MANDATORY | SPA_POD_PROP_FLAG_DONT_FIXATE));
  524. - spa_pod_builder_push_choice (&d->b, &f2, SPA_CHOICE_Enum, 0);
  525. - spa_pod_builder_long (&d->b, DRM_FORMAT_MOD_INVALID);
  526. - spa_pod_builder_long (&d->b, DRM_FORMAT_MOD_INVALID);
  527. - spa_pod_builder_long (&d->b, DRM_FORMAT_MOD_LINEAR);
  528. - spa_pod_builder_pop (&d->b, &f2);
  529. - }
  530. + return;
  531. if (d->type->media_type == SPA_MEDIA_TYPE_video)
  532. handle_video_fields (d);
  533. else if (d->type->media_type == SPA_MEDIA_TYPE_audio)
  534. handle_audio_fields (d);
  535. -
  536. - spa_pod_builder_pop (&d->b, &f);
  537. -
  538. - return SPA_PTROFF (d->b.data, 0, struct spa_pod);
  539. -}
  540. -
  541. -struct spa_pod *
  542. -gst_caps_to_format (GstCaps *caps, guint index, uint32_t id)
  543. -{
  544. - ConvertData d;
  545. - struct spa_pod *res;
  546. -
  547. - g_return_val_if_fail (GST_IS_CAPS (caps), NULL);
  548. - g_return_val_if_fail (gst_caps_is_fixed (caps), NULL);
  549. -
  550. - spa_zero (d);
  551. - d.cf = gst_caps_get_features (caps, index);
  552. - d.cs = gst_caps_get_structure (caps, index);
  553. - d.id = id;
  554. -
  555. - res = convert_1 (&d);
  556. -
  557. - return res;
  558. }
  559. static gboolean
  560. -foreach_func (GstCapsFeatures *features,
  561. - GstStructure *structure,
  562. - ConvertData *d)
  563. +foreach_func_dmabuf (GstCapsFeatures *features,
  564. + GstStructure *structure,
  565. + ConvertData *d)
  566. {
  567. - struct spa_pod *fmt;
  568. - int idx;
  569. + if (!features || !gst_caps_features_contains (features, GST_CAPS_FEATURE_MEMORY_DMABUF))
  570. + return TRUE;
  571. - spa_zero(d->b);
  572. d->cf = features;
  573. d->cs = structure;
  574. - if (d->cf && gst_caps_features_contains (d->cf, GST_CAPS_FEATURE_MEMORY_DMABUF))
  575. - idx = 0;
  576. - else
  577. - idx = -1;
  578. + handle_fields (d);
  579. - if ((fmt = convert_1 (d)))
  580. - g_ptr_array_insert (d->array, idx, fmt);
  581. + return TRUE;
  582. +}
  583. +
  584. +static gboolean
  585. +foreach_func_no_dmabuf (GstCapsFeatures *features,
  586. + GstStructure *structure,
  587. + ConvertData *d)
  588. +{
  589. + if (features && gst_caps_features_contains (features, GST_CAPS_FEATURE_MEMORY_DMABUF))
  590. + return TRUE;
  591. +
  592. + d->cf = features;
  593. + d->cs = structure;
  594. +
  595. + handle_fields (d);
  596. return TRUE;
  597. }
  598. GPtrArray *
  599. -gst_caps_to_format_all (GstCaps *caps, uint32_t id)
  600. +gst_caps_to_format_all (GstCaps *caps)
  601. {
  602. ConvertData d;
  603. - spa_zero (d);
  604. - d.id = id;
  605. d.array = g_ptr_array_new_full (gst_caps_get_size (caps), (GDestroyNotify)g_free);
  606. - gst_caps_foreach (caps, (GstCapsForeachFunc) foreach_func, &d);
  607. + gst_caps_foreach (caps, (GstCapsForeachFunc) foreach_func_dmabuf, &d);
  608. + gst_caps_foreach (caps, (GstCapsForeachFunc) foreach_func_no_dmabuf, &d);
  609. return d.array;
  610. }
  611. typedef const char *(*id_to_string_func)(uint32_t id);
  612. static const char *video_id_to_string(uint32_t id)
  613. {
  614. int idx;
  615. if ((idx = find_index(video_format_map, SPA_N_ELEMENTS(video_format_map), id)) == -1)
  616. return NULL;
  617. return gst_video_format_to_string(idx);
  618. }
  619. +#ifdef HAVE_GSTREAMER_DMA_DRM
  620. +static char *video_id_to_dma_drm_fourcc(uint32_t id, uint64_t mod)
  621. +{
  622. + int idx;
  623. + guint32 fourcc;
  624. + if ((idx = find_index(video_format_map, SPA_N_ELEMENTS(video_format_map), id)) == -1)
  625. + return NULL;
  626. + fourcc = gst_video_dma_drm_fourcc_from_format(idx);
  627. + return gst_video_dma_drm_fourcc_to_string(fourcc, mod);
  628. +}
  629. +#endif
  630. +
  631. static const char *audio_id_to_string(uint32_t id)
  632. {
  633. int idx;
  634. @@ -762,6 +868,109 @@ handle_id_prop (const struct spa_pod_prop *prop, const char *key, id_to_string_f
  635. }
  636. }
  637. +static void
  638. +handle_dmabuf_prop (const struct spa_pod_prop *prop,
  639. + const struct spa_pod_prop *prop_modifier, GstCaps *res)
  640. +{
  641. + g_autoptr (GPtrArray) fmt_array = NULL;
  642. + g_autoptr (GPtrArray) drm_fmt_array = NULL;
  643. + const struct spa_pod *pod_modifier;
  644. + struct spa_pod *val;
  645. + uint32_t *id, n_fmts, n_mods, choice, i, j;
  646. + uint64_t *mods;
  647. +
  648. +
  649. + val = spa_pod_get_values (&prop->value, &n_fmts, &choice);
  650. + if (val->type != SPA_TYPE_Id)
  651. + return;
  652. +
  653. + id = SPA_POD_BODY (val);
  654. + if (n_fmts > 1) {
  655. + n_fmts--;
  656. + id++;
  657. + }
  658. +
  659. + pod_modifier = &prop_modifier->value;
  660. + mods = SPA_POD_CHOICE_VALUES (pod_modifier);
  661. + n_mods = SPA_POD_CHOICE_N_VALUES (pod_modifier);
  662. + if (n_mods > 1) {
  663. + n_mods--;
  664. + mods++;
  665. + }
  666. +
  667. + fmt_array = g_ptr_array_new_with_free_func (g_free);
  668. + drm_fmt_array = g_ptr_array_new_with_free_func (g_free);
  669. +
  670. + for (i = 0; i < n_fmts; i++) {
  671. + for (j = 0; j < n_mods; j++) {
  672. + const char *fmt_str;
  673. +
  674. + if ((mods[j] == DRM_FORMAT_MOD_LINEAR ||
  675. + mods[j] == DRM_FORMAT_MOD_INVALID) &&
  676. + (fmt_str = video_id_to_string(id[i])))
  677. + g_ptr_array_add(fmt_array, g_strdup_printf ("%s", fmt_str));
  678. +
  679. +#ifdef HAVE_GSTREAMER_DMA_DRM
  680. + {
  681. + char *drm_str;
  682. +
  683. + if ((drm_str = video_id_to_dma_drm_fourcc(id[i], mods[j])))
  684. + g_ptr_array_add(drm_fmt_array, drm_str);
  685. + }
  686. +#endif
  687. + }
  688. + }
  689. +
  690. +#ifdef HAVE_GSTREAMER_DMA_DRM
  691. + if (drm_fmt_array->len > 0) {
  692. + g_ptr_array_add (fmt_array, g_strdup_printf ("DMA_DRM"));
  693. +
  694. + if (drm_fmt_array->len == 1) {
  695. + gst_caps_set_simple (res, "drm-format", G_TYPE_STRING,
  696. + g_ptr_array_index (drm_fmt_array, 0), NULL);
  697. + } else {
  698. + GValue list = { 0 };
  699. +
  700. + g_value_init (&list, GST_TYPE_LIST);
  701. + for (i = 0; i < drm_fmt_array->len; i++) {
  702. + GValue v = { 0 };
  703. +
  704. + g_value_init (&v, G_TYPE_STRING);
  705. + g_value_set_string (&v, g_ptr_array_index (drm_fmt_array, i));
  706. + gst_value_list_append_and_take_value (&list, &v);
  707. + }
  708. +
  709. + gst_caps_set_value (res, "drm-format", &list);
  710. + g_value_unset (&list);
  711. + }
  712. + }
  713. +#endif
  714. +
  715. + if (fmt_array->len > 0) {
  716. + gst_caps_set_features_simple (res,
  717. + gst_caps_features_from_string (GST_CAPS_FEATURE_MEMORY_DMABUF));
  718. +
  719. + if (fmt_array->len == 1) {
  720. + gst_caps_set_simple (res, "format", G_TYPE_STRING,
  721. + g_ptr_array_index (fmt_array, 0), NULL);
  722. + } else {
  723. + GValue list = { 0 };
  724. +
  725. + g_value_init (&list, GST_TYPE_LIST);
  726. + for (i = 0; i < fmt_array->len; i++) {
  727. + GValue v = { 0 };
  728. +
  729. + g_value_init (&v, G_TYPE_STRING);
  730. + g_value_set_string (&v, g_ptr_array_index (fmt_array, i));
  731. + gst_value_list_append_and_take_value (&list, &v);
  732. + }
  733. +
  734. + gst_caps_set_value (res, "format", &list);
  735. + g_value_unset (&list);
  736. + }
  737. + }
  738. +}
  739. +
  740. static void
  741. handle_int_prop (const struct spa_pod_prop *prop, const char *key, GstCaps *res)
  742. {
  743. @@ -916,9 +1125,17 @@ gst_caps_from_format (const struct spa_pod *format)
  744. if (media_type == SPA_MEDIA_TYPE_video) {
  745. if (media_subtype == SPA_MEDIA_SUBTYPE_raw) {
  746. + const struct spa_pod_prop *prop_modifier;
  747. +
  748. res = gst_caps_new_empty_simple ("video/x-raw");
  749. - if ((prop = spa_pod_object_find_prop (obj, prop, SPA_FORMAT_VIDEO_format))) {
  750. - handle_id_prop (prop, "format", video_id_to_string, res);
  751. +
  752. + if ((prop = spa_pod_object_find_prop (obj, prop, SPA_FORMAT_VIDEO_format)) &&
  753. + (prop_modifier = spa_pod_object_find_prop (obj, NULL, SPA_FORMAT_VIDEO_modifier))) {
  754. + handle_dmabuf_prop (prop, prop_modifier, res);
  755. + } else {
  756. + if ((prop = spa_pod_object_find_prop (obj, prop, SPA_FORMAT_VIDEO_format))) {
  757. + handle_id_prop (prop, "format", video_id_to_string, res);
  758. + }
  759. }
  760. }
  761. else if (media_subtype == SPA_MEDIA_SUBTYPE_mjpg) {
  762. diff --git a/src/gst/gstpipewireformat.h b/src/gst/gstpipewireformat.h
  763. index d82dbee20cef..abd45c4e9bbb 100644
  764. --- a/src/gst/gstpipewireformat.h
  765. +++ b/src/gst/gstpipewireformat.h
  766. @@ -11,9 +11,7 @@
  767. G_BEGIN_DECLS
  768. -struct spa_pod * gst_caps_to_format (GstCaps *caps,
  769. - guint index, uint32_t id);
  770. -GPtrArray * gst_caps_to_format_all (GstCaps *caps, uint32_t id);
  771. +GPtrArray * gst_caps_to_format_all (GstCaps *caps);
  772. GstCaps * gst_caps_from_format (const struct spa_pod *format);
  773. diff --git a/src/gst/gstpipewiresink.c b/src/gst/gstpipewiresink.c
  774. index 8a6541615ccb..2f3ec9b8bd93 100644
  775. --- a/src/gst/gstpipewiresink.c
  776. +++ b/src/gst/gstpipewiresink.c
  777. @@ -575,7 +575,7 @@ gst_pipewire_sink_setcaps (GstBaseSink * bsink, GstCaps * caps)
  778. pwsink = GST_PIPEWIRE_SINK (bsink);
  779. - possible = gst_caps_to_format_all (caps, SPA_PARAM_EnumFormat);
  780. + possible = gst_caps_to_format_all (caps);
  781. pw_thread_loop_lock (pwsink->core->loop);
  782. state = pw_stream_get_state (pwsink->stream, &error);
  783. diff --git a/src/gst/gstpipewiresrc.c b/src/gst/gstpipewiresrc.c
  784. index a66ef964b9cc..f96da74ba3d0 100644
  785. --- a/src/gst/gstpipewiresrc.c
  786. +++ b/src/gst/gstpipewiresrc.c
  787. @@ -15,7 +15,6 @@
  788. #define PW_ENABLE_DEPRECATED
  789. -#include "config.h"
  790. #include "gstpipewiresrc.h"
  791. #include "gstpipewireformat.h"
  792. @@ -869,7 +868,7 @@ gst_pipewire_src_negotiate (GstBaseSrc * basesrc)
  793. }
  794. /* open a connection with these caps */
  795. - possible = gst_caps_to_format_all (possible_caps, SPA_PARAM_EnumFormat);
  796. + possible = gst_caps_to_format_all (possible_caps);
  797. /* first disconnect */
  798. pw_thread_loop_lock (pwsrc->core->loop);
  799. @@ -1013,26 +1012,47 @@ on_param_changed (void *data, uint32_t id,
  800. gst_caps_unref(pwsrc->caps);
  801. pwsrc->caps = gst_caps_from_format (param);
  802. - pwsrc->is_video = pwsrc->caps != NULL
  803. - ? gst_video_info_from_caps (&pwsrc->video_info, pwsrc->caps)
  804. - : FALSE;
  805. + if (pwsrc->caps && gst_caps_is_fixed (pwsrc->caps)) {
  806. + pwsrc->negotiated = TRUE;
  807. - pwsrc->negotiated = pwsrc->caps != NULL;
  808. +#ifdef HAVE_GSTREAMER_DMA_DRM
  809. + if (gst_video_is_dma_drm_caps (pwsrc->caps)) {
  810. + if (!gst_video_info_dma_drm_from_caps (&pwsrc->drm_info, pwsrc->caps)) {
  811. + GST_WARNING_OBJECT (pwsrc, "Can't create drm video info from caps");
  812. + pw_stream_set_error (pwsrc->stream, -EINVAL, "internal error");
  813. + return;
  814. + }
  815. - if (pwsrc->negotiated) {
  816. + if (!gst_video_info_dma_drm_to_video_info (&pwsrc->drm_info,
  817. + &pwsrc->video_info)) {
  818. + GST_WARNING_OBJECT (pwsrc, "Can't create video info from drm video info");
  819. + pw_stream_set_error (pwsrc->stream, -EINVAL, "internal error");
  820. + return;
  821. + }
  822. +
  823. + pwsrc->is_video = TRUE;
  824. + } else {
  825. + gst_video_info_dma_drm_init (&pwsrc->drm_info);
  826. +#endif
  827. + pwsrc->is_video = gst_video_info_from_caps (&pwsrc->video_info,
  828. + pwsrc->caps);
  829. +#ifdef HAVE_GSTREAMER_DMA_DRM
  830. + }
  831. +#endif
  832. + } else {
  833. + pwsrc->negotiated = FALSE;
  834. + pwsrc->is_video = FALSE;
  835. + }
  836. +
  837. + if (pwsrc->caps) {
  838. const struct spa_pod *params[4];
  839. struct spa_pod_builder b = { NULL };
  840. uint8_t buffer[512];
  841. uint32_t buffers = CLAMP (16, pwsrc->min_buffers, pwsrc->max_buffers);
  842. int buffertypes;
  843. buffertypes = (1<<SPA_DATA_DmaBuf);
  844. - if (spa_pod_find_prop (param, NULL, SPA_FORMAT_VIDEO_modifier)) {
  845. - gst_caps_features_remove (gst_caps_get_features (pwsrc->caps, 0),
  846. - GST_CAPS_FEATURE_MEMORY_SYSTEM_MEMORY);
  847. - gst_caps_features_add (gst_caps_get_features (pwsrc->caps, 0),
  848. - GST_CAPS_FEATURE_MEMORY_DMABUF);
  849. - } else {
  850. + if (!spa_pod_find_prop (param, NULL, SPA_FORMAT_VIDEO_modifier)) {
  851. buffertypes |= ((1<<SPA_DATA_MemFd) | (1<<SPA_DATA_MemPtr));
  852. }
  853. diff --git a/src/gst/gstpipewiresrc.h b/src/gst/gstpipewiresrc.h
  854. index 97f636fb301f..0a61853f50ec 100644
  855. --- a/src/gst/gstpipewiresrc.h
  856. +++ b/src/gst/gstpipewiresrc.h
  857. @@ -5,6 +5,8 @@
  858. #ifndef __GST_PIPEWIRE_SRC_H__
  859. #define __GST_PIPEWIRE_SRC_H__
  860. +#include "config.h"
  861. +
  862. #include <gst/gst.h>
  863. #include <gst/base/gstpushsrc.h>
  864. @@ -56,6 +58,9 @@ struct _GstPipeWireSrc {
  865. gboolean is_video;
  866. GstVideoInfo video_info;
  867. +#ifdef HAVE_GSTREAMER_DMA_DRM
  868. + GstVideoInfoDmaDrm drm_info;
  869. +#endif
  870. gboolean negotiated;
  871. gboolean flushing;