Beispiel #1
0
static GstFlowReturn
gst_wavenc_write_tags (GstWavEnc * wavenc)
{
  const GstTagList *user_tags;
  GstTagList *tags;
  guint size;
  GstBuffer *buf;
  GstByteWriter bw;

  g_return_val_if_fail (wavenc != NULL, GST_FLOW_OK);

  user_tags = gst_tag_setter_get_tag_list (GST_TAG_SETTER (wavenc));
  if ((!wavenc->tags) && (!user_tags)) {
    GST_DEBUG_OBJECT (wavenc, "have no tags");
    return GST_FLOW_OK;
  }
  tags =
      gst_tag_list_merge (user_tags, wavenc->tags,
      gst_tag_setter_get_tag_merge_mode (GST_TAG_SETTER (wavenc)));

  GST_DEBUG_OBJECT (wavenc, "writing tags");

  gst_byte_writer_init_with_size (&bw, 1024, FALSE);

  /* add LIST INFO chunk */
  gst_byte_writer_put_data (&bw, (const guint8 *) "LIST", 4);
  gst_byte_writer_put_uint32_le (&bw, 0);
  gst_byte_writer_put_data (&bw, (const guint8 *) "INFO", 4);

  /* add tags */
  gst_tag_list_foreach (tags, gst_wavparse_tags_foreach, &bw);

  /* sets real size of LIST INFO chunk */
  size = gst_byte_writer_get_pos (&bw);
  gst_byte_writer_set_pos (&bw, 4);
  gst_byte_writer_put_uint32_le (&bw, size - 8);

  gst_tag_list_unref (tags);

  buf = gst_byte_writer_reset_and_get_buffer (&bw);
  wavenc->meta_length += gst_buffer_get_size (buf);
  return gst_pad_push (wavenc->srcpad, buf);
}
Beispiel #2
0
static GstBuffer *
write_exif_ifd (const GstTagList * taglist, gboolean byte_order,
    guint32 base_offset, const GstExifTagMatch * tag_map)
{
  GstExifWriter writer;
  gint i;

  GST_DEBUG ("Formatting taglist %p as exif buffer. Byte order: %d, "
      "base_offset: %u", taglist, byte_order, base_offset);

  g_assert (byte_order == G_LITTLE_ENDIAN || byte_order == G_BIG_ENDIAN);

  if (!gst_tag_list_has_ifd_tags (taglist, tag_map)) {
    GST_DEBUG ("No tags for this ifd");
    return NULL;
  }

  gst_exif_writer_init (&writer, byte_order);

  /* write tag number as 0 */
  gst_byte_writer_put_uint16_le (&writer.tagwriter, 0);

  /* write both tag headers and data
   * in ascending id order */

  for (i = 0; tag_map[i].exif_tag != 0; i++) {

    /* special cases have NULL gst tag */
    if (tag_map[i].gst_tag == NULL) {
      GstBuffer *inner_ifd = NULL;
      const GstExifTagMatch *inner_tag_map = NULL;

      GST_LOG ("Inner ifd tag: %x", tag_map[i].exif_tag);

      if (tag_map[i].exif_tag == EXIF_GPS_IFD_TAG) {
        inner_tag_map = tag_map_gps;
      }

      if (inner_tag_map) {
        /* The base offset for this inner ifd is the sum of:
         * - the current base offset
         * - the total tag data of current this ifd
         * - the total data of the current ifd
         * - its own tag entry length still to be writen (12)
         * - 4 bytes for the next ifd entry still to be writen
         */
        inner_ifd = write_exif_ifd (taglist, byte_order, base_offset +
            gst_byte_writer_get_size (&writer.tagwriter) +
            gst_byte_writer_get_size (&writer.datawriter) + 12 + 4,
            inner_tag_map);
      }

      if (inner_ifd) {
        GST_DEBUG ("Adding inner ifd: %x", tag_map[i].exif_tag);
        gst_exif_writer_write_tag_header (&writer, tag_map[i].exif_tag,
            EXIF_TYPE_LONG, 1,
            gst_byte_writer_get_size (&writer.datawriter), FALSE);
        gst_byte_writer_put_data (&writer.datawriter,
            GST_BUFFER_DATA (inner_ifd), GST_BUFFER_SIZE (inner_ifd));
        gst_buffer_unref (inner_ifd);
      }
      continue;
    }

    GST_LOG ("Checking tag %s", tag_map[i].gst_tag);
    if (gst_tag_list_get_value_index (taglist, tag_map[i].gst_tag, 0) == NULL)
      continue;

    write_exif_tag_from_taglist (&writer, taglist, &tag_map[i]);
  }

  /* Add the next IFD offset, we just set it to 0 because
   * there is no easy way to predict what it is going to be.
   * The user might rewrite the value if needed */
  gst_byte_writer_put_uint32_le (&writer.tagwriter, 0);

  /* write the number of tags */
  gst_byte_writer_set_pos (&writer.tagwriter, 0);
  if (writer.byte_order == G_LITTLE_ENDIAN)
    gst_byte_writer_put_uint16_le (&writer.tagwriter, writer.tags_total);
  else
    gst_byte_writer_put_uint16_be (&writer.tagwriter, writer.tags_total);

  /* now that we know the tag headers size, we can add the offsets */
  gst_exif_tag_rewrite_offsets (&writer, base_offset);

  return gst_exif_writer_reset_and_get_buffer (&writer);
}
static gboolean
flx_decode_delta_flc (GstFlxDec * flxdec, GstByteReader * reader,
    GstByteWriter * writer)
{
  guint16 lines, start_l;

  g_return_val_if_fail (flxdec != NULL, FALSE);
  g_return_val_if_fail (flxdec->delta_data != NULL, FALSE);

  /* use last frame for delta */
  if (!gst_byte_writer_put_data (writer, flxdec->delta_data, flxdec->size))
    goto error;
  if (!gst_byte_reader_get_uint16_le (reader, &lines))
    goto error;

  if (lines > flxdec->hdr.height) {
    GST_ERROR_OBJECT (flxdec, "Invalid FLC packet detected. too many lines.");
    return FALSE;
  }

  start_l = lines;

  while (lines) {
    guint16 opcode;

    if (!gst_byte_writer_set_pos (writer,
            flxdec->hdr.width * (start_l - lines)))
      goto error;

    /* process opcode(s) */
    while (TRUE) {
      if (!gst_byte_reader_get_uint16_le (reader, &opcode))
        goto error;
      if ((opcode & 0xc000) == 0)
        break;

      if ((opcode & 0xc000) == 0xc000) {
        /* line skip count */
        gulong skip = (0x10000 - opcode);
        if (skip > flxdec->hdr.height) {
          GST_ERROR_OBJECT (flxdec, "Invalid FLC packet detected. "
              "skip line count too big.");
          return FALSE;
        }
        start_l += skip;
        if (!gst_byte_writer_set_pos (writer,
                gst_byte_writer_get_pos (writer) + flxdec->hdr.width * skip))
          goto error;
      } else {
        /* last pixel */
        if (!gst_byte_writer_set_pos (writer,
                gst_byte_writer_get_pos (writer) + flxdec->hdr.width))
          goto error;
        if (!gst_byte_writer_put_uint8 (writer, opcode & 0xff))
          goto error;
      }
    }

    /* last opcode is the packet count */
    GST_LOG_OBJECT (flxdec, "have %d packets", opcode);
    while (opcode--) {
      /* skip count */
      guint8 skip;
      gint8 count;

      if (!gst_byte_reader_get_uint8 (reader, &skip))
        goto error;
      if (!gst_byte_writer_set_pos (writer,
              gst_byte_writer_get_pos (writer) + skip))
        goto error;

      /* RLE count */
      if (!gst_byte_reader_get_int8 (reader, &count))
        goto error;

      if (count < 0) {
        guint16 x;

        /* replicate word run */
        count = ABS (count);

        GST_LOG_OBJECT (flxdec, "have replicate run of size %d at offset %d",
            count, skip);

        if (skip + count > flxdec->hdr.width) {
          GST_ERROR_OBJECT (flxdec, "Invalid FLC packet detected. "
              "line too long.");
          return FALSE;
        }

        if (!gst_byte_reader_get_uint16_le (reader, &x))
          goto error;

        while (count--) {
          if (!gst_byte_writer_put_uint16_le (writer, x)) {
            goto error;
          }
        }
      } else {
        GST_LOG_OBJECT (flxdec, "have literal run of size %d at offset %d",
            count, skip);

        if (skip + count > flxdec->hdr.width) {
          GST_ERROR_OBJECT (flxdec, "Invalid FLC packet detected. "
              "line too long.");
          return FALSE;
        }

        while (count--) {
          guint16 x;

          if (!gst_byte_reader_get_uint16_le (reader, &x))
            goto error;
          if (!gst_byte_writer_put_uint16_le (writer, x))
            goto error;
        }
      }
    }
    lines--;
  }

  return TRUE;

error:
  GST_ERROR_OBJECT (flxdec, "Failed to decode FLI packet");
  return FALSE;
}
static gboolean
flx_decode_delta_fli (GstFlxDec * flxdec, GstByteReader * reader,
    GstByteWriter * writer)
{
  guint16 start_line, lines;
  guint line_start_i;

  g_return_val_if_fail (flxdec != NULL, FALSE);
  g_return_val_if_fail (flxdec->delta_data != NULL, FALSE);

  /* use last frame for delta */
  if (!gst_byte_writer_put_data (writer, flxdec->delta_data, flxdec->size))
    goto error;

  if (!gst_byte_reader_get_uint16_le (reader, &start_line))
    goto error;
  if (!gst_byte_reader_get_uint16_le (reader, &lines))
    goto error;
  GST_LOG_OBJECT (flxdec, "height %d start line %d line count %d",
      flxdec->hdr.height, start_line, lines);

  if (start_line + lines > flxdec->hdr.height) {
    GST_ERROR_OBJECT (flxdec, "Invalid FLI packet detected. too many lines.");
    return FALSE;
  }

  line_start_i = flxdec->hdr.width * start_line;
  if (!gst_byte_writer_set_pos (writer, line_start_i))
    goto error;

  while (lines--) {
    guint8 packets;

    /* packet count */
    if (!gst_byte_reader_get_uint8 (reader, &packets))
      goto error;
    GST_LOG_OBJECT (flxdec, "have %d packets", packets);

    while (packets--) {
      /* skip count */
      guint8 skip;
      gint8 count;
      if (!gst_byte_reader_get_uint8 (reader, &skip))
        goto error;

      /* skip bytes */
      if (!gst_byte_writer_set_pos (writer,
              gst_byte_writer_get_pos (writer) + skip))
        goto error;

      /* RLE count */
      if (!gst_byte_reader_get_int8 (reader, &count))
        goto error;

      if (count < 0) {
        guint8 x;

        /* literal run */
        count = ABS (count);
        GST_LOG_OBJECT (flxdec, "have literal run of size %d at offset %d",
            count, skip);

        if (skip + count > flxdec->hdr.width) {
          GST_ERROR_OBJECT (flxdec, "Invalid FLI packet detected. "
              "line too long.");
          return FALSE;
        }

        if (!gst_byte_reader_get_uint8 (reader, &x))
          goto error;
        if (!gst_byte_writer_fill (writer, x, count))
          goto error;
      } else {
        const guint8 *data;

        GST_LOG_OBJECT (flxdec, "have replicate run of size %d at offset %d",
            count, skip);

        if (skip + count > flxdec->hdr.width) {
          GST_ERROR_OBJECT (flxdec, "Invalid FLI packet detected. "
              "line too long.");
          return FALSE;
        }

        /* replicate run */
        if (!gst_byte_reader_get_data (reader, count, &data))
          goto error;
        if (!gst_byte_writer_put_data (writer, data, count))
          goto error;
      }
    }
    line_start_i += flxdec->hdr.width;
    if (!gst_byte_writer_set_pos (writer, line_start_i))
      goto error;
  }

  return TRUE;

error:
  GST_ERROR_OBJECT (flxdec, "Failed to decode FLI packet");
  return FALSE;
}