x264enc: Add support for stereoscopic video

Provide new frame-packing property to directly set
x264enc frame packing, or pass through upstream settings

The explicit layout from the frame-packing property is
preferred over any info from the caps.
This commit is contained in:
Jan Schmidt 2014-10-05 00:54:59 +10:00
parent 0f80355ba5
commit c6958c158f
2 changed files with 104 additions and 0 deletions

View file

@ -151,6 +151,7 @@ enum
ARG_SPEED_PRESET,
ARG_PSY_TUNE,
ARG_TUNE,
ARG_FRAME_PACKING,
};
#define ARG_THREADS_DEFAULT 0 /* 0 means 'auto' which is 1.5x number of CPU cores */
@ -191,6 +192,7 @@ static GString *x264enc_defaults;
#define ARG_SPEED_PRESET_DEFAULT 6 /* 'medium' preset - matches x264 CLI default */
#define ARG_PSY_TUNE_DEFAULT 0 /* no psy tuning */
#define ARG_TUNE_DEFAULT 0 /* no tuning */
#define ARG_FRAME_PACKING_DEFAULT -1 /* automatic (none, or from input caps) */
enum
{
@ -393,6 +395,52 @@ gst_x264_enc_build_tunings_string (GstX264Enc * x264enc)
x264enc->tunings->str);
}
#define GST_X264_ENC_FRAME_PACKING_TYPE (gst_x264_enc_frame_packing_get_type())
static GType
gst_x264_enc_frame_packing_get_type (void)
{
static GType fpa_type = 0;
static const GEnumValue fpa_types[] = {
{-1, "Automatic (use incoming video information)", "auto"},
{0, "checkerboard - Left and Right pixels alternate in a checkerboard pattern", "checkerboard"},
{1, "column interleaved - Alternating pixel columns represent Left and Right views", "column-interleaved"},
{2, "row interleaved - Alternating pixel rows represent Left and Right views", "row-interleaved"},
{3, "side by side - The left half of the frame contains the Left eye view, the right half the Right eye view", "side-by-side"},
{4, "top bottom - L is on top, R on bottom", "top-bottom"},
{5, "frame interleaved - Each frame contains either Left or Right view alternately", "frame-interleaved"},
{0, NULL, NULL}
};
if (!fpa_type) {
fpa_type = g_enum_register_static ("GstX264EncFramePacking", fpa_types);
}
return fpa_type;
}
static gint
gst_x264_enc_mview_mode_to_frame_packing (GstVideoMultiviewMode mode)
{
switch (mode) {
case GST_VIDEO_MULTIVIEW_MODE_CHECKERBOARD:
return 0;
case GST_VIDEO_MULTIVIEW_MODE_COLUMN_INTERLEAVED:
return 1;
case GST_VIDEO_MULTIVIEW_MODE_ROW_INTERLEAVED:
return 2;
case GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE:
return 3;
case GST_VIDEO_MULTIVIEW_MODE_TOP_BOTTOM:
return 4;
case GST_VIDEO_MULTIVIEW_MODE_FRAME_BY_FRAME:
return 5;
default:
break;
}
return -1;
}
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
#define FORMATS "I420, YV12, Y42B, Y444, NV12, I420_10LE, I422_10LE, Y444_10LE"
#else
@ -759,6 +807,12 @@ gst_x264_enc_class_init (GstX264EncClass * klass)
ARG_OPTION_STRING_DEFAULT,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, ARG_FRAME_PACKING,
g_param_spec_enum ("frame-packing", "Frame Packing",
"Set frame packing mode for Stereoscopic content",
GST_X264_ENC_FRAME_PACKING_TYPE, ARG_FRAME_PACKING_DEFAULT,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
/* options for which we _do_ use string equivalents */
g_object_class_install_property (gobject_class, ARG_THREADS,
g_param_spec_uint ("threads", "Threads",
@ -1032,6 +1086,7 @@ gst_x264_enc_init (GstX264Enc * encoder)
encoder->speed_preset = ARG_SPEED_PRESET_DEFAULT;
encoder->psy_tune = ARG_PSY_TUNE_DEFAULT;
encoder->tune = ARG_TUNE_DEFAULT;
encoder->frame_packing = ARG_FRAME_PACKING_DEFAULT;
x264_param_default (&encoder->x264param);
@ -1472,6 +1527,17 @@ gst_x264_enc_init_encoder (GstX264Enc * encoder)
}
}
/* Set 3D frame packing */
if (encoder->frame_packing != GST_VIDEO_MULTIVIEW_MODE_NONE)
encoder->x264param.i_frame_packing = encoder->frame_packing;
else
encoder->x264param.i_frame_packing =
gst_x264_enc_mview_mode_to_frame_packing (GST_VIDEO_INFO_MULTIVIEW_MODE
(info));
GST_DEBUG_OBJECT (encoder, "Stereo frame packing = %d",
encoder->x264param.i_frame_packing);
encoder->reconfig = FALSE;
/* good start, will be corrected if needed */
encoder->ts_offset = 0;
@ -1716,6 +1782,37 @@ gst_x264_enc_set_src_caps (GstX264Enc * encoder, GstCaps * caps)
state = gst_video_encoder_set_output_state (GST_VIDEO_ENCODER (encoder),
outcaps, encoder->input_state);
GST_DEBUG_OBJECT (encoder, "output caps: %" GST_PTR_FORMAT, state->caps);
/* If set, local frame packing setting overrides any upstream config */
switch (encoder->frame_packing) {
case 0:
GST_VIDEO_INFO_MULTIVIEW_MODE (&state->info) =
GST_VIDEO_MULTIVIEW_MODE_CHECKERBOARD;
break;
case 1:
GST_VIDEO_INFO_MULTIVIEW_MODE (&state->info) =
GST_VIDEO_MULTIVIEW_MODE_COLUMN_INTERLEAVED;
break;
case 2:
GST_VIDEO_INFO_MULTIVIEW_MODE (&state->info) =
GST_VIDEO_MULTIVIEW_MODE_ROW_INTERLEAVED;
break;
case 3:
GST_VIDEO_INFO_MULTIVIEW_MODE (&state->info) =
GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE;
break;
case 4:
GST_VIDEO_INFO_MULTIVIEW_MODE (&state->info) =
GST_VIDEO_MULTIVIEW_MODE_TOP_BOTTOM;
break;
case 5:
GST_VIDEO_INFO_MULTIVIEW_MODE (&state->info) =
GST_VIDEO_MULTIVIEW_MODE_FRAME_BY_FRAME;
break;
default:
break;
}
gst_video_codec_state_unref (state);
tags = gst_tag_list_new_empty ();
@ -2352,6 +2449,9 @@ gst_x264_enc_set_property (GObject * object, guint prop_id,
g_string_append_printf (encoder->option_string, ":interlaced=%d",
encoder->interlaced);
break;
case ARG_FRAME_PACKING:
encoder->frame_packing = g_value_get_enum (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@ -2488,6 +2588,9 @@ gst_x264_enc_get_property (GObject * object, guint prop_id,
case ARG_OPTION_STRING:
g_value_set_string (value, encoder->option_string_prop->str);
break;
case ARG_FRAME_PACKING:
g_value_set_enum (value, encoder->frame_packing);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;

View file

@ -97,6 +97,7 @@ struct _GstX264Enc
GString *tunings;
GString *option_string_prop; /* option-string property */
GString *option_string; /* used by set prop */
gint frame_packing;
/* input description */
GstVideoCodecState *input_state;