Esempio n. 1
0
/* see if pads were added or removed and update our stats. Any pad
 * added after releasing the PAD_LOCK will get collected in the next
 * round.
 *
 * We can do a quick check by checking the cookies, that get changed
 * whenever the pad list is updated.
 *
 * Must be called with LOCK.
 */
static void
gst_collect_pads_check_pads_unlocked (GstCollectPads * pads)
{
  GST_DEBUG ("stored cookie : %d, used_cookie:%d",
      pads->abidata.ABI.pad_cookie, pads->cookie);
  if (G_UNLIKELY (pads->abidata.ABI.pad_cookie != pads->cookie)) {
    GSList *collected;

    /* clear list and stats */
    g_slist_foreach (pads->data, (GFunc) unref_data, NULL);
    g_slist_free (pads->data);
    pads->data = NULL;
    pads->numpads = 0;
    pads->queuedpads = 0;
    pads->eospads = 0;

    /* loop over the master pad list */
    collected = pads->abidata.ABI.pad_list;
    for (; collected; collected = g_slist_next (collected)) {
      GstCollectData *data;

      /* update the stats */
      pads->numpads++;
      data = collected->data;

      if (G_LIKELY (!data->abidata.ABI.flushing)) {
        if (data->buffer)
          pads->queuedpads++;
        if (data->abidata.ABI.eos)
          pads->eospads++;
      }

      /* add to the list of pads to collect */
      ref_data (data);
      pads->data = g_slist_prepend (pads->data, data);
    }
    /* and update the cookie */
    pads->cookie = pads->abidata.ABI.pad_cookie;
  }
}
    void MultiChannelCartesianGrappaReconGadget::make_ref_coil_map(IsmrmrdDataBuffered& ref_, std::vector<size_t>  recon_dims, ReconObjType& recon_obj, size_t encoding)
    {

        try
        {
            hoNDArray< std::complex<float> >& ref_data = ref_.data_;
            hoNDArray< std::complex<float> >& ref_calib = recon_obj.ref_calib_;
            hoNDArray< std::complex<float> >& ref_coil_map = recon_obj.ref_coil_map_;

            // sampling limits
            size_t sRO = ref_.sampling_.sampling_limits_[0].min_;
            size_t eRO = ref_.sampling_.sampling_limits_[0].max_;
            size_t cRO = ref_.sampling_.sampling_limits_[0].center_;

            size_t sE1 = ref_.sampling_.sampling_limits_[1].min_;
            size_t eE1 = ref_.sampling_.sampling_limits_[1].max_;
            size_t cE1 = ref_.sampling_.sampling_limits_[1].center_;

            size_t sE2 = ref_.sampling_.sampling_limits_[2].min_;
            size_t eE2 = ref_.sampling_.sampling_limits_[2].max_;
            size_t cE2 = ref_.sampling_.sampling_limits_[2].center_;

            // recon size
            size_t recon_RO = recon_dims[0];
            size_t recon_E1 = recon_dims[1];
            size_t recon_E2 = recon_dims[2];

            // ref array size
            size_t CHA = ref_data.get_size(3);
            size_t N = ref_data.get_size(4);
            size_t S = ref_data.get_size(5);
            size_t SLC = ref_data.get_size(6);

            // determine the ref_coil_map size
            size_t RO = 2 * cRO;
            if (sRO>0 || eRO<RO - 1)
            {
                RO = 2 * std::max(cRO - sRO, eRO - cRO+1);
                if (RO>recon_RO) RO = recon_RO;
            }

            size_t E1 = eE1 - sE1 + 1;
            size_t E2 = eE2 - sE2 + 1;

            if ((calib_mode_[encoding] == Gadgetron::ISMRMRD_interleaved) || (calib_mode_[encoding] == Gadgetron::ISMRMRD_noacceleration))
            {
                E1 = 2 * std::max(cE1 - sE1, eE1 - cE1+1);
                if (E1>recon_E1) E1 = recon_E1;

                if (E2 > 1)
                {
                    E2 = 2 * std::max(cE2 - sE2, eE2 - cE2 + 1);
                    if (E2 > recon_E2) E2 = recon_E2;
                }
            }

            ref_coil_map.create(RO, E1, E2, CHA, N, S, SLC);
            Gadgetron::clear(ref_coil_map);

            size_t slc, s, n, cha, e2, e1;
            for (slc = 0; slc < SLC; slc++)
            {
                for (s = 0; s < S; s++)
                {
                    for (n = 0; n < N; n++)
                    {
                        for (cha = 0; cha < CHA; cha++)
                        {
                            for (e2 = sE2; e2 <= eE2; e2++)
                            {
                                for (e1 = sE1; e1 <= eE1; e1++)
                                {
                                    std::complex<float>* pSrc = &(ref_data(0, e1-sE1, e2-sE2, cha, n, s, slc));
                                    std::complex<float>* pDst = &(ref_coil_map(0, e1, e2, cha, n, s, slc));

                                    memcpy(pDst + sRO, pSrc, sizeof(std::complex<float>)*(eRO - sRO + 1));
                                }
                            }
                        }
                    }
                }
            }

            // filter the ref_coil_map
            if (filter_RO_ref_coi_map_.get_size(0) != RO)
            {
                Gadgetron::generate_symmetric_filter_ref(ref_coil_map.get_size(0), ref_.sampling_.sampling_limits_[0].min_, ref_.sampling_.sampling_limits_[0].max_, filter_RO_ref_coi_map_);
            }

            if (filter_E1_ref_coi_map_.get_size(0) != E1)
            {
                Gadgetron::generate_symmetric_filter_ref(ref_coil_map.get_size(1), ref_.sampling_.sampling_limits_[1].min_, ref_.sampling_.sampling_limits_[1].max_, filter_E1_ref_coi_map_);
            }

            if ( (E2 > 1) && (filter_E2_ref_coi_map_.get_size(0) != E2) )
            {
                Gadgetron::generate_symmetric_filter_ref(ref_coil_map.get_size(2), ref_.sampling_.sampling_limits_[2].min_, ref_.sampling_.sampling_limits_[2].max_, filter_E2_ref_coi_map_);
            }

            hoNDArray< std::complex<float> > ref_recon_buf;

            if (E2 > 1)
            {
                Gadgetron::apply_kspace_filter_ROE1E2(ref_coil_map, filter_RO_ref_coi_map_, filter_E1_ref_coi_map_, filter_E2_ref_coi_map_, ref_recon_buf);
            }
            else
            {
                Gadgetron::apply_kspace_filter_ROE1(ref_coil_map, filter_RO_ref_coi_map_, filter_E1_ref_coi_map_, ref_recon_buf);
            }

            // pad the ref_coil_map into the data array
            Gadgetron::pad(recon_RO, recon_E1, recon_E2, &ref_recon_buf, &ref_coil_map);

            std::vector<size_t> dim = *ref_data.get_dimensions();
            ref_calib.create(dim, ref_data.begin());

        }
        catch (...)
        {
            GADGET_THROW("Errors happened in MultiChannelCartesianGrappaReconGadget::make_ref_coil_map(...) ... ");
        }
    }
