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); }
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; }
/** * 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 GstFlowReturn gst_h264_parse_pre_push_frame (GstBaseParse * parse, GstBaseParseFrame * frame) { GstH264Parse *h264parse; GstBuffer *buffer; h264parse = GST_H264_PARSE (parse); buffer = frame->buffer; /* periodic SPS/PPS sending */ if (h264parse->interval > 0 || h264parse->push_codec) { GstClockTime timestamp = GST_BUFFER_TIMESTAMP (buffer); guint64 diff; /* init */ if (!GST_CLOCK_TIME_IS_VALID (h264parse->last_report)) { h264parse->last_report = timestamp; } if (h264parse->idr_pos >= 0) { GST_LOG_OBJECT (h264parse, "IDR nal at offset %d", h264parse->idr_pos); if (timestamp > h264parse->last_report) diff = timestamp - h264parse->last_report; else diff = 0; GST_LOG_OBJECT (h264parse, "now %" GST_TIME_FORMAT ", last SPS/PPS %" GST_TIME_FORMAT, GST_TIME_ARGS (timestamp), GST_TIME_ARGS (h264parse->last_report)); GST_DEBUG_OBJECT (h264parse, "interval since last SPS/PPS %" GST_TIME_FORMAT, GST_TIME_ARGS (diff)); if (GST_TIME_AS_SECONDS (diff) >= h264parse->interval || h264parse->push_codec) { GstBuffer *codec_nal; gint i; GstClockTime new_ts; /* avoid overwriting a perfectly fine timestamp */ new_ts = GST_CLOCK_TIME_IS_VALID (timestamp) ? timestamp : h264parse->last_report; if (h264parse->align == GST_H264_PARSE_ALIGN_NAL) { /* send separate config NAL buffers */ GST_DEBUG_OBJECT (h264parse, "- sending SPS/PPS"); for (i = 0; i < MAX_SPS_COUNT; i++) { if ((codec_nal = h264parse->params->sps_nals[i])) { GST_DEBUG_OBJECT (h264parse, "sending SPS nal"); gst_h264_parse_push_codec_buffer (h264parse, codec_nal, timestamp); h264parse->last_report = new_ts; } } for (i = 0; i < MAX_PPS_COUNT; i++) { if ((codec_nal = h264parse->params->pps_nals[i])) { GST_DEBUG_OBJECT (h264parse, "sending PPS nal"); gst_h264_parse_push_codec_buffer (h264parse, codec_nal, timestamp); h264parse->last_report = new_ts; } } } else { /* insert config NALs into AU */ GstByteWriter bw; GstBuffer *new_buf; const gboolean bs = h264parse->format == GST_H264_PARSE_FORMAT_BYTE; gst_byte_writer_init_with_size (&bw, GST_BUFFER_SIZE (buffer), FALSE); gst_byte_writer_put_data (&bw, GST_BUFFER_DATA (buffer), h264parse->idr_pos); GST_DEBUG_OBJECT (h264parse, "- inserting SPS/PPS"); for (i = 0; i < MAX_SPS_COUNT; i++) { if ((codec_nal = h264parse->params->sps_nals[i])) { GST_DEBUG_OBJECT (h264parse, "inserting SPS nal"); gst_byte_writer_put_uint32_be (&bw, bs ? 1 : GST_BUFFER_SIZE (codec_nal)); gst_byte_writer_put_data (&bw, GST_BUFFER_DATA (codec_nal), GST_BUFFER_SIZE (codec_nal)); h264parse->last_report = new_ts; } } for (i = 0; i < MAX_PPS_COUNT; i++) { if ((codec_nal = h264parse->params->pps_nals[i])) { GST_DEBUG_OBJECT (h264parse, "inserting PPS nal"); gst_byte_writer_put_uint32_be (&bw, bs ? 1 : GST_BUFFER_SIZE (codec_nal)); gst_byte_writer_put_data (&bw, GST_BUFFER_DATA (codec_nal), GST_BUFFER_SIZE (codec_nal)); h264parse->last_report = new_ts; } } gst_byte_writer_put_data (&bw, GST_BUFFER_DATA (buffer) + h264parse->idr_pos, GST_BUFFER_SIZE (buffer) - h264parse->idr_pos); /* collect result and push */ new_buf = gst_byte_writer_reset_and_get_buffer (&bw); gst_buffer_copy_metadata (new_buf, buffer, GST_BUFFER_COPY_ALL); gst_buffer_replace (&frame->buffer, new_buf); } } /* we pushed whatever we had */ h264parse->push_codec = FALSE; } } gst_h264_parse_reset_frame (h264parse); return GST_FLOW_OK; }
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 GstFlowReturn gst_jif_mux_recombine_image (GstJifMux * self, GstBuffer ** new_buf, GstBuffer * old_buf) { GstBuffer *buf; GstByteWriter *writer; GstFlowReturn fret; GstJifMuxMarker *m; GList *node; guint size = self->priv->scan_size; gboolean writer_status = TRUE; /* iterate list and collect size */ for (node = self->priv->markers; node; node = g_list_next (node)) { m = (GstJifMuxMarker *) node->data; /* some markers like e.g. SOI are empty */ if (m->size) { size += 2 + m->size; } /* 0xff <marker> */ size += 2; } GST_INFO_OBJECT (self, "old size: %u, new size: %u", GST_BUFFER_SIZE (old_buf), size); /* allocate new buffer */ fret = gst_pad_alloc_buffer_and_set_caps (self->priv->srcpad, GST_BUFFER_OFFSET (old_buf), size, GST_PAD_CAPS (self->priv->srcpad), &buf); if (fret != GST_FLOW_OK) goto no_buffer; /* copy buffer metadata */ gst_buffer_copy_metadata (buf, old_buf, GST_BUFFER_COPY_FLAGS | GST_BUFFER_COPY_TIMESTAMPS); /* memcopy markers */ writer = gst_byte_writer_new_with_buffer (buf, TRUE); for (node = self->priv->markers; node && writer_status; node = g_list_next (node)) { m = (GstJifMuxMarker *) node->data; writer_status &= gst_byte_writer_put_uint8 (writer, 0xff); writer_status &= gst_byte_writer_put_uint8 (writer, m->marker); GST_DEBUG_OBJECT (self, "marker = %2x, size = %u", m->marker, m->size + 2); if (m->size) { writer_status &= gst_byte_writer_put_uint16_be (writer, m->size + 2); writer_status &= gst_byte_writer_put_data (writer, m->data, m->size); } if (m->marker == SOS) { GST_DEBUG_OBJECT (self, "scan data, size = %u", self->priv->scan_size); writer_status &= gst_byte_writer_put_data (writer, self->priv->scan_data, self->priv->scan_size); } } gst_byte_writer_free (writer); if (!writer_status) { GST_WARNING_OBJECT (self, "Failed to write to buffer, calculated size " "was probably too short"); g_assert_not_reached (); } *new_buf = buf; return GST_FLOW_OK; no_buffer: GST_WARNING_OBJECT (self, "failed to allocate output buffer, flow_ret = %s", gst_flow_get_name (fret)); return fret; }
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; }
static gboolean flx_decode_brun (GstFlxDec * flxdec, GstByteReader * reader, GstByteWriter * writer) { gulong lines, row; g_return_val_if_fail (flxdec != NULL, FALSE); lines = flxdec->hdr.height; while (lines--) { /* packet count. * should not be used anymore, since the flc format can * contain more then 255 RLE packets. we use the frame * width instead. */ if (!gst_byte_reader_skip (reader, 1)) goto error; row = flxdec->hdr.width; while (row) { gint8 count; if (!gst_byte_reader_get_int8 (reader, &count)) goto error; if (count <= 0) { const guint8 *data; /* literal run */ count = ABS (count); GST_LOG_OBJECT (flxdec, "have literal run of size %d", count); if (count > row) { GST_ERROR_OBJECT (flxdec, "Invalid BRUN line detected. " "bytes to write exceeds the end of the row"); return FALSE; } row -= count; if (!gst_byte_reader_get_data (reader, count, &data)) goto error; if (!gst_byte_writer_put_data (writer, data, count)) goto error; } else { guint8 x; GST_LOG_OBJECT (flxdec, "have replicate run of size %d", count); if (count > row) { GST_ERROR_OBJECT (flxdec, "Invalid BRUN packet detected." "bytes to write exceeds the end of the row"); return FALSE; } /* replicate run */ row -= count; if (!gst_byte_reader_get_uint8 (reader, &x)) goto error; if (!gst_byte_writer_fill (writer, x, count)) goto error; } } } return TRUE; error: GST_ERROR_OBJECT (flxdec, "Failed to decode BRUN packet"); return FALSE; }