static gboolean gst_amc_audio_dec_set_src_caps (GstAmcAudioDec * self, GstAmcFormat * format) { gint rate, channels; guint32 channel_mask = 0; GstAudioChannelPosition to[64]; GError *err = NULL; if (!gst_amc_format_get_int (format, "sample-rate", &rate, &err) || !gst_amc_format_get_int (format, "channel-count", &channels, &err)) { GST_ERROR_OBJECT (self, "Failed to get output format metadata: %s", err->message); g_clear_error (&err); return FALSE; } if (rate == 0 || channels == 0) { GST_ERROR_OBJECT (self, "Rate or channels not set"); return FALSE; } /* Not always present */ if (gst_amc_format_contains_key (format, "channel-mask", NULL)) gst_amc_format_get_int (format, "channel-mask", (gint *) & channel_mask, NULL); gst_amc_audio_channel_mask_to_positions (channel_mask, channels, self->positions); memcpy (to, self->positions, sizeof (to)); gst_audio_channel_positions_to_valid_order (to, channels); self->needs_reorder = (memcmp (self->positions, to, sizeof (GstAudioChannelPosition) * channels) != 0); if (self->needs_reorder) gst_audio_get_channel_reorder_map (channels, self->positions, to, self->reorder_map); gst_audio_info_init (&self->info); gst_audio_info_set_format (&self->info, GST_AUDIO_FORMAT_S16, rate, channels, to); if (!gst_audio_decoder_set_output_format (GST_AUDIO_DECODER (self), &self->info)) return FALSE; self->input_caps_changed = FALSE; return TRUE; }
static GstCaps * caps_from_amc_format (GstAmcFormat * amc_format) { GstCaps *caps = NULL; gchar *mime = NULL; gint width, height; gint amc_profile, amc_level; gfloat frame_rate = 0.0; gint fraction_n, fraction_d; GError *err = NULL; if (!gst_amc_format_get_string (amc_format, "mime", &mime, &err)) { GST_ERROR ("Failed to get 'mime': %s", err->message); g_clear_error (&err); return NULL; } if (!gst_amc_format_get_int (amc_format, "width", &width, &err) || !gst_amc_format_get_int (amc_format, "height", &height, &err)) { GST_ERROR ("Failed to get size: %s", err->message); g_clear_error (&err); g_free (mime); return NULL; } gst_amc_format_get_float (amc_format, "frame-rate", &frame_rate, NULL); gst_util_double_to_fraction (frame_rate, &fraction_n, &fraction_d); if (strcmp (mime, "video/mp4v-es") == 0) { const gchar *profile_string, *level_string; caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 4, "systemstream", G_TYPE_BOOLEAN, FALSE, "parsed", G_TYPE_BOOLEAN, TRUE, NULL); if (gst_amc_format_get_int (amc_format, "profile", &amc_profile, NULL)) { profile_string = gst_amc_mpeg4_profile_to_string (amc_profile); if (!profile_string) goto unsupported_profile; gst_caps_set_simple (caps, "profile", G_TYPE_STRING, profile_string, NULL); } if (gst_amc_format_get_int (amc_format, "level", &amc_level, NULL)) { level_string = gst_amc_mpeg4_level_to_string (amc_profile); if (!level_string) goto unsupported_level; gst_caps_set_simple (caps, "level", G_TYPE_STRING, level_string, NULL); } } else if (strcmp (mime, "video/mpeg2") == 0) { caps = gst_caps_new_simple ("video/mpeg", "mpegversion", 2, NULL); } else if (strcmp (mime, "video/3gpp") == 0) { caps = gst_caps_new_empty_simple ("video/x-h263"); } else if (strcmp (mime, "video/avc") == 0) { const gchar *profile_string, *level_string; caps = gst_caps_new_simple ("video/x-h264", "parsed", G_TYPE_BOOLEAN, TRUE, "stream-format", G_TYPE_STRING, "byte-stream", "alignment", G_TYPE_STRING, "au", NULL); if (gst_amc_format_get_int (amc_format, "profile", &amc_profile, NULL)) { profile_string = gst_amc_avc_profile_to_string (amc_profile, NULL); if (!profile_string) goto unsupported_profile; gst_caps_set_simple (caps, "profile", G_TYPE_STRING, profile_string, NULL); } if (gst_amc_format_get_int (amc_format, "level", &amc_level, NULL)) { level_string = gst_amc_avc_level_to_string (amc_profile); if (!level_string) goto unsupported_level; gst_caps_set_simple (caps, "level", G_TYPE_STRING, level_string, NULL); } } else if (strcmp (mime, "video/x-vnd.on2.vp8") == 0) { caps = gst_caps_new_empty_simple ("video/x-vp8"); } gst_caps_set_simple (caps, "width", G_TYPE_INT, width, "height", G_TYPE_INT, height, "framerate", GST_TYPE_FRACTION, fraction_n, fraction_d, NULL); g_free (mime); return caps; unsupported_profile: GST_ERROR ("Unsupport amc profile id %d", amc_profile); g_free (mime); gst_object_unref (caps); return NULL; unsupported_level: GST_ERROR ("Unsupport amc level id %d", amc_level); g_free (mime); gst_object_unref (caps); return NULL; }
static gboolean gst_amc_video_dec_set_src_caps (GstAmcVideoDec * self, GstAmcFormat * format) { GstVideoCodecState *output_state; const gchar *mime; gint color_format, width, height; gint stride, slice_height; gint crop_left, crop_right; gint crop_top, crop_bottom; GstVideoFormat gst_format; GstAmcVideoDecClass *klass = GST_AMC_VIDEO_DEC_GET_CLASS (self); GError *err = NULL; gboolean ret; if (!gst_amc_format_get_int (format, "color-format", &color_format, &err) || !gst_amc_format_get_int (format, "width", &width, &err) || !gst_amc_format_get_int (format, "height", &height, &err)) { GST_ERROR_OBJECT (self, "Failed to get output format metadata: %s", err->message); g_clear_error (&err); return FALSE; } if (!gst_amc_format_get_int (format, "stride", &stride, &err) || !gst_amc_format_get_int (format, "slice-height", &slice_height, &err)) { GST_ERROR_OBJECT (self, "Failed to get stride and slice-height: %s", err->message); g_clear_error (&err); return FALSE; } if (!gst_amc_format_get_int (format, "crop-left", &crop_left, &err) || !gst_amc_format_get_int (format, "crop-right", &crop_right, &err) || !gst_amc_format_get_int (format, "crop-top", &crop_top, &err) || !gst_amc_format_get_int (format, "crop-bottom", &crop_bottom, &err)) { GST_ERROR_OBJECT (self, "Failed to get crop rectangle: %s", err->message); g_clear_error (&err); return FALSE; } if (width == 0 || height == 0) { GST_ERROR_OBJECT (self, "Height or width not set"); return FALSE; } if (crop_bottom) height = height - (height - crop_bottom - 1); if (crop_top) height = height - crop_top; if (crop_right) width = width - (width - crop_right - 1); if (crop_left) width = width - crop_left; mime = caps_to_mime (self->input_state->caps); if (!mime) { GST_ERROR_OBJECT (self, "Failed to convert caps to mime"); return FALSE; } gst_format = gst_amc_color_format_to_video_format (klass->codec_info, mime, color_format); if (gst_format == GST_VIDEO_FORMAT_UNKNOWN) { GST_ERROR_OBJECT (self, "Unknown color format 0x%08x", color_format); return FALSE; } output_state = gst_video_decoder_set_output_state (GST_VIDEO_DECODER (self), gst_format, width, height, self->input_state); /* FIXME: Special handling for multiview, untested */ if (color_format == COLOR_QCOM_FormatYVU420SemiPlanar32mMultiView) { gst_video_multiview_video_info_change_mode (&output_state->info, GST_VIDEO_MULTIVIEW_MODE_TOP_BOTTOM, GST_VIDEO_MULTIVIEW_FLAGS_NONE); } self->format = gst_format; if (!gst_amc_color_format_info_set (&self->color_format_info, klass->codec_info, mime, color_format, width, height, stride, slice_height, crop_left, crop_right, crop_top, crop_bottom)) { GST_ERROR_OBJECT (self, "Failed to set up GstAmcColorFormatInfo"); return FALSE; } GST_DEBUG_OBJECT (self, "Color format info: {color_format=%d, width=%d, height=%d, " "stride=%d, slice-height=%d, crop-left=%d, crop-top=%d, " "crop-right=%d, crop-bottom=%d, frame-size=%d}", self->color_format_info.color_format, self->color_format_info.width, self->color_format_info.height, self->color_format_info.stride, self->color_format_info.slice_height, self->color_format_info.crop_left, self->color_format_info.crop_top, self->color_format_info.crop_right, self->color_format_info.crop_bottom, self->color_format_info.frame_size); ret = gst_video_decoder_negotiate (GST_VIDEO_DECODER (self)); gst_video_codec_state_unref (output_state); self->input_state_changed = FALSE; return ret; }