1 /* GStreamer
2 * Copyright (C) 2020 Nicolas Dufresne <nicolas.dufresne@collabora.com>
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
13 *
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
18 */
19
20 #include "gstv4l2format.h"
21
22 #define GST_CAT_DEFAULT gstv4l2codecs_debug
23 GST_DEBUG_CATEGORY_EXTERN (gstv4l2codecs_debug);
24
25 struct FormatEntry
26 {
27 guint32 v4l2_pix_fmt;
28 gint num_planes;
29 GstVideoFormat gst_fmt;
30 guint bitdepth;
31 gint subsampling;
32 };
33
34 static struct FormatEntry format_map[] = {
35 {V4L2_PIX_FMT_NV12, 1, GST_VIDEO_FORMAT_NV12, 8, 420},
36 {V4L2_PIX_FMT_YUYV, 1, GST_VIDEO_FORMAT_YUY2, 8, 422},
37 {V4L2_PIX_FMT_SUNXI_TILED_NV12, 1, GST_VIDEO_FORMAT_NV12_32L32, 8, 422},
38 {V4L2_PIX_FMT_NV12_4L4, 1, GST_VIDEO_FORMAT_NV12_4L4, 8, 420},
39 {0,}
40 };
41
42 static struct FormatEntry *
lookup_v4l2_fmt(guint v4l2_pix_fmt)43 lookup_v4l2_fmt (guint v4l2_pix_fmt)
44 {
45 gint i;
46 struct FormatEntry *ret = NULL;
47
48 for (i = 0; format_map[i].v4l2_pix_fmt; i++) {
49 if (format_map[i].v4l2_pix_fmt == v4l2_pix_fmt) {
50 ret = format_map + i;
51 break;
52 }
53 }
54
55 return ret;
56 }
57
58 static struct FormatEntry *
lookup_gst_fmt(GstVideoFormat gst_fmt)59 lookup_gst_fmt (GstVideoFormat gst_fmt)
60 {
61 gint i;
62 struct FormatEntry *ret = NULL;
63
64 for (i = 0; format_map[i].v4l2_pix_fmt; i++) {
65 if (format_map[i].gst_fmt == gst_fmt) {
66 ret = format_map + i;
67 break;
68 }
69 }
70
71 return ret;
72 }
73
74 static gint
extrapolate_stride(const GstVideoFormatInfo * finfo,gint plane,gint stride)75 extrapolate_stride (const GstVideoFormatInfo * finfo, gint plane, gint stride)
76 {
77 gint estride;
78
79 switch (finfo->format) {
80 case GST_VIDEO_FORMAT_NV12:
81 case GST_VIDEO_FORMAT_NV12_4L4:
82 case GST_VIDEO_FORMAT_NV12_32L32:
83 case GST_VIDEO_FORMAT_NV12_64Z32:
84 case GST_VIDEO_FORMAT_NV16:
85 case GST_VIDEO_FORMAT_NV21:
86 case GST_VIDEO_FORMAT_NV24:
87 case GST_VIDEO_FORMAT_NV61:
88 estride = (plane == 0 ? 1 : 2) *
89 GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (finfo, plane, stride);
90 break;
91 default:
92 estride = GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (finfo, plane, stride);
93 break;
94 }
95
96 return estride;
97 }
98
99 static void
set_stride(GstVideoInfo * info,gint plane,gint stride)100 set_stride (GstVideoInfo * info, gint plane, gint stride)
101 {
102 const GstVideoFormatInfo *finfo = info->finfo;
103
104 if (GST_VIDEO_FORMAT_INFO_IS_TILED (finfo)) {
105 gint x_tiles, y_tiles, ws, hs, padded_height;
106
107 ws = GST_VIDEO_FORMAT_INFO_TILE_WS (finfo);
108 hs = GST_VIDEO_FORMAT_INFO_TILE_HS (finfo);
109
110 padded_height = GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (finfo, plane,
111 info->height);
112 padded_height = GST_ROUND_UP_N (padded_height, 1 << hs);
113
114 x_tiles = stride >> ws;
115 y_tiles = padded_height >> hs;
116 info->stride[plane] = GST_VIDEO_TILE_MAKE_STRIDE (x_tiles, y_tiles);
117 } else {
118 info->stride[plane] = stride;
119 }
120 }
121
122 gboolean
gst_v4l2_format_to_video_info(struct v4l2_format * fmt,GstVideoInfo * out_info)123 gst_v4l2_format_to_video_info (struct v4l2_format *fmt, GstVideoInfo * out_info)
124 {
125 struct FormatEntry *entry = lookup_v4l2_fmt (fmt->fmt.pix_mp.pixelformat);
126 struct v4l2_pix_format_mplane *pix_mp = &fmt->fmt.pix_mp;
127 struct v4l2_pix_format *pix = &fmt->fmt.pix;
128 gint plane;
129 gsize offset = 0;
130
131 if (!entry)
132 return FALSE;
133
134 if (entry->num_planes != 1) {
135 GST_FIXME ("Multi allocation formats are not supported yet");
136 return FALSE;
137 }
138
139 if (!gst_video_info_set_format (out_info, entry->gst_fmt,
140 pix_mp->width, pix_mp->height))
141 return FALSE;
142
143 if (V4L2_TYPE_IS_MULTIPLANAR (fmt->type)) {
144 /* TODO: We don't support multi-allocation yet */
145 g_return_val_if_fail (pix_mp->num_planes == 1, FALSE);
146 out_info->size = pix_mp->plane_fmt[0].sizeimage;
147 } else {
148 out_info->size = pix->sizeimage;
149 }
150
151 for (plane = 0; plane < GST_VIDEO_INFO_N_PLANES (out_info); plane++) {
152 gint stride;
153
154 if (V4L2_TYPE_IS_MULTIPLANAR (fmt->type))
155 stride = extrapolate_stride (out_info->finfo, plane,
156 pix_mp->plane_fmt[0].bytesperline);
157 else
158 stride = extrapolate_stride (out_info->finfo, plane, pix->bytesperline);
159
160 set_stride (out_info, plane, stride);
161 out_info->offset[plane] = offset;
162
163 offset += stride * GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (out_info->finfo,
164 plane, pix_mp->height);
165 }
166
167 return TRUE;
168 }
169
170 gboolean
gst_v4l2_format_to_video_format(guint32 pix_fmt,GstVideoFormat * out_format)171 gst_v4l2_format_to_video_format (guint32 pix_fmt, GstVideoFormat * out_format)
172 {
173 struct FormatEntry *entry = lookup_v4l2_fmt (pix_fmt);
174
175 if (!entry)
176 return FALSE;
177
178 *out_format = entry->gst_fmt;
179 return TRUE;
180 }
181
182 gboolean
gst_v4l2_format_from_video_format(GstVideoFormat format,guint32 * out_pix_fmt)183 gst_v4l2_format_from_video_format (GstVideoFormat format, guint32 * out_pix_fmt)
184 {
185 struct FormatEntry *entry = lookup_gst_fmt (format);
186
187 if (!entry)
188 return FALSE;
189
190 *out_pix_fmt = entry->v4l2_pix_fmt;
191 return TRUE;
192 }
193