1 /*
2 [title]
3 \ref page_tutorial5
4 [title]
5 */
6 /* [code] */
7 #include <spa/param/video/format-utils.h>
8 #include <spa/debug/types.h>
9 #include <spa/param/video/type-info.h>
10
11 #include <pipewire/pipewire.h>
12
13 struct data {
14 struct pw_main_loop *loop;
15 struct pw_stream *stream;
16
17 struct spa_video_info format;
18 };
19
20 /* [on_process] */
on_process(void * userdata)21 static void on_process(void *userdata)
22 {
23 struct data *data = userdata;
24 struct pw_buffer *b;
25 struct spa_buffer *buf;
26
27 if ((b = pw_stream_dequeue_buffer(data->stream)) == NULL) {
28 pw_log_warn("out of buffers: %m");
29 return;
30 }
31
32 buf = b->buffer;
33 if (buf->datas[0].data == NULL)
34 return;
35
36 /** copy frame data to screen */
37 printf("got a frame of size %d\n", buf->datas[0].chunk->size);
38
39 pw_stream_queue_buffer(data->stream, b);
40 }
41 /* [on_process] */
42
on_param_changed(void * userdata,uint32_t id,const struct spa_pod * param)43 static void on_param_changed(void *userdata, uint32_t id, const struct spa_pod *param)
44 {
45 struct data *data = userdata;
46
47 if (param == NULL || id != SPA_PARAM_Format)
48 return;
49
50 if (spa_format_parse(param,
51 &data->format.media_type,
52 &data->format.media_subtype) < 0)
53 return;
54
55 if (data->format.media_type != SPA_MEDIA_TYPE_video ||
56 data->format.media_subtype != SPA_MEDIA_SUBTYPE_raw)
57 return;
58
59 if (spa_format_video_raw_parse(param, &data->format.info.raw) < 0)
60 return;
61
62 printf("got video format:\n");
63 printf(" format: %d (%s)\n", data->format.info.raw.format,
64 spa_debug_type_find_name(spa_type_video_format,
65 data->format.info.raw.format));
66 printf(" size: %dx%d\n", data->format.info.raw.size.width,
67 data->format.info.raw.size.height);
68 printf(" framerate: %d/%d\n", data->format.info.raw.framerate.num,
69 data->format.info.raw.framerate.denom);
70
71 /** prepare to render video of this size */
72 }
73
74 static const struct pw_stream_events stream_events = {
75 PW_VERSION_STREAM_EVENTS,
76 .param_changed = on_param_changed,
77 .process = on_process,
78 };
79
main(int argc,char * argv[])80 int main(int argc, char *argv[])
81 {
82 struct data data = { 0, };
83 const struct spa_pod *params[1];
84 uint8_t buffer[1024];
85 struct spa_pod_builder b = SPA_POD_BUILDER_INIT(buffer, sizeof(buffer));
86
87 pw_init(&argc, &argv);
88
89 data.loop = pw_main_loop_new(NULL);
90
91 data.stream = pw_stream_new_simple(
92 pw_main_loop_get_loop(data.loop),
93 "video-capture",
94 pw_properties_new(
95 PW_KEY_MEDIA_TYPE, "Video",
96 PW_KEY_MEDIA_CATEGORY, "Capture",
97 PW_KEY_MEDIA_ROLE, "Camera",
98 NULL),
99 &stream_events,
100 &data);
101
102 params[0] = spa_pod_builder_add_object(&b,
103 SPA_TYPE_OBJECT_Format, SPA_PARAM_EnumFormat,
104 SPA_FORMAT_mediaType, SPA_POD_Id(SPA_MEDIA_TYPE_video),
105 SPA_FORMAT_mediaSubtype, SPA_POD_Id(SPA_MEDIA_SUBTYPE_raw),
106 SPA_FORMAT_VIDEO_format, SPA_POD_CHOICE_ENUM_Id(7,
107 SPA_VIDEO_FORMAT_RGB,
108 SPA_VIDEO_FORMAT_RGB,
109 SPA_VIDEO_FORMAT_RGBA,
110 SPA_VIDEO_FORMAT_RGBx,
111 SPA_VIDEO_FORMAT_BGRx,
112 SPA_VIDEO_FORMAT_YUY2,
113 SPA_VIDEO_FORMAT_I420),
114 SPA_FORMAT_VIDEO_size, SPA_POD_CHOICE_RANGE_Rectangle(
115 &SPA_RECTANGLE(320, 240),
116 &SPA_RECTANGLE(1, 1),
117 &SPA_RECTANGLE(4096, 4096)),
118 SPA_FORMAT_VIDEO_framerate, SPA_POD_CHOICE_RANGE_Fraction(
119 &SPA_FRACTION(25, 1),
120 &SPA_FRACTION(0, 1),
121 &SPA_FRACTION(1000, 1)));
122
123 pw_stream_connect(data.stream,
124 PW_DIRECTION_INPUT,
125 argc > 1 ? (uint32_t)atoi(argv[1]) : PW_ID_ANY,
126 PW_STREAM_FLAG_AUTOCONNECT |
127 PW_STREAM_FLAG_MAP_BUFFERS,
128 params, 1);
129
130 pw_main_loop_run(data.loop);
131
132 pw_stream_destroy(data.stream);
133 pw_main_loop_destroy(data.loop);
134
135 return 0;
136 }
137 /* [code] */
138