/* * 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++; }
/** * 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 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; }