Exemplo n.º 1
0
static GstFlowReturn
gst_ac3_parse_handle_frame (GstBaseParse * parse,
    GstBaseParseFrame * frame, gint * skipsize)
{
  GstAc3Parse *ac3parse = GST_AC3_PARSE (parse);
  GstBuffer *buf = frame->buffer;
  GstByteReader reader;
  gint off;
  gboolean lost_sync, draining, eac, more = FALSE;
  guint frmsiz, blocks, sid;
  guint rate, chans;
  gboolean update_rate = FALSE;
  gint framesize = 0;
  gint have_blocks = 0;
  GstMapInfo map;
  gboolean ret = FALSE;
  GstFlowReturn res = GST_FLOW_OK;

  gst_buffer_map (buf, &map, GST_MAP_READ);

  if (G_UNLIKELY (map.size < 6)) {
    *skipsize = 1;
    goto cleanup;
  }

  gst_byte_reader_init (&reader, map.data, map.size);
  off = gst_byte_reader_masked_scan_uint32 (&reader, 0xffff0000, 0x0b770000,
      0, map.size);

  GST_LOG_OBJECT (parse, "possible sync at buffer offset %d", off);

  /* didn't find anything that looks like a sync word, skip */
  if (off < 0) {
    *skipsize = map.size - 3;
    goto cleanup;
  }

  /* possible frame header, but not at offset 0? skip bytes before sync */
  if (off > 0) {
    *skipsize = off;
    goto cleanup;
  }

  /* make sure the values in the frame header look sane */
  if (!gst_ac3_parse_frame_header (ac3parse, buf, 0, &frmsiz, &rate, &chans,
          &blocks, &sid, &eac)) {
    *skipsize = off + 2;
    goto cleanup;
  }

  GST_LOG_OBJECT (parse, "size: %u, blocks: %u, rate: %u, chans: %u", frmsiz,
      blocks, rate, chans);

  framesize = frmsiz;

  if (G_UNLIKELY (g_atomic_int_get (&ac3parse->align) ==
          GST_AC3_PARSE_ALIGN_NONE))
    gst_ac3_parse_set_alignment (ac3parse, eac);

  GST_LOG_OBJECT (parse, "got frame");

  lost_sync = GST_BASE_PARSE_LOST_SYNC (parse);
  draining = GST_BASE_PARSE_DRAINING (parse);

  if (g_atomic_int_get (&ac3parse->align) == GST_AC3_PARSE_ALIGN_IEC61937) {
    /* We need 6 audio blocks from each substream, so we keep going forwards
     * till we have it */

    g_assert (blocks > 0);
    GST_LOG_OBJECT (ac3parse, "Need %d frames before pushing", 6 / blocks);

    if (sid != 0) {
      /* We need the first substream to be the one with id 0 */
      GST_LOG_OBJECT (ac3parse, "Skipping till we find sid 0");
      *skipsize = off + 2;
      goto cleanup;
    }

    framesize = 0;

    /* Loop till we have 6 blocks per substream */
    for (have_blocks = 0; !more && have_blocks < 6; have_blocks += blocks) {
      /* Loop till we get one frame from each substream */
      do {
        framesize += frmsiz;

        if (!gst_byte_reader_skip (&reader, frmsiz)
            || map.size < (framesize + 6)) {
          more = TRUE;
          break;
        }

        if (!gst_ac3_parse_frame_header (ac3parse, buf, framesize, &frmsiz,
                NULL, NULL, NULL, &sid, &eac)) {
          *skipsize = off + 2;
          goto cleanup;
        }
      } while (sid);
    }

    /* We're now at the next frame, so no need to skip if resyncing */
    frmsiz = 0;
  }

  if (lost_sync && !draining) {
    guint16 word = 0;

    GST_DEBUG_OBJECT (ac3parse, "resyncing; checking next frame syncword");

    if (more || !gst_byte_reader_skip (&reader, frmsiz) ||
        !gst_byte_reader_get_uint16_be (&reader, &word)) {
      GST_DEBUG_OBJECT (ac3parse, "... but not sufficient data");
      gst_base_parse_set_min_frame_size (parse, framesize + 6);
      *skipsize = 0;
      goto cleanup;
    } else {
      if (word != 0x0b77) {
        GST_DEBUG_OBJECT (ac3parse, "0x%x not OK", word);
        *skipsize = off + 2;
        goto cleanup;
      } else {
        /* ok, got sync now, let's assume constant frame size */
        gst_base_parse_set_min_frame_size (parse, framesize);
      }
    }
  }

  /* expect to have found a frame here */
  g_assert (framesize);
  ret = TRUE;

  /* arrange for metadata setup */
  if (G_UNLIKELY (sid)) {
    /* dependent frame, no need to (ac)count for or consider further */
    GST_LOG_OBJECT (parse, "sid: %d", sid);
    frame->flags |= GST_BASE_PARSE_FRAME_FLAG_NO_FRAME;
    /* TODO maybe also mark as DELTA_UNIT,
     * if that does not surprise baseparse elsewhere */
    /* occupies same time space as previous base frame */
    if (G_LIKELY (GST_BUFFER_TIMESTAMP (buf) >= GST_BUFFER_DURATION (buf)))
      GST_BUFFER_TIMESTAMP (buf) -= GST_BUFFER_DURATION (buf);
    /* only shortcut if we already arranged for caps */
    if (G_LIKELY (ac3parse->sample_rate > 0))
      goto cleanup;
  }

  if (G_UNLIKELY (ac3parse->sample_rate != rate || ac3parse->channels != chans
          || ac3parse->eac != eac)) {
    GstCaps *caps = gst_caps_new_simple (eac ? "audio/x-eac3" : "audio/x-ac3",
        "framed", G_TYPE_BOOLEAN, TRUE, "rate", G_TYPE_INT, rate,
        "channels", G_TYPE_INT, chans, NULL);
    gst_caps_set_simple (caps, "alignment", G_TYPE_STRING,
        g_atomic_int_get (&ac3parse->align) == GST_AC3_PARSE_ALIGN_IEC61937 ?
        "iec61937" : "frame", NULL);
    gst_pad_set_caps (GST_BASE_PARSE_SRC_PAD (parse), caps);
    gst_caps_unref (caps);

    ac3parse->sample_rate = rate;
    ac3parse->channels = chans;
    ac3parse->eac = eac;

    update_rate = TRUE;
  }

  if (G_UNLIKELY (ac3parse->blocks != blocks)) {
    ac3parse->blocks = blocks;

    update_rate = TRUE;
  }

  if (G_UNLIKELY (update_rate))
    gst_base_parse_set_frame_rate (parse, rate, 256 * blocks, 2, 2);

cleanup:
  gst_buffer_unmap (buf, &map);

  if (ret && framesize <= map.size) {
    res = gst_base_parse_finish_frame (parse, frame, framesize);
  }

  return res;
}
Exemplo n.º 2
0
static GstFlowReturn
gst_dirac_parse_handle_frame (GstBaseParse * parse,
    GstBaseParseFrame * frame, gint * skipsize)
{
  int off;
  guint32 next_header;
  GstMapInfo map;
  guint8 *data;
  gsize size;
  gboolean have_picture = FALSE;
  int offset;
  guint framesize = 0;

  gst_buffer_map (frame->buffer, &map, GST_MAP_READ);
  data = map.data;
  size = map.size;

  if (G_UNLIKELY (size < 13)) {
    *skipsize = 1;
    goto out;
  }

  GST_DEBUG ("%" G_GSIZE_FORMAT ": %02x %02x %02x %02x", size, data[0], data[1],
      data[2], data[3]);

  if (GST_READ_UINT32_BE (data) != 0x42424344) {
    GstByteReader reader;

    gst_byte_reader_init (&reader, data, size);
    off = gst_byte_reader_masked_scan_uint32 (&reader, 0xffffffff,
        0x42424344, 0, size);

    if (off < 0) {
      *skipsize = size - 3;
      goto out;
    }

    GST_LOG_OBJECT (parse, "possible sync at buffer offset %d", off);

    GST_DEBUG ("skipping %d", off);
    *skipsize = off;
    goto out;
  }

  /* have sync, parse chunks */

  offset = 0;
  while (!have_picture) {
    GST_DEBUG ("offset %d:", offset);

    if (offset + 13 >= size) {
      framesize = offset + 13;
      goto out;
    }

    GST_DEBUG ("chunk type %02x", data[offset + 4]);

    if (GST_READ_UINT32_BE (data + offset) != 0x42424344) {
      GST_DEBUG ("bad header");
      *skipsize = 3;
      goto out;
    }

    next_header = GST_READ_UINT32_BE (data + offset + 5);
    GST_DEBUG ("next_header %d", next_header);
    if (next_header == 0)
      next_header = 13;

    if (SCHRO_PARSE_CODE_IS_PICTURE (data[offset + 4])) {
      have_picture = TRUE;
    }

    offset += next_header;
    if (offset >= size) {
      framesize = offset;
      goto out;
    }
  }

  gst_buffer_unmap (frame->buffer, &map);

  framesize = offset;
  GST_DEBUG ("framesize %d", framesize);

  g_assert (framesize <= size);

  if (data[4] == SCHRO_PARSE_CODE_SEQUENCE_HEADER) {
    GstCaps *caps;
    GstDiracParse *diracparse = GST_DIRAC_PARSE (parse);
    DiracSequenceHeader sequence_header;
    int ret;

    ret = dirac_sequence_header_parse (&sequence_header, data + 13, size - 13);
    if (ret) {
      memcpy (&diracparse->sequence_header, &sequence_header,
          sizeof (sequence_header));
      caps = gst_caps_new_simple ("video/x-dirac",
          "width", G_TYPE_INT, sequence_header.width,
          "height", G_TYPE_INT, sequence_header.height,
          "framerate", GST_TYPE_FRACTION,
          sequence_header.frame_rate_numerator,
          sequence_header.frame_rate_denominator,
          "pixel-aspect-ratio", GST_TYPE_FRACTION,
          sequence_header.aspect_ratio_numerator,
          sequence_header.aspect_ratio_denominator,
          "interlaced", G_TYPE_BOOLEAN, sequence_header.interlaced,
          "profile", G_TYPE_INT, sequence_header.profile,
          "level", G_TYPE_INT, sequence_header.level, NULL);
      gst_pad_set_caps (GST_BASE_PARSE_SRC_PAD (parse), caps);
      gst_caps_unref (caps);

      gst_base_parse_set_frame_rate (parse,
          sequence_header.frame_rate_numerator,
          sequence_header.frame_rate_denominator, 0, 0);
    }
  }

  gst_base_parse_set_min_frame_size (parse, 13);

  return gst_base_parse_finish_frame (parse, frame, framesize);

out:
  gst_buffer_unmap (frame->buffer, &map);
  if (framesize)
    gst_base_parse_set_min_frame_size (parse, framesize);
  return GST_FLOW_OK;
}
Exemplo n.º 3
0
static GstFlowReturn
gst_h263_parse_handle_frame (GstBaseParse * parse,
    GstBaseParseFrame * frame, gint * skipsize)
{
  GstH263Parse *h263parse;
  GstBuffer *buffer;
  guint psc_pos, next_psc_pos;
  gsize size;
  H263Params params = { 0, };
  GstFlowReturn res = GST_FLOW_OK;

  h263parse = GST_H263_PARSE (parse);
  buffer = frame->buffer;
  size = gst_buffer_get_size (buffer);

  if (size < 3) {
    *skipsize = 1;
    return GST_FLOW_OK;
  }

  psc_pos = find_psc (buffer, 0);

  if (psc_pos == -1) {
    /* PSC not found, need more data */
    if (size > 3)
      psc_pos = size - 3;
    else
      psc_pos = 0;
    goto more;
  }

  /* need to skip */
  if (psc_pos > 0)
    goto more;

  /* Found the start of the frame, now try to find the end */
  next_psc_pos = psc_pos + 3;
  next_psc_pos = find_psc (buffer, next_psc_pos);

  if (next_psc_pos == -1) {
    if (GST_BASE_PARSE_DRAINING (parse))
      /* FLUSH/EOS, it's okay if we can't find the next frame */
      next_psc_pos = size;
    else
      goto more;
  }

  /* We should now have a complete frame */

  /* If this is the first frame, parse and set srcpad caps */
  if (h263parse->state == PARSING) {
    res = gst_h263_parse_get_params (&params, buffer, FALSE, &h263parse->state);
    if (res != GST_FLOW_OK || h263parse->state != GOT_HEADER) {
      GST_WARNING ("Couldn't parse header - setting passthrough mode");
      gst_base_parse_set_passthrough (parse, TRUE);
    } else {
      /* Set srcpad caps since we now have sufficient information to do so */
      gst_h263_parse_set_src_caps (h263parse, &params);
      gst_base_parse_set_passthrough (parse, FALSE);
    }
    memset (&params, 0, sizeof (params));
  }

  /* XXX: After getting a keyframe, should we adjust min_frame_size to
   * something smaller so we don't end up collecting too many non-keyframes? */

  GST_DEBUG_OBJECT (h263parse, "found a frame of size %u at pos %u",
      next_psc_pos, psc_pos);

  res = gst_h263_parse_get_params (&params, buffer, TRUE, &h263parse->state);
  if (res != GST_FLOW_OK)
    goto more;

  if (h263parse->state == PASSTHROUGH || h263parse->state == PARSING) {
    /* There's a feature we don't support, or we didn't have enough data to
     * parse the header, which should not be possible. Either way, go into
     * passthrough mode and let downstream handle it if it can. */
    GST_WARNING ("Couldn't parse header - setting passthrough mode");
    gst_base_parse_set_passthrough (parse, TRUE);
    goto more;
  }

  if (gst_h263_parse_is_delta_unit (&params))
    GST_BUFFER_FLAG_UNSET (buffer, GST_BUFFER_FLAG_DELTA_UNIT);
  else
    GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DELTA_UNIT);

  return gst_base_parse_finish_frame (parse, frame, next_psc_pos);

