• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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