Beispiel #1
0
static void
compare_shutter_speed (ExifEntry * entry, ExifTagCheckData * testdata)
{
  gdouble gst_num, exif_num;
  ExifSRational rational;
  GValue exif_value = { 0 };
  const GValue *gst_value = NULL;

  gst_value = gst_tag_list_get_value_index (testdata->taglist,
      GST_TAG_CAPTURING_SHUTTER_SPEED, 0);
  if (gst_value == NULL) {
    GST_WARNING ("Failed to get shutter-speed from taglist");
    return;
  }

  rational = exif_get_srational (entry->data,
      exif_data_get_byte_order (entry->parent->parent));

  g_value_init (&exif_value, GST_TYPE_FRACTION);
  gst_value_set_fraction (&exif_value, rational.numerator,
      rational.denominator);
  gst_util_fraction_to_double (gst_value_get_fraction_numerator (&exif_value),
      gst_value_get_fraction_denominator (&exif_value), &exif_num);
  g_value_unset (&exif_value);

  gst_util_fraction_to_double (gst_value_get_fraction_numerator (gst_value),
      gst_value_get_fraction_denominator (gst_value), &gst_num);

  exif_num = pow (2, -exif_num);

  GST_LOG ("Shutter speed in gst=%lf and in exif=%lf", gst_num, exif_num);
  fail_unless (ABS (gst_num - exif_num) < 0.001);
  testdata->result = TRUE;
}
/**
 * gst_video_time_code_to_date_time:
 * @tc: #GstVideoTimeCode to convert
 *
 * The @tc.config->latest_daily_jam is required to be non-NULL.
 *
 * Returns: the #GDateTime representation of @tc.
 *
 * Since: 1.10
 */
