Example #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);
}
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;
}
Example #3
0
/**
 * 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);
}
Example #4
0
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;
}
Example #5
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);
}
Example #6
0
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;
}