Пример #1
0
static gboolean
parse_exif_tag_header (GstByteReader * reader, gint byte_order,
    GstExifTagData * _tagdata)
{
  g_assert (_tagdata);

  /* read the fields */
  if (byte_order == G_LITTLE_ENDIAN) {
    if (!gst_byte_reader_get_uint16_le (reader, &_tagdata->tag) ||
        !gst_byte_reader_get_uint16_le (reader, &_tagdata->tag_type) ||
        !gst_byte_reader_get_uint32_le (reader, &_tagdata->count) ||
        !gst_byte_reader_get_data (reader, 4, &_tagdata->offset_as_data)) {
      return FALSE;
    }
    _tagdata->offset = GST_READ_UINT32_LE (_tagdata->offset_as_data);
  } else {
    if (!gst_byte_reader_get_uint16_be (reader, &_tagdata->tag) ||
        !gst_byte_reader_get_uint16_be (reader, &_tagdata->tag_type) ||
        !gst_byte_reader_get_uint32_be (reader, &_tagdata->count) ||
        !gst_byte_reader_get_data (reader, 4, &_tagdata->offset_as_data)) {
      return FALSE;
    }
    _tagdata->offset = GST_READ_UINT32_BE (_tagdata->offset_as_data);
  }

  return TRUE;
}
Пример #2
0
/**
 * gst_tag_list_from_exif_buffer_with_tiff_header:
 * @buffer: The exif buffer
 *
 * Parses the exif tags starting with a tiff header structure.
 *
 * Returns: The taglist
 *
 * Since: 0.10.30
 */
