mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-05-18 00:12:46 +00:00
Merge branch 'VP9_drc' into 'main'
Draft: v4l2codecs: Replace VIDIOC_REQBUFS calls by VIDIOC_CREATE_BUFS See merge request gstreamer/gstreamer!4919
This commit is contained in:
commit
6e3bdedc92
|
@ -7161,6 +7161,20 @@ This method does not preserve the original order of @caps.</doc>
|
|||
</instance-parameter>
|
||||
</parameters>
|
||||
</method>
|
||||
<method name="sort" c:identifier="gst_caps_sort" introspectable="0">
|
||||
<source-position filename="../subprojects/gstreamer/gst/gstcaps.h"/>
|
||||
<return-value transfer-ownership="full">
|
||||
<type name="Caps" c:type="GstCaps*"/>
|
||||
</return-value>
|
||||
<parameters>
|
||||
<instance-parameter name="caps" transfer-ownership="none">
|
||||
<type name="Caps" c:type="GstCaps*"/>
|
||||
</instance-parameter>
|
||||
<parameter name="func" transfer-ownership="none">
|
||||
<type name="CapsSortFunc" c:type="GstCapsSortFunc"/>
|
||||
</parameter>
|
||||
</parameters>
|
||||
</method>
|
||||
<method name="steal_structure" c:identifier="gst_caps_steal_structure">
|
||||
<doc xml:space="preserve" filename="../subprojects/gstreamer/gst/gstcaps.c">Retrieves the structure with the given index from the list of structures
|
||||
contained in @caps. The caller becomes the owner of the returned structure.</doc>
|
||||
|
@ -7837,6 +7851,25 @@ the map operation should stop with %FALSE.</doc>
|
|||
</parameter>
|
||||
</parameters>
|
||||
</callback>
|
||||
<callback name="CapsSortFunc" c:type="GstCapsSortFunc">
|
||||
<doc xml:space="preserve" filename="../subprojects/gstreamer/gst/gstcaps.h">Returns; negative value if a < b; zero if a = b; positive value if a > b.4
|
||||
|
||||
Since 1.24</doc>
|
||||
<source-position filename="../subprojects/gstreamer/gst/gstcaps.h"/>
|
||||
<return-value transfer-ownership="none">
|
||||
<type name="gint" c:type="int"/>
|
||||
</return-value>
|
||||
<parameters>
|
||||
<parameter name="a" transfer-ownership="none">
|
||||
<doc xml:space="preserve" filename="../subprojects/gstreamer/gst/gstcaps.h">a structure.</doc>
|
||||
<type name="Structure" c:type="const GstStructure*"/>
|
||||
</parameter>
|
||||
<parameter name="b" transfer-ownership="none">
|
||||
<doc xml:space="preserve" filename="../subprojects/gstreamer/gst/gstcaps.h">a structure to compare with.</doc>
|
||||
<type name="Structure" c:type="const GstStructure*"/>
|
||||
</parameter>
|
||||
</parameters>
|
||||
</callback>
|
||||
<interface name="ChildProxy" c:symbol-prefix="child_proxy" c:type="GstChildProxy" glib:type-name="GstChildProxy" glib:get-type="gst_child_proxy_get_type" glib:type-struct="ChildProxyInterface">
|
||||
<doc xml:space="preserve" filename="../subprojects/gstreamer/gst/gstchildproxy.c">This interface abstracts handling of property sets for elements with
|
||||
children. Imagine elements such as mixers or polyphonic generators. They all
|
||||
|
|
|
@ -4718,6 +4718,18 @@ and can be used as a binary.</doc>
|
|||
<field name="size" readable="0" private="1">
|
||||
<type name="gsize" c:type="gsize"/>
|
||||
</field>
|
||||
<field name="discont_state" readable="0" private="1">
|
||||
<type name="GstVideo.VideoCodecState" c:type="GstVideoCodecState*"/>
|
||||
</field>
|
||||
<field name="user_data" readable="0" private="1">
|
||||
<type name="gpointer" c:type="gpointer"/>
|
||||
</field>
|
||||
<field name="notify" readable="0" private="1">
|
||||
<type name="GLib.DestroyNotify" c:type="GDestroyNotify"/>
|
||||
</field>
|
||||
<field name="check_strides" readable="0" private="1">
|
||||
<type name="gboolean" c:type="gboolean"/>
|
||||
</field>
|
||||
<constructor name="new" c:identifier="gst_vp9_picture_new">
|
||||
<doc xml:space="preserve" filename="../subprojects/gst-plugins-bad/gst-libs/gst/codecs/gstvp9picture.c">Create new #GstVp9Picture</doc>
|
||||
<source-position filename="../subprojects/gst-plugins-bad/gst-libs/gst/codecs/gstvp9picture.h"/>
|
||||
|
|
|
@ -44,6 +44,8 @@ struct _GstVp9Picture
|
|||
/* raw data and size (does not have ownership) */
|
||||
const guint8 * data;
|
||||
gsize size;
|
||||
|
||||
gboolean check_strides;
|
||||
};
|
||||
|
||||
GST_CODECS_API
|
||||
|
|
|
@ -146,6 +146,8 @@ gst_v4l2_codec_allocator_release (GstMiniObject * mini_object)
|
|||
{
|
||||
GstMemory *mem = GST_MEMORY_CAST (mini_object);
|
||||
GstV4l2CodecAllocator *self = GST_V4L2_CODEC_ALLOCATOR (mem->allocator);
|
||||
GstV4l2Decoder *decoder = self->decoder;
|
||||
GstPadDirection direction = self->direction;
|
||||
GstV4l2CodecBuffer *buf;
|
||||
|
||||
GST_OBJECT_LOCK (self);
|
||||
|
@ -154,9 +156,15 @@ gst_v4l2_codec_allocator_release (GstMiniObject * mini_object)
|
|||
gst_memory_ref (mem);
|
||||
|
||||
if (gst_v4l2_codec_buffer_release_mem (buf)) {
|
||||
GST_DEBUG_OBJECT (self, "Placing back buffer %i into pool", buf->index);
|
||||
g_queue_push_tail (&self->pool, buf);
|
||||
g_cond_signal (&self->buffer_cond);
|
||||
if (self->detached) {
|
||||
GST_DEBUG_OBJECT (self, "Detached pool freeing buffer %d", buf->index);
|
||||
gst_v4l2_decoder_remove_buffer (decoder, direction, buf->index);
|
||||
gst_v4l2_codec_buffer_free (buf);
|
||||
} else {
|
||||
GST_DEBUG_OBJECT (self, "Placing back buffer %i into pool", buf->index);
|
||||
g_queue_push_tail (&self->pool, buf);
|
||||
g_cond_signal (&self->buffer_cond);
|
||||
}
|
||||
}
|
||||
|
||||
GST_OBJECT_UNLOCK (self);
|
||||
|
@ -173,28 +181,27 @@ gst_v4l2_codec_allocator_prepare (GstV4l2CodecAllocator * self)
|
|||
{
|
||||
GstV4l2Decoder *decoder = self->decoder;
|
||||
GstPadDirection direction = self->direction;
|
||||
gint ret;
|
||||
guint i;
|
||||
|
||||
ret = gst_v4l2_decoder_request_buffers (decoder, direction, self->pool_size);
|
||||
if (ret < self->pool_size) {
|
||||
if (ret >= 0)
|
||||
GST_ERROR_OBJECT (self,
|
||||
"%i buffer was needed, but only %i could be allocated",
|
||||
self->pool_size, ret);
|
||||
goto failed;
|
||||
}
|
||||
GST_DEBUG_OBJECT (self, "Try to create %d buffers", self->pool_size);
|
||||
|
||||
for (i = 0; i < self->pool_size; i++) {
|
||||
GstV4l2CodecBuffer *buf = gst_v4l2_codec_buffer_new (GST_ALLOCATOR (self),
|
||||
decoder, direction, i);
|
||||
GstV4l2CodecBuffer *buf;
|
||||
gint index = gst_v4l2_decoder_create_buffer (decoder, direction);
|
||||
if (index < 0) {
|
||||
GST_ERROR_OBJECT (self, "Failed to create buffer (ret =%d)", index);
|
||||
goto failed;
|
||||
}
|
||||
|
||||
buf =
|
||||
gst_v4l2_codec_buffer_new (GST_ALLOCATOR (self), decoder, direction,
|
||||
index);
|
||||
g_queue_push_tail (&self->pool, buf);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
|
||||
failed:
|
||||
gst_v4l2_decoder_request_buffers (decoder, direction, 0);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
@ -208,10 +215,14 @@ static void
|
|||
gst_v4l2_codec_allocator_dispose (GObject * object)
|
||||
{
|
||||
GstV4l2CodecAllocator *self = GST_V4L2_CODEC_ALLOCATOR (object);
|
||||
GstV4l2Decoder *decoder = self->decoder;
|
||||
GstPadDirection direction = self->direction;
|
||||
GstV4l2CodecBuffer *buf;
|
||||
|
||||
while ((buf = g_queue_pop_head (&self->pool)))
|
||||
while ((buf = g_queue_pop_head (&self->pool))) {
|
||||
gst_v4l2_decoder_remove_buffer (decoder, direction, buf->index);
|
||||
gst_v4l2_codec_buffer_free (buf);
|
||||
}
|
||||
|
||||
if (self->decoder) {
|
||||
gst_v4l2_codec_allocator_detach (self);
|
||||
|
@ -345,10 +356,10 @@ gst_v4l2_codec_allocator_get_pool_size (GstV4l2CodecAllocator * self)
|
|||
void
|
||||
gst_v4l2_codec_allocator_detach (GstV4l2CodecAllocator * self)
|
||||
{
|
||||
|
||||
GST_OBJECT_LOCK (self);
|
||||
if (!self->detached) {
|
||||
self->detached = TRUE;
|
||||
gst_v4l2_decoder_request_buffers (self->decoder, self->direction, 0);
|
||||
}
|
||||
GST_OBJECT_UNLOCK (self);
|
||||
}
|
||||
|
|
|
@ -400,9 +400,7 @@ gst_v4l2_codec_vp9_dec_open (GstVideoDecoder * decoder)
|
|||
gst_v4l2_decoder_query_control_size (self->decoder,
|
||||
V4L2_CID_STATELESS_VP9_COMPRESSED_HDR, NULL);
|
||||
|
||||
/* V4L2 does not support non-keyframe resolution change, this will ask the
|
||||
* base class to drop frame until the next keyframe as a workaround. */
|
||||
gst_vp9_decoder_set_non_keyframe_format_change_support (vp9dec, FALSE);
|
||||
gst_vp9_decoder_set_non_keyframe_format_change_support (vp9dec, TRUE);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
@ -476,10 +474,6 @@ gst_v4l2_codec_vp9_dec_negotiate (GstVideoDecoder * decoder)
|
|||
GstCaps *peer_caps, *filter, *caps;
|
||||
GstStaticCaps *static_filter;
|
||||
|
||||
/* Ignore downstream renegotiation request. */
|
||||
if (self->streaming)
|
||||
goto done;
|
||||
|
||||
GST_DEBUG_OBJECT (self, "Negotiate");
|
||||
|
||||
gst_v4l2_codec_vp9_dec_reset_allocation (self);
|
||||
|
@ -528,14 +522,18 @@ gst_v4l2_codec_vp9_dec_negotiate (GstVideoDecoder * decoder)
|
|||
}
|
||||
gst_caps_unref (caps);
|
||||
|
||||
done:
|
||||
if (self->output_state)
|
||||
gst_video_codec_state_unref (self->output_state);
|
||||
if (!self->streaming) {
|
||||
if (self->output_state)
|
||||
gst_video_codec_state_unref (self->output_state);
|
||||
|
||||
self->output_state =
|
||||
self->output_state =
|
||||
gst_v4l2_decoder_set_output_state (GST_VIDEO_DECODER (self), &self->vinfo,
|
||||
&self->vinfo_drm, self->width, self->height, vp9dec->input_state);
|
||||
|
||||
self->output_state->caps =
|
||||
gst_video_info_to_caps (&self->output_state->info);
|
||||
}
|
||||
|
||||
if (GST_VIDEO_DECODER_CLASS (parent_class)->negotiate (decoder)) {
|
||||
if (self->streaming)
|
||||
return TRUE;
|
||||
|
@ -571,11 +569,6 @@ gst_v4l2_codec_vp9_dec_decide_allocation (GstVideoDecoder * decoder,
|
|||
guint min = 0;
|
||||
guint num_bitstream;
|
||||
|
||||
/* If we are streaming here, then it means there is nothing allocation
|
||||
* related in the new state and allocation can be ignored */
|
||||
if (self->streaming)
|
||||
goto no_internal_changes;
|
||||
|
||||
g_clear_object (&self->src_pool);
|
||||
g_clear_object (&self->src_allocator);
|
||||
|
||||
|
@ -621,7 +614,6 @@ gst_v4l2_codec_vp9_dec_decide_allocation (GstVideoDecoder * decoder,
|
|||
|
||||
self->src_pool = gst_v4l2_codec_pool_new (self->src_allocator, &self->vinfo);
|
||||
|
||||
no_internal_changes:
|
||||
/* Our buffer pool is internal, we will let the base class create a video
|
||||
* pool, and use it if we are running out of buffers or if downstream does
|
||||
* not support GstVideoMeta */
|
||||
|
@ -629,6 +621,66 @@ no_internal_changes:
|
|||
(decoder, query);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
_check_strides (GstV4l2CodecVp9Dec * self, GstVp9Picture * picture)
|
||||
{
|
||||
GstVideoInfo ref_vinfo;
|
||||
gint i;
|
||||
|
||||
gst_video_info_set_format (&ref_vinfo, GST_VIDEO_INFO_FORMAT (&self->vinfo),
|
||||
self->width, self->height);
|
||||
|
||||
for (i = 0; i < GST_VIDEO_INFO_N_PLANES (&self->vinfo); i++) {
|
||||
if (self->vinfo.stride[i] != ref_vinfo.stride[i] ||
|
||||
self->vinfo.offset[i] != ref_vinfo.offset[i]) {
|
||||
/* Strides are differents we need to copy the frame */
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static GstFlowReturn
|
||||
_check_resolution_change (GstV4l2CodecVp9Dec * self, GstVp9Picture * picture)
|
||||
{
|
||||
const GstVp9FrameHeader *frame_hdr = &picture->frame_hdr;
|
||||
|
||||
if ((self->width == frame_hdr->width) && self->height == frame_hdr->height)
|
||||
return GST_FLOW_OK;
|
||||
|
||||
GST_VIDEO_INFO_WIDTH (&self->vinfo) = self->width = frame_hdr->width;
|
||||
GST_VIDEO_INFO_HEIGHT (&self->vinfo) = self->height = frame_hdr->height;
|
||||
|
||||
GST_INFO_OBJECT (self, "Negotiate new resolution %dx%d",
|
||||
self->width, self->height);
|
||||
|
||||
if (!gst_video_decoder_negotiate (GST_VIDEO_DECODER (self))) {
|
||||
GST_ERROR_OBJECT (self,
|
||||
"Resolution changed, but failed to negotiate with downstream");
|
||||
return GST_FLOW_NOT_NEGOTIATED;
|
||||
}
|
||||
|
||||
GST_INFO_OBJECT (self, "Resolution changed to %dx%d for frame %d",
|
||||
self->width, self->height, picture->parent.system_frame_number);
|
||||
|
||||
/* Because the resolution has changed strides need to be checked */
|
||||
picture->check_strides = TRUE;
|
||||
|
||||
return GST_FLOW_OK;
|
||||
}
|
||||
|
||||
static GstFlowReturn
|
||||
gst_v4l2_codec_vp9_dec_new_picture (GstVp9Decoder * decoder,
|
||||
GstVideoCodecFrame * frame, GstVp9Picture * picture)
|
||||
{
|
||||
GstV4l2CodecVp9Dec *self = GST_V4L2_CODEC_VP9_DEC (decoder);
|
||||
|
||||
GST_INFO_OBJECT (self, "gst_v4l2_codec_vp9_dec_new_picture");
|
||||
|
||||
return _check_resolution_change (self, picture);
|
||||
}
|
||||
|
||||
static GstFlowReturn
|
||||
gst_v4l2_codec_vp9_dec_new_sequence (GstVp9Decoder * decoder,
|
||||
const GstVp9FrameHeader * frame_hdr, gint max_dpb_size)
|
||||
|
@ -945,6 +997,11 @@ gst_v4l2_codec_vp9_dec_duplicate_picture (GstVp9Decoder * decoder,
|
|||
GST_DEBUG_OBJECT (decoder, "Duplicate picture %u",
|
||||
GST_CODEC_PICTURE_FRAME_NUMBER (picture));
|
||||
|
||||
if (_check_resolution_change (GST_V4L2_CODEC_VP9_DEC (decoder), picture) !=
|
||||
GST_FLOW_OK) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
new_picture = gst_vp9_picture_new ();
|
||||
new_picture->frame_hdr = picture->frame_hdr;
|
||||
GST_CODEC_PICTURE_FRAME_NUMBER (new_picture) = frame->system_frame_number;
|
||||
|
@ -981,6 +1038,7 @@ gst_v4l2_codec_vp9_dec_output_picture (GstVp9Decoder * decoder,
|
|||
{
|
||||
GstV4l2CodecVp9Dec *self = GST_V4L2_CODEC_VP9_DEC (decoder);
|
||||
GstVideoDecoder *vdec = GST_VIDEO_DECODER (decoder);
|
||||
GstVp9Decoder *vp9dec = GST_VP9_DECODER (vdec);
|
||||
GstV4l2Request *request = NULL;
|
||||
GstCodecPicture *codec_picture = GST_CODEC_PICTURE (picture);
|
||||
gint ret;
|
||||
|
@ -1034,6 +1092,21 @@ gst_v4l2_codec_vp9_dec_output_picture (GstVp9Decoder * decoder,
|
|||
goto error;
|
||||
}
|
||||
|
||||
if (picture->check_strides) {
|
||||
self->copy_frames = _check_strides (self, picture);
|
||||
|
||||
if (self->output_state)
|
||||
gst_video_codec_state_unref (self->output_state);
|
||||
|
||||
self->output_state =
|
||||
gst_video_decoder_set_output_state (GST_VIDEO_DECODER (self),
|
||||
self->vinfo.finfo->format, self->width,
|
||||
self->height, vp9dec->input_state);
|
||||
|
||||
self->output_state->caps =
|
||||
gst_video_info_to_caps (&self->output_state->info);
|
||||
}
|
||||
|
||||
if (self->copy_frames)
|
||||
gst_v4l2_codec_vp9_dec_copy_output_buffer (self, frame);
|
||||
|
||||
|
@ -1194,6 +1267,8 @@ gst_v4l2_codec_vp9_dec_subclass_init (GstV4l2CodecVp9DecClass * klass,
|
|||
|
||||
vp9decoder_class->new_sequence =
|
||||
GST_DEBUG_FUNCPTR (gst_v4l2_codec_vp9_dec_new_sequence);
|
||||
vp9decoder_class->new_picture =
|
||||
GST_DEBUG_FUNCPTR (gst_v4l2_codec_vp9_dec_new_picture);
|
||||
vp9decoder_class->start_picture =
|
||||
GST_DEBUG_FUNCPTR (gst_v4l2_codec_vp9_dec_start_picture);
|
||||
vp9decoder_class->decode_picture =
|
||||
|
|
|
@ -78,6 +78,7 @@ struct _GstV4l2Decoder
|
|||
GstQueueArray *request_pool;
|
||||
GstQueueArray *pending_requests;
|
||||
guint version;
|
||||
GstVideoInfo *info;
|
||||
|
||||
enum v4l2_buf_type src_buf_type;
|
||||
enum v4l2_buf_type sink_buf_type;
|
||||
|
@ -90,6 +91,7 @@ struct _GstV4l2Decoder
|
|||
|
||||
/* detected features */
|
||||
gboolean supports_holding_capture;
|
||||
gboolean supports_remove_buffer;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE_WITH_CODE (GstV4l2Decoder, gst_v4l2_decoder, GST_TYPE_OBJECT,
|
||||
|
@ -167,6 +169,10 @@ gst_v4l2_decoder_open (GstV4l2Decoder * self)
|
|||
{
|
||||
gint ret;
|
||||
struct v4l2_capability querycap;
|
||||
struct v4l2_remove_buffers remove_bufs = {
|
||||
.index = 0,
|
||||
.count = 0,
|
||||
};
|
||||
guint32 capabilities;
|
||||
|
||||
self->media_fd = open (self->media_device, 0);
|
||||
|
@ -211,6 +217,12 @@ gst_v4l2_decoder_open (GstV4l2Decoder * self)
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
self->supports_remove_buffer = TRUE;
|
||||
remove_bufs.type = self->sink_buf_type;
|
||||
ret = ioctl (self->video_fd, VIDIOC_REMOVE_BUFS, &remove_bufs);
|
||||
if (ret < 0 && errno == ENOTTY)
|
||||
self->supports_remove_buffer = FALSE;
|
||||
|
||||
self->opened = TRUE;
|
||||
|
||||
return TRUE;
|
||||
|
@ -512,7 +524,32 @@ gst_v4l2_decoder_enum_src_formats (GstV4l2Decoder * self,
|
|||
|
||||
GST_DEBUG_OBJECT (self, "Probed caps: %" GST_PTR_FORMAT, caps);
|
||||
|
||||
return caps;
|
||||
return gst_v4l2_sort_caps (caps);
|
||||
}
|
||||
|
||||
gboolean
|
||||
gst_v4l2_decoder_remove_buffer (GstV4l2Decoder * self,
|
||||
GstPadDirection direction, guint index)
|
||||
{
|
||||
gint ret;
|
||||
struct v4l2_remove_buffers remove_bufs = {
|
||||
.type = direction_to_buffer_type (self, direction),
|
||||
.index = index,
|
||||
.count = 1,
|
||||
};
|
||||
|
||||
if (!self->supports_remove_buffer)
|
||||
return TRUE;
|
||||
|
||||
GST_DEBUG_OBJECT (self, "remove buffers %d from index %d", remove_bufs.count,
|
||||
remove_bufs.index);
|
||||
ret = ioctl (self->video_fd, VIDIOC_REMOVE_BUFS, &remove_bufs);
|
||||
if (ret < 0) {
|
||||
GST_ERROR_OBJECT (self, "VIDIOC_REMOVE_BUF failed: %s", g_strerror (errno));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
|
@ -592,6 +629,10 @@ gst_v4l2_decoder_select_src_format (GstV4l2Decoder * self, GstCaps * caps,
|
|||
gst_video_format_to_string (vinfo->finfo->format),
|
||||
vinfo->width, vinfo->height);
|
||||
|
||||
if (self->info)
|
||||
gst_video_info_free (self->info);
|
||||
self->info = gst_video_info_copy (vinfo);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
@ -620,32 +661,44 @@ gst_v4l2_decoder_set_output_state (GstVideoDecoder * decoder,
|
|||
}
|
||||
|
||||
gint
|
||||
gst_v4l2_decoder_request_buffers (GstV4l2Decoder * self,
|
||||
GstPadDirection direction, guint num_buffers)
|
||||
gst_v4l2_decoder_create_buffer (GstV4l2Decoder * self,
|
||||
GstPadDirection direction)
|
||||
{
|
||||
gint ret;
|
||||
struct v4l2_requestbuffers reqbufs = {
|
||||
.count = num_buffers,
|
||||
int ret;
|
||||
struct v4l2_create_buffers createbufs = {
|
||||
.count = 1,
|
||||
.memory = V4L2_MEMORY_MMAP,
|
||||
.type = direction_to_buffer_type (self, direction),
|
||||
};
|
||||
|
||||
GST_DEBUG_OBJECT (self, "Requesting %u buffers", num_buffers);
|
||||
if (direction == GST_PAD_SINK) {
|
||||
createbufs.format.type = self->sink_buf_type;
|
||||
} else {
|
||||
createbufs.format.type = self->src_buf_type;
|
||||
}
|
||||
|
||||
ret = ioctl (self->video_fd, VIDIOC_REQBUFS, &reqbufs);
|
||||
ret = ioctl (self->video_fd, VIDIOC_G_FMT, &createbufs.format);
|
||||
if (ret < 0) {
|
||||
GST_ERROR_OBJECT (self, "VIDIOC_REQBUFS failed: %s", g_strerror (errno));
|
||||
GST_ERROR_OBJECT (self, "VIDIOC_G_FMT failed: %s", g_strerror (errno));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
GST_DEBUG_OBJECT (self, "Creating 1 buffer");
|
||||
|
||||
ret = ioctl (self->video_fd, VIDIOC_CREATE_BUFS, &createbufs);
|
||||
if (ret < 0) {
|
||||
GST_ERROR_OBJECT (self, "VIDIOC_CREATE_BUFS failed: %s",
|
||||
g_strerror (errno));
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (direction == GST_PAD_SINK) {
|
||||
if (reqbufs.capabilities & V4L2_BUF_CAP_SUPPORTS_M2M_HOLD_CAPTURE_BUF)
|
||||
if (createbufs.capabilities & V4L2_BUF_CAP_SUPPORTS_M2M_HOLD_CAPTURE_BUF)
|
||||
self->supports_holding_capture = TRUE;
|
||||
else
|
||||
self->supports_holding_capture = FALSE;
|
||||
}
|
||||
|
||||
return reqbufs.count;
|
||||
return createbufs.index;
|
||||
}
|
||||
|
||||
gboolean
|
||||
|
|
|
@ -82,9 +82,12 @@ GstVideoCodecState * gst_v4l2_decoder_set_output_state (GstVideoDecoder * decode
|
|||
guint height,
|
||||
GstVideoCodecState * reference);
|
||||
|
||||
gint gst_v4l2_decoder_request_buffers (GstV4l2Decoder * self,
|
||||
GstPadDirection direction,
|
||||
guint num_buffers);
|
||||
gint gst_v4l2_decoder_create_buffer (GstV4l2Decoder * self,
|
||||
GstPadDirection direction);
|
||||
|
||||
gint gst_v4l2_decoder_remove_buffer (GstV4l2Decoder * self,
|
||||
GstPadDirection direction,
|
||||
guint index);
|
||||
|
||||
gboolean gst_v4l2_decoder_export_buffer (GstV4l2Decoder * self,
|
||||
GstPadDirection directon,
|
||||
|
|
|
@ -77,6 +77,19 @@ lookup_gst_fmt (GstVideoFormat gst_fmt)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
gst_fmt_index (GstVideoFormat gst_fmt)
|
||||
{
|
||||
gint i;
|
||||
|
||||
for (i = 0; format_map[i].v4l2_pix_fmt; i++) {
|
||||
if (format_map[i].gst_fmt == gst_fmt)
|
||||
return i;
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
static void
|
||||
set_stride (GstVideoInfo * info, gint plane, gint stride)
|
||||
{
|
||||
|
@ -203,3 +216,23 @@ gst_v4l2_format_from_video_format (GstVideoFormat format, guint32 * out_pix_fmt)
|
|||
*out_pix_fmt = entry->v4l2_pix_fmt;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gint
|
||||
gst_v4l2_caps_compare_structures (const GstStructure * a,
|
||||
const GstStructure * b)
|
||||
{
|
||||
const GValue *formata = gst_structure_get_value (a, "format");
|
||||
const GValue *formatb = gst_structure_get_value (b, "format");
|
||||
GstVideoFormat vformata =
|
||||
gst_video_format_from_string (g_value_get_string (formata));
|
||||
GstVideoFormat vformatb =
|
||||
gst_video_format_from_string (g_value_get_string (formatb));
|
||||
|
||||
return gst_fmt_index (vformata) - gst_fmt_index (vformatb);
|
||||
}
|
||||
|
||||
GstCaps *
|
||||
gst_v4l2_sort_caps (GstCaps * caps)
|
||||
{
|
||||
return gst_caps_sort (caps, gst_v4l2_caps_compare_structures);
|
||||
}
|
||||
|
|
|
@ -38,4 +38,6 @@ gboolean gst_v4l2_format_to_video_format (guint32 pix_fmt,
|
|||
gboolean gst_v4l2_format_from_video_format (GstVideoFormat format,
|
||||
guint32 * out_pix_fmt);
|
||||
|
||||
GstCaps * gst_v4l2_sort_caps (GstCaps * caps);
|
||||
|
||||
#endif /* __GST_V4L2_FORMAT_H__ */
|
||||
|
|
|
@ -990,6 +990,8 @@ struct v4l2_requestbuffers {
|
|||
#define V4L2_BUF_CAP_SUPPORTS_ORPHANED_BUFS (1 << 4)
|
||||
#define V4L2_BUF_CAP_SUPPORTS_M2M_HOLD_CAPTURE_BUF (1 << 5)
|
||||
#define V4L2_BUF_CAP_SUPPORTS_MMAP_CACHE_HINTS (1 << 6)
|
||||
#define V4L2_BUF_CAP_SUPPORTS_MAX_NUM_BUFFERS (1 << 7)
|
||||
#define V4L2_BUF_CAP_SUPPORTS_REMOVE_BUFS (1 << 8)
|
||||
|
||||
/**
|
||||
* struct v4l2_plane - plane info for multi-planar buffers
|
||||
|
@ -2544,6 +2546,9 @@ struct v4l2_dbg_chip_info {
|
|||
* @flags: additional buffer management attributes (ignored unless the
|
||||
* queue has V4L2_BUF_CAP_SUPPORTS_MMAP_CACHE_HINTS capability
|
||||
* and configured for MMAP streaming I/O).
|
||||
* @max_num_buffers: if V4L2_BUF_CAP_SUPPORTS_MAX_NUM_BUFFERS capability flag is set
|
||||
* this field indicate the maximum possible number of buffers
|
||||
* for this queue.
|
||||
* @reserved: future extensions
|
||||
*/
|
||||
struct v4l2_create_buffers {
|
||||
|
@ -2553,7 +2558,22 @@ struct v4l2_create_buffers {
|
|||
struct v4l2_format format;
|
||||
__u32 capabilities;
|
||||
__u32 flags;
|
||||
__u32 reserved[6];
|
||||
__u32 max_num_buffers;
|
||||
__u32 reserved[5];
|
||||
};
|
||||
|
||||
/**
|
||||
* struct v4l2_remove_buffers - VIDIOC_REMOVE_BUFS argument
|
||||
* @index: the first buffer to be removed
|
||||
* @count: number of buffers to removed
|
||||
* @type: enum v4l2_buf_type
|
||||
* @reserved: future extensions
|
||||
*/
|
||||
struct v4l2_remove_buffers {
|
||||
__u32 index;
|
||||
__u32 count;
|
||||
__u32 type;
|
||||
__u32 reserved[13];
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -2655,6 +2675,7 @@ struct v4l2_create_buffers {
|
|||
#define VIDIOC_DBG_G_CHIP_INFO _IOWR('V', 102, struct v4l2_dbg_chip_info)
|
||||
|
||||
#define VIDIOC_QUERY_EXT_CTRL _IOWR('V', 103, struct v4l2_query_ext_ctrl)
|
||||
#define VIDIOC_REMOVE_BUFS _IOWR('V', 104, struct v4l2_remove_buffers)
|
||||
|
||||
/* Reminder: when adding new ioctls please add support for them to
|
||||
drivers/media/v4l2-core/v4l2-compat-ioctl32.c as well! */
|
||||
|
|
|
@ -2361,7 +2361,7 @@ caps_serialize (const GstCaps * caps, GstSerializeFlags flags)
|
|||
}
|
||||
|
||||
/**
|
||||
* gst_caps_to_string:
|
||||
* gst_caps_to_string
|
||||
* @caps: a #GstCaps
|
||||
*
|
||||
* Converts @caps to a string representation. This string representation
|
||||
|
@ -2809,3 +2809,45 @@ gst_caps_take (GstCaps ** old_caps, GstCaps * new_caps)
|
|||
return gst_mini_object_take ((GstMiniObject **) old_caps,
|
||||
(GstMiniObject *) new_caps);
|
||||
}
|
||||
|
||||
static gint
|
||||
gst_caps_sort_structures (gconstpointer one, gconstpointer two,
|
||||
gpointer user_data)
|
||||
{
|
||||
const GstStructure *struct1 = ((const GstCapsArrayElement *) one)->structure;
|
||||
const GstStructure *struct2 = ((const GstCapsArrayElement *) two)->structure;
|
||||
GstCapsSortFunc sort_func = (GstCapsSortFunc) user_data;
|
||||
|
||||
return sort_func (struct1, struct2);
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_caps_sort: sorts caps using compare function
|
||||
* @caps: caps to be sorted
|
||||
* @func: compare function
|
||||
*
|
||||
* Returns: sorted caps.
|
||||
*
|
||||
* Since 1.24
|
||||
*/
|
||||
GstCaps *
|
||||
gst_caps_sort (GstCaps * caps, GstCapsSortFunc func)
|
||||
{
|
||||
if (!func)
|
||||
return caps;
|
||||
|
||||
/* empty/any caps, nothing to sort */
|
||||
if (GST_CAPS_LEN (caps) == 0)
|
||||
return caps;
|
||||
|
||||
/* one caps, nothing to sort */
|
||||
if (GST_CAPS_LEN (caps) == 1)
|
||||
return caps;
|
||||
|
||||
caps = gst_caps_make_writable (caps);
|
||||
|
||||
g_array_sort_with_data (GST_CAPS_ARRAY (caps), gst_caps_sort_structures,
|
||||
func);
|
||||
|
||||
return caps;
|
||||
}
|
||||
|
|
|
@ -357,6 +357,17 @@ typedef gboolean (*GstCapsFilterMapFunc) (GstCapsFeatures *features,
|
|||
gpointer user_data);
|
||||
|
||||
|
||||
/**
|
||||
* GstCapsSortFunc:
|
||||
* @a: a structure.
|
||||
* @b: a structure to compare with.
|
||||
*
|
||||
* Returns; negative value if a < b; zero if a = b; positive value if a > b.4
|
||||
*
|
||||
* Since 1.24
|
||||
*/
|
||||
typedef int (*GstCapsSortFunc) (const GstStructure *a, const GstStructure *b);
|
||||
|
||||
GST_API
|
||||
GType gst_caps_get_type (void);
|
||||
|
||||
|
@ -526,6 +537,10 @@ GstCaps * gst_caps_simplify (GstCaps *caps) G_GNUC_WARN_U
|
|||
GST_API
|
||||
GstCaps * gst_caps_fixate (GstCaps *caps) G_GNUC_WARN_UNUSED_RESULT;
|
||||
|
||||
GST_API
|
||||
GstCaps * gst_caps_sort (GstCaps *caps, GstCapsSortFunc func);
|
||||
|
||||
|
||||
/* utility */
|
||||
|
||||
GST_API
|
||||
|
|
Loading…
Reference in a new issue