You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
377 lines
12 KiB
377 lines
12 KiB
/*****************************************************************************
|
|
* gstvlcpictureplaneallocator.c: VLC pictures wrapped by GstAllocator
|
|
*****************************************************************************
|
|
* Copyright (C) 2016 VLC authors and VideoLAN
|
|
* $Id:
|
|
*
|
|
* Author: Vikram Fugro <vikram.fugro@gmail.com>
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Library General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Library General Public
|
|
* License along with this library; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
*****************************************************************************/
|
|
|
|
/*****************************************************************************
|
|
* Preamble
|
|
*****************************************************************************/
|
|
#include <gst/gst.h>
|
|
|
|
#include "gstvlcpictureplaneallocator.h"
|
|
|
|
#include <vlc_common.h>
|
|
|
|
/* from gstreamer/fourcc.c */
|
|
vlc_fourcc_t GetGstVLCFourcc( const char* );
|
|
|
|
#define gst_vlc_picture_plane_allocator_parent_class parent_class
|
|
G_DEFINE_TYPE (GstVlcPicturePlaneAllocator, gst_vlc_picture_plane_allocator, \
|
|
GST_TYPE_ALLOCATOR);
|
|
|
|
static void gst_vlc_picture_plane_allocator_finalize( GObject *p_object );
|
|
static GstMemory* gst_vlc_picture_plane_allocator_dummy_alloc(
|
|
GstAllocator* p_allocator, gsize i_size,
|
|
GstAllocationParams *p_params );
|
|
static void gst_vlc_picture_plane_allocator_free( GstAllocator *p_allocator,
|
|
GstMemory *p_gmem);
|
|
static gpointer gst_vlc_picture_plane_map( GstMemory *p_gmem,
|
|
gsize i_maxsize, GstMapFlags flags );
|
|
static void gst_vlc_picture_plane_unmap( GstMemory *p_mem );
|
|
static GstMemory* gst_vlc_picture_plane_copy(
|
|
GstMemory *p_mem, gssize i_offset, gssize i_size );
|
|
|
|
#define GST_VLC_PICTURE_PLANE_ALLOCATOR_NAME "vlcpictureplane"
|
|
|
|
static void gst_vlc_picture_plane_allocator_class_init(
|
|
GstVlcPicturePlaneAllocatorClass *p_klass )
|
|
{
|
|
GObjectClass *p_gobject_class;
|
|
GstAllocatorClass *p_allocator_class;
|
|
|
|
p_gobject_class = (GObjectClass*) p_klass;
|
|
p_allocator_class = (GstAllocatorClass*) p_klass;
|
|
|
|
p_gobject_class->finalize = gst_vlc_picture_plane_allocator_finalize;
|
|
|
|
p_allocator_class->alloc = gst_vlc_picture_plane_allocator_dummy_alloc;
|
|
p_allocator_class->free = gst_vlc_picture_plane_allocator_free;
|
|
}
|
|
|
|
static void gst_vlc_picture_plane_allocator_init(
|
|
GstVlcPicturePlaneAllocator *p_allocator )
|
|
{
|
|
GstAllocator *p_alloc = GST_ALLOCATOR_CAST( p_allocator );
|
|
|
|
p_alloc->mem_type = GST_VLC_PICTURE_PLANE_ALLOCATOR_NAME;
|
|
p_alloc->mem_map = gst_vlc_picture_plane_map;
|
|
p_alloc->mem_unmap = gst_vlc_picture_plane_unmap;
|
|
p_alloc->mem_copy = gst_vlc_picture_plane_copy;
|
|
/* fallback is_span */
|
|
|
|
GST_OBJECT_FLAG_SET( p_allocator, GST_ALLOCATOR_FLAG_CUSTOM_ALLOC );
|
|
}
|
|
|
|
static void gst_vlc_picture_plane_allocator_finalize( GObject *p_object )
|
|
{
|
|
GstVlcPicturePlaneAllocator *p_alloc = GST_VLC_PICTURE_PLANE_ALLOCATOR(
|
|
p_object );
|
|
VLC_UNUSED( p_alloc );
|
|
|
|
G_OBJECT_CLASS (parent_class)->finalize( p_object );
|
|
}
|
|
|
|
static GstMemory* gst_vlc_picture_plane_allocator_dummy_alloc(
|
|
GstAllocator* p_allocator, gsize i_size, GstAllocationParams *p_params )
|
|
{
|
|
VLC_UNUSED( p_allocator );
|
|
VLC_UNUSED( i_size );
|
|
VLC_UNUSED( p_params );
|
|
return NULL;
|
|
}
|
|
|
|
static void gst_vlc_picture_plane_allocator_free( GstAllocator *p_allocator,
|
|
GstMemory *p_gmem)
|
|
{
|
|
VLC_UNUSED( p_allocator );
|
|
GstVlcPicturePlane *p_mem = (GstVlcPicturePlane*) p_gmem;
|
|
g_slice_free( GstVlcPicturePlane, p_mem );
|
|
}
|
|
|
|
static gpointer gst_vlc_picture_plane_map( GstMemory *p_gmem,
|
|
gsize i_maxsize, GstMapFlags flags )
|
|
{
|
|
VLC_UNUSED( i_maxsize );
|
|
VLC_UNUSED( flags );
|
|
GstVlcPicturePlane* p_mem = (GstVlcPicturePlane*) p_gmem;
|
|
|
|
if( p_mem->p_pic )
|
|
return (gpointer) (p_mem->p_plane->p_pixels + p_mem->parent.offset);
|
|
else
|
|
return NULL;
|
|
}
|
|
|
|
static void gst_vlc_picture_plane_unmap( GstMemory *p_mem )
|
|
{
|
|
VLC_UNUSED( p_mem );
|
|
}
|
|
|
|
static GstMemory* gst_vlc_picture_plane_copy(
|
|
GstMemory *p_mem, gssize i_offset, gssize i_size )
|
|
{
|
|
VLC_UNUSED( p_mem );
|
|
VLC_UNUSED( i_offset );
|
|
VLC_UNUSED( i_size );
|
|
return NULL;
|
|
}
|
|
|
|
static vlc_fourcc_t gst_vlc_to_map_format( const char* psz_fourcc )
|
|
{
|
|
if( !psz_fourcc )
|
|
return VLC_CODEC_UNKNOWN;
|
|
|
|
if( strlen( psz_fourcc ) != 4 )
|
|
{
|
|
return GetGstVLCFourcc( psz_fourcc );
|
|
}
|
|
else
|
|
{
|
|
return vlc_fourcc_GetCodecFromString(
|
|
VIDEO_ES, psz_fourcc );
|
|
}
|
|
}
|
|
|
|
void gst_vlc_picture_plane_allocator_release(
|
|
GstVlcPicturePlaneAllocator *p_allocator, GstBuffer *p_buffer )
|
|
{
|
|
VLC_UNUSED( p_allocator );
|
|
|
|
GstVlcPicturePlane* p_mem =
|
|
(GstVlcPicturePlane*) gst_buffer_peek_memory( p_buffer, 0 );
|
|
guint i_plane;
|
|
|
|
if( p_mem->p_pic )
|
|
{
|
|
picture_Release( p_mem->p_pic );
|
|
|
|
for( i_plane = 0; i_plane < gst_buffer_n_memory( p_buffer );
|
|
i_plane++ )
|
|
{
|
|
p_mem = (GstVlcPicturePlane*) gst_buffer_peek_memory ( p_buffer,
|
|
i_plane );
|
|
p_mem->p_pic = NULL;
|
|
p_mem->p_plane = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
bool gst_vlc_picture_plane_allocator_hold(
|
|
GstVlcPicturePlaneAllocator *p_allocator, GstBuffer *p_buffer )
|
|
{
|
|
picture_t* p_pic = NULL;
|
|
decoder_t* p_dec = p_allocator->p_dec;
|
|
GstVlcPicturePlane *p_mem;
|
|
int i_plane;
|
|
|
|
if( !decoder_UpdateVideoFormat( p_dec ) )
|
|
p_pic = decoder_NewPicture( p_dec );
|
|
if( !p_pic )
|
|
{
|
|
msg_Err( p_allocator->p_dec, "failed to acquire picture from vout" );
|
|
return false;
|
|
}
|
|
|
|
for( i_plane = 0; i_plane < p_pic->i_planes; i_plane++ )
|
|
{
|
|
p_mem = (GstVlcPicturePlane*) gst_buffer_peek_memory ( p_buffer,
|
|
i_plane );
|
|
p_mem->p_pic = p_pic;
|
|
p_mem->p_plane = &p_pic->p[ i_plane ];
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool gst_vlc_picture_plane_allocator_alloc(
|
|
GstVlcPicturePlaneAllocator *p_allocator,
|
|
GstBuffer *p_buffer )
|
|
{
|
|
int i_plane;
|
|
gsize i_max_size, i_align, i_offset, i_size;
|
|
picture_t *p_pic;
|
|
|
|
p_pic = &p_allocator->pic_info;
|
|
|
|
for( i_plane = 0; i_plane < p_pic->i_planes; i_plane++ )
|
|
{
|
|
GstVlcPicturePlane *p_mem =
|
|
(GstVlcPicturePlane*) g_slice_new0( GstVlcPicturePlane );
|
|
|
|
i_size = p_pic->p[ i_plane ].i_pitch *
|
|
p_pic->p[ i_plane ].i_lines;
|
|
i_max_size = p_pic->p[ i_plane ].i_pitch *
|
|
p_pic->p[ i_plane ].i_lines;
|
|
i_align = 0;
|
|
i_offset = 0;
|
|
|
|
gst_memory_init( GST_MEMORY_CAST( p_mem ), GST_MEMORY_FLAG_NO_SHARE,
|
|
GST_ALLOCATOR_CAST( p_allocator ), NULL, i_max_size,
|
|
i_align, i_offset, i_size );
|
|
gst_buffer_append_memory( p_buffer, (GstMemory*) p_mem );
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool gst_vlc_set_vout_fmt( GstVideoInfo *p_info, GstVideoAlignment *p_align,
|
|
GstCaps *p_caps, decoder_t *p_dec )
|
|
{
|
|
es_format_t *p_outfmt = &p_dec->fmt_out;
|
|
video_format_t *p_voutfmt = &p_dec->fmt_out.video;
|
|
GstStructure *p_str = gst_caps_get_structure( p_caps, 0 );
|
|
vlc_fourcc_t i_chroma;
|
|
int i_padded_width, i_padded_height;
|
|
|
|
const char* psz_fourcc = gst_structure_get_string( p_str, "format" );
|
|
|
|
i_chroma = p_outfmt->i_codec = gst_vlc_to_map_format( psz_fourcc );
|
|
if( !i_chroma || i_chroma == VLC_CODEC_UNKNOWN )
|
|
{
|
|
msg_Err( p_dec, "video chroma type not supported" );
|
|
return false;
|
|
}
|
|
|
|
i_padded_width = GST_VIDEO_INFO_WIDTH( p_info ) + p_align->padding_left +
|
|
p_align->padding_right;
|
|
i_padded_height = GST_VIDEO_INFO_HEIGHT( p_info ) + p_align->padding_top +
|
|
p_align->padding_bottom;
|
|
|
|
video_format_Setup( p_voutfmt, i_chroma, i_padded_width, i_padded_height,
|
|
GST_VIDEO_INFO_WIDTH( p_info ), GST_VIDEO_INFO_HEIGHT( p_info ),
|
|
GST_VIDEO_INFO_PAR_N( p_info ), GST_VIDEO_INFO_PAR_D( p_info ));
|
|
p_voutfmt->i_x_offset = p_align->padding_left;
|
|
p_voutfmt->i_y_offset = p_align->padding_top;
|
|
|
|
p_voutfmt->i_frame_rate = GST_VIDEO_INFO_FPS_N( p_info );
|
|
p_voutfmt->i_frame_rate_base = GST_VIDEO_INFO_FPS_D( p_info );
|
|
|
|
return true;
|
|
}
|
|
|
|
static bool gst_vlc_video_info_from_vout( GstVideoInfo *p_info,
|
|
GstVideoAlignment *p_align, GstCaps *p_caps, decoder_t *p_dec,
|
|
picture_t *p_pic_info )
|
|
{
|
|
const GstVideoFormatInfo *p_vinfo = p_info->finfo;
|
|
picture_t *p_pic = NULL;
|
|
int i;
|
|
|
|
/* Ensure the queue is empty */
|
|
gst_vlc_dec_ensure_empty_queue( p_dec );
|
|
gst_video_info_align( p_info, p_align );
|
|
|
|
if( !gst_vlc_set_vout_fmt( p_info, p_align, p_caps, p_dec ))
|
|
{
|
|
msg_Err( p_dec, "failed to set output format to vout" );
|
|
return false;
|
|
}
|
|
|
|
/* Acquire a picture and release it. This is to get the picture
|
|
* stride/offsets info for the Gstreamer decoder looking to use
|
|
* downstream bufferpool directly; Zero-Copy */
|
|
if( !decoder_UpdateVideoFormat( p_dec ) )
|
|
p_pic = decoder_NewPicture( p_dec );
|
|
if( !p_pic )
|
|
{
|
|
msg_Err( p_dec, "failed to acquire picture from vout; for pic info" );
|
|
return false;
|
|
}
|
|
|
|
/* reject if strides don't match */
|
|
for( i = 0; i < p_pic->i_planes; i++ )
|
|
if( p_info->stride[i] != p_pic->p[i].i_pitch )
|
|
goto strides_mismatch;
|
|
|
|
p_info->offset[0] = 0;
|
|
for( i = 1; i < p_pic->i_planes; i++ )
|
|
{
|
|
p_info->offset[i] = p_info->offset[i-1] +
|
|
p_pic->p[i-1].i_pitch * p_pic->p[i-1].i_lines;
|
|
}
|
|
GST_VIDEO_INFO_SIZE( p_info ) = p_info->offset[i-1] +
|
|
p_pic->p[i-1].i_pitch * p_pic->p[i-1].i_lines;
|
|
|
|
for( i = 0; i < p_pic->i_planes; i++ )
|
|
{
|
|
int i_v_edge, i_h_edge;
|
|
|
|
i_h_edge =
|
|
GST_VIDEO_FORMAT_INFO_SCALE_WIDTH( p_vinfo, i,
|
|
p_align->padding_left);
|
|
i_v_edge =
|
|
GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT( p_vinfo, i,
|
|
p_align->padding_top);
|
|
|
|
p_info->offset[i] += ( i_v_edge * p_info->stride[i] ) +
|
|
( i_h_edge * GST_VIDEO_FORMAT_INFO_PSTRIDE( p_vinfo, i ));
|
|
}
|
|
|
|
memcpy( p_pic_info, p_pic, sizeof( picture_t ));
|
|
picture_Release( p_pic );
|
|
|
|
return true;
|
|
|
|
strides_mismatch:
|
|
msg_Err( p_dec, "strides mismatch" );
|
|
picture_Release( p_pic );
|
|
return false;
|
|
}
|
|
|
|
bool gst_vlc_picture_plane_allocator_query_format(
|
|
GstVlcPicturePlaneAllocator *p_allocator, GstVideoInfo *p_info,
|
|
GstVideoAlignment *p_align, GstCaps *p_caps )
|
|
{
|
|
decoder_t *p_dec = p_allocator->p_dec;
|
|
video_format_t v_fmt;
|
|
picture_t *p_pic_info = &p_allocator->pic_info;
|
|
|
|
/* Back up the original format; as this is just a query */
|
|
v_fmt = p_dec->fmt_out.video;
|
|
video_format_Init( &p_dec->fmt_out.video, 0 );
|
|
|
|
bool b_ret =
|
|
gst_vlc_video_info_from_vout( p_info, p_align, p_caps, p_dec,
|
|
p_pic_info );
|
|
|
|
video_format_Clean( &p_dec->fmt_out.video );
|
|
|
|
/* Restore the original format; as this was just a query */
|
|
p_dec->fmt_out.video = v_fmt;
|
|
|
|
if( !b_ret )
|
|
{
|
|
msg_Err( p_allocator->p_dec, "failed to get the vout info" );
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
GstVlcPicturePlaneAllocator* gst_vlc_picture_plane_allocator_new(
|
|
decoder_t *p_dec )
|
|
{
|
|
GstVlcPicturePlaneAllocator *p_allocator;
|
|
|
|
p_allocator = g_object_new( GST_TYPE_VLC_PICTURE_PLANE_ALLOCATOR, NULL);
|
|
p_allocator->p_dec = p_dec;
|
|
|
|
return p_allocator;
|
|
}
|
|
|