static void gst_vtdec_enqueue_frame (void *data1, void *data2, VTStatus result, VTDecodeInfoFlags info, CVBufferRef cvbuf, CMTime pts, CMTime duration) { GstVTDec *self = GST_VTDEC_CAST (data1); GstBuffer *src_buf = GST_BUFFER (data2); GstBuffer *buf; if (result != kVTSuccess) { GST_ERROR_OBJECT (self, "Error decoding frame %d", result); goto beach; } if (kVTDecodeInfo_FrameDropped & info) { GST_WARNING_OBJECT (self, "Frame dropped"); goto beach; } buf = gst_core_video_buffer_new (cvbuf, &self->vinfo); gst_buffer_copy_into (buf, src_buf, GST_BUFFER_COPY_METADATA, 0, -1); GST_BUFFER_PTS (buf) = pts.value; GST_BUFFER_DURATION (buf) = duration.value; g_queue_push_head (self->cur_outbufs, buf); if (GST_BUFFER_PTS (src_buf) <= GST_BUFFER_DTS (src_buf)) { GST_LOG_OBJECT (self, "Flushing interal queue of buffers"); self->flush = TRUE; } else { GST_LOG_OBJECT (self, "Queuing buffer"); } beach: return; }
static GstFlowReturn gst_dtls_enc_push (GstDtlsEnc * self, GstBuffer * buffer) { GstDtlsBase *base = GST_DTLS_BASE (self); GstEvent *segment_event, *caps_event; gchar *stream_id; stream_id = gst_pad_get_stream_id (base->srcpad); if (stream_id == NULL) { stream_id = gst_pad_get_stream_id (base->sinkpad); if (stream_id == NULL) { stream_id = gst_pad_create_stream_id (base->srcpad, GST_ELEMENT (base), NULL); } gst_pad_push_event (base->srcpad, gst_event_new_stream_start (stream_id)); } g_free (stream_id); caps_event = gst_pad_get_sticky_event (base->srcpad, GST_EVENT_CAPS, 0); if (caps_event == NULL) { GstCaps *caps = gst_caps_from_string ("application/x-dtls"); caps_event = gst_event_new_caps (caps); gst_caps_unref (caps); gst_pad_push_event (base->srcpad, caps_event); } else { gst_event_unref (caps_event); } segment_event = gst_pad_get_sticky_event (base->srcpad, GST_EVENT_SEGMENT, 0); if (segment_event == NULL) { GstSegment *segment = gst_segment_new (); gst_segment_init (segment, GST_FORMAT_BYTES); segment_event = gst_event_new_segment (segment); gst_segment_free (segment); gst_pad_push_event (base->srcpad, segment_event); } else { gst_event_unref (segment_event); } GST_OBJECT_LOCK (self); if (self->src_buffer && self->running_thread == g_thread_self ()) { g_assert (gst_buffer_get_size (buffer) != 181); gst_buffer_copy_into (buffer, self->src_buffer, GST_BUFFER_COPY_METADATA, 0, -1); } GST_OBJECT_UNLOCK (self); return gst_pad_push (base->srcpad, buffer); }
GstBuffer * mpegtsmux_prepare_teletext (GstBuffer * buf, MpegTsPadData * pad_data, MpegTsMux * mux) { GstBuffer *out_buf; guint8 *data, *odata; gint size, stuff; gboolean add_id; GstMapInfo map, omap; gst_buffer_map (buf, &map, GST_MAP_READ); size = map.size; data = map.data; /* check if leading data_identifier byte is already present, * if not increase size since it will need to be added */ if (data[0] < 0x10 || data[0] > 0x1F) { size += 1; add_id = TRUE; } if (size <= 184 - 45) { stuff = 184 - 45 - size; } else { stuff = size - (184 - 45); stuff = 184 - (stuff % 184); } if (G_UNLIKELY (stuff == 1)) stuff += 184; GST_DEBUG_OBJECT (mux, "Preparing teletext buffer for output"); out_buf = gst_buffer_new_and_alloc (size + stuff); gst_buffer_copy_into (out_buf, buf, GST_BUFFER_COPY_METADATA | GST_BUFFER_COPY_TIMESTAMPS, 0, 0); /* copy data */ gst_buffer_map (out_buf, &omap, GST_MAP_WRITE); odata = omap.data; /* add data_identifier if needed */ if (add_id) { *odata = 0x10; memcpy (odata + 1, data, size - 1); } else { memcpy (odata, data, size); } /* add stuffing data_unit */ odata += size; *odata++ = 0xFF; *odata = stuff; gst_buffer_unmap (buf, &map); gst_buffer_unmap (out_buf, &omap); return out_buf; }
static GstFlowReturn gst_jp2k_decimator_decimate_jpc (GstJP2kDecimator * self, GstBuffer * inbuf, GstBuffer ** outbuf_) { GstBuffer *outbuf = NULL; GstFlowReturn ret = GST_FLOW_OK; GstMapInfo info; GstByteReader reader; GstByteWriter writer; MainHeader main_header; if (!gst_buffer_map (inbuf, &info, GST_MAP_READ)) { GST_ELEMENT_ERROR (self, STREAM, WRONG_TYPE, ("Unable to map memory"), (NULL)); gst_buffer_unref (inbuf); return GST_FLOW_ERROR; } gst_byte_reader_init (&reader, info.data, info.size); gst_byte_writer_init_with_size (&writer, gst_buffer_get_size (inbuf), FALSE); /* main header */ memset (&main_header, 0, sizeof (MainHeader)); ret = parse_main_header (self, &reader, &main_header); if (ret != GST_FLOW_OK) goto done; ret = decimate_main_header (self, &main_header); if (ret != GST_FLOW_OK) goto done; ret = write_main_header (self, &writer, &main_header); if (ret != GST_FLOW_OK) goto done; outbuf = gst_byte_writer_reset_and_get_buffer (&writer); gst_buffer_copy_into (outbuf, inbuf, GST_BUFFER_COPY_METADATA, 0, -1); GST_DEBUG_OBJECT (self, "Decimated buffer from %" G_GSIZE_FORMAT " bytes to %" G_GSIZE_FORMAT " bytes (%.2lf%%)", gst_buffer_get_size (inbuf), gst_buffer_get_size (outbuf), (100 * gst_buffer_get_size (outbuf)) / ((gdouble) gst_buffer_get_size (inbuf))); done: gst_buffer_unmap (inbuf, &info); *outbuf_ = outbuf; reset_main_header (self, &main_header); gst_buffer_unref (inbuf); return ret; }
static GstFlowReturn gst_ffmpegdeinterlace_chain (GstPad * pad, GstObject * parent, GstBuffer * inbuf) { GstFFMpegDeinterlace *deinterlace = GST_FFMPEGDEINTERLACE (parent); GstBuffer *outbuf = NULL; GstFlowReturn result; GstMapInfo from_map, to_map; GST_OBJECT_LOCK (deinterlace); if (deinterlace->reconfigure) { if (deinterlace->new_mode != -1) deinterlace->mode = deinterlace->new_mode; deinterlace->new_mode = -1; deinterlace->reconfigure = FALSE; GST_OBJECT_UNLOCK (deinterlace); if (gst_pad_has_current_caps (deinterlace->srcpad)) { GstCaps *caps; caps = gst_pad_get_current_caps (deinterlace->sinkpad); gst_ffmpegdeinterlace_sink_setcaps (deinterlace->sinkpad, caps); gst_caps_unref (caps); } } else { GST_OBJECT_UNLOCK (deinterlace); } if (deinterlace->passthrough) return gst_pad_push (deinterlace->srcpad, inbuf); outbuf = gst_buffer_new_and_alloc (deinterlace->to_size); gst_buffer_map (inbuf, &from_map, GST_MAP_READ); gst_ffmpeg_avpicture_fill (&deinterlace->from_frame, from_map.data, deinterlace->pixfmt, deinterlace->width, deinterlace->height); gst_buffer_map (outbuf, &to_map, GST_MAP_WRITE); gst_ffmpeg_avpicture_fill (&deinterlace->to_frame, to_map.data, deinterlace->pixfmt, deinterlace->width, deinterlace->height); avpicture_deinterlace (&deinterlace->to_frame, &deinterlace->from_frame, deinterlace->pixfmt, deinterlace->width, deinterlace->height); gst_buffer_unmap (outbuf, &to_map); gst_buffer_unmap (inbuf, &from_map); gst_buffer_copy_into (outbuf, inbuf, GST_BUFFER_COPY_TIMESTAMPS, 0, -1); result = gst_pad_push (deinterlace->srcpad, outbuf); gst_buffer_unref (inbuf); return result; }
GstBuffer* createGstBuffer(GstBuffer* buffer) { gsize bufferSize = gst_buffer_get_size(buffer); GstBuffer* newBuffer = gst_buffer_new_and_alloc(bufferSize); if (!newBuffer) return 0; gst_buffer_copy_into(newBuffer, buffer, static_cast<GstBufferCopyFlags>(GST_BUFFER_COPY_METADATA), 0, bufferSize); return newBuffer; }
/** * gst_adapter_get_buffer_fast: * @adapter: a #GstAdapter * @nbytes: the number of bytes to get * * Returns a #GstBuffer containing the first @nbytes of the @adapter, but * does not flush them from the adapter. See gst_adapter_take_buffer_fast() * for details. * * Caller owns a reference to the returned buffer. gst_buffer_unref() after * usage. * * Free-function: gst_buffer_unref * * Returns: (transfer full) (nullable): a #GstBuffer containing the first * @nbytes of the adapter, or %NULL if @nbytes bytes are not available. * gst_buffer_unref() when no longer needed. * * Since: 1.6 */ GstBuffer * gst_adapter_get_buffer_fast (GstAdapter * adapter, gsize nbytes) { GstBuffer *buffer = NULL; GstBuffer *cur; GSList *item; gsize skip; gsize left = nbytes; g_return_val_if_fail (GST_IS_ADAPTER (adapter), NULL); g_return_val_if_fail (nbytes > 0, NULL); GST_LOG_OBJECT (adapter, "getting buffer of %" G_GSIZE_FORMAT " bytes", nbytes); /* we don't have enough data, return NULL. This is unlikely * as one usually does an _available() first instead of grabbing a * random size. */ if (G_UNLIKELY (nbytes > adapter->size)) return NULL; skip = adapter->skip; cur = adapter->buflist->data; if (skip == 0 && gst_buffer_get_size (cur) == nbytes) { GST_LOG_OBJECT (adapter, "providing buffer of %" G_GSIZE_FORMAT " bytes" " as head buffer", nbytes); buffer = gst_buffer_ref (cur); goto done; } for (item = adapter->buflist; item && left > 0; item = item->next) { gsize size, cur_size; cur = item->data; cur_size = gst_buffer_get_size (cur); size = MIN (cur_size - skip, left); GST_LOG_OBJECT (adapter, "appending %" G_GSIZE_FORMAT " bytes" " via region copy", size); if (buffer) gst_buffer_copy_into (buffer, cur, GST_BUFFER_COPY_MEMORY | GST_BUFFER_COPY_META, skip, size); else buffer = gst_buffer_copy_region (cur, GST_BUFFER_COPY_ALL, skip, size); skip = 0; left -= size; } done: return buffer; }
void GStreamerReader::CopyIntoImageBuffer(GstBuffer* aBuffer, GstBuffer** aOutBuffer, nsRefPtr<PlanarYCbCrImage> &image) { *aOutBuffer = gst_buffer_new_allocate(mAllocator, gst_buffer_get_size(aBuffer), nullptr); GstMemory *mem = gst_buffer_peek_memory(*aOutBuffer, 0); GstMapInfo map_info; gst_memory_map(mem, &map_info, GST_MAP_WRITE); gst_buffer_extract(aBuffer, 0, map_info.data, gst_buffer_get_size(aBuffer)); gst_memory_unmap(mem, &map_info); /* create a new gst buffer with the newly created memory and copy the * metadata over from the incoming buffer */ gst_buffer_copy_into(*aOutBuffer, aBuffer, (GstBufferCopyFlags)(GST_BUFFER_COPY_METADATA), 0, -1); image = GetImageFromBuffer(*aOutBuffer); }
static void gst_vtdec_enqueue_frame (void *data, gsize unk1, VTStatus result, gsize unk2, CVBufferRef cvbuf) { GstVTDec *self = GST_VTDEC_CAST (data); GstBuffer *buf; if (result != kVTSuccess) goto beach; buf = gst_core_video_buffer_new (self->ctx, cvbuf, &self->vinfo); gst_buffer_copy_into (buf, self->cur_inbuf, GST_BUFFER_COPY_METADATA, 0, -1); g_ptr_array_add (self->cur_outbufs, buf); beach: return; }
static GstFlowReturn gst_vorbis_tag_parse_packet (GstVorbisParse * parse, GstBuffer * buffer) { GstTagList *old_tags, *new_tags; const GstTagList *user_tags; GstVorbisTag *tagger; gchar *encoder = NULL; GstBuffer *new_buf; GstMapInfo map; gboolean do_parse = FALSE; gst_buffer_map (buffer, &map, GST_MAP_READ); /* just pass everything except the comments packet */ if (map.size >= 1 && map.data[0] != 0x03) do_parse = TRUE; gst_buffer_unmap (buffer, &map); if (do_parse) { return GST_VORBIS_PARSE_CLASS (parent_class)->parse_packet (parse, buffer); } tagger = GST_VORBIS_TAG (parse); old_tags = gst_tag_list_from_vorbiscomment_buffer (buffer, (guint8 *) "\003vorbis", 7, &encoder); user_tags = gst_tag_setter_get_tag_list (GST_TAG_SETTER (tagger)); /* build new tag list */ new_tags = gst_tag_list_merge (user_tags, old_tags, gst_tag_setter_get_tag_merge_mode (GST_TAG_SETTER (tagger))); gst_tag_list_unref (old_tags); new_buf = gst_tag_list_to_vorbiscomment_buffer (new_tags, (guint8 *) "\003vorbis", 7, encoder); gst_buffer_copy_into (new_buf, buffer, GST_BUFFER_COPY_TIMESTAMPS, 0, -1); gst_tag_list_unref (new_tags); g_free (encoder); gst_buffer_unref (buffer); return GST_VORBIS_PARSE_CLASS (parent_class)->parse_packet (parse, new_buf); }
GstBuffer* createGstBuffer(GstBuffer* buffer) { #ifndef GST_API_VERSION_1 GstBuffer* newBuffer = gst_buffer_try_new_and_alloc(GST_BUFFER_SIZE(buffer)); #else gsize bufferSize = gst_buffer_get_size(buffer); GstBuffer* newBuffer = gst_buffer_new_and_alloc(bufferSize); #endif if (!newBuffer) return 0; #ifndef GST_API_VERSION_1 gst_buffer_copy_metadata(newBuffer, buffer, static_cast<GstBufferCopyFlags>(GST_BUFFER_COPY_ALL)); #else gst_buffer_copy_into(newBuffer, buffer, static_cast<GstBufferCopyFlags>(GST_BUFFER_COPY_METADATA), 0, bufferSize); #endif return newBuffer; }
static gboolean buffer_list_copy_data (GstBuffer ** buf, guint idx, gpointer data) { GstBuffer *dest = data; guint num, i; if (idx == 0) gst_buffer_copy_into (dest, *buf, GST_BUFFER_COPY_METADATA, 0, -1); num = gst_buffer_n_memory (*buf); for (i = 0; i < num; ++i) { GstMemory *mem; mem = gst_buffer_get_memory (*buf, i); gst_buffer_append_memory (dest, mem); } return TRUE; }
static GstBuffer * gst_directsound_sink_payload (GstAudioBaseSink * sink, GstBuffer * buf) { if (gst_directsound_sink_is_spdif_format (&sink->ringbuffer->spec)) { gint framesize = gst_audio_iec61937_frame_size (&sink->ringbuffer->spec); GstBuffer *out; GstMapInfo infobuf, infoout; gboolean success; if (framesize <= 0) return NULL; out = gst_buffer_new_and_alloc (framesize); if (!gst_buffer_map (buf, &infobuf, GST_MAP_READWRITE)) { gst_buffer_unref (out); return NULL; } if (!gst_buffer_map (out, &infoout, GST_MAP_READWRITE)) { gst_buffer_unmap (buf, &infobuf); gst_buffer_unref (out); return NULL; } success = gst_audio_iec61937_payload (infobuf.data, infobuf.size, infoout.data, infoout.size, &sink->ringbuffer->spec, G_BYTE_ORDER); if (!success) { gst_buffer_unmap (out, &infoout); gst_buffer_unmap (buf, &infobuf); gst_buffer_unref (out); return NULL; } gst_buffer_copy_into (out, buf, GST_BUFFER_COPY_ALL, 0, -1); /* Fix endianness */ _swab ((gchar *) infoout.data, (gchar *) infoout.data, infobuf.size); gst_buffer_unmap (out, &infoout); gst_buffer_unmap (buf, &infobuf); return out; } else return gst_buffer_ref (buf); }
/* chain function * this function does the actual processing */ static GstFlowReturn gst_edge_detect_chain (GstPad * pad, GstObject * parent, GstBuffer * buf) { GstEdgeDetect *filter; GstBuffer *outbuf; GstMapInfo in_info; GstMapInfo out_info; filter = GST_EDGE_DETECT (parent); buf = gst_buffer_make_writable (buf); gst_buffer_map (buf, &in_info, GST_MAP_WRITE); filter->cvImage->imageData = (char *) in_info.data; cvCvtColor (filter->cvImage, filter->cvGray, CV_RGB2GRAY); cvSmooth (filter->cvGray, filter->cvEdge, CV_BLUR, 3, 3, 0, 0); cvNot (filter->cvGray, filter->cvEdge); cvCanny (filter->cvGray, filter->cvEdge, filter->threshold1, filter->threshold2, filter->aperture); cvZero (filter->cvCEdge); if (filter->mask) { cvCopy (filter->cvImage, filter->cvCEdge, filter->cvEdge); } else { cvCvtColor (filter->cvEdge, filter->cvCEdge, CV_GRAY2RGB); } outbuf = gst_buffer_new_and_alloc (filter->cvCEdge->imageSize); gst_buffer_copy_into (outbuf, buf, GST_BUFFER_COPY_METADATA, 0, -1); gst_buffer_map (outbuf, &out_info, GST_MAP_WRITE); memcpy (out_info.data, filter->cvCEdge->imageData, gst_buffer_get_size (outbuf)); gst_buffer_unmap (buf, &in_info); gst_buffer_unmap (outbuf, &out_info); gst_buffer_unref (buf); return gst_pad_push (filter->srcpad, outbuf); }
static GstFlowReturn gst_gl_stereo_mix_aggregate_frames (GstVideoAggregator * vagg, GstBuffer * outbuf) { GstGLStereoMix *mix = GST_GL_STEREO_MIX (vagg); /* If we're operating in frame-by-frame mode, push * the primary view now, and let the parent class * push the remaining auxilliary view */ if (GST_VIDEO_INFO_MULTIVIEW_MODE (&vagg->info) == GST_VIDEO_MULTIVIEW_MODE_FRAME_BY_FRAME) { /* Transfer the timestamps video-agg put on the aux buffer */ gst_buffer_copy_into (mix->primary_out, outbuf, GST_BUFFER_COPY_TIMESTAMPS, 0, -1); gst_aggregator_finish_buffer (GST_AGGREGATOR (vagg), mix->primary_out); mix->primary_out = NULL; /* And actually, we don't want timestamps on the aux buffer */ GST_BUFFER_TIMESTAMP (outbuf) = GST_CLOCK_TIME_NONE; GST_BUFFER_DURATION (outbuf) = GST_CLOCK_TIME_NONE; } return GST_FLOW_OK; }
static GstBuffer * gst_alsasink_payload (GstAudioBaseSink * sink, GstBuffer * buf) { GstAlsaSink *alsa; alsa = GST_ALSA_SINK (sink); if (alsa->iec958) { GstBuffer *out; gint framesize; GstMapInfo iinfo, oinfo; framesize = gst_audio_iec61937_frame_size (&sink->ringbuffer->spec); if (framesize <= 0) return NULL; out = gst_buffer_new_and_alloc (framesize); gst_buffer_map (buf, &iinfo, GST_MAP_READ); gst_buffer_map (out, &oinfo, GST_MAP_WRITE); if (!gst_audio_iec61937_payload (iinfo.data, iinfo.size, oinfo.data, oinfo.size, &sink->ringbuffer->spec, G_BIG_ENDIAN)) { gst_buffer_unmap (buf, &iinfo); gst_buffer_unmap (out, &oinfo); gst_buffer_unref (out); return NULL; } gst_buffer_unmap (buf, &iinfo); gst_buffer_unmap (out, &oinfo); gst_buffer_copy_into (out, buf, GST_BUFFER_COPY_METADATA, 0, -1); return out; } return gst_buffer_ref (buf); }
static VTStatus gst_vtenc_enqueue_buffer (void *data, int a2, int a3, int a4, CMSampleBufferRef sbuf, int a6, int a7) { GstVTEnc *self = data; gboolean is_keyframe; GstBuffer *buf; /* This may happen if we don't have enough bitrate */ if (sbuf == NULL) goto beach; is_keyframe = gst_vtenc_buffer_is_keyframe (self, sbuf); if (self->expect_keyframe) { if (!is_keyframe) goto beach; CFDictionaryRemoveValue (self->options, *(self->ctx->vt->kVTEncodeFrameOptionKey_ForceKeyFrame)); } self->expect_keyframe = FALSE; /* We are dealing with block buffers here, so we don't need * to enable the use of the video meta API on the core media buffer */ buf = gst_core_media_buffer_new (sbuf, FALSE); gst_buffer_copy_into (buf, self->cur_inbuf, GST_BUFFER_COPY_TIMESTAMPS, 0, -1); if (is_keyframe) { GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT); } else { GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT); GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT); } g_ptr_array_add (self->cur_outbufs, buf); beach: return kVTSuccess; }
static GstBuffer * gst_osx_audio_sink_sink_payload (GstAudioBaseSink * sink, GstBuffer * buf) { if (RINGBUFFER_IS_SPDIF (sink->ringbuffer->spec.type)) { gint framesize = gst_audio_iec61937_frame_size (&sink->ringbuffer->spec); GstBuffer *out; GstMapInfo inmap, outmap; gboolean res; if (framesize <= 0) return NULL; out = gst_buffer_new_and_alloc (framesize); gst_buffer_map (buf, &inmap, GST_MAP_READ); gst_buffer_map (out, &outmap, GST_MAP_WRITE); /* FIXME: the endianness needs to be queried and then set */ res = gst_audio_iec61937_payload (inmap.data, inmap.size, outmap.data, outmap.size, &sink->ringbuffer->spec, G_BIG_ENDIAN); gst_buffer_unmap (buf, &inmap); gst_buffer_unmap (out, &outmap); if (!res) { gst_buffer_unref (out); return NULL; } gst_buffer_copy_into (out, buf, GST_BUFFER_COPY_METADATA, 0, -1); return out; } else { return gst_buffer_ref (buf); } }
static GstFlowReturn gst_shm_sink_render (GstBaseSink * bsink, GstBuffer * buf) { GstShmSink *self = GST_SHM_SINK (bsink); int rv = 0; GstMapInfo map; gboolean need_new_memory = FALSE; GstFlowReturn ret = GST_FLOW_OK; GstMemory *memory = NULL; GstBuffer *sendbuf = NULL; GST_OBJECT_LOCK (self); while (self->wait_for_connection && !self->clients) { g_cond_wait (&self->cond, GST_OBJECT_GET_LOCK (self)); if (self->unlock) goto flushing; } while (!gst_shm_sink_can_render (self, GST_BUFFER_TIMESTAMP (buf))) { g_cond_wait (&self->cond, GST_OBJECT_GET_LOCK (self)); if (self->unlock) goto flushing; } if (gst_buffer_n_memory (buf) > 1) { GST_LOG_OBJECT (self, "Buffer %p has %d GstMemory, we only support a single" " one, need to do a memcpy", buf, gst_buffer_n_memory (buf)); need_new_memory = TRUE; } else { memory = gst_buffer_peek_memory (buf, 0); if (memory->allocator != GST_ALLOCATOR (self->allocator)) { need_new_memory = TRUE; GST_LOG_OBJECT (self, "Memory in buffer %p was not allocated by " "%" GST_PTR_FORMAT ", will memcpy", buf, memory->allocator); } } if (need_new_memory) { if (gst_buffer_get_size (buf) > sp_writer_get_max_buf_size (self->pipe)) { gsize area_size = sp_writer_get_max_buf_size (self->pipe); GST_OBJECT_UNLOCK (self); GST_ELEMENT_ERROR (self, RESOURCE, NO_SPACE_LEFT, ("Shared memory area is too small"), ("Shared memory area of size %" G_GSIZE_FORMAT " is smaller than" "buffer of size %" G_GSIZE_FORMAT, area_size, gst_buffer_get_size (buf))); return GST_FLOW_ERROR; } while ((memory = gst_shm_sink_allocator_alloc_locked (self->allocator, gst_buffer_get_size (buf), &self->params)) == NULL) { g_cond_wait (&self->cond, GST_OBJECT_GET_LOCK (self)); if (self->unlock) goto flushing; } while (self->wait_for_connection && !self->clients) { g_cond_wait (&self->cond, GST_OBJECT_GET_LOCK (self)); if (self->unlock) { gst_memory_unref (memory); GST_OBJECT_UNLOCK (self); return GST_FLOW_FLUSHING; } } gst_memory_map (memory, &map, GST_MAP_WRITE); gst_buffer_extract (buf, 0, map.data, map.size); gst_memory_unmap (memory, &map); sendbuf = gst_buffer_new (); gst_buffer_copy_into (sendbuf, buf, GST_BUFFER_COPY_METADATA, 0, -1); gst_buffer_append_memory (sendbuf, memory); } else { sendbuf = gst_buffer_ref (buf); } gst_buffer_map (sendbuf, &map, GST_MAP_READ); /* Make the memory readonly as of now as we've sent it to the other side * We know it's not mapped for writing anywhere as we just mapped it for * reading */ rv = sp_writer_send_buf (self->pipe, (char *) map.data, map.size, sendbuf); gst_buffer_unmap (sendbuf, &map); GST_OBJECT_UNLOCK (self); if (rv == 0) { GST_DEBUG_OBJECT (self, "No clients connected, unreffing buffer"); gst_buffer_unref (sendbuf); } else if (rv == -1) { GST_ELEMENT_ERROR (self, STREAM, FAILED, ("Invalid allocated buffer"), ("The shmpipe library rejects our buffer, this is a bug")); ret = GST_FLOW_ERROR; } /* If we allocated our own memory, then unmap it */ return ret; flushing: GST_OBJECT_UNLOCK (self); return GST_FLOW_FLUSHING; }
static GstFlowReturn gst_y4m_dec_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer) { GstY4mDec *y4mdec; int n_avail; GstFlowReturn flow_ret = GST_FLOW_OK; #define MAX_HEADER_LENGTH 80 char header[MAX_HEADER_LENGTH]; int i; int len; y4mdec = GST_Y4M_DEC (parent); GST_DEBUG_OBJECT (y4mdec, "chain"); if (GST_BUFFER_IS_DISCONT (buffer)) { GST_DEBUG ("got discont"); gst_adapter_clear (y4mdec->adapter); } gst_adapter_push (y4mdec->adapter, buffer); n_avail = gst_adapter_available (y4mdec->adapter); if (!y4mdec->have_header) { gboolean ret; GstCaps *caps; GstQuery *query; if (n_avail < MAX_HEADER_LENGTH) return GST_FLOW_OK; gst_adapter_copy (y4mdec->adapter, (guint8 *) header, 0, MAX_HEADER_LENGTH); header[MAX_HEADER_LENGTH - 1] = 0; for (i = 0; i < MAX_HEADER_LENGTH; i++) { if (header[i] == 0x0a) header[i] = 0; } ret = gst_y4m_dec_parse_header (y4mdec, header); if (!ret) { GST_ELEMENT_ERROR (y4mdec, STREAM, DECODE, ("Failed to parse YUV4MPEG header"), (NULL)); return GST_FLOW_ERROR; } y4mdec->header_size = strlen (header) + 1; gst_adapter_flush (y4mdec->adapter, y4mdec->header_size); caps = gst_video_info_to_caps (&y4mdec->info); ret = gst_pad_set_caps (y4mdec->srcpad, caps); query = gst_query_new_allocation (caps, FALSE); y4mdec->video_meta = FALSE; if (y4mdec->pool) { gst_buffer_pool_set_active (y4mdec->pool, FALSE); gst_object_unref (y4mdec->pool); } y4mdec->pool = NULL; if (gst_pad_peer_query (y4mdec->srcpad, query)) { y4mdec->video_meta = gst_query_find_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL); /* We only need a pool if we need to do stride conversion for downstream */ if (!y4mdec->video_meta && memcmp (&y4mdec->info, &y4mdec->out_info, sizeof (y4mdec->info)) != 0) { GstBufferPool *pool = NULL; GstAllocator *allocator = NULL; GstAllocationParams params; GstStructure *config; guint size, min, max; if (gst_query_get_n_allocation_params (query) > 0) { gst_query_parse_nth_allocation_param (query, 0, &allocator, ¶ms); } else { allocator = NULL; gst_allocation_params_init (¶ms); } if (gst_query_get_n_allocation_pools (query) > 0) { gst_query_parse_nth_allocation_pool (query, 0, &pool, &size, &min, &max); size = MAX (size, y4mdec->out_info.size); } else { pool = NULL; size = y4mdec->out_info.size; min = max = 0; } if (pool == NULL) { pool = gst_video_buffer_pool_new (); } config = gst_buffer_pool_get_config (pool); gst_buffer_pool_config_set_params (config, caps, size, min, max); gst_buffer_pool_config_set_allocator (config, allocator, ¶ms); gst_buffer_pool_set_config (pool, config); if (allocator) gst_object_unref (allocator); y4mdec->pool = pool; } } else if (memcmp (&y4mdec->info, &y4mdec->out_info, sizeof (y4mdec->info)) != 0) { GstBufferPool *pool; GstStructure *config; /* No pool, create our own if we need to do stride conversion */ pool = gst_video_buffer_pool_new (); config = gst_buffer_pool_get_config (pool); gst_buffer_pool_config_set_params (config, caps, y4mdec->out_info.size, 0, 0); gst_buffer_pool_set_config (pool, config); y4mdec->pool = pool; } if (y4mdec->pool) { gst_buffer_pool_set_active (y4mdec->pool, TRUE); } gst_query_unref (query); gst_caps_unref (caps); if (!ret) { GST_DEBUG_OBJECT (y4mdec, "Couldn't set caps on src pad"); return GST_FLOW_ERROR; } y4mdec->have_header = TRUE; } if (y4mdec->have_new_segment) { GstEvent *event; GstClockTime start = gst_y4m_dec_bytes_to_timestamp (y4mdec, y4mdec->segment.start); GstClockTime stop = gst_y4m_dec_bytes_to_timestamp (y4mdec, y4mdec->segment.stop); GstClockTime time = gst_y4m_dec_bytes_to_timestamp (y4mdec, y4mdec->segment.time); GstSegment seg; gst_segment_init (&seg, GST_FORMAT_TIME); seg.start = start; seg.stop = stop; seg.time = time; event = gst_event_new_segment (&seg); gst_pad_push_event (y4mdec->srcpad, event); //gst_event_unref (event); y4mdec->have_new_segment = FALSE; y4mdec->frame_index = gst_y4m_dec_bytes_to_frames (y4mdec, y4mdec->segment.time); GST_DEBUG ("new frame_index %d", y4mdec->frame_index); } while (1) { n_avail = gst_adapter_available (y4mdec->adapter); if (n_avail < MAX_HEADER_LENGTH) break; gst_adapter_copy (y4mdec->adapter, (guint8 *) header, 0, MAX_HEADER_LENGTH); header[MAX_HEADER_LENGTH - 1] = 0; for (i = 0; i < MAX_HEADER_LENGTH; i++) { if (header[i] == 0x0a) header[i] = 0; } if (memcmp (header, "FRAME", 5) != 0) { GST_ELEMENT_ERROR (y4mdec, STREAM, DECODE, ("Failed to parse YUV4MPEG frame"), (NULL)); flow_ret = GST_FLOW_ERROR; break; } len = strlen (header); if (n_avail < y4mdec->info.size + len + 1) { /* not enough data */ GST_DEBUG ("not enough data for frame %d < %" G_GSIZE_FORMAT, n_avail, y4mdec->info.size + len + 1); break; } gst_adapter_flush (y4mdec->adapter, len + 1); buffer = gst_adapter_take_buffer (y4mdec->adapter, y4mdec->info.size); GST_BUFFER_TIMESTAMP (buffer) = gst_y4m_dec_frames_to_timestamp (y4mdec, y4mdec->frame_index); GST_BUFFER_DURATION (buffer) = gst_y4m_dec_frames_to_timestamp (y4mdec, y4mdec->frame_index + 1) - GST_BUFFER_TIMESTAMP (buffer); y4mdec->frame_index++; if (y4mdec->video_meta) { gst_buffer_add_video_meta_full (buffer, 0, y4mdec->info.finfo->format, y4mdec->info.width, y4mdec->info.height, y4mdec->info.finfo->n_planes, y4mdec->info.offset, y4mdec->info.stride); } else if (memcmp (&y4mdec->info, &y4mdec->out_info, sizeof (y4mdec->info)) != 0) { GstBuffer *outbuf; GstVideoFrame iframe, oframe; gint i, j; gint w, h, istride, ostride; guint8 *src, *dest; /* Allocate a new buffer and do stride conversion */ g_assert (y4mdec->pool != NULL); flow_ret = gst_buffer_pool_acquire_buffer (y4mdec->pool, &outbuf, NULL); if (flow_ret != GST_FLOW_OK) { gst_buffer_unref (buffer); break; } gst_video_frame_map (&iframe, &y4mdec->info, buffer, GST_MAP_READ); gst_video_frame_map (&oframe, &y4mdec->out_info, outbuf, GST_MAP_WRITE); for (i = 0; i < 3; i++) { w = GST_VIDEO_FRAME_COMP_WIDTH (&iframe, i); h = GST_VIDEO_FRAME_COMP_HEIGHT (&iframe, i); istride = GST_VIDEO_FRAME_COMP_STRIDE (&iframe, i); ostride = GST_VIDEO_FRAME_COMP_STRIDE (&oframe, i); src = GST_VIDEO_FRAME_COMP_DATA (&iframe, i); dest = GST_VIDEO_FRAME_COMP_DATA (&oframe, i); for (j = 0; j < h; j++) { memcpy (dest, src, w); dest += ostride; src += istride; } } gst_video_frame_unmap (&iframe); gst_video_frame_unmap (&oframe); gst_buffer_copy_into (outbuf, buffer, GST_BUFFER_COPY_TIMESTAMPS, 0, -1); gst_buffer_unref (buffer); buffer = outbuf; } flow_ret = gst_pad_push (y4mdec->srcpad, buffer); if (flow_ret != GST_FLOW_OK) break; } GST_DEBUG ("returning %d", flow_ret); return flow_ret; }
/* Copy fixed header and extension. Replace current ssrc by ssrc1, * remove OSN and replace current seq num by OSN. * Copy memory to avoid to manually copy each rtp buffer field. */ static GstBuffer * _gst_rtp_buffer_new_from_rtx (GstRTPBuffer * rtp, guint32 ssrc1, guint16 orign_seqnum, guint8 origin_payload_type) { GstMemory *mem = NULL; GstRTPBuffer new_rtp = GST_RTP_BUFFER_INIT; GstBuffer *new_buffer = gst_buffer_new (); GstMapInfo map; guint payload_len = 0; /* copy fixed header */ mem = gst_memory_copy (rtp->map[0].memory, (guint8 *) rtp->data[0] - rtp->map[0].data, rtp->size[0]); gst_buffer_append_memory (new_buffer, mem); /* copy extension if any */ if (rtp->size[1]) { mem = gst_memory_copy (rtp->map[1].memory, (guint8 *) rtp->data[1] - rtp->map[1].data, rtp->size[1]); gst_buffer_append_memory (new_buffer, mem); } /* copy payload and remove OSN */ payload_len = rtp->size[2] - 2; mem = gst_allocator_alloc (NULL, payload_len, NULL); gst_memory_map (mem, &map, GST_MAP_WRITE); if (rtp->size[2]) memcpy (map.data, (guint8 *) rtp->data[2] + 2, payload_len); gst_memory_unmap (mem, &map); gst_buffer_append_memory (new_buffer, mem); /* the sender always constructs rtx packets without padding, * But the receiver can still receive rtx packets with padding. * So just copy it. */ if (rtp->size[3]) { guint pad_len = rtp->size[3]; mem = gst_allocator_alloc (NULL, pad_len, NULL); gst_memory_map (mem, &map, GST_MAP_WRITE); map.data[pad_len - 1] = pad_len; gst_memory_unmap (mem, &map); gst_buffer_append_memory (new_buffer, mem); } /* set ssrc and seq num */ gst_rtp_buffer_map (new_buffer, GST_MAP_WRITE, &new_rtp); gst_rtp_buffer_set_ssrc (&new_rtp, ssrc1); gst_rtp_buffer_set_seq (&new_rtp, orign_seqnum); gst_rtp_buffer_set_payload_type (&new_rtp, origin_payload_type); gst_rtp_buffer_unmap (&new_rtp); gst_buffer_copy_into (new_buffer, rtp->buffer, GST_BUFFER_COPY_FLAGS | GST_BUFFER_COPY_TIMESTAMPS, 0, -1); GST_BUFFER_FLAG_SET (new_buffer, GST_RTP_BUFFER_FLAG_RETRANSMISSION); return new_buffer; }
/** * gst_vaapi_plugin_base_get_input_buffer: * @plugin: a #GstVaapiPluginBase * @incaps: the sink pad (input) buffer * @outbuf_ptr: the pointer to location to the VA surface backed buffer * * Acquires the sink pad (input) buffer as a VA surface backed * buffer. This is mostly useful for raw YUV buffers, as source * buffers that are already backed as a VA surface are passed * verbatim. * * Returns: #GST_FLOW_OK if the buffer could be acquired */ GstFlowReturn gst_vaapi_plugin_base_get_input_buffer (GstVaapiPluginBase * plugin, GstBuffer * inbuf, GstBuffer ** outbuf_ptr) { GstVaapiVideoMeta *meta; GstBuffer *outbuf; GstVideoFrame src_frame, out_frame; gboolean success; g_return_val_if_fail (inbuf != NULL, GST_FLOW_ERROR); g_return_val_if_fail (outbuf_ptr != NULL, GST_FLOW_ERROR); meta = gst_buffer_get_vaapi_video_meta (inbuf); if (meta) { *outbuf_ptr = gst_buffer_ref (inbuf); return GST_FLOW_OK; } if (!plugin->sinkpad_caps_is_raw) goto error_invalid_buffer; if (!plugin->sinkpad_buffer_pool) goto error_no_pool; if (!gst_buffer_pool_set_active (plugin->sinkpad_buffer_pool, TRUE)) goto error_active_pool; outbuf = NULL; if (gst_buffer_pool_acquire_buffer (plugin->sinkpad_buffer_pool, &outbuf, NULL) != GST_FLOW_OK) goto error_create_buffer; if (is_dma_buffer (inbuf)) { if (!plugin_bind_dma_to_vaapi_buffer (plugin, inbuf, outbuf)) goto error_bind_dma_buffer; goto done; } if (!gst_video_frame_map (&src_frame, &plugin->sinkpad_info, inbuf, GST_MAP_READ)) goto error_map_src_buffer; if (!gst_video_frame_map (&out_frame, &plugin->sinkpad_info, outbuf, GST_MAP_WRITE)) goto error_map_dst_buffer; success = gst_video_frame_copy (&out_frame, &src_frame); gst_video_frame_unmap (&out_frame); gst_video_frame_unmap (&src_frame); if (!success) goto error_copy_buffer; done: gst_buffer_copy_into (outbuf, inbuf, GST_BUFFER_COPY_FLAGS | GST_BUFFER_COPY_TIMESTAMPS, 0, -1); *outbuf_ptr = outbuf; return GST_FLOW_OK; /* ERRORS */ error_no_pool: { GST_ELEMENT_ERROR (plugin, STREAM, FAILED, ("no buffer pool was negotiated"), ("no buffer pool was negotiated")); return GST_FLOW_ERROR; } error_active_pool: { GST_ELEMENT_ERROR (plugin, STREAM, FAILED, ("failed to activate buffer pool"), ("failed to activate buffer pool")); return GST_FLOW_ERROR; } error_map_dst_buffer: { gst_video_frame_unmap (&src_frame); // fall-through } error_map_src_buffer: { GST_WARNING ("failed to map buffer"); gst_buffer_unref (outbuf); return GST_FLOW_NOT_SUPPORTED; } /* ERRORS */ error_invalid_buffer: { GST_ELEMENT_ERROR (plugin, STREAM, FAILED, ("failed to validate source buffer"), ("failed to validate source buffer")); return GST_FLOW_ERROR; } error_create_buffer: { GST_ELEMENT_ERROR (plugin, STREAM, FAILED, ("Allocation failed"), ("failed to create buffer")); return GST_FLOW_ERROR; } error_bind_dma_buffer: { GST_ELEMENT_ERROR (plugin, STREAM, FAILED, ("Allocation failed"), ("failed to bind dma_buf to VA surface buffer")); gst_buffer_unref (outbuf); return GST_FLOW_ERROR; } error_copy_buffer: { GST_WARNING ("failed to upload buffer to VA surface"); gst_buffer_unref (outbuf); return GST_FLOW_NOT_SUPPORTED; } }
static GstFlowReturn gst_mfxpostproc_transform (GstBaseTransform * trans, GstBuffer * inbuf, GstBuffer * outbuf) { GstMfxPostproc *const vpp = GST_MFXPOSTPROC (trans); GstMfxVideoMeta *inbuf_meta, *outbuf_meta; GstMfxSurface *surface, *out_surface; GstMfxFilterStatus status = GST_MFX_FILTER_STATUS_SUCCESS; GstFlowReturn ret = GST_FLOW_OK; GstBuffer *buf = NULL; GstMfxRectangle *crop_rect = NULL; GstClockTime timestamp; timestamp = GST_BUFFER_TIMESTAMP (inbuf); ret = gst_mfx_plugin_base_get_input_buffer (GST_MFX_PLUGIN_BASE (vpp), inbuf, &buf); if (GST_FLOW_OK != ret) return ret; inbuf_meta = gst_buffer_get_mfx_video_meta (buf); surface = gst_mfx_video_meta_get_surface (inbuf_meta); if (!surface) goto error_create_surface; do { if (vpp->flags & GST_MFX_POSTPROC_FLAG_FRC) { if (GST_MFX_FILTER_STATUS_ERROR_MORE_SURFACE != status) gst_buffer_replace (&buf, NULL); buf = create_output_buffer (vpp); if (!buf) goto error_create_buffer; } status = gst_mfx_filter_process (vpp->filter, surface, &out_surface); if (GST_MFX_FILTER_STATUS_SUCCESS != status && GST_MFX_FILTER_STATUS_ERROR_MORE_SURFACE != status && GST_MFX_FILTER_STATUS_ERROR_MORE_DATA != status) goto error_process_vpp; if (GST_MFX_FILTER_STATUS_ERROR_MORE_SURFACE == status) outbuf_meta = gst_buffer_get_mfx_video_meta (buf); else outbuf_meta = gst_buffer_get_mfx_video_meta (outbuf); if (!outbuf_meta) goto error_create_meta; gst_mfx_video_meta_set_surface (outbuf_meta, out_surface); crop_rect = gst_mfx_surface_get_crop_rect (out_surface); if (crop_rect) { GstVideoCropMeta *const crop_meta = gst_buffer_add_video_crop_meta (outbuf); if (crop_meta) { crop_meta->x = crop_rect->x; crop_meta->y = crop_rect->y; crop_meta->width = crop_rect->width; crop_meta->height = crop_rect->height; } } if (GST_MFX_FILTER_STATUS_ERROR_MORE_DATA == status) { gst_buffer_unref (buf); return GST_BASE_TRANSFORM_FLOW_DROPPED; } if (GST_MFX_FILTER_STATUS_ERROR_MORE_SURFACE == status) { GST_BUFFER_TIMESTAMP (buf) = timestamp; GST_BUFFER_DURATION (buf) = vpp->field_duration; timestamp += vpp->field_duration; ret = gst_pad_push (trans->srcpad, buf); } else { if (vpp->flags & GST_MFX_POSTPROC_FLAG_FRC) { GST_BUFFER_TIMESTAMP (outbuf) = timestamp; GST_BUFFER_DURATION (outbuf) = vpp->field_duration; } else { gst_buffer_copy_into (outbuf, inbuf, GST_BUFFER_COPY_TIMESTAMPS, 0, -1); } } } while (GST_MFX_FILTER_STATUS_ERROR_MORE_SURFACE == status && GST_FLOW_OK == ret); gst_mfx_surface_dequeue(surface); #if GST_CHECK_VERSION(1,8,0) gst_mfx_plugin_base_export_dma_buffer (GST_MFX_PLUGIN_BASE (vpp), outbuf); #endif // GST_CHECK_VERSION gst_buffer_unref (buf); return ret; /* ERRORS */ error_create_buffer: { GST_ERROR ("failed to output buffer"); gst_buffer_unref (buf); return GST_FLOW_ERROR; } error_create_meta: { GST_ERROR ("failed to create new output buffer meta"); gst_buffer_unref (buf); return GST_FLOW_ERROR; } error_create_surface: { GST_ERROR ("failed to create surface surface from buffer"); gst_buffer_unref (buf); return GST_FLOW_ERROR; } error_process_vpp: { GST_ERROR ("failed to apply VPP (error %d)", status); gst_buffer_unref (buf); return GST_FLOW_ERROR; } }
static GstFlowReturn stereosplit_chain (GstPad * pad, GstGLStereoSplit * split, GstBuffer * buf) { GstBuffer *uploaded_buffer, *converted_buffer, *left, *right; GstBuffer *split_buffer = NULL; GstFlowReturn ret; gint i, n_planes; if (!split->upload) _init_upload (split); n_planes = GST_VIDEO_INFO_N_PLANES (&split->viewconvert->out_info); GST_LOG_OBJECT (split, "chaining buffer %" GST_PTR_FORMAT, buf); if (GST_GL_UPLOAD_DONE != gst_gl_upload_perform_with_buffer (split->upload, buf, &uploaded_buffer)) { gst_buffer_unref (buf); GST_ELEMENT_ERROR (split, RESOURCE, NOT_FOUND, ("%s", "Failed to upload buffer"), (NULL)); return GST_FLOW_ERROR; } gst_buffer_unref (buf); if (!(converted_buffer = gst_gl_color_convert_perform (split->convert, uploaded_buffer))) { GST_ELEMENT_ERROR (split, RESOURCE, NOT_FOUND, ("%s", "Failed to convert buffer"), (NULL)); gst_buffer_unref (uploaded_buffer); return GST_FLOW_ERROR; } gst_buffer_unref (uploaded_buffer); if (gst_gl_view_convert_submit_input_buffer (split->viewconvert, GST_BUFFER_IS_DISCONT (converted_buffer), converted_buffer) != GST_FLOW_OK) { GST_ELEMENT_ERROR (split, RESOURCE, NOT_FOUND, ("%s", "Failed to 3d convert buffer"), ("Could not get submit input buffer")); return GST_FLOW_ERROR; } ret = gst_gl_view_convert_get_output (split->viewconvert, &split_buffer); if (ret != GST_FLOW_OK) { GST_ELEMENT_ERROR (split, RESOURCE, NOT_FOUND, ("%s", "Failed to 3d convert buffer"), ("Could not get output buffer")); return GST_FLOW_ERROR; } if (split_buffer == NULL) return GST_FLOW_OK; /* Need another input buffer */ left = gst_buffer_new (); gst_buffer_copy_into (left, buf, GST_BUFFER_COPY_FLAGS | GST_BUFFER_COPY_TIMESTAMPS, 0, -1); GST_BUFFER_FLAG_UNSET (left, GST_VIDEO_BUFFER_FLAG_FIRST_IN_BUNDLE); gst_buffer_add_parent_buffer_meta (left, split_buffer); for (i = 0; i < n_planes; i++) { GstMemory *mem = gst_buffer_get_memory (split_buffer, i); gst_buffer_append_memory (left, mem); } ret = gst_pad_push (split->left_pad, gst_buffer_ref (left)); /* Allow unlinked on the first pad - as long as the 2nd isn't unlinked */ gst_buffer_unref (left); if (G_UNLIKELY (ret != GST_FLOW_OK && ret != GST_FLOW_NOT_LINKED)) { gst_buffer_unref (split_buffer); return ret; } right = gst_buffer_new (); gst_buffer_copy_into (right, buf, GST_BUFFER_COPY_FLAGS | GST_BUFFER_COPY_TIMESTAMPS, 0, -1); GST_BUFFER_FLAG_UNSET (left, GST_VIDEO_BUFFER_FLAG_FIRST_IN_BUNDLE); gst_buffer_add_parent_buffer_meta (right, split_buffer); for (i = n_planes; i < n_planes * 2; i++) { GstMemory *mem = gst_buffer_get_memory (split_buffer, i); gst_buffer_append_memory (right, mem); } ret = gst_pad_push (split->right_pad, gst_buffer_ref (right)); gst_buffer_unref (right); gst_buffer_unref (split_buffer); return ret; }
static GstFlowReturn gst_frei0r_mixer_collected (GstCollectPads * pads, GstFrei0rMixer * self) { GstBuffer *inbuf0 = NULL, *inbuf1 = NULL, *inbuf2 = NULL; GstBuffer *outbuf = NULL; GstFlowReturn ret = GST_FLOW_OK; GSList *l; GstFrei0rMixerClass *klass = GST_FREI0R_MIXER_GET_CLASS (self); GstClockTime timestamp; gdouble time; GstSegment *segment = NULL; GstAllocationParams alloc_params = { 0, 31, 0, 0 }; GstMapInfo outmap, inmap0, inmap1, inmap2; if (G_UNLIKELY (self->info.width <= 0 || self->info.height <= 0)) return GST_FLOW_NOT_NEGOTIATED; if (G_UNLIKELY (!self->f0r_instance)) { self->f0r_instance = gst_frei0r_instance_construct (klass->ftable, klass->properties, klass->n_properties, self->property_cache, self->info.width, self->info.height); if (G_UNLIKELY (!self->f0r_instance)) return GST_FLOW_ERROR; } if (self->segment_event) { gst_pad_push_event (self->src, self->segment_event); self->segment_event = NULL; } /* FIXME Request an allocator and/or pool */ outbuf = gst_buffer_new_allocate (NULL, self->info.size, &alloc_params); for (l = pads->data; l; l = l->next) { GstCollectData *cdata = l->data; if (cdata->pad == self->sink0) { inbuf0 = gst_collect_pads_pop (pads, cdata); segment = &cdata->segment; } else if (cdata->pad == self->sink1) { inbuf1 = gst_collect_pads_pop (pads, cdata); } else if (cdata->pad == self->sink2) { inbuf2 = gst_collect_pads_pop (pads, cdata); } } if (!inbuf0 || !inbuf1 || (!inbuf2 && self->sink2)) goto eos; gst_buffer_map (outbuf, &outmap, GST_MAP_READWRITE); gst_buffer_map (inbuf0, &inmap0, GST_MAP_READ); gst_buffer_map (inbuf1, &inmap1, GST_MAP_READ); if (inbuf2) gst_buffer_map (inbuf2, &inmap2, GST_MAP_READ); g_assert (segment != NULL); timestamp = GST_BUFFER_PTS (inbuf0); timestamp = gst_segment_to_stream_time (segment, GST_FORMAT_TIME, timestamp); GST_DEBUG_OBJECT (self, "sync to %" GST_TIME_FORMAT, GST_TIME_ARGS (timestamp)); if (GST_CLOCK_TIME_IS_VALID (timestamp)) gst_object_sync_values (GST_OBJECT (self), timestamp); gst_buffer_copy_into (outbuf, inbuf0, GST_BUFFER_COPY_FLAGS | GST_BUFFER_COPY_TIMESTAMPS, 0, -1); time = ((gdouble) GST_BUFFER_PTS (outbuf)) / GST_SECOND; GST_OBJECT_LOCK (self); klass->ftable->update2 (self->f0r_instance, time, (const guint32 *) inmap0.data, (const guint32 *) inmap1.data, (inbuf2) ? (const guint32 *) inmap2.data : NULL, (guint32 *) outmap.data); GST_OBJECT_UNLOCK (self); gst_buffer_unmap (outbuf, &outmap); gst_buffer_unref (inbuf0); gst_buffer_unmap (inbuf0, &inmap0); gst_buffer_unref (inbuf1); gst_buffer_unmap (inbuf1, &inmap1); if (inbuf2) { gst_buffer_unmap (inbuf2, &inmap2); gst_buffer_unref (inbuf2); } ret = gst_pad_push (self->src, outbuf); return ret; eos: { GST_DEBUG_OBJECT (self, "no data available, must be EOS"); gst_buffer_unref (outbuf); if (inbuf0) gst_buffer_unref (inbuf0); if (inbuf1) gst_buffer_unref (inbuf1); if (inbuf2) gst_buffer_unref (inbuf2); gst_pad_push_event (self->src, gst_event_new_eos ()); return GST_FLOW_EOS; } }
static GstFlowReturn gst_v4l2_video_dec_handle_frame (GstVideoDecoder * decoder, GstVideoCodecFrame * frame) { GstV4l2Error error = GST_V4L2_ERROR_INIT; GstV4l2VideoDec *self = GST_V4L2_VIDEO_DEC (decoder); GstFlowReturn ret = GST_FLOW_OK; gboolean processed = FALSE; GstBuffer *tmp; GST_DEBUG_OBJECT (self, "Handling frame %d", frame->system_frame_number); if (G_UNLIKELY (!g_atomic_int_get (&self->active))) goto flushing; if (G_UNLIKELY (!GST_V4L2_IS_ACTIVE (self->v4l2output))) { if (!self->input_state) goto not_negotiated; if (!gst_v4l2_object_set_format (self->v4l2output, self->input_state->caps, &error)) goto not_negotiated; } if (G_UNLIKELY (!GST_V4L2_IS_ACTIVE (self->v4l2capture))) { GstBufferPool *pool = GST_BUFFER_POOL (self->v4l2output->pool); GstVideoInfo info; GstVideoCodecState *output_state; GstBuffer *codec_data; GstCaps *acquired_caps, *available_caps, *caps, *filter; GstStructure *st; GST_DEBUG_OBJECT (self, "Sending header"); codec_data = self->input_state->codec_data; /* We are running in byte-stream mode, so we don't know the headers, but * we need to send something, otherwise the decoder will refuse to * intialize. */ if (codec_data) { gst_buffer_ref (codec_data); } else { codec_data = gst_buffer_ref (frame->input_buffer); processed = TRUE; } /* Ensure input internal pool is active */ if (!gst_buffer_pool_is_active (pool)) { GstStructure *config = gst_buffer_pool_get_config (pool); gst_buffer_pool_config_set_params (config, self->input_state->caps, self->v4l2output->info.size, 2, 2); /* There is no reason to refuse this config */ if (!gst_buffer_pool_set_config (pool, config)) goto activate_failed; if (!gst_buffer_pool_set_active (pool, TRUE)) goto activate_failed; } GST_VIDEO_DECODER_STREAM_UNLOCK (decoder); ret = gst_v4l2_buffer_pool_process (GST_V4L2_BUFFER_POOL (self-> v4l2output->pool), &codec_data); GST_VIDEO_DECODER_STREAM_LOCK (decoder); gst_buffer_unref (codec_data); /* For decoders G_FMT returns coded size, G_SELECTION returns visible size * in the compose rectangle. gst_v4l2_object_acquire_format() checks both * and returns the visible size as with/height and the coded size as * padding. */ if (!gst_v4l2_object_acquire_format (self->v4l2capture, &info)) goto not_negotiated; /* Create caps from the acquired format, remove the format field */ acquired_caps = gst_video_info_to_caps (&info); st = gst_caps_get_structure (acquired_caps, 0); gst_structure_remove_field (st, "format"); /* Probe currently available pixel formats */ available_caps = gst_v4l2_object_probe_caps (self->v4l2capture, NULL); available_caps = gst_caps_make_writable (available_caps); /* Replace coded size with visible size, we want to negotiate visible size * with downstream, not coded size. */ gst_caps_map_in_place (available_caps, gst_v4l2_video_remove_padding, self); filter = gst_caps_intersect_full (available_caps, acquired_caps, GST_CAPS_INTERSECT_FIRST); gst_caps_unref (acquired_caps); gst_caps_unref (available_caps); caps = gst_pad_peer_query_caps (decoder->srcpad, filter); gst_caps_unref (filter); GST_DEBUG_OBJECT (self, "Possible decoded caps: %" GST_PTR_FORMAT, caps); if (gst_caps_is_empty (caps)) { gst_caps_unref (caps); goto not_negotiated; } /* Fixate pixel format */ caps = gst_caps_fixate (caps); GST_DEBUG_OBJECT (self, "Chosen decoded caps: %" GST_PTR_FORMAT, caps); /* Try to set negotiated format, on success replace acquired format */ if (gst_v4l2_object_set_format (self->v4l2capture, caps, &error)) gst_video_info_from_caps (&info, caps); else gst_v4l2_clear_error (&error); gst_caps_unref (caps); output_state = gst_video_decoder_set_output_state (decoder, info.finfo->format, info.width, info.height, self->input_state); /* Copy the rest of the information, there might be more in the future */ output_state->info.interlace_mode = info.interlace_mode; gst_video_codec_state_unref (output_state); if (!gst_video_decoder_negotiate (decoder)) { if (GST_PAD_IS_FLUSHING (decoder->srcpad)) goto flushing; else goto not_negotiated; } /* Ensure our internal pool is activated */ if (!gst_buffer_pool_set_active (GST_BUFFER_POOL (self->v4l2capture->pool), TRUE)) goto activate_failed; } if (g_atomic_int_get (&self->processing) == FALSE) { /* It's possible that the processing thread stopped due to an error */ if (self->output_flow != GST_FLOW_OK && self->output_flow != GST_FLOW_FLUSHING) { GST_DEBUG_OBJECT (self, "Processing loop stopped with error, leaving"); ret = self->output_flow; goto drop; } GST_DEBUG_OBJECT (self, "Starting decoding thread"); /* Start the processing task, when it quits, the task will disable input * processing to unlock input if draining, or prevent potential block */ g_atomic_int_set (&self->processing, TRUE); if (!gst_pad_start_task (decoder->srcpad, (GstTaskFunction) gst_v4l2_video_dec_loop, self, (GDestroyNotify) gst_v4l2_video_dec_loop_stopped)) goto start_task_failed; } if (!processed) { GST_VIDEO_DECODER_STREAM_UNLOCK (decoder); ret = gst_v4l2_buffer_pool_process (GST_V4L2_BUFFER_POOL (self->v4l2output-> pool), &frame->input_buffer); GST_VIDEO_DECODER_STREAM_LOCK (decoder); if (ret == GST_FLOW_FLUSHING) { if (g_atomic_int_get (&self->processing) == FALSE) ret = self->output_flow; goto drop; } else if (ret != GST_FLOW_OK) { goto process_failed; } } /* No need to keep input arround */ tmp = frame->input_buffer; frame->input_buffer = gst_buffer_new (); gst_buffer_copy_into (frame->input_buffer, tmp, GST_BUFFER_COPY_FLAGS | GST_BUFFER_COPY_TIMESTAMPS | GST_BUFFER_COPY_META, 0, 0); gst_buffer_unref (tmp); gst_video_codec_frame_unref (frame); return ret; /* ERRORS */ not_negotiated: { GST_ERROR_OBJECT (self, "not negotiated"); ret = GST_FLOW_NOT_NEGOTIATED; gst_v4l2_error (self, &error); goto drop; } activate_failed: { GST_ELEMENT_ERROR (self, RESOURCE, SETTINGS, (_("Failed to allocate required memory.")), ("Buffer pool activation failed")); ret = GST_FLOW_ERROR; goto drop; } flushing: { ret = GST_FLOW_FLUSHING; goto drop; } start_task_failed: { GST_ELEMENT_ERROR (self, RESOURCE, FAILED, (_("Failed to start decoding thread.")), (NULL)); g_atomic_int_set (&self->processing, FALSE); ret = GST_FLOW_ERROR; goto drop; } process_failed: { GST_ELEMENT_ERROR (self, RESOURCE, FAILED, (_("Failed to process frame.")), ("Maybe be due to not enough memory or failing driver")); ret = GST_FLOW_ERROR; goto drop; } drop: { gst_video_decoder_drop_frame (decoder, frame); return ret; } }
static GstFlowReturn gst_shm_sink_render (GstBaseSink * bsink, GstBuffer * buf) { GstShmSink *self = GST_SHM_SINK (bsink); int rv = 0; GstMapInfo map; gboolean need_new_memory = FALSE; GstFlowReturn ret = GST_FLOW_OK; GstMemory *memory = NULL; GstBuffer *sendbuf = NULL; gsize written_bytes; GST_OBJECT_LOCK (self); while (self->wait_for_connection && !self->clients) { g_cond_wait (&self->cond, GST_OBJECT_GET_LOCK (self)); if (self->unlock) { GST_OBJECT_UNLOCK (self); ret = gst_base_sink_wait_preroll (bsink); if (ret == GST_FLOW_OK) GST_OBJECT_LOCK (self); else return ret; } } while (!gst_shm_sink_can_render (self, GST_BUFFER_TIMESTAMP (buf))) { g_cond_wait (&self->cond, GST_OBJECT_GET_LOCK (self)); if (self->unlock) { GST_OBJECT_UNLOCK (self); ret = gst_base_sink_wait_preroll (bsink); if (ret == GST_FLOW_OK) GST_OBJECT_LOCK (self); else return ret; } } if (gst_buffer_n_memory (buf) > 1) { GST_LOG_OBJECT (self, "Buffer %p has %d GstMemory, we only support a single" " one, need to do a memcpy", buf, gst_buffer_n_memory (buf)); need_new_memory = TRUE; } else { memory = gst_buffer_peek_memory (buf, 0); if (memory->allocator != GST_ALLOCATOR (self->allocator)) { need_new_memory = TRUE; GST_LOG_OBJECT (self, "Memory in buffer %p was not allocated by " "%" GST_PTR_FORMAT ", will memcpy", buf, memory->allocator); } } if (need_new_memory) { if (gst_buffer_get_size (buf) > sp_writer_get_max_buf_size (self->pipe)) { gsize area_size = sp_writer_get_max_buf_size (self->pipe); GST_ELEMENT_ERROR (self, RESOURCE, NO_SPACE_LEFT, (NULL), ("Shared memory area of size %" G_GSIZE_FORMAT " is smaller than" "buffer of size %" G_GSIZE_FORMAT, area_size, gst_buffer_get_size (buf))); goto error; } while ((memory = gst_shm_sink_allocator_alloc_locked (self->allocator, gst_buffer_get_size (buf), &self->params)) == NULL) { g_cond_wait (&self->cond, GST_OBJECT_GET_LOCK (self)); if (self->unlock) { GST_OBJECT_UNLOCK (self); ret = gst_base_sink_wait_preroll (bsink); if (ret == GST_FLOW_OK) GST_OBJECT_LOCK (self); else return ret; } } while (self->wait_for_connection && !self->clients) { g_cond_wait (&self->cond, GST_OBJECT_GET_LOCK (self)); if (self->unlock) { GST_OBJECT_UNLOCK (self); ret = gst_base_sink_wait_preroll (bsink); if (ret == GST_FLOW_OK) { GST_OBJECT_LOCK (self); } else { gst_memory_unref (memory); return ret; } } } if (!gst_memory_map (memory, &map, GST_MAP_WRITE)) { GST_ELEMENT_ERROR (self, STREAM, FAILED, (NULL), ("Failed to map memory")); goto error; } GST_DEBUG_OBJECT (self, "Copying %" G_GSIZE_FORMAT " bytes into map of size %" G_GSIZE_FORMAT " bytes.", gst_buffer_get_size (buf), map.size); written_bytes = gst_buffer_extract (buf, 0, map.data, map.size); GST_DEBUG_OBJECT (self, "Copied %" G_GSIZE_FORMAT " bytes.", written_bytes); gst_memory_unmap (memory, &map); sendbuf = gst_buffer_new (); if (!gst_buffer_copy_into (sendbuf, buf, GST_BUFFER_COPY_METADATA, 0, -1)) { GST_ELEMENT_ERROR (self, STREAM, FAILED, (NULL), ("Failed to copy data into send buffer")); gst_buffer_unref (sendbuf); goto error; } gst_buffer_append_memory (sendbuf, memory); } else { sendbuf = gst_buffer_ref (buf); } if (!gst_buffer_map (sendbuf, &map, GST_MAP_READ)) { GST_ELEMENT_ERROR (self, STREAM, FAILED, (NULL), ("Failed to map data into send buffer")); goto error; } /* Make the memory readonly as of now as we've sent it to the other side * We know it's not mapped for writing anywhere as we just mapped it for * reading */ rv = sp_writer_send_buf (self->pipe, (char *) map.data, map.size, sendbuf); if (rv == -1) { GST_ELEMENT_ERROR (self, STREAM, FAILED, (NULL), ("Failed to send data over SHM")); gst_buffer_unmap (sendbuf, &map); goto error; } gst_buffer_unmap (sendbuf, &map); GST_OBJECT_UNLOCK (self); if (rv == 0) { GST_DEBUG_OBJECT (self, "No clients connected, unreffing buffer"); gst_buffer_unref (sendbuf); } return ret; error: GST_OBJECT_UNLOCK (self); return GST_FLOW_ERROR; }
static GstFlowReturn gst_deinterleave_process (GstDeinterleave * self, GstBuffer * buf) { GstFlowReturn ret = GST_FLOW_OK; guint channels = GST_AUDIO_INFO_CHANNELS (&self->audio_info); guint pads_pushed = 0, buffers_allocated = 0; guint nframes = gst_buffer_get_size (buf) / channels / (GST_AUDIO_INFO_WIDTH (&self->audio_info) / 8); guint bufsize = nframes * (GST_AUDIO_INFO_WIDTH (&self->audio_info) / 8); guint i; GList *srcs; GstBuffer **buffers_out = g_new0 (GstBuffer *, channels); guint8 *in, *out; GstMapInfo read_info; GList *pending_events, *l; /* Send any pending events to all src pads */ GST_OBJECT_LOCK (self); pending_events = self->pending_events; self->pending_events = NULL; GST_OBJECT_UNLOCK (self); if (pending_events) { GstEvent *event; GST_DEBUG_OBJECT (self, "Sending pending events to all src pads"); for (l = pending_events; l; l = l->next) { event = l->data; for (srcs = self->srcpads; srcs != NULL; srcs = srcs->next) gst_pad_push_event (GST_PAD (srcs->data), gst_event_ref (event)); gst_event_unref (event); } g_list_free (pending_events); } gst_buffer_map (buf, &read_info, GST_MAP_READ); /* Allocate buffers */ for (srcs = self->srcpads, i = 0; srcs; srcs = srcs->next, i++) { buffers_out[i] = gst_buffer_new_allocate (NULL, bufsize, NULL); /* Make sure we got a correct buffer. The only other case we allow * here is an unliked pad */ if (!buffers_out[i]) goto alloc_buffer_failed; else if (buffers_out[i] && gst_buffer_get_size (buffers_out[i]) != bufsize) goto alloc_buffer_bad_size; if (buffers_out[i]) { gst_buffer_copy_into (buffers_out[i], buf, GST_BUFFER_COPY_METADATA, 0, -1); buffers_allocated++; } } /* Return NOT_LINKED if no pad was linked */ if (!buffers_allocated) { GST_WARNING_OBJECT (self, "Couldn't allocate any buffers because no pad was linked"); ret = GST_FLOW_NOT_LINKED; goto done; } /* deinterleave */ for (srcs = self->srcpads, i = 0; srcs; srcs = srcs->next, i++) { GstPad *pad = (GstPad *) srcs->data; GstMapInfo write_info; in = (guint8 *) read_info.data; in += i * (GST_AUDIO_INFO_WIDTH (&self->audio_info) / 8); if (buffers_out[i]) { gst_buffer_map (buffers_out[i], &write_info, GST_MAP_WRITE); out = (guint8 *) write_info.data; self->func (out, in, channels, nframes); gst_buffer_unmap (buffers_out[i], &write_info); ret = gst_pad_push (pad, buffers_out[i]); buffers_out[i] = NULL; if (ret == GST_FLOW_OK) pads_pushed++; else if (ret == GST_FLOW_NOT_LINKED) ret = GST_FLOW_OK; else goto push_failed; } } /* Return NOT_LINKED if no pad was linked */ if (!pads_pushed) ret = GST_FLOW_NOT_LINKED; GST_DEBUG_OBJECT (self, "Pushed on %d pads", pads_pushed); done: gst_buffer_unmap (buf, &read_info); gst_buffer_unref (buf); g_free (buffers_out); return ret; alloc_buffer_failed: { GST_WARNING ("gst_pad_alloc_buffer() returned %s", gst_flow_get_name (ret)); goto clean_buffers; } alloc_buffer_bad_size: { GST_WARNING ("called alloc_buffer(), but didn't get requested bytes"); ret = GST_FLOW_NOT_NEGOTIATED; goto clean_buffers; } push_failed: { GST_DEBUG ("push() failed, flow = %s", gst_flow_get_name (ret)); goto clean_buffers; } clean_buffers: { gst_buffer_unmap (buf, &read_info); for (i = 0; i < channels; i++) { if (buffers_out[i]) gst_buffer_unref (buffers_out[i]); } gst_buffer_unref (buf); g_free (buffers_out); return ret; } }
static GstFlowReturn gst_shape_wipe_video_sink_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer) { GstShapeWipe *self = GST_SHAPE_WIPE (parent); GstFlowReturn ret = GST_FLOW_OK; GstBuffer *mask = NULL, *outbuf = NULL; GstClockTime timestamp; gboolean new_outbuf = FALSE; GstVideoFrame inframe, outframe, maskframe; if (G_UNLIKELY (GST_VIDEO_INFO_FORMAT (&self->vinfo) == GST_VIDEO_FORMAT_UNKNOWN)) goto not_negotiated; timestamp = GST_BUFFER_TIMESTAMP (buffer); timestamp = gst_segment_to_stream_time (&self->segment, GST_FORMAT_TIME, timestamp); if (GST_CLOCK_TIME_IS_VALID (timestamp)) gst_object_sync_values (GST_OBJECT (self), timestamp); GST_LOG_OBJECT (self, "Blending buffer with timestamp %" GST_TIME_FORMAT " at position %f", GST_TIME_ARGS (timestamp), self->mask_position); g_mutex_lock (&self->mask_mutex); if (self->shutdown) goto shutdown; if (!self->mask) g_cond_wait (&self->mask_cond, &self->mask_mutex); if (self->mask == NULL || self->shutdown) { goto shutdown; } else { mask = gst_buffer_ref (self->mask); } g_mutex_unlock (&self->mask_mutex); if (!gst_shape_wipe_do_qos (self, GST_BUFFER_TIMESTAMP (buffer))) goto qos; /* Try to blend inplace, if it's not possible * get a new buffer from downstream. */ if (!gst_buffer_is_writable (buffer)) { outbuf = gst_buffer_new_allocate (NULL, gst_buffer_get_size (buffer), NULL); gst_buffer_copy_into (outbuf, buffer, GST_BUFFER_COPY_METADATA, 0, -1); new_outbuf = TRUE; } else { outbuf = buffer; } gst_video_frame_map (&inframe, &self->vinfo, buffer, new_outbuf ? GST_MAP_READ : GST_MAP_READWRITE); gst_video_frame_map (&outframe, &self->vinfo, outbuf, new_outbuf ? GST_MAP_WRITE : GST_MAP_READWRITE); gst_video_frame_map (&maskframe, &self->minfo, mask, GST_MAP_READ); switch (GST_VIDEO_INFO_FORMAT (&self->vinfo)) { case GST_VIDEO_FORMAT_AYUV: case GST_VIDEO_FORMAT_ARGB: case GST_VIDEO_FORMAT_ABGR: if (self->mask_bpp == 16) gst_shape_wipe_blend_argb_16 (self, &inframe, &maskframe, &outframe); else gst_shape_wipe_blend_argb_8 (self, &inframe, &maskframe, &outframe); break; case GST_VIDEO_FORMAT_BGRA: case GST_VIDEO_FORMAT_RGBA: if (self->mask_bpp == 16) gst_shape_wipe_blend_bgra_16 (self, &inframe, &maskframe, &outframe); else gst_shape_wipe_blend_bgra_8 (self, &inframe, &maskframe, &outframe); break; default: g_assert_not_reached (); break; } gst_video_frame_unmap (&outframe); gst_video_frame_unmap (&inframe); gst_video_frame_unmap (&maskframe); gst_buffer_unref (mask); if (new_outbuf) gst_buffer_unref (buffer); ret = gst_pad_push (self->srcpad, outbuf); if (G_UNLIKELY (ret != GST_FLOW_OK)) goto push_failed; return ret; /* Errors */ not_negotiated: { GST_ERROR_OBJECT (self, "No valid caps yet"); gst_buffer_unref (buffer); return GST_FLOW_NOT_NEGOTIATED; } shutdown: { GST_DEBUG_OBJECT (self, "Shutting down"); gst_buffer_unref (buffer); return GST_FLOW_FLUSHING; } qos: { GST_DEBUG_OBJECT (self, "Dropping buffer because of QoS"); gst_buffer_unref (buffer); gst_buffer_unref (mask); return GST_FLOW_OK; } push_failed: { GST_ERROR_OBJECT (self, "Pushing buffer downstream failed: %s", gst_flow_get_name (ret)); return ret; } }
static GstFlowReturn gst_pnmdec_handle_frame (GstVideoDecoder * decoder, GstVideoCodecFrame * frame) { GstPnmdec *s = (GstPnmdec *) decoder; GstMapInfo imap, omap; guint i_rowstride; guint o_rowstride; GstFlowReturn r = GST_FLOW_OK; gint bytes, i, total_bytes = 0; r = gst_video_decoder_allocate_output_frame (decoder, frame); if (r != GST_FLOW_OK) { gst_video_decoder_drop_frame (GST_VIDEO_DECODER (s), frame); goto out; } if (s->mngr.info.encoding == GST_PNM_ENCODING_ASCII) { /* In case of ASCII parsed data is stored in buf, so input needs to be taken from here for frame processing */ gst_buffer_map (s->buf, &imap, GST_MAP_READ); } else { gst_buffer_map (frame->input_buffer, &imap, GST_MAP_READ); } gst_buffer_map (frame->output_buffer, &omap, GST_MAP_WRITE); gst_buffer_copy_into (frame->output_buffer, frame->input_buffer, GST_BUFFER_COPY_METADATA, 0, 0); if (s->mngr.info.type == GST_PNM_TYPE_BITMAP) { bytes = (s->mngr.info.width * s->mngr.info.height + 7) / 8; for (i = 0; i < bytes; i++) { omap.data[i * 8] = (imap.data[i] & 0x80) ? 0 : 255; omap.data[i * 8 + 1] = (imap.data[i] & 0x40) ? 0 : 255; omap.data[i * 8 + 2] = (imap.data[i] & 0x20) ? 0 : 255; omap.data[i * 8 + 3] = (imap.data[i] & 0x10) ? 0 : 255; omap.data[i * 8 + 4] = (imap.data[i] & 0x08) ? 0 : 255; omap.data[i * 8 + 5] = (imap.data[i] & 0x04) ? 0 : 255; omap.data[i * 8 + 6] = (imap.data[i] & 0x02) ? 0 : 255; omap.data[i * 8 + 7] = (imap.data[i] & 0x01) ? 0 : 255; } total_bytes = bytes * 8; } else /* Need to convert from PNM rowstride to GStreamer rowstride */ if (s->mngr.info.width % 4 != 0) { if (s->mngr.info.type == GST_PNM_TYPE_PIXMAP) { i_rowstride = 3 * s->mngr.info.width; o_rowstride = GST_ROUND_UP_4 (i_rowstride); } else { i_rowstride = s->mngr.info.width; o_rowstride = GST_ROUND_UP_4 (i_rowstride); } for (i = 0; i < s->mngr.info.height; i++) memcpy (omap.data + i * o_rowstride, imap.data + i * i_rowstride, i_rowstride); total_bytes = o_rowstride * s->mngr.info.height; } else { memcpy (omap.data, imap.data, s->size); total_bytes = s->size; } if (s->mngr.info.type != GST_PNM_TYPE_BITMAP) { /* Convert the pixels from 0 - max range to 0 - 255 range */ if (s->mngr.info.max < 255) { gint max = s->mngr.info.max; for (i = 0; i < total_bytes; i++) { if (omap.data[i] <= max) { omap.data[i] = 255 * omap.data[i] / max; } else { /* This is an error case, wherein value in the data stream is more than max. Clamp such values to 255 */ omap.data[i] = 255; } } } } if (s->mngr.info.encoding == GST_PNM_ENCODING_ASCII) { gst_buffer_unmap (s->buf, &imap); } else { gst_buffer_unmap (frame->input_buffer, &imap); } gst_buffer_unmap (frame->output_buffer, &omap); r = gst_video_decoder_finish_frame (GST_VIDEO_DECODER (s), frame); out: gst_pnmdec_flush (s); return r; }