/* * Writes the tag entry. * * The tag entry is the tag id, the tag type, * the count and the offset. * * The offset is the on the amount of data writen so far, as one * can't predict the total bytes that the tag entries will take. * This means those fields requires being updated later. */ static void gst_exif_writer_write_tag_header (GstExifWriter * writer, guint16 exif_tag, guint16 exif_type, guint32 count, guint32 offset, gboolean is_data) { GST_DEBUG ("Writing tag entry: id %x, type %u, count %u, offset %u", exif_tag, exif_type, count, offset); if (writer->byte_order == G_LITTLE_ENDIAN) { gst_byte_writer_put_uint16_le (&writer->tagwriter, exif_tag); gst_byte_writer_put_uint16_le (&writer->tagwriter, exif_type); gst_byte_writer_put_uint32_le (&writer->tagwriter, count); gst_byte_writer_put_uint32_le (&writer->tagwriter, offset); } else if (writer->byte_order == G_BIG_ENDIAN) { gst_byte_writer_put_uint16_be (&writer->tagwriter, exif_tag); gst_byte_writer_put_uint16_be (&writer->tagwriter, exif_type); gst_byte_writer_put_uint32_be (&writer->tagwriter, count); if (is_data) { gst_byte_writer_put_uint32_le (&writer->tagwriter, offset); } else { gst_byte_writer_put_uint32_be (&writer->tagwriter, offset); } } else { g_assert_not_reached (); } writer->tags_total++; }
static void gst_aiff_mux_write_form_header (GstAiffMux * aiffmux, guint32 audio_data_size, GstByteWriter * writer) { /* ckID == 'FORM' */ gst_byte_writer_put_uint32_le (writer, GST_MAKE_FOURCC ('F', 'O', 'R', 'M')); /* ckSize is currently bogus but we'll know what it is later */ gst_byte_writer_put_uint32_be (writer, audio_data_size + AIFF_HEADER_LEN - 8); /* formType == 'AIFF' */ gst_byte_writer_put_uint32_le (writer, GST_MAKE_FOURCC ('A', 'I', 'F', 'F')); }
static void gst_exif_writer_write_rational_data (GstExifWriter * writer, guint32 frac_n, guint32 frac_d) { if (writer->byte_order == G_LITTLE_ENDIAN) { gst_byte_writer_put_uint32_le (&writer->datawriter, frac_n); gst_byte_writer_put_uint32_le (&writer->datawriter, frac_d); } else { gst_byte_writer_put_uint32_be (&writer->datawriter, frac_n); gst_byte_writer_put_uint32_be (&writer->datawriter, frac_d); } }
static void gst_wavparse_tags_foreach (const GstTagList * tags, const gchar * tag, gpointer data) { const struct { guint32 fcc; const gchar *tag; } rifftags[] = { { GST_RIFF_INFO_IARL, GST_TAG_LOCATION}, { GST_RIFF_INFO_IART, GST_TAG_ARTIST}, { GST_RIFF_INFO_ICMT, GST_TAG_COMMENT}, { GST_RIFF_INFO_ICOP, GST_TAG_COPYRIGHT}, { GST_RIFF_INFO_ICRD, GST_TAG_DATE}, { GST_RIFF_INFO_IGNR, GST_TAG_GENRE}, { GST_RIFF_INFO_IKEY, GST_TAG_KEYWORDS}, { GST_RIFF_INFO_INAM, GST_TAG_TITLE}, { GST_RIFF_INFO_IPRD, GST_TAG_ALBUM}, { GST_RIFF_INFO_ISBJ, GST_TAG_ALBUM_ARTIST}, { GST_RIFF_INFO_ISFT, GST_TAG_ENCODER}, { GST_RIFF_INFO_ISRC, GST_TAG_ISRC}, { 0, NULL} }; gint n; gchar *str = NULL; GstByteWriter *bw = data; for (n = 0; rifftags[n].fcc != 0; n++) { if (!strcmp (rifftags[n].tag, tag)) { if (rifftags[n].fcc == GST_RIFF_INFO_ICRD) { GDate *date; /* special case for the date tag */ if (gst_tag_list_get_date (tags, tag, &date)) { str = g_strdup_printf ("%04d:%02d:%02d", g_date_get_year (date), g_date_get_month (date), g_date_get_day (date)); g_date_free (date); } } else { gst_tag_list_get_string (tags, tag, &str); } if (str) { gst_byte_writer_put_uint32_le (bw, rifftags[n].fcc); gst_byte_writer_put_uint32_le (bw, GST_ROUND_UP_2 (strlen (str))); gst_byte_writer_put_string (bw, str); g_free (str); str = NULL; break; } } } }
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); }
/** * gst_tag_list_to_exif_buffer_with_tiff_header: * @taglist: The taglist * * Formats the tags in taglist into exif structure, a tiff header * is put in the beginning of the buffer. * * Returns: A GstBuffer containing the data * * Since: 0.10.30 */ GstBuffer * gst_tag_list_to_exif_buffer_with_tiff_header (const GstTagList * taglist) { GstBuffer *ifd; GstByteWriter writer; guint size; ifd = gst_tag_list_to_exif_buffer (taglist, G_BYTE_ORDER, 8); if (ifd == NULL) { GST_WARNING ("Failed to create exif buffer"); return NULL; } size = TIFF_HEADER_SIZE + GST_BUFFER_SIZE (ifd); /* TODO what is the correct endianness here? */ gst_byte_writer_init_with_size (&writer, size, FALSE); /* TIFF header */ if (G_BYTE_ORDER == G_LITTLE_ENDIAN) { gst_byte_writer_put_uint16_le (&writer, TIFF_LITTLE_ENDIAN); gst_byte_writer_put_uint16_le (&writer, 42); gst_byte_writer_put_uint32_le (&writer, 8); } else { gst_byte_writer_put_uint16_be (&writer, TIFF_BIG_ENDIAN); gst_byte_writer_put_uint16_be (&writer, 42); gst_byte_writer_put_uint32_be (&writer, 8); } if (!gst_byte_writer_put_data (&writer, GST_BUFFER_DATA (ifd), GST_BUFFER_SIZE (ifd))) { GST_WARNING ("Byte writer size mismatch"); /* reaching here is a programming error because we should have a buffer * large enough */ g_assert_not_reached (); gst_buffer_unref (ifd); gst_byte_writer_reset (&writer); return NULL; } gst_buffer_unref (ifd); return gst_byte_writer_reset_and_get_buffer (&writer); }
static GstBuffer * gst_opus_enc_create_id_buffer (gint nchannels, gint n_stereo_streams, gint sample_rate, guint8 channel_mapping_family, const guint8 * channel_mapping) { GstBuffer *buffer; GstByteWriter bw; gboolean hdl = TRUE; g_return_val_if_fail (nchannels > 0 && nchannels < 256, NULL); g_return_val_if_fail (n_stereo_streams >= 0, NULL); g_return_val_if_fail (n_stereo_streams <= nchannels - n_stereo_streams, NULL); gst_byte_writer_init (&bw); /* See http://wiki.xiph.org/OggOpus */ hdl &= gst_byte_writer_put_data (&bw, (const guint8 *) "OpusHead", 8); hdl &= gst_byte_writer_put_uint8 (&bw, 0x01); /* version number */ hdl &= gst_byte_writer_put_uint8 (&bw, nchannels); hdl &= gst_byte_writer_put_uint16_le (&bw, 0); /* pre-skip */ hdl &= gst_byte_writer_put_uint32_le (&bw, sample_rate); hdl &= gst_byte_writer_put_uint16_le (&bw, 0); /* output gain */ hdl &= gst_byte_writer_put_uint8 (&bw, channel_mapping_family); if (channel_mapping_family > 0) { hdl &= gst_byte_writer_put_uint8 (&bw, nchannels - n_stereo_streams); hdl &= gst_byte_writer_put_uint8 (&bw, n_stereo_streams); hdl &= gst_byte_writer_put_data (&bw, channel_mapping, nchannels); } if (!hdl) GST_WARNING ("Error creating header"); buffer = gst_byte_writer_reset_and_get_buffer (&bw); GST_BUFFER_OFFSET (buffer) = 0; GST_BUFFER_OFFSET_END (buffer) = 0; return buffer; }
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 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"); } } }