GstTagList *
gst_tag_list_from_exif_buffer_with_tiff_header (const GstBuffer * buffer)
{
  GstByteReader reader;
  guint16 fortytwo = 42;
  guint16 endianness = 0;
  guint32 offset;
  GstTagList *taglist = NULL;
  GstBuffer *subbuffer;

  GST_LOG ("Parsing exif tags with tiff header of size %u",
      GST_BUFFER_SIZE (buffer));

  gst_byte_reader_init_from_buffer (&reader, buffer);

  GST_LOG ("Parsing the tiff header");
  if (!gst_byte_reader_get_uint16_be (&reader, &endianness)) {
    goto byte_reader_fail;
  }

  if (endianness == TIFF_LITTLE_ENDIAN) {
    if (!gst_byte_reader_get_uint16_le (&reader, &fortytwo) ||
        !gst_byte_reader_get_uint32_le (&reader, &offset))
      goto byte_reader_fail;
  } else if (endianness == TIFF_BIG_ENDIAN) {
    if (!gst_byte_reader_get_uint16_be (&reader, &fortytwo) ||
        !gst_byte_reader_get_uint32_be (&reader, &offset))
      goto byte_reader_fail;
  } else {
    GST_WARNING ("Invalid endianness number %u", endianness);
    return NULL;
  }

  if (fortytwo != 42) {
    GST_WARNING ("Invalid magic number %u, should be 42", fortytwo);
    return NULL;
  }

  subbuffer = gst_buffer_new_and_alloc (GST_BUFFER_SIZE (buffer) -
      (TIFF_HEADER_SIZE - 2));
  memcpy (GST_BUFFER_DATA (subbuffer),
      GST_BUFFER_DATA (buffer) + TIFF_HEADER_SIZE,
      GST_BUFFER_SIZE (buffer) - TIFF_HEADER_SIZE);

  taglist = gst_tag_list_from_exif_buffer (subbuffer,
      endianness == TIFF_LITTLE_ENDIAN ? G_LITTLE_ENDIAN : G_BIG_ENDIAN, 8);

  gst_buffer_unref (subbuffer);
  return taglist;

byte_reader_fail:
  {
    GST_WARNING ("Failed to read values from buffer");
    return NULL;
  }
}
Пример #3
0
static inline gboolean
gst_jpeg_parse_skip_marker (GstJpegParse * parse,
    GstByteReader * reader, guint8 marker)
{
  guint16 size = 0;

  if (!gst_byte_reader_get_uint16_be (reader, &size))
    return FALSE;

#ifndef GST_DISABLE_DEBUG
  /* We'd pry the id of the skipped application segment */
  if (marker >= APP0 && marker <= APP15) {
    const gchar *id_str = NULL;

    if (gst_byte_reader_peek_string_utf8 (reader, &id_str)) {
      GST_DEBUG_OBJECT (parse, "unhandled marker %x: '%s' skiping %u bytes",
          marker, id_str ? id_str : "(NULL)", size);
    } else {
      GST_DEBUG_OBJECT (parse, "unhandled marker %x skiping %u bytes", marker,
          size);
    }
  }
#else
  GST_DEBUG_OBJECT (parse, "unhandled marker %x skiping %u bytes", marker,
      size);
#endif // GST_DISABLE_DEBUG

  if (!gst_byte_reader_skip (reader, size - 2))
    return FALSE;

  return TRUE;
}
Пример #4
0
/* read comment and post as tag */
static inline gboolean
gst_jpeg_parse_com (GstJpegParse * parse, GstByteReader * reader)
{
  const guint8 *data = NULL;
  guint16 size = 0;
  gchar *comment;

  if (!gst_byte_reader_get_uint16_be (reader, &size))
    return FALSE;

  size -= 2;
  if (!gst_byte_reader_get_data (reader, size, &data))
    return FALSE;

  comment = get_utf8_from_data (data, size);

  if (comment) {
    GstTagList *taglist = get_tag_list (parse);
    gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE,
        GST_TAG_COMMENT, comment, NULL);
    GST_DEBUG_OBJECT (parse, "collected tags: %" GST_PTR_FORMAT, taglist);
    g_free (comment);
  }

  return TRUE;
}
Пример #5
0
static inline gboolean
gst_jpeg_parse_app1 (GstJpegParse * parse, GstByteReader * reader)
{
  guint16 size = 0;
  const gchar *id_str;
  const guint8 *data = NULL;

  if (!gst_byte_reader_get_uint16_be (reader, &size))
    return FALSE;

  size -= 2;                    /* 2 bytes for the mark */
  if (!gst_byte_reader_peek_string_utf8 (reader, &id_str))
    return FALSE;

  if (!strncmp (id_str, "Exif", 4)) {

    /* skip id + NUL + padding */
    if (!gst_byte_reader_skip (reader, 6))
      return FALSE;
    size -= 6;

    /* handle exif metadata */
    if (!gst_byte_reader_get_data (reader, size, &data))
      return FALSE;

    extract_and_queue_tags (parse, size, (guint8 *) data,
        gst_tag_list_from_exif_buffer_with_tiff_header);

    GST_LOG_OBJECT (parse, "parsed marker %x: '%s' %u bytes",
        APP1, id_str, size);

  } else if (!strncmp (id_str, "http://ns.adobe.com/xap/1.0/", 28)) {

    /* skip the id + NUL */
    if (!gst_byte_reader_skip (reader, 29))
      return FALSE;
    size -= 29;

    /* handle xmp metadata */
    if (!gst_byte_reader_get_data (reader, size, &data))
      return FALSE;

    extract_and_queue_tags (parse, size, (guint8 *) data,
        gst_tag_list_from_xmp_buffer);

    GST_LOG_OBJECT (parse, "parsed marker %x: '%s' %u bytes",
        APP1, id_str, size);

  } else {
    if (!gst_jpeg_parse_skip_marker (parse, reader, APP1))
      return FALSE;
  }

  return TRUE;
}
Пример #6
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;
  }
}
Пример #7
0
static void
gst_exif_tag_rewrite_offsets (GstExifWriter * writer, guint32 base_offset)
{
  guint32 offset;

  GST_LOG ("Rewriting tag entries offsets");

  offset = gst_byte_writer_get_size (&writer->tagwriter);
  while (gst_byte_writer_get_pos (&writer->tagwriter) <
      gst_byte_writer_get_size (&writer->tagwriter)) {
    guint16 type = 0;
    guint32 cur_offset = 0;
    GstByteReader *reader;
    gint byte_size = 0;
    guint32 count = 0;
    guint16 tag_id = 0;

    reader = (GstByteReader *) & writer->tagwriter;

    /* read the type */
    if (writer->byte_order == G_LITTLE_ENDIAN) {
      if (!gst_byte_reader_get_uint16_le (reader, &tag_id))
        break;
      if (!gst_byte_reader_get_uint16_le (reader, &type))
        break;
      if (!gst_byte_reader_get_uint32_le (reader, &count))
        break;
    } else {
      if (!gst_byte_reader_get_uint16_be (reader, &tag_id))
        break;
      if (!gst_byte_reader_get_uint16_be (reader, &type))
        break;
      if (!gst_byte_reader_get_uint32_be (reader, &count))
        break;
    }

    switch (type) {
      case EXIF_TYPE_BYTE:
      case EXIF_TYPE_ASCII:
      case EXIF_TYPE_UNDEFINED:
        byte_size = count;
        break;
      case EXIF_TYPE_SHORT:
        byte_size = count * 2;  /* 2 bytes */
        break;
      case EXIF_TYPE_LONG:
      case EXIF_TYPE_SLONG:
        byte_size = count * 4;  /* 4 bytes */
        break;
      case EXIF_TYPE_RATIONAL:
      case EXIF_TYPE_SRATIONAL:
        byte_size = count * 8;  /* 8 bytes */
        break;
      default:
        g_assert_not_reached ();
        break;
    }

    /* adjust the offset if needed */
    if (byte_size > 4 || tag_id == EXIF_GPS_IFD_TAG) {
      if (writer->byte_order == G_LITTLE_ENDIAN) {
        if (gst_byte_reader_peek_uint32_le (reader, &cur_offset)) {
          gst_byte_writer_put_uint32_le (&writer->tagwriter,
              cur_offset + offset + base_offset);
        }
      } else {
        if (gst_byte_reader_peek_uint32_be (reader, &cur_offset)) {
          gst_byte_writer_put_uint32_be (&writer->tagwriter,
              cur_offset + offset + base_offset);
        }
      }
      GST_DEBUG ("Rewriting tag offset from %u to (%u + %u + %u) %u",
          cur_offset, cur_offset, offset, base_offset,
          cur_offset + offset + base_offset);
    } else {
      gst_byte_reader_skip (reader, 4);
      GST_DEBUG ("No need to rewrite tag offset");
    }
  }
}
static gboolean webKitMediaClearKeyDecryptorDecrypt(WebKitMediaCommonEncryptionDecrypt* self, GstBuffer* ivBuffer, GstBuffer* buffer, unsigned subSampleCount, GstBuffer* subSamplesBuffer)
{
    GstMapInfo ivMap;
    if (!gst_buffer_map(ivBuffer, &ivMap, GST_MAP_READ)) {
        GST_ERROR_OBJECT(self, "Failed to map IV");
        return false;
    }

    uint8_t ctr[CLEARKEY_SIZE];
    if (ivMap.size == 8) {
        memset(ctr + 8, 0, 8);
        memcpy(ctr, ivMap.data, 8);
    } else {
        ASSERT(ivMap.size == CLEARKEY_SIZE);
        memcpy(ctr, ivMap.data, CLEARKEY_SIZE);
    }
    gst_buffer_unmap(ivBuffer, &ivMap);

    WebKitMediaClearKeyDecryptPrivate* priv = WEBKIT_MEDIA_CK_DECRYPT_GET_PRIVATE(WEBKIT_MEDIA_CK_DECRYPT(self));
    gcry_error_t error = gcry_cipher_setctr(priv->handle, ctr, CLEARKEY_SIZE);
    if (error) {
        GST_ERROR_OBJECT(self, "gcry_cipher_setctr failed: %s", gpg_strerror(error));
        return false;
    }

    GstMapInfo map;
    gboolean bufferMapped = gst_buffer_map(buffer, &map, static_cast<GstMapFlags>(GST_MAP_READWRITE));
    if (!bufferMapped) {
        GST_ERROR_OBJECT(self, "Failed to map buffer");
        return false;
    }

    GstMapInfo subSamplesMap;
    gboolean subsamplesBufferMapped = gst_buffer_map(subSamplesBuffer, &subSamplesMap, GST_MAP_READ);
    if (!subsamplesBufferMapped) {
        GST_ERROR_OBJECT(self, "Failed to map subsample buffer");
        gst_buffer_unmap(buffer, &map);
        return false;
    }

    GstByteReader* reader = gst_byte_reader_new(subSamplesMap.data, subSamplesMap.size);
    unsigned position = 0;
    unsigned sampleIndex = 0;

    GST_DEBUG_OBJECT(self, "position: %d, size: %zu", position, map.size);

    while (position < map.size) {
        guint16 nBytesClear = 0;
        guint32 nBytesEncrypted = 0;

        if (sampleIndex < subSampleCount) {
            if (!gst_byte_reader_get_uint16_be(reader, &nBytesClear)
                || !gst_byte_reader_get_uint32_be(reader, &nBytesEncrypted)) {
                GST_DEBUG_OBJECT(self, "unsupported");
                gst_byte_reader_free(reader);
                gst_buffer_unmap(buffer, &map);
                gst_buffer_unmap(subSamplesBuffer, &subSamplesMap);
                return false;
            }

            sampleIndex++;
        } else {
            nBytesClear = 0;
            nBytesEncrypted = map.size - position;
        }

        GST_TRACE_OBJECT(self, "%d bytes clear (todo=%zu)", nBytesClear, map.size - position);
        position += nBytesClear;
        if (nBytesEncrypted) {
            GST_TRACE_OBJECT(self, "%d bytes encrypted (todo=%zu)", nBytesEncrypted, map.size - position);
            error = gcry_cipher_decrypt(priv->handle, map.data + position, nBytesEncrypted, 0, 0);
            if (error) {
                GST_ERROR_OBJECT(self, "decryption failed: %s", gpg_strerror(error));
                gst_byte_reader_free(reader);
                gst_buffer_unmap(buffer, &map);
                gst_buffer_unmap(subSamplesBuffer, &subSamplesMap);
                return false;
            }
            position += nBytesEncrypted;
        }
    }

    gst_byte_reader_free(reader);
    gst_buffer_unmap(buffer, &map);
    gst_buffer_unmap(subSamplesBuffer, &subSamplesMap);
    return true;
}
Пример #9
0
/* Ideas from gstjpegparse.c */
GstTagList *
gst_droidcamsrc_exif_tags_from_jpeg_data (void *data, size_t size)
{
  GstByteReader reader;
  guint16 len = 0;
  const gchar *id;
  const guint8 *exif = NULL;
  GstBuffer *buff;
  GstTagList *tags = NULL;

  void *app1 = memmem (data, size, marker, 2);
  if (!app1) {
    GST_ERROR ("No tags found");
    goto out;
  }

  size -= (app1 - data);

  gst_byte_reader_init (&reader, app1, size);

  if (!gst_byte_reader_skip (&reader, 2)) {
    GST_ERROR ("Not enough jpeg data for tags");
    goto out;
  }

  if (!gst_byte_reader_get_uint16_be (&reader, &len)) {
    GST_ERROR ("Failed to get APP1 size");
    goto out;
  }

  len -= 2;                     /* for the marker itself */

  if (!gst_byte_reader_peek_string_utf8 (&reader, &id)) {
    goto out;
  }

  if (!strncmp (id, "Exif", 4)) {
    /* id + NUL + padding */
    if (!gst_byte_reader_skip (&reader, 6)) {
      goto out;
    }

    len -= 6;

    if (!gst_byte_reader_get_data (&reader, len, &exif)) {
      goto out;
    }

    buff =
        gst_buffer_new_wrapped_full (GST_MEMORY_FLAG_READONLY, (gpointer) exif,
        len, 0, len, NULL, NULL);

    tags = gst_tag_list_from_exif_buffer_with_tiff_header (buff);
    gst_buffer_unref (buff);

    return tags;
  }

out:
  return NULL;
}
Пример #10
0
static inline gboolean
gst_jpeg_parse_sof (GstJpegParse * parse, GstByteReader * reader)
{
  guint8 numcomps = 0;          /* Number of components in image
                                   (1 for gray, 3 for YUV, etc.) */
  guint8 precision;             /* precision (in bits) for the samples */
  guint8 compId[3];             /* unique value identifying each component */
  guint8 qtId[3];               /* quantization table ID to use for this comp */
  guint8 blockWidth[3];         /* Array[numComponents] giving the number of
                                   blocks (horiz) in this component */
  guint8 blockHeight[3];        /* Same for the vertical part of this component */
  guint8 i, value = 0;
  gint temp;

  /* flush length field */
  if (!gst_byte_reader_skip (reader, 2))
    return FALSE;

  /* Get sample precision */
  if (!gst_byte_reader_get_uint8 (reader, &precision))
    return FALSE;

  /* Get w and h */
  if (!gst_byte_reader_get_uint16_be (reader, &parse->priv->height))
    return FALSE;
  if (!gst_byte_reader_get_uint16_be (reader, &parse->priv->width))
    return FALSE;

  /* Get number of components */
  if (!gst_byte_reader_get_uint8 (reader, &numcomps))
    return FALSE;

  if (numcomps > 3)
    return FALSE;

  /* Get decimation and quantization table id for each component */
  for (i = 0; i < numcomps; i++) {
    /* Get component ID number */
    if (!gst_byte_reader_get_uint8 (reader, &value))
      return FALSE;
    compId[i] = value;

    /* Get decimation */
    if (!gst_byte_reader_get_uint8 (reader, &value))
      return FALSE;
    blockWidth[i] = (value & 0xf0) >> 4;
    blockHeight[i] = (value & 0x0f);

    /* Get quantization table id */
    if (!gst_byte_reader_get_uint8 (reader, &value))
      return FALSE;
    qtId[i] = value;
  }

  if (numcomps == 1) {
    /* gray image - no fourcc */
    parse->priv->fourcc = 0;
  } else if (numcomps == 3) {
    temp = (blockWidth[0] * blockHeight[0]) / (blockWidth[1] * blockHeight[1]);

    if (temp == 4 && blockHeight[0] == 2)
      parse->priv->fourcc = GST_MAKE_FOURCC ('I', '4', '2', '0');
    else if (temp == 4 && blockHeight[0] == 4)
      parse->priv->fourcc = GST_MAKE_FOURCC ('Y', '4', '1', 'B');
    else if (temp == 2)
      parse->priv->fourcc = GST_MAKE_FOURCC ('U', 'Y', 'V', 'Y');
    else if (temp == 1)
      parse->priv->fourcc = GST_MAKE_FOURCC ('Y', 'V', '1', '2');
    else
      parse->priv->fourcc = 0;
  } else {
    return FALSE;
  }

  GST_DEBUG_OBJECT (parse, "Header parsed");

  return TRUE;
}
static GstFlowReturn webkitMediaPlayReadyDecryptTransformInPlace(GstBaseTransform* base, GstBuffer* buffer)
{
    WebKitMediaPlayReadyDecrypt* self = WEBKIT_MEDIA_PLAYREADY_DECRYPT(base);
    GstFlowReturn result = GST_FLOW_OK;
    GstMapInfo map;
    const GValue* value;
    guint sampleIndex = 0;
    int errorCode;
    uint32_t trackID = 0;
    GstPad* pad;
    GstCaps* caps;
    GstMapInfo boxMap;
    GstBuffer* box = nullptr;
    GstProtectionMeta* protectionMeta = 0;
    gboolean boxMapped = FALSE;
    gboolean bufferMapped = FALSE;

    GST_TRACE_OBJECT(self, "Processing buffer");
    g_mutex_lock(&self->mutex);
    GST_TRACE_OBJECT(self, "Mutex acquired, stream received: %s", self->streamReceived ? "yes":"no");

    // The key might not have been received yet. Wait for it.
    if (!self->streamReceived)
        g_cond_wait(&self->condition, &self->mutex);

    if (!self->streamReceived) {
        GST_DEBUG_OBJECT(self, "Condition signaled from state change transition. Aborting.");
        result = GST_FLOW_NOT_SUPPORTED;
        goto beach;
    }

    GST_TRACE_OBJECT(self, "Proceeding with decryption");
    protectionMeta = reinterpret_cast<GstProtectionMeta*>(gst_buffer_get_protection_meta(buffer));
    if (!protectionMeta || !buffer) {
        if (!protectionMeta)
            GST_ERROR_OBJECT(self, "Failed to get GstProtection metadata from buffer %p", buffer);

        if (!buffer)
            GST_ERROR_OBJECT(self, "Failed to get writable buffer");

        result = GST_FLOW_NOT_SUPPORTED;
        goto beach;
    }

    bufferMapped = gst_buffer_map(buffer, &map, static_cast<GstMapFlags>(GST_MAP_READWRITE));
    if (!bufferMapped) {
        GST_ERROR_OBJECT(self, "Failed to map buffer");
        result = GST_FLOW_NOT_SUPPORTED;
        goto beach;
    }

    pad = gst_element_get_static_pad(GST_ELEMENT(self), "src");
    caps = gst_pad_get_current_caps(pad);
    if (g_str_has_prefix(gst_structure_get_name(gst_caps_get_structure(caps, 0)), "video/"))
        trackID = 1;
    else
        trackID = 2;
    gst_caps_unref(caps);
    gst_object_unref(pad);

    GST_TRACE_OBJECT(self, "Protection meta: %" GST_PTR_FORMAT, protectionMeta->info);

    if (gst_structure_get_uint(protectionMeta->info, "sample-index", &sampleIndex)) {
        // Process the PIFF box.
        value = gst_structure_get_value(protectionMeta->info, "box");
        if (!value) {
            GST_ERROR_OBJECT(self, "Failed to get encryption box for sample");
            result = GST_FLOW_NOT_SUPPORTED;
            goto beach;
        }

        box = gst_value_get_buffer(value);
        boxMapped = gst_buffer_map(box, &boxMap, GST_MAP_READ);
        if (!boxMapped) {
            GST_ERROR_OBJECT(self, "Failed to map encryption box");
            result = GST_FLOW_NOT_SUPPORTED;
            goto beach;
        }

        GST_TRACE_OBJECT(self, "decrypt sample %u", sampleIndex);
        if ((errorCode = self->sessionMetaData->decrypt(static_cast<void*>(map.data), static_cast<uint32_t>(map.size),
            static_cast<void*>(boxMap.data), static_cast<uint32_t>(boxMap.size), static_cast<uint32_t>(sampleIndex), trackID))) {
            GST_WARNING_OBJECT(self, "ERROR - packet decryption failed [%d]", errorCode);
            GST_MEMDUMP_OBJECT(self, "box", boxMap.data, boxMap.size);
            result = GST_FLOW_ERROR;
            goto beach;
        }
    } else {
        // Process CENC data.
        guint ivSize;
        gboolean encrypted;
        GstBuffer* ivBuffer = nullptr;
        GstMapInfo ivMap;
        unsigned position = 0;
        unsigned sampleIndex = 0;
        guint subSampleCount;
        GstBuffer* subsamplesBuffer = nullptr;
        GstMapInfo subSamplesMap;
        GstByteReader* reader = nullptr;

        if (!gst_structure_get_uint(protectionMeta->info, "iv_size", &ivSize)) {
            GST_ERROR_OBJECT(self, "failed to get iv_size");
            result = GST_FLOW_NOT_SUPPORTED;
            goto beach;
        }

        if (!gst_structure_get_boolean(protectionMeta->info, "encrypted", &encrypted)) {
            GST_ERROR_OBJECT(self, "failed to get encrypted flag");
            result = GST_FLOW_NOT_SUPPORTED;
            goto beach;
        }

        // Unencrypted sample.
        if (!ivSize || !encrypted)
            goto beach;

        if (!gst_structure_get_uint(protectionMeta->info, "subsample_count", &subSampleCount)) {
            GST_ERROR_OBJECT(self, "failed to get subsample_count");
            result = GST_FLOW_NOT_SUPPORTED;
            goto beach;
        }

        value = gst_structure_get_value(protectionMeta->info, "iv");
        if (!value) {
            GST_ERROR_OBJECT(self, "Failed to get IV for sample");
            result = GST_FLOW_NOT_SUPPORTED;
            goto beach;
        }

        ivBuffer = gst_value_get_buffer(value);
        if (!gst_buffer_map(ivBuffer, &ivMap, GST_MAP_READ)) {
            GST_ERROR_OBJECT(self, "Failed to map IV");
            result = GST_FLOW_NOT_SUPPORTED;
            goto beach;
        }

        if (subSampleCount) {
            value = gst_structure_get_value(protectionMeta->info, "subsamples");
            if (!value) {
                GST_ERROR_OBJECT(self, "Failed to get subsamples");
                result = GST_FLOW_NOT_SUPPORTED;
                goto release;
            }
            subsamplesBuffer = gst_value_get_buffer(value);
            if (!gst_buffer_map(subsamplesBuffer, &subSamplesMap, GST_MAP_READ)) {
                GST_ERROR_OBJECT(self, "Failed to map subsample buffer");
                result = GST_FLOW_NOT_SUPPORTED;
                goto release;
            }
        }

        reader = gst_byte_reader_new(subSamplesMap.data, subSamplesMap.size);
        if (!reader) {
            GST_ERROR_OBJECT(self, "Failed to allocate subsample reader");
            result = GST_FLOW_NOT_SUPPORTED;
            goto release;
        }

        GST_DEBUG_OBJECT(self, "position: %d, size: %d", position, map.size);
        while (position < map.size) {
            guint16 nBytesClear = 0;
            guint32 nBytesEncrypted = 0;

            if (sampleIndex < subSampleCount) {
                if (!gst_byte_reader_get_uint16_be(reader, &nBytesClear)
                    || !gst_byte_reader_get_uint32_be(reader, &nBytesEncrypted)) {
                    result = GST_FLOW_NOT_SUPPORTED;
                    GST_DEBUG_OBJECT(self, "unsupported");
                    goto release;
                }

                sampleIndex++;
            } else {
                nBytesClear = 0;
                nBytesEncrypted = map.size - position;
            }

            GST_TRACE_OBJECT(self, "%d bytes clear (todo=%d)", nBytesClear, map.size - position);
            position += nBytesClear;
            if (nBytesEncrypted) {
                GST_TRACE_OBJECT(self, "%d bytes encrypted (todo=%d)", nBytesEncrypted, map.size - position);
                if ((errorCode = self->sessionMetaData->processPayload(trackID, static_cast<const void*>(ivMap.data), static_cast<uint32_t>(ivMap.size), static_cast<void*>(map.data + position), static_cast<uint32_t>(nBytesEncrypted)))) {
                    GST_WARNING_OBJECT(self, "ERROR - packet decryption failed [%d]", errorCode);
                    result = GST_FLOW_ERROR;
                    goto release;
                }
                position += nBytesEncrypted;
            }
        }
    release:
        gst_buffer_unmap(ivBuffer, &ivMap);

        if (reader)
            gst_byte_reader_free(reader);

        if (subsamplesBuffer)
            gst_buffer_unmap(subsamplesBuffer, &subSamplesMap);
    }

beach:
    if (boxMapped)
        gst_buffer_unmap(box, &boxMap);

    if (bufferMapped)
        gst_buffer_unmap(buffer, &map);

    if (protectionMeta)
        gst_buffer_remove_meta(buffer, reinterpret_cast<GstMeta*>(protectionMeta));

    GST_TRACE_OBJECT(self, "Unlocking mutex");
    g_mutex_unlock(&self->mutex);
    return result;
}
Пример #12
0
static GstFlowReturn
gst_ac3_parse_handle_frame (GstBaseParse * parse,
    GstBaseParseFrame * frame, gint * skipsize)
{
  GstAc3Parse *ac3parse = GST_AC3_PARSE (parse);
  GstBuffer *buf = frame->buffer;
  GstByteReader reader;
  gint off;
  gboolean lost_sync, draining, eac, more = FALSE;
  guint frmsiz, blocks, sid;
  guint rate, chans;
  gboolean update_rate = FALSE;
  gint framesize = 0;
  gint have_blocks = 0;
  GstMapInfo map;
  gboolean ret = FALSE;
  GstFlowReturn res = GST_FLOW_OK;

  gst_buffer_map (buf, &map, GST_MAP_READ);

  if (G_UNLIKELY (map.size < 8)) {
    *skipsize = 1;
    goto cleanup;
  }

  gst_byte_reader_init (&reader, map.data, map.size);
  off = gst_byte_reader_masked_scan_uint32 (&reader, 0xffff0000, 0x0b770000,
      0, map.size);

  GST_LOG_OBJECT (parse, "possible sync at buffer offset %d", off);

  /* didn't find anything that looks like a sync word, skip */
  if (off < 0) {
    *skipsize = map.size - 3;
    goto cleanup;
  }

  /* possible frame header, but not at offset 0? skip bytes before sync */
  if (off > 0) {
    *skipsize = off;
    goto cleanup;
  }

  /* make sure the values in the frame header look sane */
  if (!gst_ac3_parse_frame_header (ac3parse, buf, 0, &frmsiz, &rate, &chans,
          &blocks, &sid, &eac)) {
    *skipsize = off + 2;
    goto cleanup;
  }

  GST_LOG_OBJECT (parse, "size: %u, blocks: %u, rate: %u, chans: %u", frmsiz,
      blocks, rate, chans);

  framesize = frmsiz;

  if (G_UNLIKELY (g_atomic_int_get (&ac3parse->align) ==
          GST_AC3_PARSE_ALIGN_NONE))
    gst_ac3_parse_set_alignment (ac3parse, eac);

  GST_LOG_OBJECT (parse, "got frame");

  lost_sync = GST_BASE_PARSE_LOST_SYNC (parse);
  draining = GST_BASE_PARSE_DRAINING (parse);

  if (g_atomic_int_get (&ac3parse->align) == GST_AC3_PARSE_ALIGN_IEC61937) {
    /* We need 6 audio blocks from each substream, so we keep going forwards
     * till we have it */

    g_assert (blocks > 0);
    GST_LOG_OBJECT (ac3parse, "Need %d frames before pushing", 6 / blocks);

    if (sid != 0) {
      /* We need the first substream to be the one with id 0 */
      GST_LOG_OBJECT (ac3parse, "Skipping till we find sid 0");
      *skipsize = off + 2;
      goto cleanup;
    }

    framesize = 0;

    /* Loop till we have 6 blocks per substream */
    for (have_blocks = 0; !more && have_blocks < 6; have_blocks += blocks) {
      /* Loop till we get one frame from each substream */
      do {
        framesize += frmsiz;

        if (!gst_byte_reader_skip (&reader, frmsiz)
            || map.size < (framesize + 6)) {
          more = TRUE;
          break;
        }

        if (!gst_ac3_parse_frame_header (ac3parse, buf, framesize, &frmsiz,
                NULL, NULL, NULL, &sid, &eac)) {
          *skipsize = off + 2;
          goto cleanup;
        }
      } while (sid);
    }

    /* We're now at the next frame, so no need to skip if resyncing */
    frmsiz = 0;
  }

  if (lost_sync && !draining) {
    guint16 word = 0;

    GST_DEBUG_OBJECT (ac3parse, "resyncing; checking next frame syncword");

    if (more || !gst_byte_reader_skip (&reader, frmsiz) ||
        !gst_byte_reader_get_uint16_be (&reader, &word)) {
      GST_DEBUG_OBJECT (ac3parse, "... but not sufficient data");
      gst_base_parse_set_min_frame_size (parse, framesize + 8);
      *skipsize = 0;
      goto cleanup;
    } else {
      if (word != 0x0b77) {
        GST_DEBUG_OBJECT (ac3parse, "0x%x not OK", word);
        *skipsize = off + 2;
        goto cleanup;
      } else {
        /* ok, got sync now, let's assume constant frame size */
        gst_base_parse_set_min_frame_size (parse, framesize);
      }
    }
  }

  /* expect to have found a frame here */
  g_assert (framesize);
  ret = TRUE;

  /* arrange for metadata setup */
  if (G_UNLIKELY (sid)) {
    /* dependent frame, no need to (ac)count for or consider further */
    GST_LOG_OBJECT (parse, "sid: %d", sid);
    frame->flags |= GST_BASE_PARSE_FRAME_FLAG_NO_FRAME;
    /* TODO maybe also mark as DELTA_UNIT,
     * if that does not surprise baseparse elsewhere */
    /* occupies same time space as previous base frame */
    if (G_LIKELY (GST_BUFFER_TIMESTAMP (buf) >= GST_BUFFER_DURATION (buf)))
      GST_BUFFER_TIMESTAMP (buf) -= GST_BUFFER_DURATION (buf);
    /* only shortcut if we already arranged for caps */
    if (G_LIKELY (ac3parse->sample_rate > 0))
      goto cleanup;
  }

  if (G_UNLIKELY (ac3parse->sample_rate != rate || ac3parse->channels != chans
          || ac3parse->eac != eac)) {
    GstCaps *caps = gst_caps_new_simple (eac ? "audio/x-eac3" : "audio/x-ac3",
        "framed", G_TYPE_BOOLEAN, TRUE, "rate", G_TYPE_INT, rate,
        "channels", G_TYPE_INT, chans, NULL);
    gst_caps_set_simple (caps, "alignment", G_TYPE_STRING,
        g_atomic_int_get (&ac3parse->align) == GST_AC3_PARSE_ALIGN_IEC61937 ?
        "iec61937" : "frame", NULL);
    gst_pad_set_caps (GST_BASE_PARSE_SRC_PAD (parse), caps);
    gst_caps_unref (caps);

    ac3parse->sample_rate = rate;
    ac3parse->channels = chans;
    ac3parse->eac = eac;

    update_rate = TRUE;
  }

  if (G_UNLIKELY (ac3parse->blocks != blocks)) {
    ac3parse->blocks = blocks;

    update_rate = TRUE;
  }

  if (G_UNLIKELY (update_rate))
    gst_base_parse_set_frame_rate (parse, rate, 256 * blocks, 2, 2);

cleanup:
  gst_buffer_unmap (buf, &map);

  if (ret && framesize <= map.size) {
    res = gst_base_parse_finish_frame (parse, frame, framesize);
  }

  return res;
}
Пример #13
0
static gboolean
gst_jif_mux_parse_image (GstJifMux * self, GstBuffer * buf)
{
    GstByteReader reader = GST_BYTE_READER_INIT_FROM_BUFFER (buf);
    GstJifMuxMarker *m;
    guint8 marker = 0;
    guint16 size = 0;
    const guint8 *data = NULL;

    GST_LOG_OBJECT (self, "Received buffer of size: %u", GST_BUFFER_SIZE (buf));

    if (!gst_byte_reader_peek_uint8 (&reader, &marker))
        goto error;

    while (marker == 0xff) {
        if (!gst_byte_reader_skip (&reader, 1))
            goto error;

        if (!gst_byte_reader_get_uint8 (&reader, &marker))
            goto error;

        switch (marker) {
        case RST0:
        case RST1:
        case RST2:
        case RST3:
        case RST4:
        case RST5:
        case RST6:
        case RST7:
        case SOI:
            GST_DEBUG_OBJECT (self, "marker = %x", marker);
            m = gst_jif_mux_new_marker (marker, 0, NULL, FALSE);
            self->priv->markers = g_list_prepend (self->priv->markers, m);
            break;
        case EOI:
            GST_DEBUG_OBJECT (self, "marker = %x", marker);
            m = gst_jif_mux_new_marker (marker, 0, NULL, FALSE);
            self->priv->markers = g_list_prepend (self->priv->markers, m);
            goto done;
            break;
        default:
            if (!gst_byte_reader_get_uint16_be (&reader, &size))
                goto error;
            if (!gst_byte_reader_get_data (&reader, size - 2, &data))
                goto error;

            m = gst_jif_mux_new_marker (marker, size - 2, data, FALSE);
            self->priv->markers = g_list_prepend (self->priv->markers, m);

            GST_DEBUG_OBJECT (self, "marker = %2x, size = %u", marker, size);
            break;
        }

        if (marker == SOS) {
            gint eoi_pos = -1;
            gint i;

            /* search the last 5 bytes for the EOI marker */
            g_assert (GST_BUFFER_SIZE (buf) >= 5);
            for (i = 5; i >= 2; i--) {
                if (GST_BUFFER_DATA (buf)[GST_BUFFER_SIZE (buf) - i] == 0xFF &&
                        GST_BUFFER_DATA (buf)[GST_BUFFER_SIZE (buf) - i + 1] == EOI) {
                    eoi_pos = GST_BUFFER_SIZE (buf) - i;
                    break;
                }
            }

            if (eoi_pos == -1) {
                GST_WARNING_OBJECT (self, "Couldn't find an EOI marker");
                eoi_pos = GST_BUFFER_SIZE (buf);
            }

            /* remaining size except EOI is scan data */
            self->priv->scan_size = eoi_pos - gst_byte_reader_get_pos (&reader);
            if (!gst_byte_reader_get_data (&reader, self->priv->scan_size,
                                           &self->priv->scan_data))
                goto error;

            GST_DEBUG_OBJECT (self, "scan data, size = %u", self->priv->scan_size);
        }

        if (!gst_byte_reader_peek_uint8 (&reader, &marker))
            goto error;
    }
    GST_INFO_OBJECT (self, "done parsing at 0x%x / 0x%x",
                     gst_byte_reader_get_pos (&reader), GST_BUFFER_SIZE (buf));

done:
    self->priv->markers = g_list_reverse (self->priv->markers);
    return TRUE;

error:
    GST_WARNING_OBJECT (self,
                        "Error parsing image header (need more that %u bytes available)",
                        gst_byte_reader_get_remaining (&reader));
    return FALSE;
}
Пример #14
0
static GstFlowReturn
gst_cenc_decrypt_transform_ip (GstBaseTransform * base, GstBuffer * buf)
{
  GstCencDecrypt *self = GST_CENC_DECRYPT (base);
  GstFlowReturn ret = GST_FLOW_OK;
  GstMapInfo map, iv_map;
  const GstCencKeyPair *keypair;
  const GstProtectionMeta *prot_meta = NULL;
  guint pos = 0;
  gint sample_index = 0;
  guint subsample_count;
  AesCtrState *state = NULL;
  guint iv_size;
  gboolean encrypted;
  const GValue *value;
  GstBuffer *key_id = NULL;
  GstBuffer *iv_buf = NULL;
  GBytes *iv_bytes = NULL;
  GstBuffer *subsamples_buf = NULL;
  GstMapInfo subsamples_map;
  GstByteReader *reader=NULL;

  GST_TRACE_OBJECT (self, "decrypt in-place");
  prot_meta = (GstProtectionMeta*) gst_buffer_get_protection_meta (buf);
  if (!prot_meta || !buf) {
    if (!prot_meta) {
      GST_ERROR_OBJECT (self, "Failed to get GstProtection metadata from buffer");
    }
    if (!buf) {
      GST_ERROR_OBJECT (self, "Failed to get writable buffer");
    }
    ret = GST_FLOW_NOT_SUPPORTED;
    goto out;
  }

  if (!gst_buffer_map (buf, &map, GST_MAP_READWRITE)) {
    GST_ERROR_OBJECT (self, "Failed to map buffer");
    ret = GST_FLOW_NOT_SUPPORTED;
    goto release;
  }

  GST_TRACE_OBJECT (self, "decrypt sample %d", (gint)map.size);
  if(!gst_structure_get_uint(prot_meta->info,"iv_size",&iv_size)){
    GST_ERROR_OBJECT (self, "failed to get iv_size");
    ret = GST_FLOW_NOT_SUPPORTED;
    goto release;
  }
  if(!gst_structure_get_boolean(prot_meta->info,"encrypted",&encrypted)){
    GST_ERROR_OBJECT (self, "failed to get encrypted flag");
    ret = GST_FLOW_NOT_SUPPORTED;
    goto release;
  }
  if (iv_size == 0 || !encrypted) {
    /* sample is not encrypted */
    goto beach;
  }
  GST_DEBUG_OBJECT (base, "protection meta: %" GST_PTR_FORMAT, prot_meta->info);
  if(!gst_structure_get_uint(prot_meta->info,"subsample_count",&subsample_count)){
    GST_ERROR_OBJECT (self, "failed to get subsample_count");
    ret = GST_FLOW_NOT_SUPPORTED;
    goto release;
  }
  value = gst_structure_get_value (prot_meta->info, "kid");
  if(!value){
    GST_ERROR_OBJECT (self, "Failed to get KID for sample");
    ret = GST_FLOW_NOT_SUPPORTED;
    goto release;
  }
  key_id = gst_value_get_buffer (value);

  value = gst_structure_get_value (prot_meta->info, "iv");
  if(!value){
    GST_ERROR_OBJECT (self, "Failed to get IV for sample");
    ret = GST_FLOW_NOT_SUPPORTED;
    goto release;
  }
  iv_buf = gst_value_get_buffer (value);
  if(!gst_buffer_map (iv_buf, &iv_map, GST_MAP_READ)){
    GST_ERROR_OBJECT (self, "Failed to map IV");
    ret = GST_FLOW_NOT_SUPPORTED;
    goto release;
  }
  iv_bytes = g_bytes_new (iv_map.data, iv_map.size);
  gst_buffer_unmap (iv_buf, &iv_map);
  if(subsample_count){
    value = gst_structure_get_value (prot_meta->info, "subsamples");
    if(!value){
      GST_ERROR_OBJECT (self, "Failed to get subsamples");
      ret = GST_FLOW_NOT_SUPPORTED;
      goto release;
    }
    subsamples_buf = gst_value_get_buffer (value);
    if(!gst_buffer_map (subsamples_buf, &subsamples_map, GST_MAP_READ)){
      GST_ERROR_OBJECT (self, "Failed to map subsample buffer");
      ret = GST_FLOW_NOT_SUPPORTED;
      goto release;
    }
  }

  keypair = gst_cenc_decrypt_lookup_key (self,key_id);

  if (!keypair) {
    gsize sz;
    GST_ERROR_OBJECT (self, "Failed to lookup key");
    GST_MEMDUMP_OBJECT (self, "Key ID:", 
                        g_bytes_get_data (keypair->key_id, &sz),
                        sz);
    ret = GST_FLOW_NOT_SUPPORTED;
    goto release;
  }

  state = gst_aes_ctr_decrypt_new (keypair->key, iv_bytes);

  if (!state) {
    GST_ERROR_OBJECT (self, "Failed to init AES cipher");
    ret = GST_FLOW_NOT_SUPPORTED;
    goto release;
  }

  if (subsample_count) {
    reader = gst_byte_reader_new (subsamples_map.data, subsamples_map.size);
    if(!reader){
      GST_ERROR_OBJECT (self, "Failed to allocate subsample reader");
      ret = GST_FLOW_NOT_SUPPORTED;
      goto release;
    }
  }

  while (pos < map.size) {
    guint16 n_bytes_clear = 0;
    guint32 n_bytes_encrypted = 0;

    if (sample_index < subsample_count) {
      if (!gst_byte_reader_get_uint16_be (reader, &n_bytes_clear)
            || !gst_byte_reader_get_uint32_be (reader, &n_bytes_encrypted)) {
          ret = GST_FLOW_NOT_SUPPORTED;
          goto release;
      }
      sample_index++;
    } else {
      n_bytes_clear = 0;
      n_bytes_encrypted = map.size - pos;
    }
    GST_TRACE_OBJECT (self, "%u bytes clear (todo=%d)", n_bytes_clear,
                      (gint)map.size - pos);
    pos += n_bytes_clear;
    if (n_bytes_encrypted) {
      GST_TRACE_OBJECT (self, "%u bytes encrypted (todo=%d)",
                        n_bytes_encrypted, (gint)map.size - pos);
      gst_aes_ctr_decrypt_ip (state, map.data + pos, n_bytes_encrypted);
      pos += n_bytes_encrypted;
    }
  }

beach:
  gst_buffer_unmap (buf, &map);
  if (state) {
    gst_aes_ctr_decrypt_unref (state);
  }
release:
  if (reader){
    gst_byte_reader_free (reader);
  }
  if(subsamples_buf){
    gst_buffer_unmap (subsamples_buf, &subsamples_map);
  }
  if (prot_meta) {
    gst_buffer_remove_meta (buf, (GstMeta *) prot_meta);
  }
  if (iv_bytes) {
    g_bytes_unref (iv_bytes);
  }
out:
  return ret;
}
static gboolean
gst_ac3_parse_check_valid_frame (GstBaseParse * parse,
    GstBaseParseFrame * frame, guint * framesize, gint * skipsize)
{
  GstAc3Parse *ac3parse = GST_AC3_PARSE (parse);
  GstBuffer *buf = frame->buffer;
  GstByteReader reader = GST_BYTE_READER_INIT_FROM_BUFFER (buf);
  gint off;
  gboolean lost_sync, draining, eac, more = FALSE;
  guint frmsiz, blocks, sid;
  gint have_blocks = 0;

  if (G_UNLIKELY (GST_BUFFER_SIZE (buf) < 6))
    return FALSE;

  off = gst_byte_reader_masked_scan_uint32 (&reader, 0xffff0000, 0x0b770000,
      0, GST_BUFFER_SIZE (buf));

  GST_LOG_OBJECT (parse, "possible sync at buffer offset %d", off);

  /* didn't find anything that looks like a sync word, skip */
  if (off < 0) {
    *skipsize = GST_BUFFER_SIZE (buf) - 3;
    return FALSE;
  }

  /* possible frame header, but not at offset 0? skip bytes before sync */
  if (off > 0) {
    *skipsize = off;
    return FALSE;
  }

  /* make sure the values in the frame header look sane */
  if (!gst_ac3_parse_frame_header (ac3parse, buf, 0, &frmsiz, NULL, NULL,
          &blocks, &sid, &eac)) {
    *skipsize = off + 2;
    return FALSE;
  }

  *framesize = frmsiz;

  if (G_UNLIKELY (g_atomic_int_get (&ac3parse->align) ==
          GST_AC3_PARSE_ALIGN_NONE))
    gst_ac3_parse_set_alignment (ac3parse, eac);

  GST_LOG_OBJECT (parse, "got frame");

  lost_sync = GST_BASE_PARSE_LOST_SYNC (parse);
  draining = GST_BASE_PARSE_DRAINING (parse);

  if (g_atomic_int_get (&ac3parse->align) == GST_AC3_PARSE_ALIGN_IEC61937) {
    /* We need 6 audio blocks from each substream, so we keep going forwards
     * till we have it */

    g_assert (blocks > 0);
    GST_LOG_OBJECT (ac3parse, "Need %d frames before pushing", 6 / blocks);

    if (sid != 0) {
      /* We need the first substream to be the one with id 0 */
      GST_LOG_OBJECT (ac3parse, "Skipping till we find sid 0");
      *skipsize = off + 2;
      return FALSE;
    }

    *framesize = 0;

    /* Loop till we have 6 blocks per substream */
    for (have_blocks = 0; !more && have_blocks < 6; have_blocks += blocks) {
      /* Loop till we get one frame from each substream */
      do {
        *framesize += frmsiz;

        if (!gst_byte_reader_skip (&reader, frmsiz) ||
            GST_BUFFER_SIZE (buf) < (*framesize + 6)) {
          more = TRUE;
          break;
        }

        if (!gst_ac3_parse_frame_header (ac3parse, buf, *framesize, &frmsiz,
                NULL, NULL, NULL, &sid, &eac)) {
          *skipsize = off + 2;
          return FALSE;
        }
      } while (sid);
    }

    /* We're now at the next frame, so no need to skip if resyncing */
    frmsiz = 0;
  }

  if (lost_sync && !draining) {
    guint16 word = 0;

    GST_DEBUG_OBJECT (ac3parse, "resyncing; checking next frame syncword");

    if (more || !gst_byte_reader_skip (&reader, frmsiz) ||
        !gst_byte_reader_get_uint16_be (&reader, &word)) {
      GST_DEBUG_OBJECT (ac3parse, "... but not sufficient data");
      gst_base_parse_set_min_frame_size (parse, *framesize + 6);
      *skipsize = 0;
      return FALSE;
    } else {
      if (word != 0x0b77) {
        GST_DEBUG_OBJECT (ac3parse, "0x%x not OK", word);
        *skipsize = off + 2;
        return FALSE;
      } else {
        /* ok, got sync now, let's assume constant frame size */
        gst_base_parse_set_min_frame_size (parse, *framesize);
      }
    }
  }

  return TRUE;
}