GDateTime *
gst_video_time_code_to_date_time (const GstVideoTimeCode * tc)
{
  GDateTime *ret;
  GDateTime *ret2;
  gdouble add_us;

  g_return_val_if_fail (gst_video_time_code_is_valid (tc), NULL);
  g_return_val_if_fail (tc->config.latest_daily_jam != NULL, NULL);

  ret = g_date_time_ref (tc->config.latest_daily_jam);

  if (ret == NULL) {
    gchar *tc_str = gst_video_time_code_to_string (tc);
    GST_WARNING
        ("Asked to convert time code %s to GDateTime, but its latest daily jam is NULL",
        tc_str);
    g_free (tc_str);
    return NULL;
  }

  if (tc->config.fps_n == 0 && tc->config.fps_d == 1) {
    gchar *tc_str = gst_video_time_code_to_string (tc);
    GST_WARNING
        ("Asked to convert time code %s to GDateTime, but its framerate is unknown",
        tc_str);
    g_free (tc_str);
    return NULL;
  }

  gst_util_fraction_to_double (tc->frames * tc->config.fps_d, tc->config.fps_n,
      &add_us);
  if ((tc->config.flags & GST_VIDEO_TIME_CODE_FLAGS_INTERLACED)
      && tc->field_count == 1) {
    gdouble sub_us;

    gst_util_fraction_to_double (tc->config.fps_d, 2 * tc->config.fps_n,
        &sub_us);
    add_us -= sub_us;
  }

  ret2 = g_date_time_add_seconds (ret, add_us + tc->seconds);
  g_date_time_unref (ret);
  ret = g_date_time_add_minutes (ret2, tc->minutes);
  g_date_time_unref (ret2);
  ret2 = g_date_time_add_hours (ret, tc->hours);
  g_date_time_unref (ret);

  return ret2;
}
Beispiel #3
0
static void
compare_aperture_value (ExifEntry * entry, ExifTagCheckData * testdata)
{
  gdouble gst_value, exif_value;
  ExifSRational rational;
  GValue value = { 0 };

  if (!gst_tag_list_get_double_index (testdata->taglist,
          GST_TAG_CAPTURING_FOCAL_RATIO, 0, &gst_value)) {
    GST_WARNING ("Failed to get focal ratio from taglist");
    return;
  }

  rational = exif_get_srational (entry->data,
      exif_data_get_byte_order (entry->parent->parent));

  g_value_init (&value, GST_TYPE_FRACTION);
  gst_value_set_fraction (&value, rational.numerator, rational.denominator);
  gst_util_fraction_to_double (gst_value_get_fraction_numerator (&value),
      gst_value_get_fraction_denominator (&value), &exif_value);
  g_value_unset (&value);

  exif_value = pow (2, exif_value / 2);

  GST_LOG ("Aperture value in gst=%lf and in exif=%lf", gst_value, exif_value);
  fail_unless (ABS (gst_value - exif_value) < 0.001);
  testdata->result = TRUE;
}
Beispiel #4
0
static void
parse_exif_rational_tag (GstExifReader * exif_reader,
    const gchar * gst_tag, guint32 count, guint32 offset, gdouble multiplier)
{
  GstByteReader data_reader;
  guint32 real_offset;
  guint32 frac_n = 0;
  guint32 frac_d = 1;
  gdouble value;

  if (count > 1) {
    GST_WARNING ("Rationals with multiple entries are not supported");
  }
  if (offset < exif_reader->base_offset) {
    GST_WARNING ("Offset is smaller (%u) than base offset (%u)", offset,
        exif_reader->base_offset);
    return;
  }

  real_offset = offset - exif_reader->base_offset;
  if (real_offset >= GST_BUFFER_SIZE (exif_reader->buffer)) {
    GST_WARNING ("Invalid offset %u for buffer of size %u, not adding tag %s",
        real_offset, GST_BUFFER_SIZE (exif_reader->buffer), gst_tag);
    return;
  }

  gst_byte_reader_init_from_buffer (&data_reader, exif_reader->buffer);
  if (!gst_byte_reader_set_pos (&data_reader, real_offset))
    goto reader_fail;

  if (exif_reader->byte_order == G_LITTLE_ENDIAN) {
    if (!gst_byte_reader_get_uint32_le (&data_reader, &frac_n) ||
        !gst_byte_reader_get_uint32_le (&data_reader, &frac_d))
      goto reader_fail;
  } else {
    if (!gst_byte_reader_get_uint32_be (&data_reader, &frac_n) ||
        !gst_byte_reader_get_uint32_be (&data_reader, &frac_d))
      goto reader_fail;
  }

  GST_DEBUG ("Read fraction for tag %s: %u/%u", gst_tag, frac_n, frac_d);

  gst_util_fraction_to_double (frac_n, frac_d, &value);

  value *= multiplier;
  GST_DEBUG ("Adding %s tag: %lf", gst_tag, value);
  gst_tag_list_add (exif_reader->taglist, GST_TAG_MERGE_REPLACE, gst_tag, value,
      NULL);

  return;

reader_fail:
  GST_WARNING ("Failed to read from byte reader. (Buffer too short?)");
}
static void
init_params (GstMfxFilter * filter)
{
  gdouble frame_rate;

  filter->params.vpp.In = filter->frame_info;

  /* Aligned frame dimensions may differ between input and output surfaces
   * so we sanitize the input frame dimensions, since output frame dimensions
   * could have certain alignment requirements used in HEVC HW encoding */
  if (filter->shared_request[1]) {
    filter->params.vpp.In.Width = GST_ROUND_UP_16 (filter->frame_info.CropW);
    filter->params.vpp.In.Height =
        (MFX_PICSTRUCT_PROGRESSIVE == filter->frame_info.PicStruct) ?
            GST_ROUND_UP_16 (filter->frame_info.CropH) :
            GST_ROUND_UP_32 (filter->frame_info.CropH);
  }
  filter->params.vpp.Out = filter->frame_info;

  if (filter->fourcc)
    filter->params.vpp.Out.FourCC = filter->fourcc;

  if (filter->width) {
    filter->params.vpp.Out.CropW = filter->width;
    filter->params.vpp.Out.Width = GST_ROUND_UP_16 (filter->width);
  }
  if (filter->height) {
    filter->params.vpp.Out.CropH = filter->height;
    filter->params.vpp.Out.Height =
        (MFX_PICSTRUCT_PROGRESSIVE == filter->frame_info.PicStruct) ?
           GST_ROUND_UP_16 (filter->height) :
           GST_ROUND_UP_32 (filter->height);
  }
  if (filter->filter_op & GST_MFX_FILTER_DEINTERLACING) {
    /* Setup special double frame rate deinterlace mode */
    gst_util_fraction_to_double (filter->params.vpp.In.FrameRateExtN,
      filter->params.vpp.In.FrameRateExtD, &frame_rate);
    if ((filter->frame_info.PicStruct == MFX_PICSTRUCT_FIELD_TFF ||
          filter->frame_info.PicStruct == MFX_PICSTRUCT_FIELD_BFF) &&
        (int)(frame_rate + 0.5) == 60)
    filter->params.vpp.In.FrameRateExtN /= 2;

    filter->params.vpp.Out.PicStruct = MFX_PICSTRUCT_PROGRESSIVE;
  }
  if (filter->filter_op & GST_MFX_FILTER_FRAMERATE_CONVERSION &&
      (filter->fps_n && filter->fps_d)) {
    filter->params.vpp.Out.FrameRateExtN = filter->fps_n;
    filter->params.vpp.Out.FrameRateExtD = filter->fps_d;
  }

  configure_filters (filter);
}
/**
 * gst_video_time_code_frames_since_daily_jam:
 * @tc: a #GstVideoTimeCode
 *
 * Returns: how many frames have passed since the daily jam of @tc .
 *
 * Since: 1.10
 */