Esempio n. 3
0
/* For each buffer we receive we check if our collected condition is reached
 * and if so we call the collected function. When this is done we check if
 * data has been unqueued. If data is still queued we wait holding the stream
 * lock to make sure no EOS event can happen while we are ready to be
 * collected 
 */
static GstFlowReturn
gst_collect_pads_chain (GstPad * pad, GstBuffer * buffer)
{
  GstCollectData *data;
  GstCollectPads *pads;
  GstCollectPadsPrivate *priv;
  GstFlowReturn ret;

  GST_DEBUG ("Got buffer for pad %s:%s", GST_DEBUG_PAD_NAME (pad));

  /* some magic to get the managing collect_pads */
  GST_OBJECT_LOCK (pad);
  data = (GstCollectData *) gst_pad_get_element_private (pad);
  if (G_UNLIKELY (data == NULL))
    goto no_data;
  ref_data (data);
  GST_OBJECT_UNLOCK (pad);

  pads = data->collect;
  priv = pads->abidata.ABI.priv;

  GST_OBJECT_LOCK (pads);
  /* if not started, bail out */
  if (G_UNLIKELY (!pads->started))
    goto not_started;
  /* check if this pad is flushing */
  if (G_UNLIKELY (data->abidata.ABI.flushing))
    goto flushing;
  /* pad was EOS, we can refuse this data */
  if (G_UNLIKELY (data->abidata.ABI.eos))
    goto unexpected;

  /* see if we need to clip */
  if (priv->clipfunc) {
    buffer = priv->clipfunc (pads, data, buffer, priv->clipfunc_user_data);

    if (G_UNLIKELY (buffer == NULL))
      goto clipped;
  }

  GST_DEBUG ("Queuing buffer %p for pad %s:%s", buffer,
      GST_DEBUG_PAD_NAME (pad));

  /* One more pad has data queued */
  pads->queuedpads++;
  /* take ownership of the buffer */
  if (data->buffer)
    gst_buffer_unref (data->buffer);
  data->buffer = buffer;
  buffer = NULL;

  /* update segment last position if in TIME */
  if (G_LIKELY (data->segment.format == GST_FORMAT_TIME)) {
    GstClockTime timestamp = GST_BUFFER_TIMESTAMP (data->buffer);

    if (GST_CLOCK_TIME_IS_VALID (timestamp))
      gst_segment_set_last_stop (&data->segment, GST_FORMAT_TIME, timestamp);
  }

  /* While we have data queued on this pad try to collect stuff */
  do {
    GST_DEBUG ("Pad %s:%s checking", GST_DEBUG_PAD_NAME (pad));
    /* Check if our collected condition is matched and call the collected function
     * if it is */
    ret = gst_collect_pads_check_collected (pads);
    /* when an error occurs, we want to report this back to the caller ASAP
     * without having to block if the buffer was not popped */
    if (G_UNLIKELY (ret != GST_FLOW_OK))
      goto error;

    /* data was consumed, we can exit and accept new data */
    if (data->buffer == NULL)
      break;

    /* Check if we got removed in the mean time, FIXME, this is racy.
     * Between this check and the _WAIT, the pad could be removed which will
     * makes us hang in the _WAIT. */
    GST_OBJECT_LOCK (pad);
    if (G_UNLIKELY (gst_pad_get_element_private (pad) == NULL))
      goto pad_removed;
    GST_OBJECT_UNLOCK (pad);

    GST_DEBUG ("Pad %s:%s has a buffer queued, waiting",
        GST_DEBUG_PAD_NAME (pad));

    /* wait to be collected, this must happen from another thread triggered
     * by the _chain function of another pad. We release the lock so we
     * can get stopped or flushed as well. We can however not get EOS
     * because we still hold the STREAM_LOCK. 
     */
    GST_COLLECT_PADS_WAIT (pads);

    GST_DEBUG ("Pad %s:%s resuming", GST_DEBUG_PAD_NAME (pad));

    /* after a signal, we could be stopped */
    if (G_UNLIKELY (!pads->started))
      goto not_started;
    /* check if this pad is flushing */
    if (G_UNLIKELY (data->abidata.ABI.flushing))
      goto flushing;
  }
  while (data->buffer != NULL);

unlock_done:
  GST_DEBUG ("Pad %s:%s done", GST_DEBUG_PAD_NAME (pad));
  GST_OBJECT_UNLOCK (pads);
  unref_data (data);
  if (buffer)
    gst_buffer_unref (buffer);
  return ret;

pad_removed:
  {
    GST_WARNING ("%s got removed from collectpads", GST_OBJECT_NAME (pad));
    GST_OBJECT_UNLOCK (pad);
    ret = GST_FLOW_NOT_LINKED;
    goto unlock_done;
  }
  /* ERRORS */
no_data:
  {
    GST_DEBUG ("%s got removed from collectpads", GST_OBJECT_NAME (pad));
    GST_OBJECT_UNLOCK (pad);
    gst_buffer_unref (buffer);
    return GST_FLOW_NOT_LINKED;
  }
not_started:
  {
    GST_DEBUG ("not started");
    gst_collect_pads_clear (pads, data);
    ret = GST_FLOW_WRONG_STATE;
    goto unlock_done;
  }
flushing:
  {
    GST_DEBUG ("pad %s:%s is flushing", GST_DEBUG_PAD_NAME (pad));
    gst_collect_pads_clear (pads, data);
    ret = GST_FLOW_WRONG_STATE;
    goto unlock_done;
  }
unexpected:
  {
    /* we should not post an error for this, just inform upstream that
     * we don't expect anything anymore */
    GST_DEBUG ("pad %s:%s is eos", GST_DEBUG_PAD_NAME (pad));
    ret = GST_FLOW_UNEXPECTED;
    goto unlock_done;
  }
clipped:
  {
    GST_DEBUG ("clipped buffer on pad %s:%s", GST_DEBUG_PAD_NAME (pad));
    ret = GST_FLOW_OK;
    goto unlock_done;
  }
error:
  {
    /* we print the error, the element should post a reasonable error
     * message for fatal errors */
    GST_DEBUG ("collect failed, reason %d (%s)", ret, gst_flow_get_name (ret));
    gst_collect_pads_clear (pads, data);
    goto unlock_done;
  }
}
Esempio n. 4
0
static gboolean
gst_collect_pads_event (GstPad * pad, GstEvent * event)
{
  gboolean res;
  GstCollectData *data;
  GstCollectPads *pads;

  /* some magic to get the managing collect_pads */
  GST_OBJECT_LOCK (pad);
  data = (GstCollectData *) gst_pad_get_element_private (pad);
  if (G_UNLIKELY (data == NULL))
    goto pad_removed;
  ref_data (data);
  GST_OBJECT_UNLOCK (pad);

  res = TRUE;

  pads = data->collect;

  GST_DEBUG ("Got %s event on pad %s:%s", GST_EVENT_TYPE_NAME (event),
      GST_DEBUG_PAD_NAME (data->pad));

  switch (GST_EVENT_TYPE (event)) {
    case GST_EVENT_FLUSH_START:
    {
      /* forward event to unblock check_collected */
      gst_pad_event_default (pad, event);

      /* now unblock the chain function.
       * no cond per pad, so they all unblock, 
       * non-flushing block again */
      GST_OBJECT_LOCK (pads);
      data->abidata.ABI.flushing = TRUE;
      gst_collect_pads_clear (pads, data);
      GST_OBJECT_UNLOCK (pads);

      /* event already cleaned up by forwarding */
      goto done;
    }
    case GST_EVENT_FLUSH_STOP:
    {
      /* flush the 1 buffer queue */
      GST_OBJECT_LOCK (pads);
      data->abidata.ABI.flushing = FALSE;
      gst_collect_pads_clear (pads, data);
      /* we need new segment info after the flush */
      gst_segment_init (&data->segment, GST_FORMAT_UNDEFINED);
      data->abidata.ABI.new_segment = FALSE;
      /* if the pad was EOS, remove the EOS flag and
       * decrement the number of eospads */
      if (G_UNLIKELY (data->abidata.ABI.eos == TRUE)) {
        pads->eospads--;
        data->abidata.ABI.eos = FALSE;
      }

      if (!gst_collect_pads_is_flushing (pads)) {
        /* forward event if all pads are no longer flushing */
        GST_DEBUG ("No more pads are flushing, forwarding FLUSH_STOP");
        GST_OBJECT_UNLOCK (pads);
        goto forward;
      }
      gst_event_unref (event);
      GST_OBJECT_UNLOCK (pads);
      goto done;
    }
    case GST_EVENT_EOS:
    {
      GST_OBJECT_LOCK (pads);
      /* if the pad was not EOS, make it EOS and so we
       * have one more eospad */
      if (G_LIKELY (data->abidata.ABI.eos == FALSE)) {
        data->abidata.ABI.eos = TRUE;
        pads->eospads++;
      }
      /* check if we need collecting anything, we ignore the
       * result. */
      gst_collect_pads_check_collected (pads);
      GST_OBJECT_UNLOCK (pads);

      /* We eat this event, element should do something
       * in the collected callback. */
      gst_event_unref (event);
      goto done;
    }
    case GST_EVENT_NEWSEGMENT:
    {
      gint64 start, stop, time;
      gdouble rate, arate;
      GstFormat format;
      gboolean update;

      gst_event_parse_new_segment_full (event, &update, &rate, &arate, &format,
          &start, &stop, &time);

      GST_DEBUG_OBJECT (data->pad, "got newsegment, start %" GST_TIME_FORMAT
          ", stop %" GST_TIME_FORMAT, GST_TIME_ARGS (start),
          GST_TIME_ARGS (stop));

      gst_segment_set_newsegment_full (&data->segment, update, rate, arate,
          format, start, stop, time);

      data->abidata.ABI.new_segment = TRUE;

      /* we must not forward this event since multiple segments will be 
       * accumulated and this is certainly not what we want. */
      gst_event_unref (event);
      /* FIXME: collect-pads based elements need to create their own newsegment
       * event (and only one really)
       * (a) make the segment part of the GstCollectData structure of each pad,
       * so you can just check that once you have a buffer queued on that pad,
       * (b) you can override a pad's event function with your own,
       * catch the newsegment event and then pass it on to the original
       * gstcollectpads event function
       * (that's what avimux does for something IIRC)
       * see #340060
       */
      goto done;
    }
    default:
      /* forward other events */
      goto forward;
  }

forward:
  GST_DEBUG_OBJECT (pads, "forward unhandled event: %s",
      GST_EVENT_TYPE_NAME (event));
  res = gst_pad_event_default (pad, event);

done:
  unref_data (data);
  return res;

  /* ERRORS */
pad_removed:
  {
    GST_DEBUG ("%s got removed from collectpads", GST_OBJECT_NAME (pad));
    GST_OBJECT_UNLOCK (pad);
    return FALSE;
  }
}