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