aboutsummaryrefslogtreecommitdiff
path: root/ext/libav/gstavviddec.c
diff options
context:
space:
mode:
Diffstat (limited to 'ext/libav/gstavviddec.c')
-rw-r--r--ext/libav/gstavviddec.c113
1 files changed, 95 insertions, 18 deletions
diff --git a/ext/libav/gstavviddec.c b/ext/libav/gstavviddec.c
index d5dc37d..3e537a0 100644
--- a/ext/libav/gstavviddec.c
+++ b/ext/libav/gstavviddec.c
@@ -68,6 +68,7 @@ static gboolean gst_ffmpegviddec_set_format (GstVideoDecoder * decoder,
GstVideoCodecState * state);
static GstFlowReturn gst_ffmpegviddec_handle_frame (GstVideoDecoder * decoder,
GstVideoCodecFrame * frame);
+static gboolean gst_ffmpegviddec_start (GstVideoDecoder * decoder);
static gboolean gst_ffmpegviddec_stop (GstVideoDecoder * decoder);
static gboolean gst_ffmpegviddec_flush (GstVideoDecoder * decoder);
static gboolean gst_ffmpegviddec_decide_allocation (GstVideoDecoder * decoder,
@@ -81,7 +82,7 @@ static void gst_ffmpegviddec_get_property (GObject * object,
guint prop_id, GValue * value, GParamSpec * pspec);
static gboolean gst_ffmpegviddec_negotiate (GstFFMpegVidDec * ffmpegdec,
- gboolean force);
+ AVCodecContext * context, gboolean force);
/* some sort of bufferpool handling, but different */
static int gst_ffmpegviddec_get_buffer (AVCodecContext * context,
@@ -234,6 +235,7 @@ gst_ffmpegviddec_class_init (GstFFMpegVidDecClass * klass)
viddec_class->set_format = gst_ffmpegviddec_set_format;
viddec_class->handle_frame = gst_ffmpegviddec_handle_frame;
+ viddec_class->start = gst_ffmpegviddec_start;
viddec_class->stop = gst_ffmpegviddec_stop;
viddec_class->flush = gst_ffmpegviddec_flush;
viddec_class->finish = gst_ffmpegviddec_finish;
@@ -275,23 +277,40 @@ gst_ffmpegviddec_finalize (GObject * object)
/* with LOCK */
-static void
-gst_ffmpegviddec_close (GstFFMpegVidDec * ffmpegdec)
+static gboolean
+gst_ffmpegviddec_close (GstFFMpegVidDec * ffmpegdec, gboolean reset)
{
+ GstFFMpegVidDecClass *oclass;
+ gint i;
+
+ oclass = (GstFFMpegVidDecClass *) (G_OBJECT_GET_CLASS (ffmpegdec));
+
GST_LOG_OBJECT (ffmpegdec, "closing ffmpeg codec");
gst_caps_replace (&ffmpegdec->last_caps, NULL);
- if (ffmpegdec->context->priv_data)
- gst_ffmpeg_avcodec_close (ffmpegdec->context);
+ gst_ffmpeg_avcodec_close (ffmpegdec->context);
ffmpegdec->opened = FALSE;
+ for (i = 0; i < G_N_ELEMENTS (ffmpegdec->stride); i++)
+ ffmpegdec->stride[i] = -1;
+
gst_buffer_replace (&ffmpegdec->palette, NULL);
if (ffmpegdec->context->extradata) {
av_free (ffmpegdec->context->extradata);
ffmpegdec->context->extradata = NULL;
}
+
+ if (reset) {
+ if (avcodec_get_context_defaults3 (ffmpegdec->context,
+ oclass->in_plugin) < 0) {
+ GST_DEBUG_OBJECT (ffmpegdec, "Failed to set context defaults");
+ return FALSE;
+ }
+ ffmpegdec->context->opaque = ffmpegdec;
+ }
+ return TRUE;
}
/* with LOCK */
@@ -299,12 +318,16 @@ static gboolean
gst_ffmpegviddec_open (GstFFMpegVidDec * ffmpegdec)
{
GstFFMpegVidDecClass *oclass;
+ gint i;
oclass = (GstFFMpegVidDecClass *) (G_OBJECT_GET_CLASS (ffmpegdec));
if (gst_ffmpeg_avcodec_open (ffmpegdec->context, oclass->in_plugin) < 0)
goto could_not_open;
+ for (i = 0; i < G_N_ELEMENTS (ffmpegdec->stride); i++)
+ ffmpegdec->stride[i] = -1;
+
ffmpegdec->opened = TRUE;
ffmpegdec->is_realvideo = FALSE;
@@ -328,7 +351,7 @@ gst_ffmpegviddec_open (GstFFMpegVidDec * ffmpegdec)
/* ERRORS */
could_not_open:
{
- gst_ffmpegviddec_close (ffmpegdec);
+ gst_ffmpegviddec_close (ffmpegdec, TRUE);
GST_DEBUG_OBJECT (ffmpegdec, "avdec_%s: Failed to open libav codec",
oclass->in_plugin->name);
return FALSE;
@@ -384,7 +407,10 @@ gst_ffmpegviddec_set_format (GstVideoDecoder * decoder,
GST_OBJECT_UNLOCK (ffmpegdec);
gst_ffmpegviddec_drain (ffmpegdec);
GST_OBJECT_LOCK (ffmpegdec);
- gst_ffmpegviddec_close (ffmpegdec);
+ if (!gst_ffmpegviddec_close (ffmpegdec, TRUE)) {
+ GST_OBJECT_UNLOCK (ffmpegdec);
+ return FALSE;
+ }
}
gst_caps_replace (&ffmpegdec->last_caps, state->caps);
@@ -559,7 +585,7 @@ gst_ffmpegviddec_get_buffer (AVCodecContext * context, AVFrame * picture)
ffmpegdec->context->pix_fmt = context->pix_fmt;
/* see if we need renegotiation */
- if (G_UNLIKELY (!gst_ffmpegviddec_negotiate (ffmpegdec, FALSE)))
+ if (G_UNLIKELY (!gst_ffmpegviddec_negotiate (ffmpegdec, context, FALSE)))
goto negotiate_failed;
if (!ffmpegdec->current_dr)
@@ -582,6 +608,30 @@ gst_ffmpegviddec_get_buffer (AVCodecContext * context, AVFrame * picture)
if (c < GST_VIDEO_INFO_N_PLANES (info)) {
picture->data[c] = GST_VIDEO_FRAME_PLANE_DATA (&dframe->vframe, c);
picture->linesize[c] = GST_VIDEO_FRAME_PLANE_STRIDE (&dframe->vframe, c);
+
+ /* libav does not allow stride changes currently, fall back to
+ * non-direct rendering here:
+ * https://bugzilla.gnome.org/show_bug.cgi?id=704769
+ * https://bugzilla.libav.org/show_bug.cgi?id=556
+ */
+ if (ffmpegdec->stride[c] == -1) {
+ ffmpegdec->stride[c] = picture->linesize[c];
+ } else if (picture->linesize[c] != ffmpegdec->stride[c]) {
+ GST_LOG_OBJECT (ffmpegdec,
+ "No direct rendering, stride changed c=%d %d->%d", c,
+ ffmpegdec->stride[c], picture->linesize[c]);
+
+ for (c = 0; c < AV_NUM_DATA_POINTERS; c++) {
+ picture->data[c] = NULL;
+ picture->linesize[c] = 0;
+ }
+ gst_video_frame_unmap (&dframe->vframe);
+ dframe->mapped = FALSE;
+ gst_buffer_replace (&frame->output_buffer, NULL);
+ ffmpegdec->current_dr = FALSE;
+
+ goto no_dr;
+ }
} else {
picture->data[c] = NULL;
picture->linesize[c] = 0;
@@ -625,7 +675,13 @@ invalid_frame:
}
fallback:
{
- return avcodec_default_get_buffer (context, picture);
+ int c;
+ int ret = avcodec_default_get_buffer (context, picture);
+
+ for (c = 0; c < AV_NUM_DATA_POINTERS; c++)
+ ffmpegdec->stride[c] = picture->linesize[c];
+
+ return ret;
}
duplicate_frame:
{
@@ -722,10 +778,9 @@ gst_ffmpegviddec_release_buffer (AVCodecContext * context, AVFrame * picture)
}
static gboolean
-update_video_context (GstFFMpegVidDec * ffmpegdec, gboolean force)
+update_video_context (GstFFMpegVidDec * ffmpegdec, AVCodecContext * context,
+ gboolean force)
{
- AVCodecContext *context = ffmpegdec->context;
-
if (!force && ffmpegdec->ctx_width == context->width
&& ffmpegdec->ctx_height == context->height
&& ffmpegdec->ctx_ticks == context->ticks_per_frame
@@ -833,14 +888,15 @@ no_par:
}
static gboolean
-gst_ffmpegviddec_negotiate (GstFFMpegVidDec * ffmpegdec, gboolean force)
+gst_ffmpegviddec_negotiate (GstFFMpegVidDec * ffmpegdec,
+ AVCodecContext * context, gboolean force)
{
GstVideoFormat fmt;
GstVideoInfo *in_info, *out_info;
GstVideoCodecState *output_state;
gint fps_n, fps_d;
- if (!update_video_context (ffmpegdec, force))
+ if (!update_video_context (ffmpegdec, context, force))
return TRUE;
fmt = gst_ffmpeg_pixfmt_to_videoformat (ffmpegdec->ctx_pix_fmt);
@@ -1158,7 +1214,7 @@ gst_ffmpegviddec_video_frame (GstFFMpegVidDec * ffmpegdec,
GST_WARNING ("Change in interlacing ! picture:%d, recorded:%d",
ffmpegdec->picture->interlaced_frame, ffmpegdec->ctx_interlaced);
ffmpegdec->ctx_interlaced = ffmpegdec->picture->interlaced_frame;
- if (!gst_ffmpegviddec_negotiate (ffmpegdec, TRUE))
+ if (!gst_ffmpegviddec_negotiate (ffmpegdec, ffmpegdec->context, TRUE))
goto negotiation_error;
}
@@ -1404,13 +1460,34 @@ gst_ffmpegviddec_handle_frame (GstVideoDecoder * decoder,
return ret;
}
+
+static gboolean
+gst_ffmpegviddec_start (GstVideoDecoder * decoder)
+{
+ GstFFMpegVidDec *ffmpegdec = (GstFFMpegVidDec *) decoder;
+ GstFFMpegVidDecClass *oclass;
+
+ oclass = (GstFFMpegVidDecClass *) (G_OBJECT_GET_CLASS (ffmpegdec));
+
+ GST_OBJECT_LOCK (ffmpegdec);
+ if (avcodec_get_context_defaults3 (ffmpegdec->context, oclass->in_plugin) < 0) {
+ GST_DEBUG_OBJECT (ffmpegdec, "Failed to set context defaults");
+ GST_OBJECT_UNLOCK (ffmpegdec);
+ return FALSE;
+ }
+ ffmpegdec->context->opaque = ffmpegdec;
+ GST_OBJECT_UNLOCK (ffmpegdec);
+
+ return TRUE;
+}
+
static gboolean
gst_ffmpegviddec_stop (GstVideoDecoder * decoder)
{
GstFFMpegVidDec *ffmpegdec = (GstFFMpegVidDec *) decoder;
GST_OBJECT_LOCK (ffmpegdec);
- gst_ffmpegviddec_close (ffmpegdec);
+ gst_ffmpegviddec_close (ffmpegdec, FALSE);
GST_OBJECT_UNLOCK (ffmpegdec);
g_free (ffmpegdec->padded);
ffmpegdec->padded = NULL;
@@ -1503,8 +1580,8 @@ gst_ffmpegviddec_decide_allocation (GstVideoDecoder * decoder, GstQuery * query)
avcodec_align_dimensions2 (ffmpegdec->context, &width, &height,
linesize_align);
edge =
- ffmpegdec->
- context->flags & CODEC_FLAG_EMU_EDGE ? 0 : avcodec_get_edge_width ();
+ ffmpegdec->context->
+ flags & CODEC_FLAG_EMU_EDGE ? 0 : avcodec_get_edge_width ();
/* increase the size for the padding */
width += edge << 1;
height += edge << 1;