AC_DEFINE(HAVE_VP9_DECODER, 1, [Defined if the VP9 decoder is available])
])
], [true])
+
+ PKG_CHECK_MODULES(VPX_140, vpx >= 1.4.0, [
+ AC_DEFINE(HAVE_VPX_1_4, 1, [Defined if the VPX library version is 1.4 or bigger])
+ ], [true])
+
LIBS="$OLD_LIBS"
CFLAGS="$OLD_CFLAGS"
fi
vpx_codec_destroy (&gst_vp8_dec->decoder);
gst_vp8_dec->decoder_inited = FALSE;
+ if (gst_vp8_dec->pool) {
+ gst_buffer_pool_set_active (gst_vp8_dec->pool, FALSE);
+ gst_object_unref (gst_vp8_dec->pool);
+ gst_vp8_dec->pool = NULL;
+ gst_vp8_dec->buf_size = 0;
+ }
+
return TRUE;
}
gst_event_new_tag (list));
}
+#ifdef HAVE_VPX_1_4
+struct Frame
+{
+ GstMapInfo info;
+ GstBuffer *buffer;
+};
+
+static GstBuffer *
+gst_vp8_dec_prepare_image (GstVP8Dec * dec, const vpx_image_t * img)
+{
+ gint comp;
+ GstVideoMeta *vmeta;
+ GstBuffer *buffer;
+ struct Frame *frame = img->fb_priv;
+ GstVideoInfo *info = &dec->output_state->info;
+
+ buffer = gst_buffer_ref (frame->buffer);
+
+ vmeta = gst_buffer_get_video_meta (buffer);
+ vmeta->format = GST_VIDEO_INFO_FORMAT (info);
+ vmeta->width = GST_VIDEO_INFO_WIDTH (info);
+ vmeta->height = GST_VIDEO_INFO_HEIGHT (info);
+ vmeta->n_planes = GST_VIDEO_INFO_N_PLANES (info);
+
+ for (comp = 0; comp < 4; comp++) {
+ vmeta->stride[comp] = img->stride[comp];
+ vmeta->offset[comp] =
+ img->planes[comp] ? img->planes[comp] - frame->info.data : 0;
+ }
+
+ /* FIXME This is a READ/WRITE mapped buffer see bug #754826 */
+
+ return buffer;
+}
+
+static int
+gst_vp8_dec_get_buffer_cb (gpointer priv, gsize min_size,
+ vpx_codec_frame_buffer_t * fb)
+{
+ GstVP8Dec *dec = priv;
+ GstBuffer *buffer;
+ struct Frame *frame;
+ GstFlowReturn ret;
+
+ if (!dec->pool || dec->buf_size != min_size) {
+ GstBufferPool *pool;
+ GstStructure *config;
+ GstCaps *caps;
+ GstAllocator *allocator;
+ GstAllocationParams params;
+
+ if (dec->pool) {
+ gst_buffer_pool_set_active (dec->pool, FALSE);
+ gst_object_unref (dec->pool);
+ dec->pool = NULL;
+ dec->buf_size = 0;
+ }
+
+ gst_video_decoder_get_allocator (GST_VIDEO_DECODER (dec), &allocator,
+ ¶ms);
+
+ if (allocator &&
+ GST_OBJECT_FLAG_IS_SET (allocator, GST_ALLOCATOR_FLAG_CUSTOM_ALLOC)) {
+ gst_object_unref (allocator);
+ allocator = NULL;
+ }
+
+ pool = gst_buffer_pool_new ();
+ config = gst_buffer_pool_get_config (pool);
+ gst_buffer_pool_config_set_allocator (config, allocator, ¶ms);
+ caps = gst_caps_from_string ("video/internal");
+ gst_buffer_pool_config_set_params (config, caps, min_size, 2, 0);
+ gst_caps_unref (caps);
+ gst_buffer_pool_set_config (pool, config);
+
+ if (allocator)
+ gst_object_unref (allocator);
+
+ if (!gst_buffer_pool_set_active (pool, TRUE)) {
+ GST_WARNING ("Failed to create internal pool");
+ gst_object_unref (pool);
+ return -1;
+ }
+
+ dec->pool = pool;
+ dec->buf_size = min_size;
+ }
+
+ ret = gst_buffer_pool_acquire_buffer (dec->pool, &buffer, NULL);
+ if (ret != GST_FLOW_OK) {
+ GST_WARNING ("Failed to acquire buffer from internal pool.");
+ return -1;
+ }
+
+ frame = g_new0 (struct Frame, 1);
+ if (!gst_buffer_map (buffer, &frame->info, GST_MAP_READWRITE)) {
+ gst_buffer_unref (buffer);
+ g_free (frame);
+ GST_WARNING ("Failed to map buffer from internal pool.");
+ return -1;
+ }
+
+ fb->size = frame->info.size;
+ fb->data = frame->info.data;
+ frame->buffer = buffer;
+ fb->priv = frame;
+
+ GST_TRACE_OBJECT (priv, "Allocated buffer %p", frame->buffer);
+
+ return 0;
+}
+
+static int
+gst_vp8_dec_release_buffer_cb (gpointer priv, vpx_codec_frame_buffer_t * fb)
+{
+ struct Frame *frame = fb->priv;
+
+ GST_TRACE_OBJECT (priv, "Release buffer %p", frame->buffer);
+
+ g_assert (frame);
+ gst_buffer_unmap (frame->buffer, &frame->info);
+ gst_buffer_unref (frame->buffer);
+ g_free (frame);
+
+ return 0;
+}
+#endif
+
static void
gst_vp8_dec_image_to_buffer (GstVP8Dec * dec, const vpx_image_t * img,
GstBuffer * buffer)
gst_vpx_error_name (status));
}
}
+#ifdef HAVE_VPX_1_4
+ vpx_codec_set_frame_buffer_functions (&dec->decoder,
+ gst_vp8_dec_get_buffer_cb, gst_vp8_dec_release_buffer_cb, dec);
+#endif
dec->decoder_inited = TRUE;
/* No need to call negotiate() here, it will be automatically called
* by allocate_output_frame() below */
}
-
- ret = gst_video_decoder_allocate_output_frame (decoder, frame);
-
- if (ret == GST_FLOW_OK) {
- gst_vp8_dec_image_to_buffer (dec, img, frame->output_buffer);
+#ifdef HAVE_VPX_1_4
+ if (img->fb_priv && dec->have_video_meta) {
+ frame->output_buffer = gst_vp8_dec_prepare_image (dec, img);
ret = gst_video_decoder_finish_frame (decoder, frame);
- } else {
- gst_video_decoder_drop_frame (decoder, frame);
+ } else
+#endif
+ {
+ ret = gst_video_decoder_allocate_output_frame (decoder, frame);
+
+ if (ret == GST_FLOW_OK) {
+ gst_vp8_dec_image_to_buffer (dec, img, frame->output_buffer);
+ ret = gst_video_decoder_finish_frame (decoder, frame);
+ } else {
+ gst_video_decoder_drop_frame (decoder, frame);
+ }
}
}
static gboolean
gst_vp8_dec_decide_allocation (GstVideoDecoder * bdec, GstQuery * query)
{
+ GstVP8Dec *dec = GST_VP8_DEC (bdec);
GstBufferPool *pool;
GstStructure *config;
if (gst_query_find_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL)) {
gst_buffer_pool_config_add_option (config,
GST_BUFFER_POOL_OPTION_VIDEO_META);
+ dec->have_video_meta = TRUE;
}
gst_buffer_pool_set_config (pool, config);
gst_object_unref (pool);
GstVideoCodecState *input_state;
GstVideoCodecState *output_state;
+
+ /* allocation */
+ gboolean have_video_meta;
+ GstBufferPool *pool;
+ gsize buf_size;
};
struct _GstVP8DecClass
vpx_codec_destroy (&gst_vp9_dec->decoder);
gst_vp9_dec->decoder_inited = FALSE;
+ if (gst_vp9_dec->pool) {
+ gst_buffer_pool_set_active (gst_vp9_dec->pool, FALSE);
+ gst_object_unref (gst_vp9_dec->pool);
+ gst_vp9_dec->pool = NULL;
+ gst_vp9_dec->buf_size = 0;
+ }
+
return TRUE;
}
gst_event_new_tag (list));
}
+#ifdef HAVE_VPX_1_4
+struct Frame
+{
+ GstMapInfo info;
+ GstBuffer *buffer;
+};
+
+static GstBuffer *
+gst_vp9_dec_prepare_image (GstVP9Dec * dec, const vpx_image_t * img)
+{
+ gint comp;
+ GstVideoMeta *vmeta;
+ GstBuffer *buffer;
+ struct Frame *frame = img->fb_priv;
+ GstVideoInfo *info = &dec->output_state->info;
+
+ buffer = gst_buffer_ref (frame->buffer);
+
+ vmeta = gst_buffer_get_video_meta (buffer);
+ vmeta->format = GST_VIDEO_INFO_FORMAT (info);
+ vmeta->width = GST_VIDEO_INFO_WIDTH (info);
+ vmeta->height = GST_VIDEO_INFO_HEIGHT (info);
+ vmeta->n_planes = GST_VIDEO_INFO_N_PLANES (info);
+
+ for (comp = 0; comp < 4; comp++) {
+ vmeta->stride[comp] = img->stride[comp];
+ vmeta->offset[comp] =
+ img->planes[comp] ? img->planes[comp] - frame->info.data : 0;
+ }
+
+ /* FIXME This is a READ/WRITE mapped buffer see bug #754826 */
+
+ return buffer;
+}
+
+static int
+gst_vp9_dec_get_buffer_cb (gpointer priv, gsize min_size,
+ vpx_codec_frame_buffer_t * fb)
+{
+ GstVP9Dec *dec = priv;
+ GstBuffer *buffer;
+ struct Frame *frame;
+ GstFlowReturn ret;
+
+ if (!dec->pool || dec->buf_size != min_size) {
+ GstBufferPool *pool;
+ GstStructure *config;
+ GstCaps *caps;
+ GstAllocator *allocator;
+ GstAllocationParams params;
+
+ if (dec->pool) {
+ gst_buffer_pool_set_active (dec->pool, FALSE);
+ gst_object_unref (dec->pool);
+ dec->pool = NULL;
+ dec->buf_size = 0;
+ }
+
+ gst_video_decoder_get_allocator (GST_VIDEO_DECODER (dec), &allocator,
+ ¶ms);
+
+ if (allocator &&
+ GST_OBJECT_FLAG_IS_SET (allocator, GST_ALLOCATOR_FLAG_CUSTOM_ALLOC)) {
+ gst_object_unref (allocator);
+ allocator = NULL;
+ }
+
+ pool = gst_buffer_pool_new ();
+ config = gst_buffer_pool_get_config (pool);
+ gst_buffer_pool_config_set_allocator (config, allocator, ¶ms);
+ caps = gst_caps_from_string ("video/internal");
+ gst_buffer_pool_config_set_params (config, caps, min_size, 2, 0);
+ gst_caps_unref (caps);
+ gst_buffer_pool_set_config (pool, config);
+
+ if (allocator)
+ gst_object_unref (allocator);
+
+ if (!gst_buffer_pool_set_active (pool, TRUE)) {
+ GST_WARNING ("Failed to create internal pool");
+ gst_object_unref (pool);
+ return -1;
+ }
+
+ dec->pool = pool;
+ dec->buf_size = min_size;
+ }
+
+ ret = gst_buffer_pool_acquire_buffer (dec->pool, &buffer, NULL);
+ if (ret != GST_FLOW_OK) {
+ GST_WARNING ("Failed to acquire buffer from internal pool.");
+ return -1;
+ }
+
+ /* Add it now, while the buffer is writable */
+ gst_buffer_add_video_meta (buffer, GST_VIDEO_FRAME_FLAG_NONE,
+ GST_VIDEO_FORMAT_ENCODED, 0, 0);
+
+ frame = g_new0 (struct Frame, 1);
+ if (!gst_buffer_map (buffer, &frame->info, GST_MAP_READWRITE)) {
+ gst_buffer_unref (buffer);
+ g_free (frame);
+ GST_WARNING ("Failed to map buffer from internal pool.");
+ return -1;
+ }
+
+ fb->size = frame->info.size;
+ fb->data = frame->info.data;
+ frame->buffer = buffer;
+ fb->priv = frame;
+
+ GST_TRACE_OBJECT (priv, "Allocated buffer %p", frame->buffer);
+
+ return 0;
+}
+
+static int
+gst_vp9_dec_release_buffer_cb (gpointer priv, vpx_codec_frame_buffer_t * fb)
+{
+ struct Frame *frame = fb->priv;
+
+ GST_TRACE_OBJECT (priv, "Release buffer %p", frame->buffer);
+
+ g_assert (frame);
+ gst_buffer_unmap (frame->buffer, &frame->info);
+ gst_buffer_unref (frame->buffer);
+ g_free (frame);
+
+ return 0;
+}
+#endif
+
static void
gst_vp9_dec_image_to_buffer (GstVP9Dec * dec, const vpx_image_t * img,
GstBuffer * buffer)
gst_vpx_error_name (status));
}
}
+#ifdef HAVE_VPX_1_4
+ vpx_codec_set_frame_buffer_functions (&dec->decoder,
+ gst_vp9_dec_get_buffer_cb, gst_vp9_dec_release_buffer_cb, dec);
+#endif
dec->decoder_inited = TRUE;
(double) -deadline / GST_SECOND);
gst_video_decoder_drop_frame (decoder, frame);
} else {
- ret = gst_video_decoder_allocate_output_frame (decoder, frame);
-
- if (ret == GST_FLOW_OK) {
- gst_vp9_dec_image_to_buffer (dec, img, frame->output_buffer);
+#ifdef HAVE_VPX_1_4
+ if (img->fb_priv && dec->have_video_meta) {
+ frame->output_buffer = gst_vp9_dec_prepare_image (dec, img);
ret = gst_video_decoder_finish_frame (decoder, frame);
- } else {
- gst_video_decoder_drop_frame (decoder, frame);
+ } else
+#endif
+ {
+ ret = gst_video_decoder_allocate_output_frame (decoder, frame);
+
+ if (ret == GST_FLOW_OK) {
+ gst_vp9_dec_image_to_buffer (dec, img, frame->output_buffer);
+ ret = gst_video_decoder_finish_frame (decoder, frame);
+ } else {
+ gst_video_decoder_drop_frame (decoder, frame);
+ }
}
}
static gboolean
gst_vp9_dec_decide_allocation (GstVideoDecoder * bdec, GstQuery * query)
{
+ GstVP9Dec *dec = GST_VP9_DEC (bdec);
GstBufferPool *pool;
GstStructure *config;
if (gst_query_find_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL)) {
gst_buffer_pool_config_add_option (config,
GST_BUFFER_POOL_OPTION_VIDEO_META);
+ dec->have_video_meta = TRUE;
}
gst_buffer_pool_set_config (pool, config);
gst_object_unref (pool);
GstVideoCodecState *input_state;
GstVideoCodecState *output_state;
+
+ /* allocation */
+ gboolean have_video_meta;
+ GstBufferPool *pool;
+ gsize buf_size;
};
struct _GstVP9DecClass