mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-03-27 11:32:51 +00:00
ffmpegviddec: Port to 0.11 again
No support for video meta, cropping, etc. yet
This commit is contained in:
parent
85f0dcb1e8
commit
6ff10a922a
1 changed files with 105 additions and 47 deletions
|
@ -24,7 +24,7 @@
|
|||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef HAVE_FFMPEG_UNINSTALLED
|
||||
#ifdef HAVE_LIBAV_UNINSTALLED
|
||||
#include <avcodec.h>
|
||||
#else
|
||||
#include <libavcodec/avcodec.h>
|
||||
|
@ -91,7 +91,6 @@ struct _GstFFMpegVidDecClass
|
|||
AVCodec *in_plugin;
|
||||
};
|
||||
|
||||
|
||||
#define GST_TYPE_FFMPEGDEC \
|
||||
(gst_ffmpegviddec_get_type())
|
||||
#define GST_FFMPEGDEC(obj) \
|
||||
|
@ -155,7 +154,7 @@ static void gst_ffmpegviddec_release_buffer (AVCodecContext * context,
|
|||
static GstFlowReturn gst_ffmpegviddec_finish (GstVideoDecoder * decoder);
|
||||
static void gst_ffmpegviddec_drain (GstFFMpegVidDec * ffmpegdec);
|
||||
|
||||
#define GST_FFDEC_PARAMS_QDATA g_quark_from_static_string("ffdec-params")
|
||||
#define GST_FFDEC_PARAMS_QDATA g_quark_from_static_string("avdec-params")
|
||||
|
||||
static GstElementClass *parent_class = NULL;
|
||||
|
||||
|
@ -174,7 +173,7 @@ gst_ffmpegviddec_lowres_get_type (void)
|
|||
};
|
||||
|
||||
ffmpegdec_lowres_type =
|
||||
g_enum_register_static ("GstFFMpegVidDecLowres", ffmpegdec_lowres);
|
||||
g_enum_register_static ("GstLibAVVidDecLowres", ffmpegdec_lowres);
|
||||
}
|
||||
|
||||
return ffmpegdec_lowres_type;
|
||||
|
@ -196,8 +195,7 @@ gst_ffmpegviddec_skipframe_get_type (void)
|
|||
};
|
||||
|
||||
ffmpegdec_skipframe_type =
|
||||
g_enum_register_static ("GstFFMpegVidDecSkipFrame",
|
||||
ffmpegdec_skipframe);
|
||||
g_enum_register_static ("GstLibAVVidDecSkipFrame", ffmpegdec_skipframe);
|
||||
}
|
||||
|
||||
return ffmpegdec_skipframe_type;
|
||||
|
@ -218,9 +216,9 @@ gst_ffmpegviddec_base_init (GstFFMpegVidDecClass * klass)
|
|||
g_assert (in_plugin != NULL);
|
||||
|
||||
/* construct the element details struct */
|
||||
longname = g_strdup_printf ("FFmpeg %s decoder", in_plugin->long_name);
|
||||
description = g_strdup_printf ("FFmpeg %s decoder", in_plugin->name);
|
||||
gst_element_class_set_details_simple (element_class, longname,
|
||||
longname = g_strdup_printf ("libav %s decoder", in_plugin->long_name);
|
||||
description = g_strdup_printf ("libav %s decoder", in_plugin->name);
|
||||
gst_element_class_set_metadata (element_class, longname,
|
||||
"Codec/Decoder/Video", description,
|
||||
"Wim Taymans <wim.taymans@gmail.com>, "
|
||||
"Ronald Bultje <rbultje@ronald.bitfreak.net>, "
|
||||
|
@ -232,11 +230,9 @@ gst_ffmpegviddec_base_init (GstFFMpegVidDecClass * klass)
|
|||
sinkcaps = gst_ffmpeg_codecid_to_caps (in_plugin->id, NULL, FALSE);
|
||||
if (!sinkcaps) {
|
||||
GST_DEBUG ("Couldn't get sink caps for decoder '%s'", in_plugin->name);
|
||||
sinkcaps = gst_caps_from_string ("unknown/unknown");
|
||||
sinkcaps = gst_caps_new_empty_simple ("unknown/unknown");
|
||||
}
|
||||
srccaps =
|
||||
gst_caps_from_string
|
||||
("video/x-raw-rgb; video/x-raw-yuv; video/x-raw-gray");
|
||||
srccaps = gst_caps_new_empty_simple ("video/x-raw");
|
||||
|
||||
/* pad templates */
|
||||
sinktempl = gst_pad_template_new ("sink", GST_PAD_SINK,
|
||||
|
@ -283,7 +279,7 @@ gst_ffmpegviddec_class_init (GstFFMpegVidDecClass * klass)
|
|||
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||
g_object_class_install_property (gobject_class, PROP_DEBUG_MV,
|
||||
g_param_spec_boolean ("debug-mv", "Debug motion vectors",
|
||||
"Whether ffmpeg should print motion vectors on top of the image",
|
||||
"Whether libav should print motion vectors on top of the image",
|
||||
DEFAULT_DEBUG_MV, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
caps = klass->in_plugin->capabilities;
|
||||
|
@ -378,7 +374,7 @@ gst_ffmpegviddec_open (GstFFMpegVidDec * ffmpegdec)
|
|||
ffmpegdec->opened = TRUE;
|
||||
ffmpegdec->is_realvideo = FALSE;
|
||||
|
||||
GST_LOG_OBJECT (ffmpegdec, "Opened ffmpeg codec %s, id %d",
|
||||
GST_LOG_OBJECT (ffmpegdec, "Opened libav codec %s, id %d",
|
||||
oclass->in_plugin->name, oclass->in_plugin->id);
|
||||
|
||||
switch (oclass->in_plugin->id) {
|
||||
|
@ -401,7 +397,7 @@ gst_ffmpegviddec_open (GstFFMpegVidDec * ffmpegdec)
|
|||
could_not_open:
|
||||
{
|
||||
gst_ffmpegviddec_close (ffmpegdec);
|
||||
GST_DEBUG_OBJECT (ffmpegdec, "ffdec_%s: Failed to open FFMPEG codec",
|
||||
GST_DEBUG_OBJECT (ffmpegdec, "avdec_%s: Failed to open libav codec",
|
||||
oclass->in_plugin->name);
|
||||
return FALSE;
|
||||
}
|
||||
|
@ -562,6 +558,8 @@ alloc_output_buffer (GstFFMpegVidDec * ffmpegdec, GstVideoCodecFrame * frame)
|
|||
fsize = GST_VIDEO_INFO_SIZE (&ffmpegdec->output_state->info);
|
||||
|
||||
if (!ffmpegdec->context->palctrl && ffmpegdec->can_allocate_aligned) {
|
||||
GstMapInfo minfo;
|
||||
|
||||
GST_LOG_OBJECT (ffmpegdec, "calling pad_alloc");
|
||||
/* no pallete, we can use the buffer size to alloc */
|
||||
ret =
|
||||
|
@ -571,12 +569,19 @@ alloc_output_buffer (GstFFMpegVidDec * ffmpegdec, GstVideoCodecFrame * frame)
|
|||
goto alloc_failed;
|
||||
|
||||
/* If buffer isn't 128-bit aligned, create a memaligned one ourselves */
|
||||
if (((uintptr_t) GST_BUFFER_DATA (frame->output_buffer)) % 16) {
|
||||
if (!gst_buffer_map (frame->output_buffer, &minfo,
|
||||
GST_MAP_READ | GST_MAP_WRITE))
|
||||
goto alloc_failed;
|
||||
|
||||
if (((uintptr_t) minfo.data) % 16) {
|
||||
gst_buffer_unmap (frame->output_buffer, &minfo);
|
||||
GST_DEBUG_OBJECT (ffmpegdec,
|
||||
"Downstream can't allocate aligned buffers.");
|
||||
ffmpegdec->can_allocate_aligned = FALSE;
|
||||
gst_buffer_unref (frame->output_buffer);
|
||||
frame->output_buffer = new_aligned_buffer (fsize, NULL);
|
||||
frame->output_buffer = new_aligned_buffer (fsize);
|
||||
} else {
|
||||
gst_buffer_unmap (frame->output_buffer, &minfo);
|
||||
}
|
||||
} else {
|
||||
GST_LOG_OBJECT (ffmpegdec,
|
||||
|
@ -585,7 +590,7 @@ alloc_output_buffer (GstFFMpegVidDec * ffmpegdec, GstVideoCodecFrame * frame)
|
|||
* fsize contains the size of the palette, so the overall size
|
||||
* is bigger than ffmpegcolorspace's unit size, which will
|
||||
* prompt GstBaseTransform to complain endlessly ... */
|
||||
frame->output_buffer = new_aligned_buffer (fsize, NULL);
|
||||
frame->output_buffer = new_aligned_buffer (fsize);
|
||||
ret = GST_FLOW_OK;
|
||||
}
|
||||
|
||||
|
@ -605,10 +610,38 @@ alloc_failed:
|
|||
}
|
||||
}
|
||||
|
||||
typedef struct
|
||||
{
|
||||
GstVideoCodecFrame *frame;
|
||||
gboolean mapped;
|
||||
GstVideoFrame vframe;
|
||||
} GstFFMpegVidDecVideoFrame;
|
||||
|
||||
static GstFFMpegVidDecVideoFrame *
|
||||
gst_ffmpegviddec_video_frame_new (GstVideoCodecFrame * frame)
|
||||
{
|
||||
GstFFMpegVidDecVideoFrame *dframe;
|
||||
|
||||
dframe = g_slice_new0 (GstFFMpegVidDecVideoFrame);
|
||||
dframe->frame = gst_video_codec_frame_ref (frame);
|
||||
|
||||
return dframe;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_ffmpegviddec_video_frame_free (GstFFMpegVidDecVideoFrame * frame)
|
||||
{
|
||||
if (frame->mapped)
|
||||
gst_video_frame_unmap (&frame->vframe);
|
||||
gst_video_codec_frame_unref (frame->frame);
|
||||
g_slice_free (GstFFMpegVidDecVideoFrame, frame);
|
||||
}
|
||||
|
||||
static int
|
||||
gst_ffmpegviddec_get_buffer (AVCodecContext * context, AVFrame * picture)
|
||||
{
|
||||
GstVideoCodecFrame *frame;
|
||||
GstFFMpegVidDecVideoFrame *dframe;
|
||||
GstFFMpegVidDec *ffmpegdec;
|
||||
gint width, height;
|
||||
gint coded_width, coded_height;
|
||||
|
@ -617,7 +650,6 @@ gst_ffmpegviddec_get_buffer (AVCodecContext * context, AVFrame * picture)
|
|||
GstVideoInfo *info;
|
||||
GstFlowReturn ret;
|
||||
|
||||
|
||||
ffmpegdec = (GstFFMpegVidDec *) context->opaque;
|
||||
|
||||
GST_DEBUG_OBJECT (ffmpegdec, "getting buffer");
|
||||
|
@ -633,7 +665,7 @@ gst_ffmpegviddec_get_buffer (AVCodecContext * context, AVFrame * picture)
|
|||
if (G_UNLIKELY (frame == NULL))
|
||||
goto no_frame;
|
||||
|
||||
picture->opaque = frame;
|
||||
picture->opaque = dframe = gst_ffmpegviddec_video_frame_new (frame);
|
||||
|
||||
if (!ffmpegdec->current_dr) {
|
||||
GST_LOG_OBJECT (ffmpegdec, "direct rendering disabled, fallback alloc");
|
||||
|
@ -676,12 +708,19 @@ gst_ffmpegviddec_get_buffer (AVCodecContext * context, AVFrame * picture)
|
|||
|
||||
/* Fill avpicture */
|
||||
info = &ffmpegdec->output_state->info;
|
||||
if (!gst_video_frame_map (&dframe->vframe, info, dframe->frame->output_buffer,
|
||||
GST_MAP_READ | GST_MAP_WRITE)) {
|
||||
GST_LOG_OBJECT (ffmpegdec, "failed to map frame, fallback alloc");
|
||||
gst_buffer_unref (frame->output_buffer);
|
||||
frame->output_buffer = NULL;
|
||||
return avcodec_default_get_buffer (context, picture);
|
||||
}
|
||||
dframe->mapped = TRUE;
|
||||
|
||||
for (c = 0; c < AV_NUM_DATA_POINTERS; c++) {
|
||||
if (c < GST_VIDEO_INFO_N_PLANES (info)) {
|
||||
picture->data[c] =
|
||||
GST_BUFFER_DATA (frame->output_buffer) +
|
||||
GST_VIDEO_INFO_PLANE_OFFSET (info, c);
|
||||
picture->linesize[c] = GST_VIDEO_INFO_PLANE_STRIDE (info, c);
|
||||
picture->data[c] = GST_VIDEO_FRAME_PLANE_DATA (&dframe->vframe, c);
|
||||
picture->linesize[c] = GST_VIDEO_FRAME_COMP_STRIDE (&dframe->vframe, c);
|
||||
} else {
|
||||
picture->data[c] = NULL;
|
||||
picture->linesize[c] = 0;
|
||||
|
@ -710,12 +749,13 @@ static void
|
|||
gst_ffmpegviddec_release_buffer (AVCodecContext * context, AVFrame * picture)
|
||||
{
|
||||
gint i;
|
||||
GstVideoCodecFrame *frame;
|
||||
GstFFMpegVidDecVideoFrame *frame;
|
||||
GstFFMpegVidDec *ffmpegdec;
|
||||
|
||||
ffmpegdec = (GstFFMpegVidDec *) context->opaque;
|
||||
frame = (GstVideoCodecFrame *) picture->opaque;
|
||||
GST_DEBUG_OBJECT (ffmpegdec, "release frame %d", frame->system_frame_number);
|
||||
frame = (GstFFMpegVidDecVideoFrame *) picture->opaque;
|
||||
GST_DEBUG_OBJECT (ffmpegdec, "release frame %d",
|
||||
frame->frame->system_frame_number);
|
||||
|
||||
/* check if it was our buffer */
|
||||
if (picture->type != FF_BUFFER_TYPE_USER) {
|
||||
|
@ -726,7 +766,7 @@ gst_ffmpegviddec_release_buffer (AVCodecContext * context, AVFrame * picture)
|
|||
/* we remove the opaque data now */
|
||||
picture->opaque = NULL;
|
||||
|
||||
gst_video_codec_frame_unref (frame);
|
||||
gst_ffmpegviddec_video_frame_free (frame);
|
||||
|
||||
/* zero out the reference in ffmpeg */
|
||||
for (i = 0; i < 4; i++) {
|
||||
|
@ -906,6 +946,7 @@ get_output_buffer (GstFFMpegVidDec * ffmpegdec, GstVideoCodecFrame * frame)
|
|||
{
|
||||
GstFlowReturn ret = GST_FLOW_OK;
|
||||
AVPicture pic, *outpic;
|
||||
GstVideoFrame vframe;
|
||||
GstVideoInfo *info;
|
||||
gint c;
|
||||
|
||||
|
@ -919,12 +960,14 @@ get_output_buffer (GstFFMpegVidDec * ffmpegdec, GstVideoCodecFrame * frame)
|
|||
* This patched up version does */
|
||||
/* Fill avpicture */
|
||||
info = &ffmpegdec->output_state->info;
|
||||
if (!gst_video_frame_map (&vframe, info, frame->output_buffer,
|
||||
GST_MAP_READ | GST_MAP_WRITE))
|
||||
goto alloc_failed;
|
||||
|
||||
for (c = 0; c < AV_NUM_DATA_POINTERS; c++) {
|
||||
if (c < GST_VIDEO_INFO_N_COMPONENTS (info)) {
|
||||
pic.data[c] =
|
||||
GST_BUFFER_DATA (frame->output_buffer) +
|
||||
GST_VIDEO_INFO_COMP_OFFSET (info, c);
|
||||
pic.linesize[c] = GST_VIDEO_INFO_COMP_STRIDE (info, c);
|
||||
pic.data[c] = GST_VIDEO_FRAME_PLANE_DATA (&vframe, c);
|
||||
pic.linesize[c] = GST_VIDEO_FRAME_COMP_STRIDE (&vframe, c);
|
||||
} else {
|
||||
pic.data[c] = NULL;
|
||||
pic.linesize[c] = 0;
|
||||
|
@ -942,6 +985,8 @@ get_output_buffer (GstFFMpegVidDec * ffmpegdec, GstVideoCodecFrame * frame)
|
|||
av_picture_copy (&pic, outpic, ffmpegdec->context->pix_fmt,
|
||||
GST_VIDEO_INFO_WIDTH (info), GST_VIDEO_INFO_HEIGHT (info));
|
||||
|
||||
gst_video_frame_unmap (&vframe);
|
||||
|
||||
ffmpegdec->picture->reordered_opaque = -1;
|
||||
|
||||
return ret;
|
||||
|
@ -985,6 +1030,7 @@ gst_ffmpegviddec_video_frame (GstFFMpegVidDec * ffmpegdec,
|
|||
gboolean decode;
|
||||
gint skip_frame = AVDISCARD_DEFAULT;
|
||||
GstVideoCodecFrame *out_frame;
|
||||
GstFFMpegVidDecVideoFrame *out_dframe;
|
||||
AVPacket packet;
|
||||
|
||||
*ret = GST_FLOW_OK;
|
||||
|
@ -1034,6 +1080,16 @@ gst_ffmpegviddec_video_frame (GstFFMpegVidDec * ffmpegdec,
|
|||
|
||||
/* now decode the frame */
|
||||
gst_avpacket_init (&packet, data, size);
|
||||
|
||||
if (ffmpegdec->context->palctrl) {
|
||||
guint8 *pal;
|
||||
|
||||
pal = av_packet_new_side_data (&packet, AV_PKT_DATA_PALETTE,
|
||||
AVPALETTE_SIZE);
|
||||
memcpy (pal, ffmpegdec->context->palctrl->palette, AVPALETTE_SIZE);
|
||||
GST_DEBUG_OBJECT (ffmpegdec, "copy pal %p %p", &packet, pal);
|
||||
}
|
||||
|
||||
len = avcodec_decode_video2 (ffmpegdec->context,
|
||||
ffmpegdec->picture, &have_data, &packet);
|
||||
|
||||
|
@ -1054,7 +1110,8 @@ gst_ffmpegviddec_video_frame (GstFFMpegVidDec * ffmpegdec,
|
|||
goto beach;
|
||||
|
||||
/* get the output picture timing info again */
|
||||
out_frame = ffmpegdec->picture->opaque;
|
||||
out_dframe = ffmpegdec->picture->opaque;
|
||||
out_frame = out_dframe->frame;
|
||||
|
||||
GST_DEBUG_OBJECT (ffmpegdec,
|
||||
"pts %" G_GUINT64_FORMAT " duration %" G_GUINT64_FORMAT,
|
||||
|
@ -1133,15 +1190,9 @@ gst_ffmpegviddec_video_frame (GstFFMpegVidDec * ffmpegdec,
|
|||
frame->n_fields = ffmpegdec->picture->repeat_pict;
|
||||
#endif
|
||||
|
||||
/* palette is not part of raw video frame in gst and the size
|
||||
* of the outgoing buffer needs to be adjusted accordingly */
|
||||
if (ffmpegdec->context->palctrl != NULL)
|
||||
GST_BUFFER_SIZE (out_frame->output_buffer) -= AVPALETTE_SIZE;
|
||||
|
||||
/* mark as keyframe or delta unit */
|
||||
if (ffmpegdec->picture->top_field_first)
|
||||
GST_VIDEO_CODEC_FRAME_FLAG_SET (out_frame, GST_VIDEO_CODEC_FRAME_FLAG_TFF);
|
||||
|
||||
GST_BUFFER_FLAG_SET (out_frame->output_buffer, GST_VIDEO_BUFFER_FLAG_TFF);
|
||||
|
||||
*ret =
|
||||
gst_video_decoder_finish_frame (GST_VIDEO_DECODER (ffmpegdec), out_frame);
|
||||
|
@ -1214,7 +1265,7 @@ gst_ffmpegviddec_frame (GstFFMpegVidDec * ffmpegdec,
|
|||
|
||||
if (len < 0 || have_data < 0) {
|
||||
GST_WARNING_OBJECT (ffmpegdec,
|
||||
"ffdec_%s: decoding error (len: %d, have_data: %d)",
|
||||
"avdec_%s: decoding error (len: %d, have_data: %d)",
|
||||
oclass->in_plugin->name, len, have_data);
|
||||
*got_data = 0;
|
||||
goto beach;
|
||||
|
@ -1267,7 +1318,8 @@ gst_ffmpegviddec_handle_frame (GstVideoDecoder * decoder,
|
|||
{
|
||||
GstFFMpegVidDec *ffmpegdec = (GstFFMpegVidDec *) decoder;
|
||||
guint8 *data, *bdata;
|
||||
gint size, bsize, len, have_data;
|
||||
gint size, len, have_data, bsize;
|
||||
GstMapInfo minfo;
|
||||
GstFlowReturn ret = GST_FLOW_OK;
|
||||
|
||||
/* do early keyframe check pretty bad to rely on the keyframe flag in the
|
||||
|
@ -1284,11 +1336,17 @@ gst_ffmpegviddec_handle_frame (GstVideoDecoder * decoder,
|
|||
GST_LOG_OBJECT (ffmpegdec,
|
||||
"Received new data of size %u, pts:%"
|
||||
GST_TIME_FORMAT ", dur:%" GST_TIME_FORMAT,
|
||||
GST_BUFFER_SIZE (frame->input_buffer),
|
||||
gst_buffer_get_size (frame->input_buffer),
|
||||
GST_TIME_ARGS (frame->pts), GST_TIME_ARGS (frame->duration));
|
||||
|
||||
bdata = GST_BUFFER_DATA (frame->input_buffer);
|
||||
bsize = GST_BUFFER_SIZE (frame->input_buffer);
|
||||
frame->input_buffer = gst_buffer_make_writable (frame->input_buffer);
|
||||
if (!gst_buffer_map (frame->input_buffer, &minfo,
|
||||
GST_MAP_READ | GST_MAP_WRITE)) {
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
|
||||
bdata = minfo.data;
|
||||
bsize = minfo.size;
|
||||
|
||||
if (ffmpegdec->do_padding) {
|
||||
/* add padding */
|
||||
|
@ -1576,7 +1634,7 @@ gst_ffmpegviddec_register (GstPlugin * plugin)
|
|||
/* construct the type */
|
||||
plugin_name = g_strdup ((gchar *) in_plugin->name);
|
||||
g_strdelimit (plugin_name, NULL, '_');
|
||||
type_name = g_strdup_printf ("ffdec_%s", plugin_name);
|
||||
type_name = g_strdup_printf ("avdec_%s", plugin_name);
|
||||
g_free (plugin_name);
|
||||
|
||||
type = g_type_from_name (type_name);
|
||||
|
|
Loading…
Reference in a new issue