1 /*****************************************************************************
2 * gstvlcpictureplaneallocator.c: VLC pictures wrapped by GstAllocator
3 *****************************************************************************
4 * Copyright (C) 2016 VLC authors and VideoLAN
5 * $Id:
6 *
7 * Author: Vikram Fugro <vikram.fugro@gmail.com>
8 *
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Library General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Library General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 *****************************************************************************/
23
24 /*****************************************************************************
25 * Preamble
26 *****************************************************************************/
27 #include <gst/gst.h>
28
29 #include "gstvlcpictureplaneallocator.h"
30
31 #include <vlc_common.h>
32
33 #define gst_vlc_picture_plane_allocator_parent_class parent_class
34 G_DEFINE_TYPE (GstVlcPicturePlaneAllocator, gst_vlc_picture_plane_allocator, \
35 GST_TYPE_ALLOCATOR);
36
37 static void gst_vlc_picture_plane_allocator_finalize( GObject *p_object );
38 static GstMemory* gst_vlc_picture_plane_allocator_dummy_alloc(
39 GstAllocator* p_allocator, gsize i_size,
40 GstAllocationParams *p_params );
41 static void gst_vlc_picture_plane_allocator_free( GstAllocator *p_allocator,
42 GstMemory *p_gmem);
43 static gpointer gst_vlc_picture_plane_map( GstMemory *p_gmem,
44 gsize i_maxsize, GstMapFlags flags );
45 static gboolean gst_vlc_picture_plane_unmap( GstVlcPicturePlane *p_mem );
46 static GstMemory* gst_vlc_picture_plane_copy(
47 GstVlcPicturePlane *p_mem, gssize i_offset, gssize i_size );
48
49 #define GST_VLC_PICTURE_PLANE_ALLOCATOR_NAME "vlcpictureplane"
50
gst_vlc_picture_plane_allocator_class_init(GstVlcPicturePlaneAllocatorClass * p_klass)51 static void gst_vlc_picture_plane_allocator_class_init(
52 GstVlcPicturePlaneAllocatorClass *p_klass )
53 {
54 GObjectClass *p_gobject_class;
55 GstAllocatorClass *p_allocator_class;
56
57 p_gobject_class = (GObjectClass*) p_klass;
58 p_allocator_class = (GstAllocatorClass*) p_klass;
59
60 p_gobject_class->finalize = gst_vlc_picture_plane_allocator_finalize;
61
62 p_allocator_class->alloc = gst_vlc_picture_plane_allocator_dummy_alloc;
63 p_allocator_class->free = gst_vlc_picture_plane_allocator_free;
64 }
65
gst_vlc_picture_plane_allocator_init(GstVlcPicturePlaneAllocator * p_allocator)66 static void gst_vlc_picture_plane_allocator_init(
67 GstVlcPicturePlaneAllocator *p_allocator )
68 {
69 GstAllocator *p_alloc = GST_ALLOCATOR_CAST( p_allocator );
70
71 p_alloc->mem_type = GST_VLC_PICTURE_PLANE_ALLOCATOR_NAME;
72 p_alloc->mem_map = (GstMemoryMapFunction) gst_vlc_picture_plane_map;
73 p_alloc->mem_unmap = (GstMemoryUnmapFunction) gst_vlc_picture_plane_unmap;
74 p_alloc->mem_copy = (GstMemoryShareFunction) gst_vlc_picture_plane_copy;
75 /* fallback is_span */
76
77 GST_OBJECT_FLAG_SET( p_allocator, GST_ALLOCATOR_FLAG_CUSTOM_ALLOC );
78 }
79
gst_vlc_picture_plane_allocator_finalize(GObject * p_object)80 static void gst_vlc_picture_plane_allocator_finalize( GObject *p_object )
81 {
82 GstVlcPicturePlaneAllocator *p_alloc = GST_VLC_PICTURE_PLANE_ALLOCATOR(
83 p_object );
84 VLC_UNUSED( p_alloc );
85
86 G_OBJECT_CLASS (parent_class)->finalize( p_object );
87 }
88
gst_vlc_picture_plane_allocator_dummy_alloc(GstAllocator * p_allocator,gsize i_size,GstAllocationParams * p_params)89 static GstMemory* gst_vlc_picture_plane_allocator_dummy_alloc(
90 GstAllocator* p_allocator, gsize i_size, GstAllocationParams *p_params )
91 {
92 VLC_UNUSED( p_allocator );
93 VLC_UNUSED( i_size );
94 VLC_UNUSED( p_params );
95 return NULL;
96 }
97
gst_vlc_picture_plane_allocator_free(GstAllocator * p_allocator,GstMemory * p_gmem)98 static void gst_vlc_picture_plane_allocator_free( GstAllocator *p_allocator,
99 GstMemory *p_gmem)
100 {
101 VLC_UNUSED( p_allocator );
102 GstVlcPicturePlane *p_mem = (GstVlcPicturePlane*) p_gmem;
103 g_slice_free( GstVlcPicturePlane, p_mem );
104 }
105
gst_vlc_picture_plane_map(GstMemory * p_gmem,gsize i_maxsize,GstMapFlags flags)106 static gpointer gst_vlc_picture_plane_map( GstMemory *p_gmem,
107 gsize i_maxsize, GstMapFlags flags )
108 {
109 VLC_UNUSED( i_maxsize );
110 VLC_UNUSED( flags );
111 GstVlcPicturePlane* p_mem = (GstVlcPicturePlane*) p_gmem;
112
113 if( p_mem->p_pic )
114 return (gpointer) (p_mem->p_plane->p_pixels + p_mem->parent.offset);
115 else
116 return NULL;
117 }
118
gst_vlc_picture_plane_unmap(GstVlcPicturePlane * p_mem)119 static gboolean gst_vlc_picture_plane_unmap(
120 GstVlcPicturePlane *p_mem )
121 {
122 VLC_UNUSED( p_mem );
123 return TRUE;
124 }
125
gst_vlc_picture_plane_copy(GstVlcPicturePlane * p_mem,gssize i_offset,gssize i_size)126 static GstMemory* gst_vlc_picture_plane_copy(
127 GstVlcPicturePlane *p_mem, gssize i_offset, gssize i_size )
128 {
129 VLC_UNUSED( p_mem );
130 VLC_UNUSED( i_offset );
131 VLC_UNUSED( i_size );
132 return NULL;
133 }
134
gst_vlc_picture_plane_allocator_release(GstVlcPicturePlaneAllocator * p_allocator,GstBuffer * p_buffer)135 void gst_vlc_picture_plane_allocator_release(
136 GstVlcPicturePlaneAllocator *p_allocator, GstBuffer *p_buffer )
137 {
138 VLC_UNUSED( p_allocator );
139
140 GstVlcPicturePlane* p_mem =
141 (GstVlcPicturePlane*) gst_buffer_peek_memory( p_buffer, 0 );
142 guint i_plane;
143
144 if( p_mem->p_pic )
145 {
146 picture_Release( p_mem->p_pic );
147
148 for( i_plane = 0; i_plane < gst_buffer_n_memory( p_buffer );
149 i_plane++ )
150 {
151 p_mem = (GstVlcPicturePlane*) gst_buffer_peek_memory ( p_buffer,
152 i_plane );
153 p_mem->p_pic = NULL;
154 p_mem->p_plane = NULL;
155 }
156 }
157 }
158
gst_vlc_picture_plane_allocator_hold(GstVlcPicturePlaneAllocator * p_allocator,GstBuffer * p_buffer)159 bool gst_vlc_picture_plane_allocator_hold(
160 GstVlcPicturePlaneAllocator *p_allocator, GstBuffer *p_buffer )
161 {
162 picture_t* p_pic = NULL;
163 decoder_t* p_dec = p_allocator->p_dec;
164 GstVlcPicturePlane *p_mem;
165 int i_plane;
166
167 if( !decoder_UpdateVideoFormat( p_dec ) )
168 p_pic = decoder_NewPicture( p_dec );
169 if( !p_pic )
170 {
171 msg_Err( p_allocator->p_dec, "failed to acquire picture from vout" );
172 return false;
173 }
174
175 for( i_plane = 0; i_plane < p_pic->i_planes; i_plane++ )
176 {
177 p_mem = (GstVlcPicturePlane*) gst_buffer_peek_memory ( p_buffer,
178 i_plane );
179 p_mem->p_pic = p_pic;
180 p_mem->p_plane = &p_pic->p[ i_plane ];
181 }
182
183 return true;
184 }
185
gst_vlc_picture_plane_allocator_alloc(GstVlcPicturePlaneAllocator * p_allocator,GstBuffer * p_buffer)186 bool gst_vlc_picture_plane_allocator_alloc(
187 GstVlcPicturePlaneAllocator *p_allocator,
188 GstBuffer *p_buffer )
189 {
190 int i_plane;
191 gsize i_max_size, i_align, i_offset, i_size;
192 picture_t *p_pic;
193
194 p_pic = &p_allocator->pic_info;
195
196 for( i_plane = 0; i_plane < p_pic->i_planes; i_plane++ )
197 {
198 GstVlcPicturePlane *p_mem =
199 (GstVlcPicturePlane*) g_slice_new0( GstVlcPicturePlane );
200
201 i_size = p_pic->p[ i_plane ].i_pitch *
202 p_pic->p[ i_plane ].i_lines;
203 i_max_size = p_pic->p[ i_plane ].i_pitch *
204 p_pic->p[ i_plane ].i_lines;
205 i_align = 0;
206 i_offset = 0;
207
208 gst_memory_init( GST_MEMORY_CAST( p_mem ), GST_MEMORY_FLAG_NO_SHARE,
209 GST_ALLOCATOR_CAST( p_allocator ), NULL, i_max_size,
210 i_align, i_offset, i_size );
211 gst_buffer_append_memory( p_buffer, (GstMemory*) p_mem );
212 }
213
214 return true;
215 }
216
gst_vlc_set_vout_fmt(GstVideoInfo * p_info,GstVideoAlignment * p_align,GstCaps * p_caps,decoder_t * p_dec)217 bool gst_vlc_set_vout_fmt( GstVideoInfo *p_info, GstVideoAlignment *p_align,
218 GstCaps *p_caps, decoder_t *p_dec )
219 {
220 es_format_t *p_outfmt = &p_dec->fmt_out;
221 video_format_t *p_voutfmt = &p_dec->fmt_out.video;
222 GstStructure *p_str = gst_caps_get_structure( p_caps, 0 );
223 vlc_fourcc_t i_chroma;
224 int i_padded_width, i_padded_height;
225
226 i_chroma = p_outfmt->i_codec = vlc_fourcc_GetCodecFromString(
227 VIDEO_ES,
228 gst_structure_get_string( p_str, "format" ) );
229 if( !i_chroma )
230 {
231 msg_Err( p_dec, "video chroma type not supported" );
232 return false;
233 }
234
235 i_padded_width = GST_VIDEO_INFO_WIDTH( p_info ) + p_align->padding_left +
236 p_align->padding_right;
237 i_padded_height = GST_VIDEO_INFO_HEIGHT( p_info ) + p_align->padding_top +
238 p_align->padding_bottom;
239
240 video_format_Setup( p_voutfmt, i_chroma, i_padded_width, i_padded_height,
241 GST_VIDEO_INFO_WIDTH( p_info ), GST_VIDEO_INFO_HEIGHT( p_info ),
242 GST_VIDEO_INFO_PAR_N( p_info ), GST_VIDEO_INFO_PAR_D( p_info ));
243 p_voutfmt->i_x_offset = p_align->padding_left;
244 p_voutfmt->i_y_offset = p_align->padding_top;
245
246 p_voutfmt->i_frame_rate = GST_VIDEO_INFO_FPS_N( p_info );
247 p_voutfmt->i_frame_rate_base = GST_VIDEO_INFO_FPS_D( p_info );
248
249 return true;
250 }
251
gst_vlc_video_info_from_vout(GstVideoInfo * p_info,GstVideoAlignment * p_align,GstCaps * p_caps,decoder_t * p_dec,picture_t * p_pic_info)252 static bool gst_vlc_video_info_from_vout( GstVideoInfo *p_info,
253 GstVideoAlignment *p_align, GstCaps *p_caps, decoder_t *p_dec,
254 picture_t *p_pic_info )
255 {
256 const GstVideoFormatInfo *p_vinfo = p_info->finfo;
257 picture_t *p_pic = NULL;
258 int i;
259
260 /* Ensure the queue is empty */
261 gst_vlc_dec_ensure_empty_queue( p_dec );
262 gst_video_info_align( p_info, p_align );
263
264 if( !gst_vlc_set_vout_fmt( p_info, p_align, p_caps, p_dec ))
265 {
266 msg_Err( p_dec, "failed to set output format to vout" );
267 return false;
268 }
269
270 /* Acquire a picture and release it. This is to get the picture
271 * stride/offsets info for the Gstreamer decoder looking to use
272 * downstream bufferpool directly; Zero-Copy */
273 if( !decoder_UpdateVideoFormat( p_dec ) )
274 p_pic = decoder_NewPicture( p_dec );
275 if( !p_pic )
276 {
277 msg_Err( p_dec, "failed to acquire picture from vout; for pic info" );
278 return false;
279 }
280
281 /* reject if strides don't match */
282 for( i = 0; i < p_pic->i_planes; i++ )
283 if( p_info->stride[i] != p_pic->p[i].i_pitch )
284 goto strides_mismatch;
285
286 p_info->offset[0] = 0;
287 for( i = 1; i < p_pic->i_planes; i++ )
288 {
289 p_info->offset[i] = p_info->offset[i-1] +
290 p_pic->p[i-1].i_pitch * p_pic->p[i-1].i_lines;
291 }
292 GST_VIDEO_INFO_SIZE( p_info ) = p_info->offset[i-1] +
293 p_pic->p[i-1].i_pitch * p_pic->p[i-1].i_lines;
294
295 for( i = 0; i < p_pic->i_planes; i++ )
296 {
297 int i_v_edge, i_h_edge;
298
299 i_h_edge =
300 GST_VIDEO_FORMAT_INFO_SCALE_WIDTH( p_vinfo, i,
301 p_align->padding_left);
302 i_v_edge =
303 GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT( p_vinfo, i,
304 p_align->padding_top);
305
306 p_info->offset[i] += ( i_v_edge * p_info->stride[i] ) +
307 ( i_h_edge * GST_VIDEO_FORMAT_INFO_PSTRIDE( p_vinfo, i ));
308 }
309
310 memcpy( p_pic_info, p_pic, sizeof( picture_t ));
311 picture_Release( p_pic );
312
313 return true;
314
315 strides_mismatch:
316 msg_Err( p_dec, "strides mismatch" );
317 picture_Release( p_pic );
318 return false;
319 }
320
gst_vlc_picture_plane_allocator_query_format(GstVlcPicturePlaneAllocator * p_allocator,GstVideoInfo * p_info,GstVideoAlignment * p_align,GstCaps * p_caps)321 bool gst_vlc_picture_plane_allocator_query_format(
322 GstVlcPicturePlaneAllocator *p_allocator, GstVideoInfo *p_info,
323 GstVideoAlignment *p_align, GstCaps *p_caps )
324 {
325 decoder_t *p_dec = p_allocator->p_dec;
326 video_format_t v_fmt;
327 picture_t *p_pic_info = &p_allocator->pic_info;
328
329 /* Back up the original format; as this is just a query */
330 v_fmt = p_dec->fmt_out.video;
331 video_format_Init( &p_dec->fmt_out.video, 0 );
332
333 bool b_ret =
334 gst_vlc_video_info_from_vout( p_info, p_align, p_caps, p_dec,
335 p_pic_info );
336
337 video_format_Clean( &p_dec->fmt_out.video );
338
339 /* Restore the original format; as this was just a query */
340 p_dec->fmt_out.video = v_fmt;
341
342 if( !b_ret )
343 {
344 msg_Err( p_allocator->p_dec, "failed to get the vout info" );
345 return false;
346 }
347
348 return true;
349 }
350
gst_vlc_picture_plane_allocator_new(decoder_t * p_dec)351 GstVlcPicturePlaneAllocator* gst_vlc_picture_plane_allocator_new(
352 decoder_t *p_dec )
353 {
354 GstVlcPicturePlaneAllocator *p_allocator;
355
356 p_allocator = g_object_new( GST_TYPE_VLC_PICTURE_PLANE_ALLOCATOR, NULL);
357 p_allocator->p_dec = p_dec;
358
359 return p_allocator;
360 }
361