void gst_vaapi_decoder_set_multiview_mode (GstVaapiDecoder * decoder, gint views, GstVideoMultiviewMode mv_mode, GstVideoMultiviewFlags mv_flags) { GstVideoCodecState *const codec_state = decoder->codec_state; GstVideoInfo *info = &codec_state->info; if (GST_VIDEO_INFO_VIEWS (info) != views || GST_VIDEO_INFO_MULTIVIEW_MODE (info) != mv_mode || GST_VIDEO_INFO_MULTIVIEW_FLAGS (info) != mv_flags) { const gchar *mv_mode_str = gst_video_multiview_mode_to_caps_string (mv_mode); GST_DEBUG ("Multiview mode changed to %s flags 0x%x views %d", mv_mode_str, mv_flags, views); GST_VIDEO_INFO_MULTIVIEW_MODE (info) = mv_mode; GST_VIDEO_INFO_MULTIVIEW_FLAGS (info) = mv_flags; GST_VIDEO_INFO_VIEWS (info) = views; gst_caps_set_simple (codec_state->caps, "multiview-mode", G_TYPE_STRING, mv_mode_str, "multiview-flags", GST_TYPE_VIDEO_MULTIVIEW_FLAGSET, mv_flags, GST_FLAG_SET_MASK_EXACT, "views", G_TYPE_INT, views, NULL); notify_codec_state_changed (decoder); } }
/** * gst_video_info_is_equal: * @info: a #GstVideoInfo * @other: a #GstVideoInfo * * Compares two #GstVideoInfo and returns whether they are equal or not * * Returns: %TRUE if @info and @other are equal, else %FALSE. */ gboolean gst_video_info_is_equal (const GstVideoInfo * info, const GstVideoInfo * other) { gint i; if (GST_VIDEO_INFO_FORMAT (info) != GST_VIDEO_INFO_FORMAT (other)) return FALSE; if (GST_VIDEO_INFO_INTERLACE_MODE (info) != GST_VIDEO_INFO_INTERLACE_MODE (other)) return FALSE; if (GST_VIDEO_INFO_FLAGS (info) != GST_VIDEO_INFO_FLAGS (other)) return FALSE; if (GST_VIDEO_INFO_WIDTH (info) != GST_VIDEO_INFO_WIDTH (other)) return FALSE; if (GST_VIDEO_INFO_HEIGHT (info) != GST_VIDEO_INFO_HEIGHT (other)) return FALSE; if (GST_VIDEO_INFO_SIZE (info) != GST_VIDEO_INFO_SIZE (other)) return FALSE; if (GST_VIDEO_INFO_PAR_N (info) != GST_VIDEO_INFO_PAR_N (other)) return FALSE; if (GST_VIDEO_INFO_PAR_D (info) != GST_VIDEO_INFO_PAR_D (other)) return FALSE; if (GST_VIDEO_INFO_FPS_N (info) != GST_VIDEO_INFO_FPS_N (other)) return FALSE; if (GST_VIDEO_INFO_FPS_D (info) != GST_VIDEO_INFO_FPS_D (other)) return FALSE; if (!gst_video_colorimetry_is_equal (&GST_VIDEO_INFO_COLORIMETRY (info), &GST_VIDEO_INFO_COLORIMETRY (other))) return FALSE; if (GST_VIDEO_INFO_CHROMA_SITE (info) != GST_VIDEO_INFO_CHROMA_SITE (other)) return FALSE; if (GST_VIDEO_INFO_MULTIVIEW_MODE (info) != GST_VIDEO_INFO_MULTIVIEW_MODE (other)) return FALSE; if (GST_VIDEO_INFO_MULTIVIEW_FLAGS (info) != GST_VIDEO_INFO_MULTIVIEW_FLAGS (other)) return FALSE; if (GST_VIDEO_INFO_VIEWS (info) != GST_VIDEO_INFO_VIEWS (other)) return FALSE; for (i = 0; i < info->finfo->n_planes; i++) { if (info->stride[i] != other->stride[i]) return FALSE; if (info->offset[i] != other->offset[i]) return FALSE; } return TRUE; }
static void gst_video_multiview_separated_video_info_to_packed (GstVideoInfo * info, GstVideoMultiviewMode packed_mview_mode, GstVideoMultiviewFlags packed_mview_flags) { /* Convert single-frame info to a packed mode */ GST_VIDEO_INFO_MULTIVIEW_MODE (info) = packed_mview_mode; GST_VIDEO_INFO_MULTIVIEW_FLAGS (info) = packed_mview_flags; switch (packed_mview_mode) { case GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE: case GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE_QUINCUNX: case GST_VIDEO_MULTIVIEW_MODE_COLUMN_INTERLEAVED: case GST_VIDEO_MULTIVIEW_MODE_CHECKERBOARD: info->width *= 2; info->views /= 2; if (packed_mview_flags & GST_VIDEO_MULTIVIEW_FLAGS_HALF_ASPECT) info->par_d *= 2; break; case GST_VIDEO_MULTIVIEW_MODE_ROW_INTERLEAVED: case GST_VIDEO_MULTIVIEW_MODE_TOP_BOTTOM: info->height *= 2; info->views /= 2; if (packed_mview_flags & GST_VIDEO_MULTIVIEW_FLAGS_HALF_ASPECT) info->par_n *= 2; break; default: break; } }
void gst_video_info_change_format (GstVideoInfo * vip, GstVideoFormat format, guint width, guint height) { GstVideoInfo vi = *vip; gst_video_info_set_format (vip, format, width, height); GST_VIDEO_INFO_INTERLACE_MODE (vip) = GST_VIDEO_INFO_INTERLACE_MODE (&vi); GST_VIDEO_FORMAT_INFO_FLAGS (vip) = GST_VIDEO_FORMAT_INFO_FLAGS (&vi); GST_VIDEO_INFO_VIEWS (vip) = GST_VIDEO_INFO_VIEWS (&vi); GST_VIDEO_INFO_PAR_N (vip) = GST_VIDEO_INFO_PAR_N (&vi); GST_VIDEO_INFO_PAR_D (vip) = GST_VIDEO_INFO_PAR_D (&vi); GST_VIDEO_INFO_FPS_N (vip) = GST_VIDEO_INFO_FPS_N (&vi); GST_VIDEO_INFO_FPS_D (vip) = GST_VIDEO_INFO_FPS_D (&vi); GST_VIDEO_INFO_MULTIVIEW_MODE (vip) = GST_VIDEO_INFO_MULTIVIEW_MODE (&vi); GST_VIDEO_INFO_MULTIVIEW_FLAGS (vip) = GST_VIDEO_INFO_MULTIVIEW_FLAGS (&vi); }
void gst_video_info_change_format (GstVideoInfo * vip, GstVideoFormat format, guint width, guint height) { GstVideoInfo vi = *vip; gst_video_info_set_format (vip, format, width, height); vip->interlace_mode = vi.interlace_mode; vip->flags = vi.flags; vip->views = vi.views; vip->par_n = vi.par_n; vip->par_d = vi.par_d; vip->fps_n = vi.fps_n; vip->fps_d = vi.fps_d; GST_VIDEO_INFO_MULTIVIEW_MODE (vip) = GST_VIDEO_INFO_MULTIVIEW_MODE (&vi); GST_VIDEO_INFO_MULTIVIEW_FLAGS (vip) = GST_VIDEO_INFO_MULTIVIEW_FLAGS (&vi); }
static void gst_video_multiview_separated_video_info_from_packed (GstVideoInfo * info) { GstVideoMultiviewMode mview_mode; mview_mode = GST_VIDEO_INFO_MULTIVIEW_MODE (info); /* Normalise the half-aspect flag by adjusting PAR */ switch (mview_mode) { case GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE: case GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE_QUINCUNX: case GST_VIDEO_MULTIVIEW_MODE_COLUMN_INTERLEAVED: case GST_VIDEO_MULTIVIEW_MODE_CHECKERBOARD: info->width /= 2; info->views *= 2; GST_VIDEO_INFO_MULTIVIEW_MODE (info) = GST_VIDEO_MULTIVIEW_MODE_SEPARATED; if (GST_VIDEO_INFO_MULTIVIEW_FLAGS (info) & GST_VIDEO_MULTIVIEW_FLAGS_HALF_ASPECT) info->par_n *= 2; break; case GST_VIDEO_MULTIVIEW_MODE_ROW_INTERLEAVED: case GST_VIDEO_MULTIVIEW_MODE_TOP_BOTTOM: info->height /= 2; info->views *= 2; GST_VIDEO_INFO_MULTIVIEW_MODE (info) = GST_VIDEO_MULTIVIEW_MODE_SEPARATED; if (GST_VIDEO_INFO_MULTIVIEW_FLAGS (info) & GST_VIDEO_MULTIVIEW_FLAGS_HALF_ASPECT) info->par_d *= 2; break; default: /* Mono/left/right/frame-by-frame/already separated */ break; } GST_VIDEO_INFO_MULTIVIEW_FLAGS (info) &= ~GST_VIDEO_MULTIVIEW_FLAGS_HALF_ASPECT; }
/** * gst_video_info_to_caps: * @info: a #GstVideoInfo * * Convert the values of @info into a #GstCaps. * * Returns: a new #GstCaps containing the info of @info. */ GstCaps * gst_video_info_to_caps (GstVideoInfo * info) { GstCaps *caps; const gchar *format; gchar *color; gint par_n, par_d; GstVideoColorimetry colorimetry; g_return_val_if_fail (info != NULL, NULL); g_return_val_if_fail (info->finfo != NULL, NULL); g_return_val_if_fail (info->finfo->format != GST_VIDEO_FORMAT_UNKNOWN, NULL); format = gst_video_format_to_string (info->finfo->format); g_return_val_if_fail (format != NULL, NULL); caps = gst_caps_new_simple ("video/x-raw", "format", G_TYPE_STRING, format, "width", G_TYPE_INT, info->width, "height", G_TYPE_INT, info->height, NULL); par_n = info->par_n; par_d = info->par_d; gst_caps_set_simple (caps, "interlace-mode", G_TYPE_STRING, gst_video_interlace_mode_to_string (info->interlace_mode), NULL); if (GST_VIDEO_INFO_MULTIVIEW_MODE (info) != GST_VIDEO_MULTIVIEW_MODE_NONE) { const gchar *caps_str = NULL; /* If the half-aspect flag is set, applying it into the PAR of the * resulting caps now seems safe, and helps with automatic behaviour * in elements that aren't explicitly multiview aware */ if (GST_VIDEO_INFO_MULTIVIEW_FLAGS (info) & GST_VIDEO_MULTIVIEW_FLAGS_HALF_ASPECT) { GST_VIDEO_INFO_MULTIVIEW_FLAGS (info) &= ~GST_VIDEO_MULTIVIEW_FLAGS_HALF_ASPECT; switch (GST_VIDEO_INFO_MULTIVIEW_MODE (info)) { case GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE: case GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE_QUINCUNX: case GST_VIDEO_MULTIVIEW_MODE_COLUMN_INTERLEAVED: case GST_VIDEO_MULTIVIEW_MODE_CHECKERBOARD: par_n *= 2; /* double the width / half the height */ break; case GST_VIDEO_MULTIVIEW_MODE_ROW_INTERLEAVED: case GST_VIDEO_MULTIVIEW_MODE_TOP_BOTTOM: par_d *= 2; /* half the width / double the height */ break; default: break; } } caps_str = gst_video_multiview_mode_to_caps_string (GST_VIDEO_INFO_MULTIVIEW_MODE (info)); if (caps_str != NULL) { gst_caps_set_simple (caps, "multiview-mode", G_TYPE_STRING, caps_str, "multiview-flags", GST_TYPE_VIDEO_MULTIVIEW_FLAGSET, GST_VIDEO_INFO_MULTIVIEW_FLAGS (info), GST_FLAG_SET_MASK_EXACT, NULL); } } gst_caps_set_simple (caps, "pixel-aspect-ratio", GST_TYPE_FRACTION, par_n, par_d, NULL); if (info->chroma_site != GST_VIDEO_CHROMA_SITE_UNKNOWN) gst_caps_set_simple (caps, "chroma-site", G_TYPE_STRING, gst_video_chroma_to_string (info->chroma_site), NULL); /* make sure we set the RGB matrix for RGB formats */ colorimetry = info->colorimetry; if (GST_VIDEO_FORMAT_INFO_IS_RGB (info->finfo) && colorimetry.matrix != GST_VIDEO_COLOR_MATRIX_RGB) { GST_WARNING ("invalid matrix %d for RGB format, using RGB", colorimetry.matrix); colorimetry.matrix = GST_VIDEO_COLOR_MATRIX_RGB; } if ((color = gst_video_colorimetry_to_string (&colorimetry))) { gst_caps_set_simple (caps, "colorimetry", G_TYPE_STRING, color, NULL); g_free (color); } if (info->views > 1) gst_caps_set_simple (caps, "views", G_TYPE_INT, info->views, NULL); if (info->flags & GST_VIDEO_FLAG_VARIABLE_FPS && info->fps_n != 0) { /* variable fps with a max-framerate */ gst_caps_set_simple (caps, "framerate", GST_TYPE_FRACTION, 0, 1, "max-framerate", GST_TYPE_FRACTION, info->fps_n, info->fps_d, NULL); } else { /* no variable fps or no max-framerate */ gst_caps_set_simple (caps, "framerate", GST_TYPE_FRACTION, info->fps_n, info->fps_d, NULL); } return caps; }
/** * gst_video_info_from_caps: * @info: a #GstVideoInfo * @caps: a #GstCaps * * Parse @caps and update @info. * * Returns: TRUE if @caps could be parsed */ gboolean gst_video_info_from_caps (GstVideoInfo * info, const GstCaps * caps) { GstStructure *structure; const gchar *s; GstVideoFormat format = GST_VIDEO_FORMAT_UNKNOWN; gint width = 0, height = 0; gint fps_n, fps_d; gint par_n, par_d; g_return_val_if_fail (info != NULL, FALSE); g_return_val_if_fail (caps != NULL, FALSE); g_return_val_if_fail (gst_caps_is_fixed (caps), FALSE); GST_DEBUG ("parsing caps %" GST_PTR_FORMAT, caps); structure = gst_caps_get_structure (caps, 0); if (gst_structure_has_name (structure, "video/x-raw")) { if (!(s = gst_structure_get_string (structure, "format"))) goto no_format; format = gst_video_format_from_string (s); if (format == GST_VIDEO_FORMAT_UNKNOWN) goto unknown_format; } else if (g_str_has_prefix (gst_structure_get_name (structure), "video/") || g_str_has_prefix (gst_structure_get_name (structure), "image/")) { format = GST_VIDEO_FORMAT_ENCODED; } else { goto wrong_name; } /* width and height are mandatory, except for non-raw-formats */ if (!gst_structure_get_int (structure, "width", &width) && format != GST_VIDEO_FORMAT_ENCODED) goto no_width; if (!gst_structure_get_int (structure, "height", &height) && format != GST_VIDEO_FORMAT_ENCODED) goto no_height; gst_video_info_init (info); info->finfo = gst_video_format_get_info (format); info->width = width; info->height = height; if (gst_structure_get_fraction (structure, "framerate", &fps_n, &fps_d)) { if (fps_n == 0) { /* variable framerate */ info->flags |= GST_VIDEO_FLAG_VARIABLE_FPS; /* see if we have a max-framerate */ gst_structure_get_fraction (structure, "max-framerate", &fps_n, &fps_d); } info->fps_n = fps_n; info->fps_d = fps_d; } else { /* unspecified is variable framerate */ info->fps_n = 0; info->fps_d = 1; } if (gst_structure_get_fraction (structure, "pixel-aspect-ratio", &par_n, &par_d)) { info->par_n = par_n; info->par_d = par_d; } else { info->par_n = 1; info->par_d = 1; } if ((s = gst_structure_get_string (structure, "interlace-mode"))) info->interlace_mode = gst_video_interlace_mode_from_string (s); else info->interlace_mode = GST_VIDEO_INTERLACE_MODE_PROGRESSIVE; { if ((s = gst_structure_get_string (structure, "multiview-mode"))) GST_VIDEO_INFO_MULTIVIEW_MODE (info) = gst_video_multiview_mode_from_caps_string (s); else GST_VIDEO_INFO_MULTIVIEW_MODE (info) = GST_VIDEO_MULTIVIEW_MODE_NONE; gst_structure_get_flagset (structure, "multiview-flags", &GST_VIDEO_INFO_MULTIVIEW_FLAGS (info), NULL); if (!gst_structure_get_int (structure, "views", &info->views)) info->views = 1; /* At one point, I tried normalising the half-aspect flag here, * but it behaves weird for GstVideoInfo operations other than * directly converting to/from caps - sometimes causing the * PAR to be doubled/halved too many times */ } if ((s = gst_structure_get_string (structure, "chroma-site"))) info->chroma_site = gst_video_chroma_from_string (s); else info->chroma_site = GST_VIDEO_CHROMA_SITE_UNKNOWN; if ((s = gst_structure_get_string (structure, "colorimetry"))) { if (!gst_video_colorimetry_from_string (&info->colorimetry, s)) { GST_WARNING ("unparsable colorimetry, using default"); set_default_colorimetry (info); } else if (!validate_colorimetry (info)) { GST_WARNING ("invalid colorimetry, using default"); set_default_colorimetry (info); } else { /* force RGB matrix for RGB formats */ if (GST_VIDEO_FORMAT_INFO_IS_RGB (info->finfo) && info->colorimetry.matrix != GST_VIDEO_COLOR_MATRIX_RGB) { GST_WARNING ("invalid matrix %d for RGB format, using RGB", info->colorimetry.matrix); info->colorimetry.matrix = GST_VIDEO_COLOR_MATRIX_RGB; } } } else { GST_DEBUG ("no colorimetry, using default"); set_default_colorimetry (info); } fill_planes (info); return TRUE; /* ERROR */ wrong_name: { GST_ERROR ("wrong name '%s', expected video/ or image/", gst_structure_get_name (structure)); return FALSE; } no_format: { GST_ERROR ("no format given"); return FALSE; } unknown_format: { GST_ERROR ("unknown format '%s' given", s); return FALSE; } no_width: { GST_ERROR ("no width property given"); return FALSE; } no_height: { GST_ERROR ("no height property given"); return FALSE; } }
/* Return the possible output caps based on inputs and downstream prefs */ static GstCaps * _update_caps (GstVideoAggregator * vagg, GstCaps * caps) { GstGLStereoMix *mix = GST_GL_STEREO_MIX (vagg); GList *l; gint best_width = -1, best_height = -1; gdouble best_fps = -1, cur_fps; gint best_fps_n = 0, best_fps_d = 1; GstVideoInfo *mix_info; GstCaps *blend_caps, *tmp_caps; GstCaps *out_caps; GST_OBJECT_LOCK (vagg); for (l = GST_ELEMENT (vagg)->sinkpads; l; l = l->next) { GstVideoAggregatorPad *pad = l->data; GstVideoInfo tmp = pad->info; gint this_width, this_height; gint fps_n, fps_d; if (!pad->info.finfo) continue; /* This can happen if we release a pad and another pad hasn't been negotiated_caps yet */ if (GST_VIDEO_INFO_FORMAT (&pad->info) == GST_VIDEO_FORMAT_UNKNOWN) continue; /* Convert to per-view width/height for unpacked forms */ gst_video_multiview_video_info_change_mode (&tmp, GST_VIDEO_MULTIVIEW_MODE_SEPARATED, GST_VIDEO_MULTIVIEW_FLAGS_NONE); this_width = GST_VIDEO_INFO_WIDTH (&tmp); this_height = GST_VIDEO_INFO_HEIGHT (&tmp); fps_n = GST_VIDEO_INFO_FPS_N (&tmp); fps_d = GST_VIDEO_INFO_FPS_D (&tmp); GST_INFO_OBJECT (vagg, "Input pad %" GST_PTR_FORMAT " w %u h %u", pad, this_width, this_height); if (this_width == 0 || this_height == 0) continue; if (best_width < this_width) best_width = this_width; if (best_height < this_height) best_height = this_height; if (fps_d == 0) cur_fps = 0.0; else gst_util_fraction_to_double (fps_n, fps_d, &cur_fps); if (best_fps < cur_fps) { best_fps = cur_fps; best_fps_n = fps_n; best_fps_d = fps_d; } /* FIXME: Preserve PAR for at least one input when different sized inputs */ } GST_OBJECT_UNLOCK (vagg); mix_info = &mix->mix_info; gst_video_info_set_format (mix_info, GST_VIDEO_FORMAT_RGBA, best_width, best_height); GST_VIDEO_INFO_FPS_N (mix_info) = best_fps_n; GST_VIDEO_INFO_FPS_D (mix_info) = best_fps_d; GST_VIDEO_INFO_MULTIVIEW_MODE (mix_info) = GST_VIDEO_MULTIVIEW_MODE_SEPARATED; GST_VIDEO_INFO_VIEWS (mix_info) = 2; /* FIXME: If input is marked as flipped or flopped, preserve those flags */ GST_VIDEO_INFO_MULTIVIEW_FLAGS (mix_info) = GST_VIDEO_MULTIVIEW_FLAGS_NONE; /* Choose our output format based on downstream preferences */ blend_caps = gst_video_info_to_caps (mix_info); gst_caps_set_features (blend_caps, 0, gst_caps_features_from_string (GST_CAPS_FEATURE_MEMORY_GL_MEMORY)); tmp_caps = get_converted_caps (GST_GL_STEREO_MIX (vagg), blend_caps); gst_caps_unref (blend_caps); out_caps = gst_caps_intersect (caps, tmp_caps); gst_caps_unref (tmp_caps); GST_DEBUG_OBJECT (vagg, "Possible output caps %" GST_PTR_FORMAT, out_caps); return out_caps; }