guint64
gst_video_time_code_frames_since_daily_jam (const GstVideoTimeCode * tc)
{
  guint ff_nom;
  gdouble ff;

  g_return_val_if_fail (gst_video_time_code_is_valid (tc), -1);
  g_assert (tc->hours <= 24);
  g_assert (tc->minutes < 60);
  g_assert (tc->seconds < 60);
  g_assert (tc->frames <= tc->config.fps_n / tc->config.fps_d);

  gst_util_fraction_to_double (tc->config.fps_n, tc->config.fps_d, &ff);
  if (tc->config.fps_d == 1001) {
    ff_nom = tc->config.fps_n / 1000;
  } else {
    ff_nom = ff;
  }
  if (tc->config.flags & GST_VIDEO_TIME_CODE_FLAGS_DROP_FRAME) {
    /* these need to be truncated to integer: side effect, code looks cleaner
     * */
    guint ff_minutes = 60 * ff;
    guint ff_hours = 3600 * ff;
    /* for 30000/1001 we drop the first 2 frames per minute, for 60000/1001 we
     * drop the first 4 : so we use this number */
    guint dropframe_multiplier;

    if (tc->config.fps_n == 30000) {
      dropframe_multiplier = 2;
    } else if (tc->config.fps_n == 60000) {
      dropframe_multiplier = 4;
    } else {
      GST_ERROR ("Unsupported drop frame rate %u/%u", tc->config.fps_n,
          tc->config.fps_d);
      return -1;
    }

    return tc->frames + (ff_nom * tc->seconds) +
        (ff_minutes * tc->minutes) +
        dropframe_multiplier * ((gint) (tc->minutes / 10)) +
        (ff_hours * tc->hours);
  } else {
    return tc->frames + (ff_nom * (tc->seconds + (60 * (tc->minutes +
                    (60 * tc->hours)))));
  }

}
/* 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;
}
Beispiel #8
0
static gint
deserialize_geo_coordinate (GstExifReader * exif_reader,
    GstByteReader * reader, const GstExifTagMatch * exiftag,
    GstExifTagData * tagdata)
{
  GstByteReader fractions_reader;
  gint multiplier;
  GstExifTagData next_tagdata;
  gint ret = 0;
  /* for the conversion */
  guint32 degrees_n = 0;
  guint32 degrees_d = 1;
  guint32 minutes_n = 0;
  guint32 minutes_d = 1;
  guint32 seconds_n = 0;
  guint32 seconds_d = 1;
  gdouble degrees;
  gdouble minutes;
  gdouble seconds;

  GST_LOG ("Starting to parse %s tag in exif 0x%x", exiftag->gst_tag,
      exiftag->exif_tag);

  if (exiftag->complementary_tag != tagdata->tag) {
    /* First should come the 'Ref' tags */
    GST_WARNING ("Tag %d is not the 'Ref' tag for latitude nor longitude",
        tagdata->tag);
    return ret;
  }

  if (tagdata->offset_as_data[0] == 'N' || tagdata->offset_as_data[0] == 'E') {
    multiplier = 1;
  } else if (tagdata->offset_as_data[0] == 'S'
      || tagdata->offset_as_data[0] == 'W') {
    multiplier = -1;
  } else {
    GST_WARNING ("Invalid LatitudeRef or LongitudeRef %c",
        tagdata->offset_as_data[0]);
    return ret;
  }

  /* now read the following tag that must be the latitude or longitude */
  if (exif_reader->byte_order == G_LITTLE_ENDIAN) {
    if (!gst_byte_reader_peek_uint16_le (reader, &next_tagdata.tag))
      goto reader_fail;
  } else {
    if (!gst_byte_reader_peek_uint16_be (reader, &next_tagdata.tag))
      goto reader_fail;
  }

  if (exiftag->exif_tag != next_tagdata.tag) {
    GST_WARNING ("This is not a geo cordinate tag");
    return ret;
  }

  /* read the remaining tag entry data */
  if (!parse_exif_tag_header (reader, exif_reader->byte_order, &next_tagdata)) {
    ret = -1;
    goto reader_fail;
  }

  ret = 1;

  /* some checking */
  if (next_tagdata.tag_type != EXIF_TYPE_RATIONAL) {
    GST_WARNING ("Invalid type %d for geo coordinate (latitude/longitude)",
        next_tagdata.tag_type);
    return ret;
  }
  if (next_tagdata.count != 3) {
    GST_WARNING ("Geo coordinate should use 3 fractions, we have %u",
        next_tagdata.count);
    return ret;
  }

  /* now parse the fractions */
  gst_byte_reader_init_from_buffer (&fractions_reader, exif_reader->buffer);
  if (!gst_byte_reader_set_pos (&fractions_reader,
          next_tagdata.offset - exif_reader->base_offset))
    goto reader_fail;

  if (exif_reader->byte_order == G_LITTLE_ENDIAN) {
    if (!gst_byte_reader_get_uint32_le (&fractions_reader, &degrees_n) ||
        !gst_byte_reader_get_uint32_le (&fractions_reader, &degrees_d) ||
        !gst_byte_reader_get_uint32_le (&fractions_reader, &minutes_n) ||
        !gst_byte_reader_get_uint32_le (&fractions_reader, &minutes_d) ||
        !gst_byte_reader_get_uint32_le (&fractions_reader, &seconds_n) ||
        !gst_byte_reader_get_uint32_le (&fractions_reader, &seconds_d))
      goto reader_fail;
  } else {
    if (!gst_byte_reader_get_uint32_be (&fractions_reader, &degrees_n) ||
        !gst_byte_reader_get_uint32_be (&fractions_reader, &degrees_d) ||
        !gst_byte_reader_get_uint32_be (&fractions_reader, &minutes_n) ||
        !gst_byte_reader_get_uint32_be (&fractions_reader, &minutes_d) ||
        !gst_byte_reader_get_uint32_be (&fractions_reader, &seconds_n) ||
        !gst_byte_reader_get_uint32_be (&fractions_reader, &seconds_d))
      goto reader_fail;
  }

  GST_DEBUG ("Read degrees fraction for tag %s: %u/%u %u/%u %u/%u",
      exiftag->gst_tag, degrees_n, degrees_d, minutes_n, minutes_d,
      seconds_n, seconds_d);

  gst_util_fraction_to_double (degrees_n, degrees_d, &degrees);
  gst_util_fraction_to_double (minutes_n, minutes_d, &minutes);
  gst_util_fraction_to_double (seconds_n, seconds_d, &seconds);

  minutes += seconds / 60;
  degrees += minutes / 60;
  degrees *= multiplier;

  GST_DEBUG ("Adding %s tag: %lf", exiftag->gst_tag, degrees);
  gst_tag_list_add (exif_reader->taglist, GST_TAG_MERGE_REPLACE,
      exiftag->gst_tag, degrees, NULL);

  return ret;

