static GstFlowReturn gst_wavenc_write_toc (GstWavEnc * wavenc) { GList *list; GstToc *toc; GstTocEntry *entry, *subentry; GstBuffer *buf; GstMapInfo map; guint8 *data; guint32 ncues, size, cues_size, labls_size, notes_size; if (!wavenc->toc) { GST_DEBUG_OBJECT (wavenc, "have no toc, checking toc_setter"); wavenc->toc = gst_toc_setter_get_toc (GST_TOC_SETTER (wavenc)); } if (!wavenc->toc) { GST_WARNING_OBJECT (wavenc, "have no toc"); return GST_FLOW_OK; } toc = gst_toc_ref (wavenc->toc); size = 0; cues_size = 0; labls_size = 0; notes_size = 0; /* check if the TOC entries is valid */ list = gst_toc_get_entries (toc); entry = list->data; if (gst_toc_entry_is_alternative (entry)) { list = gst_toc_entry_get_sub_entries (entry); while (list) { subentry = list->data; if (!gst_toc_entry_is_sequence (subentry)) return FALSE; list = g_list_next (list); } list = gst_toc_entry_get_sub_entries (entry); } if (gst_toc_entry_is_sequence (entry)) { while (list) { entry = list->data; if (!gst_toc_entry_is_sequence (entry)) return FALSE; list = g_list_next (list); } list = gst_toc_get_entries (toc); } ncues = g_list_length (list); GST_DEBUG_OBJECT (wavenc, "number of cue entries: %d", ncues); while (list) { guint32 id = 0; gint64 id64; const gchar *uid; entry = list->data; uid = gst_toc_entry_get_uid (entry); id64 = g_ascii_strtoll (uid, NULL, 0); /* check if id unique compatible with guint32 else generate random */ if (id64 >= 0 && gst_wavenc_is_cue_id_unique (id64, wavenc->cues)) { id = (guint32) id64; } else { do { id = g_random_int (); } while (!gst_wavenc_is_cue_id_unique (id, wavenc->cues)); } gst_wavenc_parse_cue (wavenc, id, entry); gst_wavenc_parse_labl (wavenc, id, entry); gst_wavenc_parse_note (wavenc, id, entry); list = g_list_next (list); } /* count cues size */ if (wavenc->cues) { cues_size = 24 * g_list_length (wavenc->cues); size += 12 + cues_size; } else { GST_WARNING_OBJECT (wavenc, "cue's not found"); return FALSE; } /* count labls size */ if (wavenc->labls) { list = wavenc->labls; while (list) { GstWavEncLabl *labl; labl = list->data; labls_size += 8 + GST_ROUND_UP_2 (labl->chunk_data_size); list = g_list_next (list); } size += labls_size; } /* count notes size */ if (wavenc->notes) { list = wavenc->notes; while (list) { GstWavEncNote *note; note = list->data; notes_size += 8 + GST_ROUND_UP_2 (note->chunk_data_size); list = g_list_next (list); } size += notes_size; } if (wavenc->labls || wavenc->notes) { size += 12; } buf = gst_buffer_new_and_alloc (size); gst_buffer_map (buf, &map, GST_MAP_WRITE); data = map.data; memset (data, 0, size); /* write Cue Chunk */ if (wavenc->cues) { memcpy (data, (gchar *) "cue ", 4); GST_WRITE_UINT32_LE (data + 4, 4 + cues_size); GST_WRITE_UINT32_LE (data + 8, ncues); data += 12; gst_wavenc_write_cues (&data, wavenc->cues); /* write Associated Data List Chunk */ if (wavenc->labls || wavenc->notes) { memcpy (data, (gchar *) "LIST", 4); GST_WRITE_UINT32_LE (data + 4, 4 + labls_size + notes_size); memcpy (data + 8, (gchar *) "adtl", 4); data += 12; if (wavenc->labls) gst_wavenc_write_labls (&data, wavenc->labls); if (wavenc->notes) gst_wavenc_write_notes (&data, wavenc->notes); } } /* free resources */ if (toc) gst_toc_unref (toc); if (wavenc->cues) g_list_free_full (wavenc->cues, g_free); if (wavenc->labls) g_list_free_full (wavenc->labls, g_free); if (wavenc->notes) g_list_free_full (wavenc->notes, g_free); gst_buffer_unmap (buf, &map); wavenc->meta_length += gst_buffer_get_size (buf); return gst_pad_push (wavenc->srcpad, buf); }
static void handle_transfer (GstCurlBaseSink * sink) { GstCurlBaseSinkClass *klass = GST_CURL_BASE_SINK_GET_CLASS (sink); gint retval; gint activated_fds; gint running_handles; gint timeout; CURLMcode m_code; CURLcode e_code; GST_OBJECT_LOCK (sink); timeout = sink->timeout; GST_OBJECT_UNLOCK (sink); GST_DEBUG_OBJECT (sink, "handling transfers"); /* Receiving CURLM_CALL_MULTI_PERFORM means that libcurl may have more data available to send or receive - call simply curl_multi_perform before poll() on more actions */ do { m_code = curl_multi_perform (sink->multi_handle, &running_handles); } while (m_code == CURLM_CALL_MULTI_PERFORM); GST_DEBUG_OBJECT (sink, "running handles: %d", running_handles); while (running_handles && (m_code == CURLM_OK)) { if (klass->transfer_prepare_poll_wait) { klass->transfer_prepare_poll_wait (sink); } activated_fds = gst_poll_wait (sink->fdset, timeout * GST_SECOND); if (G_UNLIKELY (activated_fds == -1)) { if (errno == EAGAIN || errno == EINTR) { GST_DEBUG_OBJECT (sink, "interrupted by signal"); } else if (errno == EBUSY) { GST_DEBUG_OBJECT (sink, "poll stopped"); retval = GST_FLOW_EOS; GST_OBJECT_LOCK (sink); if (gst_curl_base_sink_has_buffered_data_unlocked (sink)) GST_WARNING_OBJECT (sink, "discarding render data due to thread close flag"); GST_OBJECT_UNLOCK (sink); goto fail; } else { sink->error = g_strdup_printf ("poll failed: %s", g_strerror (errno)); retval = GST_FLOW_ERROR; goto fail; } } else if (G_UNLIKELY (activated_fds == 0)) { sink->error = g_strdup_printf ("poll timed out after %" GST_TIME_FORMAT, GST_TIME_ARGS (timeout * GST_SECOND)); retval = GST_FLOW_ERROR; goto fail; } /* readable/writable sockets */ do { m_code = curl_multi_perform (sink->multi_handle, &running_handles); } while (m_code == CURLM_CALL_MULTI_PERFORM); GST_DEBUG_OBJECT (sink, "running handles: %d", running_handles); } if (m_code != CURLM_OK) { sink->error = g_strdup_printf ("failed to write data: %s", curl_multi_strerror (m_code)); retval = GST_FLOW_ERROR; goto fail; } /* problems still might have occurred on individual transfers even when * curl_multi_perform returns CURLM_OK */ if ((e_code = gst_curl_base_sink_transfer_check (sink)) != CURLE_OK) { sink->error = g_strdup_printf ("failed to transfer data: %s", curl_easy_strerror (e_code)); retval = GST_FLOW_ERROR; goto fail; } gst_curl_base_sink_got_response_notify (sink); GST_OBJECT_LOCK (sink); if (sink->socket_type == CURLSOCKTYPE_ACCEPT) { if (!gst_poll_remove_fd (sink->fdset, &sink->fd)) { sink->error = g_strdup_printf ("failed to remove fd"); retval = GST_FLOW_ERROR; GST_OBJECT_UNLOCK (sink); goto fail; } sink->fd.fd = -1; } GST_OBJECT_UNLOCK (sink); return; fail: GST_OBJECT_LOCK (sink); if (sink->flow_ret == GST_FLOW_OK) { sink->flow_ret = retval; } GST_OBJECT_UNLOCK (sink); return; }
static GstFlowReturn mpegts_base_scan (MpegTSBase * base) { GstFlowReturn ret = GST_FLOW_OK; GstBuffer *buf = NULL; guint i; gboolean done = FALSE; MpegTSPacketizerPacketReturn pret; gint64 tmpval; gint64 upstream_size, seek_pos, reverse_limit; GstFormat format; guint initial_pcr_seen; GST_DEBUG ("Scanning for initial sync point"); /* Find initial sync point and at least 5 PCR values */ for (i = 0; i < 20 && !done; i++) { GST_DEBUG ("Grabbing %d => %d", i * 65536, (i + 1) * 65536); ret = gst_pad_pull_range (base->sinkpad, i * 65536, 65536, &buf); if (G_UNLIKELY (ret == GST_FLOW_EOS)) break; if (G_UNLIKELY (ret != GST_FLOW_OK)) goto beach; /* Push to packetizer */ mpegts_packetizer_push (base->packetizer, buf); buf = NULL; if (mpegts_packetizer_has_packets (base->packetizer)) { if (base->seek_offset == -1) { /* Mark the initial sync point and remember the packetsize */ base->seek_offset = base->packetizer->offset; GST_DEBUG ("Sync point is now %" G_GUINT64_FORMAT, base->seek_offset); base->packetsize = base->packetizer->packet_size; } while (1) { /* Eat up all packets */ pret = mpegts_packetizer_process_next_packet (base->packetizer); if (pret == PACKET_NEED_MORE) break; if (pret != PACKET_BAD && base->packetizer->nb_seen_offsets >= 5) { GST_DEBUG ("Got enough initial PCR"); done = TRUE; break; } } } } initial_pcr_seen = base->packetizer->nb_seen_offsets; if (G_UNLIKELY (initial_pcr_seen == 0)) goto no_initial_pcr; GST_DEBUG ("Seen %d initial PCR", initial_pcr_seen); /* Now send data from the end */ /* Get the size of upstream */ format = GST_FORMAT_BYTES; if (!gst_pad_peer_query_duration (base->sinkpad, format, &tmpval)) goto beach; upstream_size = tmpval; done = FALSE; /* The scanning takes place on the last 2048kB. Considering PCR should * be present at least every 100ms, this should cope with streams * up to 160Mbit/s */ reverse_limit = MAX (0, upstream_size - 2097152); /* Find last PCR value, searching backwards by chunks of 300 MPEG-ts packets */ for (seek_pos = MAX (0, upstream_size - 56400); seek_pos >= reverse_limit && !done; seek_pos -= 56400) { mpegts_packetizer_clear (base->packetizer); GST_DEBUG ("Grabbing %" G_GUINT64_FORMAT " => %" G_GUINT64_FORMAT, seek_pos, seek_pos + 56400); ret = gst_pad_pull_range (base->sinkpad, seek_pos, 56400, &buf); if (G_UNLIKELY (ret == GST_FLOW_EOS)) break; if (G_UNLIKELY (ret != GST_FLOW_OK)) goto beach; /* Push to packetizer */ mpegts_packetizer_push (base->packetizer, buf); buf = NULL; if (mpegts_packetizer_has_packets (base->packetizer)) { pret = PACKET_OK; /* Eat up all packets, really try to get last PCR(s) */ while (pret != PACKET_NEED_MORE) pret = mpegts_packetizer_process_next_packet (base->packetizer); if (base->packetizer->nb_seen_offsets > initial_pcr_seen) { GST_DEBUG ("Got last PCR(s) (total seen:%d)", base->packetizer->nb_seen_offsets); done = TRUE; break; } } } beach: mpegts_packetizer_clear (base->packetizer); return ret; no_initial_pcr: mpegts_packetizer_clear (base->packetizer); GST_WARNING_OBJECT (base, "Couldn't find any PCR within the first %d bytes", 10 * 65536); return GST_FLOW_ERROR; }
GstFlowReturn gst_kate_util_decoder_base_chain_kate_packet (GstKateDecoderBase * decoder, GstElement * element, GstPad * pad, GstBuffer * buf, GstPad * srcpad, GstPad * tagpad, GstCaps ** src_caps, const kate_event ** ev) { kate_packet kp; int ret; GstFlowReturn rflow = GST_FLOW_OK; gboolean is_header; GstMapInfo info; gsize header_size; guint8 header[1]; header_size = gst_buffer_extract (buf, 0, header, 1); GST_DEBUG_OBJECT (element, "got kate packet, %" G_GSIZE_FORMAT " bytes, type %02x", gst_buffer_get_size (buf), header_size == 0 ? -1 : header[0]); is_header = header_size > 0 && (header[0] & 0x80); if (!is_header && decoder->tags_changed) { /* after we've processed headers, send any tags before processing the data packet */ GST_DEBUG_OBJECT (element, "Not a header, sending tags for pad %s:%s", GST_DEBUG_PAD_NAME (tagpad)); gst_pad_push_event (tagpad, gst_kate_util_decoder_base_get_tag_event (decoder)); } if (gst_buffer_map (buf, &info, GST_MAP_READ)) { kate_packet_wrap (&kp, info.size, info.data); ret = kate_high_decode_packetin (&decoder->k, &kp, ev); gst_buffer_unmap (buf, &info); } else { GST_ELEMENT_ERROR (element, STREAM, DECODE, (NULL), ("Failed to map buffer")); return GST_FLOW_ERROR; } if (G_UNLIKELY (ret < 0)) { GST_ELEMENT_ERROR (element, STREAM, DECODE, (NULL), ("Failed to decode Kate packet: %s", gst_kate_util_get_error_message (ret))); return GST_FLOW_ERROR; } if (G_UNLIKELY (ret > 0)) { GST_DEBUG_OBJECT (element, "kate_high_decode_packetin has received EOS packet"); } /* headers may be interesting to retrieve information from */ if (G_UNLIKELY (is_header)) { switch (header[0]) { case 0x80: /* ID header */ GST_INFO_OBJECT (element, "Parsed ID header: language %s, category %s", decoder->k.ki->language, decoder->k.ki->category); if (src_caps) { if (*src_caps) { gst_caps_unref (*src_caps); *src_caps = NULL; } if (strcmp (decoder->k.ki->category, "K-SPU") == 0 || strcmp (decoder->k.ki->category, "spu-subtitles") == 0) { *src_caps = gst_caps_new_empty_simple ("subpicture/x-dvd"); } else if (decoder->k.ki->text_markup_type == kate_markup_none) { *src_caps = gst_caps_new_simple ("text/x-raw", "format", G_TYPE_STRING, "utf8", NULL); } else { *src_caps = gst_caps_new_simple ("text/x-raw", "format", G_TYPE_STRING, "pango-markup", NULL); } GST_INFO_OBJECT (srcpad, "Setting caps: %" GST_PTR_FORMAT, *src_caps); if (!gst_pad_set_caps (srcpad, *src_caps)) { GST_ERROR_OBJECT (srcpad, "Failed to set caps %" GST_PTR_FORMAT, *src_caps); } } if (decoder->k.ki->language && *decoder->k.ki->language) { GstTagList *tags = gst_tag_list_new_empty (); gchar *lang_code; /* en_GB -> en */ lang_code = g_ascii_strdown (decoder->k.ki->language, -1); g_strdelimit (lang_code, NULL, '\0'); gst_tag_list_add (tags, GST_TAG_MERGE_APPEND, GST_TAG_LANGUAGE_CODE, lang_code, NULL); g_free (lang_code); /* TODO: category - where should it go ? */ gst_kate_util_decoder_base_add_tags (decoder, tags, TRUE); } /* update properties */ if (decoder->language) g_free (decoder->language); decoder->language = g_strdup (decoder->k.ki->language); if (decoder->category) g_free (decoder->category); decoder->category = g_strdup (decoder->k.ki->category); decoder->original_canvas_width = decoder->k.ki->original_canvas_width; decoder->original_canvas_height = decoder->k.ki->original_canvas_height; /* we can now send away any event we've delayed, as the src pad now has caps */ gst_kate_util_decoder_base_drain_event_queue (decoder); break; case 0x81: /* Vorbis comments header */ GST_INFO_OBJECT (element, "Parsed comments header"); { gchar *encoder = NULL; GstTagList *list = gst_tag_list_from_vorbiscomment_buffer (buf, (const guint8 *) "\201kate\0\0\0\0", 9, &encoder); if (!list) { GST_ERROR_OBJECT (element, "failed to decode comment header"); list = gst_tag_list_new_empty (); } if (encoder) { gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, GST_TAG_ENCODER, encoder, NULL); g_free (encoder); } gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, GST_TAG_SUBTITLE_CODEC, "Kate", NULL); gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, GST_TAG_ENCODER_VERSION, decoder->k.ki->bitstream_version_major, NULL); gst_kate_util_decoder_base_add_tags (decoder, list, TRUE); if (decoder->initialized) { gst_pad_push_event (tagpad, gst_event_new_tag (gst_tag_list_ref (decoder->tags))); } } break; default: break; } } #if ((KATE_VERSION_MAJOR<<16)|(KATE_VERSION_MINOR<<8)|KATE_VERSION_PATCH) >= 0x000400 else if (*ev && (*ev)->meta) { int count = kate_meta_query_count ((*ev)->meta); if (count > 0) { GstTagList *evtags = gst_tag_list_new_empty (); int idx; GST_DEBUG_OBJECT (decoder, "Kate event has %d attached metadata", count); for (idx = 0; idx < count; ++idx) { const char *tag, *value; size_t len; if (kate_meta_query ((*ev)->meta, idx, &tag, &value, &len) < 0) { GST_WARNING_OBJECT (decoder, "Failed to retrieve metadata %d", idx); } else { if (gst_kate_util_is_utf8_string (value, len)) { gchar *compound = g_strdup_printf ("%s=%s", tag, value); GST_DEBUG_OBJECT (decoder, "Metadata %d: %s=%s (%" G_GSIZE_FORMAT " bytes)", idx, tag, value, len); gst_tag_list_add (evtags, GST_TAG_MERGE_APPEND, GST_TAG_EXTENDED_COMMENT, compound, NULL); g_free (compound); } else { GST_INFO_OBJECT (decoder, "Metadata %d, (%s, %" G_GSIZE_FORMAT " bytes) is binary, ignored", idx, tag, len); } } } gst_kate_util_decoder_base_add_tags (decoder, evtags, TRUE); gst_pad_push_event (tagpad, gst_kate_util_decoder_base_get_tag_event (decoder)); } } #endif return rflow; }
static gint gst_imx_v4l2src_capture_setup(GstImxV4l2VideoSrc *v4l2src) { struct v4l2_format fmt = {0}; struct v4l2_streamparm parm = {0}; struct v4l2_frmsizeenum fszenum = {0}; v4l2_std_id id; gint input; gint fd_v4l; fd_v4l = open(v4l2src->devicename, O_RDWR, 0); if (fd_v4l < 0) { GST_ERROR_OBJECT(v4l2src, "Unable to open %s", v4l2src->devicename); return -1; } if (ioctl (fd_v4l, VIDIOC_G_STD, &id) < 0) { GST_WARNING_OBJECT(v4l2src, "VIDIOC_G_STD failed: %s", strerror(errno)); } else { if (ioctl (fd_v4l, VIDIOC_S_STD, &id) < 0) { GST_ERROR_OBJECT(v4l2src, "VIDIOC_S_STD failed"); close(fd_v4l); return -1; } } fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; if (ioctl(fd_v4l, VIDIOC_G_FMT, &fmt) < 0) { GST_ERROR_OBJECT(v4l2src, "VIDIOC_G_FMT failed"); close(fd_v4l); return -1; } GST_DEBUG_OBJECT(v4l2src, "pixelformat = %d field = %d", fmt.fmt.pix.pixelformat, fmt.fmt.pix.field); fszenum.index = v4l2src->capture_mode; fszenum.pixel_format = fmt.fmt.pix.pixelformat; if (ioctl(fd_v4l, VIDIOC_ENUM_FRAMESIZES, &fszenum) < 0) { GST_ERROR_OBJECT(v4l2src, "VIDIOC_ENUM_FRAMESIZES failed: %s", strerror(errno)); close(fd_v4l); return -1; } v4l2src->capture_width = fszenum.discrete.width; v4l2src->capture_height = fszenum.discrete.height; GST_INFO_OBJECT(v4l2src, "capture mode %d: %dx%d", v4l2src->capture_mode, v4l2src->capture_width, v4l2src->capture_height); input = v4l2src->input; if (ioctl(fd_v4l, VIDIOC_S_INPUT, &input) < 0) { GST_ERROR_OBJECT(v4l2src, "VIDIOC_S_INPUT failed: %s", strerror(errno)); close(fd_v4l); return -1; } parm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; parm.parm.capture.timeperframe.numerator = v4l2src->fps_d; parm.parm.capture.timeperframe.denominator = v4l2src->fps_n; parm.parm.capture.capturemode = v4l2src->capture_mode; if (ioctl(fd_v4l, VIDIOC_S_PARM, &parm) < 0) { GST_ERROR_OBJECT(v4l2src, "VIDIOC_S_PARM failed: %s", strerror(errno)); close(fd_v4l); return -1; } /* Get the actual frame period if possible */ if (parm.parm.capture.capability & V4L2_CAP_TIMEPERFRAME) { v4l2src->fps_n = parm.parm.capture.timeperframe.denominator; v4l2src->fps_d = parm.parm.capture.timeperframe.numerator; } fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; fmt.fmt.pix.bytesperline = 0; fmt.fmt.pix.priv = 0; fmt.fmt.pix.sizeimage = 0; fmt.fmt.pix.width = v4l2src->capture_width; fmt.fmt.pix.height = v4l2src->capture_height; if (ioctl(fd_v4l, VIDIOC_S_FMT, &fmt) < 0) { GST_ERROR_OBJECT(v4l2src, "VIDIOC_S_FMT failed: %s", strerror(errno)); close(fd_v4l); return -1; } return fd_v4l; }
static gboolean gst_tag_mux_sink_event (GstPad * pad, GstObject * parent, GstEvent * event) { GstTagMux *mux; gboolean result; mux = GST_TAG_MUX (parent); result = FALSE; switch (GST_EVENT_TYPE (event)) { case GST_EVENT_TAG:{ GstTagList *tags; gst_event_parse_tag (event, &tags); GST_INFO_OBJECT (mux, "Got tag event: %" GST_PTR_FORMAT, tags); if (mux->priv->event_tags != NULL) { gst_tag_list_insert (mux->priv->event_tags, tags, GST_TAG_MERGE_REPLACE); } else { mux->priv->event_tags = gst_tag_list_copy (tags); } GST_INFO_OBJECT (mux, "Event tags are now: %" GST_PTR_FORMAT, mux->priv->event_tags); /* just drop the event, we'll push a new tag event in render_start_tag */ gst_event_unref (event); result = TRUE; break; } case GST_EVENT_SEGMENT: { GstSegment segment; gst_event_copy_segment (event, &segment); if (segment.format != GST_FORMAT_BYTES) { GST_WARNING_OBJECT (mux, "dropping newsegment event in %s format", gst_format_get_name (segment.format)); gst_event_unref (event); /* drop it quietly, so it is not seen as a failure to push event, * which will turn into failure to push data as it is sticky */ result = TRUE; break; } if (mux->priv->render_start_tag) { /* we have not rendered the tag yet, which means that we don't know * how large it is going to be yet, so we can't adjust the offsets * here at this point and need to cache the newsegment event for now * (also, there could be tag events coming after this newsegment event * and before the first buffer). */ if (mux->priv->newsegment_ev) { GST_WARNING_OBJECT (mux, "discarding old cached newsegment event"); gst_event_unref (mux->priv->newsegment_ev); } GST_LOG_OBJECT (mux, "caching newsegment event for later"); mux->priv->newsegment_ev = event; } else { GST_DEBUG_OBJECT (mux, "got newsegment event, adjusting offsets"); gst_pad_push_event (mux->priv->srcpad, gst_tag_mux_adjust_event_offsets (mux, event)); gst_event_unref (event); mux->priv->current_offset = segment.start; mux->priv->max_offset = MAX (mux->priv->max_offset, mux->priv->current_offset); } event = NULL; result = TRUE; break; } case GST_EVENT_EOS:{ if (mux->priv->render_end_tag) { GstFlowReturn ret; GST_INFO_OBJECT (mux, "Adding tags to stream"); ret = gst_tag_mux_render_end_tag (mux); if (ret != GST_FLOW_OK) { GST_DEBUG_OBJECT (mux, "flow: %s", gst_flow_get_name (ret)); return ret; } mux->priv->render_end_tag = FALSE; } /* Now forward EOS */ result = gst_pad_event_default (pad, parent, event); break; } default: result = gst_pad_event_default (pad, parent, event); break; } return result; }
static gboolean gst_kate_parse_src_query (GstPad * pad, GstObject * parent, GstQuery * query) { #if 1 // TODO GST_WARNING ("gst_kate_parse_src_query"); return FALSE; #else gint64 granulepos; GstKateParse *parse; gboolean res = FALSE; parse = GST_KATE_PARSE (parent); switch (GST_QUERY_TYPE (query)) { case GST_QUERY_POSITION: { GstFormat format; gint64 value; granulepos = parse->prev_granulepos; gst_query_parse_position (query, &format, NULL); /* and convert to the final format */ if (!(res = gst_kate_parse_convert (pad, GST_FORMAT_DEFAULT, granulepos, &format, &value))) goto error; /* fixme: support segments value = (value - parse->segment_start) + parse->segment_time; */ gst_query_set_position (query, format, value); GST_LOG_OBJECT (parse, "query %p: peer returned granulepos: %" G_GUINT64_FORMAT " - we return %" G_GUINT64_FORMAT " (format %u)", query, granulepos, value, format); break; } case GST_QUERY_DURATION: { /* fixme: not threadsafe */ /* query peer for total length */ if (!gst_pad_is_linked (parse->sinkpad)) { GST_WARNING_OBJECT (parse, "sink pad %" GST_PTR_FORMAT " is not linked", parse->sinkpad); goto error; } if (!(res = gst_pad_query (GST_PAD_PEER (parse->sinkpad), query))) goto error; break; } case GST_QUERY_CONVERT: { GstFormat src_fmt, dest_fmt; gint64 src_val, dest_val; gst_query_parse_convert (query, &src_fmt, &src_val, &dest_fmt, &dest_val); if (!(res = gst_kate_parse_convert (pad, src_fmt, src_val, &dest_fmt, &dest_val))) goto error; gst_query_set_convert (query, src_fmt, src_val, dest_fmt, dest_val); break; } default: res = gst_pad_query_default (pad, query); break; } return res; error: { GST_WARNING_OBJECT (parse, "error handling query"); return res; } #endif }
static GstFlowReturn gst_visual_chain (GstPad * pad, GstBuffer * buffer) { GstBuffer *outbuf = NULL; guint i; GstVisual *visual = GST_VISUAL (gst_pad_get_parent (pad)); GstFlowReturn ret = GST_FLOW_OK; guint avail; GST_DEBUG_OBJECT (visual, "chain function called"); /* If we don't have an output format yet, preallocate a buffer to try and * set one */ if (GST_PAD_CAPS (visual->srcpad) == NULL) { ret = get_buffer (visual, &outbuf); if (ret != GST_FLOW_OK) { gst_buffer_unref (buffer); goto beach; } } /* resync on DISCONT */ if (GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DISCONT)) { gst_adapter_clear (visual->adapter); } GST_DEBUG_OBJECT (visual, "Input buffer has %d samples, time=%" G_GUINT64_FORMAT, GST_BUFFER_SIZE (buffer) / visual->bps, GST_BUFFER_TIMESTAMP (buffer)); gst_adapter_push (visual->adapter, buffer); while (TRUE) { gboolean need_skip; const guint16 *data; guint64 dist, timestamp; GST_DEBUG_OBJECT (visual, "processing buffer"); avail = gst_adapter_available (visual->adapter); GST_DEBUG_OBJECT (visual, "avail now %u", avail); /* we need at least VISUAL_SAMPLES samples */ if (avail < VISUAL_SAMPLES * visual->bps) break; /* we need at least enough samples to make one frame */ if (avail < visual->spf * visual->bps) break; /* get timestamp of the current adapter byte */ timestamp = gst_adapter_prev_timestamp (visual->adapter, &dist); if (GST_CLOCK_TIME_IS_VALID (timestamp)) { /* convert bytes to time */ dist /= visual->bps; timestamp += gst_util_uint64_scale_int (dist, GST_SECOND, visual->rate); } if (timestamp != -1) { gint64 qostime; /* QoS is done on running time */ qostime = gst_segment_to_running_time (&visual->segment, GST_FORMAT_TIME, timestamp); qostime += visual->duration; GST_OBJECT_LOCK (visual); /* check for QoS, don't compute buffers that are known to be late */ need_skip = visual->earliest_time != -1 && qostime <= visual->earliest_time; GST_OBJECT_UNLOCK (visual); if (need_skip) { GST_WARNING_OBJECT (visual, "QoS: skip ts: %" GST_TIME_FORMAT ", earliest: %" GST_TIME_FORMAT, GST_TIME_ARGS (qostime), GST_TIME_ARGS (visual->earliest_time)); goto skip; } } /* Read VISUAL_SAMPLES samples per channel */ data = (const guint16 *) gst_adapter_peek (visual->adapter, VISUAL_SAMPLES * visual->bps); #if defined(VISUAL_API_VERSION) && VISUAL_API_VERSION >= 4000 && VISUAL_API_VERSION < 5000 { VisBuffer *lbuf, *rbuf; guint16 ldata[VISUAL_SAMPLES], rdata[VISUAL_SAMPLES]; VisAudioSampleRateType rate; lbuf = visual_buffer_new_with_buffer (ldata, sizeof (ldata), NULL); rbuf = visual_buffer_new_with_buffer (rdata, sizeof (rdata), NULL); if (visual->channels == 2) { for (i = 0; i < VISUAL_SAMPLES; i++) { ldata[i] = *data++; rdata[i] = *data++; } } else { for (i = 0; i < VISUAL_SAMPLES; i++) { ldata[i] = *data; rdata[i] = *data++; } } switch (visual->rate) { case 8000: rate = VISUAL_AUDIO_SAMPLE_RATE_8000; break; case 11250: rate = VISUAL_AUDIO_SAMPLE_RATE_11250; break; case 22500: rate = VISUAL_AUDIO_SAMPLE_RATE_22500; break; case 32000: rate = VISUAL_AUDIO_SAMPLE_RATE_32000; break; case 44100: rate = VISUAL_AUDIO_SAMPLE_RATE_44100; break; case 48000: rate = VISUAL_AUDIO_SAMPLE_RATE_48000; break; case 96000: rate = VISUAL_AUDIO_SAMPLE_RATE_96000; break; default: visual_object_unref (VISUAL_OBJECT (lbuf)); visual_object_unref (VISUAL_OBJECT (rbuf)); GST_ERROR_OBJECT (visual, "unsupported rate %d", visual->rate); ret = GST_FLOW_ERROR; goto beach; break; } visual_audio_samplepool_input_channel (visual->audio->samplepool, lbuf, rate, VISUAL_AUDIO_SAMPLE_FORMAT_S16, (char *) VISUAL_AUDIO_CHANNEL_LEFT); visual_audio_samplepool_input_channel (visual->audio->samplepool, rbuf, rate, VISUAL_AUDIO_SAMPLE_FORMAT_S16, (char *) VISUAL_AUDIO_CHANNEL_RIGHT); visual_object_unref (VISUAL_OBJECT (lbuf)); visual_object_unref (VISUAL_OBJECT (rbuf)); } #else if (visual->channels == 2) { for (i = 0; i < VISUAL_SAMPLES; i++) { visual->audio->plugpcm[0][i] = *data++; visual->audio->plugpcm[1][i] = *data++; } } else { for (i = 0; i < VISUAL_SAMPLES; i++) { visual->audio->plugpcm[0][i] = *data; visual->audio->plugpcm[1][i] = *data++; } } #endif /* alloc a buffer if we don't have one yet, this happens * when we pushed a buffer in this while loop before */ if (outbuf == NULL) { ret = get_buffer (visual, &outbuf); if (ret != GST_FLOW_OK) { goto beach; } } visual_video_set_buffer (visual->video, GST_BUFFER_DATA (outbuf)); visual_audio_analyze (visual->audio); visual_actor_run (visual->actor, visual->audio); visual_video_set_buffer (visual->video, NULL); GST_DEBUG_OBJECT (visual, "rendered one frame"); GST_BUFFER_TIMESTAMP (outbuf) = timestamp; GST_BUFFER_DURATION (outbuf) = visual->duration; ret = gst_pad_push (visual->srcpad, outbuf); outbuf = NULL; skip: GST_DEBUG_OBJECT (visual, "finished frame, flushing %u samples from input", visual->spf); /* Flush out the number of samples per frame */ gst_adapter_flush (visual->adapter, visual->spf * visual->bps); /* quit the loop if something was wrong */ if (ret != GST_FLOW_OK) break; } beach: if (outbuf != NULL) gst_buffer_unref (outbuf); gst_object_unref (visual); return ret; }
static gboolean gst_musepackdec_handle_seek_event (GstMusepackDec * dec, GstEvent * event) { GstSeekType start_type, stop_type; GstSeekFlags flags; GstSegment segment; GstFormat format; gboolean flush; gdouble rate; gint64 start, stop; gint samplerate; gst_event_parse_seek (event, &rate, &format, &flags, &start_type, &start, &stop_type, &stop); if (format != GST_FORMAT_TIME && format != GST_FORMAT_DEFAULT) { GST_DEBUG_OBJECT (dec, "seek failed: only TIME or DEFAULT format allowed"); return FALSE; } samplerate = g_atomic_int_get (&dec->rate); if (format == GST_FORMAT_TIME) { if (start_type != GST_SEEK_TYPE_NONE) start = gst_util_uint64_scale_int (start, samplerate, GST_SECOND); if (stop_type != GST_SEEK_TYPE_NONE) stop = gst_util_uint64_scale_int (stop, samplerate, GST_SECOND); } flush = ((flags & GST_SEEK_FLAG_FLUSH) == GST_SEEK_FLAG_FLUSH); if (flush) gst_pad_push_event (dec->srcpad, gst_event_new_flush_start ()); else gst_pad_pause_task (dec->sinkpad); /* not _stop_task()? */ GST_PAD_STREAM_LOCK (dec->sinkpad); /* operate on segment copy until we know the seek worked */ segment = dec->segment; gst_segment_set_seek (&segment, rate, GST_FORMAT_DEFAULT, flags, start_type, start, stop_type, stop, NULL); gst_pad_push_event (dec->sinkpad, gst_event_new_flush_stop ()); GST_DEBUG_OBJECT (dec, "segment: [%" G_GINT64_FORMAT "-%" G_GINT64_FORMAT "] = [%" GST_TIME_FORMAT "-%" GST_TIME_FORMAT "]", segment.start, segment.stop, GST_TIME_ARGS (segment.start * GST_SECOND / dec->rate), GST_TIME_ARGS (segment.stop * GST_SECOND / dec->rate)); GST_DEBUG_OBJECT (dec, "performing seek to sample %" G_GINT64_FORMAT, segment.start); if (segment.start < 0 || segment.start >= segment.duration) { GST_WARNING_OBJECT (dec, "seek out of bounds"); goto failed; } #ifdef MPC_IS_OLD_API if (!mpc_decoder_seek_sample (dec->d, segment.start)) goto failed; #else if (mpc_demux_seek_sample (dec->d, segment.start) != MPC_STATUS_OK) goto failed; #endif if ((flags & GST_SEEK_FLAG_SEGMENT) == GST_SEEK_FLAG_SEGMENT) { GST_DEBUG_OBJECT (dec, "posting SEGMENT_START message"); gst_element_post_message (GST_ELEMENT (dec), gst_message_new_segment_start (GST_OBJECT (dec), GST_FORMAT_TIME, gst_util_uint64_scale_int (segment.start, GST_SECOND, dec->rate))); } if (flush) { gst_pad_push_event (dec->srcpad, gst_event_new_flush_stop ()); } gst_segment_set_last_stop (&segment, GST_FORMAT_DEFAULT, segment.start); dec->segment = segment; gst_musepackdec_send_newsegment (dec); GST_DEBUG_OBJECT (dec, "seek successful"); gst_pad_start_task (dec->sinkpad, (GstTaskFunction) gst_musepackdec_loop, dec->sinkpad, NULL); GST_PAD_STREAM_UNLOCK (dec->sinkpad); return TRUE; failed: { GST_WARNING_OBJECT (dec, "seek failed"); GST_PAD_STREAM_UNLOCK (dec->sinkpad); return FALSE; } }
static GstFlowReturn gst_rdt_depay_handle_data (GstRDTDepay * rdtdepay, GstClockTime outtime, GstRDTPacket * packet) { GstFlowReturn ret; GstBuffer *outbuf; GstMapInfo outmap; guint8 *data, *outdata; guint size; guint16 stream_id; guint32 timestamp; gint gap; guint16 seqnum; guint8 flags; guint16 outflags; /* get pointers to the packet data */ data = gst_rdt_packet_data_map (packet, &size); outbuf = gst_buffer_new_and_alloc (12 + size); GST_BUFFER_TIMESTAMP (outbuf) = outtime; GST_DEBUG_OBJECT (rdtdepay, "have size %u", size); /* copy over some things */ stream_id = gst_rdt_packet_data_get_stream_id (packet); timestamp = gst_rdt_packet_data_get_timestamp (packet); flags = gst_rdt_packet_data_get_flags (packet); seqnum = gst_rdt_packet_data_get_seq (packet); GST_DEBUG_OBJECT (rdtdepay, "stream_id %u, timestamp %u, seqnum %d, flags %d", stream_id, timestamp, seqnum, flags); if (rdtdepay->next_seqnum != -1) { gap = gst_rdt_buffer_compare_seqnum (seqnum, rdtdepay->next_seqnum); /* if we have no gap, all is fine */ if (G_UNLIKELY (gap != 0)) { GST_LOG_OBJECT (rdtdepay, "got packet %u, expected %u, gap %d", seqnum, rdtdepay->next_seqnum, gap); if (gap < 0) { /* seqnum > next_seqnum, we are missing some packets, this is always a * DISCONT. */ GST_LOG_OBJECT (rdtdepay, "%d missing packets", gap); rdtdepay->discont = TRUE; } else { /* seqnum < next_seqnum, we have seen this packet before or the sender * could be restarted. If the packet is not too old, we throw it away as * a duplicate, otherwise we mark discont and continue. 100 misordered * packets is a good threshold. See also RFC 4737. */ if (gap < 100) goto dropping; GST_LOG_OBJECT (rdtdepay, "%d > 100, packet too old, sender likely restarted", gap); rdtdepay->discont = TRUE; } } } rdtdepay->next_seqnum = (seqnum + 1); if (rdtdepay->next_seqnum == 0xff00) rdtdepay->next_seqnum = 0; if ((flags & 1) == 0) outflags = 2; else outflags = 0; gst_buffer_map (outbuf, &outmap, GST_MAP_WRITE); outdata = outmap.data; GST_WRITE_UINT16_BE (outdata + 0, 0); /* version */ GST_WRITE_UINT16_BE (outdata + 2, size + 12); /* length */ GST_WRITE_UINT16_BE (outdata + 4, stream_id); /* stream */ GST_WRITE_UINT32_BE (outdata + 6, timestamp); /* timestamp */ GST_WRITE_UINT16_BE (outdata + 10, outflags); /* flags */ memcpy (outdata + 12, data, size); gst_buffer_unmap (outbuf, &outmap); gst_buffer_resize (outbuf, 0, 12 + size); gst_rdt_packet_data_unmap (packet); GST_DEBUG_OBJECT (rdtdepay, "Pushing packet, outtime %" GST_TIME_FORMAT, GST_TIME_ARGS (outtime)); ret = gst_rdt_depay_push (rdtdepay, outbuf); return ret; /* ERRORS */ dropping: { GST_WARNING_OBJECT (rdtdepay, "%d <= 100, dropping old packet", gap); return GST_FLOW_OK; } }
static gboolean gst_hls_demux_update_playlist (GstHLSDemux * demux, gboolean update, GError ** err) { GstAdaptiveDemux *adaptive_demux = GST_ADAPTIVE_DEMUX (demux); GstFragment *download; GstBuffer *buf; gchar *playlist; gboolean main_checked = FALSE, updated = FALSE; gchar *uri, *main_uri; retry: uri = gst_m3u8_client_get_current_uri (demux->client); main_uri = gst_m3u8_client_get_uri (demux->client); download = gst_uri_downloader_fetch_uri (adaptive_demux->downloader, uri, main_uri, TRUE, TRUE, TRUE, err); g_free (main_uri); if (download == NULL) { if (!adaptive_demux->cancelled && update && !main_checked && gst_m3u8_client_has_variant_playlist (demux->client) && gst_m3u8_client_has_main (demux->client)) { GError *err2 = NULL; main_uri = gst_m3u8_client_get_uri (demux->client); GST_INFO_OBJECT (demux, "Updating playlist %s failed, attempt to refresh variant playlist %s", uri, main_uri); download = gst_uri_downloader_fetch_uri (adaptive_demux->downloader, main_uri, NULL, TRUE, TRUE, TRUE, &err2); g_free (main_uri); g_clear_error (&err2); if (download != NULL) { gchar *base_uri; buf = gst_fragment_get_buffer (download); playlist = gst_hls_src_buf_to_utf8_playlist (buf); gst_buffer_unref (buf); if (playlist == NULL) { GST_WARNING_OBJECT (demux, "Failed to validate variant playlist encoding"); g_free (uri); g_object_unref (download); return FALSE; } g_free (uri); if (download->redirect_permanent && download->redirect_uri) { uri = download->redirect_uri; base_uri = NULL; } else { uri = download->uri; base_uri = download->redirect_uri; } if (!gst_m3u8_client_update_variant_playlist (demux->client, playlist, uri, base_uri)) { GST_WARNING_OBJECT (demux, "Failed to update the variant playlist"); g_object_unref (download); return FALSE; } g_object_unref (download); g_clear_error (err); main_checked = TRUE; goto retry; } else { g_free (uri); return FALSE; } } else { g_free (uri); return FALSE; } } g_free (uri); /* Set the base URI of the playlist to the redirect target if any */ GST_M3U8_CLIENT_LOCK (demux->client); g_free (demux->client->current->uri); g_free (demux->client->current->base_uri); if (download->redirect_permanent && download->redirect_uri) { demux->client->current->uri = g_strdup (download->redirect_uri); demux->client->current->base_uri = NULL; } else { demux->client->current->uri = g_strdup (download->uri); demux->client->current->base_uri = g_strdup (download->redirect_uri); } GST_M3U8_CLIENT_UNLOCK (demux->client); buf = gst_fragment_get_buffer (download); playlist = gst_hls_src_buf_to_utf8_playlist (buf); gst_buffer_unref (buf); g_object_unref (download); if (playlist == NULL) { GST_WARNING_OBJECT (demux, "Couldn't validate playlist encoding"); g_set_error (err, GST_STREAM_ERROR, GST_STREAM_ERROR_WRONG_TYPE, "Couldn't validate playlist encoding"); return FALSE; } updated = gst_m3u8_client_update (demux->client, playlist); if (!updated) { GST_WARNING_OBJECT (demux, "Couldn't update playlist"); g_set_error (err, GST_STREAM_ERROR, GST_STREAM_ERROR_FAILED, "Couldn't update playlist"); return FALSE; } /* If it's a live source, do not let the sequence number go beyond * three fragments before the end of the list */ if (update == FALSE && demux->client->current && gst_m3u8_client_is_live (demux->client)) { gint64 last_sequence; GST_M3U8_CLIENT_LOCK (demux->client); last_sequence = GST_M3U8_MEDIA_FILE (g_list_last (demux->client->current-> files)->data)->sequence; if (demux->client->sequence >= last_sequence - 3) { GST_DEBUG_OBJECT (demux, "Sequence is beyond playlist. Moving back to %u", (guint) (last_sequence - 3)); //demux->need_segment = TRUE; demux->client->sequence = last_sequence - 3; } GST_M3U8_CLIENT_UNLOCK (demux->client); } else if (demux->client->current && !gst_m3u8_client_is_live (demux->client)) { GstClockTime current_pos, target_pos; guint sequence = 0; GList *walk; /* Sequence numbers are not guaranteed to be the same in different * playlists, so get the correct fragment here based on the current * position */ GST_M3U8_CLIENT_LOCK (demux->client); /* Valid because hlsdemux only has a single output */ if (GST_ADAPTIVE_DEMUX_CAST (demux)->streams) { GstAdaptiveDemuxStream *stream = GST_ADAPTIVE_DEMUX_CAST (demux)->streams->data; target_pos = stream->segment.position; } else { target_pos = 0; } if (GST_CLOCK_TIME_IS_VALID (demux->client->sequence_position)) { target_pos = MAX (target_pos, demux->client->sequence_position); } current_pos = 0; for (walk = demux->client->current->files; walk; walk = walk->next) { GstM3U8MediaFile *file = walk->data; sequence = file->sequence; if (current_pos <= target_pos && target_pos < current_pos + file->duration) { break; } current_pos += file->duration; } /* End of playlist */ if (!walk) sequence++; demux->client->sequence = sequence; demux->client->sequence_position = current_pos; GST_M3U8_CLIENT_UNLOCK (demux->client); } return updated; }
static gboolean gst_v4l2src_query (GstBaseSrc * bsrc, GstQuery * query) { GstV4l2Src *src; GstV4l2Object *obj; gboolean res = FALSE; src = GST_V4L2SRC (bsrc); obj = src->v4l2object; switch (GST_QUERY_TYPE (query)) { case GST_QUERY_LATENCY:{ GstClockTime min_latency, max_latency; guint32 fps_n, fps_d; guint num_buffers = 0; /* device must be open */ if (!GST_V4L2_IS_OPEN (obj)) { GST_WARNING_OBJECT (src, "Can't give latency since device isn't open !"); goto done; } fps_n = GST_V4L2_FPS_N (obj); fps_d = GST_V4L2_FPS_D (obj); /* we must have a framerate */ if (fps_n <= 0 || fps_d <= 0) { GST_WARNING_OBJECT (src, "Can't give latency since framerate isn't fixated !"); goto done; } /* min latency is the time to capture one frame */ min_latency = gst_util_uint64_scale_int (GST_SECOND, fps_d, fps_n); /* max latency is total duration of the frame buffer */ if (obj->pool != NULL) num_buffers = GST_V4L2_BUFFER_POOL_CAST (obj->pool)->num_buffers; if (num_buffers == 0) max_latency = -1; else max_latency = num_buffers * min_latency; GST_DEBUG_OBJECT (bsrc, "report latency min %" GST_TIME_FORMAT " max %" GST_TIME_FORMAT, GST_TIME_ARGS (min_latency), GST_TIME_ARGS (max_latency)); /* we are always live, the min latency is 1 frame and the max latency is * the complete buffer of frames. */ gst_query_set_latency (query, TRUE, min_latency, max_latency); res = TRUE; break; } default: res = GST_BASE_SRC_CLASS (parent_class)->query (bsrc, query); break; } done: return res; }
static gboolean gst_v4l2src_decide_allocation (GstBaseSrc * bsrc, GstQuery * query) { GstV4l2Src *src; GstV4l2Object *obj; GstBufferPool *pool; guint size, min, max; gboolean update; src = GST_V4L2SRC (bsrc); obj = src->v4l2object; if (gst_query_get_n_allocation_pools (query) > 0) { gst_query_parse_nth_allocation_pool (query, 0, &pool, &size, &min, &max); update = TRUE; } else { pool = NULL; min = max = 0; size = 0; update = FALSE; } GST_DEBUG_OBJECT (src, "allocation: size:%u min:%u max:%u pool:%" GST_PTR_FORMAT, size, min, max, pool); if (min != 0) { /* if there is a min-buffers suggestion, use it. We add 1 because we need 1 * buffer extra to capture while the other two buffers are downstream */ min += 1; } else { min = 2; } /* select a pool */ switch (obj->mode) { case GST_V4L2_IO_RW: if (pool == NULL) { /* no downstream pool, use our own then */ GST_DEBUG_OBJECT (src, "read/write mode: no downstream pool, using our own"); pool = GST_BUFFER_POOL_CAST (obj->pool); size = obj->sizeimage; } else { /* in READ/WRITE mode, prefer a downstream pool because our own pool * doesn't help much, we have to write to it as well */ GST_DEBUG_OBJECT (src, "read/write mode: using downstream pool"); /* use the bigest size, when we use our own pool we can't really do any * other size than what the hardware gives us but for downstream pools * we can try */ size = MAX (size, obj->sizeimage); } break; case GST_V4L2_IO_MMAP: case GST_V4L2_IO_USERPTR: case GST_V4L2_IO_DMABUF: /* in streaming mode, prefer our own pool */ pool = GST_BUFFER_POOL_CAST (obj->pool); size = obj->sizeimage; GST_DEBUG_OBJECT (src, "streaming mode: using our own pool %" GST_PTR_FORMAT, pool); break; case GST_V4L2_IO_AUTO: default: GST_WARNING_OBJECT (src, "unhandled mode"); break; } if (pool) { GstStructure *config; GstCaps *caps; config = gst_buffer_pool_get_config (pool); gst_buffer_pool_config_get_params (config, &caps, NULL, NULL, NULL); gst_buffer_pool_config_set_params (config, caps, size, min, max); /* if downstream supports video metadata, add this to the pool config */ if (gst_query_find_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL)) { GST_DEBUG_OBJECT (pool, "activate Video Meta"); gst_buffer_pool_config_add_option (config, GST_BUFFER_POOL_OPTION_VIDEO_META); } gst_buffer_pool_set_config (pool, config); } if (update) gst_query_set_nth_allocation_pool (query, 0, pool, size, min, max); else gst_query_add_allocation_pool (query, pool, size, min, max); return GST_BASE_SRC_CLASS (parent_class)->decide_allocation (bsrc, query); }
static gboolean gst_wavenc_event (GstPad * pad, GstObject * parent, GstEvent * event) { gboolean res = TRUE; GstWavEnc *wavenc; GstTagList *tags; GstToc *toc; wavenc = GST_WAVENC (parent); switch (GST_EVENT_TYPE (event)) { case GST_EVENT_CAPS: { GstCaps *caps; gst_event_parse_caps (event, &caps); gst_wavenc_sink_setcaps (pad, caps); /* have our own src caps */ gst_event_unref (event); break; } case GST_EVENT_EOS: { GstFlowReturn flow; GST_DEBUG_OBJECT (wavenc, "got EOS"); flow = gst_wavenc_write_toc (wavenc); if (flow != GST_FLOW_OK) { GST_WARNING_OBJECT (wavenc, "error pushing toc: %s", gst_flow_get_name (flow)); } flow = gst_wavenc_write_tags (wavenc); if (flow != GST_FLOW_OK) { GST_WARNING_OBJECT (wavenc, "error pushing tags: %s", gst_flow_get_name (flow)); } /* write header with correct length values */ gst_wavenc_push_header (wavenc); /* we're done with this file */ wavenc->finished_properly = TRUE; /* and forward the EOS event */ res = gst_pad_event_default (pad, parent, event); break; } case GST_EVENT_SEGMENT: /* Just drop it, it's probably in TIME format * anyway. We'll send our own newsegment event */ gst_event_unref (event); break; case GST_EVENT_TOC: gst_event_parse_toc (event, &toc, NULL); if (toc) { if (wavenc->toc != toc) { if (wavenc->toc) gst_toc_unref (wavenc->toc); wavenc->toc = toc; } else { gst_toc_unref (toc); } } res = gst_pad_event_default (pad, parent, event); break; case GST_EVENT_TAG: gst_event_parse_tag (event, &tags); if (tags) { if (wavenc->tags != tags) { if (wavenc->tags) gst_tag_list_unref (wavenc->tags); wavenc->tags = gst_tag_list_ref (tags); } } res = gst_pad_event_default (pad, parent, event); break; default: res = gst_pad_event_default (pad, parent, event); break; } return res; }
static void gst_raw_parse_loop (GstElement * element) { GstRawParse *rp = GST_RAW_PARSE (element); GstRawParseClass *rp_class = GST_RAW_PARSE_GET_CLASS (rp); GstFlowReturn ret; GstBuffer *buffer; gint size; if (G_UNLIKELY (rp->push_stream_start)) { gchar *stream_id; GstEvent *event; stream_id = gst_pad_create_stream_id (rp->srcpad, GST_ELEMENT_CAST (rp), NULL); event = gst_event_new_stream_start (stream_id); gst_event_set_group_id (event, gst_util_group_id_next ()); GST_DEBUG_OBJECT (rp, "Pushing STREAM_START"); gst_pad_push_event (rp->srcpad, event); rp->push_stream_start = FALSE; g_free (stream_id); } if (!gst_raw_parse_set_src_caps (rp)) goto no_caps; if (rp->start_segment) { GST_DEBUG_OBJECT (rp, "sending start segment"); gst_pad_push_event (rp->srcpad, rp->start_segment); rp->start_segment = NULL; } if (rp_class->multiple_frames_per_buffer && rp->framesize < 4096) size = 4096 - (4096 % rp->framesize); else size = rp->framesize; if (rp->segment.rate >= 0) { if (rp->offset + size > rp->upstream_length) { GstFormat fmt = GST_FORMAT_BYTES; if (!gst_pad_peer_query_duration (rp->sinkpad, fmt, &rp->upstream_length)) { GST_WARNING_OBJECT (rp, "Could not get upstream duration, trying to pull frame by frame"); size = rp->framesize; } else if (rp->upstream_length < rp->offset + rp->framesize) { ret = GST_FLOW_EOS; goto pause; } else if (rp->offset + size > rp->upstream_length) { size = rp->upstream_length - rp->offset; size -= size % rp->framesize; } } } else { if (rp->offset == 0) { ret = GST_FLOW_EOS; goto pause; } else if (rp->offset < size) { size -= rp->offset; } rp->offset -= size; } buffer = NULL; ret = gst_pad_pull_range (rp->sinkpad, rp->offset, size, &buffer); if (ret != GST_FLOW_OK) { GST_DEBUG_OBJECT (rp, "pull_range (%" G_GINT64_FORMAT ", %u) " "failed, flow: %s", rp->offset, size, gst_flow_get_name (ret)); buffer = NULL; goto pause; } if (gst_buffer_get_size (buffer) < size) { GST_DEBUG_OBJECT (rp, "Short read at offset %" G_GINT64_FORMAT ", got only %" G_GSIZE_FORMAT " of %u bytes", rp->offset, gst_buffer_get_size (buffer), size); if (size > rp->framesize) { gst_buffer_set_size (buffer, gst_buffer_get_size (buffer) - gst_buffer_get_size (buffer) % rp->framesize); } else { gst_buffer_unref (buffer); buffer = NULL; ret = GST_FLOW_EOS; goto pause; } } ret = gst_raw_parse_push_buffer (rp, buffer); if (ret != GST_FLOW_OK) goto pause; return; /* ERRORS */ no_caps: { GST_ERROR_OBJECT (rp, "could not negotiate caps"); ret = GST_FLOW_NOT_NEGOTIATED; goto pause; } pause: { const gchar *reason = gst_flow_get_name (ret); GST_LOG_OBJECT (rp, "pausing task, reason %s", reason); gst_pad_pause_task (rp->sinkpad); if (ret == GST_FLOW_EOS) { if (rp->segment.flags & GST_SEEK_FLAG_SEGMENT) { GstClockTime stop; GST_LOG_OBJECT (rp, "Sending segment done"); if ((stop = rp->segment.stop) == -1) stop = rp->segment.duration; gst_element_post_message (GST_ELEMENT_CAST (rp), gst_message_new_segment_done (GST_OBJECT_CAST (rp), rp->segment.format, stop)); gst_pad_push_event (rp->srcpad, gst_event_new_segment_done (rp->segment.format, stop)); } else { GST_LOG_OBJECT (rp, "Sending EOS, at end of stream"); gst_pad_push_event (rp->srcpad, gst_event_new_eos ()); } } else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_EOS) { GST_ELEMENT_ERROR (rp, STREAM, FAILED, ("Internal data stream error."), ("stream stopped, reason %s", reason)); gst_pad_push_event (rp->srcpad, gst_event_new_eos ()); } return; } }
static GstFlowReturn mpegtsmux_create_stream (MpegTsMux * mux, MpegTsPadData * ts_data, GstPad * pad) { GstFlowReturn ret = GST_FLOW_ERROR; GstCaps *caps = gst_pad_get_negotiated_caps (pad); GstStructure *s; if (caps == NULL) { GST_DEBUG_OBJECT (pad, "Sink pad caps were not set before pushing"); return GST_FLOW_NOT_NEGOTIATED; } s = gst_caps_get_structure (caps, 0); g_return_val_if_fail (s != NULL, FALSE); if (gst_structure_has_name (s, "video/x-dirac")) { GST_DEBUG_OBJECT (pad, "Creating Dirac stream with PID 0x%04x", ts_data->pid); ts_data->stream = tsmux_create_stream (mux->tsmux, TSMUX_ST_VIDEO_DIRAC, ts_data->pid); } else if (gst_structure_has_name (s, "audio/x-ac3")) { GST_DEBUG_OBJECT (pad, "Creating AC3 stream with PID 0x%04x", ts_data->pid); ts_data->stream = tsmux_create_stream (mux->tsmux, TSMUX_ST_PS_AUDIO_AC3, ts_data->pid); } else if (gst_structure_has_name (s, "audio/x-dts")) { GST_DEBUG_OBJECT (pad, "Creating DTS stream with PID 0x%04x", ts_data->pid); ts_data->stream = tsmux_create_stream (mux->tsmux, TSMUX_ST_PS_AUDIO_DTS, ts_data->pid); } else if (gst_structure_has_name (s, "audio/x-lpcm")) { GST_DEBUG_OBJECT (pad, "Creating LPCM stream with PID 0x%04x", ts_data->pid); ts_data->stream = tsmux_create_stream (mux->tsmux, TSMUX_ST_PS_AUDIO_LPCM, ts_data->pid); } else if (gst_structure_has_name (s, "video/x-h264")) { const GValue *value; GST_DEBUG_OBJECT (pad, "Creating H264 stream with PID 0x%04x", ts_data->pid); /* Codec data contains SPS/PPS which need to go in stream for valid ES */ value = gst_structure_get_value (s, "codec_data"); if (value) { ts_data->codec_data = gst_buffer_ref (gst_value_get_buffer (value)); GST_DEBUG_OBJECT (pad, "we have additional codec data (%d bytes)", GST_BUFFER_SIZE (ts_data->codec_data)); ts_data->prepare_func = mpegtsmux_prepare_h264; ts_data->free_func = mpegtsmux_free_h264; } else { ts_data->codec_data = NULL; } ts_data->stream = tsmux_create_stream (mux->tsmux, TSMUX_ST_VIDEO_H264, ts_data->pid); } else if (gst_structure_has_name (s, "audio/mpeg")) { gint mpegversion; if (!gst_structure_get_int (s, "mpegversion", &mpegversion)) { GST_ELEMENT_ERROR (pad, STREAM, FORMAT, ("Invalid data format presented"), ("Caps with type audio/mpeg did not have mpegversion")); goto beach; } switch (mpegversion) { case 1: GST_DEBUG_OBJECT (pad, "Creating MPEG Audio, version 1 stream with " "PID 0x%04x", ts_data->pid); ts_data->stream = tsmux_create_stream (mux->tsmux, TSMUX_ST_AUDIO_MPEG1, ts_data->pid); break; case 2: GST_DEBUG_OBJECT (pad, "Creating MPEG Audio, version 2 stream with " "PID 0x%04x", ts_data->pid); ts_data->stream = tsmux_create_stream (mux->tsmux, TSMUX_ST_AUDIO_MPEG2, ts_data->pid); break; case 4: { const GValue *value; /* Codec data contains SPS/PPS which need to go in stream for valid ES */ value = gst_structure_get_value (s, "codec_data"); if (value) { ts_data->codec_data = gst_buffer_ref (gst_value_get_buffer (value)); GST_DEBUG_OBJECT (pad, "we have additional codec data (%d bytes)", GST_BUFFER_SIZE (ts_data->codec_data)); ts_data->prepare_func = mpegtsmux_prepare_aac; } else { ts_data->codec_data = NULL; } GST_DEBUG_OBJECT (pad, "Creating MPEG Audio, version 4 stream with " "PID 0x%04x", ts_data->pid); ts_data->stream = tsmux_create_stream (mux->tsmux, TSMUX_ST_AUDIO_AAC, ts_data->pid); break; } default: GST_WARNING_OBJECT (pad, "unsupported mpegversion %d", mpegversion); goto beach; } } else if (gst_structure_has_name (s, "video/mpeg")) { gint mpegversion; if (!gst_structure_get_int (s, "mpegversion", &mpegversion)) { GST_ELEMENT_ERROR (mux, STREAM, FORMAT, ("Invalid data format presented"), ("Caps with type video/mpeg did not have mpegversion")); goto beach; } if (mpegversion == 1) { GST_DEBUG_OBJECT (pad, "Creating MPEG Video, version 1 stream with PID 0x%04x", ts_data->pid); ts_data->stream = tsmux_create_stream (mux->tsmux, TSMUX_ST_VIDEO_MPEG1, ts_data->pid); } else if (mpegversion == 2) { GST_DEBUG_OBJECT (pad, "Creating MPEG Video, version 2 stream with PID 0x%04x", ts_data->pid); ts_data->stream = tsmux_create_stream (mux->tsmux, TSMUX_ST_VIDEO_MPEG2, ts_data->pid); } else { GST_DEBUG_OBJECT (pad, "Creating MPEG Video, version 4 stream with PID 0x%04x", ts_data->pid); ts_data->stream = tsmux_create_stream (mux->tsmux, TSMUX_ST_VIDEO_MPEG4, ts_data->pid); } } if (ts_data->stream != NULL) { gst_structure_get_int (s, "rate", &ts_data->stream->audio_sampling); gst_structure_get_int (s, "channels", &ts_data->stream->audio_channels); gst_structure_get_int (s, "bitrate", &ts_data->stream->audio_bitrate); tsmux_stream_set_buffer_release_func (ts_data->stream, release_buffer_cb); tsmux_program_add_stream (ts_data->prog, ts_data->stream); ret = GST_FLOW_OK; } beach: gst_caps_unref (caps); return ret; }
static gpointer gst_net_client_internal_clock_thread (gpointer data) { GstNetClientInternalClock *self = data; GSocket *socket = self->socket; GError *err = NULL; GST_INFO_OBJECT (self, "net client clock thread running, socket=%p", socket); g_socket_set_blocking (socket, TRUE); g_socket_set_timeout (socket, 0); while (!g_cancellable_is_cancelled (self->cancel)) { GstClockTime expiration_time = self->timeout_expiration; GstClockTime now = gst_util_get_timestamp (); gint64 socket_timeout; if (now >= expiration_time || (expiration_time - now) <= GST_MSECOND) { socket_timeout = 0; } else { socket_timeout = (expiration_time - now) / GST_USECOND; } GST_TRACE_OBJECT (self, "timeout: %" G_GINT64_FORMAT "us", socket_timeout); if (!g_socket_condition_timed_wait (socket, G_IO_IN, socket_timeout, self->cancel, &err)) { /* cancelled, timeout or error */ if (err->code == G_IO_ERROR_CANCELLED) { GST_INFO_OBJECT (self, "cancelled"); g_clear_error (&err); break; } else if (err->code == G_IO_ERROR_TIMED_OUT) { /* timed out, let's send another packet */ GST_DEBUG_OBJECT (self, "timed out"); if (self->is_ntp) { GstNtpPacket *packet; packet = gst_ntp_packet_new (NULL, NULL); packet->transmit_time = gst_clock_get_internal_time (GST_CLOCK_CAST (self)); GST_DEBUG_OBJECT (self, "sending packet, local time = %" GST_TIME_FORMAT, GST_TIME_ARGS (packet->transmit_time)); gst_ntp_packet_send (packet, self->socket, self->servaddr, NULL); g_free (packet); } else { GstNetTimePacket *packet; packet = gst_net_time_packet_new (NULL); packet->local_time = gst_clock_get_internal_time (GST_CLOCK_CAST (self)); GST_DEBUG_OBJECT (self, "sending packet, local time = %" GST_TIME_FORMAT, GST_TIME_ARGS (packet->local_time)); gst_net_time_packet_send (packet, self->socket, self->servaddr, NULL); g_free (packet); } /* reset timeout (but are expecting a response sooner anyway) */ self->timeout_expiration = gst_util_get_timestamp () + gst_clock_get_timeout (GST_CLOCK_CAST (self)); } else { GST_DEBUG_OBJECT (self, "socket error: %s", err->message); g_usleep (G_USEC_PER_SEC / 10); /* throttle */ } g_clear_error (&err); } else { GstClockTime new_local; /* got packet */ new_local = gst_clock_get_internal_time (GST_CLOCK_CAST (self)); if (self->is_ntp) { GstNtpPacket *packet; packet = gst_ntp_packet_receive (socket, NULL, &err); if (packet != NULL) { GST_LOG_OBJECT (self, "got packet back"); GST_LOG_OBJECT (self, "local_1 = %" GST_TIME_FORMAT, GST_TIME_ARGS (packet->origin_time)); GST_LOG_OBJECT (self, "remote_1 = %" GST_TIME_FORMAT, GST_TIME_ARGS (packet->receive_time)); GST_LOG_OBJECT (self, "remote_2 = %" GST_TIME_FORMAT, GST_TIME_ARGS (packet->transmit_time)); GST_LOG_OBJECT (self, "local_2 = %" GST_TIME_FORMAT, GST_TIME_ARGS (new_local)); GST_LOG_OBJECT (self, "poll_interval = %" GST_TIME_FORMAT, GST_TIME_ARGS (packet->poll_interval)); /* Remember the last poll interval we ever got from the server */ if (packet->poll_interval != GST_CLOCK_TIME_NONE) self->last_remote_poll_interval = packet->poll_interval; /* observe_times will reset the timeout */ gst_net_client_internal_clock_observe_times (self, packet->origin_time, packet->receive_time, packet->transmit_time, new_local); g_free (packet); } else if (err != NULL) { if (g_error_matches (err, GST_NTP_ERROR, GST_NTP_ERROR_WRONG_VERSION) || g_error_matches (err, GST_NTP_ERROR, GST_NTP_ERROR_KOD_DENY)) { GST_ERROR_OBJECT (self, "fatal receive error: %s", err->message); g_clear_error (&err); break; } else if (g_error_matches (err, GST_NTP_ERROR, GST_NTP_ERROR_KOD_RATE)) { GST_WARNING_OBJECT (self, "need to limit rate"); /* If the server did not tell us a poll interval before, double * our minimum poll interval. Otherwise we assume that the server * already told us something sensible and that this error here * was just a spurious error */ if (self->last_remote_poll_interval == GST_CLOCK_TIME_NONE) self->minimum_update_interval *= 2; /* And wait a bit before we send the next packet instead of * sending it immediately */ self->timeout_expiration = gst_util_get_timestamp () + gst_clock_get_timeout (GST_CLOCK_CAST (self)); } else { GST_WARNING_OBJECT (self, "receive error: %s", err->message); } g_clear_error (&err); } } else { GstNetTimePacket *packet; packet = gst_net_time_packet_receive (socket, NULL, &err); if (packet != NULL) { GST_LOG_OBJECT (self, "got packet back"); GST_LOG_OBJECT (self, "local_1 = %" GST_TIME_FORMAT, GST_TIME_ARGS (packet->local_time)); GST_LOG_OBJECT (self, "remote = %" GST_TIME_FORMAT, GST_TIME_ARGS (packet->remote_time)); GST_LOG_OBJECT (self, "local_2 = %" GST_TIME_FORMAT, GST_TIME_ARGS (new_local)); /* observe_times will reset the timeout */ gst_net_client_internal_clock_observe_times (self, packet->local_time, packet->remote_time, packet->remote_time, new_local); g_free (packet); } else if (err != NULL) { GST_WARNING_OBJECT (self, "receive error: %s", err->message); g_clear_error (&err); } } } } GST_INFO_OBJECT (self, "shutting down net client clock thread"); return NULL; }
gboolean gst_gl_handle_set_context (GstElement * element, GstContext * context, GstGLDisplay ** display, GstGLContext ** other_context) { GstGLDisplay *display_replacement = NULL; GstGLContext *context_replacement = NULL; const gchar *context_type; g_return_val_if_fail (display != NULL, FALSE); g_return_val_if_fail (other_context != NULL, FALSE); if (!context) return FALSE; context_type = gst_context_get_context_type (context); if (g_strcmp0 (context_type, GST_GL_DISPLAY_CONTEXT_TYPE) == 0) { if (!gst_context_get_gl_display (context, &display_replacement)) { GST_WARNING_OBJECT (element, "Failed to get display from context"); return FALSE; } } #if GST_GL_HAVE_WINDOW_X11 else if (g_strcmp0 (context_type, "gst.x11.display.handle") == 0) { const GstStructure *s; Display *display; s = gst_context_get_structure (context); if (gst_structure_get (s, "display", G_TYPE_POINTER, &display, NULL)) display_replacement = (GstGLDisplay *) gst_gl_display_x11_new_with_display (display); } #endif #if GST_GL_HAVE_WINDOW_WAYLAND else if (g_strcmp0 (context_type, "GstWaylandDisplayHandleContextType") == 0) { const GstStructure *s; struct wl_display *display; s = gst_context_get_structure (context); if (gst_structure_get (s, "display", G_TYPE_POINTER, &display, NULL)) display_replacement = (GstGLDisplay *) gst_gl_display_wayland_new_with_display (display); } #endif else if (g_strcmp0 (context_type, "gst.gl.app_context") == 0) { const GstStructure *s = gst_context_get_structure (context); GstGLDisplay *context_display; GstGLDisplay *element_display; if (gst_structure_get (s, "context", GST_GL_TYPE_CONTEXT, &context_replacement, NULL)) { context_display = gst_gl_context_get_display (context_replacement); element_display = display_replacement ? display_replacement : *display; if (element_display && (gst_gl_display_get_handle_type (element_display) & gst_gl_display_get_handle_type (context_display)) == 0) { GST_ELEMENT_WARNING (element, LIBRARY, SETTINGS, ("%s", "Cannot set a GL context with a different display type"), ("%s", "Cannot set a GL context with a different display type")); gst_object_unref (context_replacement); context_replacement = NULL; } gst_object_unref (context_display); } } if (display_replacement) { GstGLDisplay *old = *display; *display = display_replacement; if (old) gst_object_unref (old); } if (context_replacement) { GstGLContext *old = *other_context; *other_context = context_replacement; if (old) gst_object_unref (old); } return TRUE; }
static GstFlowReturn gst_kate_parse_push_headers (GstKateParse * parse) { /* mark and put on caps */ GstCaps *caps; GstBuffer *outbuf; kate_packet packet; GList *headers, *outbuf_list = NULL; int ret; gboolean res; /* get the headers into the caps, passing them to kate as we go */ caps = gst_kate_util_set_header_on_caps (&parse->element, gst_pad_get_current_caps (parse->sinkpad), parse->streamheader); if (G_UNLIKELY (!caps)) { GST_ELEMENT_ERROR (parse, STREAM, DECODE, (NULL), ("Failed to set headers on caps")); return GST_FLOW_ERROR; } GST_DEBUG_OBJECT (parse, "here are the caps: %" GST_PTR_FORMAT, caps); res = gst_pad_set_caps (parse->srcpad, caps); gst_caps_unref (caps); if (G_UNLIKELY (!res)) { GST_WARNING_OBJECT (parse->srcpad, "Failed to set caps on source pad"); return GST_FLOW_NOT_NEGOTIATED; } headers = parse->streamheader; while (headers) { GstMapInfo info; outbuf = GST_BUFFER_CAST (headers->data); if (!gst_buffer_map (outbuf, &info, GST_MAP_READ)) { GST_WARNING_OBJECT (outbuf, "Failed to map buffer"); continue; } kate_packet_wrap (&packet, info.size, info.data); ret = kate_decode_headerin (&parse->ki, &parse->kc, &packet); if (G_UNLIKELY (ret < 0)) { GST_WARNING_OBJECT (parse, "Failed to decode header: %s", gst_kate_util_get_error_message (ret)); } gst_buffer_unmap (outbuf, &info); /* takes ownership of outbuf, which was previously in parse->streamheader */ GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_HEADER); outbuf_list = g_list_append (outbuf_list, outbuf); headers = headers->next; } /* first process queued events */ gst_kate_parse_drain_event_queue (parse); /* push out buffers, ignoring return value... */ headers = outbuf_list; while (headers) { outbuf = GST_BUFFER_CAST (headers->data); gst_pad_push (parse->srcpad, outbuf); headers = headers->next; } g_list_free (outbuf_list); g_list_free (parse->streamheader); parse->streamheader = NULL; parse->streamheader_sent = TRUE; return GST_FLOW_OK; }
static gint gst_imx_v4l2src_capture_setup(GstImxV4l2Src *v4l2src) { struct v4l2_format fmt = {0}; struct v4l2_streamparm parm = {0}; #ifdef WITH_CHIP_IDENTIFICATION struct v4l2_dbg_chip_ident chip; #endif struct v4l2_frmsizeenum fszenum = {0}; v4l2_std_id id; gint input; gint fd_v4l; fd_v4l = open(v4l2src->devicename, O_RDWR, 0); if (fd_v4l < 0) { GST_ERROR_OBJECT(v4l2src, "Unable to open %s", v4l2src->devicename); return -1; } #ifdef WITH_CHIP_IDENTIFICATION memset(&chip, 0, sizeof(chip)); if (ioctl(fd_v4l, VIDIOC_DBG_G_CHIP_IDENT, &chip)) GST_ERROR_OBJECT(v4l2src, "VIDIOC_DBG_G_CHIP_IDENT failed"); else GST_INFO_OBJECT(v4l2src, "sensor chip is %s", chip.match.name); #endif if (ioctl (fd_v4l, VIDIOC_G_STD, &id) < 0) { GST_WARNING_OBJECT(v4l2src, "VIDIOC_G_STD failed: %s", strerror(errno)); } else { if (ioctl (fd_v4l, VIDIOC_S_STD, &id) < 0) { GST_ERROR_OBJECT(v4l2src, "VIDIOC_S_STD failed"); close(fd_v4l); return -1; } } fszenum.index = v4l2src->capture_mode; fszenum.pixel_format = V4L2_PIX_FMT_YUV420; if (ioctl(fd_v4l, VIDIOC_ENUM_FRAMESIZES, &fszenum) < 0) { GST_ERROR_OBJECT(v4l2src, "VIDIOC_ENUM_FRAMESIZES failed: %s", strerror(errno)); close(fd_v4l); return -1; } v4l2src->capture_width = fszenum.discrete.width; v4l2src->capture_height = fszenum.discrete.height; GST_INFO_OBJECT(v4l2src, "capture mode %d: %dx%d", v4l2src->capture_mode, v4l2src->capture_width, v4l2src->capture_height); input = v4l2src->input; if (ioctl(fd_v4l, VIDIOC_S_INPUT, &input) < 0) { GST_ERROR_OBJECT(v4l2src, "VIDIOC_S_INPUT failed: %s", strerror(errno)); close(fd_v4l); return -1; } parm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; parm.parm.capture.timeperframe.numerator = v4l2src->fps_d; parm.parm.capture.timeperframe.denominator = v4l2src->fps_n; parm.parm.capture.capturemode = v4l2src->capture_mode; if (ioctl(fd_v4l, VIDIOC_S_PARM, &parm) < 0) { GST_ERROR_OBJECT(v4l2src, "VIDIOC_S_PARM failed: %s", strerror(errno)); close(fd_v4l); return -1; } fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUV420; fmt.fmt.pix.bytesperline = 0; fmt.fmt.pix.priv = 0; fmt.fmt.pix.sizeimage = 0; if (ioctl(fd_v4l, VIDIOC_S_FMT, &fmt) < 0) { GST_ERROR_OBJECT(v4l2src, "VIDIOC_S_FMT failed: %s", strerror(errno)); close(fd_v4l); return -1; } return fd_v4l; }
/* FIXME: for our purposes it's probably enough to just check for the sync * marker - we just want to know if it's a header frame or not */ static gboolean gst_flac_dec_scan_got_frame (GstFlacDec * flacdec, guint8 * data, guint size, gint64 * last_sample_num) { guint headerlen; guint sr_from_end = 0; /* can be 0, 8 or 16 */ guint bs_from_end = 0; /* can be 0, 8 or 16 */ guint32 val = 0; guint8 bs, sr, ca, ss, pb; if (size < 10) return FALSE; /* sync */ if (data[0] != 0xFF || (data[1] & 0xFC) != 0xF8) return FALSE; if (data[1] & 1) { GST_WARNING_OBJECT (flacdec, "Variable block size FLAC unsupported"); return FALSE; } bs = (data[2] & 0xF0) >> 4; /* blocksize marker */ sr = (data[2] & 0x0F); /* samplerate marker */ ca = (data[3] & 0xF0) >> 4; /* channel assignment */ ss = (data[3] & 0x0F) >> 1; /* sample size marker */ pb = (data[3] & 0x01); /* padding bit */ GST_LOG_OBJECT (flacdec, "got sync, bs=%x,sr=%x,ca=%x,ss=%x,pb=%x", bs, sr, ca, ss, pb); if (bs == 0 || sr == 0x0F || ca >= 0x0B || ss == 0x03 || ss == 0x07) { return FALSE; } /* read block size from end of header? */ if (bs == 6) bs_from_end = 8; else if (bs == 7) bs_from_end = 16; /* read sample rate from end of header? */ if (sr == 0x0C) sr_from_end = 8; else if (sr == 0x0D || sr == 0x0E) sr_from_end = 16; val = data[4]; /* This is slightly faster than a loop */ if (!(val & 0x80)) { val = 0; } else if ((val & 0xc0) && !(val & 0x20)) { val = 1; } else if ((val & 0xe0) && !(val & 0x10)) { val = 2; } else if ((val & 0xf0) && !(val & 0x08)) { val = 3; } else if ((val & 0xf8) && !(val & 0x04)) { val = 4; } else if ((val & 0xfc) && !(val & 0x02)) { val = 5; } else if ((val & 0xfe) && !(val & 0x01)) { val = 6; } else { GST_LOG_OBJECT (flacdec, "failed to read sample/frame"); return FALSE; } val++; headerlen = 4 + val + (bs_from_end / 8) + (sr_from_end / 8); if (gst_flac_calculate_crc8 (data, headerlen) != data[headerlen]) { GST_LOG_OBJECT (flacdec, "invalid checksum"); return FALSE; } if (!last_sample_num) return TRUE; /* FIXME: This is can be 36 bit if variable block size is used, * fortunately not encoder supports this yet and we check for that * above. */ val = (guint32) g_utf8_get_char_validated ((gchar *) data + 4, -1); if (val == (guint32) - 1 || val == (guint32) - 2) { GST_LOG_OBJECT (flacdec, "failed to read sample/frame"); return FALSE; } if (flacdec->min_blocksize == flacdec->max_blocksize) { *last_sample_num = (val + 1) * flacdec->min_blocksize; } else { *last_sample_num = 0; /* FIXME: + length of last block in samples */ } /* FIXME: only valid for fixed block size streams */ GST_DEBUG_OBJECT (flacdec, "frame number: %" G_GINT64_FORMAT, *last_sample_num); if (flacdec->info.rate > 0 && *last_sample_num != 0) { GST_DEBUG_OBJECT (flacdec, "last sample %" G_GINT64_FORMAT " = %" GST_TIME_FORMAT, *last_sample_num, GST_TIME_ARGS (*last_sample_num * GST_SECOND / flacdec->info.rate)); } return TRUE; }
gboolean gst_riff_parse_strf_vids (GstElement * element, GstBuffer * buf, gst_riff_strf_vids ** _strf, GstBuffer ** data) { gst_riff_strf_vids *strf; g_return_val_if_fail (buf != NULL, FALSE); g_return_val_if_fail (_strf != NULL, FALSE); g_return_val_if_fail (data != NULL, FALSE); if (GST_BUFFER_SIZE (buf) < sizeof (gst_riff_strf_vids)) goto too_small; strf = g_memdup (GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf)); #if (G_BYTE_ORDER == G_BIG_ENDIAN) strf->size = GUINT32_FROM_LE (strf->size); strf->width = GUINT32_FROM_LE (strf->width); strf->height = GUINT32_FROM_LE (strf->height); strf->planes = GUINT16_FROM_LE (strf->planes); strf->bit_cnt = GUINT16_FROM_LE (strf->bit_cnt); strf->compression = GUINT32_FROM_LE (strf->compression); strf->image_size = GUINT32_FROM_LE (strf->image_size); strf->xpels_meter = GUINT32_FROM_LE (strf->xpels_meter); strf->ypels_meter = GUINT32_FROM_LE (strf->ypels_meter); strf->num_colors = GUINT32_FROM_LE (strf->num_colors); strf->imp_colors = GUINT32_FROM_LE (strf->imp_colors); #endif /* size checking */ *data = NULL; if (strf->size > GST_BUFFER_SIZE (buf)) { GST_WARNING_OBJECT (element, "strf_vids header gave %d bytes data, only %d available", strf->size, GST_BUFFER_SIZE (buf)); strf->size = GST_BUFFER_SIZE (buf); } if (sizeof (gst_riff_strf_vids) < GST_BUFFER_SIZE (buf)) { *data = gst_buffer_create_sub (buf, sizeof (gst_riff_strf_vids), GST_BUFFER_SIZE (buf) - sizeof (gst_riff_strf_vids)); } /* debug */ GST_INFO_OBJECT (element, "strf tag found in context vids:"); GST_INFO_OBJECT (element, " size %d", strf->size); GST_INFO_OBJECT (element, " width %d", strf->width); GST_INFO_OBJECT (element, " height %d", strf->height); GST_INFO_OBJECT (element, " planes %d", strf->planes); GST_INFO_OBJECT (element, " bit_cnt %d", strf->bit_cnt); GST_INFO_OBJECT (element, " compression %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (strf->compression)); GST_INFO_OBJECT (element, " image_size %d", strf->image_size); GST_INFO_OBJECT (element, " xpels_meter %d", strf->xpels_meter); GST_INFO_OBJECT (element, " ypels_meter %d", strf->ypels_meter); GST_INFO_OBJECT (element, " num_colors %d", strf->num_colors); GST_INFO_OBJECT (element, " imp_colors %d", strf->imp_colors); if (*data) GST_INFO_OBJECT (element, " %d bytes extradata", GST_BUFFER_SIZE (*data)); gst_buffer_unref (buf); *_strf = strf; return TRUE; /* ERRORS */ too_small: { GST_ERROR_OBJECT (element, "Too small strf_vids (%d available, %d needed)", GST_BUFFER_SIZE (buf), (int) sizeof (gst_riff_strf_vids)); gst_buffer_unref (buf); return FALSE; } }
static GstCaps * gst_wrapper_camera_bin_src_get_allowed_input_caps (GstBaseCameraBinSrc * bcamsrc) { GstWrapperCameraBinSrc *self = GST_WRAPPER_CAMERA_BIN_SRC (bcamsrc); GstCaps *caps = NULL; GstPad *pad = NULL, *peer_pad = NULL; GstState state; GstElement *videosrc; videosrc = self->src_vid_src ? self->src_vid_src : self->app_vid_src; if (!videosrc) { GST_WARNING_OBJECT (self, "no videosrc, can't get allowed caps"); goto failed; } if (self->allowed_caps) { GST_DEBUG_OBJECT (self, "returning cached caps"); goto done; } pad = gst_element_get_static_pad (videosrc, "src"); if (!pad) { GST_WARNING_OBJECT (self, "no srcpad in videosrc"); goto failed; } state = GST_STATE (videosrc); /* Make this function work also in NULL state */ if (state == GST_STATE_NULL) { GST_DEBUG_OBJECT (self, "setting videosrc to ready temporarily"); peer_pad = gst_pad_get_peer (pad); if (peer_pad) { gst_pad_unlink (pad, peer_pad); } /* Set videosrc to READY to open video device */ gst_element_set_locked_state (videosrc, TRUE); gst_element_set_state (videosrc, GST_STATE_READY); } self->allowed_caps = gst_pad_get_caps (pad); /* Restore state and re-link if necessary */ if (state == GST_STATE_NULL) { GST_DEBUG_OBJECT (self, "restoring videosrc state %d", state); /* Reset videosrc to NULL state, some drivers seem to need this */ gst_element_set_state (videosrc, GST_STATE_NULL); if (peer_pad) { gst_pad_link (pad, peer_pad); gst_object_unref (peer_pad); } gst_element_set_locked_state (videosrc, FALSE); } gst_object_unref (pad); done: if (self->allowed_caps) { caps = gst_caps_copy (self->allowed_caps); } GST_DEBUG_OBJECT (self, "allowed caps:%" GST_PTR_FORMAT, caps); failed: return caps; }
/** * gst_riff_parse_strf_auds: * @element: caller element (used for debugging/error). * @buf: input data to be used for parsing, stripped from header. * @strf: a pointer (returned by this function) to a filled-in * strf/auds structure. Caller should free it. * @data: a pointer (returned by this function) to a buffer * containing extradata for this particular stream (e.g. * codec initialization data). * * Parses an audio stream´s strf structure plus optionally some * extradata from input data. This function takes ownership of @buf. * use. * * Returns: TRUE if parsing succeeded, otherwise FALSE. The stream * should be skipped on error, but it is not fatal. */ gboolean gst_riff_parse_strf_auds (GstElement * element, GstBuffer * buf, gst_riff_strf_auds ** _strf, GstBuffer ** data) { gst_riff_strf_auds *strf; guint bufsize; g_return_val_if_fail (buf != NULL, FALSE); g_return_val_if_fail (_strf != NULL, FALSE); g_return_val_if_fail (data != NULL, FALSE); bufsize = GST_BUFFER_SIZE (buf); if (bufsize < sizeof (gst_riff_strf_auds)) goto too_small; strf = g_memdup (GST_BUFFER_DATA (buf), bufsize); #if (G_BYTE_ORDER == G_BIG_ENDIAN) strf->format = GUINT16_FROM_LE (strf->format); strf->channels = GUINT16_FROM_LE (strf->channels); strf->rate = GUINT32_FROM_LE (strf->rate); strf->av_bps = GUINT32_FROM_LE (strf->av_bps); strf->blockalign = GUINT16_FROM_LE (strf->blockalign); strf->size = GUINT16_FROM_LE (strf->size); #endif /* size checking */ *data = NULL; if (bufsize > sizeof (gst_riff_strf_auds) + 2) { gint len; len = GST_READ_UINT16_LE (&GST_BUFFER_DATA (buf)[16]); if (len + 2 + sizeof (gst_riff_strf_auds) > bufsize) { GST_WARNING_OBJECT (element, "Extradata indicated %d bytes, but only %" G_GSSIZE_FORMAT " available", len, bufsize - 2 - sizeof (gst_riff_strf_auds)); len = bufsize - 2 - sizeof (gst_riff_strf_auds); } if (len) *data = gst_buffer_create_sub (buf, sizeof (gst_riff_strf_auds) + 2, len); } /* debug */ GST_INFO_OBJECT (element, "strf tag found in context auds:"); GST_INFO_OBJECT (element, " format %d", strf->format); GST_INFO_OBJECT (element, " channels %d", strf->channels); GST_INFO_OBJECT (element, " rate %d", strf->rate); GST_INFO_OBJECT (element, " av_bps %d", strf->av_bps); GST_INFO_OBJECT (element, " blockalign %d", strf->blockalign); GST_INFO_OBJECT (element, " size %d", strf->size); if (*data) GST_INFO_OBJECT (element, " %d bytes extradata", GST_BUFFER_SIZE (*data)); gst_buffer_unref (buf); *_strf = strf; return TRUE; /* ERROR */ too_small: { GST_ERROR_OBJECT (element, "Too small strf_auds (%d available, %" G_GSSIZE_FORMAT " needed)", bufsize, sizeof (gst_riff_strf_auds)); gst_buffer_unref (buf); return FALSE; } }
static void gst_curl_base_sink_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec) { GstCurlBaseSink *sink; GstState cur_state; g_return_if_fail (GST_IS_CURL_BASE_SINK (object)); sink = GST_CURL_BASE_SINK (object); gst_element_get_state (GST_ELEMENT (sink), &cur_state, NULL, 0); if (cur_state != GST_STATE_PLAYING && cur_state != GST_STATE_PAUSED) { GST_OBJECT_LOCK (sink); switch (prop_id) { case PROP_LOCATION: g_free (sink->url); sink->url = g_value_dup_string (value); GST_DEBUG_OBJECT (sink, "url set to %s", sink->url); break; case PROP_USER_NAME: g_free (sink->user); sink->user = g_value_dup_string (value); GST_DEBUG_OBJECT (sink, "user set to %s", sink->user); break; case PROP_USER_PASSWD: g_free (sink->passwd); sink->passwd = g_value_dup_string (value); GST_DEBUG_OBJECT (sink, "passwd set to %s", sink->passwd); break; case PROP_FILE_NAME: g_free (sink->file_name); sink->file_name = g_value_dup_string (value); GST_DEBUG_OBJECT (sink, "file_name set to %s", sink->file_name); break; case PROP_TIMEOUT: sink->timeout = g_value_get_int (value); GST_DEBUG_OBJECT (sink, "timeout set to %d", sink->timeout); break; case PROP_QOS_DSCP: sink->qos_dscp = g_value_get_int (value); gst_curl_base_sink_setup_dscp_unlocked (sink); GST_DEBUG_OBJECT (sink, "dscp set to %d", sink->qos_dscp); break; default: GST_DEBUG_OBJECT (sink, "invalid property id %d", prop_id); break; } GST_OBJECT_UNLOCK (sink); return; } /* in PLAYING or PAUSED state */ GST_OBJECT_LOCK (sink); switch (prop_id) { case PROP_FILE_NAME: g_free (sink->file_name); sink->file_name = g_value_dup_string (value); GST_DEBUG_OBJECT (sink, "file_name set to %s", sink->file_name); gst_curl_base_sink_new_file_notify_unlocked (sink); break; case PROP_TIMEOUT: sink->timeout = g_value_get_int (value); GST_DEBUG_OBJECT (sink, "timeout set to %d", sink->timeout); break; case PROP_QOS_DSCP: sink->qos_dscp = g_value_get_int (value); gst_curl_base_sink_setup_dscp_unlocked (sink); GST_DEBUG_OBJECT (sink, "dscp set to %d", sink->qos_dscp); break; default: GST_WARNING_OBJECT (sink, "cannot set property when PLAYING"); break; } GST_OBJECT_UNLOCK (sink); }
/** * gst_riff_parse_info: * @element: caller element (used for debugging/error). * @buf: input data to be used for parsing, stripped from header. * @taglist: a pointer to a taglist (returned by this function) * containing information about this stream. May be * NULL if no supported tags were found. * * Parses stream metadata from input data. */ void gst_riff_parse_info (GstElement * element, GstBuffer * buf, GstTagList ** _taglist) { guint8 *data; guint size, tsize; guint32 tag; const gchar *type; GstTagList *taglist; g_return_if_fail (_taglist != NULL); if (!buf) { *_taglist = NULL; return; } data = GST_BUFFER_DATA (buf); size = GST_BUFFER_SIZE (buf); taglist = gst_tag_list_new (); while (size > 8) { tag = GST_READ_UINT32_LE (data); tsize = GST_READ_UINT32_LE (data + 4); GST_MEMDUMP_OBJECT (element, "tag chunk", data, MIN (tsize + 8, size)); size -= 8; data += 8; GST_DEBUG ("tag %" GST_FOURCC_FORMAT ", size %u", GST_FOURCC_ARGS (tag), tsize); if (tsize > size) { GST_WARNING_OBJECT (element, "Tagsize %d is larger than available data %d", tsize, size); tsize = size; } /* make uppercase */ tag = tag & 0xDFDFDFDF; /* find out the type of metadata */ switch (tag) { case GST_RIFF_INFO_IARL: type = GST_TAG_LOCATION; break; case GST_RIFF_INFO_IAAR: type = GST_TAG_ALBUM_ARTIST; break; case GST_RIFF_INFO_IART: type = GST_TAG_ARTIST; break; case GST_RIFF_INFO_ICMS: type = NULL; /*"Commissioner"; */ break; case GST_RIFF_INFO_ICMT: type = GST_TAG_COMMENT; break; case GST_RIFF_INFO_ICOP: type = GST_TAG_COPYRIGHT; break; case GST_RIFF_INFO_ICRD: type = GST_TAG_DATE; break; case GST_RIFF_INFO_ICRP: type = NULL; /*"Cropped"; */ break; case GST_RIFF_INFO_IDIM: type = NULL; /*"Dimensions"; */ break; case GST_RIFF_INFO_IDPI: type = NULL; /*"Dots per Inch"; */ break; case GST_RIFF_INFO_IENG: type = NULL; /*"Engineer"; */ break; case GST_RIFF_INFO_IGNR: type = GST_TAG_GENRE; break; case GST_RIFF_INFO_IKEY: type = GST_TAG_KEYWORDS; break; case GST_RIFF_INFO_ILGT: type = NULL; /*"Lightness"; */ break; case GST_RIFF_INFO_IMED: type = NULL; /*"Medium"; */ break; case GST_RIFF_INFO_INAM: type = GST_TAG_TITLE; break; case GST_RIFF_INFO_IPLT: type = NULL; /*"Palette"; */ break; case GST_RIFF_INFO_IPRD: type = GST_TAG_ALBUM; break; case GST_RIFF_INFO_ISBJ: type = GST_TAG_ALBUM_ARTIST; break; case GST_RIFF_INFO_ISFT: type = GST_TAG_ENCODER; break; case GST_RIFF_INFO_ISHP: type = NULL; /*"Sharpness"; */ break; case GST_RIFF_INFO_ISRC: type = GST_TAG_ISRC; break; case GST_RIFF_INFO_ISRF: type = NULL; /*"Source Form"; */ break; case GST_RIFF_INFO_ITCH: type = NULL; /*"Technician"; */ break; case GST_RIFF_INFO_ITRK: type = GST_TAG_TRACK_NUMBER; break; default: type = NULL; GST_WARNING_OBJECT (element, "Unknown INFO (metadata) tag entry %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (tag)); break; } if (type != NULL && data[0] != '\0') { static const gchar *env_vars[] = { "GST_AVI_TAG_ENCODING", "GST_RIFF_TAG_ENCODING", "GST_TAG_ENCODING", NULL }; GType tag_type; gchar *val; GST_DEBUG_OBJECT (element, "mapped tag %" GST_FOURCC_FORMAT " to tag %s", GST_FOURCC_ARGS (tag), type); tag_type = gst_tag_get_type (type); val = gst_tag_freeform_string_to_utf8 ((gchar *) data, tsize, env_vars); if (val != NULL) { if (tag_type == G_TYPE_STRING) { gst_tag_list_add (taglist, GST_TAG_MERGE_APPEND, type, val, NULL); } else { GValue tag_val = { 0, }; g_value_init (&tag_val, tag_type); if (gst_value_deserialize (&tag_val, val)) { gst_tag_list_add_value (taglist, GST_TAG_MERGE_APPEND, type, &tag_val); } else { GST_WARNING_OBJECT (element, "could not deserialize '%s' into a " "tag %s of type %s", val, type, g_type_name (tag_type)); } g_value_unset (&tag_val); } g_free (val); } else { GST_WARNING_OBJECT (element, "could not extract %s tag", type); } } if (tsize & 1) { tsize++; if (tsize > size) tsize = size; } data += tsize; size -= tsize; } if (!gst_tag_list_is_empty (taglist)) { GST_INFO_OBJECT (element, "extracted tags: %" GST_PTR_FORMAT, taglist); *_taglist = taglist; } else { *_taglist = NULL; gst_tag_list_free (taglist); } return; }
static GstFlowReturn gst_mpg123_audio_dec_handle_frame (GstAudioDecoder * dec, GstBuffer * input_buffer) { GstMpg123AudioDec *mpg123_decoder; int decode_error; unsigned char *decoded_bytes; size_t num_decoded_bytes; GstFlowReturn retval; mpg123_decoder = GST_MPG123_AUDIO_DEC (dec); g_assert (mpg123_decoder->handle != NULL); /* The actual decoding */ { /* feed input data (if there is any) */ if (G_LIKELY (input_buffer != NULL)) { GstMapInfo info; if (gst_buffer_map (input_buffer, &info, GST_MAP_READ)) { mpg123_feed (mpg123_decoder->handle, info.data, info.size); gst_buffer_unmap (input_buffer, &info); } else { GST_ERROR_OBJECT (mpg123_decoder, "gst_memory_map() failed"); return GST_FLOW_ERROR; } } /* Try to decode a frame */ decoded_bytes = NULL; num_decoded_bytes = 0; decode_error = mpg123_decode_frame (mpg123_decoder->handle, &mpg123_decoder->frame_offset, &decoded_bytes, &num_decoded_bytes); } retval = GST_FLOW_OK; switch (decode_error) { case MPG123_NEW_FORMAT: /* As mentioned in gst_mpg123_audio_dec_set_format(), the next audioinfo * is not set immediately; instead, the code waits for mpg123 to take * note of the new format, and then sets the audioinfo. This fixes glitches * with mp3s containing several format headers (for example, first half * using 44.1kHz, second half 32 kHz) */ GST_LOG_OBJECT (dec, "mpg123 reported a new format -> setting next srccaps"); gst_mpg123_audio_dec_push_decoded_bytes (mpg123_decoder, decoded_bytes, num_decoded_bytes); /* If there is a next audioinfo, use it, then set has_next_audioinfo to * FALSE, to make sure gst_audio_decoder_set_output_format() isn't called * again until set_format is called by the base class */ if (mpg123_decoder->has_next_audioinfo) { if (!gst_audio_decoder_set_output_format (dec, &(mpg123_decoder->next_audioinfo))) { GST_WARNING_OBJECT (dec, "Unable to set output format"); retval = GST_FLOW_NOT_NEGOTIATED; } mpg123_decoder->has_next_audioinfo = FALSE; } break; case MPG123_NEED_MORE: case MPG123_OK: retval = gst_mpg123_audio_dec_push_decoded_bytes (mpg123_decoder, decoded_bytes, num_decoded_bytes); break; case MPG123_DONE: /* If this happens, then the upstream parser somehow missed the ending * of the bitstream */ GST_LOG_OBJECT (dec, "mpg123 is done decoding"); gst_mpg123_audio_dec_push_decoded_bytes (mpg123_decoder, decoded_bytes, num_decoded_bytes); retval = GST_FLOW_EOS; break; default: { /* Anything else is considered an error */ int errcode; switch (decode_error) { case MPG123_ERR: errcode = mpg123_errcode (mpg123_decoder->handle); break; default: errcode = decode_error; } switch (errcode) { case MPG123_BAD_OUTFORMAT:{ GstCaps *input_caps = gst_pad_get_current_caps (GST_AUDIO_DECODER_SINK_PAD (dec)); GST_ELEMENT_ERROR (dec, STREAM, FORMAT, (NULL), ("Output sample format could not be used when trying to decode frame. " "This is typically caused when the input caps (often the sample " "rate) do not match the actual format of the audio data. " "Input caps: %" GST_PTR_FORMAT, input_caps) ); gst_caps_unref (input_caps); break; } default:{ char const *errmsg = mpg123_plain_strerror (errcode); GST_ERROR_OBJECT (dec, "Reported error: %s", errmsg); } } retval = GST_FLOW_ERROR; } } return retval; }
static void gst_compare_meta (GstCompare * comp, GstBuffer * buf1, GstCaps * caps1, GstBuffer * buf2, GstCaps * caps2) { gint flags = 0; if (comp->meta & GST_BUFFER_COPY_FLAGS) { if (GST_BUFFER_FLAGS (buf1) != GST_BUFFER_FLAGS (buf2)) { flags |= GST_BUFFER_COPY_FLAGS; GST_DEBUG_OBJECT (comp, "flags %d != flags %d", GST_BUFFER_FLAGS (buf1), GST_BUFFER_FLAGS (buf2)); } } if (comp->meta & GST_BUFFER_COPY_TIMESTAMPS) { if (GST_BUFFER_TIMESTAMP (buf1) != GST_BUFFER_TIMESTAMP (buf2)) { flags |= GST_BUFFER_COPY_TIMESTAMPS; GST_DEBUG_OBJECT (comp, "ts %" GST_TIME_FORMAT " != ts %" GST_TIME_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf1)), GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf2))); } if (GST_BUFFER_DURATION (buf1) != GST_BUFFER_DURATION (buf2)) { flags |= GST_BUFFER_COPY_TIMESTAMPS; GST_DEBUG_OBJECT (comp, "dur %" GST_TIME_FORMAT " != dur %" GST_TIME_FORMAT, GST_TIME_ARGS (GST_BUFFER_DURATION (buf1)), GST_TIME_ARGS (GST_BUFFER_DURATION (buf2))); } if (comp->offset_ts) { if (GST_BUFFER_OFFSET (buf1) != GST_BUFFER_OFFSET (buf2)) { flags |= GST_BUFFER_COPY_TIMESTAMPS; GST_DEBUG_OBJECT (comp, "offset %" G_GINT64_FORMAT " != offset %" G_GINT64_FORMAT, GST_BUFFER_OFFSET (buf1), GST_BUFFER_OFFSET (buf2)); } if (GST_BUFFER_OFFSET_END (buf1) != GST_BUFFER_OFFSET_END (buf2)) { flags |= GST_BUFFER_COPY_TIMESTAMPS; GST_DEBUG_OBJECT (comp, "offset_end %" G_GINT64_FORMAT " != offset_end %" G_GINT64_FORMAT, GST_BUFFER_OFFSET_END (buf1), GST_BUFFER_OFFSET_END (buf2)); } } } #if 0 /* FIXME ?? */ if (comp->meta & GST_BUFFER_COPY_CAPS) { if (!gst_caps_is_equal (caps1, caps2)) { flags |= GST_BUFFER_COPY_CAPS; GST_DEBUG_OBJECT (comp, "caps %" GST_PTR_FORMAT " != caps %" GST_PTR_FORMAT, caps1, caps2); } } #endif /* signal mismatch by debug and message */ if (flags) { GST_WARNING_OBJECT (comp, "buffers %p and %p failed metadata match %d", buf1, buf2, flags); gst_element_post_message (GST_ELEMENT (comp), gst_message_new_element (GST_OBJECT (comp), gst_structure_new ("delta", "meta", G_TYPE_INT, flags, NULL))); } }
static GstFlowReturn gst_timestampoverlay_transform_frame_ip (GstVideoFilter * filter, GstVideoFrame * frame) { GstTimeStampOverlay *overlay = GST_TIMESTAMPOVERLAY (filter); GST_DEBUG_OBJECT (overlay, "transform_frame_ip"); GstClockTime buffer_time, stream_time, running_time, clock_time, latency, render_time, render_realtime; GstSegment *segment = &GST_BASE_TRANSFORM (overlay)->segment; unsigned char * imgdata; buffer_time = GST_BUFFER_TIMESTAMP (frame->buffer); if (!GST_CLOCK_TIME_IS_VALID (buffer_time)) { GST_DEBUG_OBJECT (filter, "Can't draw timestamps: buffer timestamp is " "invalid"); return GST_FLOW_OK; } if (frame->info.stride[0] < (8 * frame->info.finfo->pixel_stride[0] * 64)) { GST_WARNING_OBJECT (filter, "Can't draw timestamps: video-frame is to narrow"); return GST_FLOW_OK; } GST_DEBUG ("buffer with timestamp %" GST_TIME_FORMAT, GST_TIME_ARGS (buffer_time)); stream_time = gst_segment_to_stream_time (segment, GST_FORMAT_TIME, buffer_time); running_time = gst_segment_to_running_time (segment, GST_FORMAT_TIME, buffer_time); clock_time = running_time + gst_element_get_base_time (GST_ELEMENT (overlay)); latency = overlay->latency; if (GST_CLOCK_TIME_IS_VALID (latency)) render_time = clock_time + latency; else render_time = clock_time; GST_OBJECT_LOCK (overlay->realtime_clock); render_realtime = gst_clock_unadjust_unlocked ( overlay->realtime_clock, render_time); GST_OBJECT_UNLOCK (overlay->realtime_clock); imgdata = frame->data[0]; /* Centre Vertically: */ imgdata += (frame->info.height - 6 * 8) * frame->info.stride[0] / 2; /* Centre Horizontally: */ imgdata += (frame->info.width - 64 * 8) * frame->info.finfo->pixel_stride[0] / 2; draw_timestamp (0, buffer_time, imgdata, frame->info.stride[0], frame->info.finfo->pixel_stride[0]); draw_timestamp (1, stream_time, imgdata, frame->info.stride[0], frame->info.finfo->pixel_stride[0]); draw_timestamp (2, running_time, imgdata, frame->info.stride[0], frame->info.finfo->pixel_stride[0]); draw_timestamp (3, clock_time, imgdata, frame->info.stride[0], frame->info.finfo->pixel_stride[0]); draw_timestamp (4, render_time, imgdata, frame->info.stride[0], frame->info.finfo->pixel_stride[0]); draw_timestamp (5, render_realtime, imgdata, frame->info.stride[0], frame->info.finfo->pixel_stride[0]); return GST_FLOW_OK; }
static gboolean gst_wavenc_sink_setcaps (GstPad * pad, GstCaps * caps) { GstWavEnc *wavenc; GstStructure *structure; const gchar *name; gint chans, rate; GstCaps *ccaps; wavenc = GST_WAVENC (gst_pad_get_parent (pad)); ccaps = gst_pad_get_current_caps (pad); if (wavenc->sent_header && ccaps && !gst_caps_can_intersect (caps, ccaps)) { gst_caps_unref (ccaps); GST_WARNING_OBJECT (wavenc, "cannot change format in middle of stream"); goto fail; } if (ccaps) gst_caps_unref (ccaps); GST_DEBUG_OBJECT (wavenc, "got caps: %" GST_PTR_FORMAT, caps); structure = gst_caps_get_structure (caps, 0); name = gst_structure_get_name (structure); if (!gst_structure_get_int (structure, "channels", &chans) || !gst_structure_get_int (structure, "rate", &rate)) { GST_WARNING_OBJECT (wavenc, "caps incomplete"); goto fail; } if (strcmp (name, "audio/x-raw") == 0) { GstAudioInfo info; if (!gst_audio_info_from_caps (&info, caps)) goto fail; if (GST_AUDIO_INFO_IS_INTEGER (&info)) wavenc->format = GST_RIFF_WAVE_FORMAT_PCM; else if (GST_AUDIO_INFO_IS_FLOAT (&info)) wavenc->format = GST_RIFF_WAVE_FORMAT_IEEE_FLOAT; else goto fail; wavenc->width = GST_AUDIO_INFO_WIDTH (&info); } else if (strcmp (name, "audio/x-alaw") == 0) { wavenc->format = GST_RIFF_WAVE_FORMAT_ALAW; wavenc->width = 8; } else if (strcmp (name, "audio/x-mulaw") == 0) { wavenc->format = GST_RIFF_WAVE_FORMAT_MULAW; wavenc->width = 8; } else { GST_WARNING_OBJECT (wavenc, "Unsupported format %s", name); goto fail; } wavenc->channels = chans; wavenc->rate = rate; GST_LOG_OBJECT (wavenc, "accepted caps: format=0x%04x chans=%u width=%u rate=%u", wavenc->format, wavenc->channels, wavenc->width, wavenc->rate); gst_object_unref (wavenc); return TRUE; fail: gst_object_unref (wavenc); return FALSE; }