/* the first caps we receive on any of the sinkpads will define the caps for all
 * the other sinkpads because we can only mix streams with the same caps.
 * */
static gboolean
gst_live_adder_setcaps (GstPad * pad, GstCaps * caps)
{
    GstLiveAdder *adder;
    GList *pads;
    GstStructure *structure;
    const char *media_type;

    adder = GST_LIVE_ADDER (GST_PAD_PARENT (pad));

    GST_LOG_OBJECT (adder, "setting caps on pad %p,%s to %" GST_PTR_FORMAT, pad,
                    GST_PAD_NAME (pad), caps);

    /* FIXME, see if the other pads can accept the format. Also lock the
     * format on the other pads to this new format. */
    GST_OBJECT_LOCK (adder);
    pads = GST_ELEMENT (adder)->pads;
    while (pads) {
        GstPad *otherpad = GST_PAD (pads->data);

        if (otherpad != pad)
            gst_caps_replace (&GST_PAD_CAPS (otherpad), caps);

        pads = g_list_next (pads);
    }

    /* parse caps now */
    structure = gst_caps_get_structure (caps, 0);
    media_type = gst_structure_get_name (structure);
    if (strcmp (media_type, "audio/x-raw-int") == 0) {
        GST_DEBUG_OBJECT (adder, "parse_caps sets adder to format int");
        adder->format = GST_LIVE_ADDER_FORMAT_INT;
        gst_structure_get_int (structure, "width", &adder->width);
        gst_structure_get_int (structure, "depth", &adder->depth);
        gst_structure_get_int (structure, "endianness", &adder->endianness);
        gst_structure_get_boolean (structure, "signed", &adder->is_signed);

        if (adder->endianness != G_BYTE_ORDER)
            goto not_supported;

        switch (adder->width) {
        case 8:
            adder->func = (adder->is_signed ?
                           (GstLiveAdderFunction) add_int8 : (GstLiveAdderFunction) add_uint8);
            break;
        case 16:
            adder->func = (adder->is_signed ?
                           (GstLiveAdderFunction) add_int16 : (GstLiveAdderFunction)
                           add_uint16);
            break;
        case 32:
            adder->func = (adder->is_signed ?
                           (GstLiveAdderFunction) add_int32 : (GstLiveAdderFunction)
                           add_uint32);
            break;
        default:
            goto not_supported;
        }
    } else if (strcmp (media_type, "audio/x-raw-float") == 0) {
        GST_DEBUG_OBJECT (adder, "parse_caps sets adder to format float");
        adder->format = GST_LIVE_ADDER_FORMAT_FLOAT;
        gst_structure_get_int (structure, "width", &adder->width);

        switch (adder->width) {
        case 32:
            adder->func = (GstLiveAdderFunction) add_float32;
            break;
        case 64:
            adder->func = (GstLiveAdderFunction) add_float64;
            break;
        default:
            goto not_supported;
        }
    } else {
        goto not_supported;
    }

    gst_structure_get_int (structure, "channels", &adder->channels);
    gst_structure_get_int (structure, "rate", &adder->rate);
    /* precalc bps */
    adder->bps = (adder->width / 8) * adder->channels;

    GST_OBJECT_UNLOCK (adder);
    return TRUE;

    /* ERRORS */
not_supported:
    {
        GST_OBJECT_UNLOCK (adder);
        GST_DEBUG_OBJECT (adder, "unsupported format set as caps");
        return FALSE;
    }
}
Exemple #2
0
static GstFlowReturn
theora_enc_chain (GstPad * pad, GstBuffer * buffer)
{
  GstTheoraEnc *enc;
  ogg_packet op;
  GstClockTime timestamp, duration, running_time;
  GstFlowReturn ret;
  gboolean force_keyframe;

  enc = GST_THEORA_ENC (GST_PAD_PARENT (pad));

  /* we keep track of two timelines.
   * - The timestamps from the incomming buffers, which we copy to the outgoing
   *   encoded buffers as-is. We need to do this as we simply forward the
   *   newsegment events.
   * - The running_time of the buffers, which we use to construct the granulepos
   *   in the packets.
   */
  timestamp = GST_BUFFER_TIMESTAMP (buffer);
  duration = GST_BUFFER_DURATION (buffer);

  running_time =
      gst_segment_to_running_time (&enc->segment, GST_FORMAT_TIME, timestamp);
  if ((gint64) running_time < 0) {
    GST_DEBUG_OBJECT (enc, "Dropping buffer, timestamp: %" GST_TIME_FORMAT,
        GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)));
    gst_buffer_unref (buffer);
    return GST_FLOW_OK;
  }

  GST_OBJECT_LOCK (enc);
  if (enc->bitrate_changed) {
    long int bitrate = enc->video_bitrate;

    th_encode_ctl (enc->encoder, TH_ENCCTL_SET_BITRATE, &bitrate,
        sizeof (long int));
    enc->bitrate_changed = FALSE;
  }

  if (enc->quality_changed) {
    long int quality = enc->video_quality;

    th_encode_ctl (enc->encoder, TH_ENCCTL_SET_QUALITY, &quality,
        sizeof (long int));
    enc->quality_changed = FALSE;
  }

  /* see if we need to schedule a keyframe */
  force_keyframe = enc->force_keyframe;
  enc->force_keyframe = FALSE;
  GST_OBJECT_UNLOCK (enc);

  if (force_keyframe) {
    GstClockTime stream_time;
    GstStructure *s;

    stream_time = gst_segment_to_stream_time (&enc->segment,
        GST_FORMAT_TIME, timestamp);

    s = gst_structure_new ("GstForceKeyUnit",
        "timestamp", G_TYPE_UINT64, timestamp,
        "stream-time", G_TYPE_UINT64, stream_time,
        "running-time", G_TYPE_UINT64, running_time, NULL);

    theora_enc_force_keyframe (enc);

    gst_pad_push_event (enc->srcpad,
        gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM, s));
  }

  /* make sure we copy the discont flag to the next outgoing buffer when it's
   * set on the incomming buffer */
  if (GST_BUFFER_IS_DISCONT (buffer)) {
    enc->next_discont = TRUE;
  }

  if (enc->packetno == 0) {
    /* no packets written yet, setup headers */
    GstCaps *caps;
    GstBuffer *buf;
    GSList *buffers = NULL;
    int result;

    enc->granulepos_offset = 0;
    enc->timestamp_offset = 0;

    GST_DEBUG_OBJECT (enc, "output headers");
    /* Theora streams begin with three headers; the initial header (with
       most of the codec setup parameters) which is mandated by the Ogg
       bitstream spec.  The second header holds any comment fields.  The
       third header holds the bitstream codebook.  We merely need to
       make the headers, then pass them to libtheora one at a time;
       libtheora handles the additional Ogg bitstream constraints */

    /* create the remaining theora headers */
    th_comment_clear (&enc->comment);
    th_comment_init (&enc->comment);

    while ((result =
            th_encode_flushheader (enc->encoder, &enc->comment, &op)) > 0) {
      ret =
          theora_buffer_from_packet (enc, &op, GST_CLOCK_TIME_NONE,
          GST_CLOCK_TIME_NONE, GST_CLOCK_TIME_NONE, &buf);
      if (ret != GST_FLOW_OK) {
        goto header_buffer_alloc;
      }
      buffers = g_slist_prepend (buffers, buf);
    }
    if (result < 0) {
      g_slist_foreach (buffers, (GFunc) gst_buffer_unref, NULL);
      g_slist_free (buffers);
      goto encoder_disabled;
    }

    buffers = g_slist_reverse (buffers);

    /* mark buffers and put on caps */
    caps = gst_pad_get_caps (enc->srcpad);
    caps = theora_set_header_on_caps (caps, buffers);
    GST_DEBUG ("here are the caps: %" GST_PTR_FORMAT, caps);
    gst_pad_set_caps (enc->srcpad, caps);

    g_slist_foreach (buffers, (GFunc) gst_buffer_set_caps, caps);

    gst_caps_unref (caps);

    /* push out the header buffers */
    while (buffers) {
      buf = buffers->data;
      buffers = g_slist_delete_link (buffers, buffers);
      if ((ret = theora_push_buffer (enc, buf)) != GST_FLOW_OK) {
        g_slist_foreach (buffers, (GFunc) gst_buffer_unref, NULL);
        g_slist_free (buffers);
        goto header_push;
      }
    }

    enc->granulepos_offset =
        gst_util_uint64_scale (running_time, enc->fps_n,
        GST_SECOND * enc->fps_d);
    enc->timestamp_offset = running_time;
    enc->next_ts = 0;
  }

  {
    th_ycbcr_buffer ycbcr;
    gint res;

    theora_enc_init_buffer (ycbcr, &enc->info, GST_BUFFER_DATA (buffer));

    if (theora_enc_is_discontinuous (enc, running_time, duration)) {
      theora_enc_reset (enc);
      enc->granulepos_offset =
          gst_util_uint64_scale (running_time, enc->fps_n,
          GST_SECOND * enc->fps_d);
      enc->timestamp_offset = running_time;
      enc->next_ts = 0;
      enc->next_discont = TRUE;
    }

    if (enc->multipass_cache_fd
        && enc->multipass_mode == MULTIPASS_MODE_SECOND_PASS) {
      if (!theora_enc_read_multipass_cache (enc)) {
        ret = GST_FLOW_ERROR;
        goto multipass_read_failed;
      }
    }

    res = th_encode_ycbcr_in (enc->encoder, ycbcr);
    /* none of the failure cases can happen here */
    g_assert (res == 0);

    if (enc->multipass_cache_fd
        && enc->multipass_mode == MULTIPASS_MODE_FIRST_PASS) {
      if (!theora_enc_write_multipass_cache (enc, FALSE, FALSE)) {
        ret = GST_FLOW_ERROR;
        goto multipass_write_failed;
      }
    }

    ret = GST_FLOW_OK;
    while (th_encode_packetout (enc->encoder, 0, &op)) {
      GstClockTime next_time;

      next_time = th_granule_time (enc->encoder, op.granulepos) * GST_SECOND;

      ret =
          theora_push_packet (enc, &op, timestamp, enc->next_ts,
          next_time - enc->next_ts);

      enc->next_ts = next_time;
      if (ret != GST_FLOW_OK)
        goto data_push;
    }
    gst_buffer_unref (buffer);
  }

  return ret;

  /* ERRORS */
multipass_read_failed:
  {
    gst_buffer_unref (buffer);
    return ret;
  }
multipass_write_failed:
  {
    gst_buffer_unref (buffer);
    return ret;
  }
header_buffer_alloc:
  {
    gst_buffer_unref (buffer);
    return ret;
  }
header_push:
  {
    gst_buffer_unref (buffer);
    return ret;
  }
data_push:
  {
    gst_buffer_unref (buffer);
    return ret;
  }