reader_fail:
  GST_WARNING ("Failed to read fields from buffer (too short?)");
  return ret;
}
/**
 * gst_video_time_code_add_frames:
 * @tc: a #GstVideoTimeCode
 * @frames: How many frames to add or subtract
 *
 * Adds or subtracts @frames amount of frames to @tc .
 *
 * Since: 1.10
 */
void
gst_video_time_code_add_frames (GstVideoTimeCode * tc, gint64 frames)
{
  guint64 framecount;
  guint64 h_notmod24;
  guint64 h_new, min_new, sec_new, frames_new;
  gdouble ff;
  guint ff_nom;
  /* This allows for better readability than putting G_GUINT64_CONSTANT(60)
   * into a long calculation line */
  const guint64 sixty = 60;
  /* formulas found in SMPTE ST 2059-1:2015 section 9.4.3
   * and adapted for 60/1.001 as well as 30/1.001 */

  g_return_if_fail (gst_video_time_code_is_valid (tc));
  g_assert (tc->hours <= 24);
  g_assert (tc->minutes < 60);
  g_assert (tc->seconds < 60);
  g_assert (tc->frames <= tc->config.fps_n / tc->config.fps_d);

  gst_util_fraction_to_double (tc->config.fps_n, tc->config.fps_d, &ff);
  if (tc->config.fps_d == 1001) {
    ff_nom = tc->config.fps_n / 1000;
  } else {
    ff_nom = ff;
    if (tc->config.fps_d != 1)
      GST_WARNING ("Unsupported frame rate %u/%u, results may be wrong",
          tc->config.fps_n, tc->config.fps_d);
  }
  if (tc->config.flags & GST_VIDEO_TIME_CODE_FLAGS_DROP_FRAME) {
    /* these need to be truncated to integer: side effect, code looks cleaner
     * */
    guint ff_minutes = 60 * ff;
    guint ff_hours = 3600 * ff;
    /* a bunch of intermediate variables, to avoid monster code with possible
     * integer overflows */
    guint64 min_new_tmp1, min_new_tmp2, min_new_tmp3, min_new_denom;
    /* for 30000/1001 we drop the first 2 frames per minute, for 60000/1001 we
     * drop the first 4 : so we use this number */
    guint dropframe_multiplier;

    if (tc->config.fps_n == 30000)
      dropframe_multiplier = 2;
    else if (tc->config.fps_n == 60000)
      dropframe_multiplier = 4;
    else {
      GST_ERROR ("Unsupported drop frame rate %u/%u", tc->config.fps_n,
          tc->config.fps_d);
      return;
    }

    framecount =
        frames + tc->frames + (ff_nom * tc->seconds) +
        (ff_minutes * tc->minutes) +
        dropframe_multiplier * ((gint) (tc->minutes / 10)) +
        (ff_hours * tc->hours);
    h_notmod24 = gst_util_uint64_scale_int (framecount, 1, ff_hours);

    min_new_denom = sixty * ff_nom;
    min_new_tmp1 = (framecount - (h_notmod24 * ff_hours)) / min_new_denom;
    min_new_tmp2 = framecount + dropframe_multiplier * min_new_tmp1;
    min_new_tmp1 =
        (framecount - (h_notmod24 * ff_hours)) / (sixty * 10 * ff_nom);
    min_new_tmp3 =
        dropframe_multiplier * min_new_tmp1 + (h_notmod24 * ff_hours);
    min_new =
        gst_util_uint64_scale_int (min_new_tmp2 - min_new_tmp3, 1,
        min_new_denom);

    sec_new =
        (guint64) ((framecount - (ff_minutes * min_new) -
            dropframe_multiplier * ((gint) (min_new / 10)) -
            (ff_hours * h_notmod24)) / ff_nom);

    frames_new =
        framecount - (ff_nom * sec_new) - (ff_minutes * min_new) -
        (dropframe_multiplier * ((gint) (min_new / 10))) -
        (ff_hours * h_notmod24);
  } else {
    framecount =
        frames + tc->frames + (ff_nom * (tc->seconds + (sixty * (tc->minutes +
                    (sixty * tc->hours)))));
    h_notmod24 =
        gst_util_uint64_scale_int (framecount, 1, ff_nom * sixty * sixty);
    min_new =
        gst_util_uint64_scale_int ((framecount -
            (ff_nom * sixty * sixty * h_notmod24)), 1, (ff_nom * sixty));
    sec_new =
        gst_util_uint64_scale_int ((framecount - (ff_nom * sixty * (min_new +
                    (sixty * h_notmod24)))), 1, ff_nom);
    frames_new =
        framecount - (ff_nom * (sec_new + sixty * (min_new +
                (sixty * h_notmod24))));
    if (frames_new > ff_nom)
      frames_new = 0;
  }
  h_new = h_notmod24 % 24;

  g_assert (min_new < 60);
  g_assert (sec_new < 60);
  g_assert (frames_new < ff_nom);
  tc->hours = h_new;
  tc->minutes = min_new;
  tc->seconds = sec_new;
  tc->frames = frames_new;
}
Beispiel #10
0
static void
deserialize_exif_gps_direction (GstTagList * taglist, const gchar * gst_tag,
    const gchar * xmp_tag, const gchar * str, GSList ** pending_tags,
    const gchar * direction_tag, const gchar * directionref_tag)
{
  const gchar *dir_str = NULL;
  const gchar *dirref_str = NULL;
  gint frac_n;
  gint frac_d;
  gdouble value;

  GSList *entry;
  PendingXmpTag *ptag = NULL;

  /* find the other missing part */
  if (strcmp (xmp_tag, direction_tag) == 0) {
    dir_str = str;

    for (entry = *pending_tags; entry; entry = g_slist_next (entry)) {
      ptag = (PendingXmpTag *) entry->data;

      if (strcmp (ptag->xmp_tag->tag_name, directionref_tag) == 0) {
        dirref_str = ptag->str;
        break;
      }
    }

  } else if (strcmp (xmp_tag, directionref_tag) == 0) {
    dirref_str = str;

    for (entry = *pending_tags; entry; entry = g_slist_next (entry)) {
      ptag = (PendingXmpTag *) entry->data;

      if (strcmp (ptag->xmp_tag->tag_name, direction_tag) == 0) {
        dir_str = ptag->str;
        break;
      }
    }

  } else {
    GST_WARNING ("Unexpected xmp tag %s", xmp_tag);
    return;
  }

  if (!dir_str) {
    GST_WARNING ("Missing %s tag", dir_str);
    return;
  }
  if (!dirref_str) {
    GST_WARNING ("Missing %s tag", dirref_str);
    return;
  }

  if (sscanf (dir_str, "%d/%d", &frac_n, &frac_d) != 2) {
    GST_WARNING ("Failed to parse fraction: %s", dir_str);
    return;
  }

  gst_util_fraction_to_double (frac_n, frac_d, &value);

  if (dirref_str[0] == 'T') {
    /* nop */
  } else if (dirref_str[0] == 'M') {
    GST_WARNING ("Magnetic direction tags aren't supported yet");
    return;
  } else {
    GST_WARNING ("Unexpected %s value: %s", directionref_tag, dirref_str);
    return;
  }

  /* add to the taglist */
  gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, gst_tag, value, NULL);

  /* clean up entry */
  g_free (ptag->str);
  g_slice_free (PendingXmpTag, ptag);
  *pending_tags = g_slist_delete_link (*pending_tags, entry);
}
Beispiel #11
0
static void
deserialize_exif_gps_speed (GstTagList * taglist, const gchar * gst_tag,
    const gchar * xmp_tag, const gchar * str, GSList ** pending_tags)
{
  const gchar *speed_str = NULL;
  const gchar *speedref_str = NULL;
  gint frac_n;
  gint frac_d;
  gdouble value;

  GSList *entry;
  PendingXmpTag *ptag = NULL;

  /* find the other missing part */
  if (strcmp (xmp_tag, "exif:GPSSpeed") == 0) {
    speed_str = str;

    for (entry = *pending_tags; entry; entry = g_slist_next (entry)) {
      ptag = (PendingXmpTag *) entry->data;

      if (strcmp (ptag->xmp_tag->tag_name, "exif:GPSSpeedRef") == 0) {
        speedref_str = ptag->str;
        break;
      }
    }

  } else if (strcmp (xmp_tag, "exif:GPSSpeedRef") == 0) {
    speedref_str = str;

    for (entry = *pending_tags; entry; entry = g_slist_next (entry)) {
      ptag = (PendingXmpTag *) entry->data;

      if (strcmp (ptag->xmp_tag->tag_name, "exif:GPSSpeed") == 0) {
        speed_str = ptag->str;
        break;
      }
    }

  } else {
    GST_WARNING ("Unexpected xmp tag %s", xmp_tag);
    return;
  }

  if (!speed_str) {
    GST_WARNING ("Missing exif:GPSSpeed tag");
    return;
  }
  if (!speedref_str) {
    GST_WARNING ("Missing exif:GPSSpeedRef tag");
    return;
  }

  if (sscanf (speed_str, "%d/%d", &frac_n, &frac_d) != 2) {
    GST_WARNING ("Failed to parse fraction: %s", speed_str);
    return;
  }

  gst_util_fraction_to_double (frac_n, frac_d, &value);

  if (speedref_str[0] == 'K') {
    value *= KILOMETERS_PER_HOUR_TO_METERS_PER_SECOND;
  } else if (speedref_str[0] == 'M') {
    value *= MILES_PER_HOUR_TO_METERS_PER_SECOND;
  } else if (speedref_str[0] == 'N') {
    value *= KNOTS_TO_METERS_PER_SECOND;
  } else {
    GST_WARNING ("Unexpected exif:SpeedRef value: %s", speedref_str);
    return;
  }

  /* add to the taglist */
  gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE,
      GST_TAG_GEO_LOCATION_MOVEMENT_SPEED, value, NULL);

  /* clean up entry */
  g_free (ptag->str);
  g_slice_free (PendingXmpTag, ptag);
  *pending_tags = g_slist_delete_link (*pending_tags, entry);
}
Beispiel #12
0
static void
deserialize_exif_altitude (GstTagList * taglist, const gchar * gst_tag,
    const gchar * xmp_tag, const gchar * str, GSList ** pending_tags)
{
  const gchar *altitude_str = NULL;
  const gchar *altituderef_str = NULL;
  gint frac_n;
  gint frac_d;
  gdouble value;

  GSList *entry;
  PendingXmpTag *ptag = NULL;

  /* find the other missing part */
  if (strcmp (xmp_tag, "exif:GPSAltitude") == 0) {
    altitude_str = str;

    for (entry = *pending_tags; entry; entry = g_slist_next (entry)) {
      ptag = (PendingXmpTag *) entry->data;

      if (strcmp (ptag->xmp_tag->tag_name, "exif:GPSAltitudeRef") == 0) {
        altituderef_str = ptag->str;
        break;
      }
    }

  } else if (strcmp (xmp_tag, "exif:GPSAltitudeRef") == 0) {
    altituderef_str = str;

    for (entry = *pending_tags; entry; entry = g_slist_next (entry)) {
      ptag = (PendingXmpTag *) entry->data;

      if (strcmp (ptag->xmp_tag->tag_name, "exif:GPSAltitude") == 0) {
        altitude_str = ptag->str;
        break;
      }
    }

  } else {
    GST_WARNING ("Unexpected xmp tag %s", xmp_tag);
    return;
  }

  if (!altitude_str) {
    GST_WARNING ("Missing exif:GPSAltitude tag");
    return;
  }
  if (!altituderef_str) {
    GST_WARNING ("Missing exif:GPSAltitudeRef tag");
    return;
  }

  if (sscanf (altitude_str, "%d/%d", &frac_n, &frac_d) != 2) {
    GST_WARNING ("Failed to parse fraction: %s", altitude_str);
    return;
  }

  gst_util_fraction_to_double (frac_n, frac_d, &value);

  if (altituderef_str[0] == '0') {
    /* nop */
  } else if (altituderef_str[0] == '1') {
    value *= -1;
  } else {
    GST_WARNING ("Unexpected exif:AltitudeRef value: %s", altituderef_str);
    return;
  }

  /* add to the taglist */
  gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE,
      GST_TAG_GEO_LOCATION_ELEVATION, value, NULL);

  /* clean up entry */
  g_free (ptag->str);
  g_slice_free (PendingXmpTag, ptag);
  *pending_tags = g_slist_delete_link (*pending_tags, entry);
}