mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-02-02 04:22:27 +00:00
ffvidenc: Port to 0.11
This commit is contained in:
parent
de82bfbbba
commit
107c00a761
2 changed files with 70 additions and 56 deletions
|
@ -28,13 +28,14 @@
|
|||
#include <glib/gstdio.h>
|
||||
#include <errno.h>
|
||||
|
||||
#ifdef HAVE_FFMPEG_UNINSTALLED
|
||||
#ifdef HAVE_LIBAV_UNINSTALLED
|
||||
#include <avcodec.h>
|
||||
#else
|
||||
#include <libavcodec/avcodec.h>
|
||||
#endif
|
||||
|
||||
#include <gst/gst.h>
|
||||
#include <gst/video/gstvideometa.h>
|
||||
|
||||
#include "gstffmpeg.h"
|
||||
#include "gstffmpegcodecmap.h"
|
||||
|
@ -100,8 +101,11 @@ static gboolean gst_ffmpegvidenc_stop (GstVideoEncoder * encoder);
|
|||
static GstFlowReturn gst_ffmpegvidenc_finish (GstVideoEncoder * encoder);
|
||||
static gboolean gst_ffmpegvidenc_set_format (GstVideoEncoder * encoder,
|
||||
GstVideoCodecState * state);
|
||||
static gboolean gst_ffmpegvidenc_propose_allocation (GstVideoEncoder * encoder,
|
||||
GstQuery * query);
|
||||
|
||||
static GstCaps *gst_ffmpegvidenc_getcaps (GstVideoEncoder * encoder);
|
||||
static GstCaps *gst_ffmpegvidenc_getcaps (GstVideoEncoder * encoder,
|
||||
GstCaps * filter);
|
||||
static GstFlowReturn gst_ffmpegvidenc_handle_frame (GstVideoEncoder * encoder,
|
||||
GstVideoCodecFrame * frame);
|
||||
|
||||
|
@ -110,7 +114,7 @@ static void gst_ffmpegvidenc_set_property (GObject * object,
|
|||
static void gst_ffmpegvidenc_get_property (GObject * object,
|
||||
guint prop_id, GValue * value, GParamSpec * pspec);
|
||||
|
||||
#define GST_FFENC_PARAMS_QDATA g_quark_from_static_string("ffenc-params")
|
||||
#define GST_FFENC_PARAMS_QDATA g_quark_from_static_string("avenc-params")
|
||||
|
||||
static GstElementClass *parent_class = NULL;
|
||||
|
||||
|
@ -131,9 +135,9 @@ gst_ffmpegvidenc_base_init (GstFFMpegVidEncClass * klass)
|
|||
g_assert (in_plugin != NULL);
|
||||
|
||||
/* construct the element details struct */
|
||||
longname = g_strdup_printf ("FFmpeg %s encoder", in_plugin->long_name);
|
||||
description = g_strdup_printf ("FFmpeg %s encoder", in_plugin->name);
|
||||
gst_element_class_set_details_simple (element_class, longname,
|
||||
longname = g_strdup_printf ("libav %s encoder", in_plugin->long_name);
|
||||
description = g_strdup_printf ("libav %s encoder", in_plugin->name);
|
||||
gst_element_class_set_metadata (element_class, longname,
|
||||
"Codec/Encoder/Video", description,
|
||||
"Wim Taymans <wim.taymans@gmail.com>, "
|
||||
"Ronald Bultje <rbultje@ronald.bitfreak.net>");
|
||||
|
@ -142,11 +146,10 @@ gst_ffmpegvidenc_base_init (GstFFMpegVidEncClass * klass)
|
|||
|
||||
if (!(srccaps = gst_ffmpeg_codecid_to_caps (in_plugin->id, NULL, TRUE))) {
|
||||
GST_DEBUG ("Couldn't get source caps for encoder '%s'", in_plugin->name);
|
||||
srccaps = gst_caps_new_simple ("unknown/unknown", NULL);
|
||||
srccaps = gst_caps_new_empty_simple ("unknown/unknown");
|
||||
}
|
||||
|
||||
sinkcaps = gst_caps_from_string
|
||||
("video/x-raw-rgb; video/x-raw-yuv; video/x-raw-gray");
|
||||
sinkcaps = gst_caps_new_empty_simple ("video/x-raw");
|
||||
|
||||
/* pad templates */
|
||||
sinktempl = gst_pad_template_new ("sink", GST_PAD_SINK,
|
||||
|
@ -178,9 +181,11 @@ gst_ffmpegvidenc_class_init (GstFFMpegVidEncClass * klass)
|
|||
gobject_class->set_property = gst_ffmpegvidenc_set_property;
|
||||
gobject_class->get_property = gst_ffmpegvidenc_get_property;
|
||||
|
||||
/* FIXME: could use -1 for a sensible per-codec default based on
|
||||
* e.g. input resolution and framerate */
|
||||
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_BIT_RATE,
|
||||
g_param_spec_ulong ("bitrate", "Bit Rate",
|
||||
"Target Video Bitrate", 0, G_MAXULONG, DEFAULT_VIDEO_BITRATE,
|
||||
g_param_spec_int ("bitrate", "Bit Rate",
|
||||
"Target Video Bitrate", 0, G_MAXINT, DEFAULT_VIDEO_BITRATE,
|
||||
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_GOP_SIZE,
|
||||
g_param_spec_int ("gop-size", "GOP Size",
|
||||
|
@ -191,16 +196,13 @@ gst_ffmpegvidenc_class_init (GstFFMpegVidEncClass * klass)
|
|||
GST_TYPE_ME_METHOD, ME_EPZS,
|
||||
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
/* FIXME 0.11: Make this property read-only */
|
||||
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_BUFSIZE,
|
||||
g_param_spec_ulong ("buffer-size", "Buffer Size",
|
||||
"Size of the video buffers. "
|
||||
"Note: Setting this property has no effect "
|
||||
"and is deprecated!", 0, G_MAXULONG, 0,
|
||||
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||
g_param_spec_int ("buffer-size", "Buffer Size",
|
||||
"Size of the video buffers", 0, G_MAXINT, 0,
|
||||
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
|
||||
g_object_class_install_property (G_OBJECT_CLASS (klass),
|
||||
ARG_RTP_PAYLOAD_SIZE, g_param_spec_ulong ("rtp-payload-size",
|
||||
"RTP Payload Size", "Target GOB length", 0, G_MAXULONG, 0,
|
||||
ARG_RTP_PAYLOAD_SIZE, g_param_spec_int ("rtp-payload-size",
|
||||
"RTP Payload Size", "Target GOB length", 0, G_MAXINT, 0,
|
||||
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
/* register additional properties, possibly dependent on the exact CODEC */
|
||||
|
@ -211,6 +213,7 @@ gst_ffmpegvidenc_class_init (GstFFMpegVidEncClass * klass)
|
|||
venc_class->handle_frame = gst_ffmpegvidenc_handle_frame;
|
||||
venc_class->getcaps = gst_ffmpegvidenc_getcaps;
|
||||
venc_class->set_format = gst_ffmpegvidenc_set_format;
|
||||
venc_class->propose_allocation = gst_ffmpegvidenc_propose_allocation;
|
||||
|
||||
gobject_class->finalize = gst_ffmpegvidenc_finalize;
|
||||
}
|
||||
|
@ -261,7 +264,7 @@ gst_ffmpegvidenc_finalize (GObject * object)
|
|||
}
|
||||
|
||||
static GstCaps *
|
||||
gst_ffmpegvidenc_getcaps (GstVideoEncoder * encoder)
|
||||
gst_ffmpegvidenc_getcaps (GstVideoEncoder * encoder, GstCaps * filter)
|
||||
{
|
||||
GstFFMpegVidEnc *ffmpegenc = (GstFFMpegVidEnc *) encoder;
|
||||
GstFFMpegVidEncClass *oclass =
|
||||
|
@ -275,7 +278,7 @@ gst_ffmpegvidenc_getcaps (GstVideoEncoder * encoder)
|
|||
|
||||
/* cached */
|
||||
if (oclass->sinkcaps) {
|
||||
caps = gst_video_encoder_proxy_getcaps (encoder, oclass->sinkcaps);
|
||||
caps = gst_video_encoder_proxy_getcaps (encoder, oclass->sinkcaps, filter);
|
||||
GST_DEBUG_OBJECT (ffmpegenc, "return cached caps %" GST_PTR_FORMAT, caps);
|
||||
return caps;
|
||||
}
|
||||
|
@ -372,9 +375,9 @@ gst_ffmpegvidenc_getcaps (GstVideoEncoder * encoder)
|
|||
_shut_up_I_am_probing = FALSE;
|
||||
#endif
|
||||
|
||||
oclass->sinkcaps = gst_video_encoder_proxy_getcaps (encoder, caps);
|
||||
oclass->sinkcaps = caps;
|
||||
|
||||
return gst_caps_ref (oclass->sinkcaps);
|
||||
return gst_video_encoder_proxy_getcaps (encoder, caps, filter);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
|
@ -394,12 +397,6 @@ gst_ffmpegvidenc_set_format (GstVideoEncoder * encoder,
|
|||
if (ffmpegenc->opened) {
|
||||
gst_ffmpeg_avcodec_close (ffmpegenc->context);
|
||||
ffmpegenc->opened = FALSE;
|
||||
#if 0
|
||||
/* FIXME : Is this still needed with GstVideoEncoder ?? */
|
||||
/* fixed src caps;
|
||||
* so clear src caps for proper (re-)negotiation */
|
||||
gst_pad_set_caps (ffmpegenc->srcpad, NULL);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* set defaults */
|
||||
|
@ -532,8 +529,7 @@ gst_ffmpegvidenc_set_format (GstVideoEncoder * encoder,
|
|||
/* we need to copy because get_allowed_caps returns a ref, and
|
||||
* get_pad_template_caps doesn't */
|
||||
allowed_caps =
|
||||
gst_caps_copy (gst_pad_get_pad_template_caps (GST_VIDEO_ENCODER_SRC_PAD
|
||||
(encoder)));
|
||||
gst_pad_get_pad_template_caps (GST_VIDEO_ENCODER_SRC_PAD (encoder));
|
||||
}
|
||||
GST_DEBUG_OBJECT (ffmpegenc, "chose caps %" GST_PTR_FORMAT, allowed_caps);
|
||||
gst_ffmpeg_caps_with_codecid (oclass->in_plugin->id,
|
||||
|
@ -543,8 +539,10 @@ gst_ffmpegvidenc_set_format (GstVideoEncoder * encoder,
|
|||
other_caps = gst_ffmpeg_codecid_to_caps (oclass->in_plugin->id,
|
||||
ffmpegenc->context, TRUE);
|
||||
|
||||
if (!other_caps)
|
||||
if (!other_caps) {
|
||||
gst_caps_unref (allowed_caps);
|
||||
goto unsupported_codec;
|
||||
}
|
||||
|
||||
icaps = gst_caps_intersect (allowed_caps, other_caps);
|
||||
gst_caps_unref (allowed_caps);
|
||||
|
@ -599,7 +597,7 @@ open_codec_fail:
|
|||
gst_ffmpeg_avcodec_close (ffmpegenc->context);
|
||||
if (ffmpegenc->context->stats_in)
|
||||
g_free (ffmpegenc->context->stats_in);
|
||||
GST_DEBUG_OBJECT (ffmpegenc, "ffenc_%s: Failed to open FFMPEG codec",
|
||||
GST_DEBUG_OBJECT (ffmpegenc, "avenc_%s: Failed to open libav codec",
|
||||
oclass->in_plugin->name);
|
||||
return FALSE;
|
||||
}
|
||||
|
@ -608,14 +606,14 @@ pix_fmt_err:
|
|||
{
|
||||
gst_ffmpeg_avcodec_close (ffmpegenc->context);
|
||||
GST_DEBUG_OBJECT (ffmpegenc,
|
||||
"ffenc_%s: AV wants different colourspace (%d given, %d wanted)",
|
||||
"avenc_%s: AV wants different colourspace (%d given, %d wanted)",
|
||||
oclass->in_plugin->name, pix_fmt, ffmpegenc->context->pix_fmt);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
bad_input_fmt:
|
||||
{
|
||||
GST_DEBUG_OBJECT (ffmpegenc, "ffenc_%s: Failed to determine input format",
|
||||
GST_DEBUG_OBJECT (ffmpegenc, "avenc_%s: Failed to determine input format",
|
||||
oclass->in_plugin->name);
|
||||
return FALSE;
|
||||
}
|
||||
|
@ -628,6 +626,17 @@ unsupported_codec:
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
static gboolean
|
||||
gst_ffmpegvidenc_propose_allocation (GstVideoEncoder * encoder,
|
||||
GstQuery * query)
|
||||
{
|
||||
gst_query_add_allocation_meta (query, GST_VIDEO_META_API_TYPE);
|
||||
|
||||
return GST_VIDEO_ENCODER_CLASS (parent_class)->propose_allocation (encoder,
|
||||
query);
|
||||
}
|
||||
|
||||
static void
|
||||
ffmpegenc_setup_working_buf (GstFFMpegVidEnc * ffmpegenc)
|
||||
{
|
||||
|
@ -655,16 +664,22 @@ gst_ffmpegvidenc_handle_frame (GstVideoEncoder * encoder,
|
|||
GstBuffer *outbuf;
|
||||
gint ret_size = 0, c;
|
||||
GstVideoInfo *info = &ffmpegenc->input_state->info;
|
||||
guint8 *data = GST_BUFFER_DATA (frame->input_buffer);
|
||||
GstVideoFrame vframe;
|
||||
|
||||
if (GST_VIDEO_CODEC_FRAME_IS_FORCE_KEYFRAME (frame))
|
||||
ffmpegenc->picture->pict_type = FF_I_TYPE;
|
||||
|
||||
if (!gst_video_frame_map (&vframe, info, frame->input_buffer, GST_MAP_READ)) {
|
||||
GST_ERROR_OBJECT (encoder, "Failed to map input buffer");
|
||||
return GST_FLOW_ERROR;
|
||||
}
|
||||
|
||||
/* Fill avpicture */
|
||||
for (c = 0; c < AV_NUM_DATA_POINTERS; c++) {
|
||||
if (c < GST_VIDEO_INFO_N_COMPONENTS (info)) {
|
||||
ffmpegenc->picture->data[c] = data + GST_VIDEO_INFO_COMP_OFFSET (info, c);
|
||||
ffmpegenc->picture->linesize[c] = GST_VIDEO_INFO_COMP_STRIDE (info, c);
|
||||
ffmpegenc->picture->data[c] = GST_VIDEO_FRAME_PLANE_DATA (&vframe, c);
|
||||
ffmpegenc->picture->linesize[c] =
|
||||
GST_VIDEO_FRAME_PLANE_STRIDE (&vframe, c);
|
||||
} else {
|
||||
ffmpegenc->picture->data[c] = NULL;
|
||||
ffmpegenc->picture->linesize[c] = 0;
|
||||
|
@ -680,6 +695,8 @@ gst_ffmpegvidenc_handle_frame (GstVideoEncoder * encoder,
|
|||
ret_size = avcodec_encode_video (ffmpegenc->context,
|
||||
ffmpegenc->working_buf, ffmpegenc->working_buf_size, ffmpegenc->picture);
|
||||
|
||||
gst_video_frame_unmap (&vframe);
|
||||
|
||||
if (ret_size < 0)
|
||||
goto encode_fail;
|
||||
|
||||
|
@ -699,7 +716,7 @@ gst_ffmpegvidenc_handle_frame (GstVideoEncoder * encoder,
|
|||
|
||||
/* Allocate output buffer */
|
||||
frame->output_buffer = outbuf = gst_buffer_new_and_alloc (ret_size);
|
||||
memcpy (GST_BUFFER_DATA (outbuf), ffmpegenc->working_buf, ret_size);
|
||||
gst_buffer_fill (outbuf, 0, ffmpegenc->working_buf, ret_size);
|
||||
|
||||
/* buggy codec may not set coded_frame */
|
||||
if (ffmpegenc->context->coded_frame) {
|
||||
|
@ -721,7 +738,7 @@ encode_fail:
|
|||
GstFFMpegVidEncClass *oclass =
|
||||
(GstFFMpegVidEncClass *) (G_OBJECT_GET_CLASS (ffmpegenc));
|
||||
GST_ERROR_OBJECT (ffmpegenc,
|
||||
"ffenc_%s: failed to encode buffer", oclass->in_plugin->name);
|
||||
"avenc_%s: failed to encode buffer", oclass->in_plugin->name);
|
||||
#endif /* GST_DISABLE_GST_DEBUG */
|
||||
return GST_FLOW_OK;
|
||||
}
|
||||
|
@ -753,7 +770,7 @@ gst_ffmpegvidenc_flush_buffers (GstFFMpegVidEnc * ffmpegenc, gboolean send)
|
|||
GstFFMpegVidEncClass *oclass =
|
||||
(GstFFMpegVidEncClass *) (G_OBJECT_GET_CLASS (ffmpegenc));
|
||||
GST_WARNING_OBJECT (ffmpegenc,
|
||||
"ffenc_%s: failed to flush buffer", oclass->in_plugin->name);
|
||||
"avenc_%s: failed to flush buffer", oclass->in_plugin->name);
|
||||
#endif /* GST_DISABLE_GST_DEBUG */
|
||||
break;
|
||||
}
|
||||
|
@ -766,7 +783,7 @@ gst_ffmpegvidenc_flush_buffers (GstFFMpegVidEnc * ffmpegenc, gboolean send)
|
|||
GST_ERROR_SYSTEM);
|
||||
|
||||
frame->output_buffer = outbuf = gst_buffer_new_and_alloc (ret_size);
|
||||
memcpy (GST_BUFFER_DATA (outbuf), ffmpegenc->working_buf, ret_size);
|
||||
gst_buffer_fill (outbuf, 0, ffmpegenc->working_buf, ret_size);
|
||||
|
||||
if (ffmpegenc->context->coded_frame->key_frame)
|
||||
GST_VIDEO_CODEC_FRAME_SET_SYNC_POINT (frame);
|
||||
|
@ -794,7 +811,7 @@ gst_ffmpegvidenc_set_property (GObject * object,
|
|||
/* Check the argument id to see which argument we're setting. */
|
||||
switch (prop_id) {
|
||||
case ARG_BIT_RATE:
|
||||
ffmpegenc->bitrate = g_value_get_ulong (value);
|
||||
ffmpegenc->bitrate = g_value_get_int (value);
|
||||
break;
|
||||
case ARG_GOP_SIZE:
|
||||
ffmpegenc->gop_size = g_value_get_int (value);
|
||||
|
@ -805,7 +822,7 @@ gst_ffmpegvidenc_set_property (GObject * object,
|
|||
case ARG_BUFSIZE:
|
||||
break;
|
||||
case ARG_RTP_PAYLOAD_SIZE:
|
||||
ffmpegenc->rtp_payload_size = g_value_get_ulong (value);
|
||||
ffmpegenc->rtp_payload_size = g_value_get_int (value);
|
||||
break;
|
||||
default:
|
||||
if (!gst_ffmpeg_cfg_set_property (object, value, pspec))
|
||||
|
@ -826,7 +843,7 @@ gst_ffmpegvidenc_get_property (GObject * object,
|
|||
|
||||
switch (prop_id) {
|
||||
case ARG_BIT_RATE:
|
||||
g_value_set_ulong (value, ffmpegenc->bitrate);
|
||||
g_value_set_int (value, ffmpegenc->bitrate);
|
||||
break;
|
||||
case ARG_GOP_SIZE:
|
||||
g_value_set_int (value, ffmpegenc->gop_size);
|
||||
|
@ -835,10 +852,10 @@ gst_ffmpegvidenc_get_property (GObject * object,
|
|||
g_value_set_enum (value, ffmpegenc->me_method);
|
||||
break;
|
||||
case ARG_BUFSIZE:
|
||||
g_value_set_ulong (value, ffmpegenc->buffer_size);
|
||||
g_value_set_int (value, ffmpegenc->buffer_size);
|
||||
break;
|
||||
case ARG_RTP_PAYLOAD_SIZE:
|
||||
g_value_set_ulong (value, ffmpegenc->rtp_payload_size);
|
||||
g_value_set_int (value, ffmpegenc->rtp_payload_size);
|
||||
break;
|
||||
default:
|
||||
if (!gst_ffmpeg_cfg_get_property (object, value, pspec))
|
||||
|
@ -914,10 +931,7 @@ gst_ffmpegvidenc_register (GstPlugin * plugin)
|
|||
if (in_plugin->id == CODEC_ID_RAWVIDEO ||
|
||||
in_plugin->id == CODEC_ID_V210 ||
|
||||
in_plugin->id == CODEC_ID_V210X ||
|
||||
in_plugin->id == CODEC_ID_R210 ||
|
||||
in_plugin->id == CODEC_ID_ZLIB ||
|
||||
(in_plugin->id >= CODEC_ID_PCM_S16LE &&
|
||||
in_plugin->id <= CODEC_ID_PCM_BLURAY)) {
|
||||
in_plugin->id == CODEC_ID_R210 || in_plugin->id == CODEC_ID_ZLIB) {
|
||||
goto next;
|
||||
}
|
||||
|
||||
|
@ -948,7 +962,7 @@ gst_ffmpegvidenc_register (GstPlugin * plugin)
|
|||
}
|
||||
|
||||
/* construct the type */
|
||||
type_name = g_strdup_printf ("ffenc_%s", in_plugin->name);
|
||||
type_name = g_strdup_printf ("avenc_%s", in_plugin->name);
|
||||
|
||||
type = g_type_from_name (type_name);
|
||||
|
||||
|
|
|
@ -42,14 +42,14 @@ struct _GstFFMpegVidEnc
|
|||
gboolean discont;
|
||||
|
||||
/* cache */
|
||||
gulong bitrate;
|
||||
gint bitrate;
|
||||
gint me_method;
|
||||
gint gop_size;
|
||||
gulong buffer_size;
|
||||
gulong rtp_payload_size;
|
||||
gint buffer_size;
|
||||
gint rtp_payload_size;
|
||||
|
||||
guint8 *working_buf;
|
||||
gulong working_buf_size;
|
||||
gsize working_buf_size;
|
||||
|
||||
/* settings with some special handling */
|
||||
guint pass;
|
||||
|
|
Loading…
Reference in a new issue