blob: 0a4691b05803eede81a9eeb15d4d7a820b6de454
1 | /* |
2 | * Copyright (c) 2014 Amlogic, Inc. All rights reserved. |
3 | * |
4 | * This source code is subject to the terms and conditions defined in the |
5 | * file 'LICENSE' which is part of this source code package. |
6 | * |
7 | * Description: |
8 | */ |
9 | |
10 | |
11 | #include <stdio.h> |
12 | #include <fcntl.h> |
13 | #include <errno.h> |
14 | #include <sys/mman.h> |
15 | #include <sys/ioctl.h> |
16 | |
17 | #include "amlv4l.h" |
18 | #include "amvdec_priv.h" |
19 | #define V4LDEVICE_NAME "/dev/video10" |
20 | |
21 | static int amlv4l_unmapbufs(amvideo_dev_t *dev); |
22 | static int amlv4l_mapbufs(amvideo_dev_t *dev); |
23 | int amlv4l_setfmt(amvideo_dev_t *dev, struct v4l2_format *fmt); |
24 | int amlv4l_stop(amvideo_dev_t *dev); |
25 | int amlv4l_release(amvideo_dev_t *dev); |
26 | int amlv4l_init(amvideo_dev_t *dev, int type, int width, int height, int fmt) |
27 | { |
28 | int ret; |
29 | amlv4l_dev_t *v4l = dev->devpriv; |
30 | struct v4l2_format v4lfmt; |
31 | ret = open(V4LDEVICE_NAME, O_RDWR | O_NONBLOCK); |
32 | if (ret < 0) { |
33 | LOGE("v4l device opend failed!,ret=%d,%s(%d)\n", ret, strerror(errno), errno); |
34 | return errno; |
35 | } |
36 | v4l->v4l_fd = ret; |
37 | v4l->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
38 | v4l->width = width; |
39 | v4l->height = height; |
40 | v4l->pixformat = fmt; |
41 | v4lfmt.type = v4l->type; |
42 | v4lfmt.fmt.pix.width = v4l->width; |
43 | v4lfmt.fmt.pix.height = v4l->height; |
44 | v4lfmt.fmt.pix.pixelformat = v4l->pixformat; |
45 | ret = amlv4l_setfmt(dev, &v4lfmt); |
46 | if (ret != 0) { |
47 | goto error_out; |
48 | } |
49 | ret = amlv4l_mapbufs(dev); |
50 | error_out: |
51 | return ret; |
52 | } |
53 | |
54 | static int amlv4l_ioctl(amvideo_dev_t *dev, int request, void *arg) |
55 | { |
56 | int ret; |
57 | amlv4l_dev_t *v4l = dev->devpriv; |
58 | ret = ioctl(v4l->v4l_fd, request, arg); |
59 | if (ret == -1 && errno) { |
60 | LOGE("amlv4l_ioctlfailed!,request=%x,ret=%d,%s(%d)\n", request, ret, strerror(errno), errno); |
61 | ret = -errno; |
62 | } |
63 | return ret; |
64 | } |
65 | |
66 | int amlv4l_release(amvideo_dev_t *dev) |
67 | { |
68 | int ret = -1; |
69 | amlv4l_dev_t *v4l = dev->devpriv; |
70 | if (v4l->v4l_fd < 0) { |
71 | return 0; |
72 | } |
73 | amlv4l_stop(dev); |
74 | amlv4l_unmapbufs(dev); |
75 | if (v4l->v4l_fd >= 0) { |
76 | ret = close(v4l->v4l_fd); |
77 | } |
78 | v4l->v4l_fd = -1; |
79 | free(dev); |
80 | if (ret == -1 && errno) { |
81 | ret = -errno; |
82 | } |
83 | |
84 | return ret; |
85 | } |
86 | |
87 | int amlv4l_dequeue_buf(amvideo_dev_t *dev, vframebuf_t *vf) |
88 | { |
89 | struct v4l2_buffer vbuf; |
90 | int ret; |
91 | amlv4l_dev_t *v4l = dev->devpriv; |
92 | vbuf.type = v4l->type; |
93 | vbuf.memory = V4L2_MEMORY_MMAP; |
94 | vbuf.index = v4l->bufferNum; |
95 | ret = amlv4l_ioctl(dev, VIDIOC_DQBUF, &vbuf); |
96 | if (!ret && vbuf.index < v4l->bufferNum) { |
97 | memcpy(vf, &v4l->vframe[vbuf.index], sizeof(vframebuf_t)); |
98 | } |
99 | return ret; |
100 | } |
101 | |
102 | int amlv4l_queue_buf(amvideo_dev_t *dev, vframebuf_t *vf) |
103 | { |
104 | struct v4l2_buffer vbuf; |
105 | int ret; |
106 | amlv4l_dev_t *v4l = dev->devpriv; |
107 | vbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
108 | vbuf.memory = V4L2_MEMORY_MMAP; |
109 | vbuf.index = vf->index; |
110 | return amlv4l_ioctl(dev, VIDIOC_QBUF, &vbuf); |
111 | } |
112 | |
113 | int amlv4l_start(amvideo_dev_t *dev) |
114 | { |
115 | int type; |
116 | amlv4l_dev_t *v4l = dev->devpriv; |
117 | type = v4l->type; |
118 | return amlv4l_ioctl(dev, VIDIOC_STREAMON, &type); |
119 | } |
120 | |
121 | int amlv4l_stop(amvideo_dev_t *dev) |
122 | { |
123 | int type; |
124 | amlv4l_dev_t *v4l = dev->devpriv; |
125 | type = v4l->type; |
126 | return amlv4l_ioctl(dev, VIDIOC_STREAMOFF, &type); |
127 | } |
128 | |
129 | |
130 | int amlv4l_setfmt(amvideo_dev_t *dev, struct v4l2_format *fmt) |
131 | { |
132 | return amlv4l_ioctl(dev, VIDIOC_S_FMT, fmt); |
133 | } |
134 | |
135 | |
136 | static int amlv4l_unmapbufs(amvideo_dev_t *dev) |
137 | { |
138 | int i, ret; |
139 | amlv4l_dev_t *v4l = dev->devpriv; |
140 | vframebuf_t *vf = v4l->vframe; |
141 | ret = 0; |
142 | if (!vf) { |
143 | return 0; |
144 | } |
145 | for (i = 0; i < v4l->bufferNum; i++) { |
146 | if (vf[i].vbuf == NULL || vf[i].vbuf == MAP_FAILED) { |
147 | continue; |
148 | } |
149 | ret = munmap(vf[i].vbuf, vf[i].length); |
150 | vf[i].vbuf = NULL; |
151 | } |
152 | free(v4l->vframe); |
153 | v4l->vframe = NULL; |
154 | return ret; |
155 | } |
156 | |
157 | static int amlv4l_mapbufs(amvideo_dev_t *dev) |
158 | { |
159 | struct v4l2_buffer vbuf; |
160 | int ret; |
161 | int i; |
162 | amlv4l_dev_t *v4l = dev->devpriv; |
163 | vframebuf_t *vf; |
164 | struct v4l2_requestbuffers req; |
165 | |
166 | req.count = 4; |
167 | req.type = v4l->type;; |
168 | req.memory = v4l->memory_mode; ; |
169 | ret = amlv4l_ioctl(dev, VIDIOC_REQBUFS, &req); |
170 | if (ret != 0) { |
171 | LOGE("VIDIOC_REQBUFS failed,ret=%d\n", ret); |
172 | return ret; |
173 | } |
174 | v4l->bufferNum = req.count; |
175 | vf = (vframebuf_t *)malloc(sizeof(vframebuf_t) * req.count); |
176 | if (!vf) { |
177 | goto errors_out; |
178 | } |
179 | v4l->vframe = vf; |
180 | vbuf.type = v4l->type; |
181 | vbuf.memory = v4l->memory_mode; |
182 | for (i = 0; i < v4l->bufferNum; i++) { |
183 | vbuf.index = i; |
184 | ret = amlv4l_ioctl(dev, VIDIOC_QUERYBUF, &vbuf); |
185 | if (ret < 0) { |
186 | LOGE("VIDIOC_QUERYBUF,ret=%d\n", ret); |
187 | goto errors_out; |
188 | } |
189 | |
190 | vf[i].index = i; |
191 | vf[i].offset = vbuf.m.offset; |
192 | vf[i].pts = 0; |
193 | vf[i].duration = 0; |
194 | vf[i].vbuf = mmap(NULL, vbuf.length, PROT_READ | PROT_WRITE, MAP_SHARED, v4l->v4l_fd, vbuf.m.offset); |
195 | if (vf[i].vbuf == NULL || vf[i].vbuf == MAP_FAILED) { |
196 | LOGE("mmap failed,index=%d,ret=%p, errstr=%s\n", i, vf[i].vbuf, strerror(errno)); |
197 | ret = -errno; |
198 | goto errors_out; |
199 | } |
200 | vf[i].length = vbuf.length; |
201 | LOGI("mmaped buf %d,off=%d,vbuf=%p,len=%d\n", vf[i].index, vf[i].offset, vf[i].vbuf, vf[i].length); |
202 | } |
203 | LOGI("mmap ok,bufnum=%d\n", i); |
204 | return 0; |
205 | errors_out: |
206 | amlv4l_unmapbufs(dev); |
207 | return ret; |
208 | } |
209 | |
210 | amvideo_dev_t *new_amlv4l(void) |
211 | { |
212 | //... |
213 | amvideo_dev_t *dev; |
214 | amlv4l_dev_t *v4l; |
215 | dev = malloc(sizeof(amvideo_dev_t) + sizeof(amlv4l_dev_t)); |
216 | memset(dev, 0, sizeof(amvideo_dev_t) + sizeof(amlv4l_dev_t)); |
217 | dev->devpriv = (void *)((unsigned long)(&dev->devpriv) + 4); |
218 | v4l = dev->devpriv; |
219 | v4l->memory_mode = V4L2_MEMORY_MMAP; |
220 | dev->ops.init = amlv4l_init; |
221 | dev->ops.release = amlv4l_release; |
222 | dev->ops.dequeuebuf = amlv4l_dequeue_buf; |
223 | dev->ops.queuebuf = amlv4l_queue_buf; |
224 | dev->ops.start = amlv4l_start; |
225 | dev->ops.stop = amlv4l_stop; |
226 | /**/ |
227 | return dev; |
228 | } |
229 | |
230 |