more:
  *skipsize = psc_pos;

  return res;
}
Exemplo n.º 4
0
static GstFlowReturn
gst_irtsp_parse_handle_frame (GstBaseParse * parse,
    GstBaseParseFrame * frame, gint * skipsize)
{
  GstIRTSPParse *IRTSPParse = GST_IRTSP_PARSE (parse);
  GstBuffer *buf = frame->buffer;
  GstByteReader reader;
  gint off;
  GstMapInfo map;
  guint framesize;

  gst_buffer_map (buf, &map, GST_MAP_READ);
  if (G_UNLIKELY (map.size < 4))
    goto exit;

  gst_byte_reader_init (&reader, map.data, map.size);

  off = gst_byte_reader_masked_scan_uint32 (&reader, 0xffff0000,
      0x24000000 + (IRTSPParse->channel_id << 16), 0, map.size);

  GST_LOG_OBJECT (parse, "possible sync at buffer offset %d", off);

  /* didn't find anything that looks like a sync word, skip */
  if (off < 0) {
    *skipsize = map.size - 3;
    goto exit;
  }

  /* possible frame header, but not at offset 0? skip bytes before sync */
  if (off > 0) {
    *skipsize = off;
    goto exit;
  }

  framesize = GST_READ_UINT16_BE (map.data + 2) + 4;
  GST_LOG_OBJECT (parse, "got frame size %d", framesize);

  if (!gst_pad_has_current_caps (GST_BASE_PARSE_SRC_PAD (parse))) {
    GstCaps *caps;

    caps = gst_caps_new_empty_simple ("application/x-rtp");
    gst_pad_set_caps (GST_BASE_PARSE_SRC_PAD (parse), caps);
    gst_caps_unref (caps);
  }

  if (framesize <= map.size) {
    gst_buffer_unmap (buf, &map);
    /* HACK HACK skip header.
     * could also ask baseparse to skip this,
     * but that would give us a discontinuity for free
     * which is a bit too much to have on all our packets */
    frame->out_buffer = gst_buffer_copy (frame->buffer);
    gst_buffer_resize (frame->out_buffer, 4, -1);
    GST_BUFFER_FLAG_UNSET (frame->out_buffer, GST_BUFFER_FLAG_DISCONT);
    return gst_base_parse_finish_frame (parse, frame, framesize);
  }

exit:
  gst_buffer_unmap (buf, &map);
  return GST_FLOW_OK;
}
Exemplo n.º 5
0
static GstFlowReturn
gst_mpegv_parse_handle_frame (GstBaseParse * parse,
    GstBaseParseFrame * frame, gint * skipsize)
{
  GstFlowReturn flowret = GST_FLOW_OK;
  GstMpegvParse *mpvparse = GST_MPEGVIDEO_PARSE (parse);
  GstBuffer *buf = frame->buffer;
  gboolean ret = FALSE;
  gint off = 0;
  GstMpegVideoPacket packet;
  guint8 *data;
  gint size;
  GstMapInfo map;

  update_frame_parsing_status (mpvparse, frame);

  gst_buffer_map (buf, &map, GST_MAP_READ);
  data = map.data;
  size = map.size;

retry:
  /* at least start code and subsequent byte */
  if (G_UNLIKELY (size < 5 + off))
    goto exit;

  /* if already found a previous start code, e.g. start of frame, go for next */
  if (mpvparse->last_sc >= 0) {
    off = packet.offset = mpvparse->last_sc;
    packet.size = 0;
    goto next;
  }

  if (!gst_mpeg_video_parse (&packet, data, size, off)) {
    /* didn't find anything that looks like a sync word, skip */
    GST_LOG_OBJECT (mpvparse, "no start code found");
    *skipsize = size - 3;
    goto exit;
  }

  off = packet.offset - 4;
  GST_LOG_OBJECT (mpvparse, "possible sync at buffer offset %d", off);

  /* possible frame header, but not at offset 0? skip bytes before sync */
  if (G_UNLIKELY (off > 0)) {
    *skipsize = off;
    goto exit;
  }

  /* note: initial start code is assumed at offset 0 by subsequent code */

  /* examine start code, see if it looks like an initial start code */
  if (gst_mpegv_parse_process_sc (mpvparse, &map, 4, &packet)) {
    /* found sc */
    GST_LOG_OBJECT (mpvparse, "valid start code found");
    mpvparse->last_sc = 0;
  } else {
    off++;
    gst_mpegv_parse_reset_frame (mpvparse);
    GST_LOG_OBJECT (mpvparse, "invalid start code");
    goto retry;
  }

next:
  /* start is fine as of now */
  *skipsize = 0;
  /* terminating start code may have been found in prev scan already */
  if (((gint) packet.size) >= 0) {
    off = packet.offset + packet.size;
    /* so now we have start code at start of data; locate next start code */
    if (!gst_mpeg_video_parse (&packet, data, size, off)) {
      off = -1;
    } else {
      g_assert (packet.offset >= 4);
      off = packet.offset - 4;
    }
  } else {
    off = -1;
  }

  GST_LOG_OBJECT (mpvparse, "next start code at %d", off);
  if (off < 0) {
    /* if draining, take all */
    if (GST_BASE_PARSE_DRAINING (parse)) {
      GST_LOG_OBJECT (mpvparse, "draining, accepting all data");
      off = size;
      ret = TRUE;
    } else {
      GST_LOG_OBJECT (mpvparse, "need more data");
      /* resume scan where we left it */
      mpvparse->last_sc = size - 3;
      /* request best next available */
      off = G_MAXUINT;
      goto exit;
    }
  } else {
    /* decide whether this startcode ends a frame */
    ret = gst_mpegv_parse_process_sc (mpvparse, &map, off + 4, &packet);
  }

  if (!ret)
    goto next;

exit:
  gst_buffer_unmap (buf, &map);

  if (ret) {
    GstFlowReturn res;

    *skipsize = 0;
    g_assert (off <= map.size);
    res = gst_mpegv_parse_parse_frame (parse, frame);
    if (res == GST_BASE_PARSE_FLOW_DROPPED)
      frame->flags |= GST_BASE_PARSE_FRAME_FLAG_DROP;
    flowret = gst_base_parse_finish_frame (parse, frame, off);
    /* Reset local information */
    mpvparse->seqhdr_updated = FALSE;
    mpvparse->seqext_updated = FALSE;
    mpvparse->seqdispext_updated = FALSE;
    mpvparse->picext_updated = FALSE;
    mpvparse->quantmatrext_updated = FALSE;
  }

  return flowret;
}