encoder_disabled:
  {
    GST_ELEMENT_ERROR (enc, STREAM, ENCODE, (NULL),
        ("libtheora has been compiled with the encoder disabled"));
    gst_buffer_unref (buffer);
    return GST_FLOW_ERROR;
  }
}
static GstFlowReturn
gst_deinterlace2_chain (GstPad * pad, GstBuffer * buf)
{
  GstDeinterlace2 *self = NULL;
  GstClockTime timestamp;
  GstFlowReturn ret = GST_FLOW_OK;
  gint fields_required = 0;
  gint cur_field_idx = 0;

  self = GST_DEINTERLACE2 (GST_PAD_PARENT (pad));

  gst_deinterlace2_push_history (self, buf);
  buf = NULL;

  fields_required = gst_deinterlace_method_get_fields_required (self->method);

  /* Not enough fields in the history */
  if (self->history_count < fields_required + 1) {
    /* TODO: do bob or just forward frame */
    GST_DEBUG ("HistoryCount=%d", self->history_count);
    return GST_FLOW_OK;
  }

  while (self->history_count >= fields_required) {
    if (self->fields == GST_DEINTERLACE2_ALL)
      GST_DEBUG ("All fields");
    if (self->fields == GST_DEINTERLACE2_TF)
      GST_DEBUG ("Top fields");
    if (self->fields == GST_DEINTERLACE2_BF)
      GST_DEBUG ("Bottom fields");

    cur_field_idx = self->history_count - fields_required;

    if ((self->field_history[cur_field_idx].flags == PICTURE_INTERLACED_TOP
            && self->fields == GST_DEINTERLACE2_TF) ||
        self->fields == GST_DEINTERLACE2_ALL) {
      GST_DEBUG ("deinterlacing top field");

      /* create new buffer */
      ret = gst_pad_alloc_buffer_and_set_caps (self->srcpad,
          GST_BUFFER_OFFSET_NONE, self->frame_size,
          GST_PAD_CAPS (self->srcpad), &self->out_buf);
      if (ret != GST_FLOW_OK)
        return ret;

      /* do magic calculus */
      gst_deinterlace_method_deinterlace_frame (self->method, self);

      g_assert (self->history_count - 1 -
          gst_deinterlace_method_get_latency (self->method) >= 0);
      buf =
          self->field_history[self->history_count - 1 -
          gst_deinterlace_method_get_latency (self->method)].buf;
      timestamp = GST_BUFFER_TIMESTAMP (buf);

      gst_buffer_unref (gst_deinterlace2_pop_history (self));

      GST_BUFFER_TIMESTAMP (self->out_buf) = timestamp;
      if (self->fields == GST_DEINTERLACE2_ALL)
        GST_BUFFER_DURATION (self->out_buf) = self->field_duration;
      else
        GST_BUFFER_DURATION (self->out_buf) = 2 * self->field_duration;

      ret = gst_pad_push (self->srcpad, self->out_buf);
      self->out_buf = NULL;
      if (ret != GST_FLOW_OK)
        return ret;
    }
    /* no calculation done: remove excess field */
    else if (self->field_history[cur_field_idx].flags ==
        PICTURE_INTERLACED_TOP && self->fields == GST_DEINTERLACE2_BF) {
      GST_DEBUG ("Removing unused top field");
      gst_buffer_unref (gst_deinterlace2_pop_history (self));
    }

    cur_field_idx = self->history_count - fields_required;
    if (self->history_count < fields_required)
      break;

    /* deinterlace bottom_field */
    if ((self->field_history[cur_field_idx].flags == PICTURE_INTERLACED_BOTTOM
            && self->fields == GST_DEINTERLACE2_BF) ||
        self->fields == GST_DEINTERLACE2_ALL) {
      GST_DEBUG ("deinterlacing bottom field");

      /* create new buffer */
      ret = gst_pad_alloc_buffer_and_set_caps (self->srcpad,
          GST_BUFFER_OFFSET_NONE, self->frame_size,
          GST_PAD_CAPS (self->srcpad), &self->out_buf);
      if (ret != GST_FLOW_OK)
        return ret;

      /* do magic calculus */
      gst_deinterlace_method_deinterlace_frame (self->method, self);

      g_assert (self->history_count - 1 -
          gst_deinterlace_method_get_latency (self->method) >= 0);
      buf =
          self->field_history[self->history_count - 1 -
          gst_deinterlace_method_get_latency (self->method)].buf;
      timestamp = GST_BUFFER_TIMESTAMP (buf);

      gst_buffer_unref (gst_deinterlace2_pop_history (self));

      GST_BUFFER_TIMESTAMP (self->out_buf) = timestamp;
      if (self->fields == GST_DEINTERLACE2_ALL)
        GST_BUFFER_DURATION (self->out_buf) = self->field_duration;
      else
        GST_BUFFER_DURATION (self->out_buf) = 2 * self->field_duration;

      ret = gst_pad_push (self->srcpad, self->out_buf);
      self->out_buf = NULL;

      if (ret != GST_FLOW_OK)
        return ret;
    }
    /* no calculation done: remove excess field */
    else if (self->field_history[cur_field_idx].flags ==
        PICTURE_INTERLACED_BOTTOM && self->fields == GST_DEINTERLACE2_TF) {
      GST_DEBUG ("Removing unused bottom field");
      gst_buffer_unref (gst_deinterlace2_pop_history (self));
    }
  }

  GST_DEBUG ("----chain end ----\n\n");

  return ret;
}
static void
gst_musepackdec_loop (GstPad * sinkpad)
{
  GstMusepackDec *musepackdec;
  GstFlowReturn flow;
  GstBuffer *out;

#ifdef MPC_IS_OLD_API
  guint32 update_acc, update_bits;
#else
  mpc_frame_info frame;
  mpc_status err;
#endif
  gint num_samples, samplerate, bitspersample;

  musepackdec = GST_MUSEPACK_DEC (GST_PAD_PARENT (sinkpad));

  samplerate = g_atomic_int_get (&musepackdec->rate);

  if (samplerate == 0) {
    if (!gst_musepack_stream_init (musepackdec))
      goto pause_task;

    gst_musepackdec_send_newsegment (musepackdec);
    samplerate = g_atomic_int_get (&musepackdec->rate);
  }

  bitspersample = g_atomic_int_get (&musepackdec->bps);

  flow = gst_pad_alloc_buffer_and_set_caps (musepackdec->srcpad, -1,
      MPC_DECODER_BUFFER_LENGTH * 4, GST_PAD_CAPS (musepackdec->srcpad), &out);

  if (flow != GST_FLOW_OK) {
    GST_DEBUG_OBJECT (musepackdec, "Flow: %s", gst_flow_get_name (flow));
    goto pause_task;
  }
#ifdef MPC_IS_OLD_API
  num_samples = mpc_decoder_decode (musepackdec->d,
      (MPC_SAMPLE_FORMAT *) GST_BUFFER_DATA (out), &update_acc, &update_bits);

  if (num_samples < 0) {
    GST_ERROR_OBJECT (musepackdec, "Failed to decode sample");
    GST_ELEMENT_ERROR (musepackdec, STREAM, DECODE, (NULL), (NULL));
    goto pause_task;
  } else if (num_samples == 0) {
    goto eos_and_pause;
  }
#else
  frame.buffer = (MPC_SAMPLE_FORMAT *) GST_BUFFER_DATA (out);
  err = mpc_demux_decode (musepackdec->d, &frame);

  if (err != MPC_STATUS_OK) {
    GST_ERROR_OBJECT (musepackdec, "Failed to decode sample");
    GST_ELEMENT_ERROR (musepackdec, STREAM, DECODE, (NULL), (NULL));
    goto pause_task;
  } else if (frame.bits == -1) {
    goto eos_and_pause;
  }

  num_samples = frame.samples;
#endif

  GST_BUFFER_SIZE (out) = num_samples * bitspersample;

  GST_BUFFER_OFFSET (out) = musepackdec->segment.last_stop;
  GST_BUFFER_TIMESTAMP (out) =
      gst_util_uint64_scale_int (musepackdec->segment.last_stop,
      GST_SECOND, samplerate);
  GST_BUFFER_DURATION (out) =
      gst_util_uint64_scale_int (num_samples, GST_SECOND, samplerate);

  musepackdec->segment.last_stop += num_samples;

  GST_LOG_OBJECT (musepackdec, "Pushing buffer, timestamp %" GST_TIME_FORMAT,
      GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (out)));

  flow = gst_pad_push (musepackdec->srcpad, out);
  if (flow != GST_FLOW_OK) {
    GST_DEBUG_OBJECT (musepackdec, "Flow: %s", gst_flow_get_name (flow));
    goto pause_task;
  }

  /* check if we're at the end of a configured segment */
  if (musepackdec->segment.stop != -1 &&
      musepackdec->segment.last_stop >= musepackdec->segment.stop) {
    gint64 stop_time;

    GST_DEBUG_OBJECT (musepackdec, "Reached end of configured segment");

    if ((musepackdec->segment.flags & GST_SEEK_FLAG_SEGMENT) == 0)
      goto eos_and_pause;

    GST_DEBUG_OBJECT (musepackdec, "Posting SEGMENT_DONE message");

    stop_time = gst_util_uint64_scale_int (musepackdec->segment.stop,
        GST_SECOND, samplerate);

    gst_element_post_message (GST_ELEMENT (musepackdec),
        gst_message_new_segment_done (GST_OBJECT (musepackdec),
            GST_FORMAT_TIME, stop_time));

    goto pause_task;
  }

  return;

eos_and_pause:
  {
    GST_DEBUG_OBJECT (musepackdec, "sending EOS event");
    gst_pad_push_event (musepackdec->srcpad, gst_event_new_eos ());
    /* fall through to pause */
  }

