Example #1
0
static inline gboolean
gst_jpeg_parse_remove_marker (GstJpegParse * parse,
    GstByteReader * reader, guint8 marker, GstBuffer * buffer)
{
  guint16 size = 0;
  guint pos = gst_byte_reader_get_pos (reader);
  guint8 *data;
  gsize bsize;

  if (!gst_byte_reader_peek_uint16_be (reader, &size))
    return FALSE;
  if (gst_byte_reader_get_remaining (reader) < size)
    return FALSE;

  GST_LOG_OBJECT (parse, "unhandled marker %x removing %u bytes", marker, size);

  data = gst_buffer_map (buffer, &bsize, NULL, GST_MAP_READWRITE);
  memmove (&data[pos], &data[pos + size], bsize - (pos + size));
  gst_buffer_unmap (buffer, data, bsize - size);

  if (!gst_byte_reader_set_pos (reader, pos - size))
    return FALSE;

  return TRUE;
}
Example #2
0
static guint
find_psc (GstBuffer * buffer, guint skip)
{
  GstByteReader br;
  guint psc_pos = -1, psc;

  gst_byte_reader_init_from_buffer (&br, buffer);

  if (!gst_byte_reader_set_pos (&br, skip))
    goto out;

  gst_byte_reader_peek_uint24_be (&br, &psc);

  /* Scan for the picture start code (22 bits - 0x0020) */
  while ((gst_byte_reader_get_remaining (&br) >= 3)) {
    if (gst_byte_reader_peek_uint24_be (&br, &psc) &&
        ((psc & 0xffffc0) == 0x000080)) {
      psc_pos = gst_byte_reader_get_pos (&br);
      break;
    } else
      gst_byte_reader_skip (&br, 1);
  }

out:
  return psc_pos;
}
Example #3
0
static GstBuffer *
gst_vdp_mpeg_packetizer_get_next_packet (GstVdpMpegPacketizer * packetizer)
{
    guint offset, size;
    GstBuffer *buf;

    if (packetizer->start == -1)
        return NULL;

    if (!gst_byte_reader_set_pos (&packetizer->reader, packetizer->start + 3))
        return NULL;

    offset = gst_byte_reader_masked_scan_uint32 (&packetizer->reader, 0xffffff00,
             0x00000100, 0, gst_byte_reader_get_remaining (&packetizer->reader));

    if (offset != -1) {
        offset = gst_byte_reader_get_pos (&packetizer->reader) + offset;
        size = offset - packetizer->start;
    } else
        size = gst_byte_reader_get_remaining (&packetizer->reader) + 3;

    buf = gst_buffer_create_sub (packetizer->buffer, packetizer->start, size);

    packetizer->start = offset;

    return buf;
}
Example #4
0
static guint
find_psc (GstBuffer * buffer, guint skip)
{
  GstMapInfo map;
  GstByteReader br;
  guint psc_pos = -1, psc;

  gst_buffer_map (buffer, &map, GST_MAP_READ);
  gst_byte_reader_init (&br, map.data, map.size);

  if (!gst_byte_reader_set_pos (&br, skip))
    goto out;

  if (gst_byte_reader_peek_uint24_be (&br, &psc) == FALSE)
    goto out;

  /* Scan for the picture start code (22 bits - 0x0020) */
  while ((gst_byte_reader_get_remaining (&br) >= 3)) {
    if (gst_byte_reader_peek_uint24_be (&br, &psc) &&
        ((psc & 0xffffc0) == 0x000080)) {
      psc_pos = gst_byte_reader_get_pos (&br);
      break;
    } else if (gst_byte_reader_skip (&br, 1) == FALSE)
      break;
  }

out:
  gst_buffer_unmap (buffer, &map);
  return psc_pos;
}
Example #5
0
GstIsoffParserResult
gst_isoff_sidx_parser_add_buffer (GstSidxParser * parser, GstBuffer * buffer,
    guint * consumed)
{
  GstIsoffParserResult res = GST_ISOFF_PARSER_OK;
  GstByteReader reader;
  GstMapInfo info;
  guint32 fourcc;

  if (!gst_buffer_map (buffer, &info, GST_MAP_READ)) {
    *consumed = 0;
    return GST_ISOFF_PARSER_ERROR;
  }

  gst_byte_reader_init (&reader, info.data, info.size);

  if (parser->status == GST_ISOFF_SIDX_PARSER_INIT) {
    if (!gst_isoff_parse_box_header (&reader, &fourcc, NULL, NULL,
            &parser->size))
      goto done;

    if (fourcc != GST_ISOFF_FOURCC_SIDX) {
      res = GST_ISOFF_PARSER_UNEXPECTED;
      gst_byte_reader_set_pos (&reader, 0);
      goto done;
    }

    if (parser->size == 0) {
      res = GST_ISOFF_PARSER_ERROR;
      gst_byte_reader_set_pos (&reader, 0);
      goto done;
    }

    /* Try again once we have enough data for the FullBox header */
    if (gst_byte_reader_get_remaining (&reader) < 4) {
      gst_byte_reader_set_pos (&reader, 0);
      goto done;
    }
  }

  res = gst_isoff_sidx_parser_parse (parser, &reader, consumed);

done:
  gst_buffer_unmap (buffer, &info);
  return res;
}
Example #6
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?)");
}
Example #7
0
/* gst_isoff_parse_box:
 * @reader:
 * @type: type that was found at the current position
 * @extended_type: (allow-none): extended type if type=='uuid'
 * @header_size: (allow-none): size of the box header (type, extended type and size)
 * @size: size of the complete box including type, extended type and size
 *
 * Advances the byte reader to the start of the box content. To skip
 * over the complete box, skip size - header_size bytes.
 *
 * Returns: TRUE if a box header could be parsed, FALSE if more data is needed
 */
