static gint multipart_find_boundary (GstMultipartDemux * multipart, gint * datalen) { /* Adaptor is positioned at the start of the data */ const guint8 *data, *pos; const guint8 *dataend; gint len; if (multipart->content_length >= 0) { /* fast path, known content length :) */ len = multipart->content_length; if (gst_adapter_available (multipart->adapter) >= len + 2) { *datalen = len; data = gst_adapter_map (multipart->adapter, len + 1); /* If data[len] contains \r then assume a newline is \r\n */ if (data[len] == '\r') len += 2; else if (data[len] == '\n') len += 1; gst_adapter_unmap (multipart->adapter); /* Don't check if boundary is actually there, but let the header parsing * bail out if it isn't */ return len; } else { /* need more data */ return MULTIPART_NEED_MORE_DATA; } } len = gst_adapter_available (multipart->adapter); if (len == 0) return MULTIPART_NEED_MORE_DATA; data = gst_adapter_map (multipart->adapter, len); dataend = data + len; for (pos = data + multipart->scanpos; pos <= dataend - multipart->boundary_len - 2; pos++) { if (*pos == '-' && pos[1] == '-' && !strncmp ((gchar *) pos + 2, multipart->boundary, multipart->boundary_len)) { /* Found the boundary! Check if there was a newline before the boundary */ len = pos - data; if (pos - 2 > data && pos[-2] == '\r') len -= 2; else if (pos - 1 > data && pos[-1] == '\n') len -= 1; *datalen = len; gst_adapter_unmap (multipart->adapter); multipart->scanpos = 0; return pos - data; } } gst_adapter_unmap (multipart->adapter); multipart->scanpos = pos - data; return MULTIPART_NEED_MORE_DATA; }
static gboolean theora_enc_read_multipass_cache (GstTheoraEnc * enc) { GstBuffer *cache_buf; const guint8 *cache_data; gsize bytes_read = 0; gssize bytes_consumed = 0; GIOStatus stat = G_IO_STATUS_NORMAL; gboolean done = FALSE; while (!done) { if (gst_adapter_available (enc->multipass_cache_adapter) == 0) { GstMapInfo minfo; cache_buf = gst_buffer_new_allocate (NULL, 512, NULL); gst_buffer_map (cache_buf, &minfo, GST_MAP_WRITE); stat = g_io_channel_read_chars (enc->multipass_cache_fd, (gchar *) minfo.data, minfo.size, &bytes_read, NULL); if (bytes_read <= 0) { gst_buffer_unmap (cache_buf, &minfo); gst_buffer_unref (cache_buf); break; } else { gst_buffer_unmap (cache_buf, &minfo); gst_buffer_resize (cache_buf, 0, bytes_read); gst_adapter_push (enc->multipass_cache_adapter, cache_buf); } } if (gst_adapter_available (enc->multipass_cache_adapter) == 0) break; bytes_read = MIN (gst_adapter_available (enc->multipass_cache_adapter), 512); cache_data = gst_adapter_map (enc->multipass_cache_adapter, bytes_read); bytes_consumed = th_encode_ctl (enc->encoder, TH_ENCCTL_2PASS_IN, (guint8 *) cache_data, bytes_read); gst_adapter_unmap (enc->multipass_cache_adapter); done = bytes_consumed <= 0; if (bytes_consumed > 0) gst_adapter_flush (enc->multipass_cache_adapter, bytes_consumed); } if (stat == G_IO_STATUS_ERROR || (stat == G_IO_STATUS_EOF && bytes_read == 0) || bytes_consumed < 0) { GST_ELEMENT_ERROR (enc, RESOURCE, READ, (NULL), ("Failed to read multipass cache file")); return FALSE; } return TRUE; }
/*Flushes the first @flush bytes in the @adapter*/ static void gst_adapter_flush_unchecked (GstAdapter * adapter, gsize flush) { GstBuffer *cur; gsize size; GSList *g; GST_LOG_OBJECT (adapter, "flushing %" G_GSIZE_FORMAT " bytes", flush); if (adapter->info.memory) gst_adapter_unmap (adapter); /* clear state */ adapter->size -= flush; adapter->assembled_len = 0; /* take skip into account */ flush += adapter->skip; /* distance is always at least the amount of skipped bytes */ adapter->pts_distance -= adapter->skip; adapter->dts_distance -= adapter->skip; g = adapter->buflist; cur = g->data; size = gst_buffer_get_size (cur); while (flush >= size) { /* can skip whole buffer */ GST_LOG_OBJECT (adapter, "flushing out head buffer"); adapter->pts_distance += size; adapter->dts_distance += size; flush -= size; gst_buffer_unref (cur); g = g_slist_delete_link (g, g); --adapter->count; if (G_UNLIKELY (g == NULL)) { GST_LOG_OBJECT (adapter, "adapter empty now"); adapter->buflist_end = NULL; break; } /* there is a new head buffer, update the timestamps */ cur = g->data; update_timestamps (adapter, cur); size = gst_buffer_get_size (cur); } adapter->buflist = g; /* account for the remaining bytes */ adapter->skip = flush; adapter->pts_distance += flush; adapter->dts_distance += flush; /* invalidate scan position */ adapter->scan_offset = 0; adapter->scan_entry = NULL; }
HRESULT Output::RenderAudioSamples (bool preroll) { uint32_t samplesWritten; // guint64 samplesToWrite; if (decklinksink->stop) { GST_DEBUG ("decklinksink->stop set TRUE!"); decklinksink->output->BeginAudioPreroll (); // running = true; } else { gconstpointer data; int n; g_mutex_lock (&decklinksink->audio_mutex); n = gst_adapter_available (decklinksink->audio_adapter); if (n > 0) { data = gst_adapter_map (decklinksink->audio_adapter, n); decklinksink->output->ScheduleAudioSamples ((void *) data, n / 4, 0, 0, &samplesWritten); gst_adapter_unmap (decklinksink->audio_adapter); gst_adapter_flush (decklinksink->audio_adapter, samplesWritten * 4); GST_DEBUG ("wrote %d samples, %d available", samplesWritten, n / 4); g_cond_signal (&decklinksink->audio_cond); } else { if (decklinksink->audio_eos) { GstMessage *message; message = gst_message_new_eos (GST_OBJECT_CAST (decklinksink)); gst_message_set_seqnum (message, decklinksink->audio_seqnum); gst_element_post_message (GST_ELEMENT_CAST (decklinksink), message); } } g_mutex_unlock (&decklinksink->audio_mutex); } GST_DEBUG ("RenderAudioSamples"); return S_OK; }
static GstFlowReturn gst_dtsdec_parse (GstAudioDecoder * bdec, GstAdapter * adapter, gint * _offset, gint * len) { GstDtsDec *dts; guint8 *data; gint av, size; gint length = 0, flags, sample_rate, bit_rate, frame_length; GstFlowReturn result = GST_FLOW_EOS; dts = GST_DTSDEC (bdec); size = av = gst_adapter_available (adapter); data = (guint8 *) gst_adapter_map (adapter, av); /* find and read header */ bit_rate = dts->bit_rate; sample_rate = dts->sample_rate; flags = 0; while (size >= 7) { length = dca_syncinfo (dts->state, data, &flags, &sample_rate, &bit_rate, &frame_length); if (length == 0) { /* shift window to re-find sync */ data++; size--; } else if (length <= size) { GST_LOG_OBJECT (dts, "Sync: frame size %d", length); result = GST_FLOW_OK; break; } else { GST_LOG_OBJECT (dts, "Not enough data available (needed %d had %d)", length, size); break; } } gst_adapter_unmap (adapter); *_offset = av - size; *len = length; return result; }
static GstFlowReturn theora_dec_parse (GstVideoDecoder * decoder, GstVideoCodecFrame * frame, GstAdapter * adapter, gboolean at_eos) { gint av; const guint8 *data; av = gst_adapter_available (adapter); data = gst_adapter_map (adapter, 1); /* check for keyframe; must not be header packet */ if (!(data[0] & 0x80) && (data[0] & 0x40) == 0) GST_VIDEO_CODEC_FRAME_SET_SYNC_POINT (frame); gst_adapter_unmap (adapter); /* and pass along all */ gst_video_decoder_add_to_frame (decoder, av); return gst_video_decoder_have_frame (decoder); }
/** * gst_adapter_clear: * @adapter: a #GstAdapter * * Removes all buffers from @adapter. */ void gst_adapter_clear (GstAdapter * adapter) { g_return_if_fail (GST_IS_ADAPTER (adapter)); if (adapter->info.memory) gst_adapter_unmap (adapter); g_slist_foreach (adapter->buflist, (GFunc) gst_mini_object_unref, NULL); g_slist_free (adapter->buflist); adapter->buflist = NULL; adapter->buflist_end = NULL; adapter->size = 0; adapter->skip = 0; adapter->assembled_len = 0; adapter->pts = GST_CLOCK_TIME_NONE; adapter->pts_distance = 0; adapter->dts = GST_CLOCK_TIME_NONE; adapter->dts_distance = 0; adapter->scan_offset = 0; adapter->scan_entry = NULL; }
static GstFlowReturn gst_mim_dec_chain (GstPad * pad, GstObject * parent, GstBuffer * buf) { GstMimDec *mimdec = GST_MIM_DEC (parent); GstBuffer *out_buf; const guchar *header, *frame_body; guint32 fourcc; guint16 header_size; gint width, height; GstCaps *caps; GstFlowReturn res = GST_FLOW_OK; GstClockTime in_time = GST_BUFFER_TIMESTAMP (buf); GstEvent *event = NULL; gboolean result = TRUE; guint32 payload_size; guint32 current_ts; GstMapInfo map; gst_adapter_push (mimdec->adapter, buf); /* do we have enough bytes to read a header */ while (gst_adapter_available (mimdec->adapter) >= 24) { header = gst_adapter_map (mimdec->adapter, 24); header_size = header[0]; if (header_size != 24) { gst_adapter_unmap (mimdec->adapter); gst_adapter_flush (mimdec->adapter, 24); GST_ELEMENT_ERROR (mimdec, STREAM, DECODE, (NULL), ("invalid frame: header size %d incorrect", header_size)); return GST_FLOW_ERROR; } if (header[1] == 1) { /* This is a a paused frame, skip it */ gst_adapter_unmap (mimdec->adapter); gst_adapter_flush (mimdec->adapter, 24); continue; } fourcc = GUINT32_FROM_LE (*((guint32 *) (header + 12))); if (GST_MAKE_FOURCC ('M', 'L', '2', '0') != fourcc) { gst_adapter_unmap (mimdec->adapter); gst_adapter_flush (mimdec->adapter, 24); GST_ELEMENT_ERROR (mimdec, STREAM, WRONG_TYPE, (NULL), ("invalid frame: unknown FOURCC code %X (%" GST_FOURCC_FORMAT ")", fourcc, GST_FOURCC_ARGS (fourcc))); return GST_FLOW_ERROR; } payload_size = GUINT32_FROM_LE (*((guint32 *) (header + 8))); current_ts = GUINT32_FROM_LE (*((guint32 *) (header + 20))); gst_adapter_unmap (mimdec->adapter); GST_LOG_OBJECT (mimdec, "Got packet, payload size %d", payload_size); if (gst_adapter_available (mimdec->adapter) < payload_size + 24) return GST_FLOW_OK; /* We have a whole packet and have read the header, lets flush it out */ gst_adapter_flush (mimdec->adapter, 24); frame_body = gst_adapter_map (mimdec->adapter, payload_size); if (mimdec->buffer_size < 0) { /* Check if its a keyframe, otherwise skip it */ if (GUINT32_FROM_LE (*((guint32 *) (frame_body + 12))) != 0) { gst_adapter_unmap (mimdec->adapter); gst_adapter_flush (mimdec->adapter, payload_size); return GST_FLOW_OK; } if (!mimic_decoder_init (mimdec->dec, frame_body)) { gst_adapter_unmap (mimdec->adapter); gst_adapter_flush (mimdec->adapter, payload_size); GST_ELEMENT_ERROR (mimdec, LIBRARY, INIT, (NULL), ("mimic_decoder_init error")); return GST_FLOW_ERROR; } if (!mimic_get_property (mimdec->dec, "buffer_size", &mimdec->buffer_size)) { gst_adapter_unmap (mimdec->adapter); gst_adapter_flush (mimdec->adapter, payload_size); GST_ELEMENT_ERROR (mimdec, LIBRARY, INIT, (NULL), ("mimic_get_property('buffer_size') error")); return GST_FLOW_ERROR; } mimic_get_property (mimdec->dec, "width", &width); mimic_get_property (mimdec->dec, "height", &height); GST_DEBUG_OBJECT (mimdec, "Initialised decoder with %d x %d payload size %d buffer_size %d", width, height, payload_size, mimdec->buffer_size); caps = gst_caps_new_simple ("video/x-raw", "format", G_TYPE_STRING, "RGB", "framerate", GST_TYPE_FRACTION, 0, 1, "width", G_TYPE_INT, width, "height", G_TYPE_INT, height, NULL); gst_pad_set_caps (mimdec->srcpad, caps); gst_caps_unref (caps); } if (mimdec->need_segment) { GstSegment segment; gst_segment_init (&segment, GST_FORMAT_TIME); if (GST_CLOCK_TIME_IS_VALID (in_time)) segment.start = in_time; else segment.start = current_ts * GST_MSECOND; event = gst_event_new_segment (&segment); } mimdec->need_segment = FALSE; if (event) result = gst_pad_push_event (mimdec->srcpad, event); event = NULL; if (!result) { GST_WARNING_OBJECT (mimdec, "gst_pad_push_event failed"); return GST_FLOW_ERROR; } out_buf = gst_buffer_new_allocate (NULL, mimdec->buffer_size, NULL); gst_buffer_map (out_buf, &map, GST_MAP_READWRITE); if (!mimic_decode_frame (mimdec->dec, frame_body, map.data)) { GST_WARNING_OBJECT (mimdec, "mimic_decode_frame error\n"); gst_adapter_flush (mimdec->adapter, payload_size); gst_buffer_unmap (out_buf, &map); gst_buffer_unref (out_buf); GST_ELEMENT_ERROR (mimdec, STREAM, DECODE, (NULL), ("mimic_decode_frame error")); return GST_FLOW_ERROR; } gst_buffer_unmap (out_buf, &map); gst_adapter_flush (mimdec->adapter, payload_size); if (GST_CLOCK_TIME_IS_VALID (in_time)) GST_BUFFER_TIMESTAMP (out_buf) = in_time; else GST_BUFFER_TIMESTAMP (out_buf) = current_ts * GST_MSECOND; res = gst_pad_push (mimdec->srcpad, out_buf); if (res != GST_FLOW_OK) break; } return res; }
static GstVaapiDecoderStatus gst_vaapi_decoder_jpeg_parse (GstVaapiDecoder * base_decoder, GstAdapter * adapter, gboolean at_eos, GstVaapiDecoderUnit * unit) { GstVaapiDecoderJpeg *const decoder = GST_VAAPI_DECODER_JPEG_CAST (base_decoder); GstVaapiDecoderJpegPrivate *const priv = &decoder->priv; GstVaapiParserState *const ps = GST_VAAPI_PARSER_STATE (base_decoder); GstVaapiDecoderStatus status; GstJpegMarker marker; GstJpegSegment seg; const guchar *buf; guint buf_size, flags; gint ofs1, ofs2; status = ensure_decoder (decoder); if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) return status; /* Expect at least 2 bytes for the marker */ buf_size = gst_adapter_available (adapter); if (buf_size < 2) return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA; buf = gst_adapter_map (adapter, buf_size); if (!buf) return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA; ofs1 = ps->input_offset1 - 2; if (ofs1 < 0) ofs1 = 0; for (;;) { // Skip any garbage until we reach SOI, if needed if (!gst_jpeg_parse (&seg, buf, buf_size, ofs1)) { gst_adapter_unmap (adapter); ps->input_offset1 = buf_size; return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA; } ofs1 = seg.offset; marker = seg.marker; if (!VALID_STATE (parser, GOT_SOI) && marker != GST_JPEG_MARKER_SOI) continue; if (marker == GST_JPEG_MARKER_SOS) { ofs2 = ps->input_offset2 - 2; if (ofs2 < ofs1 + seg.size) ofs2 = ofs1 + seg.size; // Parse the whole scan + ECSs, including RSTi for (;;) { if (!gst_jpeg_parse (&seg, buf, buf_size, ofs2)) { gst_adapter_unmap (adapter); ps->input_offset1 = ofs1; ps->input_offset2 = buf_size; return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA; } if (is_scan_complete (seg.marker)) break; ofs2 = seg.offset + seg.size; } ofs2 = seg.offset - 2; } else { // Check that the whole segment is actually available (in buffer) ofs2 = ofs1 + seg.size; if (ofs2 > buf_size) { gst_adapter_unmap (adapter); ps->input_offset1 = ofs1; return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA; } } break; } gst_adapter_unmap (adapter); unit->size = ofs2 - ofs1; unit_set_marker_code (unit, marker); gst_adapter_flush (adapter, ofs1); ps->input_offset1 = 2; ps->input_offset2 = 2; flags = 0; switch (marker) { case GST_JPEG_MARKER_SOI: flags |= GST_VAAPI_DECODER_UNIT_FLAG_FRAME_START; priv->parser_state |= GST_JPEG_VIDEO_STATE_GOT_SOI; break; case GST_JPEG_MARKER_EOI: flags |= GST_VAAPI_DECODER_UNIT_FLAG_FRAME_END; priv->parser_state = 0; break; case GST_JPEG_MARKER_SOS: flags |= GST_VAAPI_DECODER_UNIT_FLAG_SLICE; priv->parser_state |= GST_JPEG_VIDEO_STATE_GOT_SOS; break; case GST_JPEG_MARKER_DAC: case GST_JPEG_MARKER_DHT: case GST_JPEG_MARKER_DQT: if (priv->parser_state & GST_JPEG_VIDEO_STATE_GOT_SOF) flags |= GST_VAAPI_DECODER_UNIT_FLAG_SLICE; break; case GST_JPEG_MARKER_DRI: if (priv->parser_state & GST_JPEG_VIDEO_STATE_GOT_SOS) flags |= GST_VAAPI_DECODER_UNIT_FLAG_SLICE; break; case GST_JPEG_MARKER_DNL: flags |= GST_VAAPI_DECODER_UNIT_FLAG_SLICE; break; case GST_JPEG_MARKER_COM: flags |= GST_VAAPI_DECODER_UNIT_FLAG_SKIP; break; default: /* SOFn segments */ if (marker >= GST_JPEG_MARKER_SOF_MIN && marker <= GST_JPEG_MARKER_SOF_MAX) priv->parser_state |= GST_JPEG_VIDEO_STATE_GOT_SOF; /* Application segments */ else if (marker >= GST_JPEG_MARKER_APP_MIN && marker <= GST_JPEG_MARKER_APP_MAX) flags |= GST_VAAPI_DECODER_UNIT_FLAG_SKIP; /* Reserved */ else if (marker >= 0x02 && marker <= 0xbf) flags |= GST_VAAPI_DECODER_UNIT_FLAG_SKIP; break; } GST_VAAPI_DECODER_UNIT_FLAG_SET (unit, flags); return GST_VAAPI_DECODER_STATUS_SUCCESS; }
static GstFlowReturn gst_flxdec_chain (GstPad * pad, GstObject * parent, GstBuffer * buf) { GstCaps *caps; guint avail; GstFlowReturn res = GST_FLOW_OK; GstFlxDec *flxdec; FlxHeader *flxh; g_return_val_if_fail (buf != NULL, GST_FLOW_ERROR); flxdec = (GstFlxDec *) parent; g_return_val_if_fail (flxdec != NULL, GST_FLOW_ERROR); gst_adapter_push (flxdec->adapter, buf); avail = gst_adapter_available (flxdec->adapter); if (flxdec->state == GST_FLXDEC_READ_HEADER) { if (avail >= FlxHeaderSize) { const guint8 *data = gst_adapter_map (flxdec->adapter, FlxHeaderSize); GstCaps *templ; memcpy ((gchar *) & flxdec->hdr, data, FlxHeaderSize); FLX_HDR_FIX_ENDIANNESS (&(flxdec->hdr)); gst_adapter_unmap (flxdec->adapter); gst_adapter_flush (flxdec->adapter, FlxHeaderSize); flxh = &flxdec->hdr; /* check header */ if (flxh->type != FLX_MAGICHDR_FLI && flxh->type != FLX_MAGICHDR_FLC && flxh->type != FLX_MAGICHDR_FLX) goto wrong_type; GST_LOG ("size : %d", flxh->size); GST_LOG ("frames : %d", flxh->frames); GST_LOG ("width : %d", flxh->width); GST_LOG ("height : %d", flxh->height); GST_LOG ("depth : %d", flxh->depth); GST_LOG ("speed : %d", flxh->speed); flxdec->next_time = 0; if (flxh->type == FLX_MAGICHDR_FLI) { flxdec->frame_time = JIFFIE * flxh->speed; } else if (flxh->speed == 0) { flxdec->frame_time = GST_SECOND / 70; } else { flxdec->frame_time = flxh->speed * GST_MSECOND; } flxdec->duration = flxh->frames * flxdec->frame_time; GST_LOG ("duration : %" GST_TIME_FORMAT, GST_TIME_ARGS (flxdec->duration)); templ = gst_pad_get_pad_template_caps (flxdec->srcpad); caps = gst_caps_copy (templ); gst_caps_unref (templ); gst_caps_set_simple (caps, "width", G_TYPE_INT, flxh->width, "height", G_TYPE_INT, flxh->height, "framerate", GST_TYPE_FRACTION, (gint) GST_MSECOND, (gint) flxdec->frame_time / 1000, NULL); gst_pad_set_caps (flxdec->srcpad, caps); gst_caps_unref (caps); if (flxh->depth <= 8) flxdec->converter = flx_colorspace_converter_new (flxh->width, flxh->height); if (flxh->type == FLX_MAGICHDR_FLC || flxh->type == FLX_MAGICHDR_FLX) { GST_LOG ("(FLC) aspect_dx : %d", flxh->aspect_dx); GST_LOG ("(FLC) aspect_dy : %d", flxh->aspect_dy); GST_LOG ("(FLC) oframe1 : 0x%08x", flxh->oframe1); GST_LOG ("(FLC) oframe2 : 0x%08x", flxh->oframe2); } flxdec->size = (flxh->width * flxh->height); /* create delta and output frame */ flxdec->frame_data = g_malloc (flxdec->size); flxdec->delta_data = g_malloc (flxdec->size); flxdec->state = GST_FLXDEC_PLAYING; } } else if (flxdec->state == GST_FLXDEC_PLAYING) { GstBuffer *out; /* while we have enough data in the adapter */ while (avail >= FlxFrameChunkSize && res == GST_FLOW_OK) { FlxFrameChunk flxfh; guchar *chunk; const guint8 *data; GstMapInfo map; chunk = NULL; data = gst_adapter_map (flxdec->adapter, FlxFrameChunkSize); memcpy (&flxfh, data, FlxFrameChunkSize); FLX_FRAME_CHUNK_FIX_ENDIANNESS (&flxfh); gst_adapter_unmap (flxdec->adapter); switch (flxfh.id) { case FLX_FRAME_TYPE: /* check if we have the complete frame */ if (avail < flxfh.size) goto need_more_data; /* flush header */ gst_adapter_flush (flxdec->adapter, FlxFrameChunkSize); chunk = gst_adapter_take (flxdec->adapter, flxfh.size - FlxFrameChunkSize); FLX_FRAME_TYPE_FIX_ENDIANNESS ((FlxFrameType *) chunk); if (((FlxFrameType *) chunk)->chunks == 0) break; /* create 32 bits output frame */ // res = gst_pad_alloc_buffer_and_set_caps (flxdec->srcpad, // GST_BUFFER_OFFSET_NONE, // flxdec->size * 4, GST_PAD_CAPS (flxdec->srcpad), &out); // if (res != GST_FLOW_OK) // break; out = gst_buffer_new_and_alloc (flxdec->size * 4); /* decode chunks */ flx_decode_chunks (flxdec, ((FlxFrameType *) chunk)->chunks, chunk + FlxFrameTypeSize, flxdec->frame_data); /* save copy of the current frame for possible delta. */ memcpy (flxdec->delta_data, flxdec->frame_data, flxdec->size); gst_buffer_map (out, &map, GST_MAP_WRITE); /* convert current frame. */ flx_colorspace_convert (flxdec->converter, flxdec->frame_data, map.data); gst_buffer_unmap (out, &map); GST_BUFFER_TIMESTAMP (out) = flxdec->next_time; flxdec->next_time += flxdec->frame_time; res = gst_pad_push (flxdec->srcpad, out); break; default: /* check if we have the complete frame */ if (avail < flxfh.size) goto need_more_data; gst_adapter_flush (flxdec->adapter, flxfh.size); break; } if (chunk) g_free (chunk); avail = gst_adapter_available (flxdec->adapter); } } need_more_data: return res; /* ERRORS */ wrong_type: { GST_ELEMENT_ERROR (flxdec, STREAM, WRONG_TYPE, (NULL), ("not a flx file (type %x)", flxh->type)); gst_object_unref (flxdec); return GST_FLOW_ERROR; } }
static GstFlowReturn gst_asf_parse_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer) { GstAsfParse *asfparse; GstFlowReturn ret = GST_FLOW_OK; asfparse = GST_ASF_PARSE (parent); gst_adapter_push (asfparse->adapter, buffer); switch (asfparse->parse_state) { case ASF_PARSING_HEADERS: if (asfparse->headers_size == 0 && gst_adapter_available (asfparse->adapter) >= ASF_GUID_OBJSIZE_SIZE) { /* we can peek at the object size */ asfparse->headers_size = gst_asf_match_and_peek_obj_size (gst_adapter_map (asfparse->adapter, ASF_GUID_OBJSIZE_SIZE), &(guids[ASF_HEADER_OBJECT_INDEX])); gst_adapter_unmap (asfparse->adapter); if (asfparse->headers_size == 0) { /* something is wrong, this probably ain't an ASF stream */ GST_ERROR_OBJECT (asfparse, "ASF starting identifier missing"); ret = GST_FLOW_ERROR; goto end; } } if (gst_adapter_available (asfparse->adapter) >= asfparse->headers_size) { GstBuffer *headers = gst_adapter_take_buffer (asfparse->adapter, asfparse->headers_size); if (gst_asf_parse_headers (headers, asfparse->asfinfo)) { ret = gst_asf_parse_push (asfparse, headers); asfparse->parse_state = ASF_PARSING_DATA; } else { ret = GST_FLOW_ERROR; GST_ERROR_OBJECT (asfparse, "Failed to parse headers"); } } break; case ASF_PARSING_DATA: if (asfparse->data_size == 0 && gst_adapter_available (asfparse->adapter) >= ASF_GUID_OBJSIZE_SIZE) { /* we can peek at the object size */ asfparse->data_size = gst_asf_match_and_peek_obj_size (gst_adapter_map (asfparse->adapter, ASF_GUID_OBJSIZE_SIZE), &(guids[ASF_DATA_OBJECT_INDEX])); gst_adapter_unmap (asfparse->adapter); if (asfparse->data_size == 0) { /* something is wrong */ GST_ERROR_OBJECT (asfparse, "Unexpected object after headers, was " "expecting a data object"); ret = GST_FLOW_ERROR; goto end; } } /* if we have received the full data object headers */ if (gst_adapter_available (asfparse->adapter) >= ASF_DATA_OBJECT_SIZE) { ret = gst_asf_parse_parse_data_object (asfparse, gst_adapter_take_buffer (asfparse->adapter, ASF_DATA_OBJECT_SIZE)); if (ret != GST_FLOW_OK) { goto end; } asfparse->parse_state = ASF_PARSING_PACKETS; } break; case ASF_PARSING_PACKETS: g_assert (asfparse->asfinfo->packet_size); while ((asfparse->asfinfo->broadcast || asfparse->parsed_packets < asfparse->asfinfo->packets_count) && gst_adapter_available (asfparse->adapter) >= asfparse->asfinfo->packet_size) { GstBuffer *packet = gst_adapter_take_buffer (asfparse->adapter, asfparse->asfinfo->packet_size); asfparse->parsed_packets++; ret = gst_asf_parse_parse_packet (asfparse, packet); if (ret != GST_FLOW_OK) goto end; } if (!asfparse->asfinfo->broadcast && asfparse->parsed_packets >= asfparse->asfinfo->packets_count) { GST_INFO_OBJECT (asfparse, "Finished parsing packets"); asfparse->parse_state = ASF_PARSING_INDEXES; } break; case ASF_PARSING_INDEXES: /* we currently don't care about any of those objects */ if (gst_adapter_available (asfparse->adapter) >= ASF_GUID_OBJSIZE_SIZE) { guint64 obj_size; /* we can peek at the object size */ obj_size = gst_asf_match_and_peek_obj_size (gst_adapter_map (asfparse->adapter, ASF_GUID_OBJSIZE_SIZE), NULL); gst_adapter_unmap (asfparse->adapter); if (gst_adapter_available (asfparse->adapter) >= obj_size) { GST_DEBUG_OBJECT (asfparse, "Skiping object"); ret = gst_asf_parse_push (asfparse, gst_adapter_take_buffer (asfparse->adapter, obj_size)); if (ret != GST_FLOW_OK) { goto end; } } } break; default: break; } end: return ret; }
static GstFlowReturn gst_type_find_element_chain_do_typefinding (GstTypeFindElement * typefind, gboolean check_avail, gboolean at_eos) { GstTypeFindProbability probability; GstCaps *caps = NULL; gsize avail; const guint8 *data; gboolean have_min, have_max; GST_OBJECT_LOCK (typefind); if (typefind->force_caps) { caps = gst_caps_ref (typefind->force_caps); probability = GST_TYPE_FIND_MAXIMUM; } if (!caps) { avail = gst_adapter_available (typefind->adapter); if (check_avail) { have_min = avail >= TYPE_FIND_MIN_SIZE; have_max = avail >= TYPE_FIND_MAX_SIZE; } else { have_min = avail > 0; have_max = TRUE; } if (!have_min) goto not_enough_data; /* map all available data */ data = gst_adapter_map (typefind->adapter, avail); caps = gst_type_find_helper_for_data (GST_OBJECT (typefind), data, avail, &probability); gst_adapter_unmap (typefind->adapter); if (caps == NULL && have_max) goto no_type_found; else if (caps == NULL) goto wait_for_data; /* found a type */ if (probability < typefind->min_probability) goto low_probability; } GST_OBJECT_UNLOCK (typefind); /* probability is good enough too, so let's make it known ... emiting this * signal calls our object handler which sets the caps. */ gst_type_find_element_emit_have_type (typefind, probability, caps); /* .. and send out the accumulated data */ stop_typefinding (typefind); gst_caps_unref (caps); return GST_FLOW_OK; not_enough_data: { GST_OBJECT_UNLOCK (typefind); if (at_eos) { GST_ELEMENT_ERROR (typefind, STREAM, TYPE_NOT_FOUND, (_("Stream doesn't contain enough data.")), ("Can't typefind stream")); return GST_FLOW_ERROR; } else { GST_DEBUG_OBJECT (typefind, "not enough data for typefinding yet " "(%" G_GSIZE_FORMAT " bytes)", avail); return GST_FLOW_OK; } } no_type_found: { GST_OBJECT_UNLOCK (typefind); GST_ELEMENT_ERROR (typefind, STREAM, TYPE_NOT_FOUND, (NULL), (NULL)); stop_typefinding (typefind); return GST_FLOW_ERROR; } wait_for_data: { GST_OBJECT_UNLOCK (typefind); if (at_eos) { GST_ELEMENT_ERROR (typefind, STREAM, TYPE_NOT_FOUND, (_("Stream doesn't contain enough data.")), ("Can't typefind stream")); return GST_FLOW_ERROR; } else { GST_DEBUG_OBJECT (typefind, "no caps found with %" G_GSIZE_FORMAT " bytes of data, " "waiting for more data", avail); return GST_FLOW_OK; } } low_probability: { GST_DEBUG_OBJECT (typefind, "found caps %" GST_PTR_FORMAT ", but " "probability is %u which is lower than the required minimum of %u", caps, probability, typefind->min_probability); gst_caps_unref (caps); if (have_max) goto no_type_found; GST_OBJECT_UNLOCK (typefind); GST_DEBUG_OBJECT (typefind, "waiting for more data to try again"); return GST_FLOW_OK; } }
static GstFlowReturn gst_real_audio_demux_parse_header (GstRealAudioDemux * demux) { const guint8 *data; gchar *codec_name = NULL; GstCaps *caps = NULL; GstEvent *event; gchar *stream_id; guint avail; g_assert (demux->ra_version == 4 || demux->ra_version == 3); avail = gst_adapter_available (demux->adapter); if (avail < 16) return GST_FLOW_OK; if (!gst_real_audio_demux_get_data_offset_from_header (demux)) return GST_FLOW_ERROR; /* shouldn't happen */ GST_DEBUG_OBJECT (demux, "data_offset = %u", demux->data_offset); if (avail + 6 < demux->data_offset) { GST_DEBUG_OBJECT (demux, "Need %u bytes, but only %u available now", demux->data_offset - 6, avail); return GST_FLOW_OK; } data = gst_adapter_map (demux->adapter, demux->data_offset - 6); g_assert (data); switch (demux->ra_version) { case 3: demux->fourcc = GST_RM_AUD_14_4; demux->packet_size = 20; demux->sample_rate = 8000; demux->channels = 1; demux->sample_width = 16; demux->flavour = 1; demux->leaf_size = 0; demux->height = 0; break; case 4: demux->flavour = GST_READ_UINT16_BE (data + 16); /* demux->frame_size = GST_READ_UINT32_BE (data + 36); */ demux->leaf_size = GST_READ_UINT16_BE (data + 38); demux->height = GST_READ_UINT16_BE (data + 34); demux->packet_size = GST_READ_UINT32_BE (data + 18); demux->sample_rate = GST_READ_UINT16_BE (data + 42); demux->sample_width = GST_READ_UINT16_BE (data + 46); demux->channels = GST_READ_UINT16_BE (data + 48); demux->fourcc = GST_READ_UINT32_LE (data + 56); demux->pending_tags = gst_rm_utils_read_tags (data + 63, demux->data_offset - 63, gst_rm_utils_read_string8); if (demux->pending_tags) gst_tag_list_set_scope (demux->pending_tags, GST_TAG_SCOPE_GLOBAL); break; default: g_assert_not_reached (); #if 0 case 5: demux->flavour = GST_READ_UINT16_BE (data + 16); /* demux->frame_size = GST_READ_UINT32_BE (data + 36); */ demux->leaf_size = GST_READ_UINT16_BE (data + 38); demux->height = GST_READ_UINT16_BE (data + 34); demux->sample_rate = GST_READ_UINT16_BE (data + 48); demux->sample_width = GST_READ_UINT16_BE (data + 52); demux->n_channels = GST_READ_UINT16_BE (data + 54); demux->fourcc = RMDEMUX_FOURCC_GET (data + 60); break; #endif } GST_INFO_OBJECT (demux, "packet_size = %u", demux->packet_size); GST_INFO_OBJECT (demux, "sample_rate = %u", demux->sample_rate); GST_INFO_OBJECT (demux, "sample_width = %u", demux->sample_width); GST_INFO_OBJECT (demux, "channels = %u", demux->channels); GST_INFO_OBJECT (demux, "fourcc = '%" GST_FOURCC_FORMAT "' (%08X)", GST_FOURCC_ARGS (demux->fourcc), demux->fourcc); switch (demux->fourcc) { case GST_RM_AUD_14_4: caps = gst_caps_new_simple ("audio/x-pn-realaudio", "raversion", G_TYPE_INT, 1, NULL); demux->byterate_num = 1000; demux->byterate_denom = 1; break; case GST_RM_AUD_28_8: /* FIXME: needs descrambling */ caps = gst_caps_new_simple ("audio/x-pn-realaudio", "raversion", G_TYPE_INT, 2, NULL); break; case GST_RM_AUD_DNET: caps = gst_caps_new_simple ("audio/x-ac3", "rate", G_TYPE_INT, demux->sample_rate, NULL); if (demux->packet_size == 0 || demux->sample_rate == 0) goto broken_file; demux->byterate_num = demux->packet_size * demux->sample_rate; demux->byterate_denom = 1536; break; /* Sipro/ACELP.NET Voice Codec (MIME unknown) */ case GST_RM_AUD_SIPR: caps = gst_caps_new_empty_simple ("audio/x-sipro"); break; default: GST_WARNING_OBJECT (demux, "unknown fourcc %08X", demux->fourcc); break; } if (caps == NULL) goto unknown_fourcc; gst_caps_set_simple (caps, "flavor", G_TYPE_INT, demux->flavour, "rate", G_TYPE_INT, demux->sample_rate, "channels", G_TYPE_INT, demux->channels, "width", G_TYPE_INT, demux->sample_width, "leaf_size", G_TYPE_INT, demux->leaf_size, "packet_size", G_TYPE_INT, demux->packet_size, "height", G_TYPE_INT, demux->height, NULL); GST_INFO_OBJECT (demux, "Adding source pad, caps %" GST_PTR_FORMAT, caps); demux->srcpad = gst_pad_new_from_static_template (&src_template, "src"); gst_pad_set_event_function (demux->srcpad, GST_DEBUG_FUNCPTR (gst_real_audio_demux_src_event)); gst_pad_set_query_function (demux->srcpad, GST_DEBUG_FUNCPTR (gst_real_audio_demux_src_query)); gst_pad_set_active (demux->srcpad, TRUE); gst_pad_use_fixed_caps (demux->srcpad); stream_id = gst_pad_create_stream_id (demux->srcpad, GST_ELEMENT_CAST (demux), NULL); event = gst_pad_get_sticky_event (demux->sinkpad, GST_EVENT_STREAM_START, 0); if (event) { if (gst_event_parse_group_id (event, &demux->group_id)) demux->have_group_id = TRUE; else demux->have_group_id = FALSE; gst_event_unref (event); } else if (!demux->have_group_id) { demux->have_group_id = TRUE; demux->group_id = gst_util_group_id_next (); } event = gst_event_new_stream_start (stream_id); if (demux->have_group_id) gst_event_set_group_id (event, demux->group_id); gst_pad_push_event (demux->srcpad, event); g_free (stream_id); gst_pad_set_caps (demux->srcpad, caps); codec_name = gst_pb_utils_get_codec_description (caps); gst_caps_unref (caps); gst_element_add_pad (GST_ELEMENT (demux), demux->srcpad); if (demux->byterate_num > 0 && demux->byterate_denom > 0) { GstFormat bformat = GST_FORMAT_BYTES; gint64 size_bytes = 0; GST_INFO_OBJECT (demux, "byte rate = %u/%u = %u bytes/sec", demux->byterate_num, demux->byterate_denom, demux->byterate_num / demux->byterate_denom); if (gst_pad_peer_query_duration (demux->sinkpad, bformat, &size_bytes)) { demux->duration = gst_real_demux_get_timestamp_from_offset (demux, size_bytes); demux->upstream_size = size_bytes; GST_INFO_OBJECT (demux, "upstream_size = %" G_GUINT64_FORMAT, demux->upstream_size); GST_INFO_OBJECT (demux, "duration = %" GST_TIME_FORMAT, GST_TIME_ARGS (demux->duration)); } } demux->need_newsegment = TRUE; if (codec_name) { if (demux->pending_tags == NULL) { demux->pending_tags = gst_tag_list_new_empty (); gst_tag_list_set_scope (demux->pending_tags, GST_TAG_SCOPE_GLOBAL); } gst_tag_list_add (demux->pending_tags, GST_TAG_MERGE_REPLACE, GST_TAG_AUDIO_CODEC, codec_name, NULL); g_free (codec_name); } gst_adapter_unmap (demux->adapter); gst_adapter_flush (demux->adapter, demux->data_offset - 6); demux->state = REAL_AUDIO_DEMUX_STATE_DATA; demux->need_newsegment = TRUE; return GST_FLOW_OK; /* ERRORS */ unknown_fourcc: { GST_ELEMENT_ERROR (GST_ELEMENT (demux), STREAM, DECODE, (NULL), ("Unknown fourcc '%" GST_FOURCC_FORMAT "'", GST_FOURCC_ARGS (demux->fourcc))); return GST_FLOW_ERROR; } broken_file: { GST_ELEMENT_ERROR (GST_ELEMENT (demux), STREAM, DECODE, (NULL), ("Broken file - invalid sample_rate or other header value")); return GST_FLOW_ERROR; } }
static GstFlowReturn gst_rtp_h263p_pay_flush (GstRtpH263PPay * rtph263ppay) { guint avail; GstBuffer *outbuf; GstFlowReturn ret; gboolean fragmented; avail = gst_adapter_available (rtph263ppay->adapter); if (avail == 0) return GST_FLOW_OK; fragmented = FALSE; /* This algorithm assumes the H263/+/++ encoder sends complete frames in each * buffer */ /* With Fragmentation Mode at GST_FRAGMENTATION_MODE_NORMAL: * This algorithm implements the Follow-on packets method for packetization. * This assumes low packet loss network. * With Fragmentation Mode at GST_FRAGMENTATION_MODE_SYNC: * This algorithm separates large frames at synchronisation points (Segments) * (See RFC 4629 section 6). It would be interesting to have a property such as network * quality to select between both packetization methods */ /* TODO Add VRC supprt (See RFC 4629 section 5.2) */ while (avail > 0) { guint towrite; guint8 *payload; guint payload_len; gint header_len; guint next_gop = 0; gboolean found_gob = FALSE; GstRTPBuffer rtp = { NULL }; if (rtph263ppay->fragmentation_mode == GST_FRAGMENTATION_MODE_SYNC) { /* start after 1st gop possible */ guint parsed_len = 3; const guint8 *parse_data = NULL; parse_data = gst_adapter_map (rtph263ppay->adapter, avail); /* Check if we have a gob or eos , eossbs */ /* FIXME EOS and EOSSBS packets should never contain any gobs and vice-versa */ if (avail >= 3 && *parse_data == 0 && *(parse_data + 1) == 0 && *(parse_data + 2) >= 0x80) { GST_DEBUG_OBJECT (rtph263ppay, " Found GOB header"); found_gob = TRUE; } /* Find next and cut the packet accordingly */ /* TODO we should get as many gobs as possible until MTU is reached, this * code seems to just get one GOB per packet */ while (parsed_len + 2 < avail) { if (parse_data[parsed_len] == 0 && parse_data[parsed_len + 1] == 0 && parse_data[parsed_len + 2] >= 0x80) { next_gop = parsed_len; GST_DEBUG_OBJECT (rtph263ppay, " Next GOB Detected at : %d", next_gop); break; } parsed_len++; } gst_adapter_unmap (rtph263ppay->adapter); } /* for picture start frames (non-fragmented), we need to remove the first * two 0x00 bytes and set P=1 */ header_len = (fragmented && !found_gob) ? 2 : 0; towrite = MIN (avail, gst_rtp_buffer_calc_payload_len (GST_RTP_BASE_PAYLOAD_MTU (rtph263ppay) - header_len, 0, 0)); if (next_gop > 0) towrite = MIN (next_gop, towrite); payload_len = header_len + towrite; outbuf = gst_rtp_buffer_new_allocate (payload_len, 0, 0); gst_rtp_buffer_map (outbuf, GST_MAP_WRITE, &rtp); /* last fragment gets the marker bit set */ gst_rtp_buffer_set_marker (&rtp, avail > towrite ? 0 : 1); payload = gst_rtp_buffer_get_payload (&rtp); gst_adapter_copy (rtph263ppay->adapter, &payload[header_len], 0, towrite); /* 0 1 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | RR |P|V| PLEN |PEBIT| * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ /* if fragmented or gop header , write p bit =1 */ payload[0] = (fragmented && !found_gob) ? 0x00 : 0x04; payload[1] = 0; GST_BUFFER_TIMESTAMP (outbuf) = rtph263ppay->first_timestamp; GST_BUFFER_DURATION (outbuf) = rtph263ppay->first_duration; gst_rtp_buffer_unmap (&rtp); gst_adapter_flush (rtph263ppay->adapter, towrite); ret = gst_rtp_base_payload_push (GST_RTP_BASE_PAYLOAD (rtph263ppay), outbuf); avail -= towrite; fragmented = TRUE; } return ret; }
static GstFlowReturn gst_gdp_depay_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer) { GstGDPDepay *this; GstFlowReturn ret = GST_FLOW_OK; GstCaps *caps; GstBuffer *buf; GstEvent *event; guint available; this = GST_GDP_DEPAY (parent); /* On DISCONT, get rid of accumulated data. We assume a buffer after the * DISCONT contains (part of) a new valid header, if not we error because we * lost sync */ if (GST_BUFFER_IS_DISCONT (buffer)) { gst_adapter_clear (this->adapter); this->state = GST_GDP_DEPAY_STATE_HEADER; } gst_adapter_push (this->adapter, buffer); while (TRUE) { switch (this->state) { case GST_GDP_DEPAY_STATE_HEADER: { guint8 *header; /* collect a complete header, validate and store the header. Figure out * the payload length and switch to the PAYLOAD state */ available = gst_adapter_available (this->adapter); if (available < GST_DP_HEADER_LENGTH) goto done; GST_LOG_OBJECT (this, "reading GDP header from adapter"); header = gst_adapter_take (this->adapter, GST_DP_HEADER_LENGTH); if (!gst_dp_validate_header (GST_DP_HEADER_LENGTH, header)) { g_free (header); goto header_validate_error; } /* store types and payload length. Also store the header, which we need * to make the payload. */ this->payload_length = gst_dp_header_payload_length (header); this->payload_type = gst_dp_header_payload_type (header); /* free previous header and store new one. */ g_free (this->header); this->header = header; GST_LOG_OBJECT (this, "read GDP header, payload size %d, payload type %d, switching to state PAYLOAD", this->payload_length, this->payload_type); this->state = GST_GDP_DEPAY_STATE_PAYLOAD; break; } case GST_GDP_DEPAY_STATE_PAYLOAD: { /* in this state we wait for all the payload data to be available in the * adapter. Then we switch to the state where we actually process the * payload. */ available = gst_adapter_available (this->adapter); if (available < this->payload_length) goto done; /* change state based on type */ if (this->payload_type == GST_DP_PAYLOAD_BUFFER) { GST_LOG_OBJECT (this, "switching to state BUFFER"); this->state = GST_GDP_DEPAY_STATE_BUFFER; } else if (this->payload_type == GST_DP_PAYLOAD_CAPS) { GST_LOG_OBJECT (this, "switching to state CAPS"); this->state = GST_GDP_DEPAY_STATE_CAPS; } else if (this->payload_type >= GST_DP_PAYLOAD_EVENT_NONE) { GST_LOG_OBJECT (this, "switching to state EVENT"); this->state = GST_GDP_DEPAY_STATE_EVENT; } else { goto wrong_type; } if (this->payload_length) { const guint8 *data; gboolean res; data = gst_adapter_map (this->adapter, this->payload_length); res = gst_dp_validate_payload (GST_DP_HEADER_LENGTH, this->header, data); gst_adapter_unmap (this->adapter); if (!res) goto payload_validate_error; } break; } case GST_GDP_DEPAY_STATE_BUFFER: { /* if we receive a buffer without caps first, we error out */ if (!this->caps) goto no_caps; GST_LOG_OBJECT (this, "reading GDP buffer from adapter"); buf = gst_dp_buffer_from_header (GST_DP_HEADER_LENGTH, this->header); if (!buf) goto buffer_failed; /* now take the payload if there is any */ if (this->payload_length > 0) { GstMapInfo map; gst_buffer_map (buf, &map, GST_MAP_WRITE); gst_adapter_copy (this->adapter, map.data, 0, this->payload_length); gst_buffer_unmap (buf, &map); gst_adapter_flush (this->adapter, this->payload_length); } /* set caps and push */ GST_LOG_OBJECT (this, "deserialized buffer %p, pushing, timestamp %" GST_TIME_FORMAT ", duration %" GST_TIME_FORMAT ", offset %" G_GINT64_FORMAT ", offset_end %" G_GINT64_FORMAT ", size %" G_GSIZE_FORMAT ", flags 0x%x", buf, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)), GST_TIME_ARGS (GST_BUFFER_DURATION (buf)), GST_BUFFER_OFFSET (buf), GST_BUFFER_OFFSET_END (buf), gst_buffer_get_size (buf), GST_BUFFER_FLAGS (buf)); ret = gst_pad_push (this->srcpad, buf); if (ret != GST_FLOW_OK) goto push_error; GST_LOG_OBJECT (this, "switching to state HEADER"); this->state = GST_GDP_DEPAY_STATE_HEADER; break; } case GST_GDP_DEPAY_STATE_CAPS: { guint8 *payload; /* take the payload of the caps */ GST_LOG_OBJECT (this, "reading GDP caps from adapter"); payload = gst_adapter_take (this->adapter, this->payload_length); caps = gst_dp_caps_from_packet (GST_DP_HEADER_LENGTH, this->header, payload); g_free (payload); if (!caps) goto caps_failed; GST_DEBUG_OBJECT (this, "deserialized caps %" GST_PTR_FORMAT, caps); gst_caps_replace (&(this->caps), caps); gst_pad_set_caps (this->srcpad, caps); /* drop the creation ref we still have */ gst_caps_unref (caps); GST_LOG_OBJECT (this, "switching to state HEADER"); this->state = GST_GDP_DEPAY_STATE_HEADER; break; } case GST_GDP_DEPAY_STATE_EVENT: { guint8 *payload; GST_LOG_OBJECT (this, "reading GDP event from adapter"); /* adapter doesn't like 0 length payload */ if (this->payload_length > 0) payload = gst_adapter_take (this->adapter, this->payload_length); else payload = NULL; event = gst_dp_event_from_packet (GST_DP_HEADER_LENGTH, this->header, payload); g_free (payload); if (!event) goto event_failed; GST_DEBUG_OBJECT (this, "deserialized event %p of type %s, pushing", event, gst_event_type_get_name (event->type)); gst_pad_push_event (this->srcpad, event); GST_LOG_OBJECT (this, "switching to state HEADER"); this->state = GST_GDP_DEPAY_STATE_HEADER; break; } } } done: return ret; /* ERRORS */ header_validate_error: { GST_ELEMENT_ERROR (this, STREAM, DECODE, (NULL), ("GDP packet header does not validate")); ret = GST_FLOW_ERROR; goto done; } payload_validate_error: { GST_ELEMENT_ERROR (this, STREAM, DECODE, (NULL), ("GDP packet payload does not validate")); ret = GST_FLOW_ERROR; goto done; } wrong_type: { GST_ELEMENT_ERROR (this, STREAM, DECODE, (NULL), ("GDP packet header is of wrong type")); ret = GST_FLOW_ERROR; goto done; } no_caps: { GST_ELEMENT_ERROR (this, STREAM, DECODE, (NULL), ("Received a buffer without first receiving caps")); ret = GST_FLOW_NOT_NEGOTIATED; goto done; } buffer_failed: { GST_ELEMENT_ERROR (this, STREAM, DECODE, (NULL), ("could not create buffer from GDP packet")); ret = GST_FLOW_ERROR; goto done; } push_error: { GST_WARNING_OBJECT (this, "pushing depayloaded buffer returned %d", ret); goto done; } caps_failed: { GST_ELEMENT_ERROR (this, STREAM, DECODE, (NULL), ("could not create caps from GDP packet")); ret = GST_FLOW_ERROR; goto done; } event_failed: { GST_ELEMENT_ERROR (this, STREAM, DECODE, (NULL), ("could not create event from GDP packet")); ret = GST_FLOW_ERROR; goto done; } }
static GstFlowReturn gst_goom_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer) { GstGoom *goom; GstFlowReturn ret; GstBuffer *outbuf = NULL; goom = GST_GOOM (parent); if (goom->bps == 0) { gst_buffer_unref (buffer); ret = GST_FLOW_NOT_NEGOTIATED; goto beach; } /* Make sure have an output format */ ret = ensure_negotiated (goom); if (ret != GST_FLOW_OK) { gst_buffer_unref (buffer); goto beach; } /* don't try to combine samples from discont buffer */ if (GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DISCONT)) { gst_adapter_clear (goom->adapter); } GST_DEBUG_OBJECT (goom, "Input buffer has %" G_GSIZE_FORMAT " samples, time=%" G_GUINT64_FORMAT, gst_buffer_get_size (buffer) / goom->bps, GST_BUFFER_TIMESTAMP (buffer)); /* Collect samples until we have enough for an output frame */ gst_adapter_push (goom->adapter, buffer); ret = GST_FLOW_OK; while (TRUE) { const guint16 *data; guchar *out_frame; gint i; guint avail, to_flush; guint64 dist, timestamp; avail = gst_adapter_available (goom->adapter); GST_DEBUG_OBJECT (goom, "avail now %u", avail); /* we need GOOM_SAMPLES to get a meaningful result from goom. */ if (avail < (GOOM_SAMPLES * goom->bps)) break; /* we also need enough samples to produce one frame at least */ if (avail < goom->bpf) break; GST_DEBUG_OBJECT (goom, "processing buffer"); /* get timestamp of the current adapter byte */ timestamp = gst_adapter_prev_timestamp (goom->adapter, &dist); if (GST_CLOCK_TIME_IS_VALID (timestamp)) { /* convert bytes to time */ dist /= goom->bps; timestamp += gst_util_uint64_scale_int (dist, GST_SECOND, goom->rate); } if (GST_CLOCK_TIME_IS_VALID (timestamp)) { gint64 qostime; gboolean need_skip; qostime = gst_segment_to_running_time (&goom->segment, GST_FORMAT_TIME, timestamp) + goom->duration; GST_OBJECT_LOCK (goom); /* check for QoS, don't compute buffers that are known to be late */ need_skip = goom->earliest_time != -1 && qostime <= goom->earliest_time; GST_OBJECT_UNLOCK (goom); if (need_skip) { GST_WARNING_OBJECT (goom, "QoS: skip ts: %" GST_TIME_FORMAT ", earliest: %" GST_TIME_FORMAT, GST_TIME_ARGS (qostime), GST_TIME_ARGS (goom->earliest_time)); goto skip; } } /* get next GOOM_SAMPLES, we have at least this amount of samples */ data = (const guint16 *) gst_adapter_map (goom->adapter, GOOM_SAMPLES * goom->bps); if (goom->channels == 2) { for (i = 0; i < GOOM_SAMPLES; i++) { goom->datain[0][i] = *data++; goom->datain[1][i] = *data++; } } else { for (i = 0; i < GOOM_SAMPLES; i++) { goom->datain[0][i] = *data; goom->datain[1][i] = *data++; } } /* 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) { GST_DEBUG_OBJECT (goom, "allocating output buffer"); ret = gst_buffer_pool_acquire_buffer (goom->pool, &outbuf, NULL); if (ret != GST_FLOW_OK) { gst_adapter_unmap (goom->adapter); goto beach; } } GST_BUFFER_TIMESTAMP (outbuf) = timestamp; GST_BUFFER_DURATION (outbuf) = goom->duration; out_frame = (guchar *) goom_update (goom->plugin, goom->datain, 0, 0); gst_buffer_fill (outbuf, 0, out_frame, goom->outsize); gst_adapter_unmap (goom->adapter); GST_DEBUG ("Pushing frame with time=%" GST_TIME_FORMAT ", duration=%" GST_TIME_FORMAT, GST_TIME_ARGS (timestamp), GST_TIME_ARGS (goom->duration)); ret = gst_pad_push (goom->srcpad, outbuf); outbuf = NULL; skip: /* Now flush the samples we needed for this frame, which might be more than * the samples we used (GOOM_SAMPLES). */ to_flush = goom->bpf; GST_DEBUG_OBJECT (goom, "finished frame, flushing %u bytes from input", to_flush); gst_adapter_flush (goom->adapter, to_flush); if (ret != GST_FLOW_OK) break; } if (outbuf != NULL) gst_buffer_unref (outbuf); beach: return ret; }
static GstFlowReturn gst_flac_tag_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer) { GstFlacTag *tag; GstFlowReturn ret; GstMapInfo map; gsize size; ret = GST_FLOW_OK; tag = GST_FLAC_TAG (parent); gst_adapter_push (tag->adapter, buffer); /* Initial state, we don't even know if we are dealing with a flac file */ if (tag->state == GST_FLAC_TAG_STATE_INIT) { GstBuffer *id_buffer; if (gst_adapter_available (tag->adapter) < sizeof (FLAC_MAGIC)) goto cleanup; id_buffer = gst_adapter_take_buffer (tag->adapter, FLAC_MAGIC_SIZE); GST_DEBUG_OBJECT (tag, "looking for " FLAC_MAGIC " identifier"); if (gst_buffer_memcmp (id_buffer, 0, FLAC_MAGIC, FLAC_MAGIC_SIZE) == 0) { GST_DEBUG_OBJECT (tag, "pushing " FLAC_MAGIC " identifier buffer"); ret = gst_pad_push (tag->srcpad, id_buffer); if (ret != GST_FLOW_OK) goto cleanup; tag->state = GST_FLAC_TAG_STATE_METADATA_BLOCKS; } else { /* FIXME: does that work well with FLAC files containing ID3v2 tags ? */ gst_buffer_unref (id_buffer); GST_ELEMENT_ERROR (tag, STREAM, WRONG_TYPE, (NULL), (NULL)); ret = GST_FLOW_ERROR; } } /* The fLaC magic string has been skipped, try to detect the beginning * of a metadata block */ if (tag->state == GST_FLAC_TAG_STATE_METADATA_BLOCKS) { guint type; gboolean is_last; const guint8 *block_header; g_assert (tag->metadata_block_size == 0); g_assert (tag->metadata_last_block == FALSE); /* The header of a flac metadata block is 4 bytes long: * 1st bit: indicates whether this is the last metadata info block * 7 next bits: 4 if vorbis comment block * 24 next bits: size of the metadata to follow (big endian) */ if (gst_adapter_available (tag->adapter) < 4) goto cleanup; block_header = gst_adapter_map (tag->adapter, 4); is_last = ((block_header[0] & 0x80) == 0x80); type = block_header[0] & 0x7F; size = (block_header[1] << 16) | (block_header[2] << 8) | block_header[3]; gst_adapter_unmap (tag->adapter); /* The 4 bytes long header isn't included in the metadata size */ tag->metadata_block_size = size + 4; tag->metadata_last_block = is_last; GST_DEBUG_OBJECT (tag, "got metadata block: %" G_GSIZE_FORMAT " bytes, type %d, " "is vorbiscomment: %d, is last: %d", size, type, (type == 0x04), is_last); /* Metadata blocks of type 4 are vorbis comment blocks */ if (type == 0x04) { tag->state = GST_FLAC_TAG_STATE_VC_METADATA_BLOCK; } else { tag->state = GST_FLAC_TAG_STATE_WRITING_METADATA_BLOCK; } } /* Reads a metadata block */ if ((tag->state == GST_FLAC_TAG_STATE_WRITING_METADATA_BLOCK) || (tag->state == GST_FLAC_TAG_STATE_VC_METADATA_BLOCK)) { GstBuffer *metadata_buffer; if (gst_adapter_available (tag->adapter) < tag->metadata_block_size) goto cleanup; metadata_buffer = gst_adapter_take_buffer (tag->adapter, tag->metadata_block_size); /* clear the is-last flag, as the last metadata block will * be the vorbis comment block which we will build ourselves. */ gst_buffer_map (metadata_buffer, &map, GST_MAP_READWRITE); map.data[0] &= (~0x80); gst_buffer_unmap (metadata_buffer, &map); if (tag->state == GST_FLAC_TAG_STATE_WRITING_METADATA_BLOCK) { GST_DEBUG_OBJECT (tag, "pushing metadata block buffer"); ret = gst_pad_push (tag->srcpad, metadata_buffer); if (ret != GST_FLOW_OK) goto cleanup; } else { tag->vorbiscomment = metadata_buffer; } tag->metadata_block_size = 0; tag->state = GST_FLAC_TAG_STATE_METADATA_NEXT_BLOCK; } /* This state is mainly used to be able to stop as soon as we read * a vorbiscomment block from the flac file if we are in an only output * tags mode */ if (tag->state == GST_FLAC_TAG_STATE_METADATA_NEXT_BLOCK) { /* Check if in the previous iteration we read a vorbis comment metadata * block, and stop now if the user only wants to read tags */ if (tag->vorbiscomment != NULL) { guint8 id_data[4]; /* We found some tags, try to parse them and notify the other elements * that we encountered some tags */ GST_DEBUG_OBJECT (tag, "emitting vorbiscomment tags"); gst_buffer_extract (tag->vorbiscomment, 0, id_data, 4); tag->tags = gst_tag_list_from_vorbiscomment_buffer (tag->vorbiscomment, id_data, 4, NULL); if (tag->tags != NULL) { gst_pad_push_event (tag->srcpad, gst_event_new_tag (gst_tag_list_copy (tag->tags))); } gst_buffer_unref (tag->vorbiscomment); tag->vorbiscomment = NULL; } /* Skip to next state */ if (tag->metadata_last_block == FALSE) { tag->state = GST_FLAC_TAG_STATE_METADATA_BLOCKS; } else { tag->state = GST_FLAC_TAG_STATE_ADD_VORBIS_COMMENT; } } /* Creates a vorbis comment block from the metadata which was set * on the gstreamer element, and add it to the flac stream */ if (tag->state == GST_FLAC_TAG_STATE_ADD_VORBIS_COMMENT) { GstBuffer *buffer; const GstTagList *user_tags; GstTagList *merged_tags; /* merge the tag lists */ user_tags = gst_tag_setter_get_tag_list (GST_TAG_SETTER (tag)); if (user_tags != NULL) { merged_tags = gst_tag_list_merge (user_tags, tag->tags, gst_tag_setter_get_tag_merge_mode (GST_TAG_SETTER (tag))); } else { merged_tags = gst_tag_list_copy (tag->tags); } if (merged_tags == NULL) { /* If we get a NULL list of tags, we must generate a padding block * which is marked as the last metadata block, otherwise we'll * end up with a corrupted flac file. */ GST_WARNING_OBJECT (tag, "No tags found"); buffer = gst_buffer_new_and_alloc (12); if (buffer == NULL) goto no_buffer; gst_buffer_map (buffer, &map, GST_MAP_WRITE); memset (map.data, 0, map.size); map.data[0] = 0x81; /* 0x80 = Last metadata block, * 0x01 = padding block */ gst_buffer_unmap (buffer, &map); } else { guchar header[4]; guint8 fbit[1]; memset (header, 0, sizeof (header)); header[0] = 0x84; /* 0x80 = Last metadata block, * 0x04 = vorbiscomment block */ buffer = gst_tag_list_to_vorbiscomment_buffer (merged_tags, header, sizeof (header), NULL); GST_DEBUG_OBJECT (tag, "Writing tags %" GST_PTR_FORMAT, merged_tags); gst_tag_list_free (merged_tags); if (buffer == NULL) goto no_comment; size = gst_buffer_get_size (buffer); if ((size < 4) || ((size - 4) > 0xFFFFFF)) goto comment_too_long; fbit[0] = 1; /* Get rid of the framing bit at the end of the vorbiscomment buffer * if it exists since libFLAC seems to lose sync because of this * bit in gstflacdec */ if (gst_buffer_memcmp (buffer, size - 1, fbit, 1) == 0) { buffer = gst_buffer_make_writable (buffer); gst_buffer_resize (buffer, 0, size - 1); } } /* The 4 byte metadata block header isn't accounted for in the total * size of the metadata block */ gst_buffer_map (buffer, &map, GST_MAP_WRITE); map.data[1] = (((map.size - 4) & 0xFF0000) >> 16); map.data[2] = (((map.size - 4) & 0x00FF00) >> 8); map.data[3] = ((map.size - 4) & 0x0000FF); gst_buffer_unmap (buffer, &map); GST_DEBUG_OBJECT (tag, "pushing %" G_GSIZE_FORMAT " byte vorbiscomment " "buffer", map.size); ret = gst_pad_push (tag->srcpad, buffer); if (ret != GST_FLOW_OK) { goto cleanup; } tag->state = GST_FLAC_TAG_STATE_AUDIO_DATA; }
static gint multipart_parse_header (GstMultipartDemux * multipart) { const guint8 *data; const guint8 *dataend; gchar *boundary; int boundary_len; int datalen; guint8 *pos; guint8 *end, *next; datalen = gst_adapter_available (multipart->adapter); data = gst_adapter_map (multipart->adapter, datalen); dataend = data + datalen; /* Skip leading whitespace, pos endposition should at least leave space for * the boundary and a \n */ for (pos = (guint8 *) data; pos < dataend - 4 && g_ascii_isspace (*pos); pos++); if (pos >= dataend - 4) goto need_more_data; if (G_UNLIKELY (pos[0] != '-' || pos[1] != '-')) { GST_DEBUG_OBJECT (multipart, "No boundary available"); goto wrong_header; } /* First the boundary */ if (!get_line_end (pos, dataend, &end, &next)) goto need_more_data; /* Ignore the leading -- */ boundary_len = end - pos - 2; boundary = (gchar *) pos + 2; if (boundary_len < 1) { GST_DEBUG_OBJECT (multipart, "No boundary available"); goto wrong_header; } if (G_UNLIKELY (multipart->boundary == NULL)) { /* First time we see the boundary, copy it */ multipart->boundary = g_strndup (boundary, boundary_len); multipart->boundary_len = boundary_len; } else if (G_UNLIKELY (boundary_len != multipart->boundary_len)) { /* Something odd is going on, either the boundary indicated EOS or it's * invalid */ if (G_UNLIKELY (boundary_len == multipart->boundary_len + 2 && !strncmp (boundary, multipart->boundary, multipart->boundary_len) && !strncmp (boundary + multipart->boundary_len, "--", 2))) goto eos; GST_DEBUG_OBJECT (multipart, "Boundary length doesn't match detected boundary (%d <> %d", boundary_len, multipart->boundary_len); goto wrong_header; } else if (G_UNLIKELY (strncmp (boundary, multipart->boundary, boundary_len))) { GST_DEBUG_OBJECT (multipart, "Boundary doesn't match previous boundary"); goto wrong_header; } pos = next; while (get_line_end (pos, dataend, &end, &next)) { guint len = end - pos; if (len == 0) { /* empty line, data starts behind us */ GST_DEBUG_OBJECT (multipart, "Parsed the header - boundary: %s, mime-type: %s, content-length: %d", multipart->boundary, multipart->mime_type, multipart->content_length); gst_adapter_unmap (multipart->adapter); return next - data; } if (len >= 14 && !g_ascii_strncasecmp ("content-type:", (gchar *) pos, 13)) { guint mime_len; /* only take the mime type up to the first ; if any. After ; there can be * properties that we don't handle yet. */ mime_len = get_mime_len (pos + 14, len - 14); g_free (multipart->mime_type); multipart->mime_type = g_ascii_strdown ((gchar *) pos + 14, mime_len); } else if (len >= 15 && !g_ascii_strncasecmp ("content-length:", (gchar *) pos, 15)) { multipart->content_length = g_ascii_strtoull ((gchar *) pos + 15, NULL, 10); } pos = next; } need_more_data: GST_DEBUG_OBJECT (multipart, "Need more data for the header"); gst_adapter_unmap (multipart->adapter); return MULTIPART_NEED_MORE_DATA; wrong_header: { GST_ELEMENT_ERROR (multipart, STREAM, DEMUX, (NULL), ("Boundary not found in the multipart header")); gst_adapter_unmap (multipart->adapter); return MULTIPART_DATA_ERROR; } eos: { GST_DEBUG_OBJECT (multipart, "we are EOS"); gst_adapter_unmap (multipart->adapter); return MULTIPART_DATA_EOS; } }
static GstFlowReturn gst_monoscope_chain (GstPad * pad, GstObject * parent, GstBuffer * inbuf) { GstFlowReturn flow_ret = GST_FLOW_OK; GstMonoscope *monoscope; monoscope = GST_MONOSCOPE (parent); if (monoscope->rate == 0) { gst_buffer_unref (inbuf); flow_ret = GST_FLOW_NOT_NEGOTIATED; goto out; } /* Make sure have an output format */ flow_ret = ensure_negotiated (monoscope); if (flow_ret != GST_FLOW_OK) { gst_buffer_unref (inbuf); goto out; } /* don't try to combine samples from discont buffer */ if (GST_BUFFER_FLAG_IS_SET (inbuf, GST_BUFFER_FLAG_DISCONT)) { gst_adapter_clear (monoscope->adapter); monoscope->next_ts = GST_CLOCK_TIME_NONE; } /* Match timestamps from the incoming audio */ if (GST_BUFFER_TIMESTAMP (inbuf) != GST_CLOCK_TIME_NONE) monoscope->next_ts = GST_BUFFER_TIMESTAMP (inbuf); GST_LOG_OBJECT (monoscope, "in buffer has %d samples, ts=%" GST_TIME_FORMAT, gst_buffer_get_size (inbuf) / monoscope->bps, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (inbuf))); gst_adapter_push (monoscope->adapter, inbuf); inbuf = NULL; /* Collect samples until we have enough for an output frame */ while (flow_ret == GST_FLOW_OK) { gint16 *samples; GstBuffer *outbuf = NULL; guint32 *pixels, avail, bytesperframe; avail = gst_adapter_available (monoscope->adapter); GST_LOG_OBJECT (monoscope, "bytes avail now %u", avail); bytesperframe = monoscope->spf * monoscope->bps; if (avail < bytesperframe) break; /* FIXME: something is wrong with QoS, we are skipping way too much * stuff even with very low CPU loads */ #if 0 if (monoscope->next_ts != -1) { gboolean need_skip; gint64 qostime; qostime = gst_segment_to_running_time (&monoscope->segment, GST_FORMAT_TIME, monoscope->next_ts); GST_OBJECT_LOCK (monoscope); /* check for QoS, don't compute buffers that are known to be late */ need_skip = GST_CLOCK_TIME_IS_VALID (monoscope->earliest_time) && qostime <= monoscope->earliest_time; GST_OBJECT_UNLOCK (monoscope); if (need_skip) { GST_WARNING_OBJECT (monoscope, "QoS: skip ts: %" GST_TIME_FORMAT ", earliest: %" GST_TIME_FORMAT, GST_TIME_ARGS (qostime), GST_TIME_ARGS (monoscope->earliest_time)); goto skip; } } #endif samples = (gint16 *) gst_adapter_map (monoscope->adapter, bytesperframe); if (monoscope->spf < 512) { gint16 in_data[512], i; for (i = 0; i < 512; ++i) { gdouble off; off = ((gdouble) i * (gdouble) monoscope->spf) / 512.0; in_data[i] = samples[MIN ((guint) off, monoscope->spf)]; } pixels = monoscope_update (monoscope->visstate, in_data); } else { /* not really correct, but looks much prettier */ pixels = monoscope_update (monoscope->visstate, samples); } GST_LOG_OBJECT (monoscope, "allocating output buffer"); flow_ret = gst_buffer_pool_acquire_buffer (monoscope->pool, &outbuf, NULL); if (flow_ret != GST_FLOW_OK) { gst_adapter_unmap (monoscope->adapter); goto out; } gst_buffer_fill (outbuf, 0, pixels, monoscope->outsize); GST_BUFFER_TIMESTAMP (outbuf) = monoscope->next_ts; GST_BUFFER_DURATION (outbuf) = monoscope->frame_duration; flow_ret = gst_pad_push (monoscope->srcpad, outbuf); #if 0 skip: #endif if (GST_CLOCK_TIME_IS_VALID (monoscope->next_ts)) monoscope->next_ts += monoscope->frame_duration; gst_adapter_flush (monoscope->adapter, bytesperframe); } out: return flow_ret; }
/** * gst_adapter_map: * @adapter: a #GstAdapter * @size: the number of bytes to map/peek * * Gets the first @size bytes stored in the @adapter. The returned pointer is * valid until the next function is called on the adapter. * * Note that setting the returned pointer as the data of a #GstBuffer is * incorrect for general-purpose plugins. The reason is that if a downstream * element stores the buffer so that it has access to it outside of the bounds * of its chain function, the buffer will have an invalid data pointer after * your element flushes the bytes. In that case you should use * gst_adapter_take(), which returns a freshly-allocated buffer that you can set * as #GstBuffer memory or the potentially more performant * gst_adapter_take_buffer(). * * Returns #NULL if @size bytes are not available. * * Returns: (transfer none) (array length=size) (element-type guint8): * a pointer to the first @size bytes of data, or NULL */ gconstpointer gst_adapter_map (GstAdapter * adapter, gsize size) { GstBuffer *cur; gsize skip, csize; gsize toreuse, tocopy; guint8 *data; g_return_val_if_fail (GST_IS_ADAPTER (adapter), NULL); g_return_val_if_fail (size > 0, NULL); if (adapter->info.memory) gst_adapter_unmap (adapter); /* we don't have enough data, return NULL. This is unlikely * as one usually does an _available() first instead of peeking a * random size. */ if (G_UNLIKELY (size > adapter->size)) return NULL; /* we have enough assembled data, return it */ if (adapter->assembled_len >= size) return adapter->assembled_data; #if 0 do { #endif cur = adapter->buflist->data; skip = adapter->skip; csize = gst_buffer_get_size (cur); if (csize >= size + skip) { if (!gst_buffer_map (cur, &adapter->info, GST_MAP_READ)) return FALSE; return (guint8 *) adapter->info.data + skip; } /* We may be able to efficiently merge buffers in our pool to * gather a big enough chunk to return it from the head buffer directly */ #if 0 } while (gst_adapter_try_to_merge_up (adapter, size)); #endif /* see how much data we can reuse from the assembled memory and how much * we need to copy */ toreuse = adapter->assembled_len; tocopy = size - toreuse; /* Gonna need to copy stuff out */ if (G_UNLIKELY (adapter->assembled_size < size)) { adapter->assembled_size = (size / DEFAULT_SIZE + 1) * DEFAULT_SIZE; GST_DEBUG_OBJECT (adapter, "resizing internal buffer to %" G_GSIZE_FORMAT, adapter->assembled_size); if (toreuse == 0) { GST_CAT_DEBUG (GST_CAT_PERFORMANCE, "alloc new buffer"); /* no g_realloc to avoid a memcpy that is not desired here since we are * not going to reuse any data here */ g_free (adapter->assembled_data); adapter->assembled_data = g_malloc (adapter->assembled_size); } else { /* we are going to reuse all data, realloc then */ GST_CAT_DEBUG (GST_CAT_PERFORMANCE, "reusing %" G_GSIZE_FORMAT " bytes", toreuse); adapter->assembled_data = g_realloc (adapter->assembled_data, adapter->assembled_size); } } GST_CAT_DEBUG (GST_CAT_PERFORMANCE, "copy remaining %" G_GSIZE_FORMAT " bytes from adapter", tocopy); data = adapter->assembled_data; copy_into_unchecked (adapter, data + toreuse, skip + toreuse, tocopy); adapter->assembled_len = size; return adapter->assembled_data; }