pause_task:
  {
    GST_DEBUG_OBJECT (musepackdec, "Pausing task");
    gst_pad_pause_task (sinkpad);
    return;
  }
}
static void
gst_type_find_element_loop (GstPad * pad)
{
  GstTypeFindElement *typefind;
  GstFlowReturn ret = GST_FLOW_OK;

  typefind = GST_TYPE_FIND_ELEMENT (GST_PAD_PARENT (pad));

  if (typefind->mode == MODE_TYPEFIND) {
    GstPad *peer;
    GstCaps *found_caps = NULL;
    GstTypeFindProbability probability = GST_TYPE_FIND_NONE;

    GST_DEBUG_OBJECT (typefind, "find type in pull mode");

    peer = gst_pad_get_peer (pad);
    if (peer) {
      gint64 size;
      gchar *ext;

      if (!gst_pad_query_duration (peer, GST_FORMAT_BYTES, &size)) {
        GST_WARNING_OBJECT (typefind, "Could not query upstream length!");
        gst_object_unref (peer);

        ret = GST_FLOW_ERROR;
        goto pause;
      }

      /* the size if 0, we cannot continue */
      if (size == 0) {
        /* keep message in sync with message in sink event handler */
        GST_ELEMENT_ERROR (typefind, STREAM, TYPE_NOT_FOUND,
            (_("Stream contains no data.")), ("Can't typefind empty stream"));
        gst_object_unref (peer);
        ret = GST_FLOW_ERROR;
        goto pause;
      }
      ext = gst_type_find_get_extension (typefind, pad);

      found_caps =
          gst_type_find_helper_get_range (GST_OBJECT_CAST (peer),
          GST_OBJECT_PARENT (peer),
          (GstTypeFindHelperGetRangeFunction) (GST_PAD_GETRANGEFUNC (peer)),
          (guint64) size, ext, &probability);
      g_free (ext);

      GST_DEBUG ("Found caps %" GST_PTR_FORMAT, found_caps);

      gst_object_unref (peer);
    }

    if (!found_caps || probability < typefind->min_probability) {
      GST_DEBUG ("Trying to guess using extension");
      gst_caps_replace (&found_caps, NULL);
      found_caps =
          gst_type_find_guess_by_extension (typefind, pad, &probability);
    }

    if (!found_caps || probability < typefind->min_probability) {
      GST_ELEMENT_ERROR (typefind, STREAM, TYPE_NOT_FOUND, (NULL), (NULL));
      gst_caps_replace (&found_caps, NULL);
      ret = GST_FLOW_ERROR;
      goto pause;
    }

    GST_DEBUG ("Emiting found caps %" GST_PTR_FORMAT, found_caps);
    g_signal_emit (typefind, gst_type_find_element_signals[HAVE_TYPE],
        0, probability, found_caps);
    typefind->mode = MODE_NORMAL;
    gst_caps_unref (found_caps);
  } else if (typefind->mode == MODE_NORMAL) {
    GstBuffer *outbuf = NULL;

    if (typefind->need_stream_start) {
      gchar *stream_id;

      stream_id =
          gst_pad_create_stream_id (typefind->src, GST_ELEMENT_CAST (typefind),
          NULL);

      GST_DEBUG_OBJECT (typefind, "Pushing STREAM_START");
      gst_pad_push_event (typefind->src,
          gst_event_new_stream_start (stream_id));

      typefind->need_stream_start = FALSE;
      g_free (stream_id);
    }

    if (typefind->need_segment) {
      typefind->need_segment = FALSE;
      gst_pad_push_event (typefind->src,
          gst_event_new_segment (&typefind->segment));
    }

    /* Pull 4k blocks and send downstream */
    ret = gst_pad_pull_range (typefind->sink, typefind->offset, 4096, &outbuf);
    if (ret != GST_FLOW_OK)
      goto pause;

    typefind->offset += 4096;

    ret = gst_pad_push (typefind->src, outbuf);
    if (ret != GST_FLOW_OK)
      goto pause;
  } else {
    /* Error out */
    ret = GST_FLOW_ERROR;
    goto pause;
  }

  return;

pause:
  {
    const gchar *reason = gst_flow_get_name (ret);
    gboolean push_eos = FALSE;

    GST_LOG_OBJECT (typefind, "pausing task, reason %s", reason);
    gst_pad_pause_task (typefind->sink);

    if (ret == GST_FLOW_EOS) {
      /* perform EOS logic */

      if (typefind->segment.flags & GST_SEGMENT_FLAG_SEGMENT) {
        gint64 stop;

        /* for segment playback we need to post when (in stream time)
         * we stopped, this is either stop (when set) or the duration. */
        if ((stop = typefind->segment.stop) == -1)
          stop = typefind->offset;

        GST_LOG_OBJECT (typefind, "Sending segment done, at end of segment");
        gst_element_post_message (GST_ELEMENT (typefind),
            gst_message_new_segment_done (GST_OBJECT (typefind),
                GST_FORMAT_BYTES, stop));
        gst_pad_push_event (typefind->src,
            gst_event_new_segment_done (GST_FORMAT_BYTES, stop));
      } else {
        push_eos = TRUE;
      }
    } else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_EOS) {
      /* for fatal errors we post an error message */
      GST_ELEMENT_ERROR (typefind, STREAM, FAILED, (NULL),
          ("stream stopped, reason %s", reason));
      push_eos = TRUE;
    }
    if (push_eos) {
      /* send EOS, and prevent hanging if no streams yet */
      GST_LOG_OBJECT (typefind, "Sending EOS, at end of stream");
      gst_pad_push_event (typefind->src, gst_event_new_eos ());
    }
    return;
  }
}
static GstFlowReturn
gst_shape_wipe_video_sink_chain (GstPad * pad, GstBuffer * buffer)
{
  GstShapeWipe *self = GST_SHAPE_WIPE (GST_PAD_PARENT (pad));
  GstFlowReturn ret = GST_FLOW_OK;
  GstBuffer *mask = NULL, *outbuf = NULL;
  GstClockTime timestamp;
  gboolean new_outbuf = FALSE;

  if (G_UNLIKELY (self->fmt == GST_VIDEO_FORMAT_UNKNOWN))
    return GST_FLOW_NOT_NEGOTIATED;

  timestamp = GST_BUFFER_TIMESTAMP (buffer);
  timestamp =
      gst_segment_to_stream_time (&self->segment, GST_FORMAT_TIME, timestamp);

  if (GST_CLOCK_TIME_IS_VALID (timestamp))
    gst_object_sync_values (G_OBJECT (self), timestamp);

  GST_DEBUG_OBJECT (self,
      "Blending buffer with timestamp %" GST_TIME_FORMAT " at position %lf",
      GST_TIME_ARGS (timestamp), self->mask_position);

  g_mutex_lock (self->mask_mutex);
  if (!self->mask)
    g_cond_wait (self->mask_cond, self->mask_mutex);

  if (self->mask == NULL) {
    g_mutex_unlock (self->mask_mutex);
    gst_buffer_unref (buffer);
    return GST_FLOW_UNEXPECTED;
  } else {
    mask = gst_buffer_ref (self->mask);
  }
  g_mutex_unlock (self->mask_mutex);

  if (!gst_shape_wipe_do_qos (self, GST_BUFFER_TIMESTAMP (buffer))) {
    gst_buffer_unref (buffer);
    gst_buffer_unref (mask);
    return GST_FLOW_OK;
  }

  /* Try to blend inplace, if it's not possible
   * get a new buffer from downstream.
   */
  if (!gst_buffer_is_writable (buffer)) {
    ret =
        gst_pad_alloc_buffer_and_set_caps (self->srcpad, GST_BUFFER_OFFSET_NONE,
        GST_BUFFER_SIZE (buffer), GST_PAD_CAPS (self->srcpad), &outbuf);
    if (G_UNLIKELY (ret != GST_FLOW_OK)) {
      gst_buffer_unref (buffer);
      gst_buffer_unref (mask);
      return ret;
    }
    gst_buffer_copy_metadata (outbuf, buffer, GST_BUFFER_COPY_ALL);
    new_outbuf = TRUE;
  } else {
    outbuf = buffer;
  }

  if (self->fmt == GST_VIDEO_FORMAT_AYUV && self->mask_bpp == 16)
    ret = gst_shape_wipe_blend_ayuv_16 (self, buffer, mask, outbuf);
  else if (self->fmt == GST_VIDEO_FORMAT_AYUV)
    ret = gst_shape_wipe_blend_ayuv_8 (self, buffer, mask, outbuf);
  else if (self->fmt == GST_VIDEO_FORMAT_ARGB && self->mask_bpp == 16)
    ret = gst_shape_wipe_blend_argb_16 (self, buffer, mask, outbuf);
  else if (self->fmt == GST_VIDEO_FORMAT_ARGB)
    ret = gst_shape_wipe_blend_argb_8 (self, buffer, mask, outbuf);
  else if (self->fmt == GST_VIDEO_FORMAT_BGRA && self->mask_bpp == 16)
    ret = gst_shape_wipe_blend_bgra_16 (self, buffer, mask, outbuf);
  else if (self->fmt == GST_VIDEO_FORMAT_BGRA)
    ret = gst_shape_wipe_blend_bgra_8 (self, buffer, mask, outbuf);
  else
    g_assert_not_reached ();

  gst_buffer_unref (mask);
  if (new_outbuf)
    gst_buffer_unref (buffer);

  if (ret != GST_FLOW_OK) {
    gst_buffer_unref (outbuf);
    return ret;
  }

  ret = gst_pad_push (self->srcpad, outbuf);
  return ret;
}
static gboolean
gst_real_audio_dec_setcaps (GstPad * pad, GstCaps * caps)
{
  GstRealAudioDec *dec = GST_REAL_AUDIO_DEC (GST_PAD_PARENT (pad));
  GstStructure *s = gst_caps_get_structure (caps, 0);
  gint version, flavor, channels, rate, leaf_size, packet_size, width, height;
  guint16 res = 0;
  RAInit data;
  gboolean bres;
  const GValue *v;
  GstBuffer *buf = NULL;
  const gchar *name = gst_structure_get_name (s);

  if (!strcmp (name, "audio/x-sipro")) {
    version = GST_REAL_AUDIO_DEC_VERSION_SIPR;
  } else {
    if (!gst_structure_get_int (s, "raversion", &version))
      goto missing_keys;
  }

  if (!gst_structure_get_int (s, "flavor", &flavor) ||
      !gst_structure_get_int (s, "channels", &channels) ||
      !gst_structure_get_int (s, "width", &width) ||
      !gst_structure_get_int (s, "rate", &rate) ||
      !gst_structure_get_int (s, "height", &height) ||
      !gst_structure_get_int (s, "leaf_size", &leaf_size) ||
      !gst_structure_get_int (s, "packet_size", &packet_size))
    goto missing_keys;

  if ((v = gst_structure_get_value (s, "codec_data")))
    buf = g_value_peek_pointer (v);

  GST_LOG_OBJECT (dec, "opening code for version %d", version);

  /* first close existing decoder */
  close_library (dec, &dec->lib);

  if (!open_library (dec, version, &dec->lib))
    goto could_not_open;

  /* we have the module, no initialize with the caps data */
  data.samplerate = rate;
  data.width = width;
  data.channels = channels;
  data.quality = 100;
  data.leaf_size = leaf_size;
  data.packet_size = packet_size;
  data.datalen = buf ? GST_BUFFER_SIZE (buf) : 0;
  data.data = buf ? GST_BUFFER_DATA (buf) : NULL;

  if ((res = dec->lib.RAInitDecoder (dec->lib.context, &data))) {
    GST_WARNING_OBJECT (dec, "RAInitDecoder() failed");
    goto could_not_initialize;
  }

  if (dec->lib.RASetPwd) {
    dec->lib.RASetPwd (dec->lib.context, dec->pwd ? dec->pwd : DEFAULT_PWD);
  }

  if ((res = dec->lib.RASetFlavor (dec->lib.context, flavor))) {
    GST_WARNING_OBJECT (dec, "RASetFlavor(%d) failed", flavor);
    goto could_not_initialize;
  }

  caps = gst_caps_new_simple ("audio/x-raw-int",
      "endianness", G_TYPE_INT, G_BYTE_ORDER,
      "width", G_TYPE_INT, width,
      "depth", G_TYPE_INT, width,
      "rate", G_TYPE_INT, rate,
      "channels", G_TYPE_INT, channels, "signed", G_TYPE_BOOLEAN, TRUE, NULL);
  bres = gst_pad_set_caps (GST_PAD (dec->src), caps);
  gst_caps_unref (caps);
  if (!bres)
    goto could_not_set_caps;

  dec->width = width;
  dec->height = height;
  dec->leaf_size = leaf_size;

  GST_LOG_OBJECT (dec, "opened module");

  return TRUE;

missing_keys:
  {
    GST_DEBUG_OBJECT (dec, "Could not find all necessary keys in structure.");
    return FALSE;
  }
could_not_open:
  {
    GST_DEBUG_OBJECT (dec, "Could not find decoder");
    return FALSE;
  }
could_not_initialize:
  {
    close_library (dec, &dec->lib);
    GST_WARNING_OBJECT (dec, "Initialization of REAL driver failed (%i).", res);
    return FALSE;
  }
could_not_set_caps:
  {
    /* should normally not fail */
    close_library (dec, &dec->lib);
    GST_DEBUG_OBJECT (dec, "Could not convince peer to accept caps.");
    return FALSE;
  }
}
static void
gst_image_freeze_src_loop (GstPad * pad)
{
    GstImageFreeze *self = GST_IMAGE_FREEZE (GST_PAD_PARENT (pad));
    GstBuffer *buffer;
    guint64 offset;
    GstClockTime timestamp, timestamp_end;
    guint64 cstart, cstop;
    gboolean in_seg, eos;
    GstFlowReturn flow_ret = GST_FLOW_OK;

    g_mutex_lock (&self->lock);
    if (!gst_pad_has_current_caps (self->srcpad)) {
        GST_ERROR_OBJECT (pad, "Not negotiated yet");
        flow_ret = GST_FLOW_NOT_NEGOTIATED;
        g_mutex_unlock (&self->lock);
        goto pause_task;
    }

    if (!self->buffer) {
        GST_ERROR_OBJECT (pad, "Have no buffer yet");
        flow_ret = GST_FLOW_ERROR;
        g_mutex_unlock (&self->lock);
        goto pause_task;
    }
    buffer = gst_buffer_ref (self->buffer);
    buffer = gst_buffer_make_writable (buffer);
    g_mutex_unlock (&self->lock);

    if (self->need_segment) {
        GstEvent *e;

        GST_DEBUG_OBJECT (pad, "Pushing SEGMENT event: %" GST_SEGMENT_FORMAT,
                          &self->segment);
        e = gst_event_new_segment (&self->segment);

        g_mutex_lock (&self->lock);
        if (self->segment.rate >= 0) {
            self->offset =
                gst_util_uint64_scale (self->segment.start, self->fps_n,
                                       self->fps_d * GST_SECOND);
        } else {
            self->offset =
                gst_util_uint64_scale (self->segment.stop, self->fps_n,
                                       self->fps_d * GST_SECOND);
        }
        g_mutex_unlock (&self->lock);

        self->need_segment = FALSE;

        gst_pad_push_event (self->srcpad, e);
    }

    g_mutex_lock (&self->lock);
    offset = self->offset;

    if (self->fps_n != 0) {
        timestamp =
            gst_util_uint64_scale (offset, self->fps_d * GST_SECOND, self->fps_n);
        timestamp_end =
            gst_util_uint64_scale (offset + 1, self->fps_d * GST_SECOND,
                                   self->fps_n);
    } else {
        timestamp = self->segment.start;
        timestamp_end = GST_CLOCK_TIME_NONE;
    }

    eos = (self->fps_n == 0 && offset > 0) ||
          (self->segment.rate >= 0 && self->segment.stop != -1
           && timestamp > self->segment.stop) || (self->segment.rate < 0
                   && offset == 0) || (self->segment.rate < 0
                                       && self->segment.start != -1 && timestamp_end < self->segment.start);

    if (self->fps_n == 0 && offset > 0)
        in_seg = FALSE;
    else
        in_seg =
            gst_segment_clip (&self->segment, GST_FORMAT_TIME, timestamp,
                              timestamp_end, &cstart, &cstop);

    if (in_seg) {
        self->segment.position = cstart;
        if (self->segment.rate >= 0)
            self->segment.position = cstop;
    }

    if (self->segment.rate >= 0)
        self->offset++;
    else
        self->offset--;
    g_mutex_unlock (&self->lock);

    GST_DEBUG_OBJECT (pad, "Handling buffer with timestamp %" GST_TIME_FORMAT,
                      GST_TIME_ARGS (timestamp));

    if (in_seg) {
        GST_BUFFER_DTS (buffer) = GST_CLOCK_TIME_NONE;
        GST_BUFFER_PTS (buffer) = cstart;
        GST_BUFFER_DURATION (buffer) = cstop - cstart;
        GST_BUFFER_OFFSET (buffer) = offset;
        GST_BUFFER_OFFSET_END (buffer) = offset + 1;
        flow_ret = gst_pad_push (self->srcpad, buffer);
        GST_DEBUG_OBJECT (pad, "Pushing buffer resulted in %s",
                          gst_flow_get_name (flow_ret));
        if (flow_ret != GST_FLOW_OK)
            goto pause_task;
    } else {
        gst_buffer_unref (buffer);
    }

    if (eos) {
        flow_ret = GST_FLOW_EOS;
        goto pause_task;
    }

    return;

pause_task:
    {
        const gchar *reason = gst_flow_get_name (flow_ret);

        GST_LOG_OBJECT (self, "pausing task, reason %s", reason);
        gst_pad_pause_task (pad);

        if (flow_ret == GST_FLOW_EOS) {
            if ((self->segment.flags & GST_SEEK_FLAG_SEGMENT)) {
                GstMessage *m;
                GstEvent *e;

                GST_DEBUG_OBJECT (pad, "Sending segment done at end of segment");
                if (self->segment.rate >= 0) {
                    m = gst_message_new_segment_done (GST_OBJECT_CAST (self),
                                                      GST_FORMAT_TIME, self->segment.stop);
                    e = gst_event_new_segment_done (GST_FORMAT_TIME, self->segment.stop);
                } else {
                    m = gst_message_new_segment_done (GST_OBJECT_CAST (self),
                                                      GST_FORMAT_TIME, self->segment.start);
                    e = gst_event_new_segment_done (GST_FORMAT_TIME, self->segment.start);
                }
                gst_element_post_message (GST_ELEMENT_CAST (self), m);
                gst_pad_push_event (self->srcpad, e);
            } else {
                GST_DEBUG_OBJECT (pad, "Sending EOS at end of segment");
                gst_pad_push_event (self->srcpad, gst_event_new_eos ());
            }
        } else if (flow_ret == GST_FLOW_NOT_LINKED || flow_ret < GST_FLOW_EOS) {
            GST_ELEMENT_ERROR (self, STREAM, FAILED,
                               ("Internal data stream error."),
                               ("stream stopped, reason %s", reason));
            gst_pad_push_event (self->srcpad, gst_event_new_eos ());
        }
        return;
    }
}
Exemple #9
0
static gboolean
gst_speed_convert (GstPad * pad, GstFormat src_format, gint64 src_value,
    GstFormat * dest_format, gint64 * dest_value)
{
  gboolean ret = TRUE;
  guint scale = 1;
  GstSpeed *filter;

  if (src_format == *dest_format) {
    *dest_value = src_value;
    return TRUE;
  }

  filter = GST_SPEED (GST_PAD_PARENT (pad));

  switch (src_format) {
    case GST_FORMAT_BYTES:
      switch (*dest_format) {
        case GST_FORMAT_DEFAULT:
          if (filter->sample_size == 0) {
            ret = FALSE;
            break;
          }
          *dest_value = src_value / filter->sample_size;
          break;
        case GST_FORMAT_TIME:
        {
          gint byterate = filter->sample_size * filter->rate;

          if (byterate == 0) {
            ret = FALSE;
            break;
          }
          *dest_value = src_value * GST_SECOND / byterate;
          break;
        }
        default:
          ret = FALSE;
      }
      break;
    case GST_FORMAT_DEFAULT:
      switch (*dest_format) {
        case GST_FORMAT_BYTES:
          *dest_value = src_value * filter->sample_size;
          break;
        case GST_FORMAT_TIME:
          if (filter->rate == 0) {
            ret = FALSE;
            break;
          }
          *dest_value = src_value * GST_SECOND / filter->rate;
          break;
        default:
          ret = FALSE;
      }
      break;
    case GST_FORMAT_TIME:
      switch (*dest_format) {
        case GST_FORMAT_BYTES:
          scale = filter->sample_size;
          /* fallthrough */
        case GST_FORMAT_DEFAULT:
          *dest_value = src_value * scale * filter->rate / GST_SECOND;
          break;
        default:
          ret = FALSE;
      }
      break;
    default:
      ret = FALSE;
  }

  return ret;

}
Exemple #10
0
static GstFlowReturn
gst_mulawdec_chain (GstPad * pad, GstBuffer * buffer)
{
  GstMuLawDec *mulawdec;
  gint16 *linear_data;
  guint8 *mulaw_data;
  guint mulaw_size;
  GstBuffer *outbuf;
  GstFlowReturn ret;

  mulawdec = GST_MULAWDEC (GST_PAD_PARENT (pad));

  if (G_UNLIKELY (mulawdec->rate == 0))
    goto not_negotiated;

  mulaw_data = (guint8 *) GST_BUFFER_DATA (buffer);
  mulaw_size = GST_BUFFER_SIZE (buffer);

  ret =
      gst_pad_alloc_buffer_and_set_caps (mulawdec->srcpad,
      GST_BUFFER_OFFSET_NONE, mulaw_size * 2, GST_PAD_CAPS (mulawdec->srcpad),
      &outbuf);
  if (ret != GST_FLOW_OK)
    goto alloc_failed;

  linear_data = (gint16 *) GST_BUFFER_DATA (outbuf);

  /* copy discont flag */
  if (GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DISCONT))
    GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);

  GST_BUFFER_TIMESTAMP (outbuf) = GST_BUFFER_TIMESTAMP (buffer);
  if (GST_BUFFER_DURATION (outbuf) == GST_CLOCK_TIME_NONE)
    GST_BUFFER_DURATION (outbuf) = gst_util_uint64_scale_int (GST_SECOND,
        mulaw_size * 2, 2 * mulawdec->rate * mulawdec->channels);
  else
    GST_BUFFER_DURATION (outbuf) = GST_BUFFER_DURATION (buffer);
  gst_buffer_set_caps (outbuf, GST_PAD_CAPS (mulawdec->srcpad));

  mulaw_decode (mulaw_data, linear_data, mulaw_size);

  gst_buffer_unref (buffer);

  ret = gst_pad_push (mulawdec->srcpad, outbuf);

  return ret;

  /* ERRORS */
