gboolean
gst_media_descriptors_compare (GstMediaDescriptor * ref,
    GstMediaDescriptor * compared)
{
  GList *rstream_list;
  FileNode *rfilenode = ref->filenode, *cfilenode = compared->filenode;

  if (rfilenode->duration != cfilenode->duration) {
    GST_VALIDATE_REPORT (ref, FILE_DURATION_INCORRECT,
        "Duration %" GST_TIME_FORMAT " is different from the reference %"
        GST_TIME_FORMAT, GST_TIME_ARGS (cfilenode->duration),
        GST_TIME_ARGS (rfilenode->duration));
  }

  if (rfilenode->seekable != cfilenode->seekable) {
    GST_VALIDATE_REPORT (ref, FILE_SEEKABLE_INCORRECT,
        "File known as %s but is reported %s now",
        rfilenode->seekable ? "seekable" : "not seekable",
        cfilenode->seekable ? "seekable" : "not seekable");
  }

  if (g_list_length (rfilenode->streams) != g_list_length (cfilenode->streams)) {
    GST_VALIDATE_REPORT (ref, FILE_PROFILE_INCORRECT,
        "Reference descriptor has %i streams != compared which has %i streams",
        g_list_length (rfilenode->streams), g_list_length (cfilenode->streams));

    return FALSE;
  }


  for (rstream_list = rfilenode->streams; rstream_list;
      rstream_list = rstream_list->next) {
    GList *cstream_list;
    gint sfound = -1;

    for (cstream_list = cfilenode->streams; cstream_list;
        cstream_list = cstream_list->next) {

      sfound = comparse_stream (ref, rstream_list->data, cstream_list->data);
      if (sfound == 0) {
        return FALSE;
      } else if (sfound == 1) {
        break;
      }
    }

    if (sfound == FALSE) {
      GST_VALIDATE_REPORT (ref, FILE_PROFILE_INCORRECT,
          "Could not find stream %s in the compared descriptor",
          ((StreamNode *) rstream_list->data)->id);

      return FALSE;
    }
  }

  return TRUE;
}
Exemplo n.º 2
0
static gboolean
gst_validate_ssim_convert (GstValidateSsim * self, SSimConverterInfo * info,
    GstVideoFrame * frame, GstVideoFrame * converted_frame)
{
  gboolean res = TRUE;
  GstBuffer *outbuf = NULL;

  g_return_val_if_fail (info != NULL, FALSE);

  outbuf = gst_buffer_new_allocate (NULL, info->out_info.size, NULL);
  if (!gst_video_frame_map (converted_frame, &info->out_info, outbuf,
          GST_MAP_WRITE)) {
    GST_VALIDATE_REPORT (self, GENERAL_INPUT_ERROR,
        "Could not map output converted_frame");
    goto fail;
  }

  gst_video_converter_frame (info->converter, frame, converted_frame);

done:
  if (outbuf)
    gst_buffer_unref (outbuf);

  return res;

fail:
  res = FALSE;
  goto done;
}
Exemplo n.º 3
0
static void
_check_message_level (const gchar * factoryname, GstValidateReportLevel level,
    const gchar * message_id)
{
  GList *reports;
  GstElement *element;
  GstValidateRunner *runner;
  GstValidateMonitor *monitor;

  element = gst_element_factory_make (factoryname, NULL);
  fail_unless (g_setenv ("GST_VALIDATE_REPORTING_DETAILS", "all", TRUE));
  runner = gst_validate_runner_new ();
  monitor =
      gst_validate_monitor_factory_create (GST_OBJECT (element), runner, NULL);

  GST_VALIDATE_REPORT (monitor, g_quark_from_string (message_id),
      "Just some fakery");

  reports = gst_validate_runner_get_reports (runner);
  fail_unless_equals_int (g_list_length (reports), 1);
  fail_unless_equals_int (((GstValidateReport *) reports->data)->level, level);
  g_list_free_full (reports, (GDestroyNotify) gst_validate_report_unref);
  gst_object_unref (element);
  gst_object_unref (monitor);

}
Exemplo n.º 4
0
static void
bin_element_added (GstTracer * runner, GstClockTime ts,
    GstBin * bin, GstElement * element, gboolean result)
{
  GstObject *parent;
  GstValidateElementMonitor *monitor =
      g_object_get_data (G_OBJECT (element), "validate-monitor");

  if (!monitor)
    return;

  if (!monitor->is_decoder)
    return;


  parent = gst_object_get_parent (GST_OBJECT (element));
  do {
    if (GES_IS_TRACK (parent)) {
      GstElementClass *klass = GST_ELEMENT_CLASS (G_OBJECT_GET_CLASS (element));
      const gchar *klassname =
          gst_element_class_get_metadata (klass, GST_ELEMENT_METADATA_KLASS);

      if (GES_IS_AUDIO_TRACK (parent) && strstr (klassname, "Audio") == NULL) {
        GST_VALIDATE_REPORT (monitor, WRONG_DECODER_ADDED,
            "Adding non audio decoder %s in audio track %s.",
            GST_OBJECT_NAME (element), GST_OBJECT_NAME (parent));
      } else if (GES_IS_VIDEO_TRACK (parent)
          && strstr (klassname, "Video") == NULL
          && strstr (klassname, "Image") == NULL) {
        GST_VALIDATE_REPORT (monitor, WRONG_DECODER_ADDED,
            "Adding non video decoder %s in video track %s.",
            GST_OBJECT_NAME (element), GST_OBJECT_NAME (parent));

      }
      gst_object_unref (parent);
      break;
    }

    gst_object_unref (parent);
    parent = gst_object_get_parent (parent);
  } while (parent);
}
Exemplo n.º 5
0
static gboolean
gst_validate_ssim_get_frame_from_png (GstValidateSsim * self, const char *file,
    GstVideoFrame * frame)
{
  guint8 *data;
  GstBuffer *buf;
  GstVideoInfo info;
  cairo_surface_t *surface = NULL;

  surface = cairo_image_surface_create_from_png (file);
  if (surface == NULL
      || (cairo_surface_status (surface) != CAIRO_STATUS_SUCCESS)) {
    GST_VALIDATE_REPORT (self, GENERAL_INPUT_ERROR, "Could not open %s: %s",
        file, cairo_status_to_string (cairo_surface_status (surface)));

    return FALSE;
  }

  gst_video_info_init (&info);
  gst_video_info_set_format (&info,
      _get_format_from_surface (surface),
      cairo_image_surface_get_width (surface),
      cairo_image_surface_get_height (surface));

  data = cairo_image_surface_get_data (surface);
  buf = gst_buffer_new_wrapped_full (GST_MEMORY_FLAG_READONLY,
      data, info.size, 0, info.size, surface,
      (GDestroyNotify) cairo_surface_destroy);
  if (!gst_video_frame_map (frame, &info, buf, GST_MAP_READ)) {
    gst_buffer_unref (buf);
    GST_VALIDATE_REPORT (self, GENERAL_INPUT_ERROR,
        "Could not map input frame");

    return FALSE;
  }

  gst_buffer_unref (buf);

  return TRUE;
}
Exemplo n.º 6
0
gboolean
gst_validate_ssim_compare_image_files (GstValidateSsim * self,
    const gchar * ref_file, const gchar * file, gfloat * mean, gfloat * lowest,
    gfloat * highest, const gchar * outfolder)
{
  if (g_file_test (ref_file, G_FILE_TEST_IS_DIR)) {
    if (!g_file_test (file, G_FILE_TEST_IS_DIR)) {
      GST_VALIDATE_REPORT (self, GENERAL_INPUT_ERROR,
          "%s is a directory but %s is not", ref_file, file);

      return FALSE;
    }

    return _check_directory (self, ref_file, file, mean, lowest, highest,
        outfolder);
  } else {
    return gst_validate_ssim_compare_image_file (self, ref_file, file, mean,
        lowest, highest, outfolder);
  }
}
/*  Return -1 if not found 1 if OK 0 if an error occured */
static gint
comparse_stream (GstMediaDescriptor * ref, StreamNode * rstream,
    StreamNode * cstream)
{
  if (g_strcmp0 (rstream->id, cstream->id) == 0) {
    if (!gst_caps_is_equal (rstream->caps, cstream->caps)) {
      gchar *rcaps = gst_caps_to_string (rstream->caps),
          *ccaps = gst_caps_to_string (cstream->caps);
      GST_VALIDATE_REPORT (ref, FILE_PROFILE_INCORRECT,
          "Reference descriptor for stream %s has caps: %s"
          " but compared stream %s has caps: %s",
          rstream->id, rcaps, cstream->id, ccaps);
      g_free (rcaps);
      g_free (ccaps);
      return 0;
    }

    compare_tags (ref, rstream, cstream);

    return 1;
  }

  return -1;
}
Exemplo n.º 8
0
static void
_bus_handler (GstBus * bus, GstMessage * message,
    GstValidatePipelineMonitor * monitor)
{
  GError *err = NULL;
  gchar *debug = NULL;
  const GstStructure *details = NULL;
  gint error_flow = GST_FLOW_OK;

  switch (GST_MESSAGE_TYPE (message)) {
    case GST_MESSAGE_ERROR:
      gst_message_parse_error (message, &err, &debug);
      gst_message_parse_error_details (message, &details);

      if (g_error_matches (err, GST_CORE_ERROR, GST_CORE_ERROR_MISSING_PLUGIN)) {
        GST_VALIDATE_REPORT (monitor, MISSING_PLUGIN,
            "Error: %s -- Debug message: %s", err->message, debug);
      } else if ((g_error_matches (err, GST_STREAM_ERROR,
                  GST_STREAM_ERROR_FAILED) && details
              && gst_structure_get_int (details, "flow-return", &error_flow)
              && error_flow == GST_FLOW_NOT_NEGOTIATED)
          || g_error_matches (err, GST_STREAM_ERROR, GST_STREAM_ERROR_FORMAT)) {
        gchar *report = _generate_not_negotiated_error_report (message);

        GST_VALIDATE_REPORT (monitor, NOT_NEGOTIATED, "%s", report);
        g_free (report);
      } else {
        GST_VALIDATE_REPORT (monitor, ERROR_ON_BUS,
            "Got error: %s -- Debug message: %s", err->message, debug);
      }

      GST_VALIDATE_MONITOR_LOCK (monitor);
      monitor->got_error = TRUE;
      GST_VALIDATE_MONITOR_UNLOCK (monitor);
      g_error_free (err);
      g_free (debug);
      break;
    case GST_MESSAGE_WARNING:
      gst_message_parse_warning (message, &err, &debug);
      GST_VALIDATE_REPORT (monitor, WARNING_ON_BUS,
          "Got warning: %s -- Debug message: %s", err->message, debug);
      g_error_free (err);
      g_free (debug);
      break;
    case GST_MESSAGE_STATE_CHANGED:
    {
      if (GST_MESSAGE_SRC (message) == GST_VALIDATE_MONITOR (monitor)->target) {
        GstState oldstate, newstate, pending;

        gst_message_parse_state_changed (message, &oldstate, &newstate,
            &pending);

        if (oldstate == GST_STATE_READY && newstate == GST_STATE_PAUSED) {
          monitor->print_pos_srcid =
              g_timeout_add (PRINT_POSITION_TIMEOUT,
              (GSourceFunc) print_position, monitor);
        } else if (oldstate >= GST_STATE_PAUSED && newstate <= GST_STATE_READY) {
          if (monitor->print_pos_srcid
              && g_source_remove (monitor->print_pos_srcid))
            monitor->print_pos_srcid = 0;
          monitor->got_error = FALSE;
        }
      }

      break;
    }
    case GST_MESSAGE_BUFFERING:
    {
      JsonBuilder *jbuilder = json_builder_new ();
      GstBufferingMode mode;
      gint percent;

      gst_message_parse_buffering (message, &percent);
      gst_message_parse_buffering_stats (message, &mode, NULL, NULL, NULL);

      json_builder_begin_object (jbuilder);
      json_builder_set_member_name (jbuilder, "type");
      json_builder_add_string_value (jbuilder, "buffering");
      json_builder_set_member_name (jbuilder, "state");
      if (percent == 100) {
        /* a 100% message means buffering is done */
        gst_validate_printf (NULL, "\nDone buffering\n");
        json_builder_add_string_value (jbuilder, "done");
        if (monitor->buffering) {
          monitor->print_pos_srcid =
              g_timeout_add (PRINT_POSITION_TIMEOUT,
              (GSourceFunc) print_position, monitor);
          monitor->buffering = FALSE;
        }
      } else {
        /* buffering... */
        if (!monitor->buffering) {
          monitor->buffering = TRUE;
          gst_validate_printf (NULL, "\nStart buffering\n");
          json_builder_add_string_value (jbuilder, "started");
          if (monitor->print_pos_srcid
              && g_source_remove (monitor->print_pos_srcid)) {
            monitor->print_pos_srcid = 0;
          }
        } else {
          json_builder_add_string_value (jbuilder, "progress");
        }
        gst_validate_printf (NULL, "%s %d%%  \r", "Buffering...", percent);
      }
      json_builder_set_member_name (jbuilder, "position");
      json_builder_add_int_value (jbuilder, percent);
      json_builder_end_object (jbuilder);

      gst_validate_send (json_builder_get_root (jbuilder));
      g_object_unref (jbuilder);
      break;
    }
    case GST_MESSAGE_STREAM_COLLECTION:
    {
      GstStreamCollection *collection = NULL;
      gst_message_parse_stream_collection (message, &collection);
      gst_object_replace ((GstObject **) & monitor->stream_collection,
          (GstObject *) collection);
      gst_object_unref (collection);
      break;
    }
    case GST_MESSAGE_STREAMS_SELECTED:
    {
      guint i;

      if (monitor->streams_selected) {
        g_list_free_full (monitor->streams_selected, gst_object_unref);
        monitor->streams_selected = NULL;
      }

      for (i = 0; i < gst_message_streams_selected_get_size (message); i++) {
        GstStream *stream =
            gst_message_streams_selected_get_stream (message, i);

        monitor->streams_selected =
            g_list_append (monitor->streams_selected, stream);
      }
      break;
    }
    default:
      break;
  }
}
Exemplo n.º 9
0
static gboolean
gst_validate_ssim_compare_image_file (GstValidateSsim * self,
    const gchar * ref_file, const gchar * file, gfloat * mean, gfloat * lowest,
    gfloat * highest, const gchar * outfolder)
{
  GstBuffer *outbuf = NULL, **poutbuf = NULL;
  gboolean res = TRUE;
  GstVideoFrame ref_frame, frame;
  gchar *real_ref_file = NULL;

  real_ref_file = _get_ref_file_path (self, ref_file, file, FALSE);

  if (!real_ref_file) {
    GST_VALIDATE_REPORT (self, GENERAL_INPUT_ERROR,
        "Could find ref file for %s", ref_file);
    goto fail;
  }

  if (!gst_validate_ssim_get_frame_from_file (self, real_ref_file, &ref_frame))
    goto fail;


  if (!gst_validate_ssim_get_frame_from_file (self, file, &frame)) {
    gst_video_frame_unmap (&ref_frame);

    goto fail;
  }

  if (outfolder) {
    poutbuf = &outbuf;
  }

  gst_validate_ssim_compare_frames (self, &ref_frame, &frame,
      poutbuf, mean, lowest, highest);

  if (*mean < self->priv->min_avg_similarity) {
    gst_video_frame_unmap (&ref_frame);
    gst_video_frame_unmap (&frame);

    if (g_strcmp0 (ref_file, real_ref_file)) {
      gchar *tmpref = real_ref_file;

      real_ref_file = _get_ref_file_path (self, ref_file, file, TRUE);

      GST_VALIDATE_REPORT (self, SIMILARITY_ISSUE_WITH_PREVIOUS,
          "\nComparing %s with %s failed, (mean %f "
          " min %f), checking next %s\n", tmpref, file,
          *mean, *lowest, real_ref_file);

      g_free (tmpref);

      res = gst_validate_ssim_compare_image_file (self,
          real_ref_file, file, mean, lowest, highest, outfolder);
      goto done;
    }

    GST_VALIDATE_REPORT (self, SIMILARITY_ISSUE,
        "Average similarity '%f' between %s and %s inferior"
        " than the minimum average: %f", *mean,
        real_ref_file, file, self->priv->min_avg_similarity);

    goto fail;
  }

  if (*lowest < self->priv->min_lowest_similarity) {
    GST_VALIDATE_REPORT (self, SIMILARITY_ISSUE,
        "Lowest similarity '%f' between %s and %s inferior"
        " than the minimum lowest similarity: %f", *lowest,
        real_ref_file, file, self->priv->min_lowest_similarity);

    gst_video_frame_unmap (&ref_frame);
    gst_video_frame_unmap (&frame);

    goto fail;
  }

  gst_video_frame_unmap (&ref_frame);
  gst_video_frame_unmap (&frame);

done:

  g_free (real_ref_file);
  if (outbuf)
    gst_buffer_unref (outbuf);

  return res;

fail:
  res = FALSE;

  if (outbuf)
    gst_validate_ssim_save_out (self, outbuf, real_ref_file, file, outfolder);

  goto done;
}
Exemplo n.º 10
0
static gboolean
gst_validate_ssim_get_frame_from_file (GstValidateSsim * self, const char *file,
    GstVideoFrame * frame)
{
  gchar *data;
  gsize length;
  GstBuffer *buf;
  GstVideoInfo info;
  GstVideoFormat format;
  gint strv_length, width, height;

  gboolean res = TRUE;
  gchar **splited_name = NULL, **splited_size = NULL, *strformat;

  GError *error = NULL;

  if (g_str_has_suffix (file, ".png")) {
    return gst_validate_ssim_get_frame_from_png (self, file, frame);
  }

  splited_name = g_strsplit (file, ".", -1);
  strv_length = g_strv_length (splited_name);

  strformat = splited_name[strv_length - 1];
  format = gst_video_format_from_string (strformat);
  if (format == GST_VIDEO_FORMAT_UNKNOWN) {
    GST_VALIDATE_REPORT (self, WRONG_FORMAT, "Unknown format: %s", strformat);

    goto fail;
  }

  splited_size = g_strsplit (splited_name[strv_length - 2], "x", -1);
  if (g_strv_length (splited_size) != 2) {
    GST_VALIDATE_REPORT (self, WRONG_FORMAT,
        "Can not determine video size from filename: %s ", file);

    goto fail;
  }

  errno = 0;
  width = g_ascii_strtoull (splited_size[0], NULL, 10);
  if (errno) {
    GST_VALIDATE_REPORT (self, WRONG_FORMAT,
        "Can not determine video size from filename: %s ", file);

    goto fail;
  }

  errno = 0;
  height = g_ascii_strtoull (splited_size[1], NULL, 10);
  if (errno) {
    GST_VALIDATE_REPORT (self, WRONG_FORMAT,
        "Can not determine video size from filename: %s ", file);

    goto fail;
  }

  gst_video_info_init (&info);
  gst_video_info_set_format (&info, format, width, height);

  if (!g_file_get_contents (file, &data, &length, &error)) {
    GST_VALIDATE_REPORT (self, GENERAL_INPUT_ERROR, "Could not open %s: %s",
        file, error->message);
    g_error_free (error);

    goto fail;
  }

  buf = gst_buffer_new_wrapped (data, length);
  if (!gst_video_frame_map (frame, &info, buf, GST_MAP_READ)) {
    gst_buffer_unref (buf);
    GST_VALIDATE_REPORT (self, GENERAL_INPUT_ERROR,
        "Could not map input frame");

    goto fail;
  }
  gst_buffer_unref (buf);

done:
  g_strfreev (splited_name);
  g_strfreev (splited_size);

  return res;

fail:
  res = FALSE;

  goto done;
}
Exemplo n.º 11
0
void
gst_validate_ssim_compare_frames (GstValidateSsim * self,
    GstVideoFrame * ref_frame, GstVideoFrame * frame, GstBuffer ** outbuf,
    gfloat * mean, gfloat * lowest, gfloat * highest)
{
  gboolean reconf;
  guint8 *outdata = NULL;
  GstMapInfo map1, map2, outmap;

  GstVideoFrame converted_frame1, converted_frame2;
  SSimConverterInfo *convinfo1, *convinfo2;

  reconf =
      gst_validate_ssim_configure (self, ref_frame->info.width,
      ref_frame->info.height);

  gst_validate_ssim_configure_converter (self, 0, reconf,
      ref_frame->info.finfo->format, ref_frame->info.width,
      ref_frame->info.height);

  gst_validate_ssim_configure_converter (self, 1, reconf,
      frame->info.finfo->format, frame->info.width, frame->info.height);

  convinfo1 = (SSimConverterInfo *) g_list_nth_data (self->priv->converters, 0);
  if (convinfo1->converter)
    gst_validate_ssim_convert (self, convinfo1, ref_frame, &converted_frame1);
  else
    converted_frame1 = *ref_frame;

  convinfo2 = (SSimConverterInfo *) g_list_nth_data (self->priv->converters, 1);
  if (convinfo2->converter)
    gst_validate_ssim_convert (self, convinfo2, frame, &converted_frame2);
  else
    converted_frame2 = *frame;

  if (!gst_buffer_map (converted_frame1.buffer, &map1, GST_MAP_READ)) {
    GST_VALIDATE_REPORT (self, GENERAL_INPUT_ERROR,
        "Could not map reference frame");

    return;
  }

  if (!gst_buffer_map (converted_frame2.buffer, &map2, GST_MAP_READ)) {
    gst_buffer_unmap (converted_frame1.buffer, &map1);
    GST_VALIDATE_REPORT (self, GENERAL_INPUT_ERROR,
        "Could not map compared frame");

    return;
  }

  if (outbuf) {
    *outbuf = gst_buffer_new_and_alloc (GST_ROUND_UP_4 (self->priv->width) *
        self->priv->height);
    if (!gst_buffer_map (*outbuf, &outmap, GST_MAP_WRITE)) {
      GST_VALIDATE_REPORT (self, GENERAL_INPUT_ERROR,
          "Could not map output frame");

      gst_buffer_unref (*outbuf);
      gst_buffer_unmap (converted_frame1.buffer, &map1);
      gst_buffer_unmap (converted_frame2.buffer, &map2);
      *outbuf = NULL;

      return;
    }

    outdata = outmap.data;
  }

  gssim_compare (self->priv->ssim, map1.data, map2.data, outdata, mean,
      lowest, highest);

  gst_buffer_unmap (ref_frame->buffer, &map1);
  gst_buffer_unmap (frame->buffer, &map2);

  if (convinfo1->converter)
    gst_video_frame_unmap (&converted_frame1);
  if (convinfo2->converter)
    gst_video_frame_unmap (&converted_frame2);

  if (outbuf)
    gst_buffer_unmap (*outbuf, &outmap);
}
Exemplo n.º 12
0
static void
gst_validate_ssim_save_out (GstValidateSsim * self, GstBuffer * buffer,
    const gchar * ref_file, const gchar * file, const gchar * outfolder)
{
  GstVideoFrame frame, converted;

  if (!g_file_test (outfolder, G_FILE_TEST_IS_DIR)) {
    if (g_mkdir_with_parents (outfolder, 0755) != 0) {

      GST_VALIDATE_REPORT (self, GENERAL_INPUT_ERROR,
          "Could not create output directory %s", outfolder);
      return;
    }
  }

  if (self->priv->outconverter_info.converter == NULL ||
      self->priv->width != self->priv->outconverter_info.out_info.width ||
      self->priv->height != self->priv->outconverter_info.out_info.height) {

    if (self->priv->outconverter_info.converter)
      gst_video_converter_free (self->priv->outconverter_info.converter);

    gst_video_info_init (&self->priv->outconverter_info.in_info);
    gst_video_info_set_format (&self->priv->outconverter_info.in_info,
        GST_VIDEO_FORMAT_GRAY8, self->priv->width, self->priv->height);

    gst_video_info_init (&self->priv->outconverter_info.out_info);
    gst_video_info_set_format (&self->priv->outconverter_info.out_info,
        GST_VIDEO_FORMAT_RGBx, self->priv->width, self->priv->height);

    self->priv->outconverter_info.converter =
        gst_video_converter_new (&self->priv->outconverter_info.in_info,
        &self->priv->outconverter_info.out_info, NULL);
  }

  if (!gst_video_frame_map (&frame, &self->priv->outconverter_info.in_info,
          buffer, GST_MAP_READ)) {
    GST_VALIDATE_REPORT (self, GENERAL_INPUT_ERROR,
        "Could not map output frame");

    return;
  }

  if (gst_validate_ssim_convert (self, &self->priv->outconverter_info,
          &frame, &converted)) {
    cairo_status_t status;
    cairo_surface_t *surface;
    gchar *bn1 = g_path_get_basename (ref_file);
    gchar *bn2 = g_path_get_basename (file);
    gchar *fname = g_strdup_printf ("%s.VS.%s.result.png", bn1, bn2);
    gchar *outfile = g_build_path (G_DIR_SEPARATOR_S, outfolder, fname, NULL);

    surface =
        cairo_image_surface_create_for_data (GST_VIDEO_FRAME_PLANE_DATA
        (&converted, 0), CAIRO_FORMAT_RGB24, GST_VIDEO_FRAME_WIDTH (&converted),
        GST_VIDEO_FRAME_HEIGHT (&converted),
        GST_VIDEO_FRAME_PLANE_STRIDE (&converted, 0));

    if ((status = cairo_surface_write_to_png (surface, outfile)) !=
        CAIRO_STATUS_SUCCESS) {
      GST_VALIDATE_REPORT (self, GENERAL_INPUT_ERROR,
          "Could not save '%s', cairo status is '%s'", outfile,
          cairo_status_to_string (status));
    }

    cairo_surface_destroy (surface);
    gst_video_frame_unmap (&frame);
    gst_video_frame_unmap (&converted);
    g_free (bn1);
    g_free (bn2);
    g_free (fname);
    g_free (outfile);
  }
}
static gint
compare_tags (GstMediaDescriptor * ref, StreamNode * rstream,
    StreamNode * cstream)
{
  gboolean found;
  TagNode *rtag, *ctag;
  GList *rtag_list, *ctag_list;
  TagsNode *rtags, *ctags;

  rtags = rstream->tags;
  ctags = cstream->tags;
  if (rtags == NULL && ctags)
    return 1;
  else if (!rtags && ctags) {
    GList *taglist;
    GString *all_tags = g_string_new (NULL);

    for (taglist = ctags->tags; taglist; taglist = taglist->next) {
      gchar *stags =
          gst_tag_list_to_string (((TagNode *) taglist->data)->taglist);

      g_string_append_printf (all_tags, "%s\n", stags);
      g_free (stags);
    }

    GST_VALIDATE_REPORT (ref, FILE_TAG_DETECTION_INCORRECT,
        "Reference descriptor for stream %s has NO tags"
        " but tags found: %s", all_tags->str);

    g_string_free (all_tags, TRUE);

    return 0;
  } else if (rtags && !ctags) {
    GList *taglist;
    GString *all_tags = g_string_new (NULL);

    for (taglist = rtags->tags; taglist; taglist = taglist->next) {
      gchar *stags =
          gst_tag_list_to_string (((TagNode *) taglist->data)->taglist);

      g_string_append_printf (all_tags, "%s\n", stags);
      g_free (stags);
    }

    GST_VALIDATE_REPORT (ref, FILE_TAG_DETECTION_INCORRECT,
        "Reference descriptor for stream %s has tags:\n %s\n"
        " but NO tags found on the stream");

    g_string_free (all_tags, TRUE);
    return 0;
  }

  for (rtag_list = rtags->tags; rtag_list; rtag_list = rtag_list->next) {
    rtag = rtag_list->data;
    found = FALSE;
    for (ctag_list = ctags->tags; ctag_list; ctag_list = ctag_list->next) {
      ctag = ctag_list->data;
      if (gst_tag_list_is_equal (rtag->taglist, ctag->taglist)) {
        found = TRUE;

        break;
      }
    }

    if (found == FALSE) {
      gchar *rtaglist = gst_tag_list_to_string (rtag->taglist);

      GST_VALIDATE_REPORT (ref, FILE_TAG_DETECTION_INCORRECT,
          "Reference descriptor for stream %s has tags %s"
          " but no equivalent taglist was found on the compared stream",
          rstream->id, rtaglist);
      g_free (rtaglist);

      return 0;
    }
  }

  return 1;
}
static void
_bus_handler (GstBus * bus, GstMessage * message,
    GstValidatePipelineMonitor * monitor)
{
  GError *err = NULL;
  gchar *debug = NULL;

  switch (GST_MESSAGE_TYPE (message)) {
    case GST_MESSAGE_ERROR:
      gst_message_parse_error (message, &err, &debug);

      if (g_error_matches (err, GST_CORE_ERROR, GST_CORE_ERROR_MISSING_PLUGIN)) {
        GST_VALIDATE_REPORT (monitor, MISSING_PLUGIN,
            "Error: %s -- Debug message: %s", err->message, debug);
      } else {
        GST_VALIDATE_REPORT (monitor, ERROR_ON_BUS,
            "Got error: %s -- Debug message: %s", err->message, debug);
      }
      GST_VALIDATE_MONITOR_LOCK (monitor);
      monitor->got_error = TRUE;
      GST_VALIDATE_MONITOR_UNLOCK (monitor);
      g_error_free (err);
      g_free (debug);
      break;
    case GST_MESSAGE_WARNING:
      gst_message_parse_warning (message, &err, &debug);
      GST_VALIDATE_REPORT (monitor, WARNING_ON_BUS,
          "Got warning: %s -- Debug message: %s", err->message, debug);
      g_error_free (err);
      g_free (debug);
      break;
    case GST_MESSAGE_STATE_CHANGED:
    {
      if (GST_MESSAGE_SRC (message) == GST_VALIDATE_MONITOR (monitor)->target) {
        GstState oldstate, newstate, pending;

        gst_message_parse_state_changed (message, &oldstate, &newstate,
            &pending);

        if (oldstate == GST_STATE_READY && newstate == GST_STATE_PAUSED) {
          monitor->print_pos_srcid =
              g_timeout_add (PRINT_POSITION_TIMEOUT,
              (GSourceFunc) print_position, monitor);
        } else if (oldstate >= GST_STATE_PAUSED && newstate <= GST_STATE_READY) {
          if (monitor->print_pos_srcid
              && g_source_remove (monitor->print_pos_srcid))
            monitor->print_pos_srcid = 0;
          monitor->got_error = FALSE;
        }
      }

      break;
    }
    case GST_MESSAGE_BUFFERING:
    {
      GstBufferingMode mode;
      gint percent;

      gst_message_parse_buffering (message, &percent);
      gst_message_parse_buffering_stats (message, &mode, NULL, NULL, NULL);

      if (percent == 100) {
        /* a 100% message means buffering is done */
        if (monitor->buffering) {
          monitor->print_pos_srcid =
              g_timeout_add (PRINT_POSITION_TIMEOUT,
              (GSourceFunc) print_position, monitor);
          monitor->buffering = FALSE;
        }
      } else {
        /* buffering... */
        if (!monitor->buffering) {
          monitor->buffering = TRUE;
          if (monitor->print_pos_srcid
              && g_source_remove (monitor->print_pos_srcid))
            monitor->print_pos_srcid = 0;
        }
      }
      break;
    }
    default:
      break;
  }
}