static gboolean theora_enc_write_multipass_cache (GstTheoraEnc * enc, gboolean begin, gboolean eos) { GError *err = NULL; GIOStatus stat = G_IO_STATUS_NORMAL; gint bytes_read = 0; gsize bytes_written = 0; gchar *buf; if (begin) stat = g_io_channel_seek_position (enc->multipass_cache_fd, 0, G_SEEK_SET, &err); if (stat != G_IO_STATUS_ERROR) { do { bytes_read = th_encode_ctl (enc->encoder, TH_ENCCTL_2PASS_OUT, &buf, sizeof (buf)); if (bytes_read > 0) g_io_channel_write_chars (enc->multipass_cache_fd, buf, bytes_read, &bytes_written, NULL); } while (bytes_read > 0 && bytes_written > 0); } if (stat == G_IO_STATUS_ERROR || bytes_read < 0) { if (begin) { if (eos) GST_ELEMENT_WARNING (enc, RESOURCE, WRITE, (NULL), ("Failed to seek to beginning of multipass cache file: %s", err->message)); else GST_ELEMENT_ERROR (enc, RESOURCE, WRITE, (NULL), ("Failed to seek to beginning of multipass cache file: %s", err->message)); } else { GST_ELEMENT_ERROR (enc, RESOURCE, WRITE, (NULL), ("Failed to write multipass cache file")); } if (err) g_error_free (err); return FALSE; } return TRUE; }
static GstBuffer * gst_rtp_g723_depay_process (GstBaseRTPDepayload * depayload, GstBuffer * buf) { GstRtpG723Depay *rtpg723depay; GstBuffer *outbuf = NULL; gint payload_len; gboolean marker; rtpg723depay = GST_RTP_G723_DEPAY (depayload); payload_len = gst_rtp_buffer_get_payload_len (buf); /* At least 4 bytes */ if (payload_len < 4) goto too_small; GST_LOG_OBJECT (rtpg723depay, "payload len %d", payload_len); outbuf = gst_rtp_buffer_get_payload_buffer (buf); marker = gst_rtp_buffer_get_marker (buf); if (marker) { /* marker bit starts talkspurt */ GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT); } GST_LOG_OBJECT (depayload, "pushing buffer of size %d", GST_BUFFER_SIZE (outbuf)); return outbuf; /* ERRORS */ too_small: { GST_ELEMENT_WARNING (rtpg723depay, STREAM, DECODE, (NULL), ("G723 RTP payload too small (%d)", payload_len)); goto bad_packet; } bad_packet: { /* no fatal error */ return NULL; } }
GstElement * gst_play_sink_convert_bin_add_conversion_element_factory (GstPlaySinkConvertBin * self, const char *factory, const char *name) { GstElement *el; el = gst_element_factory_make (factory, name); if (el == NULL) { gst_play_sink_convert_bin_post_missing_element_message (self, factory); GST_ELEMENT_WARNING (self, CORE, MISSING_PLUGIN, (_("Missing element '%s' - check your GStreamer installation."), factory), (self->audio ? "audio rendering might fail" : "video rendering might fail")); } else { gst_play_sink_convert_bin_add_conversion_element (self, el); } return el; }
void gst_phoenixsrc_set_property (GObject * object, guint property_id, const GValue * value, GParamSpec * pspec) { GstPhoenixSrc *phoenixsrc; g_return_if_fail (GST_IS_PHOENIX_SRC (object)); phoenixsrc = GST_PHOENIX_SRC (object); switch (property_id) { case PROP_CAMERA_CONFIG_FILEPATH: g_free (phoenixsrc->config_filepath); phoenixsrc->config_filepath = g_strdup (g_value_get_string (value)); break; case PROP_NUM_CAPTURE_BUFFERS: if (phoenixsrc->acq_started) { GST_ELEMENT_WARNING (phoenixsrc, RESOURCE, SETTINGS, ("Number of capture buffers cannot be changed after acquisition has started."), (NULL)); } else { phoenixsrc->num_capture_buffers = g_value_get_uint (value); g_free (phoenixsrc->frame_start_times); phoenixsrc->frame_start_times = g_new (guint64, phoenixsrc->num_capture_buffers); g_free (phoenixsrc->frame_end_times); phoenixsrc->frame_end_times = g_new (guint64, phoenixsrc->num_capture_buffers); } break; case PROP_BOARD: phoenixsrc->board = g_value_get_uint (value); break; case PROP_CHANNEL: phoenixsrc->channel = g_value_get_uint (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; } }
static GstFlowReturn gst_face_blur_transform_ip (GstOpencvVideoFilter * transform, GstBuffer * buffer, IplImage * img) { GstFaceBlur *filter = GST_FACE_BLUR (transform); CvSeq *faces; int i; if (!filter->cvCascade) { if (filter->profile != NULL && filter->sent_profile_load_failed_msg == FALSE) { GST_ELEMENT_WARNING (filter, RESOURCE, NOT_FOUND, ("Profile %s is missing.", filter->profile), ("missing faceblur profile file %s", filter->profile)); filter->sent_profile_load_failed_msg = TRUE; } return GST_FLOW_OK; } cvCvtColor (img, filter->cvGray, CV_RGB2GRAY); cvClearMemStorage (filter->cvStorage); faces = cvHaarDetectObjects (filter->cvGray, filter->cvCascade, filter->cvStorage, filter->scale_factor, filter->min_neighbors, filter->flags, cvSize (filter->min_size_width, filter->min_size_height) #if (CV_MAJOR_VERSION >= 2) && (CV_MINOR_VERSION >= 2) , cvSize (filter->min_size_width + 2, filter->min_size_height + 2) #endif ); for (i = 0; i < (faces ? faces->total : 0); i++) { CvRect *r = (CvRect *) cvGetSeqElem (faces, i); cvSetImageROI (img, *r); cvSmooth (img, img, CV_BLUR, 11, 11, 0, 0); cvSmooth (img, img, CV_GAUSSIAN, 11, 11, 0, 0); cvResetImageROI (img); } return GST_FLOW_OK; }
static gboolean gst_aggregator_query_latency (GstAggregator * self, GstQuery * query) { LatencyData data; data.min = 0; data.max = GST_CLOCK_TIME_NONE; data.live = FALSE; /* query upstream's latency */ gst_aggregator_iterate_sinkpads (self, (GstAggregatorPadForeachFunc) _latency_query, &data); if (data.live && GST_CLOCK_TIME_IS_VALID (self->timeout) && self->timeout > data.max) { GST_ELEMENT_WARNING (self, CORE, NEGOTIATION, ("%s", "Timeout too big"), ("The requested timeout value is too big for the latency in the " "current pipeline. Limiting to %" G_GINT64_FORMAT, data.max)); self->timeout = data.max; } self->priv->latency_live = data.live; self->priv->latency_min = data.min; self->priv->latency_max = data.max; /* add our own */ if (GST_CLOCK_TIME_IS_VALID (self->timeout)) { if (GST_CLOCK_TIME_IS_VALID (data.min)) data.min += self->timeout; if (GST_CLOCK_TIME_IS_VALID (data.max)) data.max += self->timeout; } GST_DEBUG_OBJECT (self, "configured latency live:%s min:%" G_GINT64_FORMAT " max:%" G_GINT64_FORMAT, data.live ? "true" : "false", data.min, data.max); gst_query_set_latency (query, data.live, data.min, data.max); return TRUE; }
/** * gst_aggregator_set_timeout: * @agg: a #GstAggregator * @timeout: the new timeout value. * * Sets the new timeout value to @timeout. This value is used to limit the * amount of time a pad waits for data to appear before considering the pad * as unresponsive. */ static void gst_aggregator_set_timeout (GstAggregator * self, gint64 timeout) { g_return_if_fail (GST_IS_AGGREGATOR (self)); GST_OBJECT_LOCK (self); if (self->priv->latency_live && self->priv->latency_max != 0 && GST_CLOCK_TIME_IS_VALID (timeout) && timeout > self->priv->latency_max) { GST_ELEMENT_WARNING (self, CORE, NEGOTIATION, ("%s", "Timeout too big"), ("The requested timeout value is too big for the latency in the " "current pipeline. Limiting to %" G_GINT64_FORMAT, self->priv->latency_max)); timeout = self->priv->latency_max; } self->timeout = timeout; GST_OBJECT_UNLOCK (self); }
/* We take ownership of mask here */ static void gst_motiondetect_load_mask (StbtMotionDetect * filter, char* mask) { char *oldMaskFilename = NULL; IplImage *oldMaskImage = NULL, *newMaskImage = NULL; if (mask) { newMaskImage = cvLoadImage (mask, CV_LOAD_IMAGE_GRAYSCALE); if (!newMaskImage) { /* Unfortunately OpenCV doesn't seem to provide any way of finding out why the image load failed, so we can't be more specific than FAILED: */ GST_ELEMENT_WARNING (filter, RESOURCE, FAILED, ("OpenCV failed to load mask image"), ("While attempting to load mask '%s'", mask)); GST_WARNING ("Couldn't load mask image: %s. error: %s", mask, g_strerror (errno)); g_free (mask); mask = NULL; } gst_motiondetect_check_mask_compability(filter); } GST_OBJECT_LOCK(filter); oldMaskFilename = filter->mask; filter->mask = mask; oldMaskImage = filter->cvMaskImage; filter->cvMaskImage = newMaskImage; if (filter->cvInvertedMaskImage) { cvReleaseImage (&filter->cvInvertedMaskImage); filter->cvInvertedMaskImage = NULL; } if (filter->cvMaskImage) { filter->cvInvertedMaskImage = cvCloneImage (filter->cvMaskImage); cvNot(filter->cvMaskImage, filter->cvInvertedMaskImage); } GST_OBJECT_UNLOCK(filter); cvReleaseImage (&oldMaskImage); g_free(oldMaskFilename); }
void gst_play_sink_convert_bin_add_identity (GstPlaySinkConvertBin * self) { if (self->identity) return; self->identity = gst_element_factory_make ("identity", "identity"); if (self->identity == NULL) { gst_play_sink_convert_bin_post_missing_element_message (self, "identity"); GST_ELEMENT_WARNING (self, CORE, MISSING_PLUGIN, (_("Missing element '%s' - check your GStreamer installation."), "identity"), (self->audio ? "audio rendering might fail" : "video rendering might fail") ); } else { g_object_set (self->identity, "silent", TRUE, "signal-handoffs", FALSE, NULL); gst_bin_add (GST_BIN_CAST (self), self->identity); } }
static GstStateChangeReturn gst_wavenc_change_state (GstElement * element, GstStateChange transition) { GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS; GstWavEnc *wavenc = GST_WAVENC (element); switch (transition) { case GST_STATE_CHANGE_NULL_TO_READY: wavenc->format = 0; wavenc->channels = 0; wavenc->width = 0; wavenc->rate = 0; wavenc->length = 0; wavenc->sent_header = FALSE; /* its true because we haven't writen anything */ wavenc->finished_properly = TRUE; break; default: break; } ret = parent_class->change_state (element, transition); if (ret != GST_STATE_CHANGE_SUCCESS) return ret; switch (transition) { case GST_STATE_CHANGE_PAUSED_TO_READY: if (!wavenc->finished_properly) { GST_ELEMENT_WARNING (wavenc, STREAM, MUX, ("Wav stream not finished properly"), ("Wav stream not finished properly, no EOS received " "before shutdown")); } break; default: break; } return ret; }
static gboolean gst_identity_query (GstBaseTransform * base, GstPadDirection direction, GstQuery * query) { GstIdentity *identity; gboolean ret; identity = GST_IDENTITY (base); ret = GST_BASE_TRANSFORM_CLASS (parent_class)->query (base, direction, query); if (GST_QUERY_TYPE (query) == GST_QUERY_LATENCY) { gboolean live = FALSE; GstClockTime min = 0, max = 0; if (ret) { gst_query_parse_latency (query, &live, &min, &max); if (identity->sync && max < min) { GST_ELEMENT_WARNING (base, CORE, CLOCK, (NULL), ("Impossible to configure latency before identity sync=true:" " max %" GST_TIME_FORMAT " < min %" GST_TIME_FORMAT ". Add queues or other buffering elements.", GST_TIME_ARGS (max), GST_TIME_ARGS (min))); } } /* Ignore the upstream latency if it is not live */ GST_OBJECT_LOCK (identity); if (live) identity->upstream_latency = min; else identity->upstream_latency = 0; GST_OBJECT_UNLOCK (identity); gst_query_set_latency (query, live || identity->sync, min, max); ret = TRUE; } return ret; }
static GstBuffer * gst_rtp_g722_depay_process (GstRTPBaseDepayload * depayload, GstBuffer * buf) { GstRtpG722Depay *rtpg722depay; GstBuffer *outbuf; gint payload_len; gboolean marker; GstRTPBuffer rtp = { NULL }; rtpg722depay = GST_RTP_G722_DEPAY (depayload); gst_rtp_buffer_map (buf, GST_MAP_READ, &rtp); payload_len = gst_rtp_buffer_get_payload_len (&rtp); if (payload_len <= 0) goto empty_packet; GST_DEBUG_OBJECT (rtpg722depay, "got payload of %d bytes", payload_len); outbuf = gst_rtp_buffer_get_payload_buffer (&rtp); marker = gst_rtp_buffer_get_marker (&rtp); gst_rtp_buffer_unmap (&rtp); if (marker && outbuf) { /* mark talk spurt with DISCONT */ GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT); } return outbuf; /* ERRORS */ empty_packet: { GST_ELEMENT_WARNING (rtpg722depay, STREAM, DECODE, ("Empty Payload."), (NULL)); gst_rtp_buffer_unmap (&rtp); return NULL; } }
gboolean gst_v4l2_set_input (GstV4l2Object * v4l2object, gint input) { GST_DEBUG_OBJECT (v4l2object->element, "trying to set input to %d", input); if (!GST_V4L2_IS_OPEN (v4l2object)) return FALSE; if (v4l2_ioctl (v4l2object->video_fd, VIDIOC_S_INPUT, &input) < 0) goto input_failed; return TRUE; /* ERRORS */ input_failed: { GST_ELEMENT_WARNING (v4l2object->element, RESOURCE, SETTINGS, (_("Failed to set input %d on device %s."), input, v4l2object->videodev), GST_ERROR_SYSTEM); return FALSE; } }
/****************************************************** * gst_v4l2_set_norm() * Set the norm of the current device * return value: TRUE on success, FALSE on error ******************************************************/ gboolean gst_v4l2_set_norm (GstV4l2Object * v4l2object, v4l2_std_id norm) { GST_DEBUG_OBJECT (v4l2object->element, "trying to set norm to %llx", norm); if (!GST_V4L2_IS_OPEN (v4l2object)) return FALSE; if (v4l2_ioctl (v4l2object->video_fd, VIDIOC_S_STD, &norm) < 0) goto std_failed; return TRUE; /* ERRORS */ std_failed: { GST_ELEMENT_WARNING (v4l2object->element, RESOURCE, SETTINGS, (_("Failed to set norm for device '%s'."), v4l2object->videodev), GST_ERROR_SYSTEM); return FALSE; } }
void gst_decklink_video_sink_set_property (GObject * object, guint property_id, const GValue * value, GParamSpec * pspec) { GstDecklinkVideoSink *self = GST_DECKLINK_VIDEO_SINK_CAST (object); switch (property_id) { case PROP_MODE: self->mode = (GstDecklinkModeEnum) g_value_get_enum (value); break; case PROP_DEVICE_NUMBER: self->device_number = g_value_get_int (value); break; case PROP_VIDEO_FORMAT: self->video_format = (GstDecklinkVideoFormat) g_value_get_enum (value); switch (self->video_format) { case GST_DECKLINK_VIDEO_FORMAT_AUTO: case GST_DECKLINK_VIDEO_FORMAT_8BIT_YUV: case GST_DECKLINK_VIDEO_FORMAT_10BIT_YUV: case GST_DECKLINK_VIDEO_FORMAT_8BIT_ARGB: case GST_DECKLINK_VIDEO_FORMAT_8BIT_BGRA: break; default: GST_ELEMENT_WARNING (GST_ELEMENT (self), CORE, NOT_IMPLEMENTED, ("Format %d not supported", self->video_format), (NULL)); break; } break; case PROP_TIMECODE_FORMAT: self->timecode_format = gst_decklink_timecode_format_from_enum ((GstDecklinkTimecodeFormat) g_value_get_enum (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; } }
static void kms_recorder_end_point_dispose (GObject * object) { KmsRecorderEndPoint *self = KMS_RECORDER_END_POINT (object); g_clear_object (&self->priv->loop); g_clear_object (&self->priv->controller); if (self->priv->pipeline != NULL) { if (GST_STATE (self->priv->pipeline) != GST_STATE_NULL) { GST_ELEMENT_WARNING (self, RESOURCE, BUSY, ("Recorder may have buffers to save"), ("Disposing recorder when it isn't stopped.")); } gst_element_set_state (self->priv->pipeline, GST_STATE_NULL); g_object_unref (self->priv->pipeline); self->priv->pipeline = NULL; } /* clean up as possible. may be called multiple times */ G_OBJECT_CLASS (kms_recorder_end_point_parent_class)->dispose (object); }
static void pad_blocked_cb (GstPad * pad, gboolean blocked, GstPlaySinkVideoConvert * self) { GstPad *peer; GstCaps *caps; gboolean raw; GST_PLAY_SINK_VIDEO_CONVERT_LOCK (self); self->sink_proxypad_blocked = blocked; GST_DEBUG_OBJECT (self, "Pad blocked: %d", blocked); if (!blocked) goto done; /* There must be a peer at this point */ peer = gst_pad_get_peer (self->sinkpad); caps = gst_pad_get_negotiated_caps (peer); if (!caps) caps = gst_pad_get_caps_reffed (peer); gst_object_unref (peer); raw = is_raw_caps (caps); GST_DEBUG_OBJECT (self, "Caps %" GST_PTR_FORMAT " are raw: %d", caps, raw); gst_caps_unref (caps); if (raw == self->raw) goto unblock; self->raw = raw; if (raw) { GstBin *bin = GST_BIN_CAST (self); GstElement *head = NULL, *prev = NULL; GstPad *pad; GST_DEBUG_OBJECT (self, "Creating raw conversion pipeline"); gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (self->sinkpad), NULL); gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (self->srcpad), NULL); self->conv = gst_element_factory_make ("ffmpegcolorspace", "conv"); if (self->conv == NULL) { post_missing_element_message (self, "ffmpegcolorspace"); GST_ELEMENT_WARNING (self, CORE, MISSING_PLUGIN, (_("Missing element '%s' - check your GStreamer installation."), "ffmpegcolorspace"), ("video rendering might fail")); } else { gst_bin_add (bin, self->conv); gst_element_sync_state_with_parent (self->conv); distribute_running_time (self->conv, &self->segment); prev = head = self->conv; } self->scale = gst_element_factory_make ("videoscale", "scale"); if (self->scale == NULL) { post_missing_element_message (self, "videoscale"); GST_ELEMENT_WARNING (self, CORE, MISSING_PLUGIN, (_("Missing element '%s' - check your GStreamer installation."), "videoscale"), ("possibly a liboil version mismatch?")); } else { /* Add black borders if necessary to keep the DAR */ g_object_set (self->scale, "add-borders", TRUE, NULL); gst_bin_add (bin, self->scale); gst_element_sync_state_with_parent (self->scale); distribute_running_time (self->scale, &self->segment); if (prev) { if (!gst_element_link_pads_full (prev, "src", self->scale, "sink", GST_PAD_LINK_CHECK_TEMPLATE_CAPS)) goto link_failed; } else { head = self->scale; } prev = self->scale; } if (head) { pad = gst_element_get_static_pad (head, "sink"); gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (self->sinkpad), pad); gst_object_unref (pad); } if (prev) { pad = gst_element_get_static_pad (prev, "src"); gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (self->srcpad), pad); gst_object_unref (pad); } if (!head && !prev) { gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (self->srcpad), self->sink_proxypad); } GST_DEBUG_OBJECT (self, "Raw conversion pipeline created"); } else { GstBin *bin = GST_BIN_CAST (self); GST_DEBUG_OBJECT (self, "Removing raw conversion pipeline"); gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (self->sinkpad), NULL); gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (self->srcpad), NULL); if (self->conv) { gst_element_set_state (self->conv, GST_STATE_NULL); gst_bin_remove (bin, self->conv); self->conv = NULL; } if (self->scale) { gst_element_set_state (self->scale, GST_STATE_NULL); gst_bin_remove (bin, self->scale); self->scale = NULL; } gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (self->srcpad), self->sink_proxypad); GST_DEBUG_OBJECT (self, "Raw conversion pipeline removed"); } unblock: gst_pad_set_blocked_async_full (self->sink_proxypad, FALSE, (GstPadBlockCallback) pad_blocked_cb, gst_object_ref (self), (GDestroyNotify) gst_object_unref); done: GST_PLAY_SINK_VIDEO_CONVERT_UNLOCK (self); return; link_failed: { GST_ELEMENT_ERROR (self, CORE, PAD, (NULL), ("Failed to configure the video converter.")); gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (self->srcpad), self->sink_proxypad); gst_pad_set_blocked_async_full (self->sink_proxypad, FALSE, (GstPadBlockCallback) pad_blocked_cb, gst_object_ref (self), (GDestroyNotify) gst_object_unref); return; } }
static GstFlowReturn gst_opus_dec_parse_header (GstOpusDec * dec, GstBuffer * buf) { const guint8 *data; GstAudioChannelPosition pos[64]; const GstAudioChannelPosition *posn = NULL; GstMapInfo map; if (!gst_opus_header_is_id_header (buf)) { GST_ERROR_OBJECT (dec, "Header is not an Opus ID header"); return GST_FLOW_ERROR; } gst_buffer_map (buf, &map, GST_MAP_READ); data = map.data; if (!(dec->n_channels == 0 || dec->n_channels == data[9])) { gst_buffer_unmap (buf, &map); GST_ERROR_OBJECT (dec, "Opus ID header has invalid channels"); return GST_FLOW_ERROR; } dec->n_channels = data[9]; dec->sample_rate = GST_READ_UINT32_LE (data + 12); dec->pre_skip = GST_READ_UINT16_LE (data + 10); dec->r128_gain = GST_READ_UINT16_LE (data + 16); dec->r128_gain_volume = gst_opus_dec_get_r128_volume (dec->r128_gain); GST_INFO_OBJECT (dec, "Found pre-skip of %u samples, R128 gain %d (volume %f)", dec->pre_skip, dec->r128_gain, dec->r128_gain_volume); dec->channel_mapping_family = data[18]; if (dec->channel_mapping_family == 0) { /* implicit mapping */ GST_INFO_OBJECT (dec, "Channel mapping family 0, implicit mapping"); dec->n_streams = dec->n_stereo_streams = 1; dec->channel_mapping[0] = 0; dec->channel_mapping[1] = 1; } else { dec->n_streams = data[19]; dec->n_stereo_streams = data[20]; memcpy (dec->channel_mapping, data + 21, dec->n_channels); if (dec->channel_mapping_family == 1) { GST_INFO_OBJECT (dec, "Channel mapping family 1, Vorbis mapping"); switch (dec->n_channels) { case 1: case 2: /* nothing */ break; case 3: case 4: case 5: case 6: case 7: case 8: posn = gst_opus_channel_positions[dec->n_channels - 1]; break; default:{ gint i; GST_ELEMENT_WARNING (GST_ELEMENT (dec), STREAM, DECODE, (NULL), ("Using NONE channel layout for more than 8 channels")); for (i = 0; i < dec->n_channels; i++) pos[i] = GST_AUDIO_CHANNEL_POSITION_NONE; posn = pos; } } } else { GST_INFO_OBJECT (dec, "Channel mapping family %d", dec->channel_mapping_family); } } gst_opus_dec_negotiate (dec, posn); gst_buffer_unmap (buf, &map); return GST_FLOW_OK; }
static GstBuffer * gst_rtp_j2k_depay_process (GstBaseRTPDepayload * depayload, GstBuffer * buf) { GstRtpJ2KDepay *rtpj2kdepay; guint8 *payload; guint MHF, mh_id, frag_offset, tile, payload_len, j2klen; gint gap; guint32 rtptime; rtpj2kdepay = GST_RTP_J2K_DEPAY (depayload); payload = gst_rtp_buffer_get_payload (buf); payload_len = gst_rtp_buffer_get_payload_len (buf); /* we need at least a header */ if (payload_len < 8) goto empty_packet; rtptime = gst_rtp_buffer_get_timestamp (buf); /* new timestamp marks new frame */ if (rtpj2kdepay->last_rtptime != rtptime) { rtpj2kdepay->last_rtptime = rtptime; /* flush pending frame */ gst_rtp_j2k_depay_flush_frame (depayload); } /* * 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 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * |tp |MHF|mh_id|T| priority | tile number | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * |reserved | fragment offset | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ MHF = (payload[0] & 0x30) >> 4; mh_id = (payload[0] & 0xe) >> 1; if (rtpj2kdepay->last_mh_id == -1) rtpj2kdepay->last_mh_id = mh_id; else if (rtpj2kdepay->last_mh_id != mh_id) goto wrong_mh_id; tile = (payload[2] << 8) | payload[3]; frag_offset = (payload[5] << 16) | (payload[6] << 8) | payload[7]; j2klen = payload_len - 8; GST_DEBUG_OBJECT (rtpj2kdepay, "MHF %u, tile %u, frag %u, expected %u", MHF, tile, frag_offset, rtpj2kdepay->next_frag); /* calculate the gap between expected frag */ gap = frag_offset - rtpj2kdepay->next_frag; /* calculate next frag */ rtpj2kdepay->next_frag = frag_offset + j2klen; if (gap != 0) { GST_DEBUG_OBJECT (rtpj2kdepay, "discont of %d, clear PU", gap); /* discont, clear pu adapter and resync */ gst_rtp_j2k_depay_clear_pu (rtpj2kdepay); } /* check for sync code */ if (j2klen > 2 && payload[8] == 0xff) { guint marker = payload[9]; /* packets must start with SOC, SOT or SOP */ switch (marker) { case J2K_MARKER_SOC: GST_DEBUG_OBJECT (rtpj2kdepay, "found SOC packet"); /* flush the previous frame, should have happened when the timestamp * changed above. */ gst_rtp_j2k_depay_flush_frame (depayload); rtpj2kdepay->have_sync = TRUE; break; case J2K_MARKER_SOT: /* flush the previous tile */ gst_rtp_j2k_depay_flush_tile (depayload); GST_DEBUG_OBJECT (rtpj2kdepay, "found SOT packet"); rtpj2kdepay->have_sync = TRUE; /* we sync on the tile now */ rtpj2kdepay->last_tile = tile; break; case J2K_MARKER_SOP: GST_DEBUG_OBJECT (rtpj2kdepay, "found SOP packet"); /* flush the previous PU */ gst_rtp_j2k_depay_flush_pu (depayload); if (rtpj2kdepay->last_tile != tile) { /* wrong tile, we lose sync and we need a new SOT or SOC to regain * sync. First flush out the previous tile if we have one. */ if (rtpj2kdepay->last_tile != -1) gst_rtp_j2k_depay_flush_tile (depayload); /* now we have no more valid tile and no sync */ rtpj2kdepay->last_tile = -1; rtpj2kdepay->have_sync = FALSE; } else { rtpj2kdepay->have_sync = TRUE; } break; default: GST_DEBUG_OBJECT (rtpj2kdepay, "no sync packet 0x%02d", marker); break; } } if (rtpj2kdepay->have_sync) { GstBuffer *pu_frag; if (gst_adapter_available (rtpj2kdepay->pu_adapter) == 0) { /* first part of pu, record state */ GST_DEBUG_OBJECT (rtpj2kdepay, "first PU"); rtpj2kdepay->pu_MHF = MHF; } /* and push in pu adapter */ GST_DEBUG_OBJECT (rtpj2kdepay, "push pu of size %u in adapter", j2klen); pu_frag = gst_rtp_buffer_get_payload_subbuffer (buf, 8, -1); gst_adapter_push (rtpj2kdepay->pu_adapter, pu_frag); if (MHF & 2) { /* last part of main header received, we can flush it */ GST_DEBUG_OBJECT (rtpj2kdepay, "header end, flush pu"); gst_rtp_j2k_depay_flush_pu (depayload); } } else { GST_DEBUG_OBJECT (rtpj2kdepay, "discard packet, no sync"); } /* marker bit finishes the frame */ if (gst_rtp_buffer_get_marker (buf)) { GST_DEBUG_OBJECT (rtpj2kdepay, "marker set, last buffer"); /* then flush frame */ gst_rtp_j2k_depay_flush_frame (depayload); } return NULL; /* ERRORS */ empty_packet: { GST_ELEMENT_WARNING (rtpj2kdepay, STREAM, DECODE, ("Empty Payload."), (NULL)); return NULL; } wrong_mh_id: { GST_ELEMENT_WARNING (rtpj2kdepay, STREAM, DECODE, ("Invalid mh_id %u, expected %u", mh_id, rtpj2kdepay->last_mh_id), (NULL)); gst_rtp_j2k_depay_clear_pu (rtpj2kdepay); return NULL; } }
static GstFlowReturn gst_rtp_j2k_depay_flush_tile (GstBaseRTPDepayload * depayload) { GstRtpJ2KDepay *rtpj2kdepay; guint avail, mh_id; GList *packets, *walk; guint8 end[2]; GstFlowReturn ret = GST_FLOW_OK; rtpj2kdepay = GST_RTP_J2K_DEPAY (depayload); /* flush pending PU */ gst_rtp_j2k_depay_flush_pu (depayload); /* take all available buffers */ avail = gst_adapter_available (rtpj2kdepay->t_adapter); if (avail == 0) goto done; mh_id = rtpj2kdepay->last_mh_id; GST_DEBUG_OBJECT (rtpj2kdepay, "flushing tile of size %u", avail); if (gst_adapter_available (rtpj2kdepay->f_adapter) == 0) { GstBuffer *mheader; /* we need a header now */ if ((mheader = rtpj2kdepay->MH[mh_id]) == NULL) goto waiting_header; /* push header in the adapter */ GST_DEBUG_OBJECT (rtpj2kdepay, "pushing header %u", mh_id); gst_adapter_push (rtpj2kdepay->f_adapter, gst_buffer_ref (mheader)); } /* check for last bytes */ gst_adapter_copy (rtpj2kdepay->t_adapter, end, avail - 2, 2); /* now append the tile packets to the frame */ packets = gst_adapter_take_list (rtpj2kdepay->t_adapter, avail); for (walk = packets; walk; walk = g_list_next (walk)) { GstBuffer *buf = GST_BUFFER_CAST (walk->data); if (walk == packets) { guint8 *data; guint size; /* first buffer should contain the SOT */ data = GST_BUFFER_DATA (buf); size = GST_BUFFER_SIZE (buf); if (size < 12) goto invalid_tile; if (data[0] == 0xff && data[1] == J2K_MARKER_SOT) { guint Psot, nPsot; if (end[0] == 0xff && end[1] == J2K_MARKER_EOC) nPsot = avail - 2; else nPsot = avail; Psot = GST_READ_UINT32_BE (&data[6]); if (Psot != nPsot && Psot != 0) { /* Psot must match the size of the tile */ GST_DEBUG_OBJECT (rtpj2kdepay, "set Psot from %u to %u", Psot, nPsot); buf = gst_buffer_make_writable (buf); data = GST_BUFFER_DATA (buf); GST_WRITE_UINT32_BE (&data[6], nPsot); } } } GST_DEBUG_OBJECT (rtpj2kdepay, "append pu packet of size %u", GST_BUFFER_SIZE (buf)); gst_adapter_push (rtpj2kdepay->f_adapter, buf); } g_list_free (packets); done: rtpj2kdepay->last_tile = -1; return ret; /* errors */ waiting_header: { GST_DEBUG_OBJECT (rtpj2kdepay, "waiting for header %u", mh_id); gst_adapter_clear (rtpj2kdepay->t_adapter); rtpj2kdepay->last_tile = -1; return ret; } invalid_tile: { GST_ELEMENT_WARNING (rtpj2kdepay, STREAM, DECODE, ("Invalid tile"), (NULL)); gst_adapter_clear (rtpj2kdepay->t_adapter); rtpj2kdepay->last_tile = -1; return ret; } }
/* create a socket for sending to remote machine */ static void gst_sctp_base_sink_create_socket (GstSCTPBaseSink * self) { GSocketAddress *saddr; GResolver *resolver; GInetAddress *addr; GError *err = NULL; if (GST_OBJECT_FLAG_IS_SET (self, GST_SCTP_BASE_SINK_OPEN)) return; /* look up name if we need to */ addr = g_inet_address_new_from_string (self->priv->host); if (addr == NULL) { GList *results; resolver = g_resolver_get_default (); results = g_resolver_lookup_by_name (resolver, self->priv->host, self->priv->cancellable, &err); if (results == NULL) goto name_resolve; addr = G_INET_ADDRESS (g_object_ref (results->data)); g_resolver_free_addresses (results); g_object_unref (resolver); } if (G_UNLIKELY (GST_LEVEL_DEBUG <= _gst_debug_min)) { gchar *ip = g_inet_address_to_string (addr); GST_DEBUG_OBJECT (self, "IP address for host %s is %s", self->priv->host, ip); g_free (ip); } saddr = g_inet_socket_address_new (addr, self->priv->port); g_object_unref (addr); /* create sending client socket */ GST_DEBUG_OBJECT (self, "opening sending client socket to %s:%d", self->priv->host, self->priv->port); self->priv->socket = g_socket_new (g_socket_address_get_family (saddr), G_SOCKET_TYPE_STREAM, G_SOCKET_PROTOCOL_SCTP, &err); if (self->priv->socket == NULL) goto no_socket; #if defined (SCTP_INITMSG) { struct sctp_initmsg initmsg; memset (&initmsg, 0, sizeof (initmsg)); initmsg.sinit_num_ostreams = self->priv->num_ostreams; initmsg.sinit_max_instreams = self->priv->max_istreams; if (setsockopt (g_socket_get_fd (self->priv->socket), IPPROTO_SCTP, SCTP_INITMSG, &initmsg, sizeof (initmsg)) < 0) GST_ELEMENT_WARNING (self, RESOURCE, SETTINGS, (NULL), ("Could not configure SCTP socket: %s (%d)", g_strerror (errno), errno)); } #else GST_WARNING_OBJECT (self, "don't know how to configure the SCTP initiation " "parameters on this OS."); #endif GST_DEBUG_OBJECT (self, "opened sending client socket"); /* connect to server */ if (!g_socket_connect (self->priv->socket, saddr, self->priv->cancellable, &err)) goto connect_failed; g_object_unref (saddr); GST_OBJECT_FLAG_SET (self, GST_SCTP_BASE_SINK_OPEN); GST_DEBUG ("Created sctp socket"); return; no_socket: { GST_ELEMENT_ERROR (self, RESOURCE, OPEN_READ, (NULL), ("Failed to create socket: %s", err->message)); g_clear_error (&err); g_object_unref (saddr); return; } name_resolve: { if (g_error_matches (err, G_IO_ERROR, G_IO_ERROR_CANCELLED)) { GST_DEBUG_OBJECT (self, "Cancelled name resolval"); } else { GST_ELEMENT_ERROR (self, RESOURCE, OPEN_READ, (NULL), ("Failed to resolve host '%s': %s", self->priv->host, err->message)); } g_clear_error (&err); g_object_unref (resolver); return; } connect_failed: { if (g_error_matches (err, G_IO_ERROR, G_IO_ERROR_CANCELLED)) { GST_DEBUG_OBJECT (self, "Cancelled connecting"); } else { GST_ELEMENT_ERROR (self, RESOURCE, OPEN_READ, (NULL), ("Failed to connect to host '%s:%d': %s", self->priv->host, self->priv->port, err->message)); } g_clear_error (&err); g_object_unref (saddr); /* pretend we opened ok for proper cleanup to happen */ GST_OBJECT_FLAG_SET (self, GST_SCTP_BASE_SINK_OPEN); gst_sctp_base_sink_destroy_socket (self); return; } }
static GstBuffer * gst_rtp_jpeg_depay_process (GstRTPBaseDepayload * depayload, GstRTPBuffer * rtp) { GstRtpJPEGDepay *rtpjpegdepay; GstBuffer *outbuf; gint payload_len, header_len; guint8 *payload; guint frag_offset; gint Q; guint type, width, height; guint16 dri, precision, length; guint8 *qtable; rtpjpegdepay = GST_RTP_JPEG_DEPAY (depayload); if (GST_BUFFER_IS_DISCONT (rtp->buffer)) { GST_DEBUG_OBJECT (depayload, "DISCONT, reset adapter"); gst_adapter_clear (rtpjpegdepay->adapter); rtpjpegdepay->discont = TRUE; } payload_len = gst_rtp_buffer_get_payload_len (rtp); if (payload_len < 8) goto empty_packet; payload = gst_rtp_buffer_get_payload (rtp); header_len = 0; /* 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 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Type-specific | Fragment Offset | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Type | Q | Width | Height | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ frag_offset = (payload[1] << 16) | (payload[2] << 8) | payload[3]; type = payload[4]; Q = payload[5]; width = payload[6] * 8; height = payload[7] * 8; /* saw a packet with fragment offset > 0 and we don't already have data queued * up (most importantly, we don't have a header for this data) -- drop it * XXX: maybe we can check if the jpeg is progressive and salvage the data? * XXX: not implemented yet because jpegenc can't create progressive jpegs */ if (frag_offset > 0 && gst_adapter_available (rtpjpegdepay->adapter) == 0) goto no_header_packet; /* allow frame dimensions > 2040, passed in SDP session or media attributes * from gstrtspsrc.c (gst_rtspsrc_sdp_attributes_to_caps), or in caps */ if (!width) width = rtpjpegdepay->media_width; if (!height) height = rtpjpegdepay->media_height; if (width == 0 || height == 0) goto invalid_dimension; GST_DEBUG_OBJECT (rtpjpegdepay, "frag %u, type %u, Q %d, width %u, height %u", frag_offset, type, Q, width, height); header_len += 8; payload += 8; payload_len -= 8; dri = 0; if (type > 63) { if (payload_len < 4) goto empty_packet; /* 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 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Restart Interval |F|L| Restart Count | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ dri = (payload[0] << 8) | payload[1]; GST_DEBUG_OBJECT (rtpjpegdepay, "DRI %" G_GUINT16_FORMAT, dri); payload += 4; header_len += 4; payload_len -= 4; } if (Q >= 128 && frag_offset == 0) { if (payload_len < 4) goto empty_packet; /* 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 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | MBZ | Precision | Length | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Quantization Table Data | * | ... | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ precision = payload[1]; length = (payload[2] << 8) | payload[3]; GST_DEBUG_OBJECT (rtpjpegdepay, "precision %04x, length %" G_GUINT16_FORMAT, precision, length); if (Q == 255 && length == 0) goto empty_packet; payload += 4; header_len += 4; payload_len -= 4; if (length > payload_len) goto empty_packet; if (length > 0) qtable = payload; else qtable = rtpjpegdepay->qtables[Q]; payload += length; header_len += length; payload_len -= length; } else { length = 0; qtable = NULL; precision = 0; } if (frag_offset == 0) { GstMapInfo map; guint size; if (rtpjpegdepay->width != width || rtpjpegdepay->height != height) { GstCaps *outcaps; outcaps = gst_caps_new_simple ("image/jpeg", "framerate", GST_TYPE_FRACTION, rtpjpegdepay->frate_num, rtpjpegdepay->frate_denom, "width", G_TYPE_INT, width, "height", G_TYPE_INT, height, NULL); gst_pad_set_caps (depayload->srcpad, outcaps); gst_caps_unref (outcaps); rtpjpegdepay->width = width; rtpjpegdepay->height = height; } GST_LOG_OBJECT (rtpjpegdepay, "first packet, length %" G_GUINT16_FORMAT, length); /* first packet */ if (length == 0) { if (Q < 128) { /* no quant table, see if we have one cached */ qtable = rtpjpegdepay->qtables[Q]; if (!qtable) { GST_DEBUG_OBJECT (rtpjpegdepay, "making Q %d table", Q); /* make and cache the table */ qtable = g_new (guint8, 128); MakeTables (rtpjpegdepay, Q, qtable); rtpjpegdepay->qtables[Q] = qtable; } else { GST_DEBUG_OBJECT (rtpjpegdepay, "using cached table for Q %d", Q); } /* all 8 bit quantizers */ precision = 0; } else { if (!qtable) goto no_qtable; } } /* I think we can get here with a NULL qtable, so make sure we don't go dereferencing it in MakeHeaders if we do */ if (!qtable) goto no_qtable; /* max header length, should be big enough */ outbuf = gst_buffer_new_and_alloc (1000); gst_buffer_map (outbuf, &map, GST_MAP_WRITE); size = MakeHeaders (map.data, type, width, height, qtable, precision, dri); gst_buffer_unmap (outbuf, &map); gst_buffer_resize (outbuf, 0, size); GST_DEBUG_OBJECT (rtpjpegdepay, "pushing %u bytes of header", size); gst_adapter_push (rtpjpegdepay->adapter, outbuf); } /* take JPEG data, push in the adapter */ GST_DEBUG_OBJECT (rtpjpegdepay, "pushing data at offset %d", header_len); outbuf = gst_rtp_buffer_get_payload_subbuffer (rtp, header_len, -1); gst_adapter_push (rtpjpegdepay->adapter, outbuf); outbuf = NULL; if (gst_rtp_buffer_get_marker (rtp)) { guint avail; guint8 end[2]; GstMapInfo map; /* last buffer take all data out of the adapter */ avail = gst_adapter_available (rtpjpegdepay->adapter); GST_DEBUG_OBJECT (rtpjpegdepay, "marker set, last buffer"); if (avail < 2) goto invalid_packet; /* take the last bytes of the jpeg data to see if there is an EOI * marker */ gst_adapter_copy (rtpjpegdepay->adapter, end, avail - 2, 2); if (end[0] != 0xff && end[1] != 0xd9) { GST_DEBUG_OBJECT (rtpjpegdepay, "no EOI marker, adding one"); /* no EOI marker, add one */ outbuf = gst_buffer_new_and_alloc (2); gst_buffer_map (outbuf, &map, GST_MAP_WRITE); map.data[0] = 0xff; map.data[1] = 0xd9; gst_buffer_unmap (outbuf, &map); gst_adapter_push (rtpjpegdepay->adapter, outbuf); avail += 2; } outbuf = gst_adapter_take_buffer (rtpjpegdepay->adapter, avail); if (rtpjpegdepay->discont) { GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT); rtpjpegdepay->discont = FALSE; } gst_rtp_drop_meta (GST_ELEMENT_CAST (rtpjpegdepay), outbuf, g_quark_from_static_string (GST_META_TAG_VIDEO_STR)); GST_DEBUG_OBJECT (rtpjpegdepay, "returning %u bytes", avail); } return outbuf; /* ERRORS */ empty_packet: { GST_ELEMENT_WARNING (rtpjpegdepay, STREAM, DECODE, ("Empty Payload."), (NULL)); return NULL; } invalid_dimension: { GST_ELEMENT_WARNING (rtpjpegdepay, STREAM, FORMAT, ("Invalid Dimension %dx%d.", width, height), (NULL)); return NULL; } no_qtable: { GST_WARNING_OBJECT (rtpjpegdepay, "no qtable"); return NULL; } invalid_packet: { GST_WARNING_OBJECT (rtpjpegdepay, "invalid packet"); gst_adapter_flush (rtpjpegdepay->adapter, gst_adapter_available (rtpjpegdepay->adapter)); return NULL; } no_header_packet: { GST_WARNING_OBJECT (rtpjpegdepay, "discarding data packets received when we have no header"); return NULL; } }
/* allocate a buffer and setup resources to process the audio samples of * the format as specified in @spec. * * We allocate N jack ports, one for each channel. If we are asked to * automatically make a connection with physical ports, we connect as many * ports as there are physical ports, leaving leftover ports unconnected. * * It is assumed that samplerate and number of channels are acceptable since our * getcaps method will always provide correct values. If unacceptable caps are * received for some reason, we fail here. */ static gboolean gst_jack_ring_buffer_acquire (GstRingBuffer * buf, GstRingBufferSpec * spec) { GstJackAudioSrc *src; GstJackRingBuffer *abuf; const char **ports; gint sample_rate, buffer_size; gint i, channels, res; jack_client_t *client; src = GST_JACK_AUDIO_SRC (GST_OBJECT_PARENT (buf)); abuf = GST_JACK_RING_BUFFER_CAST (buf); GST_DEBUG_OBJECT (src, "acquire"); client = gst_jack_audio_client_get_client (src->client); /* sample rate must be that of the server */ sample_rate = jack_get_sample_rate (client); if (sample_rate != spec->rate) goto wrong_samplerate; channels = spec->channels; if (!gst_jack_audio_src_allocate_channels (src, channels)) goto out_of_ports; buffer_size = jack_get_buffer_size (client); /* the segment size in bytes, this is large enough to hold a buffer of 32bit floats * for all channels */ spec->segsize = buffer_size * sizeof (gfloat) * channels; spec->latency_time = gst_util_uint64_scale (spec->segsize, (GST_SECOND / GST_USECOND), spec->rate * spec->bytes_per_sample); /* segtotal based on buffer-time latency */ spec->segtotal = spec->buffer_time / spec->latency_time; GST_DEBUG_OBJECT (src, "segsize %d, segtotal %d", spec->segsize, spec->segtotal); /* allocate the ringbuffer memory now */ buf->data = gst_buffer_new_and_alloc (spec->segtotal * spec->segsize); memset (GST_BUFFER_DATA (buf->data), 0, GST_BUFFER_SIZE (buf->data)); if ((res = gst_jack_audio_client_set_active (src->client, TRUE))) goto could_not_activate; /* if we need to automatically connect the ports, do so now. We must do this * after activating the client. */ if (src->connect == GST_JACK_CONNECT_AUTO) { /* find all the physical output ports. A physical output port is a port * associated with a hardware device. Someone needs connect to a physical * port in order to capture something. */ ports = jack_get_ports (client, NULL, NULL, JackPortIsPhysical | JackPortIsOutput); if (ports == NULL) { /* no ports? fine then we don't do anything except for posting a warning * message. */ GST_ELEMENT_WARNING (src, RESOURCE, NOT_FOUND, (NULL), ("No physical output ports found, leaving ports unconnected")); goto done; } for (i = 0; i < channels; i++) { /* stop when all output ports are exhausted */ if (ports[i] == NULL) { /* post a warning that we could not connect all ports */ GST_ELEMENT_WARNING (src, RESOURCE, NOT_FOUND, (NULL), ("No more physical ports, leaving some ports unconnected")); break; } GST_DEBUG_OBJECT (src, "try connecting to %s", jack_port_name (src->ports[i])); /* connect the physical port to a port */ res = jack_connect (client, ports[i], jack_port_name (src->ports[i])); g_print ("connecting to %s\n", jack_port_name (src->ports[i])); if (res != 0 && res != EEXIST) goto cannot_connect; } free (ports); } done: abuf->sample_rate = sample_rate; abuf->buffer_size = buffer_size; abuf->channels = spec->channels; return TRUE; /* ERRORS */ wrong_samplerate: { GST_ELEMENT_ERROR (src, RESOURCE, SETTINGS, (NULL), ("Wrong samplerate, server is running at %d and we received %d", sample_rate, spec->rate)); return FALSE; } out_of_ports: { GST_ELEMENT_ERROR (src, RESOURCE, SETTINGS, (NULL), ("Cannot allocate more Jack ports")); return FALSE; } could_not_activate: { GST_ELEMENT_ERROR (src, RESOURCE, SETTINGS, (NULL), ("Could not activate client (%d:%s)", res, g_strerror (res))); return FALSE; } cannot_connect: { GST_ELEMENT_ERROR (src, RESOURCE, SETTINGS, (NULL), ("Could not connect input ports to physical ports (%d:%s)", res, g_strerror (res))); free (ports); return FALSE; } }
static void demux_pad_added (GstElement * element, GstPad * pad, RsnDvdBin * dvdbin) { gboolean skip_mq = FALSE; GstPad *mq_pad = NULL; GstPad *dest_pad = NULL; GstCaps *caps; GstStructure *s; GST_DEBUG_OBJECT (dvdbin, "New pad: %" GST_PTR_FORMAT, pad); caps = gst_pad_get_caps (pad); if (caps == NULL) { GST_WARNING_OBJECT (dvdbin, "NULL caps from pad %" GST_PTR_FORMAT, pad); return; } if (!gst_caps_is_fixed (caps)) { GST_WARNING_OBJECT (dvdbin, "Unfixed caps %" GST_PTR_FORMAT " on pad %" GST_PTR_FORMAT, caps, pad); gst_caps_unref (caps); return; } GST_DEBUG_OBJECT (dvdbin, "Pad %" GST_PTR_FORMAT " has caps: %" GST_PTR_FORMAT, pad, caps); s = gst_caps_get_structure (caps, 0); g_return_if_fail (s != NULL); if (can_sink_caps (dvdbin->pieces[DVD_ELEM_VIDDEC], caps)) { dest_pad = gst_element_get_static_pad (dvdbin->pieces[DVD_ELEM_VIDDEC], "sink"); } else if (g_str_equal (gst_structure_get_name (s), "video/x-dvd-subpicture")) { dest_pad = gst_element_get_request_pad (dvdbin->pieces[DVD_ELEM_SPU_SELECT], "sink%d"); skip_mq = TRUE; } else if (can_sink_caps (dvdbin->pieces[DVD_ELEM_AUDDEC], caps)) { GST_LOG_OBJECT (dvdbin, "Found audio pad w/ caps %" GST_PTR_FORMAT, caps); dest_pad = gst_element_get_request_pad (dvdbin->pieces[DVD_ELEM_AUD_SELECT], "sink%d"); } else { GstStructure *s; GST_DEBUG_OBJECT (dvdbin, "Ignoring unusable pad w/ caps %" GST_PTR_FORMAT, caps); gst_element_post_message (GST_ELEMENT_CAST (dvdbin), gst_missing_decoder_message_new (GST_ELEMENT_CAST (dvdbin), caps)); s = gst_caps_get_structure (caps, 0); if (g_str_has_prefix ("video/", gst_structure_get_name (s))) { GST_ELEMENT_ERROR (dvdbin, STREAM, CODEC_NOT_FOUND, (NULL), ("No MPEG video decoder found")); } else { GST_ELEMENT_WARNING (dvdbin, STREAM, CODEC_NOT_FOUND, (NULL), ("No MPEG video decoder found")); } } gst_caps_unref (caps); if (dest_pad == NULL) { GST_DEBUG_OBJECT (dvdbin, "Don't know how to handle pad. Ignoring"); return; } if (skip_mq) { mq_pad = gst_object_ref (pad); } else { mq_pad = connect_thru_mq (dvdbin, pad); if (mq_pad == NULL) goto failed; GST_DEBUG_OBJECT (dvdbin, "Linking new pad %" GST_PTR_FORMAT " through multiqueue to %" GST_PTR_FORMAT, pad, dest_pad); } gst_pad_link (mq_pad, dest_pad); gst_object_unref (mq_pad); gst_object_unref (dest_pad); return; failed: GST_ELEMENT_ERROR (dvdbin, CORE, FAILED, (NULL), ("Failed to handle new demuxer pad %s", GST_PAD_NAME (pad))); if (mq_pad) gst_object_unref (mq_pad); if (dest_pad) gst_object_unref (dest_pad); return; }
static GstBuffer * gst_rtp_sv3v_depay_process (GstBaseRTPDepayload * depayload, GstBuffer * buf) { GstRtpSV3VDepay *rtpsv3vdepay; GstBuffer *outbuf; guint16 seq; rtpsv3vdepay = GST_RTP_SV3V_DEPAY (depayload); if (!gst_rtp_buffer_validate (buf)) goto bad_packet; /* flush on sequence number gaps */ seq = gst_rtp_buffer_get_seq (buf); if (seq != rtpsv3vdepay->nextseq) { gst_adapter_clear (rtpsv3vdepay->adapter); } rtpsv3vdepay->nextseq = seq + 1; { gint payload_len; guint8 *payload; gboolean M; gboolean C, S, E; payload_len = gst_rtp_buffer_get_payload_len (buf); if (payload_len < 3) goto bad_packet; payload = gst_rtp_buffer_get_payload (buf); M = gst_rtp_buffer_get_marker (buf); /* This is all a guess: * 1 1 1 1 1 1 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * |0|C|S|E|0|0|0|0|0|0|0|0|0|0|0|0| * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * * C: config, packet contains config info * S: start, packet contains start of frame * E: end, packet contains end of frame */ /* this seems to indicate a packet with a config string sent before each * keyframe */ C = (payload[0] & 0x40) == 0x40; /* redundant with the RTP marker bit */ S = (payload[0] & 0x20) == 0x20; E = (payload[0] & 0x10) == 0x10; if (C) { GstCaps *caps; GstBuffer *codec_data; GValue value = { 0 }; /* if we already have caps, we don't need to do anything. FIXME, check if * something changed. */ if (GST_PAD_CAPS (GST_BASE_RTP_DEPAYLOAD_SRCPAD (depayload))) return NULL; /* No idea... These are the two examples I found.. */ if (payload[2] == 0x1d) { rtpsv3vdepay->width = 160; rtpsv3vdepay->height = 128; } else if (payload[2] == 0xdd) { rtpsv3vdepay->width = 320; rtpsv3vdepay->height = 240; } /* we need a dummy empty codec data */ g_value_init (&value, GST_TYPE_BUFFER); gst_value_deserialize (&value, ""); codec_data = gst_value_get_buffer (&value); caps = gst_caps_new_simple ("video/x-svq", "svqversion", G_TYPE_INT, 3, "width", G_TYPE_INT, rtpsv3vdepay->width, "height", G_TYPE_INT, rtpsv3vdepay->height, "codec_data", GST_TYPE_BUFFER, codec_data, NULL); gst_pad_set_caps (GST_BASE_RTP_DEPAYLOAD_SRCPAD (depayload), caps); gst_caps_unref (caps); g_value_unset (&value); return NULL; } /* store data in adapter, stip off 2 bytes header */ outbuf = gst_rtp_buffer_get_payload_subbuffer (buf, 2, -1); gst_adapter_push (rtpsv3vdepay->adapter, outbuf); if (M) { /* frame is completed: push contents of adapter */ guint avail; avail = gst_adapter_available (rtpsv3vdepay->adapter); outbuf = gst_adapter_take_buffer (rtpsv3vdepay->adapter, avail); /* timestamp for complete buffer is that of last buffer as well */ gst_buffer_set_caps (outbuf, GST_PAD_CAPS (depayload->srcpad)); return outbuf; } } return NULL; /* ERRORS */ bad_packet: { GST_ELEMENT_WARNING (rtpsv3vdepay, STREAM, DECODE, ("Packet did not validate"), (NULL)); return NULL; } }
static GstBuffer * gst_rtp_qcelp_depay_process (GstRTPBaseDepayload * depayload, GstRTPBuffer * rtp) { GstRtpQCELPDepay *depay; GstBuffer *outbuf; GstClockTime timestamp; guint payload_len, offset, index; guint8 *payload; guint LLL, NNN; depay = GST_RTP_QCELP_DEPAY (depayload); payload_len = gst_rtp_buffer_get_payload_len (rtp); if (payload_len < 2) goto too_small; timestamp = GST_BUFFER_PTS (rtp->buffer); payload = gst_rtp_buffer_get_payload (rtp); /* 0 1 2 3 4 5 6 7 * +-+-+-+-+-+-+-+-+ * |RR | LLL | NNN | * +-+-+-+-+-+-+-+-+ */ /* RR = payload[0] >> 6; */ LLL = (payload[0] & 0x38) >> 3; NNN = (payload[0] & 0x07); payload_len--; payload++; GST_DEBUG_OBJECT (depay, "LLL %u, NNN %u", LLL, NNN); if (LLL > 5) goto invalid_lll; if (NNN > LLL) goto invalid_nnn; if (LLL != 0) { /* we are interleaved */ if (!depay->interleaved) { guint size; GST_DEBUG_OBJECT (depay, "starting interleaving group"); /* bundling is not allowed to change in one interleave group */ depay->bundling = count_packets (depay, payload, payload_len); GST_DEBUG_OBJECT (depay, "got bundling of %u", depay->bundling); /* we have one bundle where NNN goes from 0 to L, we don't store the index * 0 frames, so L+1 packets. Each packet has 'bundling - 1' packets */ size = (depay->bundling - 1) * (LLL + 1); /* create the array to hold the packets */ if (depay->packets == NULL) depay->packets = g_ptr_array_sized_new (size); GST_DEBUG_OBJECT (depay, "created packet array of size %u", size); g_ptr_array_set_size (depay->packets, size); /* we were previously not interleaved, figure out how much space we * need to deinterleave */ depay->interleaved = TRUE; } } else { /* we are not interleaved */ if (depay->interleaved) { GST_DEBUG_OBJECT (depay, "stopping interleaving"); /* flush packets if we were previously interleaved */ flush_packets (depay); } depay->bundling = 0; } index = 0; offset = 1; while (payload_len > 0) { gint frame_len; gboolean do_erasure; frame_len = get_frame_len (depay, payload[0]); GST_DEBUG_OBJECT (depay, "got frame len %d", frame_len); if (frame_len == 0) goto invalid_frame; if (frame_len < 0) { /* need to add an erasure frame but we can recover */ frame_len = -frame_len; do_erasure = TRUE; } else { do_erasure = FALSE; } if (frame_len > payload_len) goto invalid_frame; if (do_erasure) { /* create erasure frame */ outbuf = create_erasure_buffer (depay); } else { /* each frame goes into its buffer */ outbuf = gst_rtp_buffer_get_payload_subbuffer (rtp, offset, frame_len); } GST_BUFFER_PTS (outbuf) = timestamp; GST_BUFFER_DURATION (outbuf) = FRAME_DURATION; gst_rtp_drop_meta (GST_ELEMENT_CAST (depayload), outbuf, g_quark_from_static_string (GST_META_TAG_AUDIO_STR)); if (!depay->interleaved || index == 0) { /* not interleaved or first frame in packet, just push */ gst_rtp_base_depayload_push (depayload, outbuf); if (timestamp != -1) timestamp += FRAME_DURATION; } else { /* put in interleave buffer */ add_packet (depay, LLL, NNN, index, outbuf); if (timestamp != -1) timestamp += (FRAME_DURATION * (LLL + 1)); } payload_len -= frame_len; payload += frame_len; offset += frame_len; index++; /* discard excess packets */ if (depay->bundling > 0 && depay->bundling <= index) break; } while (index < depay->bundling) { GST_DEBUG_OBJECT (depay, "filling with erasure buffer"); /* fill remainder with erasure packets */ outbuf = create_erasure_buffer (depay); add_packet (depay, LLL, NNN, index, outbuf); index++; } if (depay->interleaved && LLL == NNN) { GST_DEBUG_OBJECT (depay, "interleave group ended, flushing"); /* we have the complete interleave group, flush */ flush_packets (depay); } return NULL; /* ERRORS */ too_small: { GST_ELEMENT_WARNING (depay, STREAM, DECODE, (NULL), ("QCELP RTP payload too small (%d)", payload_len)); return NULL; } invalid_lll: { GST_ELEMENT_WARNING (depay, STREAM, DECODE, (NULL), ("QCELP RTP invalid LLL received (%d)", LLL)); return NULL; } invalid_nnn: { GST_ELEMENT_WARNING (depay, STREAM, DECODE, (NULL), ("QCELP RTP invalid NNN received (%d)", NNN)); return NULL; } invalid_frame: { GST_ELEMENT_WARNING (depay, STREAM, DECODE, (NULL), ("QCELP RTP invalid frame received")); return NULL; } }
static GstBuffer * gst_rtp_dtmf_depay_process (GstBaseRTPDepayload * depayload, GstBuffer * buf) { GstRtpDTMFDepay *rtpdtmfdepay = NULL; GstBuffer *outbuf = NULL; gint payload_len; guint8 *payload = NULL; guint32 timestamp; GstRTPDTMFPayload dtmf_payload; gboolean marker; GstStructure *structure = NULL; GstMessage *dtmf_message = NULL; rtpdtmfdepay = GST_RTP_DTMF_DEPAY (depayload); if (!gst_rtp_buffer_validate (buf)) goto bad_packet; payload_len = gst_rtp_buffer_get_payload_len (buf); payload = gst_rtp_buffer_get_payload (buf); if (payload_len != sizeof (GstRTPDTMFPayload)) goto bad_packet; memcpy (&dtmf_payload, payload, sizeof (GstRTPDTMFPayload)); if (dtmf_payload.event > MAX_EVENT) goto bad_packet; marker = gst_rtp_buffer_get_marker (buf); timestamp = gst_rtp_buffer_get_timestamp (buf); dtmf_payload.duration = g_ntohs (dtmf_payload.duration); /* clip to whole units of unit_time */ if (rtpdtmfdepay->unit_time) { guint unit_time_clock = (rtpdtmfdepay->unit_time * depayload->clock_rate) / 1000; if (dtmf_payload.duration % unit_time_clock) { /* Make sure we don't overflow the duration */ if (dtmf_payload.duration < G_MAXUINT16 - unit_time_clock) dtmf_payload.duration += unit_time_clock - (dtmf_payload.duration % unit_time_clock); else dtmf_payload.duration -= dtmf_payload.duration % unit_time_clock; } } /* clip to max duration */ if (rtpdtmfdepay->max_duration) { guint max_duration_clock = (rtpdtmfdepay->max_duration * depayload->clock_rate) / 1000; if (max_duration_clock < G_MAXUINT16 && dtmf_payload.duration > max_duration_clock) dtmf_payload.duration = max_duration_clock; } GST_DEBUG_OBJECT (depayload, "Received new RTP DTMF packet : " "marker=%d - timestamp=%u - event=%d - duration=%d", marker, timestamp, dtmf_payload.event, dtmf_payload.duration); GST_DEBUG_OBJECT (depayload, "Previous information : timestamp=%u - duration=%d", rtpdtmfdepay->previous_ts, rtpdtmfdepay->previous_duration); /* First packet */ if (marker || rtpdtmfdepay->previous_ts != timestamp) { rtpdtmfdepay->sample = 0; rtpdtmfdepay->previous_ts = timestamp; rtpdtmfdepay->previous_duration = dtmf_payload.duration; rtpdtmfdepay->first_gst_ts = GST_BUFFER_TIMESTAMP (buf); structure = gst_structure_new ("dtmf-event", "number", G_TYPE_INT, dtmf_payload.event, "volume", G_TYPE_INT, dtmf_payload.volume, "type", G_TYPE_INT, 1, "method", G_TYPE_INT, 1, NULL); if (structure) { dtmf_message = gst_message_new_element (GST_OBJECT (depayload), structure); if (dtmf_message) { if (!gst_element_post_message (GST_ELEMENT (depayload), dtmf_message)) { GST_ERROR_OBJECT (depayload, "Unable to send dtmf-event message to bus"); } } else { GST_ERROR_OBJECT (depayload, "Unable to create dtmf-event message"); } } else { GST_ERROR_OBJECT (depayload, "Unable to create dtmf-event structure"); } } else { guint16 duration = dtmf_payload.duration; dtmf_payload.duration -= rtpdtmfdepay->previous_duration; /* If late buffer, ignore */ if (duration > rtpdtmfdepay->previous_duration) rtpdtmfdepay->previous_duration = duration; } GST_DEBUG_OBJECT (depayload, "new previous duration : %d - new duration : %d" " - diff : %d - clock rate : %d - timestamp : %llu", rtpdtmfdepay->previous_duration, dtmf_payload.duration, (rtpdtmfdepay->previous_duration - dtmf_payload.duration), depayload->clock_rate, GST_BUFFER_TIMESTAMP (buf)); /* If late or duplicate packet (like the redundant end packet). Ignore */ if (dtmf_payload.duration > 0) { outbuf = gst_buffer_new (); gst_dtmf_src_generate_tone (rtpdtmfdepay, dtmf_payload, outbuf); GST_BUFFER_TIMESTAMP (outbuf) = rtpdtmfdepay->first_gst_ts + (rtpdtmfdepay->previous_duration - dtmf_payload.duration) * GST_SECOND / depayload->clock_rate; GST_BUFFER_OFFSET (outbuf) = (rtpdtmfdepay->previous_duration - dtmf_payload.duration) * GST_SECOND / depayload->clock_rate; GST_BUFFER_OFFSET_END (outbuf) = rtpdtmfdepay->previous_duration * GST_SECOND / depayload->clock_rate; GST_DEBUG_OBJECT (depayload, "timestamp : %llu - time %" GST_TIME_FORMAT, GST_BUFFER_TIMESTAMP (buf), GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf))); } return outbuf; bad_packet: GST_ELEMENT_WARNING (rtpdtmfdepay, STREAM, DECODE, ("Packet did not validate"), (NULL)); return NULL; }
static gboolean gst_rtp_g722_depay_setcaps (GstBaseRTPDepayload * depayload, GstCaps * caps) { GstStructure *structure; GstRtpG722Depay *rtpg722depay; gint clock_rate, payload, samplerate; gint channels; GstCaps *srccaps; gboolean res; const gchar *channel_order; const GstRTPChannelOrder *order; rtpg722depay = GST_RTP_G722_DEPAY (depayload); structure = gst_caps_get_structure (caps, 0); payload = 96; gst_structure_get_int (structure, "payload", &payload); switch (payload) { case GST_RTP_PAYLOAD_G722: channels = 1; clock_rate = 8000; samplerate = 16000; break; default: /* no fixed mapping, we need clock-rate */ channels = 0; clock_rate = 0; samplerate = 0; break; } /* caps can overwrite defaults */ clock_rate = gst_rtp_g722_depay_parse_int (structure, "clock-rate", clock_rate); if (clock_rate == 0) goto no_clockrate; if (clock_rate == 8000) samplerate = 16000; if (samplerate == 0) samplerate = clock_rate; channels = gst_rtp_g722_depay_parse_int (structure, "encoding-params", channels); if (channels == 0) { channels = gst_rtp_g722_depay_parse_int (structure, "channels", channels); if (channels == 0) { /* channels defaults to 1 otherwise */ channels = 1; } } depayload->clock_rate = clock_rate; rtpg722depay->rate = samplerate; rtpg722depay->channels = channels; srccaps = gst_caps_new_simple ("audio/G722", "rate", G_TYPE_INT, samplerate, "channels", G_TYPE_INT, channels, NULL); /* add channel positions */ channel_order = gst_structure_get_string (structure, "channel-order"); order = gst_rtp_channels_get_by_order (channels, channel_order); if (order) { gst_audio_set_channel_positions (gst_caps_get_structure (srccaps, 0), order->pos); } else { GstAudioChannelPosition *pos; GST_ELEMENT_WARNING (rtpg722depay, STREAM, DECODE, (NULL), ("Unknown channel order '%s' for %d channels", GST_STR_NULL (channel_order), channels)); /* create default NONE layout */ pos = gst_rtp_channels_create_default (channels); gst_audio_set_channel_positions (gst_caps_get_structure (srccaps, 0), pos); g_free (pos); } res = gst_pad_set_caps (depayload->srcpad, srccaps); gst_caps_unref (srccaps); return res; /* ERRORS */ no_clockrate: { GST_ERROR_OBJECT (depayload, "no clock-rate specified"); return FALSE; } }
static GstFlowReturn gst_rtp_dec_chain_rtp (GstPad * pad, GstObject * parent, GstBuffer * buffer) { GstFlowReturn res; GstRTPDec *rtpdec; GstRTPDecSession *session; guint32 ssrc; guint8 pt; GstRTPBuffer rtp = { NULL, }; rtpdec = GST_RTP_DEC (parent); GST_DEBUG_OBJECT (rtpdec, "got rtp packet"); if (!gst_rtp_buffer_map (buffer, GST_MAP_READ, &rtp)) goto bad_packet; ssrc = gst_rtp_buffer_get_ssrc (&rtp); pt = gst_rtp_buffer_get_payload_type (&rtp); gst_rtp_buffer_unmap (&rtp); GST_DEBUG_OBJECT (rtpdec, "SSRC %08x, PT %d", ssrc, pt); /* find session */ session = gst_pad_get_element_private (pad); /* see if we have the pad */ if (!session->active) { GstPadTemplate *templ; GstElementClass *klass; gchar *name; GstCaps *caps; GValue ret = { 0 }; GValue args[3] = { {0} , {0} , {0} }; GST_DEBUG_OBJECT (rtpdec, "creating stream"); session->ssrc = ssrc; session->pt = pt; /* get pt map */ g_value_init (&args[0], GST_TYPE_ELEMENT); g_value_set_object (&args[0], rtpdec); g_value_init (&args[1], G_TYPE_UINT); g_value_set_uint (&args[1], session->id); g_value_init (&args[2], G_TYPE_UINT); g_value_set_uint (&args[2], pt); g_value_init (&ret, GST_TYPE_CAPS); g_value_set_boxed (&ret, NULL); g_signal_emitv (args, gst_rtp_dec_signals[SIGNAL_REQUEST_PT_MAP], 0, &ret); caps = (GstCaps *) g_value_get_boxed (&ret); name = g_strdup_printf ("recv_rtp_src_%u_%u_%u", session->id, ssrc, pt); klass = GST_ELEMENT_GET_CLASS (rtpdec); templ = gst_element_class_get_pad_template (klass, "recv_rtp_src_%u_%u_%u"); session->recv_rtp_src = gst_pad_new_from_template (templ, name); g_free (name); gst_pad_set_caps (session->recv_rtp_src, caps); gst_pad_set_element_private (session->recv_rtp_src, session); gst_pad_set_query_function (session->recv_rtp_src, gst_rtp_dec_query_src); gst_pad_set_active (session->recv_rtp_src, TRUE); gst_element_add_pad (GST_ELEMENT_CAST (rtpdec), session->recv_rtp_src); session->active = TRUE; } res = gst_pad_push (session->recv_rtp_src, buffer); return res; bad_packet: { GST_ELEMENT_WARNING (rtpdec, STREAM, DECODE, (NULL), ("RTP packet did not validate, dropping")); gst_buffer_unref (buffer); return GST_FLOW_OK; } }
static int set_hwparams (GstAlsaSink * alsa) { guint rrate; gint err; snd_pcm_hw_params_t *params; guint period_time, buffer_time; snd_pcm_hw_params_malloc (¶ms); GST_DEBUG_OBJECT (alsa, "Negotiating to %d channels @ %d Hz (format = %s) " "SPDIF (%d)", alsa->channels, alsa->rate, snd_pcm_format_name (alsa->format), alsa->iec958); /* start with requested values, if we cannot configure alsa for those values, * we set these values to -1, which will leave the default alsa values */ buffer_time = alsa->buffer_time; period_time = alsa->period_time; retry: /* choose all parameters */ CHECK (snd_pcm_hw_params_any (alsa->handle, params), no_config); /* set the interleaved read/write format */ CHECK (snd_pcm_hw_params_set_access (alsa->handle, params, alsa->access), wrong_access); /* set the sample format */ if (alsa->iec958) { /* Try to use big endian first else fallback to le and swap bytes */ if (snd_pcm_hw_params_set_format (alsa->handle, params, alsa->format) < 0) { alsa->format = SND_PCM_FORMAT_S16_LE; alsa->need_swap = TRUE; GST_DEBUG_OBJECT (alsa, "falling back to little endian with swapping"); } else { alsa->need_swap = FALSE; } } CHECK (snd_pcm_hw_params_set_format (alsa->handle, params, alsa->format), no_sample_format); /* set the count of channels */ CHECK (snd_pcm_hw_params_set_channels (alsa->handle, params, alsa->channels), no_channels); /* set the stream rate */ rrate = alsa->rate; CHECK (snd_pcm_hw_params_set_rate_near (alsa->handle, params, &rrate, NULL), no_rate); #ifndef GST_DISABLE_GST_DEBUG /* get and dump some limits */ { guint min, max; snd_pcm_hw_params_get_buffer_time_min (params, &min, NULL); snd_pcm_hw_params_get_buffer_time_max (params, &max, NULL); GST_DEBUG_OBJECT (alsa, "buffer time %u, min %u, max %u", alsa->buffer_time, min, max); snd_pcm_hw_params_get_period_time_min (params, &min, NULL); snd_pcm_hw_params_get_period_time_max (params, &max, NULL); GST_DEBUG_OBJECT (alsa, "period time %u, min %u, max %u", alsa->period_time, min, max); snd_pcm_hw_params_get_periods_min (params, &min, NULL); snd_pcm_hw_params_get_periods_max (params, &max, NULL); GST_DEBUG_OBJECT (alsa, "periods min %u, max %u", min, max); } #endif /* now try to configure the buffer time and period time, if one * of those fail, we fall back to the defaults and emit a warning. */ if (buffer_time != -1 && !alsa->iec958) { /* set the buffer time */ if ((err = snd_pcm_hw_params_set_buffer_time_near (alsa->handle, params, &buffer_time, NULL)) < 0) { GST_ELEMENT_WARNING (alsa, RESOURCE, SETTINGS, (NULL), ("Unable to set buffer time %i for playback: %s", buffer_time, snd_strerror (err))); /* disable buffer_time the next round */ buffer_time = -1; goto retry; } GST_DEBUG_OBJECT (alsa, "buffer time %u", buffer_time); } if (period_time != -1 && !alsa->iec958) { /* set the period time */ if ((err = snd_pcm_hw_params_set_period_time_near (alsa->handle, params, &period_time, NULL)) < 0) { GST_ELEMENT_WARNING (alsa, RESOURCE, SETTINGS, (NULL), ("Unable to set period time %i for playback: %s", period_time, snd_strerror (err))); /* disable period_time the next round */ period_time = -1; goto retry; } GST_DEBUG_OBJECT (alsa, "period time %u", period_time); } /* Set buffer size and period size manually for SPDIF */ if (G_UNLIKELY (alsa->iec958)) { snd_pcm_uframes_t buffer_size = SPDIF_BUFFER_SIZE; snd_pcm_uframes_t period_size = SPDIF_PERIOD_SIZE; CHECK (snd_pcm_hw_params_set_buffer_size_near (alsa->handle, params, &buffer_size), buffer_size); CHECK (snd_pcm_hw_params_set_period_size_near (alsa->handle, params, &period_size, NULL), period_size); } /* write the parameters to device */ CHECK (snd_pcm_hw_params (alsa->handle, params), set_hw_params); /* now get the configured values */ CHECK (snd_pcm_hw_params_get_buffer_size (params, &alsa->buffer_size), buffer_size); CHECK (snd_pcm_hw_params_get_period_size (params, &alsa->period_size, NULL), period_size); GST_DEBUG_OBJECT (alsa, "buffer size %lu, period size %lu", alsa->buffer_size, alsa->period_size); snd_pcm_hw_params_free (params); return 0; /* ERRORS */ no_config: { GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL), ("Broken configuration for playback: no configurations available: %s", snd_strerror (err))); snd_pcm_hw_params_free (params); return err; } wrong_access: { GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL), ("Access type not available for playback: %s", snd_strerror (err))); snd_pcm_hw_params_free (params); return err; } no_sample_format: { GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL), ("Sample format not available for playback: %s", snd_strerror (err))); snd_pcm_hw_params_free (params); return err; } no_channels: { gchar *msg = NULL; if ((alsa->channels) == 1) msg = g_strdup (_("Could not open device for playback in mono mode.")); if ((alsa->channels) == 2) msg = g_strdup (_("Could not open device for playback in stereo mode.")); if ((alsa->channels) > 2) msg = g_strdup_printf (_ ("Could not open device for playback in %d-channel mode."), alsa->channels); GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, ("%s", msg), ("%s", snd_strerror (err))); g_free (msg); snd_pcm_hw_params_free (params); return err; } no_rate: { GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL), ("Rate %iHz not available for playback: %s", alsa->rate, snd_strerror (err))); return err; } buffer_size: { GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL), ("Unable to get buffer size for playback: %s", snd_strerror (err))); snd_pcm_hw_params_free (params); return err; } period_size: { GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL), ("Unable to get period size for playback: %s", snd_strerror (err))); snd_pcm_hw_params_free (params); return err; } set_hw_params: { GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL), ("Unable to set hw params for playback: %s", snd_strerror (err))); snd_pcm_hw_params_free (params); return err; } }