not_negotiated:
  {
    GST_WARNING_OBJECT (mulawdec, "no input format set: not-negotiated");
    gst_buffer_unref (buffer);
    return GST_FLOW_NOT_NEGOTIATED;
  }
alloc_failed:
  {
    GST_DEBUG_OBJECT (mulawdec, "pad alloc failed, flow: %s",
        gst_flow_get_name (ret));
    gst_buffer_unref (buffer);
    return ret;
  }
}
Exemple #11
0
static void
gst_midi_parse_loop (GstPad * sinkpad)
{
  GstMidiParse *midiparse = GST_MIDI_PARSE (GST_PAD_PARENT (sinkpad));
  GstFlowReturn ret;

  switch (midiparse->state) {
    case GST_MIDI_PARSE_STATE_LOAD:
    {
      GstBuffer *buffer = NULL;

      GST_DEBUG_OBJECT (midiparse, "loading song");

      ret =
          gst_pad_pull_range (midiparse->sinkpad, midiparse->offset, -1,
          &buffer);

      if (ret == GST_FLOW_EOS) {
        GST_DEBUG_OBJECT (midiparse, "Song loaded");
        midiparse->state = GST_MIDI_PARSE_STATE_PARSE;
      } else if (ret != GST_FLOW_OK) {
        GST_ELEMENT_ERROR (midiparse, STREAM, DECODE, (NULL),
            ("Unable to read song"));
        goto pause;
      } else {
        GST_DEBUG_OBJECT (midiparse, "pushing buffer");
        gst_adapter_push (midiparse->adapter, buffer);
        midiparse->offset += gst_buffer_get_size (buffer);
      }
      break;
    }
    case GST_MIDI_PARSE_STATE_PARSE:
      ret = gst_midi_parse_parse_song (midiparse);
      if (ret != GST_FLOW_OK)
        goto pause;
      midiparse->state = GST_MIDI_PARSE_STATE_PLAY;
      break;
    case GST_MIDI_PARSE_STATE_PLAY:
      ret = gst_midi_parse_do_play (midiparse);
      if (ret != GST_FLOW_OK)
        goto pause;
      break;
    default:
      break;
  }
  return;

pause:
  {
    const gchar *reason = gst_flow_get_name (ret);
    GstEvent *event;

    GST_DEBUG_OBJECT (midiparse, "pausing task, reason %s", reason);
    gst_pad_pause_task (sinkpad);
    if (ret == GST_FLOW_EOS) {
      /* perform EOS logic */
      event = gst_event_new_eos ();
      gst_pad_push_event (midiparse->srcpad, event);
    } else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_EOS) {
      event = gst_event_new_eos ();
      /* for fatal errors we post an error message, post the error
       * first so the app knows about the error first. */
      GST_ELEMENT_ERROR (midiparse, STREAM, FAILED,
          ("Internal data flow error."),
          ("streaming task paused, reason %s (%d)", reason, ret));
      gst_pad_push_event (midiparse->srcpad, event);
    }
  }
}
Exemple #12
0
/* we can only accept caps that we and downstream can handle.
 * if we have filtercaps set, use those to constrain the target caps.
 */
