void shader_t::source(std::vector<std::string> const& src) { if (src.empty()) throw compilation_failed_exception_t(name_, "shader empty source"); // prepare source std::vector<char const *> srcs(src.size()); for (int i = 0; i < (int)src.size(); i++) srcs[i] = src[i].c_str(); // compilation glShaderSource(id_, srcs.size(), &srcs[0], NULL); glCompileShader(id_); GLint status; glGetShaderiv(id_, GL_COMPILE_STATUS, &status); if (status == GL_TRUE) is_ready_ = true; else { GLint log_len; glGetShaderiv(id_, GL_INFO_LOG_LENGTH, &log_len); assert(log_len > 0); std::vector<char> log_buffer(log_len); glGetShaderInfoLog(id_, log_len, &log_len, &log_buffer[0]); throw compilation_failed_exception_t(name_, &log_buffer[0]); } }
void unabto_log_system_log_buffer(uint32_t module, uint32_t severity, const char* file, unsigned int line, const uint8_t* buffer, size_t bufferLength, const char* format, ...) { if ((module & stdout_module) && (severity & stdout_severity)) { va_list args; unabto_log_header(file, line); va_start (args, format); vprintf (format, args); va_end (args); printf("\n"); log_buffer(buffer, bufferLength); } if (check_syslog_state() && (module & syslog_module) && (severity & syslog_severity)) { va_list args; va_start (args, format); unabto_syslog_buffer(module, severity, file, line, syslog_host, syslog_port, buffer, bufferLength, format, args); va_end (args); } }
TEST_F(LogBufferPoolTests, PoolTest) { logging::LogBufferPool log_buffer_pool(1); size_t thread_id = log_buffer_pool.GetThreadId(); EXPECT_EQ(thread_id, 1); std::unique_ptr<logging::LogBuffer> log_buffer(new logging::LogBuffer(1, 1)); log_buffer_pool.GetBuffer(1); size_t slot_count = log_buffer_pool.GetEmptySlotCount(); EXPECT_EQ(slot_count, log_buffer_pool.GetMaxSlotCount() - 1); log_buffer_pool.PutBuffer(std::move(log_buffer)); slot_count = log_buffer_pool.GetEmptySlotCount(); EXPECT_EQ(slot_count, log_buffer_pool.GetMaxSlotCount()); }
void LogMapper::flush_bucket(const BucketHashList& hashlist) { ASSERT_ND(hashlist.head_); ASSERT_ND(hashlist.tail_); // temporary variables to store partitioning results BufferPosition* position_array = reinterpret_cast<BufferPosition*>( tmp_position_array_slice_.get_block()); PartitionSortEntry* sort_array = reinterpret_cast<PartitionSortEntry*>( tmp_sort_array_slice_.get_block()); storage::PartitionId* partition_array = reinterpret_cast<storage::PartitionId*>( tmp_partition_array_slice_.get_block()); LogBuffer log_buffer(reinterpret_cast<char*>(io_buffer_.get_block())); const bool multi_partitions = engine_->get_options().thread_.group_count_ > 1U; if (!engine_->get_storage_manager()->get_storage(hashlist.storage_id_)->exists()) { // We ignore such logs in snapshot. As DROP STORAGE immediately becomes durable, // There is no point to collect logs for the storage. LOG(INFO) << "These logs are sent to a dropped storage.. ignore them"; return; } uint64_t log_count = 0; // just for reporting debugging::StopWatch stop_watch; for (Bucket* bucket = hashlist.head_; bucket != nullptr; bucket = bucket->next_bucket_) { ASSERT_ND(bucket->counts_ > 0); ASSERT_ND(bucket->counts_ <= kBucketMaxCount); ASSERT_ND(bucket->storage_id_ == hashlist.storage_id_); log_count += bucket->counts_; // if there are multiple partitions, we first partition log entries. if (multi_partitions) { storage::Partitioner partitioner(engine_, bucket->storage_id_); ASSERT_ND(partitioner.is_valid()); if (partitioner.is_partitionable()) { // calculate partitions for (uint32_t i = 0; i < bucket->counts_; ++i) { position_array[i] = bucket->log_positions_[i]; ASSERT_ND(log_buffer.resolve(position_array[i])->header_.storage_id_ == bucket->storage_id_); ASSERT_ND(log_buffer.resolve(position_array[i])->header_.storage_id_ == hashlist.storage_id_); } storage::Partitioner::PartitionBatchArguments args = { static_cast< storage::PartitionId >(numa_node_), log_buffer, position_array, bucket->counts_, partition_array}; partitioner.partition_batch(args); // sort the log positions by the calculated partitions std::memset(sort_array, 0, sizeof(PartitionSortEntry) * bucket->counts_); for (uint32_t i = 0; i < bucket->counts_; ++i) { sort_array[i].set(partition_array[i], bucket->log_positions_[i]); } std::sort(sort_array, sort_array + bucket->counts_); // let's reuse the current bucket as a temporary memory to hold sorted entries. // buckets are discarded after the flushing, so this doesn't cause any issue. const uint32_t original_count = bucket->counts_; storage::PartitionId current_partition = sort_array[0].partition_; bucket->log_positions_[0] = sort_array[0].position_; bucket->counts_ = 1; for (uint32_t i = 1; i < original_count; ++i) { if (current_partition == sort_array[i].partition_) { bucket->log_positions_[bucket->counts_] = sort_array[i].position_; ++bucket->counts_; ASSERT_ND(bucket->counts_ <= original_count); } else { // the current partition has ended. // let's send out these log entries to this partition send_bucket_partition(bucket, current_partition); // this is the beginning of next partition current_partition = sort_array[i].partition_; bucket->log_positions_[0] = sort_array[i].position_; bucket->counts_ = 1; } } ASSERT_ND(bucket->counts_ > 0); // send out the last partition send_bucket_partition(bucket, current_partition); } else { // in this case, it's same as single partition regarding this storage. send_bucket_partition(bucket, 0); } } else { // if it's not multi-partition, we blindly send everything to partition-0 (NUMA node 0) send_bucket_partition(bucket, 0); } } stop_watch.stop(); LOG(INFO) << to_string() << " sent out " << log_count << " log entries for storage-" << hashlist.storage_id_ << " in " << stop_watch.elapsed_ms() << " milliseconds"; }
static GstFlowReturn pad_chain (GstPad *pad, GstBuffer *buf) { GOmxCore *gomx; GOmxPort *in_port; GstOmxBaseFilter *self; GstFlowReturn ret = GST_FLOW_OK; self = GST_OMX_BASE_FILTER (GST_OBJECT_PARENT (pad)); gomx = self->gomx; GST_LOG_OBJECT (self, "begin"); GST_LOG_OBJECT (self, "gst_buffer: size=%u", GST_BUFFER_SIZE (buf)); GST_LOG_OBJECT (self, "state: %d", gomx->omx_state); if (G_UNLIKELY (gomx->omx_state == OMX_StateLoaded)) { g_mutex_lock (self->ready_lock); GST_INFO_OBJECT (self, "omx: prepare"); /** @todo this should probably go after doing preparations. */ if (self->omx_setup) { self->omx_setup (self); } setup_ports (self); g_omx_core_prepare (self->gomx); if (gomx->omx_state == OMX_StateIdle) { self->ready = TRUE; gst_pad_start_task (self->srcpad, output_loop, self->srcpad); } g_mutex_unlock (self->ready_lock); if (gomx->omx_state != OMX_StateIdle) goto out_flushing; } in_port = self->in_port; if (G_LIKELY (in_port->enabled)) { guint buffer_offset = 0; if (G_UNLIKELY (gomx->omx_state == OMX_StateIdle)) { GST_INFO_OBJECT (self, "omx: play"); g_omx_core_start (gomx); if (gomx->omx_state != OMX_StateExecuting) goto out_flushing; /* send buffer with codec data flag */ /** @todo move to util */ if (self->codec_data) { OMX_BUFFERHEADERTYPE *omx_buffer; GST_LOG_OBJECT (self, "request buffer"); omx_buffer = g_omx_port_request_buffer (in_port); if (G_LIKELY (omx_buffer)) { omx_buffer->nFlags |= 0x00000080; /* codec data flag */ omx_buffer->nFilledLen = GST_BUFFER_SIZE (self->codec_data); memcpy (omx_buffer->pBuffer + omx_buffer->nOffset, GST_BUFFER_DATA (self->codec_data), omx_buffer->nFilledLen); GST_LOG_OBJECT (self, "release_buffer"); g_omx_port_release_buffer (in_port, omx_buffer); } } } if (G_UNLIKELY (gomx->omx_state != OMX_StateExecuting)) { GST_ERROR_OBJECT (self, "Whoa! very wrong"); } while (G_LIKELY (buffer_offset < GST_BUFFER_SIZE (buf))) { OMX_BUFFERHEADERTYPE *omx_buffer; if (self->last_pad_push_return != GST_FLOW_OK || !(gomx->omx_state == OMX_StateExecuting || gomx->omx_state == OMX_StatePause)) { goto out_flushing; } GST_LOG_OBJECT (self, "request buffer"); omx_buffer = g_omx_port_request_buffer (in_port); GST_LOG_OBJECT (self, "omx_buffer: %p", omx_buffer); if (G_LIKELY (omx_buffer)) { log_buffer (self, omx_buffer); if (omx_buffer->nOffset == 0 && self->share_input_buffer) { { GstBuffer *old_buf; old_buf = omx_buffer->pAppPrivate; if (old_buf) { gst_buffer_unref (old_buf); } else if (omx_buffer->pBuffer) { g_free (omx_buffer->pBuffer); } } omx_buffer->pBuffer = GST_BUFFER_DATA (buf); omx_buffer->nAllocLen = GST_BUFFER_SIZE (buf); omx_buffer->nFilledLen = GST_BUFFER_SIZE (buf); omx_buffer->pAppPrivate = buf; } else { omx_buffer->nFilledLen = MIN (GST_BUFFER_SIZE (buf) - buffer_offset, omx_buffer->nAllocLen - omx_buffer->nOffset); memcpy (omx_buffer->pBuffer + omx_buffer->nOffset, GST_BUFFER_DATA (buf) + buffer_offset, omx_buffer->nFilledLen); } if (self->use_timestamps) { GstClockTime timestamp_offset = 0; if (buffer_offset && GST_BUFFER_DURATION (buf) != GST_CLOCK_TIME_NONE) { timestamp_offset = gst_util_uint64_scale_int (buffer_offset, GST_BUFFER_DURATION (buf), GST_BUFFER_SIZE (buf)); } omx_buffer->nTimeStamp = gst_util_uint64_scale_int (GST_BUFFER_TIMESTAMP (buf) + timestamp_offset, OMX_TICKS_PER_SECOND, GST_SECOND); } buffer_offset += omx_buffer->nFilledLen; GST_LOG_OBJECT (self, "release_buffer"); /** @todo untaint buffer */ g_omx_port_release_buffer (in_port, omx_buffer); } else { GST_WARNING_OBJECT (self, "null buffer"); ret = GST_FLOW_WRONG_STATE; goto out_flushing; } } } else { GST_WARNING_OBJECT (self, "done"); ret = GST_FLOW_UNEXPECTED; } if (!self->share_input_buffer) { gst_buffer_unref (buf); } leave: GST_LOG_OBJECT (self, "end"); return ret; /* special conditions */ out_flushing: { const gchar *error_msg = NULL; if (gomx->omx_error) { error_msg = "Error from OpenMAX component"; } else if (gomx->omx_state != OMX_StateExecuting && gomx->omx_state != OMX_StatePause) { error_msg = "OpenMAX component in wrong state"; } if (error_msg) { GST_ELEMENT_ERROR (self, STREAM, FAILED, (NULL), ("%s", error_msg)); ret = GST_FLOW_ERROR; } gst_buffer_unref (buf); goto leave; } }
static void output_loop (gpointer data) { GstPad *pad; GOmxCore *gomx; GOmxPort *out_port; GstOmxBaseFilter *self; GstFlowReturn ret = GST_FLOW_OK; pad = data; self = GST_OMX_BASE_FILTER (gst_pad_get_parent (pad)); gomx = self->gomx; GST_LOG_OBJECT (self, "begin"); /* do not bother if we have been setup to bail out */ if ((ret = g_atomic_int_get (&self->last_pad_push_return)) != GST_FLOW_OK) goto leave; if (!self->ready) { g_error ("not ready"); return; } out_port = self->out_port; if (G_LIKELY (out_port->enabled)) { OMX_BUFFERHEADERTYPE *omx_buffer = NULL; GST_LOG_OBJECT (self, "request buffer"); omx_buffer = g_omx_port_request_buffer (out_port); GST_LOG_OBJECT (self, "omx_buffer: %p", omx_buffer); if (G_UNLIKELY (!omx_buffer)) { GST_WARNING_OBJECT (self, "null buffer: leaving"); ret = GST_FLOW_WRONG_STATE; goto leave; } log_buffer (self, omx_buffer); if (G_LIKELY (omx_buffer->nFilledLen > 0)) { GstBuffer *buf; #if 1 /** @todo remove this check */ if (G_LIKELY (self->in_port->enabled)) { GstCaps *caps = NULL; caps = gst_pad_get_negotiated_caps (self->srcpad); if (!caps) { /** @todo We shouldn't be doing this. */ GST_WARNING_OBJECT (self, "faking settings changed notification"); if (gomx->settings_changed_cb) gomx->settings_changed_cb (gomx); } else { GST_LOG_OBJECT (self, "caps already fixed: %" GST_PTR_FORMAT, caps); gst_caps_unref (caps); } } #endif /* buf is always null when the output buffer pointer isn't shared. */ buf = omx_buffer->pAppPrivate; /** @todo we need to move all the caps handling to one single * place, in the output loop probably. */ if (G_UNLIKELY (omx_buffer->nFlags & 0x80)) { GstCaps *caps = NULL; GstStructure *structure; GValue value = { 0 }; caps = gst_pad_get_negotiated_caps (self->srcpad); caps = gst_caps_make_writable (caps); structure = gst_caps_get_structure (caps, 0); g_value_init (&value, GST_TYPE_BUFFER); buf = gst_buffer_new_and_alloc (omx_buffer->nFilledLen); memcpy (GST_BUFFER_DATA (buf), omx_buffer->pBuffer + omx_buffer->nOffset, omx_buffer->nFilledLen); gst_value_set_buffer (&value, buf); gst_buffer_unref (buf); gst_structure_set_value (structure, "codec_data", &value); g_value_unset (&value); gst_pad_set_caps (self->srcpad, caps); } else if (buf && !(omx_buffer->nFlags & OMX_BUFFERFLAG_EOS)) { GST_BUFFER_SIZE (buf) = omx_buffer->nFilledLen; if (self->use_timestamps) { GST_BUFFER_TIMESTAMP (buf) = gst_util_uint64_scale_int (omx_buffer->nTimeStamp, GST_SECOND, OMX_TICKS_PER_SECOND); } omx_buffer->pAppPrivate = NULL; omx_buffer->pBuffer = NULL; ret = push_buffer (self, buf); gst_buffer_unref (buf); } else { /* This is only meant for the first OpenMAX buffers, * which need to be pre-allocated. */ /* Also for the very last one. */ ret = gst_pad_alloc_buffer_and_set_caps (self->srcpad, GST_BUFFER_OFFSET_NONE, omx_buffer->nFilledLen, GST_PAD_CAPS (self->srcpad), &buf); if (G_LIKELY (buf)) { memcpy (GST_BUFFER_DATA (buf), omx_buffer->pBuffer + omx_buffer->nOffset, omx_buffer->nFilledLen); if (self->use_timestamps) { GST_BUFFER_TIMESTAMP (buf) = gst_util_uint64_scale_int (omx_buffer->nTimeStamp, GST_SECOND, OMX_TICKS_PER_SECOND); } if (self->share_output_buffer) { GST_WARNING_OBJECT (self, "couldn't zero-copy"); /* If pAppPrivate is NULL, it means it was a dummy * allocation, free it. */ if (!omx_buffer->pAppPrivate) { g_free (omx_buffer->pBuffer); omx_buffer->pBuffer = NULL; } } ret = push_buffer (self, buf); } else { GST_WARNING_OBJECT (self, "couldn't allocate buffer of size %lu", omx_buffer->nFilledLen); } } } else { GST_WARNING_OBJECT (self, "empty buffer"); } if (G_UNLIKELY (omx_buffer->nFlags & OMX_BUFFERFLAG_EOS)) { GST_DEBUG_OBJECT (self, "got eos"); gst_pad_push_event (self->srcpad, gst_event_new_eos ()); ret = GST_FLOW_UNEXPECTED; goto leave; } if (self->share_output_buffer && !omx_buffer->pBuffer && omx_buffer->nOffset == 0) { GstBuffer *buf; GstFlowReturn result; GST_LOG_OBJECT (self, "allocate buffer"); result = gst_pad_alloc_buffer_and_set_caps (self->srcpad, GST_BUFFER_OFFSET_NONE, omx_buffer->nAllocLen, GST_PAD_CAPS (self->srcpad), &buf); if (G_LIKELY (result == GST_FLOW_OK)) { gst_buffer_ref (buf); omx_buffer->pAppPrivate = buf; omx_buffer->pBuffer = GST_BUFFER_DATA (buf); omx_buffer->nAllocLen = GST_BUFFER_SIZE (buf); } else { GST_WARNING_OBJECT (self, "could not pad allocate buffer, using malloc"); omx_buffer->pBuffer = g_malloc (omx_buffer->nAllocLen); } } if (self->share_output_buffer && !omx_buffer->pBuffer) { GST_ERROR_OBJECT (self, "no input buffer to share"); } omx_buffer->nFilledLen = 0; GST_LOG_OBJECT (self, "release_buffer"); g_omx_port_release_buffer (out_port, omx_buffer); } leave: self->last_pad_push_return = ret; if (gomx->omx_error != OMX_ErrorNone) ret = GST_FLOW_ERROR; if (ret != GST_FLOW_OK) { GST_INFO_OBJECT (self, "pause task, reason: %s", gst_flow_get_name (ret)); gst_pad_pause_task (self->srcpad); } GST_LOG_OBJECT (self, "end"); gst_object_unref (self); }
static void output_loop (gpointer data) { GstPad *pad; GOmxCore *gomx; GOmxPort *out_port; GstOmxBaseFilter *self; GstFlowReturn ret = GST_FLOW_OK; pad = data; self = GST_OMX_BASE_FILTER (gst_pad_get_parent (pad)); gomx = self->gomx; GST_LOG_OBJECT (self, "begin"); /* do not bother if we have been setup to bail out */ if ((ret = g_atomic_int_get (&self->last_pad_push_return)) != GST_FLOW_OK) goto leave; if (!self->ready) { g_error ("not ready"); return; } out_port = self->out_port; if (G_LIKELY (out_port->enabled)) { OMX_BUFFERHEADERTYPE *omx_buffer = NULL; GST_LOG_OBJECT (self, "request buffer"); omx_buffer = g_omx_port_request_buffer (out_port); GST_LOG_OBJECT (self, "omx_buffer: %p", omx_buffer); if (G_UNLIKELY (!omx_buffer)) { GST_WARNING_OBJECT (self, "null buffer: leaving"); ret = GST_FLOW_WRONG_STATE; goto leave; } log_buffer (self, omx_buffer); if (G_LIKELY (omx_buffer->nFilledLen > 0)) { GstBuffer *buf; #if 1 /** @todo remove this check */ if (G_LIKELY (self->in_port->enabled)) { GstCaps *caps = NULL; caps = gst_pad_get_negotiated_caps (self->srcpad); #ifdef ANDROID if (!caps || gomx->settings_changed) { #else if (!caps) { #endif /** @todo We shouldn't be doing this. */ GST_WARNING_OBJECT (self, "faking settings changed notification"); if (gomx->settings_changed_cb) gomx->settings_changed_cb (gomx); #ifdef ANDROID gomx->settings_changed = FALSE; #endif } else { GST_LOG_OBJECT (self, "caps already fixed: %" GST_PTR_FORMAT, caps); gst_caps_unref (caps); } } #endif /* buf is always null when the output buffer pointer isn't shared. */ buf = omx_buffer->pAppPrivate; /** @todo we need to move all the caps handling to one single * place, in the output loop probably. */ if (G_UNLIKELY (omx_buffer->nFlags & 0x80)) { GstCaps *caps = NULL; GstStructure *structure; GValue value = { 0, {{0} } }; caps = gst_pad_get_negotiated_caps (self->srcpad); caps = gst_caps_make_writable (caps); structure = gst_caps_get_structure (caps, 0); g_value_init (&value, GST_TYPE_BUFFER); buf = gst_buffer_new_and_alloc (omx_buffer->nFilledLen); memcpy (GST_BUFFER_DATA (buf), omx_buffer->pBuffer + omx_buffer->nOffset, omx_buffer->nFilledLen); gst_value_set_buffer (&value, buf); gst_buffer_unref (buf); gst_structure_set_value (structure, "codec_data", &value); g_value_unset (&value); gst_pad_set_caps (self->srcpad, caps); } else if (buf && !(omx_buffer->nFlags & OMX_BUFFERFLAG_EOS)) { GST_BUFFER_SIZE (buf) = omx_buffer->nFilledLen; if (self->use_timestamps) { GST_BUFFER_TIMESTAMP (buf) = gst_util_uint64_scale_int (omx_buffer->nTimeStamp, GST_SECOND, OMX_TICKS_PER_SECOND); } omx_buffer->pAppPrivate = NULL; omx_buffer->pBuffer = NULL; ret = push_buffer (self, buf); gst_buffer_unref (buf); } else { /* This is only meant for the first OpenMAX buffers, * which need to be pre-allocated. */ /* Also for the very last one. */ ret = gst_pad_alloc_buffer_and_set_caps (self->srcpad, GST_BUFFER_OFFSET_NONE, omx_buffer->nFilledLen, GST_PAD_CAPS (self->srcpad), &buf); if (G_LIKELY (buf)) { memcpy (GST_BUFFER_DATA (buf), omx_buffer->pBuffer + omx_buffer->nOffset, omx_buffer->nFilledLen); if (self->use_timestamps) { GST_BUFFER_TIMESTAMP (buf) = gst_util_uint64_scale_int (omx_buffer->nTimeStamp, GST_SECOND, OMX_TICKS_PER_SECOND); } if (self->share_output_buffer) { GST_WARNING_OBJECT (self, "couldn't zero-copy"); /* If pAppPrivate is NULL, it means it was a dummy * allocation, free it. */ if (!omx_buffer->pAppPrivate) { g_free (omx_buffer->pBuffer); omx_buffer->pBuffer = NULL; } } ret = push_buffer (self, buf); } else { GST_WARNING_OBJECT (self, "couldn't allocate buffer of size %lu", omx_buffer->nFilledLen); } } } else { GST_WARNING_OBJECT (self, "empty buffer"); } if (self->share_output_buffer && !omx_buffer->pBuffer && omx_buffer->nOffset == 0) { GstBuffer *buf; GstFlowReturn result; GST_LOG_OBJECT (self, "allocate buffer"); result = gst_pad_alloc_buffer_and_set_caps (self->srcpad, GST_BUFFER_OFFSET_NONE, omx_buffer->nAllocLen, GST_PAD_CAPS (self->srcpad), &buf); if (G_LIKELY (result == GST_FLOW_OK)) { gst_buffer_ref (buf); omx_buffer->pAppPrivate = buf; omx_buffer->pBuffer = GST_BUFFER_DATA (buf); omx_buffer->nAllocLen = GST_BUFFER_SIZE (buf); } else { GST_WARNING_OBJECT (self, "could not pad allocate buffer, using malloc"); omx_buffer->pBuffer = g_malloc (omx_buffer->nAllocLen); } } if (self->share_output_buffer && !omx_buffer->pBuffer) { GST_ERROR_OBJECT (self, "no input buffer to share"); } if (G_UNLIKELY (omx_buffer->nFlags & OMX_BUFFERFLAG_EOS)) { GST_DEBUG_OBJECT (self, "got eos"); gst_pad_push_event (self->srcpad, gst_event_new_eos ()); omx_buffer->nFlags &= ~OMX_BUFFERFLAG_EOS; ret = GST_FLOW_UNEXPECTED; } omx_buffer->nFilledLen = 0; GST_LOG_OBJECT (self, "release_buffer"); g_omx_port_release_buffer (out_port, omx_buffer); } leave: self->last_pad_push_return = ret; if (gomx->omx_error != OMX_ErrorNone) ret = GST_FLOW_ERROR; if (ret != GST_FLOW_OK) { GST_INFO_OBJECT (self, "pause task, reason: %s", gst_flow_get_name (ret)); gst_pad_pause_task (self->srcpad); } GST_LOG_OBJECT (self, "end"); gst_object_unref (self); } static GstFlowReturn pad_chain (GstPad * pad, GstBuffer * buf) { GOmxCore *gomx; GOmxPort *in_port; GstOmxBaseFilter *self; GstFlowReturn ret = GST_FLOW_OK; self = GST_OMX_BASE_FILTER (GST_OBJECT_PARENT (pad)); gomx = self->gomx; GST_LOG_OBJECT (self, "begin"); GST_LOG_OBJECT (self, "gst_buffer: size=%u", GST_BUFFER_SIZE (buf)); GST_LOG_OBJECT (self, "state: %d", gomx->omx_state); if (G_UNLIKELY (gomx->omx_state == OMX_StateLoaded)) { g_mutex_lock (self->ready_lock); GST_INFO_OBJECT (self, "omx: prepare"); /** @todo this should probably go after doing preparations. */ if (self->omx_setup) { self->omx_setup (self); } setup_ports (self); g_omx_core_prepare (self->gomx); if (gomx->omx_state == OMX_StateIdle) { self->ready = TRUE; GST_INFO_OBJECT (self, "start srcpad task"); gst_pad_start_task (self->srcpad, output_loop, self->srcpad); } g_mutex_unlock (self->ready_lock); if (gomx->omx_state != OMX_StateIdle) goto out_flushing; } #ifdef ANDROID if (gomx->settings_changed) { GST_DEBUG_OBJECT (self, "settings changed called from streaming thread... Android"); if (gomx->settings_changed_cb) gomx->settings_changed_cb (gomx); gomx->settings_changed = FALSE; } #endif in_port = self->in_port; if (G_LIKELY (in_port->enabled)) { guint buffer_offset = 0; if (G_UNLIKELY (gomx->omx_state == OMX_StateIdle)) { GST_INFO_OBJECT (self, "omx: play"); g_omx_core_start (gomx); if (gomx->omx_state != OMX_StateExecuting) goto out_flushing; /* send buffer with codec data flag */ /** @todo move to util */ if (self->codec_data) { OMX_BUFFERHEADERTYPE *omx_buffer; GST_LOG_OBJECT (self, "request buffer"); omx_buffer = g_omx_port_request_buffer (in_port); if (G_LIKELY (omx_buffer)) { omx_buffer->nFlags |= 0x00000080; /* codec data flag */ omx_buffer->nFilledLen = GST_BUFFER_SIZE (self->codec_data); memcpy (omx_buffer->pBuffer + omx_buffer->nOffset, GST_BUFFER_DATA (self->codec_data), omx_buffer->nFilledLen); GST_LOG_OBJECT (self, "release_buffer"); g_omx_port_release_buffer (in_port, omx_buffer); } } } if (G_UNLIKELY (gomx->omx_state != OMX_StateExecuting)) { GST_ERROR_OBJECT (self, "Whoa! very wrong"); } while (G_LIKELY (buffer_offset < GST_BUFFER_SIZE (buf))) { OMX_BUFFERHEADERTYPE *omx_buffer; if (self->last_pad_push_return != GST_FLOW_OK || !(gomx->omx_state == OMX_StateExecuting || gomx->omx_state == OMX_StatePause)) { goto out_flushing; } GST_LOG_OBJECT (self, "request buffer"); omx_buffer = g_omx_port_request_buffer (in_port); GST_LOG_OBJECT (self, "omx_buffer: %p", omx_buffer); if (G_LIKELY (omx_buffer)) { log_buffer (self, omx_buffer); if (omx_buffer->nOffset == 0 && self->share_input_buffer) { { GstBuffer *old_buf; old_buf = omx_buffer->pAppPrivate; if (old_buf) { gst_buffer_unref (old_buf); } else if (omx_buffer->pBuffer) { g_free (omx_buffer->pBuffer); } } omx_buffer->pBuffer = GST_BUFFER_DATA (buf); omx_buffer->nAllocLen = GST_BUFFER_SIZE (buf); omx_buffer->nFilledLen = GST_BUFFER_SIZE (buf); omx_buffer->pAppPrivate = buf; } else { omx_buffer->nFilledLen = MIN (GST_BUFFER_SIZE (buf) - buffer_offset, omx_buffer->nAllocLen - omx_buffer->nOffset); memcpy (omx_buffer->pBuffer + omx_buffer->nOffset, GST_BUFFER_DATA (buf) + buffer_offset, omx_buffer->nFilledLen); } if (self->use_timestamps) { GstClockTime timestamp_offset = 0; if (buffer_offset && GST_BUFFER_DURATION (buf) != GST_CLOCK_TIME_NONE) { timestamp_offset = gst_util_uint64_scale_int (buffer_offset, GST_BUFFER_DURATION (buf), GST_BUFFER_SIZE (buf)); } omx_buffer->nTimeStamp = gst_util_uint64_scale_int (GST_BUFFER_TIMESTAMP (buf) + timestamp_offset, OMX_TICKS_PER_SECOND, GST_SECOND); } buffer_offset += omx_buffer->nFilledLen; #ifdef ANDROID omx_buffer->nFlags |= OMX_BUFFERFLAG_ENDOFFRAME; log_buffer (self, omx_buffer); #endif GST_LOG_OBJECT (self, "release_buffer"); /** @todo untaint buffer */ g_omx_port_release_buffer (in_port, omx_buffer); } else { GST_WARNING_OBJECT (self, "null buffer"); ret = GST_FLOW_WRONG_STATE; goto out_flushing; } } } else { GST_WARNING_OBJECT (self, "done"); ret = GST_FLOW_UNEXPECTED; } if (!self->share_input_buffer) { gst_buffer_unref (buf); } leave: GST_LOG_OBJECT (self, "end"); return ret; /* special conditions */ out_flushing: { const gchar *error_msg = NULL; if (gomx->omx_error) { error_msg = "Error from OpenMAX component"; } else if (gomx->omx_state != OMX_StateExecuting && gomx->omx_state != OMX_StatePause) { error_msg = "OpenMAX component in wrong state"; } if (error_msg) { GST_ELEMENT_ERROR (self, STREAM, FAILED, (NULL), ("%s", error_msg)); ret = GST_FLOW_ERROR; } gst_buffer_unref (buf); goto leave; } }