gboolean
gst_isoff_parse_box_header (GstByteReader * reader, guint32 * type,
    guint8 extended_type[16], guint * header_size, guint64 * size)
{
  guint header_start_offset;
  guint32 size_field;

  header_start_offset = gst_byte_reader_get_pos (reader);

  if (gst_byte_reader_get_remaining (reader) < 8)
    goto not_enough_data;

  size_field = gst_byte_reader_get_uint32_be_unchecked (reader);
  *type = gst_byte_reader_get_uint32_le_unchecked (reader);

  if (size_field == 1) {
    if (gst_byte_reader_get_remaining (reader) < 8)
      goto not_enough_data;
    *size = gst_byte_reader_get_uint64_be_unchecked (reader);
  } else {
    *size = size_field;
  }

  if (*type == GST_ISOFF_FOURCC_UUID) {
    if (gst_byte_reader_get_remaining (reader) < 16)
      goto not_enough_data;

    if (extended_type)
      memcpy (extended_type, gst_byte_reader_get_data_unchecked (reader, 16),
          16);
  }

  if (header_size)
    *header_size = gst_byte_reader_get_pos (reader) - header_start_offset;

  return TRUE;

not_enough_data:
  gst_byte_reader_set_pos (reader, header_start_offset);
  return FALSE;
}
Example #8
0
static inline gboolean
gst_jpeg_parse_remove_marker (GstJpegParse * parse,
    GstByteReader * reader, guint8 marker, GstBuffer * buffer)
{
  guint16 size = 0;
  guint pos = gst_byte_reader_get_pos (reader);
  guint8 *data = GST_BUFFER_DATA (buffer);

  if (!gst_byte_reader_peek_uint16_be (reader, &size))
    return FALSE;
  if (gst_byte_reader_get_remaining (reader) < size)
    return FALSE;

  GST_LOG_OBJECT (parse, "unhandled marker %x removing %u bytes", marker, size);

  memmove (&data[pos], &data[pos + size],
      GST_BUFFER_SIZE (buffer) - (pos + size));
  GST_BUFFER_SIZE (buffer) -= size;

  if (!gst_byte_reader_set_pos (reader, pos - size))
    return FALSE;

  return TRUE;
}
Example #9
0
static gboolean
parse_exif_ifd (GstExifReader * exif_reader, gint buf_offset,
    const GstExifTagMatch * tag_map)
{
  GstByteReader reader;
  guint16 entries = 0;
  guint16 i;

  g_return_val_if_fail (exif_reader->byte_order == G_LITTLE_ENDIAN
      || exif_reader->byte_order == G_BIG_ENDIAN, FALSE);

  gst_byte_reader_init_from_buffer (&reader, exif_reader->buffer);
  if (!gst_byte_reader_set_pos (&reader, buf_offset)) {
    GST_WARNING ("Buffer offset invalid when parsing exif ifd");
    return FALSE;
  }

  /* read the IFD entries number */
  if (exif_reader->byte_order == G_LITTLE_ENDIAN) {
    if (!gst_byte_reader_get_uint16_le (&reader, &entries))
      goto read_error;
  } else {
    if (!gst_byte_reader_get_uint16_be (&reader, &entries))
      goto read_error;
  }
  GST_DEBUG ("Read number of entries: %u", entries);

  /* iterate over the buffer and find the tags and stuff */
  for (i = 0; i < entries; i++) {
    GstExifTagData tagdata;
    gint map_index;

    GST_LOG ("Reading entry: %u", i);

    if (!parse_exif_tag_header (&reader, exif_reader->byte_order, &tagdata))
      goto read_error;

    GST_DEBUG ("Parsed tag: id 0x%x, type %u, count %u, offset %u (0x%x)",
        tagdata.tag, tagdata.tag_type, tagdata.count, tagdata.offset,
        tagdata.offset);

    map_index = exif_tag_map_find_reverse (tagdata.tag, tag_map, TRUE);
    if (map_index == -1) {
      GST_WARNING ("Unmapped exif tag: 0x%x", tagdata.tag);
      continue;
    }

    /* inner ifd tags handling */
    if (tagdata.tag == EXIF_GPS_IFD_TAG) {
      i += parse_exif_ifd (exif_reader,
          tagdata.offset - exif_reader->base_offset, tag_map_gps);

      continue;
    }

    /* tags that need specialized deserialization */
    if (tag_map[map_index].deserialize) {
      i += tag_map[map_index].deserialize (exif_reader, &reader,
          &tag_map[map_index], &tagdata);
      continue;
    }

    switch (tagdata.tag_type) {
      case EXIF_TYPE_ASCII:
        parse_exif_ascii_tag (exif_reader, tag_map[map_index].gst_tag,
            tagdata.count, tagdata.offset, tagdata.offset_as_data);
        break;
      case EXIF_TYPE_RATIONAL:
        parse_exif_rational_tag (exif_reader, tag_map[map_index].gst_tag,
            tagdata.count, tagdata.offset, 1);
        break;
      default:
        GST_WARNING ("Unhandled tag type: %u", tagdata.tag_type);
        break;
    }
  }

  return TRUE;

read_error:
  {
    GST_WARNING ("Failed to parse the exif ifd");
    return FALSE;
  }
}
Example #10
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;
}
Example #11
0
GstIsoffParserResult
gst_isoff_sidx_parser_parse (GstSidxParser * parser,
    GstByteReader * reader, guint * consumed)
{
  GstIsoffParserResult res = GST_ISOFF_PARSER_OK;
  gsize remaining;

  switch (parser->status) {
    case GST_ISOFF_SIDX_PARSER_INIT:
      /* Try again once we have enough data for the FullBox header */
      if (gst_byte_reader_get_remaining (reader) < 4) {
        gst_byte_reader_set_pos (reader, 0);
        break;
      }
      parser->sidx.version = gst_byte_reader_get_uint8_unchecked (reader);
      parser->sidx.flags = gst_byte_reader_get_uint24_le_unchecked (reader);

      parser->status = GST_ISOFF_SIDX_PARSER_HEADER;

    case GST_ISOFF_SIDX_PARSER_HEADER:
      remaining = gst_byte_reader_get_remaining (reader);
      if (remaining < 12 + (parser->sidx.version == 0 ? 8 : 16)) {
        break;
      }

      parser->sidx.ref_id = gst_byte_reader_get_uint32_be_unchecked (reader);
      parser->sidx.timescale = gst_byte_reader_get_uint32_be_unchecked (reader);
      if (parser->sidx.version == 0) {
        parser->sidx.earliest_pts =
            gst_byte_reader_get_uint32_be_unchecked (reader);
        parser->sidx.first_offset =
            gst_byte_reader_get_uint32_be_unchecked (reader);
      } else {
        parser->sidx.earliest_pts =
            gst_byte_reader_get_uint64_be_unchecked (reader);
        parser->sidx.first_offset =
            gst_byte_reader_get_uint64_be_unchecked (reader);
      }
      /* skip 2 reserved bytes */
      gst_byte_reader_skip_unchecked (reader, 2);
      parser->sidx.entries_count =
          gst_byte_reader_get_uint16_be_unchecked (reader);

      GST_LOG ("Timescale: %" G_GUINT32_FORMAT, parser->sidx.timescale);
      GST_LOG ("Earliest pts: %" G_GUINT64_FORMAT, parser->sidx.earliest_pts);
      GST_LOG ("First offset: %" G_GUINT64_FORMAT, parser->sidx.first_offset);

      parser->cumulative_pts =
          gst_util_uint64_scale_int_round (parser->sidx.earliest_pts,
          GST_SECOND, parser->sidx.timescale);

      if (parser->sidx.entries_count) {
        parser->sidx.entries =
            g_malloc (sizeof (GstSidxBoxEntry) * parser->sidx.entries_count);
      }
      parser->sidx.entry_index = 0;

      parser->status = GST_ISOFF_SIDX_PARSER_DATA;

    case GST_ISOFF_SIDX_PARSER_DATA:
      while (parser->sidx.entry_index < parser->sidx.entries_count) {
        GstSidxBoxEntry *entry =
            &parser->sidx.entries[parser->sidx.entry_index];

        remaining = gst_byte_reader_get_remaining (reader);
        if (remaining < 12)
          break;

        entry->offset = parser->cumulative_entry_size;
        entry->pts = parser->cumulative_pts;
        gst_isoff_parse_sidx_entry (entry, reader);
        entry->duration = gst_util_uint64_scale_int_round (entry->duration,
            GST_SECOND, parser->sidx.timescale);
        parser->cumulative_entry_size += entry->size;
        parser->cumulative_pts += entry->duration;

        GST_LOG ("Sidx entry %d) offset: %" G_GUINT64_FORMAT ", pts: %"
            GST_TIME_FORMAT ", duration %" GST_TIME_FORMAT " - size %"
            G_GUINT32_FORMAT, parser->sidx.entry_index, entry->offset,
            GST_TIME_ARGS (entry->pts), GST_TIME_ARGS (entry->duration),
            entry->size);

        parser->sidx.entry_index++;
      }

      if (parser->sidx.entry_index == parser->sidx.entries_count)
        parser->status = GST_ISOFF_SIDX_PARSER_FINISHED;
      else
        break;
    case GST_ISOFF_SIDX_PARSER_FINISHED:
      parser->sidx.entry_index = 0;
      res = GST_ISOFF_PARSER_DONE;
      break;
  }

  *consumed = gst_byte_reader_get_pos (reader);

  return res;
}
Example #12
0
GstIsoffParserResult
gst_isoff_sidx_parser_add_buffer (GstSidxParser * parser, GstBuffer * buffer,
    guint * consumed)
{
  GstIsoffParserResult res = GST_ISOFF_PARSER_OK;
  GstByteReader reader;
  GstMapInfo info;
  gsize remaining;
  guint32 fourcc;

  if (!gst_buffer_map (buffer, &info, GST_MAP_READ)) {
    *consumed = 0;
    return GST_ISOFF_PARSER_ERROR;
  }

  gst_byte_reader_init (&reader, info.data, info.size);

  switch (parser->status) {
    case GST_ISOFF_SIDX_PARSER_INIT:
      if (gst_byte_reader_get_remaining (&reader) < GST_ISOFF_FULL_BOX_SIZE) {
        break;
      }

      parser->size = gst_byte_reader_get_uint32_be_unchecked (&reader);
      fourcc = gst_byte_reader_get_uint32_le_unchecked (&reader);
      if (fourcc != GST_ISOFF_FOURCC_SIDX) {
        res = GST_ISOFF_PARSER_UNEXPECTED;
        gst_byte_reader_set_pos (&reader, 0);
        break;
      }
      if (parser->size == 1) {
        if (gst_byte_reader_get_remaining (&reader) < 12) {
          gst_byte_reader_set_pos (&reader, 0);
          break;
        }

        parser->size = gst_byte_reader_get_uint64_be_unchecked (&reader);
      }
      if (parser->size == 0) {
        res = GST_ISOFF_PARSER_ERROR;
        gst_byte_reader_set_pos (&reader, 0);
        break;
      }
      parser->sidx.version = gst_byte_reader_get_uint8_unchecked (&reader);
      parser->sidx.flags = gst_byte_reader_get_uint24_le_unchecked (&reader);

      parser->status = GST_ISOFF_SIDX_PARSER_HEADER;

    case GST_ISOFF_SIDX_PARSER_HEADER:
      remaining = gst_byte_reader_get_remaining (&reader);
      if (remaining < 12 + (parser->sidx.version == 0 ? 8 : 16)) {
        break;
      }

      parser->sidx.ref_id = gst_byte_reader_get_uint32_be_unchecked (&reader);
      parser->sidx.timescale =
          gst_byte_reader_get_uint32_be_unchecked (&reader);
      if (parser->sidx.version == 0) {
        parser->sidx.earliest_pts =
            gst_byte_reader_get_uint32_be_unchecked (&reader);
        parser->sidx.first_offset = parser->sidx.earliest_pts =
            gst_byte_reader_get_uint32_be_unchecked (&reader);
      } else {
        parser->sidx.earliest_pts =
            gst_byte_reader_get_uint64_be_unchecked (&reader);
        parser->sidx.first_offset =
            gst_byte_reader_get_uint64_be_unchecked (&reader);
      }
      /* skip 2 reserved bytes */
      gst_byte_reader_skip_unchecked (&reader, 2);
      parser->sidx.entries_count =
          gst_byte_reader_get_uint16_be_unchecked (&reader);

      GST_LOG ("Timescale: %" G_GUINT32_FORMAT, parser->sidx.timescale);
      GST_LOG ("Earliest pts: %" G_GUINT64_FORMAT, parser->sidx.earliest_pts);
      GST_LOG ("First offset: %" G_GUINT64_FORMAT, parser->sidx.first_offset);

      parser->cumulative_pts =
          gst_util_uint64_scale_int_round (parser->sidx.earliest_pts,
          GST_SECOND, parser->sidx.timescale);

      if (parser->sidx.entries_count) {
        parser->sidx.entries =
            g_malloc (sizeof (GstSidxBoxEntry) * parser->sidx.entries_count);
      }
      parser->sidx.entry_index = 0;

      parser->status = GST_ISOFF_SIDX_PARSER_DATA;

    case GST_ISOFF_SIDX_PARSER_DATA:
      while (parser->sidx.entry_index < parser->sidx.entries_count) {
        GstSidxBoxEntry *entry =
            &parser->sidx.entries[parser->sidx.entry_index];

        remaining = gst_byte_reader_get_remaining (&reader);;
        if (remaining < 12)
          break;

        entry->offset = parser->cumulative_entry_size;
        entry->pts = parser->cumulative_pts;
        gst_isoff_parse_sidx_entry (entry, &reader);
        entry->duration = gst_util_uint64_scale_int_round (entry->duration,
            GST_SECOND, parser->sidx.timescale);
        parser->cumulative_entry_size += entry->size;
        parser->cumulative_pts += entry->duration;

        GST_LOG ("Sidx entry %d) offset: %" G_GUINT64_FORMAT ", pts: %"
            GST_TIME_FORMAT ", duration %" GST_TIME_FORMAT " - size %"
            G_GUINT32_FORMAT, parser->sidx.entry_index, entry->offset,
            GST_TIME_ARGS (entry->pts), GST_TIME_ARGS (entry->duration),
            entry->size);

        parser->sidx.entry_index++;
      }

      if (parser->sidx.entry_index == parser->sidx.entries_count)
        parser->status = GST_ISOFF_SIDX_PARSER_FINISHED;
      else
        break;
    case GST_ISOFF_SIDX_PARSER_FINISHED:
      parser->sidx.entry_index = 0;
      res = GST_ISOFF_PARSER_DONE;
      break;
  }

  *consumed = gst_byte_reader_get_pos (&reader);
  gst_buffer_unmap (buffer, &info);
  return res;
}