static GstCaps *
gst_adder_sink_getcaps (GstPad * pad, GstCaps * filter)
{
  GstAdder *adder;
  GstCaps *result, *peercaps, *current_caps, *filter_caps;
  GstStructure *s;
  gint i, n;

  adder = GST_ADDER (GST_PAD_PARENT (pad));

  GST_OBJECT_LOCK (adder);
  /* take filter */
  if ((filter_caps = adder->filter_caps)) {
    if (filter)
      filter_caps =
          gst_caps_intersect_full (filter, filter_caps,
          GST_CAPS_INTERSECT_FIRST);
    else
      gst_caps_ref (filter_caps);
  } else {
    filter_caps = filter ? gst_caps_ref (filter) : NULL;
  }
  GST_OBJECT_UNLOCK (adder);

  if (filter_caps && gst_caps_is_empty (filter_caps)) {
    GST_WARNING_OBJECT (pad, "Empty filter caps");
    return filter_caps;
  }

  /* get the downstream possible caps */
  peercaps = gst_pad_peer_query_caps (adder->srcpad, filter_caps);

  /* get the allowed caps on this sinkpad */
  GST_OBJECT_LOCK (adder);
  current_caps =
      adder->current_caps ? gst_caps_ref (adder->current_caps) : NULL;
  if (current_caps == NULL) {
    current_caps = gst_pad_get_pad_template_caps (pad);
    if (!current_caps)
      current_caps = gst_caps_new_any ();
  }
  GST_OBJECT_UNLOCK (adder);

  if (peercaps) {
    /* if the peer has caps, intersect */
    GST_DEBUG_OBJECT (adder, "intersecting peer and our caps");
    result =
        gst_caps_intersect_full (peercaps, current_caps,
        GST_CAPS_INTERSECT_FIRST);
    gst_caps_unref (peercaps);
    gst_caps_unref (current_caps);
  } else {
    /* the peer has no caps (or there is no peer), just use the allowed caps
     * of this sinkpad. */
    /* restrict with filter-caps if any */
    if (filter_caps) {
      GST_DEBUG_OBJECT (adder, "no peer caps, using filtered caps");
      result =
          gst_caps_intersect_full (filter_caps, current_caps,
          GST_CAPS_INTERSECT_FIRST);
      gst_caps_unref (current_caps);
    } else {
      GST_DEBUG_OBJECT (adder, "no peer caps, using our caps");
      result = current_caps;
    }
  }

  result = gst_caps_make_writable (result);

  n = gst_caps_get_size (result);
  for (i = 0; i < n; i++) {
    GstStructure *sref;

    s = gst_caps_get_structure (result, i);
    sref = gst_structure_copy (s);
    gst_structure_set (sref, "channels", GST_TYPE_INT_RANGE, 0, 2, NULL);
    if (gst_structure_is_subset (s, sref)) {
      /* This field is irrelevant when in mono or stereo */
      gst_structure_remove_field (s, "channel-mask");
    }
    gst_structure_free (sref);
  }

  if (filter_caps)
    gst_caps_unref (filter_caps);

  GST_LOG_OBJECT (adder, "getting caps on pad %p,%s to %" GST_PTR_FORMAT, pad,
      GST_PAD_NAME (pad), result);

  return result;
}
Exemple #13
0
static gboolean
gst_xvidenc_setcaps (GstPad * pad, GstCaps * vscaps)
{
  GstXvidEnc *xvidenc;
  GstStructure *structure;
  gint w, h;
  const GValue *fps, *par;
  gint xvid_cs = -1;

  xvidenc = GST_XVIDENC (GST_PAD_PARENT (pad));

  /* if there's something old around, remove it */
  if (xvidenc->handle) {
    gst_xvidenc_flush_buffers (xvidenc, TRUE);
    xvid_encore (xvidenc->handle, XVID_ENC_DESTROY, NULL, NULL);
    xvidenc->handle = NULL;
  }

  structure = gst_caps_get_structure (vscaps, 0);

  if (!gst_structure_get_int (structure, "width", &w) ||
      !gst_structure_get_int (structure, "height", &h)) {
    return FALSE;
  }

  fps = gst_structure_get_value (structure, "framerate");
  if (fps == NULL || !GST_VALUE_HOLDS_FRACTION (fps)) {
    GST_WARNING_OBJECT (pad, "no framerate specified, or not a GstFraction");
    return FALSE;
  }

  /* optional par info */
  par = gst_structure_get_value (structure, "pixel-aspect-ratio");

  xvid_cs = gst_xvid_structure_to_csp (structure);
  if (xvid_cs == -1) {
    gchar *sstr;

    sstr = gst_structure_to_string (structure);
    GST_DEBUG_OBJECT (xvidenc, "Did not find xvid colourspace for caps %s",
        sstr);
    g_free (sstr);
    return FALSE;
  }

  xvidenc->csp = xvid_cs;
  xvidenc->width = w;
  xvidenc->height = h;
  xvidenc->fbase = gst_value_get_fraction_numerator (fps);
  xvidenc->fincr = gst_value_get_fraction_denominator (fps);
  if ((par != NULL) && GST_VALUE_HOLDS_FRACTION (par)) {
    xvidenc->par_width = gst_value_get_fraction_numerator (par);
    xvidenc->par_height = gst_value_get_fraction_denominator (par);
  } else {
    xvidenc->par_width = 1;
    xvidenc->par_height = 1;
  }

  /* wipe xframe cache given possible change caps properties */
  g_free (xvidenc->xframe_cache);
  xvidenc->xframe_cache = NULL;

  if (gst_xvidenc_setup (xvidenc)) {
    gboolean ret = FALSE;
    GstCaps *new_caps = NULL, *allowed_caps;

    /* please downstream with preferred caps */
    allowed_caps = gst_pad_get_allowed_caps (xvidenc->srcpad);
    GST_DEBUG_OBJECT (xvidenc, "allowed caps: %" GST_PTR_FORMAT, allowed_caps);

    if (allowed_caps && !gst_caps_is_empty (allowed_caps)) {
      new_caps = gst_caps_copy_nth (allowed_caps, 0);
    } else {
      new_caps = gst_caps_new_simple ("video/x-xvid", NULL);
    }
    if (allowed_caps)
      gst_caps_unref (allowed_caps);

    gst_caps_set_simple (new_caps,
        "width", G_TYPE_INT, w, "height", G_TYPE_INT, h,
        "framerate", GST_TYPE_FRACTION, xvidenc->fbase, xvidenc->fincr,
        "pixel-aspect-ratio", GST_TYPE_FRACTION,
        xvidenc->par_width, xvidenc->par_height, NULL);
    /* just to be sure */
    gst_pad_fixate_caps (xvidenc->srcpad, new_caps);

    if (xvidenc->used_profile != 0) {
      switch (xvidenc->used_profile) {
        case XVID_PROFILE_S_L0:
          gst_caps_set_simple (new_caps, "profile", G_TYPE_STRING, "simple",
              "level", G_TYPE_STRING, "0", NULL);
          break;
        case XVID_PROFILE_S_L1:
          gst_caps_set_simple (new_caps, "profile", G_TYPE_STRING, "simple",
              "level", G_TYPE_STRING, "1", NULL);
          break;
        case XVID_PROFILE_S_L2:
          gst_caps_set_simple (new_caps, "profile", G_TYPE_STRING, "simple",
              "level", G_TYPE_STRING, "2", NULL);
          break;
        case XVID_PROFILE_S_L3:
          gst_caps_set_simple (new_caps, "profile", G_TYPE_STRING, "simple",
              "level", G_TYPE_STRING, "3", NULL);
          break;
       /* case XVID_PROFILE_S_L4a:
          gst_caps_set_simple (new_caps, "profile", G_TYPE_STRING, "simple",
              "level", G_TYPE_STRING, "4a", NULL);
          break;
        case XVID_PROFILE_S_L5:
          gst_caps_set_simple (new_caps, "profile", G_TYPE_STRING, "simple",
              "level", G_TYPE_STRING, "5", NULL);
          break;
        case XVID_PROFILE_S_L6:
          gst_caps_set_simple (new_caps, "profile", G_TYPE_STRING, "simple",
              "level", G_TYPE_STRING, "6", NULL);
          break;*/
        case XVID_PROFILE_ARTS_L1:
          gst_caps_set_simple (new_caps, "profile", G_TYPE_STRING,
              "advanced-real-time-simple", "level", G_TYPE_STRING, "1", NULL);
          break;
        case XVID_PROFILE_ARTS_L2:
          gst_caps_set_simple (new_caps, "profile", G_TYPE_STRING,
              "advanced-real-time-simple", "level", G_TYPE_STRING, "2", NULL);
          break;
        case XVID_PROFILE_ARTS_L3:
          gst_caps_set_simple (new_caps, "profile", G_TYPE_STRING,
              "advanced-real-time-simple", "level", G_TYPE_STRING, "3", NULL);
          break;
        case XVID_PROFILE_ARTS_L4:
          gst_caps_set_simple (new_caps, "profile", G_TYPE_STRING,
              "advanced-real-time-simple", "level", G_TYPE_STRING, "4", NULL);
          break;
        case XVID_PROFILE_AS_L0:
          gst_caps_set_simple (new_caps, "profile", G_TYPE_STRING,
              "advanced-simple", "level", G_TYPE_STRING, "0", NULL);
          break;
        case XVID_PROFILE_AS_L1:
          gst_caps_set_simple (new_caps, "profile", G_TYPE_STRING,
              "advanced-simple", "level", G_TYPE_STRING, "1", NULL);
          break;
        case XVID_PROFILE_AS_L2:
          gst_caps_set_simple (new_caps, "profile", G_TYPE_STRING,
              "advanced-simple", "level", G_TYPE_STRING, "2", NULL);
          break;
        case XVID_PROFILE_AS_L3:
          gst_caps_set_simple (new_caps, "profile", G_TYPE_STRING,
              "advanced-simple", "level", G_TYPE_STRING, "3", NULL);
          break;
        case XVID_PROFILE_AS_L4:
          gst_caps_set_simple (new_caps, "profile", G_TYPE_STRING,
              "advanced-simple", "level", G_TYPE_STRING, "4", NULL);
          break;
        default:
          g_assert_not_reached ();
          break;
      }
    }

    /* src pad should accept anyway */
    ret = gst_pad_set_caps (xvidenc->srcpad, new_caps);
    gst_caps_unref (new_caps);

    if (!ret && xvidenc->handle) {
      xvid_encore (xvidenc->handle, XVID_ENC_DESTROY, NULL, NULL);
      xvidenc->handle = NULL;
    }
    return ret;

  } else                        /* setup did not work out */
    return FALSE;
}
Exemple #14
0
static GstFlowReturn
gst_xvidenc_chain (GstPad * pad, GstBuffer * buf)
{
  GstXvidEnc *xvidenc = GST_XVIDENC (GST_PAD_PARENT (pad));
  GstBuffer *outbuf;
  xvid_enc_frame_t xframe;

  const gint motion_presets[] = {
    0, 0, 0, 0,
    XVID_ME_HALFPELREFINE16,
    XVID_ME_HALFPELREFINE16 | XVID_ME_ADVANCEDDIAMOND16,
    XVID_ME_HALFPELREFINE16 | XVID_ME_EXTSEARCH16
        | XVID_ME_HALFPELREFINE8 | XVID_ME_USESQUARES16
  };

  if (!xvidenc->handle) {
    GST_ELEMENT_ERROR (xvidenc, CORE, NEGOTIATION, (NULL),
        ("format wasn't negotiated before chain function"));
    gst_buffer_unref (buf);
    return GST_FLOW_NOT_NEGOTIATED;
  }

  GST_DEBUG_OBJECT (xvidenc,
      "Received buffer of time %" GST_TIME_FORMAT ", size %d",
      GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)), GST_BUFFER_SIZE (buf));

  if (xvidenc->xframe_cache)
    memcpy (&xframe, xvidenc->xframe_cache, sizeof (xframe));
  else {                        /* need to build some inital xframe to be cached */
    /* encode and so ... */
    gst_xvid_init_struct (xframe);

    if (xvidenc->par_width == xvidenc->par_height)
      xframe.par = XVID_PAR_11_VGA;
    else {
      xframe.par = XVID_PAR_EXT;
      xframe.par_width = xvidenc->par_width;
      xframe.par_height = xvidenc->par_height;
    }

    /* handle options */
    xframe.vol_flags |= xvidenc->quant_type;
    xframe.vop_flags = XVID_VOP_HALFPEL;
    xframe.motion = motion_presets[xvidenc->motion];

    if (xvidenc->me_chroma) {
      xframe.motion |= XVID_ME_CHROMA_PVOP;
      xframe.motion |= XVID_ME_CHROMA_BVOP;
    }

    if (xvidenc->me_vhq >= 1) {
      xframe.vop_flags |= XVID_VOP_MODEDECISION_RD;
    }
    if (xvidenc->me_vhq >= 2) {
      xframe.motion |= XVID_ME_HALFPELREFINE16_RD;
      xframe.motion |= XVID_ME_QUARTERPELREFINE16_RD;
    }
    if (xvidenc->me_vhq >= 3) {
      xframe.motion |= XVID_ME_HALFPELREFINE8_RD;
      xframe.motion |= XVID_ME_QUARTERPELREFINE8_RD;
      xframe.motion |= XVID_ME_CHECKPREDICTION_RD;
    }
    if (xvidenc->me_vhq >= 4) {
      xframe.motion |= XVID_ME_EXTSEARCH_RD;
    }

    /* no motion estimation, then only intra */
    if (xvidenc->motion == 0) {
      xframe.type = XVID_TYPE_IVOP;
    } else {
      xframe.type = XVID_TYPE_AUTO;
    }

    if (xvidenc->motion > 4) {
      xframe.vop_flags |= XVID_VOP_INTER4V;
    }

    if (xvidenc->me_quarterpel) {
      xframe.vol_flags |= XVID_VOL_QUARTERPEL;
      xframe.motion |= XVID_ME_QUARTERPELREFINE16;
      xframe.motion |= XVID_ME_QUARTERPELREFINE8;
    }

    if (xvidenc->gmc) {
      xframe.vol_flags |= XVID_VOL_GMC;
      xframe.motion |= XVID_ME_GME_REFINE;
    }

    if (xvidenc->interlaced) {
      xframe.vol_flags |= XVID_VOL_INTERLACING;
    }

    if (xvidenc->trellis) {
      xframe.vop_flags |= XVID_VOP_TRELLISQUANT;
    }

    if (xvidenc->hqacpred) {
      xframe.vop_flags |= XVID_VOP_HQACPRED;
    }

    if (xvidenc->greyscale) {
      xframe.vop_flags |= XVID_VOP_GREYSCALE;
    }

    if (xvidenc->cartoon) {
      xframe.vop_flags |= XVID_VOP_CARTOON;
      xframe.motion |= XVID_ME_DETECT_STATIC_MOTION;
    }

    xframe.bframe_threshold = xvidenc->bframe_threshold;
    xframe.input.csp = xvidenc->csp;

    /* save in cache */
    xvidenc->xframe_cache = g_memdup (&xframe, sizeof (xframe));
  }

  outbuf = gst_xvidenc_encode (xvidenc, buf, xframe);

  if (!outbuf)                  /* error or no data yet */
    return GST_FLOW_OK;

  /* go out, multiply! */
  return gst_pad_push (xvidenc->srcpad, outbuf);
}
static int mfw_gst_vpuenc_init_encoder(GstPad *pad, enum v4l2_memory memory)
{
	GstVPU_Enc *vpu_enc = MFW_GST_VPU_ENC(GST_PAD_PARENT(pad));
	gchar *mime = "undef";
	gint ret;
	GstCaps *caps = NULL;
	struct v4l2_format fmt;
	int retval, i;

	if (!vpu_enc->codecTypeProvided) {
		GST_ERROR("Incomplete command line.\n");
		GError *error = NULL;
		GQuark domain = g_quark_from_string("mfw_vpuencoder");
		error = g_error_new(domain, 10, "fatal error");
		gst_element_post_message(GST_ELEMENT(vpu_enc),
					 gst_message_new_error
					 (GST_OBJECT(vpu_enc), error,
					  "Incomplete command line - codec type was not provided."));
		return GST_FLOW_ERROR;
	}

	fmt.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
	fmt.fmt.pix.width = vpu_enc->width;
	fmt.fmt.pix.height = vpu_enc->height;
	fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YVU420;

	retval = ioctl(vpu_enc->vpu_fd, VIDIOC_S_FMT, &fmt);
	if (retval) {
		printf("VIDIOC_S_FMT failed: %s\n", strerror(errno));
		return GST_FLOW_ERROR;
	}

	reqs.memory = memory;
	retval = ioctl(vpu_enc->vpu_fd, VIDIOC_REQBUFS, &reqs);
	if (retval) {
		perror("VIDIOC_REQBUFS");
		return GST_FLOW_ERROR;
	}

	retval = ioctl(vpu_enc->vpu_fd, VPU_IOC_CODEC, vpu_enc->codec);
	if (retval) {
		perror("VPU_IOC_CODEC");
		return GST_FLOW_ERROR;
	}

	retval = ioctl(vpu_enc->vpu_fd, VPU_IOC_MJPEG_QUALITY, vpu_enc->mjpeg_quality);
	if (retval) {
		perror("VPU_IOC_MJPEG_QUALITY");
		return GST_FLOW_ERROR;
	}

	for (i = 0; i < NUM_BUFFERS; i++) {
		struct v4l2_buffer *buf = &vpu_enc->buf_v4l2[i];
		buf->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
		buf->memory = memory;
		buf->index = i;

		if (memory == V4L2_MEMORY_MMAP) {
			retval = ioctl(vpu_enc->vpu_fd, VIDIOC_QUERYBUF, buf);
			if (retval) {
				GST_ERROR("VIDIOC_QUERYBUF failed: %s\n", strerror(errno));
				return GST_FLOW_ERROR;
			}
			vpu_enc->buf_size[i] = buf->length;
			vpu_enc->buf_data[i] = mmap(NULL, buf->length,
					   PROT_READ | PROT_WRITE, MAP_SHARED,
					   vpu_enc->vpu_fd, vpu_enc->buf_v4l2[i].m.offset);
		}
	}

	switch (vpu_enc->codec) {
	case  STD_MPEG4:
		mime = "video/mpeg";
		break;
	case STD_AVC:
		mime = "video/x-h264";
		break;
	case STD_H263:
		mime = "video/x-h263";
		break;
	case STD_MJPG:
		mime = "image/jpeg";
		break;
	default:
		return GST_FLOW_ERROR;
	}

	caps = gst_caps_new_simple(mime,
			   "mpegversion", G_TYPE_INT, 4,
			   "systemstream", G_TYPE_BOOLEAN, FALSE,
			   "height", G_TYPE_INT, vpu_enc->height,
			   "width", G_TYPE_INT, vpu_enc->width,
			   "framerate", GST_TYPE_FRACTION, (gint32) (vpu_enc->framerate * 1000),
			   1000, NULL);

	gst_pad_set_caps(vpu_enc->srcpad, caps);

	vpu_enc->init = TRUE;

	return GST_FLOW_OK;
}
Exemple #16
0
static GstFlowReturn
speed_chain (GstPad * pad, GstBuffer * in_buf)
{
  GstBuffer *out_buf;
  GstSpeed *filter;
  guint c, in_samples, out_samples, out_size;
  GstFlowReturn flow;

  filter = GST_SPEED (GST_PAD_PARENT (pad));

  if (G_UNLIKELY (filter->sample_size == 0 || filter->rate == 0)) {
    flow = GST_FLOW_NOT_NEGOTIATED;
    goto done;
  }

  if (G_UNLIKELY (filter->offset == GST_BUFFER_OFFSET_NONE)) {
    filter->offset =
        gst_util_uint64_scale_int (filter->timestamp, filter->rate, GST_SECOND);
  }

  /* buffersize has to be aligned by samplesize */
  out_size = ceil ((gfloat) GST_BUFFER_SIZE (in_buf) / filter->speed);
  out_size = ((out_size + filter->sample_size - 1) / filter->sample_size) *
      filter->sample_size;

  flow =
      gst_pad_alloc_buffer_and_set_caps (filter->srcpad, -1, out_size,
      GST_PAD_CAPS (filter->srcpad), &out_buf);

  if (flow != GST_FLOW_OK)
    goto done;

  in_samples = GST_BUFFER_SIZE (in_buf) / filter->sample_size;

  out_samples = 0;

  for (c = 0; c < filter->channels; ++c) {
    if (filter->format == GST_SPEED_FORMAT_INT) {
      out_samples = speed_chain_int16 (filter, in_buf, out_buf, c, in_samples);
    } else {
      out_samples =
          speed_chain_float32 (filter, in_buf, out_buf, c, in_samples);
    }
  }

  GST_BUFFER_SIZE (out_buf) = out_samples * filter->sample_size;

  GST_BUFFER_OFFSET (out_buf) = filter->offset;
  GST_BUFFER_TIMESTAMP (out_buf) = filter->timestamp;

  filter->offset += GST_BUFFER_SIZE (out_buf) / filter->sample_size;
  filter->timestamp =
      gst_util_uint64_scale_int (filter->offset, GST_SECOND, filter->rate);

  /* make sure it's at least nominally a perfect stream */
  GST_BUFFER_DURATION (out_buf) =
      filter->timestamp - GST_BUFFER_TIMESTAMP (out_buf);

  flow = gst_pad_push (filter->srcpad, out_buf);

done:

  if (G_UNLIKELY (flow != GST_FLOW_OK))
    GST_DEBUG_OBJECT (filter, "flow: %s", gst_flow_get_name (flow));

  gst_buffer_unref (in_buf);
  return flow;
}
static GstFlowReturn mfw_gst_vpuenc_chain(GstPad * pad, GstBuffer * buffer)
{
	GstVPU_Enc *vpu_enc = NULL;
	GstFlowReturn retval = GST_FLOW_OK;
	GstCaps *src_caps;
	GstBuffer *outbuffer;
	gint i = 0;
	int ret;
	struct pollfd pollfd;
	unsigned long type = V4L2_BUF_TYPE_VIDEO_OUTPUT;

	GST_DEBUG(__func__);

	vpu_enc = MFW_GST_VPU_ENC(GST_PAD_PARENT(pad));

	if (vpu_enc->init == FALSE) {
		retval = mfw_gst_vpuenc_init_encoder(pad, vpu_enc->memory);
		if (retval != GST_FLOW_OK)
			return retval;
		printf("VPU ENC initialised\n");
	}

	i = 0;
	if (vpu_enc->memory == V4L2_MEMORY_USERPTR) {
		for (i = 0; i < NUM_BUFFERS; i++) {
			if (vpu_enc->buf_v4l2[i].m.userptr == (long int)GST_BUFFER_DATA (buffer))
				break;
		}
		if (i == NUM_BUFFERS) {
			for (i = 0; i < NUM_BUFFERS; i++) {
				if (!vpu_enc->buf_v4l2[i].m.userptr)
					break;
			}
		}
		i = i % NUM_BUFFERS;
	}

	if (i == NUM_BUFFERS) {
		printf("NO BUFFER AVAILABLE\n");
		return GST_FLOW_ERROR;
	}

	if (!buffer)
		return GST_FLOW_OK;

	if (vpu_enc->memory == V4L2_MEMORY_MMAP) {
		/* copy the input Frame into the allocated buffer */
		memcpy(vpu_enc->buf_data[i], GST_BUFFER_DATA(buffer), GST_BUFFER_SIZE(buffer));
		gst_buffer_unref(buffer);
	} else {
		vpu_enc->buf_v4l2[i].m.userptr = (long int)GST_BUFFER_DATA (buffer);
		vpu_enc->buf_v4l2[i].length = GST_BUFFER_SIZE (buffer);
	}

	pollfd.fd = vpu_enc->vpu_fd;
	pollfd.events = POLLIN | POLLOUT;

	ret = ioctl(vpu_enc->vpu_fd, VIDIOC_QBUF, &vpu_enc->buf_v4l2[i]);
	if (ret) {
		if (vpu_enc->memory == V4L2_MEMORY_USERPTR) {
			/* fallback to mmap */
			vpu_enc->init = FALSE;
			vpu_enc->memory = V4L2_MEMORY_MMAP;
			GST_WARNING("mfw_gst_vpuenc_chain: fallback to mmap");
			return mfw_gst_vpuenc_chain(pad, buffer);
		}
		GST_ERROR("VIDIOC_QBUF failed: %s\n", strerror(errno));
		return GST_FLOW_ERROR;
	}

	if (!vpu_enc->once) {
		retval = ioctl(vpu_enc->vpu_fd, VIDIOC_STREAMON, &type);
		if (retval) {
			printf("streamon failed with %d", retval);
			return GST_FLOW_ERROR;
		}
		vpu_enc->once = 1;
	}

	ret = ioctl(vpu_enc->vpu_fd, VIDIOC_DQBUF, &vpu_enc->buf_v4l2[0]);
	if (ret) {
		GST_ERROR("VIDIOC_DQBUF failed: %s\n", strerror(errno));
		return GST_FLOW_ERROR;
	}

	if (vpu_enc->memory == V4L2_MEMORY_USERPTR) {
		gst_buffer_unref(buffer);
	}

	src_caps = GST_PAD_CAPS(vpu_enc->srcpad);

	retval = gst_pad_alloc_buffer_and_set_caps(vpu_enc->srcpad,
			0, 1024 * 1024, src_caps, &outbuffer);
	if (retval != GST_FLOW_OK) {
		GST_ERROR("Allocating buffer failed with %d", ret);
		return retval;
	}

	ret = read(vpu_enc->vpu_fd, GST_BUFFER_DATA(outbuffer), 1024 * 1024);
	if (ret < 0) {
		printf("read failed: %s\n", strerror(errno));
		return GST_FLOW_ERROR;
	}
	GST_BUFFER_SIZE(outbuffer) = ret;
	GST_BUFFER_TIMESTAMP(outbuffer) = gst_util_uint64_scale(vpu_enc->encoded_frames,
		1 * GST_SECOND,
		vpu_enc->framerate);

	vpu_enc->encoded_frames++;

	GST_DEBUG_OBJECT(vpu_enc, "frame encoded : %lld ts = %" GST_TIME_FORMAT,
			vpu_enc->encoded_frames,
			GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(outbuffer)));

	retval = gst_pad_push(vpu_enc->srcpad, outbuffer);
	if (retval != GST_FLOW_OK) {
		GST_ERROR("Pushing Output onto the source pad failed with %d \n",
			  retval);
	}

	return retval;
}
static gboolean
gst_type_find_element_handle_event (GstPad * pad, GstEvent * event)
{
  gboolean res = FALSE;
  GstTypeFindElement *typefind = GST_TYPE_FIND_ELEMENT (GST_PAD_PARENT (pad));

  GST_DEBUG_OBJECT (typefind, "got %s event in mode %d",
      GST_EVENT_TYPE_NAME (event), typefind->mode);

  switch (typefind->mode) {
    case MODE_TYPEFIND:
      switch (GST_EVENT_TYPE (event)) {
        case GST_EVENT_EOS:{
          GstTypeFindProbability prob = 0;
          GstCaps *caps = NULL;

          GST_INFO_OBJECT (typefind, "Got EOS and no type found yet");

          /* we might not have started typefinding yet because there was not
           * enough data so far; just give it a shot now and see what we get */
          if (typefind->store) {
            caps = gst_type_find_helper_for_buffer (GST_OBJECT (typefind),
                typefind->store, &prob);

            if (caps && prob >= typefind->min_probability) {
              g_signal_emit (typefind, gst_type_find_element_signals[HAVE_TYPE],
                  0, prob, caps);
            } else {
              GST_ELEMENT_ERROR (typefind, STREAM, TYPE_NOT_FOUND,
                  (NULL), (NULL));
            }
            gst_caps_replace (&caps, NULL);
          } else {
            /* keep message in sync with the one in the pad activate function */
            GST_ELEMENT_ERROR (typefind, STREAM, TYPE_NOT_FOUND,
                (_("Stream contains no data.")),
                ("Can't typefind empty stream"));
          }

          stop_typefinding (typefind);
          res = gst_pad_push_event (typefind->src, event);
          break;
        }
        case GST_EVENT_FLUSH_STOP:
          g_list_foreach (typefind->cached_events,
              (GFunc) gst_mini_object_unref, NULL);
          g_list_free (typefind->cached_events);
          typefind->cached_events = NULL;
          gst_buffer_replace (&typefind->store, NULL);
          /* fall through */
        case GST_EVENT_FLUSH_START:
          res = gst_pad_push_event (typefind->src, event);
          break;
        default:
          GST_DEBUG_OBJECT (typefind, "Saving %s event to send later",
              GST_EVENT_TYPE_NAME (event));
          typefind->cached_events =
              g_list_append (typefind->cached_events, event);
          res = TRUE;
          break;
      }
      break;
    case MODE_NORMAL:
      res = gst_pad_push_event (typefind->src, event);
      break;
    case MODE_ERROR:
      break;
    default:
      g_assert_not_reached ();
  }
  return res;
}
static GstFlowReturn
gst_icydemux_chain (GstPad * pad, GstBuffer * buf)
{
  GstICYDemux *icydemux;
  guint size, chunk, offset;
  GstBuffer *sub;
  GstFlowReturn ret = GST_FLOW_OK;

  icydemux = GST_ICYDEMUX (GST_PAD_PARENT (pad));

  if (G_UNLIKELY (icydemux->meta_interval < 0))
    goto not_negotiated;

  if (icydemux->meta_interval == 0) {
    ret = gst_icydemux_typefind_or_forward (icydemux, buf);
    goto done;
  }

  /* Go through the buffer, chopping it into appropriate chunks. Forward as
   * tags or buffers, as appropriate
   */
  size = GST_BUFFER_SIZE (buf);
  offset = 0;
  while (size) {
    if (icydemux->remaining) {
      chunk = (size <= icydemux->remaining) ? size : icydemux->remaining;
      sub = gst_buffer_create_sub (buf, offset, chunk);
      offset += chunk;
      icydemux->remaining -= chunk;
      size -= chunk;

      /* This buffer goes onto typefinding, and/or directly pushed out */
      ret = gst_icydemux_typefind_or_forward (icydemux, sub);
      if (ret != GST_FLOW_OK)
        goto done;
    } else if (icydemux->meta_remaining) {
      chunk = (size <= icydemux->meta_remaining) ?
          size : icydemux->meta_remaining;
      sub = gst_buffer_create_sub (buf, offset, chunk);
      gst_icydemux_add_meta (icydemux, sub);

      offset += chunk;
      icydemux->meta_remaining -= chunk;
      size -= chunk;

      if (icydemux->meta_remaining == 0) {
        /* Parse tags from meta_adapter, send off as tag messages */
        GST_DEBUG_OBJECT (icydemux, "No remaining metadata, parsing for tags");
        gst_icydemux_parse_and_send_tags (icydemux);

        icydemux->remaining = icydemux->meta_interval;
      }
    } else {
      /* We need to read a single byte (always safe at this point in the loop)
       * to figure out how many bytes of metadata exist. 
       * The 'spec' tells us to read 16 * (byte_value) bytes of metadata after
       * this (zero is common, and means the metadata hasn't changed).
       */
      icydemux->meta_remaining = 16 * GST_BUFFER_DATA (buf)[offset];
      if (icydemux->meta_remaining == 0)
        icydemux->remaining = icydemux->meta_interval;

      offset += 1;
      size -= 1;
    }
  }

done:
  gst_buffer_unref (buf);

  return ret;

  /* ERRORS */
not_negotiated:
  {
    GST_WARNING_OBJECT (icydemux, "meta_interval not set, buffer probably had "
        "no caps set. Try enabling iradio-mode on the http source element");
    gst_buffer_unref (buf);
    return GST_FLOW_NOT_NEGOTIATED;
  }
}
static GstFlowReturn
gst_shape_wipe_video_sink_chain (GstPad * pad, GstBuffer * buffer)
{
  GstShapeWipe *self = GST_SHAPE_WIPE (GST_PAD_PARENT (pad));
  GstFlowReturn ret = GST_FLOW_OK;
  GstBuffer *mask = NULL, *outbuf = NULL;
  GstClockTime timestamp;
  gboolean new_outbuf = FALSE;

  if (G_UNLIKELY (self->fmt == GST_VIDEO_FORMAT_UNKNOWN))
    goto not_negotiated;

  timestamp = GST_BUFFER_TIMESTAMP (buffer);
  timestamp =
      gst_segment_to_stream_time (&self->segment, GST_FORMAT_TIME, timestamp);

  if (GST_CLOCK_TIME_IS_VALID (timestamp))
    gst_object_sync_values (G_OBJECT (self), timestamp);

  GST_LOG_OBJECT (self,
      "Blending buffer with timestamp %" GST_TIME_FORMAT " at position %f",
      GST_TIME_ARGS (timestamp), self->mask_position);

  g_mutex_lock (self->mask_mutex);
  if (self->shutdown)
    goto shutdown;

  if (!self->mask)
    g_cond_wait (self->mask_cond, self->mask_mutex);

  if (self->mask == NULL || self->shutdown) {
    goto shutdown;
  } else {
    mask = gst_buffer_ref (self->mask);
  }
  g_mutex_unlock (self->mask_mutex);

  if (!gst_shape_wipe_do_qos (self, GST_BUFFER_TIMESTAMP (buffer)))
    goto qos;

  /* Try to blend inplace, if it's not possible
   * get a new buffer from downstream. */
  if (!gst_buffer_is_writable (buffer)) {
    ret =
        gst_pad_alloc_buffer_and_set_caps (self->srcpad, GST_BUFFER_OFFSET_NONE,
        GST_BUFFER_SIZE (buffer), GST_PAD_CAPS (self->srcpad), &outbuf);
    if (G_UNLIKELY (ret != GST_FLOW_OK))
      goto alloc_failed;

    gst_buffer_copy_metadata (outbuf, buffer, GST_BUFFER_COPY_ALL);
    new_outbuf = TRUE;
  } else {
    outbuf = buffer;
  }

  switch (self->fmt) {
    case GST_VIDEO_FORMAT_AYUV:
    case GST_VIDEO_FORMAT_ARGB:
    case GST_VIDEO_FORMAT_ABGR:
      if (self->mask_bpp == 16)
        gst_shape_wipe_blend_argb_16 (self, buffer, mask, outbuf);
      else
        gst_shape_wipe_blend_argb_8 (self, buffer, mask, outbuf);
      break;
    case GST_VIDEO_FORMAT_BGRA:
    case GST_VIDEO_FORMAT_RGBA:
      if (self->mask_bpp == 16)
        gst_shape_wipe_blend_bgra_16 (self, buffer, mask, outbuf);
      else
        gst_shape_wipe_blend_bgra_8 (self, buffer, mask, outbuf);
      break;
    default:
      g_assert_not_reached ();
      break;
  }

  gst_buffer_unref (mask);
  if (new_outbuf)
    gst_buffer_unref (buffer);

  ret = gst_pad_push (self->srcpad, outbuf);
  if (G_UNLIKELY (ret != GST_FLOW_OK))
    goto push_failed;

  return ret;

  /* Errors */
not_negotiated:
  GST_ERROR_OBJECT (self, "No valid caps yet");
  gst_buffer_unref (buffer);
  return GST_FLOW_NOT_NEGOTIATED;
shutdown:
  GST_DEBUG_OBJECT (self, "Shutting down");
  gst_buffer_unref (buffer);
  return GST_FLOW_WRONG_STATE;
qos:
  GST_DEBUG_OBJECT (self, "Dropping buffer because of QoS");
  gst_buffer_unref (buffer);
  gst_buffer_unref (mask);
  return GST_FLOW_OK;
alloc_failed:
  GST_ERROR_OBJECT (self, "Buffer allocation from downstream failed: %s",
      gst_flow_get_name (ret));
  gst_buffer_unref (buffer);
  gst_buffer_unref (mask);
  return ret;
push_failed:
  GST_ERROR_OBJECT (self, "Pushing buffer downstream failed: %s",
      gst_flow_get_name (ret));
  return ret;
}
static gboolean
gst_y4m_encode_setcaps (GstPad * pad, GstCaps * vscaps)
{
  GstY4mEncode *filter;
  GstStructure *structure;
  gboolean res;
  gint w, h;
  guint32 fourcc;
  const GValue *fps, *par, *interlaced;

  filter = GST_Y4M_ENCODE (GST_PAD_PARENT (pad));

  structure = gst_caps_get_structure (vscaps, 0);

  res = gst_structure_get_int (structure, "width", &w);
  res &= gst_structure_get_int (structure, "height", &h);
  res &= ((fps = gst_structure_get_value (structure, "framerate")) != NULL);
  res &= gst_structure_get_fourcc (structure, "format", &fourcc);

  switch (fourcc) {             /* Translate fourcc to Y4M colorspace code */
    case GST_MAKE_FOURCC ('I', '4', '2', '0'):
    case GST_MAKE_FOURCC ('I', 'Y', 'U', 'V'):
      filter->colorspace = "420";
      break;
    case GST_MAKE_FOURCC ('Y', '4', '2', 'B'):
      filter->colorspace = "422";
      break;
    case GST_MAKE_FOURCC ('Y', '4', '1', 'B'):
      filter->colorspace = "411";
      break;
    case GST_MAKE_FOURCC ('Y', '4', '4', '4'):
      filter->colorspace = "444";
      break;
    default:
      res = FALSE;
      break;
  }

  if (!res || w <= 0 || h <= 0 || !GST_VALUE_HOLDS_FRACTION (fps))
    return FALSE;

  /* optional interlaced info */
  interlaced = gst_structure_get_value (structure, "interlaced");

  /* optional par info */
  par = gst_structure_get_value (structure, "pixel-aspect-ratio");

  filter->width = w;
  filter->height = h;
  filter->fps_num = gst_value_get_fraction_numerator (fps);
  filter->fps_den = gst_value_get_fraction_denominator (fps);
  if ((par != NULL) && GST_VALUE_HOLDS_FRACTION (par)) {
    filter->par_num = gst_value_get_fraction_numerator (par);
    filter->par_den = gst_value_get_fraction_denominator (par);
  } else {                      /* indicates unknown */
    filter->par_num = 0;
    filter->par_den = 0;
  }
  if ((interlaced != NULL) && G_VALUE_HOLDS (interlaced, G_TYPE_BOOLEAN)) {
    filter->interlaced = g_value_get_boolean (interlaced);
  } else {
    /* assume progressive if no interlaced property in caps */
    filter->interlaced = FALSE;
  }
  /* the template caps will do for the src pad, should always accept */
  return gst_pad_set_caps (filter->srcpad,
      gst_static_pad_template_get_caps (&y4mencode_src_factory));
}
Exemple #22
0
static gboolean
gst_real_video_dec_setcaps (GstPad * pad, GstCaps * caps)
{
  GstRealVideoDec *dec = GST_REAL_VIDEO_DEC (GST_PAD_PARENT (pad));
  GstStructure *s = gst_caps_get_structure (caps, 0);
  gint version, res, width, height, format, subformat;
  gint framerate_num, framerate_denom;
  gchar data[36];
  gboolean bres;
  const GValue *v;

  if (!gst_structure_get_int (s, "rmversion", &version) ||
      !gst_structure_get_int (s, "width", (gint *) & width) ||
      !gst_structure_get_int (s, "height", (gint *) & height) ||
      !gst_structure_get_int (s, "format", &format) ||
      !gst_structure_get_int (s, "subformat", &subformat) ||
      !gst_structure_get_fraction (s, "framerate", &framerate_num,
          &framerate_denom))
    goto missing_keys;

  GST_LOG_OBJECT (dec, "Setting version to %d", version);

  close_library (dec, &dec->lib);

  if (!open_library (dec, version, &dec->lib))
    goto open_failed;

  /* Initialize REAL driver. */
  GST_WRITE_UINT16_LE (data + 0, 11);
  GST_WRITE_UINT16_LE (data + 2, width);
  GST_WRITE_UINT16_LE (data + 4, height);
  GST_WRITE_UINT16_LE (data + 6, 0);
  GST_WRITE_UINT32_LE (data + 8, 0);
  GST_WRITE_UINT32_LE (data + 12, subformat);
  GST_WRITE_UINT32_LE (data + 16, 1);
  GST_WRITE_UINT32_LE (data + 20, format);

  if ((res = dec->lib.Init (&data, &dec->lib.context)))
    goto could_not_initialize;

  if ((v = gst_structure_get_value (s, "codec_data"))) {
    GstBuffer *buf;
    guint32 *msgdata;
    guint i;
    guint8 *bufdata;
    guint bufsize;
    struct
    {
      guint32 type;
      guint32 msg;
      gpointer data;
      guint32 extra[6];
    } msg;

    buf = g_value_peek_pointer (v);

    bufdata = GST_BUFFER_DATA (buf);
    bufsize = GST_BUFFER_SIZE (buf);

    /* skip format and subformat */
    bufdata += 8;
    bufsize -= 8;

    GST_LOG_OBJECT (dec, "Creating custom message of length %d", bufsize);

    msgdata = g_new0 (guint32, bufsize + 2);
    if (!msgdata)
      goto could_not_allocate;

    msg.type = 0x24;
    msg.msg = 1 + ((subformat >> 16) & 7);
    msg.data = msgdata;
    for (i = 0; i < 6; i++)
      msg.extra[i] = 0;
    msgdata[0] = width;
    msgdata[1] = height;
    for (i = 0; i < bufsize; i++)
      msgdata[i + 2] = 4 * (guint32) bufdata[i];

    res = dec->lib.Message (&msg, dec->lib.context);

    g_free (msgdata);
    if (res)
      goto could_not_send_message;
  }
static void
stop_typefinding (GstTypeFindElement * typefind)
{
  GstState state;
  gboolean push_cached_buffers;
  gsize avail;
  GstBuffer *buffer;

  gst_element_get_state (GST_ELEMENT (typefind), &state, NULL, 0);

  push_cached_buffers = (state >= GST_STATE_PAUSED);

  GST_DEBUG_OBJECT (typefind, "stopping typefinding%s",
      push_cached_buffers ? " and pushing cached buffers" : "");

  GST_OBJECT_LOCK (typefind);
  avail = gst_adapter_available (typefind->adapter);
  if (avail == 0)
    goto no_data;

  buffer = gst_adapter_take_buffer (typefind->adapter, avail);
  GST_OBJECT_UNLOCK (typefind);

  if (!push_cached_buffers) {
    gst_buffer_unref (buffer);
  } else {
    GstPad *peer = gst_pad_get_peer (typefind->src);

    typefind->mode = MODE_NORMAL;

    /* make sure the user gets a meaningful error message in this case,
     * which is not a core bug or bug of any kind (as the default error
     * message emitted by gstpad.c otherwise would make you think) */
    if (peer && GST_PAD_CHAINFUNC (peer) == NULL) {
      GST_DEBUG_OBJECT (typefind, "upstream only supports push mode, while "
          "downstream element only works in pull mode, erroring out");
      GST_ELEMENT_ERROR (typefind, STREAM, FAILED,
          ("%s cannot work in push mode. The operation is not supported "
              "with this source element or protocol.",
              G_OBJECT_TYPE_NAME (GST_PAD_PARENT (peer))),
          ("Downstream pad %s:%s has no chainfunction, and the upstream "
              "element does not support pull mode", GST_DEBUG_PAD_NAME (peer)));
      typefind->mode = MODE_ERROR;      /* make the chain function error out */
      gst_buffer_unref (buffer);
    } else {
      gst_type_find_element_send_cached_events (typefind);
      gst_pad_push (typefind->src, buffer);
    }
    if (peer)
      gst_object_unref (peer);
  }
  return;

  /* ERRORS */
no_data:
  {
    GST_DEBUG_OBJECT (typefind, "we have no data to typefind");
    GST_OBJECT_UNLOCK (typefind);
    return;
  }
}
Exemple #24
0
static GstFlowReturn
gst_real_video_dec_chain (GstPad * pad, GstBuffer * in)
{
  GstRealVideoDec *dec;
  guint8 *data;
  guint size;
  GstFlowReturn ret;
  RVInData tin;
  RVOutData tout;
  GstClockTime timestamp, duration;
  GstBuffer *out;
  guint32 result;
  guint frag_count, frag_size;

  dec = GST_REAL_VIDEO_DEC (GST_PAD_PARENT (pad));

  if (G_UNLIKELY (dec->lib.Transform == NULL || dec->lib.module == NULL))
    goto not_negotiated;

  data = GST_BUFFER_DATA (in);
  size = GST_BUFFER_SIZE (in);
  timestamp = GST_BUFFER_TIMESTAMP (in);
  duration = GST_BUFFER_DURATION (in);

  GST_DEBUG_OBJECT (dec, "got buffer of size %u, timestamp %" GST_TIME_FORMAT,
      size, GST_TIME_ARGS (timestamp));

  /* alloc output buffer */
  ret = gst_pad_alloc_buffer (dec->src, GST_BUFFER_OFFSET_NONE,
      dec->width * dec->height * 3 / 2, GST_PAD_CAPS (dec->src), &out);
  if (ret != GST_FLOW_OK)
    goto alloc_failed;

  GST_BUFFER_TIMESTAMP (out) = timestamp;
  GST_BUFFER_DURATION (out) = duration;

  frag_count = *data++;
  frag_size = (frag_count + 1) * 8;
  size -= (frag_size + 1);

  GST_DEBUG_OBJECT (dec, "frag_count %u, frag_size %u, data size %u",
      frag_count, frag_size, size);

  /* Decode.
   *
   * The Buffers contain
   *
   *  0                   1                   2                   3
   *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   * |  nfragments   |   fragment1 ...                               |
   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   * |  ....                                                         |
   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   * |  ...          |   fragment2 ...                               |
   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   *    ....                                                          
   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   * |  ...          |   fragment data                               |
   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   *
   * nfragments: number of fragments 
   * fragmentN: 8 bytes of fragment data (nfragements + 1) of them
   * fragment data: the data of the fragments.
   */
  tin.datalen = size;
  tin.interpolate = 0;
  tin.nfragments = frag_count;
  tin.fragments = data;
  tin.flags = 0;
  tin.timestamp = timestamp;

  /* jump over the frag table to the fragments */
  data += frag_size;

  result = dec->lib.Transform (
      (gchar *) data,
      (gchar *) GST_BUFFER_DATA (out), &tin, &tout, dec->lib.context);
  if (result)
    goto could_not_transform;

  /* When we decoded a frame, reset the error counter. We only fail after N
   * consecutive decoding errors. */
  dec->error_count = 0;

  gst_buffer_unref (in);

  /* Check for new dimensions */
  if (tout.frames && ((dec->width != tout.width)
          || (dec->height != tout.height))) {
    GstCaps *caps = gst_caps_copy (GST_PAD_CAPS (dec->src));
    GstStructure *s = gst_caps_get_structure (caps, 0);

    GST_DEBUG_OBJECT (dec, "New dimensions: %"
        G_GUINT32_FORMAT " x %" G_GUINT32_FORMAT, tout.width, tout.height);

    gst_structure_set (s, "width", G_TYPE_INT, (gint) tout.width,
        "height", G_TYPE_INT, (gint) tout.height, NULL);

    gst_pad_set_caps (dec->src, caps);
    gst_buffer_set_caps (out, caps);
    gst_caps_unref (caps);

    dec->width = tout.width;
    dec->height = tout.height;
    GST_BUFFER_SIZE (out) = dec->width * dec->height * 3 / 2;
  }

  GST_DEBUG_OBJECT (dec,
      "Pushing out buffer with timestamp %" GST_TIME_FORMAT,
      GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (out)));

  if ((ret = gst_pad_push (dec->src, out)) != GST_FLOW_OK)
    goto could_not_push;

  return ret;

  /* Errors */
not_negotiated:
  {
    GST_WARNING_OBJECT (dec, "decoder not open, probably no input caps set "
        "yet, caps on input buffer: %" GST_PTR_FORMAT, GST_BUFFER_CAPS (in));
    gst_buffer_unref (in);
    return GST_FLOW_NOT_NEGOTIATED;
  }
alloc_failed:
  {
    GST_DEBUG_OBJECT (dec, "buffer alloc failed: %s", gst_flow_get_name (ret));
    gst_buffer_unref (in);
    return ret;
  }
could_not_transform:
  {
    gst_buffer_unref (out);
    gst_buffer_unref (in);

    dec->error_count++;

    if (dec->max_errors && dec->error_count >= dec->max_errors) {
      GST_ELEMENT_ERROR (dec, STREAM, DECODE,
          ("Could not decode buffer: %" G_GUINT32_FORMAT, result), (NULL));
      return GST_FLOW_ERROR;
    } else {
      GST_ELEMENT_WARNING (dec, STREAM, DECODE,
          ("Could not decode buffer: %" G_GUINT32_FORMAT, result), (NULL));
      return GST_FLOW_OK;
    }
  }
could_not_push:
  {
    GST_DEBUG_OBJECT (dec, "Could not push buffer: %s",
        gst_flow_get_name (ret));
    return ret;
  }
}
static gboolean
gst_navseek_handle_src_event (GstPad * pad, GstEvent * event)
{
  GstNavSeek *navseek;
  gboolean ret = TRUE;

  navseek = GST_NAVSEEK (GST_PAD_PARENT (pad));

  switch (GST_EVENT_TYPE (event)) {
    case GST_EVENT_NAVIGATION:
      /* Check for a keyup and convert left/right to a seek event */
    {
      const GstStructure *structure;
      const gchar *event_type;

      structure = gst_event_get_structure (event);
      g_return_val_if_fail (structure != NULL, FALSE);

      event_type = gst_structure_get_string (structure, "event");
      g_return_val_if_fail (event_type != NULL, FALSE);

      if (strcmp (event_type, "key-press") == 0) {
        const gchar *key;

        key = gst_structure_get_string (structure, "key");
        g_return_val_if_fail (key != NULL, FALSE);

        if (strcmp (key, "Left") == 0) {
          /* Seek backward by 5 secs */
          gst_navseek_seek (navseek, -1.0 * navseek->seek_offset * GST_SECOND);
        } else if (strcmp (key, "Right") == 0) {
          /* Seek forward */
          gst_navseek_seek (navseek, navseek->seek_offset * GST_SECOND);
        } else if (strcmp (key, "s") == 0) {
          /* Grab the next frame as the start frame of a segment */
          navseek->grab_seg_start = TRUE;
        } else if (strcmp (key, "e") == 0) {
          /* Grab the next frame as the end frame of a segment */
          navseek->grab_seg_end = TRUE;
        } else if (strcmp (key, "l") == 0) {
          /* Toggle the loop flag. If we have both start and end segment times send a seek */
          navseek->loop = !navseek->loop;
          gst_navseek_segseek (navseek);
        }
      } else {
        break;
      }
      gst_event_unref (event);
      event = NULL;
    }
      break;
    default:
      break;
  }

  if (event && GST_PAD_IS_LINKED (GST_BASE_TRANSFORM (navseek)->sinkpad)) {
    GstPad *peer_pad = gst_pad_get_peer (GST_BASE_TRANSFORM (navseek)->sinkpad);

    ret = gst_pad_send_event (peer_pad, event);
    gst_object_unref (peer_pad);
  }

  return ret;
}
static GstFlowReturn
gst_mve_demux_chain (GstPad * sinkpad, GstBuffer * inbuf)
{
  GstMveDemux *mve = GST_MVE_DEMUX (GST_PAD_PARENT (sinkpad));
  GstFlowReturn ret = GST_FLOW_OK;

  gst_adapter_push (mve->adapter, inbuf);

  GST_DEBUG_OBJECT (mve, "queuing buffer, needed:%d, available:%u",
      mve->needed_bytes, gst_adapter_available (mve->adapter));

  while ((gst_adapter_available (mve->adapter) >= mve->needed_bytes) &&
      (ret == GST_FLOW_OK)) {
    GstMveDemuxStream *stream = NULL;
    GstBuffer *outbuf = NULL;

    switch (mve->state) {
      case MVEDEMUX_STATE_INITIAL:
        gst_adapter_flush (mve->adapter, mve->needed_bytes);

        mve->chunk_offset += mve->needed_bytes;
        mve->needed_bytes = 4;
        mve->state = MVEDEMUX_STATE_NEXT_CHUNK;
        break;

      case MVEDEMUX_STATE_NEXT_CHUNK:{
        const guint8 *data;
        guint16 size;

        data = gst_adapter_peek (mve->adapter, mve->needed_bytes);
        size = GST_MVE_SEGMENT_SIZE (data);

        if (mve->chunk_offset >= mve->chunk_size) {
          /* new chunk, flush buffer and proceed with next segment */
          guint16 chunk_type = GST_READ_UINT16_LE (data + 2);

          gst_adapter_flush (mve->adapter, mve->needed_bytes);
          mve->chunk_size = size;
          mve->chunk_offset = 0;

          if (chunk_type > MVE_CHUNK_END) {
            GST_WARNING_OBJECT (mve,
                "skipping unknown chunk type 0x%02x of size:%u", chunk_type,
                size);
            mve->needed_bytes += size;
            mve->state = MVEDEMUX_STATE_SKIP;
          } else {
            GST_DEBUG_OBJECT (mve, "found new chunk type 0x%02x of size:%u",
                chunk_type, size);
          }
        } else if (mve->chunk_offset <= mve->chunk_size) {
          /* new segment */
          GST_DEBUG_OBJECT (mve, "found segment type 0x%02x of size:%u",
              GST_MVE_SEGMENT_TYPE (data), size);

          mve->needed_bytes += size;
          mve->state = MVEDEMUX_STATE_MOVIE;
        }
      }
        break;

      case MVEDEMUX_STATE_MOVIE:
        ret = gst_mve_parse_segment (mve, &stream, &outbuf);

        if ((ret == GST_FLOW_OK) && (outbuf != NULL)) {
          /* send buffer */
          GST_DEBUG_OBJECT (mve,
              "pushing buffer with time %" GST_TIME_FORMAT
              " (%u bytes) on pad %s",
              GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)),
              GST_BUFFER_SIZE (outbuf), GST_PAD_NAME (stream->pad));

          ret = gst_pad_push (stream->pad, outbuf);
          stream->last_flow = ret;
        }

        if (ret == GST_FLOW_NOT_LINKED) {
          if (mve->audio_stream
              && mve->audio_stream->last_flow != GST_FLOW_NOT_LINKED)
            ret = GST_FLOW_OK;
          if (mve->video_stream
              && mve->video_stream->last_flow != GST_FLOW_NOT_LINKED)
            ret = GST_FLOW_OK;
        }

        /* update current offset */
        mve->chunk_offset += mve->needed_bytes;

        mve->state = MVEDEMUX_STATE_NEXT_CHUNK;
        mve->needed_bytes = 4;
        break;

      case MVEDEMUX_STATE_SKIP:
        mve->chunk_offset += mve->needed_bytes;
        gst_adapter_flush (mve->adapter, mve->needed_bytes);
        mve->state = MVEDEMUX_STATE_NEXT_CHUNK;
        mve->needed_bytes = 4;
        break;

      default:
        GST_ERROR_OBJECT (mve, "invalid state: %d", mve->state);
        break;
    }
  }

  return ret;
}
Exemple #27
0
static gboolean
theora_enc_sink_event (GstPad * pad, GstEvent * event)
{
  GstTheoraEnc *enc;
  ogg_packet op;
  gboolean res;

  enc = GST_THEORA_ENC (GST_PAD_PARENT (pad));

  switch (GST_EVENT_TYPE (event)) {
    case GST_EVENT_NEWSEGMENT:
    {
      gboolean update;
      gdouble rate, applied_rate;
      GstFormat format;
      gint64 start, stop, time;

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

      gst_segment_set_newsegment_full (&enc->segment, update, rate,
          applied_rate, format, start, stop, time);

      res = gst_pad_push_event (enc->srcpad, event);
      break;
    }
    case GST_EVENT_EOS:
      if (enc->initialised) {
        /* push last packet with eos flag, should not be called */
        while (th_encode_packetout (enc->encoder, 1, &op)) {
          GstClockTime next_time =
              th_granule_time (enc->encoder, op.granulepos) * GST_SECOND;

          theora_push_packet (enc, &op, GST_CLOCK_TIME_NONE, enc->next_ts,
              next_time - enc->next_ts);
          enc->next_ts = next_time;
        }
      }
      if (enc->initialised && enc->multipass_cache_fd
          && enc->multipass_mode == MULTIPASS_MODE_FIRST_PASS)
        theora_enc_write_multipass_cache (enc, TRUE, TRUE);

      theora_enc_clear_multipass_cache (enc);

      res = gst_pad_push_event (enc->srcpad, event);
      break;
    case GST_EVENT_FLUSH_STOP:
      gst_segment_init (&enc->segment, GST_FORMAT_UNDEFINED);
      res = gst_pad_push_event (enc->srcpad, event);
      break;
    case GST_EVENT_CUSTOM_DOWNSTREAM:
    {
      const GstStructure *s;

      s = gst_event_get_structure (event);

      if (gst_structure_has_name (s, "GstForceKeyUnit"))
        theora_enc_force_keyframe (enc);
      res = gst_pad_push_event (enc->srcpad, event);
      break;
    }
    default:
      res = gst_pad_push_event (enc->srcpad, event);
      break;
  }
  return res;
}
static GstFlowReturn
gst_base_video_parse_chain (GstPad * pad, GstBuffer * buf)
{
  GstBaseVideoParse *base_video_parse;
  GstBaseVideoParseClass *klass;
  GstFlowReturn ret;

  GST_DEBUG ("chain with %d bytes", GST_BUFFER_SIZE (buf));

  base_video_parse = GST_BASE_VIDEO_PARSE (GST_PAD_PARENT (pad));
  klass = GST_BASE_VIDEO_PARSE_GET_CLASS (base_video_parse);

  if (!base_video_parse->started) {
    klass->start (base_video_parse);
    base_video_parse->started = TRUE;
  }

  if (G_UNLIKELY (GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DISCONT))) {
    GST_DEBUG_OBJECT (base_video_parse, "received DISCONT buffer");
    gst_base_video_parse_reset (base_video_parse);
    base_video_parse->discont = TRUE;
    base_video_parse->have_sync = FALSE;
  }

  if (GST_BUFFER_TIMESTAMP (buf) != GST_CLOCK_TIME_NONE) {
    base_video_parse->last_timestamp = GST_BUFFER_TIMESTAMP (buf);
  }
  gst_adapter_push (base_video_parse->input_adapter, buf);

  if (!base_video_parse->have_sync) {
    int n, m;

    GST_DEBUG ("no sync, scanning");

    n = gst_adapter_available (base_video_parse->input_adapter);
    m = klass->scan_for_sync (base_video_parse->input_adapter, FALSE, 0, n);

    gst_adapter_flush (base_video_parse->input_adapter, m);

    if (m < n) {
      GST_DEBUG ("found possible sync after %d bytes (of %d)", m, n);

      /* this is only "maybe" sync */
      base_video_parse->have_sync = TRUE;
    }

    if (!base_video_parse->have_sync) {
      return GST_FLOW_OK;
    }
  }

  /* FIXME check klass->parse_data */

  do {
    ret = klass->parse_data (base_video_parse, FALSE);
  } while (ret == GST_FLOW_OK);

  if (ret == GST_BASE_VIDEO_PARSE_FLOW_NEED_DATA) {
    return GST_FLOW_OK;
  }
  return ret;
}
Exemple #29
0
static void
gst_wildmidi_loop (GstPad * sinkpad)
{
  GstWildmidi *wildmidi = GST_WILDMIDI (GST_PAD_PARENT (sinkpad));
  GstFlowReturn ret;

  switch (wildmidi->state) {
    case GST_WILDMIDI_STATE_LOAD:
    {
      GstBuffer *buffer;

      GST_DEBUG_OBJECT (wildmidi, "loading song");

      ret =
          gst_pad_pull_range (wildmidi->sinkpad, wildmidi->offset, -1, &buffer);

      if (ret == GST_FLOW_UNEXPECTED) {
        GST_DEBUG_OBJECT (wildmidi, "Song loaded");
        wildmidi->state = GST_WILDMIDI_STATE_PARSE;
      } else if (ret != GST_FLOW_OK) {
        GST_ELEMENT_ERROR (wildmidi, STREAM, DECODE, (NULL),
            ("Unable to read song"));
        goto pause;
      } else {
        GST_DEBUG_OBJECT (wildmidi, "pushing buffer");
        gst_adapter_push (wildmidi->adapter, buffer);
        wildmidi->offset += GST_BUFFER_SIZE (buffer);
      }
      break;
    }
    case GST_WILDMIDI_STATE_PARSE:
      ret = gst_wildmidi_parse_song (wildmidi);
      if (ret != GST_FLOW_OK)
        goto pause;
      wildmidi->state = GST_WILDMIDI_STATE_PLAY;
      break;
    case GST_WILDMIDI_STATE_PLAY:
      ret = gst_wildmidi_do_play (wildmidi);
      if (ret != GST_FLOW_OK)
        goto pause;
      break;
    default:
      break;
  }
  return;

pause:
  {
    const gchar *reason = gst_flow_get_name (ret);
    GstEvent *event;

    GST_DEBUG_OBJECT (wildmidi, "pausing task, reason %s", reason);
    gst_pad_pause_task (sinkpad);
    if (GST_FLOW_IS_FATAL (ret) || ret == GST_FLOW_NOT_LINKED) {
      if (ret == GST_FLOW_UNEXPECTED) {
        /* perform EOS logic */
        event = gst_event_new_eos ();
        gst_pad_push_event (wildmidi->srcpad, event);
      } else {
        event = gst_event_new_eos ();
        /* for fatal errors we post an error message, post the error
         * first so the app knows about the error first. */
        GST_ELEMENT_ERROR (wildmidi, STREAM, FAILED,
            ("Internal data flow error."),
            ("streaming task paused, reason %s (%d)", reason, ret));
        gst_pad_push_event (wildmidi->srcpad, event);
      }
    }
  }
}
static void
src_task_loop (GstPad * pad)
{
  GstDtlsEnc *self = GST_DTLS_ENC (GST_PAD_PARENT (pad));
  GstFlowReturn ret;
  GstBuffer *buffer;
  gboolean check_connection_timeout = FALSE;

  GST_TRACE_OBJECT (self, "src loop: acquiring lock");
  g_mutex_lock (&self->queue_lock);
  GST_TRACE_OBJECT (self, "src loop: acquired lock");

  if (self->flushing) {
    GST_LOG_OBJECT (self, "src task loop entered on inactive pad");
    GST_TRACE_OBJECT (self, "src loop: releasing lock");
    g_mutex_unlock (&self->queue_lock);
    return;
  }

  while (g_queue_is_empty (&self->queue)) {
    GST_TRACE_OBJECT (self, "src loop: queue empty, waiting for add");
    g_cond_wait (&self->queue_cond_add, &self->queue_lock);
    GST_TRACE_OBJECT (self, "src loop: add signaled");

    if (self->flushing) {
      GST_LOG_OBJECT (self, "pad inactive, task returning");
      GST_TRACE_OBJECT (self, "src loop: releasing lock");
      g_mutex_unlock (&self->queue_lock);
      return;
    }
  }
  GST_TRACE_OBJECT (self, "src loop: queue has element");

  buffer = g_queue_pop_head (&self->queue);
  g_mutex_unlock (&self->queue_lock);

  if (self->send_initial_events) {
    GstSegment segment;
    gchar s_id[32];
    GstCaps *caps;

    self->send_initial_events = FALSE;

    g_snprintf (s_id, sizeof (s_id), "dtlsenc-%08x", g_random_int ());
    gst_pad_push_event (self->src, gst_event_new_stream_start (s_id));
    caps = gst_caps_new_empty_simple ("application/x-dtls");
    gst_pad_push_event (self->src, gst_event_new_caps (caps));
    gst_caps_unref (caps);
    gst_segment_init (&segment, GST_FORMAT_BYTES);
    gst_pad_push_event (self->src, gst_event_new_segment (&segment));
    check_connection_timeout = TRUE;
  }

  GST_TRACE_OBJECT (self, "src loop: releasing lock");

  ret = gst_pad_push (self->src, buffer);
  if (check_connection_timeout)
    gst_dtls_connection_check_timeout (self->connection);

  if (G_UNLIKELY (ret != GST_FLOW_OK)) {
    GST_WARNING_OBJECT (self, "failed to push buffer on src pad: %s",
        gst_flow_get_name (ret));
  }
}