/* ...buffer completion hook (tbd - need that at all?) */ static void __objdet_buffer_release(void *cdata, void *cookie) { GstBuffer *buffer = cookie; TRACE(DEBUG, _b("buffer %p released by engine (count=%d)"), buffer, GST_MINI_OBJECT_REFCOUNT(buffer)); /* ...release buffer handle */ gst_buffer_unref(buffer); }
/* ...process new input buffer submitted from camera */ static int objdet_input_process(void *data, int i, GstBuffer *buffer) { app_data_t *app = data; TRACE(DEBUG, _b("front-camera: input buffer received (%p, count=%d)"), buffer, GST_MINI_OBJECT_REFCOUNT(buffer)); /* ...get internal data access lock */ pthread_mutex_lock(&app->lock); /* ...bail out if playback is stopped */ if ((app->flags & APP_FLAG_EOS) == 0) { vsink_meta_t *vmeta = gst_buffer_get_vsink_meta(buffer); objdet_meta_t *ometa = gst_buffer_get_objdet_meta(buffer); /* ...attach current vehicle status info to the buffer */ memcpy(&ometa->info, &app->vehicle, sizeof(vehicle_info_t)); /* ...release internal data access lock */ pthread_mutex_unlock(&app->lock); /* ...serialize access to the object-detection engine */ pthread_mutex_lock(&app->access); /* ...submit buffer to a processing engine */ if (objdet_engine_push_buffer(app->od, buffer, vmeta->plane[0], &ometa->info, &ometa->scene, ometa->buf) < 0) { /* ...silently ignore the error */ TRACE(ERROR, _x("failed to submit a buffer to detection engine: %m")); } else { /* ...buffer submitted successfully; take ownership */ gst_buffer_ref(buffer); } /* ...release object-detection engine access lock */ pthread_mutex_unlock(&app->access); } else { /* ...object detection visualization is disabled */ pthread_mutex_unlock(&app->lock); } return 0; }
/* Function for sent each encoder instance to be process after collect the buffers in the sink pads */ GstFlowReturn gst_tidmai_base_video_dualencoder_entry_buffers_collected (GstCollectPads * pads, GstTIDmaiBaseVideoDualEncoder * video_dualencoder) { GST_DEBUG_OBJECT (video_dualencoder, "Entry gst_tidmai_base_video_dualencoder_entry_buffers_collected"); GstTIDmaiBaseDualEncoder *base_dualencoder = GST_TI_DMAI_BASE_DUALENCODER(video_dualencoder); GstFlowReturn ret; GstBuffer *low_res_buffer; GstBuffer *high_res_buffer; /* Obtain the buffers */ low_res_buffer = gst_collect_pads_pop (base_dualencoder->collect_sink_pads, base_dualencoder->low_resolution_encoder->collect); high_res_buffer = gst_collect_pads_pop (base_dualencoder->collect_sink_pads, base_dualencoder->high_resolution_encoder->collect); /* Process for the low resolution instance */ GST_DEBUG_OBJECT (video_dualencoder, "Process low resolution instance"); ret = gst_tidmai_base_video_dualencoder_realize_instance(video_dualencoder, base_dualencoder->low_resolution_encoder, low_res_buffer); /* Process for the high resolution instance */ GST_DEBUG_OBJECT (video_dualencoder, "Process high resolution instance"); ret = gst_tidmai_base_video_dualencoder_realize_instance(video_dualencoder, base_dualencoder->high_resolution_encoder, high_res_buffer); /* unref the buffer with the high-resolution for being reuse for the driver */ gst_buffer_unref(high_res_buffer); if(1 == GST_MINI_OBJECT_REFCOUNT(high_res_buffer)) { gst_buffer_unref(high_res_buffer); } GST_DEBUG_OBJECT (video_dualencoder, "Leave gst_tidmai_base_video_dualencoder_entry_buffers_collected"); return ret; }
/** * gst_v4l2_buffer_pool_dqbuf: * @pool: the pool * * Dequeue a buffer from the driver. Some generic error handling is done in * this function, but any error handling specific to v4l2src (capture) or * v4l2sink (output) can be done outside this function by checking 'errno' * * Returns: a buffer */ GstV4l2Buffer * gst_v4l2_buffer_pool_dqbuf (GstV4l2BufferPool * pool) { GstV4l2Object *v4l2object = get_v4l2_object (pool->v4l2elem); GstV4l2Buffer *pool_buffer; struct v4l2_buffer buffer; memset (&buffer, 0x00, sizeof (buffer)); buffer.type = pool->type; buffer.memory = V4L2_MEMORY_MMAP; if (v4l2_ioctl (pool->video_fd, VIDIOC_DQBUF, &buffer) >= 0) { GST_V4L2_BUFFER_POOL_LOCK (pool); /* get our GstBuffer with that index from the pool, if the buffer was * outstanding we have a serious problem. */ pool_buffer = pool->buffers[buffer.index]; if (pool_buffer == NULL) { GST_ELEMENT_ERROR (pool->v4l2elem, RESOURCE, FAILED, (_("Failed trying to get video frames from device '%s'."), v4l2object->videodev), (_("No free buffers found in the pool at index %d."), buffer.index)); GST_V4L2_BUFFER_POOL_UNLOCK (pool); return NULL; } GST_LOG_OBJECT (pool->v4l2elem, "grabbed frame %d (ix=%d), flags %08x, pool-ct=%d, buffer=%p", buffer.sequence, buffer.index, buffer.flags, pool->num_live_buffers, pool_buffer); pool->num_live_buffers++; GST_DEBUG_OBJECT (pool->v4l2elem, "num_live_buffers++: %d", pool->num_live_buffers); /* set top/bottom field first if v4l2_buffer has the information */ if (buffer.field == V4L2_FIELD_INTERLACED_TB) GST_BUFFER_FLAG_SET (pool_buffer, GST_VIDEO_BUFFER_TFF); if (buffer.field == V4L2_FIELD_INTERLACED_BT) GST_BUFFER_FLAG_UNSET (pool_buffer, GST_VIDEO_BUFFER_TFF); /* this can change at every frame, esp. with jpeg */ GST_BUFFER_SIZE (pool_buffer) = buffer.bytesused; GST_V4L2_BUFFER_POOL_UNLOCK (pool); return pool_buffer; } GST_WARNING_OBJECT (pool->v4l2elem, "problem grabbing frame %d (ix=%d), pool-ct=%d, buf.flags=%d", buffer.sequence, buffer.index, GST_MINI_OBJECT_REFCOUNT (pool), buffer.flags); switch (errno) { case EAGAIN: GST_WARNING_OBJECT (pool->v4l2elem, "Non-blocking I/O has been selected using O_NONBLOCK and" " no buffer was in the outgoing queue. device %s", v4l2object->videodev); break; case EINVAL: GST_ELEMENT_ERROR (pool->v4l2elem, RESOURCE, FAILED, (_("Failed trying to get video frames from device '%s'."), v4l2object->videodev), (_("The buffer type is not supported, or the index is out of bounds," " or no buffers have been allocated yet, or the userptr" " or length are invalid. device %s"), v4l2object->videodev)); break; case ENOMEM: GST_ELEMENT_ERROR (pool->v4l2elem, RESOURCE, FAILED, (_("Failed trying to get video frames from device '%s'. Not enough memory."), v4l2object->videodev), (_("insufficient memory to enqueue a user pointer buffer. device %s."), v4l2object->videodev)); break; case EIO: GST_INFO_OBJECT (pool->v4l2elem, "VIDIOC_DQBUF failed due to an internal error." " Can also indicate temporary problems like signal loss." " Note the driver might dequeue an (empty) buffer despite" " returning an error, or even stop capturing." " device %s", v4l2object->videodev); /* have we de-queued a buffer ? */ if (!(buffer.flags & (V4L2_BUF_FLAG_QUEUED | V4L2_BUF_FLAG_DONE))) { GST_DEBUG_OBJECT (pool->v4l2elem, "reenqueing buffer"); /* FIXME ... should we do something here? */ } break; case EINTR: GST_WARNING_OBJECT (pool->v4l2elem, "could not sync on a buffer on device %s", v4l2object->videodev); break; default: GST_WARNING_OBJECT (pool->v4l2elem, "Grabbing frame got interrupted on %s unexpectedly. %d: %s.", v4l2object->videodev, errno, g_strerror (errno)); break; } return NULL; }
static GstFlowReturn gst_v4l2_buffer_pool_dqbuf (GstV4l2BufferPool * pool, GstBuffer ** buffer) { GstFlowReturn res; GstBuffer *outbuf; struct v4l2_buffer vbuffer; GstV4l2Object *obj = pool->obj; GstClockTime timestamp; if (obj->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { /* select works for input devices when data is available. According to the * specs we can also poll to find out when a frame has been displayed but * that just seems to lock up here */ if ((res = gst_v4l2_object_poll (obj)) != GST_FLOW_OK) goto poll_error; } memset (&vbuffer, 0x00, sizeof (vbuffer)); vbuffer.type = obj->type; vbuffer.memory = V4L2_MEMORY_MMAP; GST_LOG_OBJECT (pool, "doing DQBUF"); if (v4l2_ioctl (pool->video_fd, VIDIOC_DQBUF, &vbuffer) < 0) goto error; /* get our GstBuffer with that index from the pool, if the buffer was * outstanding we have a serious problem. */ outbuf = pool->buffers[vbuffer.index]; if (outbuf == NULL) goto no_buffer; /* mark the buffer outstanding */ pool->buffers[vbuffer.index] = NULL; pool->num_queued--; timestamp = GST_TIMEVAL_TO_TIME (vbuffer.timestamp); GST_LOG_OBJECT (pool, "dequeued buffer %p seq:%d (ix=%d), used %d, flags %08x, ts %" GST_TIME_FORMAT ", pool-queued=%d, buffer=%p", outbuf, vbuffer.sequence, vbuffer.index, vbuffer.bytesused, vbuffer.flags, GST_TIME_ARGS (timestamp), pool->num_queued, outbuf); /* set top/bottom field first if v4l2_buffer has the information */ if (vbuffer.field == V4L2_FIELD_INTERLACED_TB) { GST_BUFFER_FLAG_SET (outbuf, GST_VIDEO_BUFFER_FLAG_TFF); } if (vbuffer.field == V4L2_FIELD_INTERLACED_BT) { GST_BUFFER_FLAG_UNSET (outbuf, GST_VIDEO_BUFFER_FLAG_TFF); } /* this can change at every frame, esp. with jpeg */ if (obj->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) gst_buffer_resize (outbuf, 0, vbuffer.bytesused); else gst_buffer_resize (outbuf, 0, vbuffer.length); GST_BUFFER_TIMESTAMP (outbuf) = timestamp; *buffer = outbuf; return GST_FLOW_OK; /* ERRORS */ poll_error: { GST_DEBUG_OBJECT (pool, "poll error %s", gst_flow_get_name (res)); return res; } error: { GST_WARNING_OBJECT (pool, "problem dequeuing frame %d (ix=%d), pool-ct=%d, buf.flags=%d", vbuffer.sequence, vbuffer.index, GST_MINI_OBJECT_REFCOUNT (pool), vbuffer.flags); switch (errno) { case EAGAIN: GST_WARNING_OBJECT (pool, "Non-blocking I/O has been selected using O_NONBLOCK and" " no buffer was in the outgoing queue. device %s", obj->videodev); break; case EINVAL: GST_ERROR_OBJECT (pool, "The buffer type is not supported, or the index is out of bounds, " "or no buffers have been allocated yet, or the userptr " "or length are invalid. device %s", obj->videodev); break; case ENOMEM: GST_ERROR_OBJECT (pool, "insufficient memory to enqueue a user pointer buffer"); break; case EIO: GST_INFO_OBJECT (pool, "VIDIOC_DQBUF failed due to an internal error." " Can also indicate temporary problems like signal loss." " Note the driver might dequeue an (empty) buffer despite" " returning an error, or even stop capturing." " device %s", obj->videodev); /* have we de-queued a buffer ? */ if (!(vbuffer.flags & (V4L2_BUF_FLAG_QUEUED | V4L2_BUF_FLAG_DONE))) { GST_DEBUG_OBJECT (pool, "reenqueing buffer"); /* FIXME ... should we do something here? */ } break; case EINTR: GST_WARNING_OBJECT (pool, "could not sync on a buffer on device %s", obj->videodev); break; default: GST_WARNING_OBJECT (pool, "Grabbing frame got interrupted on %s unexpectedly. %d: %s.", obj->videodev, errno, g_strerror (errno)); break; } return GST_FLOW_ERROR; } no_buffer: { GST_ERROR_OBJECT (pool, "No free buffer found in the pool at index %d.", vbuffer.index); return GST_FLOW_ERROR; } }