1 #include <errno.h>
2 #include <fcntl.h>
3 #include <linux/dma-heap.h>
4 #include <linux/videodev2.h>
5 #include <stdint.h>
6 #include <stdio.h>
7 #include <string.h>
8 #include <sys/ioctl.h>
9 #include <sys/mman.h>
10 #include <sys/stat.h>
11 #include <sys/types.h>
12 #include <unistd.h>
13
14 #include "v4l2r.h"
15
16 struct allocated_dmabufs {
17 size_t nb_buffers;
18 struct v4l2r_video_frame buffers[16];
19 };
20
21 // Helper function to allocate DMABUF memory from a V4L2 device.
22 static struct allocated_dmabufs
allocate_dmabufs(const struct v4l2_format * format,size_t nb_buffers)23 allocate_dmabufs(const struct v4l2_format *format,
24 size_t nb_buffers) {
25 struct allocated_dmabufs dmabufs;
26 int dma_device;
27 int ret;
28 int i;
29
30 memset(&dmabufs, 0, sizeof(dmabufs));
31
32 dma_device = open("/dev/dma_heap/system", O_RDWR | O_CLOEXEC);
33 if (dma_device < 0) {
34 perror("error opening DMA heap device /dev/dma_heap/system");
35 goto end;
36 }
37
38 for (i = 0; i < nb_buffers; i++) {
39 struct dma_heap_allocation_data allocation_data;
40
41 // TODO support multiple planes? This is not strictly needed for
42 // FWHT/RGB3...
43 memset(&allocation_data, 0, sizeof(allocation_data));
44 allocation_data.len = format->fmt.pix_mp.plane_fmt[0].sizeimage;
45 allocation_data.fd_flags = O_CLOEXEC | O_RDWR;
46 ret = ioctl(dma_device, DMA_HEAP_IOCTL_ALLOC, &allocation_data);
47 if (ret < 0) {
48 perror("error while allocating DMA memory");
49 goto close_dev;
50 }
51
52 dmabufs.buffers[i].id = i;
53 dmabufs.buffers[i].num_planes = 1;
54 dmabufs.buffers[i].planes[0] = allocation_data.fd;
55 }
56
57 dmabufs.nb_buffers = nb_buffers;
58
59 close_dev:
60 close(dma_device);
61
62 end:
63 return dmabufs;
64 }
65
66 static const char *input_file_path = "sample.fwht";
67 static size_t input_frame_sizes[] = {
68 39504, 5822, 42410, 5822, 42106, 5822, 41802, 7646, 40606, 8468,
69 42640, 6644, 42928, 6644, 42624, 8468, 40540, 8846, 43002, 8846,
70 };
71
72 static const struct v4l2r_video_frame_provider *capture_provider = NULL;
73 static bool drain_completed = false;
74
75 const char *device_path = "/dev/video1";
76
on_input_done(void * ptr,const struct v4l2_buffer * buffer)77 static void on_input_done(void *ptr, const struct v4l2_buffer *buffer) {
78 printf("Input buffer %d done\n", buffer->index);
79 }
80
81 static void
on_frame_decoded(void * ptr,const struct v4l2r_decoder_frame_decoded_event * event)82 on_frame_decoded(void *ptr,
83 const struct v4l2r_decoder_frame_decoded_event *event) {
84 printf("Frame %d decoded, size: %d, timestamp: %ld\n",
85 event->buffer->index, event->buffer->m.planes[0].bytesused,
86 event->buffer->timestamp.tv_sec);
87
88 printf("Recycling frame %d\n", event->frame.id);
89 v4l2r_video_frame_provider_queue_frame(capture_provider, event->frame);
90 }
91
92 static struct allocated_dmabufs dmabufs;
93
94 static void
on_format_change(void * ptr,const struct v4l2r_decoder_format_changed_event * event)95 on_format_change(void *ptr,
96 const struct v4l2r_decoder_format_changed_event *event) {
97 const struct v4l2_format *format = event->new_format;
98 const struct v4l2_rect *visible_rect = &event->visible_rect;
99 char fmt[4];
100 int i;
101
102 *((uint32_t*)&fmt) = format->fmt.pix_mp.pixelformat;
103 printf("New CAPTURE format: %c%c%c%c, %dx%d, min frames: %d visible rect: "
104 "(%d,%d),%ux%u \n",
105 fmt[0], fmt[1], fmt[2], fmt[3], format->fmt.pix_mp.width,
106 format->fmt.pix_mp.height, event->min_num_frames, visible_rect->left,
107 visible_rect->top, visible_rect->width, visible_rect->height);
108
109 if (capture_provider)
110 v4l2r_video_frame_provider_drop(capture_provider);
111 capture_provider = event->new_provider;
112
113 dmabufs = allocate_dmabufs(format, event->min_num_frames);
114 printf("Got %zu CAPTURE frames\n", dmabufs.nb_buffers);
115 for (i = 0; i < dmabufs.nb_buffers; i++)
116 v4l2r_video_frame_provider_queue_frame(capture_provider,
117 dmabufs.buffers[i]);
118 }
119
on_event(void * ptr,struct v4l2r_decoder_event * event)120 void on_event(void *ptr, struct v4l2r_decoder_event *event) {
121 switch (event->tag) {
122 case FrameDecoded:
123 on_frame_decoded(ptr, &event->frame_decoded);
124 break;
125 case FormatChanged:
126 on_format_change(ptr, &event->format_changed);
127 break;
128 case EndOfStream:
129 printf("Drain completed!\n");
130 drain_completed = true;
131 break;
132 }
133 }
134
main()135 int main() {
136 struct allocated_dmabufs dmabufs;
137 struct v4l2_format output_format;
138 size_t output_buffer_size;
139 int output_dmabuf;
140 char fmt[4];
141 int i;
142 int ret;
143
144 FILE *input_file = fopen(input_file_path, "r");
145 if (!input_file) {
146 perror("Cannot open input file");
147 return 1;
148 }
149
150 v4l2r_init();
151
152 struct v4l2r_decoder *decoder =
153 v4l2r_decoder_new(device_path, V4L2_PIX_FMT_FWHT, 1, 0, 0, on_input_done,
154 on_event, (void *)0xdeadbeef);
155
156 ret = v4l2r_decoder_get_input_format(decoder, &output_format);
157 if (ret < 0)
158 return ret;
159 *((uint32_t*)&fmt) = output_format.fmt.pix_mp.pixelformat;
160 printf("Reported OUTPUT format: %c%c%c%c, %d bytes per frame\n",
161 fmt[0], fmt[1], fmt[2], fmt[3],
162 output_format.fmt.pix_mp.plane_fmt[0].sizeimage);
163 dmabufs = allocate_dmabufs(&output_format, 1);
164 if (dmabufs.nb_buffers < 1) {
165 return -1;
166 }
167 output_dmabuf = dmabufs.buffers[0].planes[0];
168 output_buffer_size = output_format.fmt.pix_mp.plane_fmt[0].sizeimage;
169 printf("Got DMABUF: %lu %d %zu\n", dmabufs.buffers[0].num_planes,
170 dmabufs.buffers[0].planes[0], output_buffer_size);
171
172 for (i = 0; i < 20; i++) {
173 size_t frame_bytes_used = input_frame_sizes[i];
174 void *mapping = mmap(NULL, output_buffer_size, PROT_READ | PROT_WRITE,
175 MAP_SHARED, output_dmabuf, 0);
176 if (!mapping) {
177 perror("Error while mapping");
178 return 1;
179 }
180 if (fread(mapping, frame_bytes_used, 1, input_file) != 1) {
181 perror("Error reading file");
182 return 1;
183 }
184 munmap(mapping, output_buffer_size);
185
186 ret = v4l2r_decoder_decode(decoder, i, output_dmabuf, frame_bytes_used);
187 if (ret < 0)
188 return 1;
189 }
190
191 v4l2r_decoder_drain(decoder, false);
192 while (!drain_completed)
193 usleep(10000);
194
195 v4l2r_decoder_destroy(decoder);
196 if (capture_provider)
197 v4l2r_video_frame_provider_drop(capture_provider);
198 printf("Decoding complete\n");
199
200 close(output_dmabuf);
201 fclose(input_file);
202
203 return 0;
204 }
205