static GstFlowReturn gst_y4m_encode_handle_frame (GstVideoEncoder * encoder, GstVideoCodecFrame * frame) { GstY4mEncode *filter = GST_Y4M_ENCODE (encoder); GstClockTime timestamp; /* check we got some decent info from caps */ if (GST_VIDEO_INFO_FORMAT (&filter->info) == GST_VIDEO_FORMAT_UNKNOWN) goto not_negotiated; timestamp = GST_BUFFER_TIMESTAMP (frame->input_buffer); if (G_UNLIKELY (!filter->header)) { gboolean tff = FALSE; if (GST_VIDEO_INFO_IS_INTERLACED (&filter->info)) { tff = GST_BUFFER_FLAG_IS_SET (frame->input_buffer, GST_VIDEO_BUFFER_FLAG_TFF); } frame->output_buffer = gst_y4m_encode_get_stream_header (filter, tff); filter->header = TRUE; frame->output_buffer = gst_buffer_append (frame->output_buffer, gst_y4m_encode_get_frame_header (filter)); } else { frame->output_buffer = gst_y4m_encode_get_frame_header (filter); } frame->output_buffer = gst_buffer_append (frame->output_buffer, gst_buffer_copy (frame->input_buffer)); /* decorate */ frame->output_buffer = gst_buffer_make_writable (frame->output_buffer); GST_BUFFER_TIMESTAMP (frame->output_buffer) = timestamp; return gst_video_encoder_finish_frame (encoder, frame); not_negotiated: { GST_ELEMENT_ERROR (filter, CORE, NEGOTIATION, (NULL), ("format wasn't negotiated")); return GST_FLOW_NOT_NEGOTIATED; } }
static void dxr3videosink_chain (GstPad * pad, GstData * _data) { GstBuffer *buf = GST_BUFFER (_data); Dxr3VideoSink *sink; g_return_if_fail (pad != NULL); g_return_if_fail (GST_IS_PAD (pad)); g_return_if_fail (buf != NULL); sink = DXR3VIDEOSINK (gst_pad_get_parent (pad)); if (GST_IS_EVENT (buf)) { dxr3videosink_handle_event (pad, GST_EVENT (buf)); return; } /* fprintf (stderr, "^^^^^^ Video block\n"); */ if (sink->cur_buf == NULL) { sink->cur_buf = buf; } else { sink->cur_buf = gst_buffer_append (sink->cur_buf, buf); } sink->last_ts = GST_BUFFER_TIMESTAMP (buf); dxr3videosink_parse_data (sink); }
static gint gst_ffmpegauddec_frame (GstFFMpegAudDec * ffmpegdec, guint8 * data, guint size, gint * got_data, GstFlowReturn * ret) { GstFFMpegAudDecClass *oclass; GstBuffer *outbuf = NULL; gint have_data = 0, len = 0; if (G_UNLIKELY (ffmpegdec->context->codec == NULL)) goto no_codec; GST_LOG_OBJECT (ffmpegdec, "data:%p, size:%d", data, size); *ret = GST_FLOW_OK; ffmpegdec->context->frame_number++; oclass = (GstFFMpegAudDecClass *) (G_OBJECT_GET_CLASS (ffmpegdec)); len = gst_ffmpegauddec_audio_frame (ffmpegdec, oclass->in_plugin, data, size, &outbuf, ret); if (outbuf) have_data = 1; if (len < 0 || have_data < 0) { GST_WARNING_OBJECT (ffmpegdec, "avdec_%s: decoding error (len: %d, have_data: %d)", oclass->in_plugin->name, len, have_data); *got_data = 0; goto beach; } else if (len == 0 && have_data == 0) { *got_data = 0; goto beach; } else { /* this is where I lost my last clue on ffmpeg... */ *got_data = 1; } if (outbuf) { GST_LOG_OBJECT (ffmpegdec, "Decoded data, now storing buffer %p", outbuf); if (ffmpegdec->outbuf) ffmpegdec->outbuf = gst_buffer_append (ffmpegdec->outbuf, outbuf); else ffmpegdec->outbuf = outbuf; } else { GST_DEBUG_OBJECT (ffmpegdec, "We didn't get a decoded buffer"); } beach: return len; /* ERRORS */ no_codec: { GST_ERROR_OBJECT (ffmpegdec, "no codec context"); return -1; } }
static GstFlowReturn gst_rtp_opus_pay_handle_buffer (GstRTPBasePayload * basepayload, GstBuffer * buffer) { GstBuffer *outbuf; GstClockTime pts, dts, duration; CopyMetaData data; pts = GST_BUFFER_PTS (buffer); dts = GST_BUFFER_DTS (buffer); duration = GST_BUFFER_DURATION (buffer); outbuf = gst_rtp_buffer_new_allocate (0, 0, 0); data.pay = GST_RTP_OPUS_PAY (basepayload); data.outbuf = outbuf; gst_buffer_foreach_meta (buffer, foreach_metadata, &data); outbuf = gst_buffer_append (outbuf, buffer); GST_BUFFER_PTS (outbuf) = pts; GST_BUFFER_DTS (outbuf) = dts; GST_BUFFER_DURATION (outbuf) = duration; /* Push out */ return gst_rtp_base_payload_push (basepayload, outbuf); }
/* Handles decrypted buffers only */ static GstFlowReturn gst_hls_demux_handle_buffer (GstAdaptiveDemux * demux, GstAdaptiveDemuxStream * stream, GstBuffer * buffer, gboolean force) { GstHLSDemux *hlsdemux = GST_HLS_DEMUX_CAST (demux); if (G_UNLIKELY (hlsdemux->do_typefind && buffer != NULL)) { GstCaps *caps = NULL; GstMapInfo info; guint buffer_size; GstTypeFindProbability prob = GST_TYPE_FIND_NONE; if (hlsdemux->pending_typefind_buffer) buffer = gst_buffer_append (hlsdemux->pending_typefind_buffer, buffer); hlsdemux->pending_typefind_buffer = NULL; gst_buffer_map (buffer, &info, GST_MAP_READ); buffer_size = info.size; /* Typefind could miss if buffer is too small. In this case we * will retry later */ if (buffer_size >= (2 * 1024)) { caps = gst_type_find_helper_for_data (GST_OBJECT_CAST (hlsdemux), info.data, info.size, &prob); } gst_buffer_unmap (buffer, &info); if (G_UNLIKELY (!caps)) { /* Only fail typefinding if we already a good amount of data * and we still don't know the type */ if (buffer_size > (2 * 1024 * 1024) || force) { GST_ELEMENT_ERROR (hlsdemux, STREAM, TYPE_NOT_FOUND, ("Could not determine type of stream"), (NULL)); gst_buffer_unref (buffer); return GST_FLOW_NOT_NEGOTIATED; } else { hlsdemux->pending_typefind_buffer = buffer; return GST_FLOW_OK; } } GST_DEBUG_OBJECT (hlsdemux, "Typefind result: %" GST_PTR_FORMAT " prob:%d", caps, prob); gst_adaptive_demux_stream_set_caps (stream, caps); hlsdemux->do_typefind = FALSE; } g_assert (hlsdemux->pending_typefind_buffer == NULL); if (buffer) { buffer = gst_buffer_make_writable (buffer); GST_BUFFER_OFFSET (buffer) = hlsdemux->current_offset; hlsdemux->current_offset += gst_buffer_get_size (buffer); GST_BUFFER_OFFSET_END (buffer) = hlsdemux->current_offset; return gst_adaptive_demux_stream_push_buffer (stream, buffer); } return GST_FLOW_OK; }
static void gst_mikmod_loop (GstElement * element) { GstMikMod *mikmod; GstBuffer *buffer_in; g_return_if_fail (element != NULL); g_return_if_fail (GST_IS_MIKMOD (element)); mikmod = GST_MIKMOD (element); srcpad = mikmod->srcpad; mikmod->Buffer = NULL; if (!mikmod->initialized) { while ((buffer_in = GST_BUFFER (gst_pad_pull (mikmod->sinkpad)))) { if (GST_IS_EVENT (buffer_in)) { GstEvent *event = GST_EVENT (buffer_in); if (GST_EVENT_TYPE (event) == GST_EVENT_EOS) break; } else { if (mikmod->Buffer) { mikmod->Buffer = gst_buffer_append (mikmod->Buffer, buffer_in); } else { mikmod->Buffer = buffer_in; } } } if (!GST_PAD_CAPS (mikmod->srcpad)) { if (GST_PAD_LINK_SUCCESSFUL (gst_pad_renegotiate (mikmod->srcpad))) { GST_ELEMENT_ERROR (mikmod, CORE, NEGOTIATION, (NULL), (NULL)); return; } } MikMod_RegisterDriver (&drv_gst); MikMod_RegisterAllLoaders (); MikMod_Init (""); reader = GST_READER_new (mikmod); module = Player_LoadGeneric (reader, 64, 0); gst_buffer_unref (mikmod->Buffer); if (!Player_Active ()) Player_Start (module); mikmod->initialized = TRUE; } if (Player_Active ()) { timestamp = (module->sngtime / 1024.0) * GST_SECOND; drv_gst.Update (); } else { gst_element_set_eos (GST_ELEMENT (mikmod)); gst_pad_push (mikmod->srcpad, GST_DATA (gst_event_new (GST_EVENT_EOS))); } }
static GstFlowReturn gst_y4m_encode_chain (GstPad * pad, GstObject * parent, GstBuffer * buf) { GstY4mEncode *filter = GST_Y4M_ENCODE (parent); GstBuffer *outbuf; GstClockTime timestamp; /* check we got some decent info from caps */ if (GST_VIDEO_INFO_FORMAT (&filter->info) == GST_VIDEO_FORMAT_UNKNOWN) goto not_negotiated; timestamp = GST_BUFFER_TIMESTAMP (buf); if (G_UNLIKELY (!filter->header)) { gboolean tff; if (GST_VIDEO_INFO_IS_INTERLACED (&filter->info)) { tff = GST_BUFFER_FLAG_IS_SET (buf, GST_VIDEO_BUFFER_FLAG_TFF); } outbuf = gst_y4m_encode_get_stream_header (filter, tff); filter->header = TRUE; outbuf = gst_buffer_append (outbuf, gst_y4m_encode_get_frame_header (filter)); } else { outbuf = gst_y4m_encode_get_frame_header (filter); } /* join with data, FIXME, strides are all wrong etc */ outbuf = gst_buffer_append (outbuf, buf); /* decorate */ outbuf = gst_buffer_make_writable (outbuf); GST_BUFFER_TIMESTAMP (outbuf) = timestamp; return gst_pad_push (filter->srcpad, outbuf); /* ERRORS */ not_negotiated: { GST_ELEMENT_ERROR (filter, CORE, NEGOTIATION, (NULL), ("format wasn't negotiated before chain function")); gst_buffer_unref (buf); return GST_FLOW_NOT_NEGOTIATED; } }
static GstFlowReturn gst_rtp_base_audio_payload_push_buffer (GstRTPBaseAudioPayload * baseaudiopayload, GstBuffer * buffer, GstClockTime timestamp) { GstRTPBasePayload *basepayload; GstRTPBaseAudioPayloadPrivate *priv; GstBuffer *outbuf; guint payload_len; GstFlowReturn ret; priv = baseaudiopayload->priv; basepayload = GST_RTP_BASE_PAYLOAD (baseaudiopayload); payload_len = gst_buffer_get_size (buffer); GST_DEBUG_OBJECT (baseaudiopayload, "Pushing %d bytes ts %" GST_TIME_FORMAT, payload_len, GST_TIME_ARGS (timestamp)); /* create just the RTP header buffer */ outbuf = gst_rtp_base_payload_allocate_output_buffer (basepayload, 0, 0, 0); /* set metadata */ gst_rtp_base_audio_payload_set_meta (baseaudiopayload, outbuf, payload_len, timestamp); if (priv->buffer_list) { GstBufferList *list; guint i, len; list = gst_buffer_list_new (); len = gst_buffer_list_length (list); for (i = 0; i < len; i++) { /* FIXME */ g_warning ("bufferlist not implemented"); gst_buffer_list_add (list, outbuf); gst_buffer_list_add (list, buffer); } GST_DEBUG_OBJECT (baseaudiopayload, "Pushing list %p", list); ret = gst_rtp_base_payload_push_list (basepayload, list); } else { CopyMetaData data; /* copy payload */ data.pay = baseaudiopayload; data.outbuf = outbuf; gst_buffer_foreach_meta (buffer, foreach_metadata, &data); outbuf = gst_buffer_append (outbuf, buffer); GST_DEBUG_OBJECT (baseaudiopayload, "Pushing buffer %p", outbuf); ret = gst_rtp_base_payload_push (basepayload, outbuf); } return ret; }
static GstFlowReturn gst_rtp_sbc_pay_flush_buffers (GstRtpSBCPay * sbcpay) { GstRTPBuffer rtp = GST_RTP_BUFFER_INIT; guint available; guint max_payload; GstBuffer *outbuf, *paybuf; guint8 *payload_data; guint frame_count; guint payload_length; struct rtp_payload *payload; if (sbcpay->frame_length == 0) { GST_ERROR_OBJECT (sbcpay, "Frame length is 0"); return GST_FLOW_ERROR; } available = gst_adapter_available (sbcpay->adapter); max_payload = gst_rtp_buffer_calc_payload_len (GST_RTP_BASE_PAYLOAD_MTU (sbcpay) - RTP_SBC_PAYLOAD_HEADER_SIZE, 0, 0); max_payload = MIN (max_payload, available); frame_count = max_payload / sbcpay->frame_length; payload_length = frame_count * sbcpay->frame_length; if (payload_length == 0) /* Nothing to send */ return GST_FLOW_OK; outbuf = gst_rtp_buffer_new_allocate (RTP_SBC_PAYLOAD_HEADER_SIZE, 0, 0); /* get payload */ gst_rtp_buffer_map (outbuf, GST_MAP_WRITE, &rtp); gst_rtp_buffer_set_payload_type (&rtp, GST_RTP_BASE_PAYLOAD_PT (sbcpay)); /* write header and copy data into payload */ payload_data = gst_rtp_buffer_get_payload (&rtp); payload = (struct rtp_payload *) payload_data; memset (payload, 0, sizeof (struct rtp_payload)); payload->frame_count = frame_count; gst_rtp_buffer_unmap (&rtp); paybuf = gst_adapter_take_buffer_fast (sbcpay->adapter, payload_length); gst_rtp_copy_meta (GST_ELEMENT_CAST (sbcpay), outbuf, paybuf, g_quark_from_static_string (GST_META_TAG_AUDIO_STR)); outbuf = gst_buffer_append (outbuf, paybuf); /* FIXME: what about duration? */ GST_BUFFER_PTS (outbuf) = sbcpay->timestamp; GST_DEBUG_OBJECT (sbcpay, "Pushing %d bytes", payload_length); return gst_rtp_base_payload_push (GST_RTP_BASE_PAYLOAD (sbcpay), outbuf); }
static GstFlowReturn _download_chain (GstBuffer * buffer, gpointer user_data) { dl_context *ctx = user_data; if (ctx->buffer) gst_buffer_append (ctx->buffer, buffer); else ctx->buffer = buffer; return GST_FLOW_OK; }
static GstFlowReturn gst_rtp_opus_pay_handle_buffer (GstRTPBasePayload * basepayload, GstBuffer * buffer) { GstBuffer *outbuf; outbuf = gst_rtp_buffer_new_allocate (0, 0, 0); outbuf = gst_buffer_append (outbuf, gst_buffer_ref (buffer)); /* Push out */ return gst_rtp_base_payload_push (basepayload, outbuf); }
static GstFlowReturn gst_hls_demux_chain (GstPad * pad, GstObject * parent, GstBuffer * buf) { GstHLSDemux *demux = GST_HLS_DEMUX (parent); if (demux->playlist == NULL) demux->playlist = buf; else demux->playlist = gst_buffer_append (demux->playlist, buf); return GST_FLOW_OK; }
static GstBufferList * create_buffer_list (guint * data_size) { GstBufferList *list; GstBuffer *rtp_buffer; GstBuffer *data_buffer; list = gst_buffer_list_new (); /*** First group, i.e. first packet. **/ /* Create the RTP header buffer */ rtp_buffer = gst_buffer_new_allocate (NULL, RTP_HEADER_SIZE, NULL); gst_buffer_memset (rtp_buffer, 0, 0, RTP_HEADER_SIZE); /* Create the buffer that holds the payload */ data_buffer = gst_buffer_new_allocate (NULL, RTP_PAYLOAD_SIZE, NULL); gst_buffer_memset (data_buffer, 0, 0, RTP_PAYLOAD_SIZE); /* Create a new group to hold the rtp header and the payload */ gst_buffer_list_add (list, gst_buffer_append (rtp_buffer, data_buffer)); /*** Second group, i.e. second packet. ***/ /* Create the RTP header buffer */ rtp_buffer = gst_buffer_new_allocate (NULL, RTP_HEADER_SIZE, NULL); gst_buffer_memset (rtp_buffer, 0, 0, RTP_HEADER_SIZE); /* Create the buffer that holds the payload */ data_buffer = gst_buffer_new_allocate (NULL, RTP_PAYLOAD_SIZE, NULL); gst_buffer_memset (data_buffer, 0, 0, RTP_PAYLOAD_SIZE); /* Create a new group to hold the rtp header and the payload */ gst_buffer_list_add (list, gst_buffer_append (rtp_buffer, data_buffer)); /* Calculate the size of the data */ *data_size = 2 * RTP_HEADER_SIZE + 2 * RTP_PAYLOAD_SIZE; return list; }
static GstFlowReturn gst_rtp_mp2t_pay_flush (GstRTPMP2TPay * rtpmp2tpay) { guint avail, mtu; GstFlowReturn ret = GST_FLOW_OK; GstBuffer *outbuf; avail = gst_adapter_available (rtpmp2tpay->adapter); mtu = GST_RTP_BASE_PAYLOAD_MTU (rtpmp2tpay); while (avail > 0 && (ret == GST_FLOW_OK)) { guint towrite; guint payload_len; guint packet_len; GstBuffer *paybuf; /* this will be the total length of the packet */ packet_len = gst_rtp_buffer_calc_packet_len (avail, 0, 0); /* fill one MTU or all available bytes */ towrite = MIN (packet_len, mtu); /* this is the payload length */ payload_len = gst_rtp_buffer_calc_payload_len (towrite, 0, 0); payload_len -= payload_len % 188; /* need whole packets */ if (!payload_len) break; /* create buffer to hold the payload */ outbuf = gst_rtp_buffer_new_allocate (0, 0, 0); /* get payload */ paybuf = gst_adapter_take_buffer_fast (rtpmp2tpay->adapter, payload_len); gst_rtp_copy_meta (GST_ELEMENT_CAST (rtpmp2tpay), outbuf, paybuf, 0); outbuf = gst_buffer_append (outbuf, paybuf); avail -= payload_len; GST_BUFFER_PTS (outbuf) = rtpmp2tpay->first_ts; GST_BUFFER_DURATION (outbuf) = rtpmp2tpay->duration; GST_DEBUG_OBJECT (rtpmp2tpay, "pushing buffer of size %u", (guint) gst_buffer_get_size (outbuf)); ret = gst_rtp_base_payload_push (GST_RTP_BASE_PAYLOAD (rtpmp2tpay), outbuf); } return ret; }
static GstFlowReturn gst_rtp_gsm_pay_handle_buffer (GstRTPBasePayload * basepayload, GstBuffer * buffer) { GstRTPGSMPay *rtpgsmpay; guint payload_len; GstBuffer *outbuf; GstClockTime timestamp, duration; GstFlowReturn ret; rtpgsmpay = GST_RTP_GSM_PAY (basepayload); timestamp = GST_BUFFER_PTS (buffer); duration = GST_BUFFER_DURATION (buffer); /* FIXME, only one GSM frame per RTP packet for now */ payload_len = gst_buffer_get_size (buffer); /* FIXME, just error out for now */ if (payload_len > GST_RTP_BASE_PAYLOAD_MTU (rtpgsmpay)) goto too_big; outbuf = gst_rtp_buffer_new_allocate (payload_len, 0, 0); /* copy timestamp and duration */ GST_BUFFER_PTS (outbuf) = timestamp; GST_BUFFER_DURATION (outbuf) = duration; gst_rtp_copy_meta (GST_ELEMENT_CAST (rtpgsmpay), outbuf, buffer, g_quark_from_static_string (GST_META_TAG_AUDIO_STR)); /* append payload */ outbuf = gst_buffer_append (outbuf, buffer); GST_DEBUG ("gst_rtp_gsm_pay_chain: pushing buffer of size %" G_GSIZE_FORMAT, gst_buffer_get_size (outbuf)); ret = gst_rtp_base_payload_push (basepayload, outbuf); return ret; /* ERRORS */ too_big: { GST_ELEMENT_ERROR (rtpgsmpay, STREAM, ENCODE, (NULL), ("payload_len %u > mtu %u", payload_len, GST_RTP_BASE_PAYLOAD_MTU (rtpgsmpay))); return GST_FLOW_ERROR; } }
/* Internal method only. Tries to merge buffers at the head of the queue * to form a single larger buffer of size 'size'. * * Returns TRUE if it managed to merge anything. */ static gboolean gst_adapter_try_to_merge_up (GstAdapter * adapter, gsize size) { GstBuffer *cur, *head; GSList *g; gboolean ret = FALSE; gsize hsize; g = adapter->buflist; if (g == NULL) return FALSE; head = g->data; hsize = gst_buffer_get_size (head); /* Remove skipped part from the buffer (otherwise the buffer might grow indefinitely) */ head = gst_buffer_make_writable (head); gst_buffer_resize (head, adapter->skip, hsize - adapter->skip); hsize -= adapter->skip; adapter->skip = 0; g->data = head; g = g_slist_next (g); while (g != NULL && hsize < size) { cur = g->data; /* Merge the head buffer and the next in line */ GST_LOG_OBJECT (adapter, "Merging buffers of size %" G_GSIZE_FORMAT " & %" G_GSIZE_FORMAT " in search of target %" G_GSIZE_FORMAT, hsize, gst_buffer_get_size (cur), size); head = gst_buffer_append (head, cur); hsize = gst_buffer_get_size (head); ret = TRUE; /* Delete the front list item, and store our new buffer in the 2nd list * item */ adapter->buflist = g_slist_delete_link (adapter->buflist, adapter->buflist); g->data = head; /* invalidate scan position */ adapter->scan_offset = 0; adapter->scan_entry = NULL; g = g_slist_next (g); } return ret; }
static GstFlowReturn gst_vqe_sdp_demux_sink_chain( GstPad *pad, GstObject *parent, GstBuffer *buffer) { GstVQESDPDemux * demux = GST_VQE_SDP_DEMUX(parent); if (!demux->sdpfile_complete) { if (!demux->sdpfile) demux->sdpfile = gst_buffer_new(); demux->sdpfile = gst_buffer_append(demux->sdpfile, buffer); return GST_FLOW_OK; } else { return GST_FLOW_EOS; } }
static GstFlowReturn gst_asf_parse_pull_headers (GstAsfParse * asfparse) { GstBuffer *guid_and_size = NULL; GstBuffer *headers = NULL; guint64 size; GstFlowReturn ret; GstMapInfo map; if ((ret = gst_pad_pull_range (asfparse->sinkpad, asfparse->offset, ASF_GUID_OBJSIZE_SIZE, &guid_and_size)) != GST_FLOW_OK) { GST_ERROR_OBJECT (asfparse, "Failed to pull data from headers"); goto leave; } asfparse->offset += ASF_GUID_OBJSIZE_SIZE; gst_buffer_map (guid_and_size, &map, GST_MAP_READ); size = gst_asf_match_and_peek_obj_size (map.data, &(guids[ASF_HEADER_OBJECT_INDEX])); gst_buffer_unmap (guid_and_size, &map); if (size == 0) { GST_ERROR_OBJECT (asfparse, "ASF starting identifier missing"); goto leave; } if ((ret = gst_pad_pull_range (asfparse->sinkpad, asfparse->offset, size - ASF_GUID_OBJSIZE_SIZE, &headers)) != GST_FLOW_OK) { GST_ERROR_OBJECT (asfparse, "Failed to pull data from headers"); goto leave; } headers = gst_buffer_append (guid_and_size, headers); guid_and_size = NULL; asfparse->offset += size - ASF_GUID_OBJSIZE_SIZE; if (!gst_asf_parse_headers (headers, asfparse->asfinfo)) { goto leave; } return gst_asf_parse_push (asfparse, headers); leave: if (headers) gst_buffer_unref (headers); if (guid_and_size) gst_buffer_unref (guid_and_size); return ret; }
static GstFlowReturn gst_hls_demux_data_received (GstAdaptiveDemux * demux, GstAdaptiveDemuxStream * stream) { GstHLSDemux *hlsdemux = GST_HLS_DEMUX_CAST (demux); gsize available; GstBuffer *buffer = NULL; available = gst_adapter_available (stream->adapter); /* Is it encrypted? */ if (hlsdemux->current_key) { GError *err = NULL; GstBuffer *tmp_buffer; /* must be a multiple of 16 */ available = available & (~0xF); if (available == 0) { return GST_FLOW_OK; } buffer = gst_adapter_take_buffer (stream->adapter, available); buffer = gst_hls_demux_decrypt_fragment (hlsdemux, buffer, &err); if (buffer == NULL) { GST_ELEMENT_ERROR (demux, STREAM, DECODE, ("Failed to decrypt buffer"), ("decryption failed %s", err->message)); g_error_free (err); return GST_FLOW_ERROR; } tmp_buffer = hlsdemux->pending_buffer; hlsdemux->pending_buffer = buffer; buffer = tmp_buffer; } else { buffer = gst_adapter_take_buffer (stream->adapter, available); if (hlsdemux->pending_buffer) { buffer = gst_buffer_append (hlsdemux->pending_buffer, buffer); hlsdemux->pending_buffer = NULL; } } return gst_hls_demux_handle_buffer (demux, stream, buffer, FALSE); }
gboolean gst_fragment_add_buffer (GstFragment * fragment, GstBuffer * buffer) { g_return_val_if_fail (fragment != NULL, FALSE); g_return_val_if_fail (buffer != NULL, FALSE); if (fragment->completed) { GST_WARNING ("Fragment is completed, could not add more buffers"); return FALSE; } GST_DEBUG ("Adding new buffer to the fragment"); /* We steal the buffers you pass in */ if (fragment->priv->buffer == NULL) fragment->priv->buffer = buffer; else fragment->priv->buffer = gst_buffer_append (fragment->priv->buffer, buffer); return TRUE; }
static GstFlowReturn gst_nsfdec_chain (GstPad * pad, GstBuffer * buffer) { GstNsfDec *nsfdec; nsfdec = GST_NSFDEC (gst_pad_get_parent (pad)); /* collect all data, we start doing something when we get an EOS * event */ if (nsfdec->tune_buffer) { nsfdec->tune_buffer = gst_buffer_append (nsfdec->tune_buffer, buffer); } else { nsfdec->tune_buffer = buffer; } gst_object_unref (nsfdec); return GST_FLOW_OK; }
static GstFlowReturn gst_asf_parse_pull_indexes (GstAsfParse * asfparse) { GstBuffer *guid_and_size; GstBuffer *buf; guint64 obj_size; GstFlowReturn ret = GST_FLOW_OK; while (1) { guid_and_size = NULL; ret = gst_pad_pull_range (asfparse->sinkpad, asfparse->offset, ASF_GUID_OBJSIZE_SIZE, &guid_and_size); if (ret != GST_FLOW_OK) break; /* we can peek at the object size */ obj_size = gst_asf_match_and_peek_obj_size_buf (guid_and_size, NULL); if (obj_size == 0) { GST_ERROR_OBJECT (asfparse, "Incomplete object found"); gst_buffer_unref (guid_and_size); ret = GST_FLOW_ERROR; break; } asfparse->offset += ASF_GUID_OBJSIZE_SIZE; /* pull the rest of the object */ buf = NULL; ret = gst_pad_pull_range (asfparse->sinkpad, asfparse->offset, obj_size, &buf); if (ret != GST_FLOW_OK) { gst_buffer_unref (guid_and_size); break; } asfparse->offset += obj_size - ASF_GUID_OBJSIZE_SIZE; buf = gst_buffer_append (guid_and_size, buf); ret = gst_asf_parse_push (asfparse, buf); if (ret != GST_FLOW_OK) break; } return ret; }
static GstFlowReturn gst_rtp_g723_pay_flush (GstRTPG723Pay * pay) { GstBuffer *outbuf, *payload_buf; GstFlowReturn ret; guint avail; GstRTPBuffer rtp = { NULL }; avail = gst_adapter_available (pay->adapter); outbuf = gst_rtp_buffer_new_allocate (0, 0, 0); gst_rtp_buffer_map (outbuf, GST_MAP_WRITE, &rtp); GST_BUFFER_PTS (outbuf) = pay->timestamp; GST_BUFFER_DURATION (outbuf) = pay->duration; /* copy G723 data as payload */ payload_buf = gst_adapter_take_buffer_fast (pay->adapter, avail); pay->timestamp = GST_CLOCK_TIME_NONE; pay->duration = 0; /* set discont and marker */ if (pay->discont) { GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT); gst_rtp_buffer_set_marker (&rtp, TRUE); pay->discont = FALSE; } gst_rtp_buffer_unmap (&rtp); gst_rtp_copy_meta (GST_ELEMENT_CAST (pay), outbuf, payload_buf, g_quark_from_static_string (GST_META_TAG_AUDIO_STR)); outbuf = gst_buffer_append (outbuf, payload_buf); ret = gst_rtp_base_payload_push (GST_RTP_BASE_PAYLOAD (pay), outbuf); return ret; }
/** * gst_rtp_base_audio_payload_flush: * @baseaudiopayload: a #GstRTPBasePayload * @payload_len: length of payload * @timestamp: a #GstClockTime * * Create an RTP buffer and store @payload_len bytes of the adapter as the * payload. Set the timestamp on the new buffer to @timestamp before pushing * the buffer downstream. * * If @payload_len is -1, all pending bytes will be flushed. If @timestamp is * -1, the timestamp will be calculated automatically. * * Returns: a #GstFlowReturn */ GstFlowReturn gst_rtp_base_audio_payload_flush (GstRTPBaseAudioPayload * baseaudiopayload, guint payload_len, GstClockTime timestamp) { GstRTPBasePayload *basepayload; GstRTPBaseAudioPayloadPrivate *priv; GstBuffer *outbuf; GstFlowReturn ret; GstAdapter *adapter; guint64 distance; priv = baseaudiopayload->priv; adapter = priv->adapter; basepayload = GST_RTP_BASE_PAYLOAD (baseaudiopayload); if (payload_len == -1) payload_len = gst_adapter_available (adapter); /* nothing to do, just return */ if (payload_len == 0) return GST_FLOW_OK; if (timestamp == -1) { /* calculate the timestamp */ timestamp = gst_adapter_prev_pts (adapter, &distance); GST_LOG_OBJECT (baseaudiopayload, "last timestamp %" GST_TIME_FORMAT ", distance %" G_GUINT64_FORMAT, GST_TIME_ARGS (timestamp), distance); if (GST_CLOCK_TIME_IS_VALID (timestamp) && distance > 0) { /* convert the number of bytes since the last timestamp to time and add to * the last seen timestamp */ timestamp += priv->bytes_to_time (baseaudiopayload, distance); } } GST_DEBUG_OBJECT (baseaudiopayload, "Pushing %d bytes ts %" GST_TIME_FORMAT, payload_len, GST_TIME_ARGS (timestamp)); if (priv->buffer_list && gst_adapter_available_fast (adapter) >= payload_len) { GstBuffer *buffer; /* we can quickly take a buffer out of the adapter without having to copy * anything. */ buffer = gst_adapter_take_buffer (adapter, payload_len); ret = gst_rtp_base_audio_payload_push_buffer (baseaudiopayload, buffer, timestamp); } else { GstBuffer *paybuf; CopyMetaData data; /* create buffer to hold the payload */ outbuf = gst_rtp_base_payload_allocate_output_buffer (basepayload, 0, 0, 0); paybuf = gst_adapter_take_buffer_fast (adapter, payload_len); data.pay = baseaudiopayload; data.outbuf = outbuf; gst_buffer_foreach_meta (paybuf, foreach_metadata, &data); outbuf = gst_buffer_append (outbuf, paybuf); /* set metadata */ gst_rtp_base_audio_payload_set_meta (baseaudiopayload, outbuf, payload_len, timestamp); ret = gst_rtp_base_payload_push (basepayload, outbuf); } return ret; }
static GstFlowReturn gst_rtp_asf_pay_handle_buffer (GstRTPBasePayload * rtppay, GstBuffer * buffer) { GstRtpAsfPay *rtpasfpay = GST_RTP_ASF_PAY_CAST (rtppay); if (G_UNLIKELY (rtpasfpay->state == ASF_END)) { GST_LOG_OBJECT (rtpasfpay, "Dropping buffer as we already pushed all packets"); gst_buffer_unref (buffer); return GST_FLOW_EOS; /* we already finished our job */ } /* receive headers * we only accept if they are in a single buffer */ if (G_UNLIKELY (rtpasfpay->state == ASF_NOT_STARTED)) { guint64 header_size; if (gst_buffer_get_size (buffer) < 24) { /* guid+object size size */ GST_ERROR_OBJECT (rtpasfpay, "Buffer too small, smaller than a Guid and object size"); gst_buffer_unref (buffer); return GST_FLOW_ERROR; } header_size = gst_asf_match_and_peek_obj_size_buf (buffer, &(guids[ASF_HEADER_OBJECT_INDEX])); if (header_size > 0) { GST_DEBUG_OBJECT (rtpasfpay, "ASF header guid received, size %" G_GUINT64_FORMAT, header_size); if (gst_buffer_get_size (buffer) < header_size) { GST_ERROR_OBJECT (rtpasfpay, "Headers should be contained in a single" " buffer"); gst_buffer_unref (buffer); return GST_FLOW_ERROR; } else { rtpasfpay->state = ASF_DATA_OBJECT; /* clear previous headers, if any */ if (rtpasfpay->headers) { gst_buffer_unref (rtpasfpay->headers); } GST_DEBUG_OBJECT (rtpasfpay, "Storing headers"); if (gst_buffer_get_size (buffer) == header_size) { rtpasfpay->headers = buffer; return GST_FLOW_OK; } else { /* headers are a subbuffer of thie buffer */ GstBuffer *aux = gst_buffer_copy_region (buffer, GST_BUFFER_COPY_ALL, header_size, gst_buffer_get_size (buffer) - header_size); rtpasfpay->headers = gst_buffer_copy_region (buffer, GST_BUFFER_COPY_ALL, 0, header_size); gst_buffer_replace (&buffer, aux); } } } else { GST_ERROR_OBJECT (rtpasfpay, "Missing ASF header start"); gst_buffer_unref (buffer); return GST_FLOW_ERROR; } } if (G_UNLIKELY (rtpasfpay->state == ASF_DATA_OBJECT)) { GstMapInfo map; if (gst_buffer_get_size (buffer) != ASF_DATA_OBJECT_SIZE) { GST_ERROR_OBJECT (rtpasfpay, "Received buffer of different size of " "the data object header"); gst_buffer_unref (buffer); return GST_FLOW_ERROR; } gst_buffer_map (buffer, &map, GST_MAP_READ); if (gst_asf_match_guid (map.data, &(guids[ASF_DATA_OBJECT_INDEX]))) { gst_buffer_unmap (buffer, &map); GST_DEBUG_OBJECT (rtpasfpay, "Received data object header"); rtpasfpay->headers = gst_buffer_append (rtpasfpay->headers, buffer); rtpasfpay->state = ASF_PACKETS; return gst_rtp_asf_pay_parse_headers (rtpasfpay); } else { gst_buffer_unmap (buffer, &map); GST_ERROR_OBJECT (rtpasfpay, "Unexpected object received (was expecting " "data object)"); gst_buffer_unref (buffer); return GST_FLOW_ERROR; } } if (G_LIKELY (rtpasfpay->state == ASF_PACKETS)) { /* in broadcast mode we can't trust the packets count information * from the headers * We assume that if this is on broadcast mode it is a live stream * and we are going to keep receiving packets indefinitely */ if (rtpasfpay->asfinfo.broadcast || rtpasfpay->packets_count < rtpasfpay->asfinfo.packets_count) { GST_DEBUG_OBJECT (rtpasfpay, "Received packet %" G_GUINT64_FORMAT "/%" G_GUINT64_FORMAT, rtpasfpay->packets_count, rtpasfpay->asfinfo.packets_count); rtpasfpay->packets_count++; return gst_rtp_asf_pay_handle_packet (rtpasfpay, buffer); } else { GST_INFO_OBJECT (rtpasfpay, "Packets ended"); rtpasfpay->state = ASF_END; gst_buffer_unref (buffer); return GST_FLOW_EOS; } } gst_buffer_unref (buffer); return GST_FLOW_OK; }
static GstFlowReturn gst_rtp_mpa_pay_flush (GstRtpMPAPay * rtpmpapay) { guint avail; GstBuffer *outbuf; GstFlowReturn ret; guint16 frag_offset; GstBufferList *list; /* the data available in the adapter is either smaller * than the MTU or bigger. In the case it is smaller, the complete * adapter contents can be put in one packet. In the case the * adapter has more than one MTU, we need to split the MPA data * over multiple packets. The frag_offset in each packet header * needs to be updated with the position in the MPA frame. */ avail = gst_adapter_available (rtpmpapay->adapter); ret = GST_FLOW_OK; list = gst_buffer_list_new_sized (avail / (GST_RTP_BASE_PAYLOAD_MTU (rtpmpapay) - RTP_HEADER_LEN) + 1); frag_offset = 0; while (avail > 0) { guint towrite; guint8 *payload; guint payload_len; guint packet_len; GstRTPBuffer rtp = { NULL }; GstBuffer *paybuf; /* this will be the total length of the packet */ packet_len = gst_rtp_buffer_calc_packet_len (4 + avail, 0, 0); /* fill one MTU or all available bytes */ towrite = MIN (packet_len, GST_RTP_BASE_PAYLOAD_MTU (rtpmpapay)); /* this is the payload length */ payload_len = gst_rtp_buffer_calc_payload_len (towrite, 0, 0); /* create buffer to hold the payload */ outbuf = gst_rtp_buffer_new_allocate (4, 0, 0); gst_rtp_buffer_map (outbuf, GST_MAP_WRITE, &rtp); payload_len -= 4; gst_rtp_buffer_set_payload_type (&rtp, GST_RTP_PAYLOAD_MPA); /* * 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 | Frag_offset | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ payload = gst_rtp_buffer_get_payload (&rtp); payload[0] = 0; payload[1] = 0; payload[2] = frag_offset >> 8; payload[3] = frag_offset & 0xff; avail -= payload_len; frag_offset += payload_len; if (avail == 0) gst_rtp_buffer_set_marker (&rtp, TRUE); gst_rtp_buffer_unmap (&rtp); paybuf = gst_adapter_take_buffer_fast (rtpmpapay->adapter, payload_len); gst_rtp_copy_meta (GST_ELEMENT_CAST (rtpmpapay), outbuf, paybuf, g_quark_from_static_string (GST_META_TAG_AUDIO_STR)); outbuf = gst_buffer_append (outbuf, paybuf); GST_BUFFER_PTS (outbuf) = rtpmpapay->first_ts; GST_BUFFER_DURATION (outbuf) = rtpmpapay->duration; gst_buffer_list_add (list, outbuf); } ret = gst_rtp_base_payload_push_list (GST_RTP_BASE_PAYLOAD (rtpmpapay), list); return ret; }
/* * Test if the parser pushes clean data properly. */ void gst_parser_test_run (GstParserTest * test, GstCaps ** out_caps) { buffer_verify_data_s vdata = { 0, 0, 0, NULL, 0, NULL, FALSE }; GstElement *element; GstBuffer *buffer = NULL; GstCaps *src_caps; guint i, j, k; guint frames = 0, size = 0; element = setup_element (test->factory, test->sink_template, NULL, test->src_template, test->src_caps); /* push some setup headers */ for (j = 0; j < G_N_ELEMENTS (test->headers) && test->headers[j].data; j++) { buffer = buffer_new (test->headers[j].data, test->headers[j].size); fail_unless_equals_int (gst_pad_push (srcpad, buffer), GST_FLOW_OK); } for (j = 0; j < 3; j++) { for (i = 0; i < test->series[j].num; i++) { /* sanity enforcing */ for (k = 0; k < MAX (1, test->series[j].fpb); k++) { if (!k) buffer = buffer_new (test->series[j].data, test->series[j].size); else { buffer = gst_buffer_append (buffer, buffer_new (test->series[j].data, test->series[j].size)); } } fail_unless_equals_int (gst_pad_push (srcpad, buffer), GST_FLOW_OK); if (j == 0) vdata.buffers_before_offset_skip++; else if (j == 1) vdata.offset_skip_amount += test->series[j].size * test->series[j].fpb; if (j != 1) { frames += test->series[j].fpb; size += test->series[j].size * test->series[j].fpb; } } } gst_pad_push_event (srcpad, gst_event_new_eos ()); if (G_LIKELY (test->framed)) fail_unless_equals_int (g_list_length (buffers) - test->discard, frames); /* if all frames are identical, do extended test, * otherwise only verify total data size */ if (test->series[0].data && (!test->series[2].size || (test->series[0].size == test->series[2].size && test->series[2].data && !memcmp (test->series[0].data, test->series[2].data, test->series[0].size)))) { vdata.data_to_verify = test->series[0].data; vdata.data_to_verify_size = test->series[0].size; vdata.caps = test->sink_caps; vdata.discard = test->discard; vdata.no_metadata = test->no_metadata; g_list_foreach (buffers, buffer_verify_data, &vdata); } else { guint datasum = 0; g_list_foreach (buffers, buffer_count_size, &datasum); size -= test->dropped; fail_unless_equals_int (datasum, size); } src_caps = gst_pad_get_current_caps (sinkpad); GST_LOG ("output caps: %" GST_PTR_FORMAT, src_caps); if (test->sink_caps) { GST_LOG ("%" GST_PTR_FORMAT " = %" GST_PTR_FORMAT " ?", src_caps, test->sink_caps); fail_unless (gst_caps_is_equal (src_caps, test->sink_caps)); } if (out_caps) *out_caps = src_caps; else gst_caps_unref (src_caps); cleanup_element (element); }
static GstFlowReturn gst_dvd_spu_subpic_chain (GstPad * pad, GstObject * parent, GstBuffer * buf) { GstDVDSpu *dvdspu = (GstDVDSpu *) parent; GstFlowReturn ret = GST_FLOW_OK; gsize size; g_return_val_if_fail (dvdspu != NULL, GST_FLOW_ERROR); GST_INFO_OBJECT (dvdspu, "Have subpicture buffer with timestamp %" GST_TIME_FORMAT " and size %" G_GSIZE_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)), gst_buffer_get_size (buf)); DVD_SPU_LOCK (dvdspu); if (GST_BUFFER_TIMESTAMP_IS_VALID (buf)) { dvdspu->subp_seg.position = GST_BUFFER_TIMESTAMP (buf); } if (GST_BUFFER_IS_DISCONT (buf) && dvdspu->partial_spu) { gst_buffer_unref (dvdspu->partial_spu); dvdspu->partial_spu = NULL; } if (dvdspu->partial_spu != NULL) { if (GST_BUFFER_TIMESTAMP_IS_VALID (buf)) GST_WARNING_OBJECT (dvdspu, "Joining subpicture buffer with timestamp to previous"); dvdspu->partial_spu = gst_buffer_append (dvdspu->partial_spu, buf); } else { /* If we don't yet have a buffer, wait for one with a timestamp, * since that will avoid collecting the 2nd half of a partial buf */ if (GST_BUFFER_TIMESTAMP_IS_VALID (buf)) dvdspu->partial_spu = buf; else gst_buffer_unref (buf); } if (dvdspu->partial_spu == NULL) goto done; size = gst_buffer_get_size (dvdspu->partial_spu); switch (dvdspu->spu_input_type) { case SPU_INPUT_TYPE_VOBSUB: if (size >= 2) { guint8 header[2]; guint16 packet_size; gst_buffer_extract (dvdspu->partial_spu, 0, header, 2); packet_size = GST_READ_UINT16_BE (header); if (packet_size == size) { submit_new_spu_packet (dvdspu, dvdspu->partial_spu); dvdspu->partial_spu = NULL; } else if (packet_size == 0) { GST_LOG_OBJECT (dvdspu, "Discarding empty SPU buffer"); gst_buffer_unref (dvdspu->partial_spu); dvdspu->partial_spu = NULL; } else if (packet_size < size) { /* Somehow we collected too much - something is wrong. Drop the * packet entirely and wait for a new one */ GST_DEBUG_OBJECT (dvdspu, "Discarding invalid SPU buffer of size %" G_GSIZE_FORMAT, size); gst_buffer_unref (dvdspu->partial_spu); dvdspu->partial_spu = NULL; } else { GST_LOG_OBJECT (dvdspu, "SPU buffer claims to be of size %u. Collected %" G_GSIZE_FORMAT " so far.", packet_size, size); } } break; case SPU_INPUT_TYPE_PGS:{ /* Collect until we have a command buffer that ends exactly at the size * we've collected */ guint8 packet_type; guint16 packet_size; GstMapInfo map; guint8 *ptr, *end; gboolean invalid = FALSE; gst_buffer_map (dvdspu->partial_spu, &map, GST_MAP_READ); ptr = map.data; end = ptr + map.size; /* FIXME: There's no need to walk the command set each time. We can set a * marker and resume where we left off next time */ /* FIXME: Move the packet parsing and sanity checking into the format-specific modules */ while (ptr != end) { if (ptr + 3 > end) break; packet_type = *ptr++; packet_size = GST_READ_UINT16_BE (ptr); ptr += 2; if (ptr + packet_size > end) break; ptr += packet_size; /* 0x80 is the END command for PGS packets */ if (packet_type == 0x80 && ptr != end) { /* Extra cruft on the end of the packet -> assume invalid */ invalid = TRUE; break; } } gst_buffer_unmap (dvdspu->partial_spu, &map); if (invalid) { gst_buffer_unref (dvdspu->partial_spu); dvdspu->partial_spu = NULL; } else if (ptr == end) { GST_DEBUG_OBJECT (dvdspu, "Have complete PGS packet of size %" G_GSIZE_FORMAT ". Enqueueing.", map.size); submit_new_spu_packet (dvdspu, dvdspu->partial_spu); dvdspu->partial_spu = NULL; } break; } default: GST_ERROR_OBJECT (dvdspu, "Input type not configured before SPU passing"); goto caps_not_set; } done: DVD_SPU_UNLOCK (dvdspu); return ret; /* ERRORS */ caps_not_set: { GST_ELEMENT_ERROR (dvdspu, RESOURCE, NO_SPACE_LEFT, (_("Subpicture format was not configured before data flow")), (NULL)); ret = GST_FLOW_ERROR; goto done; } }
static GstFlowReturn gst_jasper_dec_chain (GstPad * pad, GstBuffer * buf) { GstJasperDec *dec; GstFlowReturn ret = GST_FLOW_OK; GstClockTime ts; GstBuffer *outbuf = NULL; guint8 *data; guint size; gboolean decode; dec = GST_JASPER_DEC (GST_PAD_PARENT (pad)); if (dec->fmt < 0) goto not_negotiated; ts = GST_BUFFER_TIMESTAMP (buf); GST_LOG_OBJECT (dec, "buffer with ts: %" GST_TIME_FORMAT, GST_TIME_ARGS (ts)); if (GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DISCONT)) dec->discont = TRUE; decode = gst_jasper_dec_do_qos (dec, ts); /* FIXME: do clipping */ if (G_UNLIKELY (!decode)) { dec->discont = TRUE; goto done; } /* strip possible prefix */ if (dec->strip) { GstBuffer *tmp; tmp = gst_buffer_create_sub (buf, dec->strip, GST_BUFFER_SIZE (buf) - dec->strip); gst_buffer_copy_metadata (tmp, buf, GST_BUFFER_COPY_TIMESTAMPS); gst_buffer_unref (buf); buf = tmp; } /* preprend possible codec_data */ if (dec->codec_data) { GstBuffer *tmp; tmp = gst_buffer_append (gst_buffer_ref (dec->codec_data), gst_buffer_ref (buf)); gst_buffer_copy_metadata (tmp, buf, GST_BUFFER_COPY_TIMESTAMPS); gst_buffer_unref (buf); buf = tmp; } /* now really feed the data to decoder */ data = GST_BUFFER_DATA (buf); size = GST_BUFFER_SIZE (buf); ret = gst_jasper_dec_get_picture (dec, data, size, &outbuf); if (outbuf) { gst_buffer_copy_metadata (outbuf, buf, GST_BUFFER_COPY_TIMESTAMPS); if (dec->discont) { GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT); dec->discont = FALSE; } if (ret == GST_FLOW_OK) ret = gst_pad_push (dec->srcpad, outbuf); else gst_buffer_unref (outbuf); } done: gst_buffer_unref (buf); return ret; /* ERRORS */ not_negotiated: { GST_ELEMENT_ERROR (dec, CORE, NEGOTIATION, (NULL), ("format wasn't negotiated before chain function")); ret = GST_FLOW_NOT_NEGOTIATED; goto done; } }
static GstFlowReturn gst_rtp_klv_pay_handle_buffer (GstRTPBasePayload * basepayload, GstBuffer * buf) { GstFlowReturn ret = GST_FLOW_OK; GstBufferList *list = NULL; GstRtpKlvPay *pay; GstMapInfo map; GstBuffer *outbuf = NULL; gsize offset; guint mtu, rtp_header_size, max_payload_size; pay = GST_RTP_KLV_PAY (basepayload); mtu = GST_RTP_BASE_PAYLOAD_MTU (basepayload); rtp_header_size = gst_rtp_buffer_calc_header_len (0); max_payload_size = mtu - rtp_header_size; gst_buffer_map (buf, &map, GST_MAP_READ); if (map.size == 0) goto done; /* KLV coding shall use and only use a fixed 16-byte SMPTE-administered * Universal Label, according to SMPTE 298M as Key (Rec. ITU R-BT.1653-1) */ if (map.size < 16 || GST_READ_UINT32_BE (map.data) != 0x060E2B34) goto bad_input; if (map.size > max_payload_size) list = gst_buffer_list_new (); GST_LOG_OBJECT (pay, "%" G_GSIZE_FORMAT " bytes of data to payload", map.size); offset = 0; while (offset < map.size) { GstBuffer *payloadbuf; GstRTPBuffer rtp = { NULL }; guint payload_size; guint bytes_left; bytes_left = map.size - offset; payload_size = MIN (bytes_left, max_payload_size); outbuf = gst_rtp_buffer_new_allocate (0, 0, 0); if (payload_size == bytes_left) { GST_LOG_OBJECT (pay, "last packet of KLV unit"); gst_rtp_buffer_map (outbuf, GST_MAP_WRITE, &rtp); gst_rtp_buffer_set_marker (&rtp, 1); gst_rtp_buffer_unmap (&rtp); } GST_LOG_OBJECT (pay, "packet with payload size %u", payload_size); gst_rtp_copy_meta (GST_ELEMENT_CAST (pay), outbuf, buf, 0); payloadbuf = gst_buffer_copy_region (buf, GST_BUFFER_COPY_MEMORY, offset, payload_size); /* join rtp header + payload memory parts */ outbuf = gst_buffer_append (outbuf, payloadbuf); GST_BUFFER_PTS (outbuf) = GST_BUFFER_PTS (buf); GST_BUFFER_DTS (outbuf) = GST_BUFFER_DTS (buf); /* and add to list */ if (list != NULL) gst_buffer_list_insert (list, -1, outbuf); offset += payload_size; } done: gst_buffer_unmap (buf, &map); gst_buffer_unref (buf); if (list != NULL) ret = gst_rtp_base_payload_push_list (basepayload, list); else if (outbuf != NULL) ret = gst_rtp_base_payload_push (basepayload, outbuf); return ret; /* ERRORS */ bad_input: { GST_ERROR_OBJECT (pay, "Input doesn't look like a KLV packet, ignoring"); goto done; } }