summaryrefslogtreecommitdiff
path: root/amvdec/amlv4l.c (plain)
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
21static int amlv4l_unmapbufs(amvideo_dev_t *dev);
22static int amlv4l_mapbufs(amvideo_dev_t *dev);
23int amlv4l_setfmt(amvideo_dev_t *dev, struct v4l2_format *fmt);
24int amlv4l_stop(amvideo_dev_t *dev);
25int amlv4l_release(amvideo_dev_t *dev);
26int 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);
50error_out:
51 return ret;
52}
53
54static 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
66int 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
87int 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
102int 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
113int 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
121int 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
130int amlv4l_setfmt(amvideo_dev_t *dev, struct v4l2_format *fmt)
131{
132 return amlv4l_ioctl(dev, VIDIOC_S_FMT, fmt);
133}
134
135
136static 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
157static 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;
205errors_out:
206 amlv4l_unmapbufs(dev);
207 return ret;
208}
209
210amvideo_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