static int flush_decoder(decoder_t *dec) { decoder_sys_t *sys = dec->p_sys; MMAL_BUFFER_HEADER_T *buffer; MMAL_STATUS_T status; int ret = 0; msg_Dbg(dec, "Flushing decoder ports..."); mmal_port_disable(sys->output); mmal_port_disable(sys->input); mmal_port_flush(sys->output); mmal_port_flush(sys->input); /* Reload extradata if available */ if (dec->fmt_in.i_codec == VLC_CODEC_H264) { if (dec->fmt_in.i_extra > 0) { status = mmal_format_extradata_alloc(sys->input->format, dec->fmt_in.i_extra); if (status == MMAL_SUCCESS) { memcpy(sys->input->format->extradata, dec->fmt_in.p_extra, dec->fmt_in.i_extra); sys->input->format->extradata_size = dec->fmt_in.i_extra; } else { msg_Err(dec, "Failed to allocate extra format data on input port %s (status=%"PRIx32" %s)", sys->input->name, status, mmal_status_to_string(status)); } } } status = mmal_port_format_commit(sys->input); if (status != MMAL_SUCCESS) { msg_Err(dec, "Failed to commit format for input port %s (status=%"PRIx32" %s)", sys->input->name, status, mmal_status_to_string(status)); } mmal_port_enable(sys->output, output_port_cb); mmal_port_enable(sys->input, input_port_cb); while (atomic_load(&sys->output_in_transit)) vlc_sem_wait(&sys->sem); /* Free pictures which are decoded but have not yet been sent * out to the core */ while ((buffer = mmal_queue_get(sys->decoded_pictures))) { picture_t *pic = (picture_t *)buffer->user_data; picture_Release(pic); if (sys->output_pool) { buffer->user_data = NULL; buffer->alloc_size = 0; buffer->data = NULL; mmal_buffer_header_release(buffer); } } msg_Dbg(dec, "Ports flushed, returning to normal operation"); return ret; }
static int set_latency_target(vout_display_t *vd, bool enable) { vout_display_sys_t *sys = vd->sys; MMAL_STATUS_T status; MMAL_PARAMETER_AUDIO_LATENCY_TARGET_T latency_target = { .hdr = { MMAL_PARAMETER_AUDIO_LATENCY_TARGET, sizeof(latency_target) }, .enable = enable ? MMAL_TRUE : MMAL_FALSE, .filter = 2, .target = 4000, .shift = 3, .speed_factor = -135, .inter_factor = 500, .adj_cap = 20 }; status = mmal_port_parameter_set(sys->input, &latency_target.hdr); if (status != MMAL_SUCCESS) { msg_Err(vd, "Failed to configure latency target on input port %s (status=%"PRIx32" %s)", sys->input->name, status, mmal_status_to_string(status)); return VLC_EGENERIC; } return VLC_SUCCESS; }
/* Send a payload buffer to a connected port/client */ static MMAL_STATUS_T mmal_port_clock_forward_payload(MMAL_PORT_T *port, const MMAL_CLOCK_PAYLOAD_T *payload) { MMAL_STATUS_T status; MMAL_BUFFER_HEADER_T *buffer; buffer = mmal_queue_get(port->priv->module->queue); if (!buffer) { LOG_ERROR("no free buffers available"); return MMAL_ENOSPC; } status = mmal_buffer_header_mem_lock(buffer); if (status != MMAL_SUCCESS) { LOG_ERROR("failed to lock buffer %s", mmal_status_to_string(status)); mmal_queue_put_back(port->priv->module->queue, buffer); goto end; } buffer->length = sizeof(MMAL_CLOCK_PAYLOAD_T); memcpy(buffer->data, payload, buffer->length); mmal_buffer_header_mem_unlock(buffer); mmal_port_buffer_header_callback(port, buffer); end: return status; }
/** Callback from a control port. */ static void svp_bh_control_cb(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buf) { SVP_T *svp = (SVP_T *)port->userdata; switch (buf->cmd) { case MMAL_EVENT_EOS: LOG_TRACE("%s: EOS", port->name); svp_set_stop(svp, SVP_STOP_EOS); break; case MMAL_EVENT_ERROR: LOG_ERROR("%s: MMAL error: %s", port->name, mmal_status_to_string(*(MMAL_STATUS_T *)buf->data)); svp_set_stop(svp, SVP_STOP_ERROR); break; default: LOG_TRACE("%s: buf %p, event %4.4s", port->name, buf, (char *)&buf->cmd); break; } mmal_buffer_header_release(buf); vcos_semaphore_post(&svp->sema); }
/** Connected output port buffer callback */ static void mmal_port_connected_output_cb(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer) { MMAL_PORT_T* connected_port = port->priv->core->connected_port; MMAL_STATUS_T status; LOG_TRACE("buffer %p from connected output port %p: data %p, alloc_size %u, length %u", buffer, port, buffer->data, buffer->alloc_size, buffer->length); if (buffer->cmd) { MMAL_EVENT_FORMAT_CHANGED_T *event = mmal_event_format_changed_get(buffer); /* Handle format changed events */ if (event) { /* Apply the change */ status = mmal_format_full_copy(port->format, event->format); if (status == MMAL_SUCCESS) status = mmal_port_format_commit(port); if (status != MMAL_SUCCESS) LOG_ERROR("format commit failed on port %s (%i)", port->name, status); /* Forward to the connected port */ if (status == MMAL_SUCCESS) status = mmal_port_send_buffer(connected_port, buffer); if (status != MMAL_SUCCESS) { mmal_event_error_send(port->component, status); mmal_buffer_header_release(buffer); } return; /* Event handled */ } /* FIXME Release other event buffers for now, until we can deal with shared memory issues */ mmal_buffer_header_release(buffer); } else { if (port->is_enabled) { /* Forward data buffers to the connected input port */ status = mmal_port_send_buffer(connected_port, buffer); if (status != MMAL_SUCCESS) { LOG_ERROR("%s could not send buffer on port %s (%s)", port->name, connected_port->name, mmal_status_to_string(status)); mmal_buffer_header_release(buffer); } } else { /* This port is disabled. Buffer will be a flushed buffer, so * return to the pool rather than delivering it. */ mmal_buffer_header_release(buffer); } } }
static picture_t *deinterlace(filter_t *filter, picture_t *picture) { filter_sys_t *sys = filter->p_sys; MMAL_BUFFER_HEADER_T *buffer; picture_t *out_picture = NULL; picture_t *ret = NULL; MMAL_STATUS_T status; unsigned i = 0; fill_output_port(filter); buffer = picture->p_sys->buffer; buffer->user_data = picture; buffer->pts = picture->date; buffer->cmd = 0; if (!picture->p_sys->displayed) { vlc_mutex_lock(&sys->buffer_cond_mutex); status = mmal_port_send_buffer(sys->input, buffer); if (status != MMAL_SUCCESS) { msg_Err(filter, "Failed to send buffer to input port (status=%"PRIx32" %s)", status, mmal_status_to_string(status)); picture_Release(picture); } else { picture->p_sys->displayed = true; atomic_fetch_add(&sys->input_in_transit, 1); vlc_cond_signal(&sys->buffer_cond); } vlc_mutex_unlock(&sys->buffer_cond_mutex); } else { picture_Release(picture); } /* * Send output buffers */ while(atomic_load(&sys->started) && i < 2) { if (buffer = mmal_queue_timedwait(sys->filtered_pictures, 2000)) { i++; if (!out_picture) { out_picture = (picture_t *)buffer->user_data; ret = out_picture; } else { out_picture->p_next = (picture_t *)buffer->user_data; out_picture = out_picture->p_next; } out_picture->date = buffer->pts; } else { msg_Dbg(filter, "Failed waiting for filtered picture"); break; } } if (out_picture) out_picture->p_next = NULL; return ret; }
/** Send a buffer header to a port */ MMAL_STATUS_T mmal_port_send_buffer(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer) { MMAL_STATUS_T status; if (!port || !port->priv) { LOG_ERROR("invalid port"); return MMAL_EINVAL; } #ifdef ENABLE_MMAL_EXTRA_LOGGING LOG_TRACE("%s(%i:%i) port %p, buffer %p (%p,%i,%i)", port->component->name, (int)port->type, (int)port->index, port, buffer, buffer ? buffer->data: 0, buffer ? (int)buffer->offset : 0, buffer ? (int)buffer->length : 0); #endif if (!buffer->data && !(port->capabilities & MMAL_PORT_CAPABILITY_PASSTHROUGH)) { LOG_ERROR("%s(%p) received invalid buffer header", port->name, port); return MMAL_EINVAL; } if (!port->priv->pf_send) return MMAL_ENOSYS; LOCK_SENDING(port); if (!port->is_enabled) { UNLOCK_SENDING(port); return MMAL_EINVAL; } if (port->type == MMAL_PORT_TYPE_OUTPUT && buffer->length) { LOG_DEBUG("given an output buffer with length != 0"); buffer->length = 0; } IN_TRANSIT_INCREMENT(port); status = port->priv->pf_send(port, buffer); if (status != MMAL_SUCCESS) { IN_TRANSIT_DECREMENT(port); LOG_ERROR("%s: send failed: %s", port->name, mmal_status_to_string(status)); } else { mmal_port_update_port_stats(port, MMAL_CORE_STATS_RX); } UNLOCK_SENDING(port); return status; }
static MMAL_STATUS_T mmal_port_disable_internal(MMAL_PORT_T *port) { MMAL_PORT_PRIVATE_CORE_T* core = port->priv->core; MMAL_STATUS_T status = MMAL_SUCCESS; MMAL_BUFFER_HEADER_T *buffer; LOCK_PORT(port); if (!port->is_enabled) goto end; LOCK_SENDING(port); port->is_enabled = 0; UNLOCK_SENDING(port); mmal_component_action_lock(port->component); if (core->pool_for_connection) mmal_pool_callback_set(core->pool_for_connection, NULL, NULL); status = port->priv->pf_disable(port); mmal_component_action_unlock(port->component); if (status != MMAL_SUCCESS) { LOG_ERROR("port %p could not be disabled (%s)", port->name, mmal_status_to_string(status)); LOCK_SENDING(port); port->is_enabled = 1; UNLOCK_SENDING(port); goto end; } /* Flush our internal queue */ buffer = port->priv->core->queue_first; while (buffer) { MMAL_BUFFER_HEADER_T *next = buffer->next; mmal_port_buffer_header_callback(port, buffer); buffer = next; } port->priv->core->queue_first = 0; port->priv->core->queue_last = &port->priv->core->queue_first; /* Wait for all the buffers to have come back from the component */ LOG_DEBUG("%s waiting for %i buffers left in transit", port->name, (int)IN_TRANSIT_COUNT(port)); IN_TRANSIT_WAIT(port); LOG_DEBUG("%s has no buffers left in transit", port->name); port->priv->core->buffer_header_callback = NULL; end: UNLOCK_PORT(port); return status; }
static void do_connect(void) { /* this command needs a vchiq connection */ MMAL_STATUS_T st; if ((st = mmal_vc_init()) != MMAL_SUCCESS) { fprintf(stderr, "failed to initialize mmal vc library (%i:%s)\n", st, mmal_status_to_string(st)); exit(1); } }
static void control_port_cb(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer) { vout_display_t *vd = (vout_display_t *)port->userdata; MMAL_STATUS_T status; if (buffer->cmd == MMAL_EVENT_ERROR) { status = *(uint32_t *)buffer->data; msg_Err(vd, "MMAL error %"PRIx32" \"%s\"", status, mmal_status_to_string(status)); } mmal_buffer_header_release(buffer); }
static int do_components(int argc, const char **argv) { VC_MEM_ACCESS_HANDLE_T vc; VC_MEM_ADDR_T addr, statsaddr; size_t size; MMAL_VC_STATS_T stats; int rc; if (argc > 2 && (strcasecmp(argv[2], "update") == 0)) { MMAL_STATUS_T status; do_connect(); status = mmal_vc_get_stats(&stats, 0); if (status != MMAL_SUCCESS) { fprintf(stderr, "Failed to update MMAL stats. error %s", mmal_status_to_string(status)); return -1; } } else { if ((rc = OpenVideoCoreMemory(&vc)) < 0) { fprintf(stderr,"Unable to open videocore memory: %d\n", rc); return -1; } if (!LookupVideoCoreSymbol(vc, "mmal_vc_stats", &addr, &size)) { fprintf(stderr,"Could not get MMAL stats address\n"); goto fail; } if (!ReadVideoCoreUInt32(vc, &statsaddr, addr)) { fprintf(stderr,"Could not read MMAL stats pointer at address 0x%x\n", addr); goto fail; } if (!ReadVideoCoreMemory(vc, &stats, statsaddr, sizeof(stats))) { fprintf(stderr,"Could not read MMAL stats at address 0x%x\n", addr); goto fail; } CloseVideoCoreMemory(vc); } rc = print_component_stats(&stats); return rc; fail: CloseVideoCoreMemory(vc); return -1; }
static int do_version(int argc, const char **argv) { uint32_t maj = UINT_MAX, min = UINT_MAX, minimum; MMAL_STATUS_T st = mmal_vc_get_version(&maj, &min, &minimum); (void)argc; (void)argv; if (st == MMAL_SUCCESS) { printf("version %d.%02d (min %d)\n", maj, min, minimum); return 0; } else { fprintf(stderr, "error getting version (%i:%s)\n", st, mmal_status_to_string(st)); return -1; } }
static MMAL_STATUS_T mmal_port_disable_locked(MMAL_PORT_T *port) { MMAL_PORT_PRIVATE_CORE_T* core = port->priv->core; MMAL_STATUS_T status; if (!port->is_enabled) { LOG_ERROR("port %p is not enabled", port); return MMAL_EINVAL; } LOCK_SENDING(port); port->is_enabled = 0; UNLOCK_SENDING(port); mmal_component_action_lock(port->component); if (core->pool_for_connection) mmal_pool_callback_set(core->pool_for_connection, NULL, NULL); status = port->priv->pf_disable(port); mmal_component_action_unlock(port->component); if (status != MMAL_SUCCESS) { LOG_ERROR("port %p could not be disabled (%s)", port->name, mmal_status_to_string(status)); LOCK_SENDING(port); port->is_enabled = 1; UNLOCK_SENDING(port); return status; } /* Wait for all the buffers to have come back from the component */ LOG_DEBUG("%s waiting for %i buffers left in transit", port->name, (int)IN_TRANSIT_COUNT(port)); IN_TRANSIT_WAIT(port); LOG_DEBUG("%s has no buffers left in transit", port->name); port->priv->core->buffer_header_callback = NULL; if (core->connected_port && port->type == MMAL_PORT_TYPE_OUTPUT) mmal_port_disable(core->connected_port); return status; }
static int send_output_buffer(filter_t *filter) { filter_sys_t *sys = filter->p_sys; MMAL_BUFFER_HEADER_T *buffer; MMAL_STATUS_T status; picture_t *picture; int ret = 0; if (!sys->output->is_enabled) { ret = VLC_EGENERIC; goto out; } picture = filter_NewPicture(filter); if (!picture) { msg_Warn(filter, "Failed to get new picture"); ret = -1; goto out; } picture->format.i_frame_rate = filter->fmt_out.video.i_frame_rate; picture->format.i_frame_rate_base = filter->fmt_out.video.i_frame_rate_base; buffer = picture->p_sys->buffer; buffer->user_data = picture; buffer->cmd = 0; mmal_picture_lock(picture); vlc_mutex_lock(&sys->buffer_cond_mutex); status = mmal_port_send_buffer(sys->output, buffer); if (status != MMAL_SUCCESS) { msg_Err(filter, "Failed to send buffer to output port (status=%"PRIx32" %s)", status, mmal_status_to_string(status)); mmal_buffer_header_release(buffer); picture_Release(picture); ret = -1; } else { atomic_fetch_add(&sys->output_in_transit, 1); vlc_cond_signal(&sys->buffer_cond); } vlc_mutex_unlock(&sys->buffer_cond_mutex); out: return ret; }
void CMMALVideo::dec_control_port_cb(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer) { MMAL_STATUS_T status; if (buffer->cmd == MMAL_EVENT_ERROR) { status = (MMAL_STATUS_T)*(uint32_t *)buffer->data; CLog::Log(LOGERROR, "%s::%s Error (status=%x %s)", CLASSNAME, __func__, status, mmal_status_to_string(status)); } else if (buffer->cmd == MMAL_EVENT_FORMAT_CHANGED) { if (g_advancedSettings.CanLogComponent(LOGVIDEO)) CLog::Log(LOGDEBUG, "%s::%s format changed", CLASSNAME, __func__); PortSettingsChanged(port, buffer); } else CLog::Log(LOGERROR, "%s::%s other (cmd:%x data:%x)", CLASSNAME, __func__, buffer->cmd, *(uint32_t *)buffer->data); mmal_buffer_header_release(buffer); }
/** Callback from a control port. Error and EOS events stop playback. */ static void mmalplay_bh_control_cb(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer) { MMALPLAY_T *ctx = (MMALPLAY_T *)port->userdata; LOG_TRACE("%s(%p),%p,%4.4s", port->name, port, buffer, (char *)&buffer->cmd); if (buffer->cmd == MMAL_EVENT_ERROR || buffer->cmd == MMAL_EVENT_EOS) { if (buffer->cmd == MMAL_EVENT_ERROR) { LOG_INFO("error event from %s: %s", port->name, mmal_status_to_string(*(MMAL_STATUS_T*)buffer->data)); ctx->status = *(MMAL_STATUS_T *)buffer->data; } else if (buffer->cmd == MMAL_EVENT_EOS) LOG_INFO("%s: EOS received", port->name); mmalplay_stop(ctx); } mmal_buffer_header_release(buffer); }
/* Initialise all callbacks and setup internal resources */ static MMAL_STATUS_T mmal_port_clock_setup(MMAL_PORT_T *port, MMAL_PORT_CLOCK_EVENT_CB event_cb) { MMAL_STATUS_T status; status = mmal_clock_create(&port->priv->module->clock); if (status != MMAL_SUCCESS) { LOG_ERROR("failed to create clock module on port %s (%s)", port->name, mmal_status_to_string(status)); return status; } port->priv->module->clock->user_data = port; port->buffer_size = sizeof(MMAL_CLOCK_PAYLOAD_T); port->buffer_size_min = sizeof(MMAL_CLOCK_PAYLOAD_T); port->buffer_num_min = MMAL_PORT_CLOCK_BUFFERS_MIN; port->buffer_num_recommended = MMAL_PORT_CLOCK_BUFFERS_MIN; port->priv->module->event_cb = event_cb; port->priv->module->queue = mmal_queue_create(); if (!port->priv->module->queue) { mmal_clock_destroy(port->priv->module->clock); return MMAL_ENOMEM; } port->priv->pf_set_format = mmal_port_clock_set_format; port->priv->pf_enable = mmal_port_clock_enable; port->priv->pf_disable = mmal_port_clock_disable; port->priv->pf_send = mmal_port_clock_send; port->priv->pf_flush = mmal_port_clock_flush; port->priv->pf_parameter_set = mmal_port_clock_parameter_set; port->priv->pf_parameter_get = mmal_port_clock_parameter_get; port->priv->pf_connect = mmal_port_clock_connect; #ifdef __VIDEOCORE__ port->priv->pf_payload_alloc = mmal_port_clock_payload_alloc; port->priv->pf_payload_free = mmal_port_clock_payload_free; port->capabilities = MMAL_PORT_CAPABILITY_ALLOCATION; #endif return status; }
static int do_stats(int argc, const char **argv) { MMAL_VC_STATS_T stats; int reset_stats = strcasecmp(argv[1], "reset") == 0; MMAL_STATUS_T st = mmal_vc_get_stats(&stats, reset_stats); int ret; (void)argc; (void)argv; if (st != MMAL_SUCCESS) { fprintf(stderr, "error getting status (%i,%s)\n", st, mmal_status_to_string(st)); ret = -1; } else { unsigned i; uint32_t *ptr = (uint32_t*)&stats; for (i=0; i<vcos_countof(stats_fields); i++) { printf("%-32s: %u\n", stats_fields[i].name, ptr[stats_fields[i].offset/sizeof(uint32_t)]); } ret = 0; } return ret; }
static int Open(filter_t *filter) { int32_t frame_duration = filter->fmt_in.video.i_frame_rate != 0 ? (int64_t)1000000 * filter->fmt_in.video.i_frame_rate_base / filter->fmt_in.video.i_frame_rate : 0; MMAL_PARAMETER_IMAGEFX_PARAMETERS_T imfx_param = { { MMAL_PARAMETER_IMAGE_EFFECT_PARAMETERS, sizeof(imfx_param) }, MMAL_PARAM_IMAGEFX_DEINTERLACE_ADV, 2, { 3, frame_duration } }; int ret = VLC_SUCCESS; MMAL_STATUS_T status; filter_sys_t *sys; msg_Dbg(filter, "Try to open mmal_deinterlace filter. frame_duration: %d!", frame_duration); if (filter->fmt_in.video.i_chroma != VLC_CODEC_MMAL_OPAQUE) return VLC_EGENERIC; if (filter->fmt_out.video.i_chroma != VLC_CODEC_MMAL_OPAQUE) return VLC_EGENERIC; sys = calloc(1, sizeof(filter_sys_t)); if (!sys) return VLC_ENOMEM; filter->p_sys = sys; bcm_host_init(); status = mmal_component_create(MMAL_COMPONENT_DEFAULT_DEINTERLACE, &sys->component); if (status != MMAL_SUCCESS) { msg_Err(filter, "Failed to create MMAL component %s (status=%"PRIx32" %s)", MMAL_COMPONENT_DEFAULT_DEINTERLACE, status, mmal_status_to_string(status)); ret = VLC_EGENERIC; goto out; } status = mmal_port_parameter_set(sys->component->output[0], &imfx_param.hdr); if (status != MMAL_SUCCESS) { msg_Err(filter, "Failed to configure MMAL component %s (status=%"PRIx32" %s)", MMAL_COMPONENT_DEFAULT_DEINTERLACE, status, mmal_status_to_string(status)); ret = VLC_EGENERIC; goto out; } sys->component->control->userdata = (struct MMAL_PORT_USERDATA_T *)filter; status = mmal_port_enable(sys->component->control, control_port_cb); if (status != MMAL_SUCCESS) { msg_Err(filter, "Failed to enable control port %s (status=%"PRIx32" %s)", sys->component->control->name, status, mmal_status_to_string(status)); ret = VLC_EGENERIC; goto out; } sys->input = sys->component->input[0]; sys->input->userdata = (struct MMAL_PORT_USERDATA_T *)filter; if (filter->fmt_in.i_codec == VLC_CODEC_MMAL_OPAQUE) sys->input->format->encoding = MMAL_ENCODING_OPAQUE; sys->input->format->es->video.width = filter->fmt_in.video.i_width; sys->input->format->es->video.height = filter->fmt_in.video.i_height; sys->input->format->es->video.crop.x = 0; sys->input->format->es->video.crop.y = 0; sys->input->format->es->video.crop.width = filter->fmt_in.video.i_width; sys->input->format->es->video.crop.height = filter->fmt_in.video.i_height; sys->input->format->es->video.par.num = filter->fmt_in.video.i_sar_num; sys->input->format->es->video.par.den = filter->fmt_in.video.i_sar_den; es_format_Copy(&filter->fmt_out, &filter->fmt_in); filter->fmt_out.video.i_frame_rate *= 2; status = mmal_port_format_commit(sys->input); if (status != MMAL_SUCCESS) { msg_Err(filter, "Failed to commit format for input port %s (status=%"PRIx32" %s)", sys->input->name, status, mmal_status_to_string(status)); ret = VLC_EGENERIC; goto out; } sys->input->buffer_size = sys->input->buffer_size_recommended; sys->input->buffer_num = sys->input->buffer_num_recommended; if (filter->fmt_in.i_codec == VLC_CODEC_MMAL_OPAQUE) { MMAL_PARAMETER_BOOLEAN_T zero_copy = { { MMAL_PARAMETER_ZERO_COPY, sizeof(MMAL_PARAMETER_BOOLEAN_T) }, 1 }; status = mmal_port_parameter_set(sys->input, &zero_copy.hdr); if (status != MMAL_SUCCESS) { msg_Err(filter, "Failed to set zero copy on port %s (status=%"PRIx32" %s)", sys->input->name, status, mmal_status_to_string(status)); goto out; } } status = mmal_port_enable(sys->input, input_port_cb); if (status != MMAL_SUCCESS) { msg_Err(filter, "Failed to enable input port %s (status=%"PRIx32" %s)", sys->input->name, status, mmal_status_to_string(status)); ret = VLC_EGENERIC; goto out; } sys->output = sys->component->output[0]; sys->output->userdata = (struct MMAL_PORT_USERDATA_T *)filter; mmal_format_full_copy(sys->output->format, sys->input->format); status = mmal_port_format_commit(sys->output); if (status != MMAL_SUCCESS) { msg_Err(filter, "Failed to commit format for output port %s (status=%"PRIx32" %s)", sys->input->name, status, mmal_status_to_string(status)); ret = VLC_EGENERIC; goto out; } sys->output->buffer_num = 3; if (filter->fmt_in.i_codec == VLC_CODEC_MMAL_OPAQUE) { MMAL_PARAMETER_BOOLEAN_T zero_copy = { { MMAL_PARAMETER_ZERO_COPY, sizeof(MMAL_PARAMETER_BOOLEAN_T) }, 1 }; status = mmal_port_parameter_set(sys->output, &zero_copy.hdr); if (status != MMAL_SUCCESS) { msg_Err(filter, "Failed to set zero copy on port %s (status=%"PRIx32" %s)", sys->output->name, status, mmal_status_to_string(status)); goto out; } } status = mmal_port_enable(sys->output, output_port_cb); if (status != MMAL_SUCCESS) { msg_Err(filter, "Failed to enable output port %s (status=%"PRIx32" %s)", sys->output->name, status, mmal_status_to_string(status)); ret = VLC_EGENERIC; goto out; } status = mmal_component_enable(sys->component); if (status != MMAL_SUCCESS) { msg_Err(filter, "Failed to enable component %s (status=%"PRIx32" %s)", sys->component->name, status, mmal_status_to_string(status)); ret = VLC_EGENERIC; goto out; } sys->filtered_pictures = mmal_queue_create(); filter->pf_video_filter = deinterlace; filter->pf_video_flush = flush; vlc_mutex_init_recursive(&sys->mutex); vlc_mutex_init(&sys->buffer_cond_mutex); vlc_cond_init(&sys->buffer_cond); out: if (ret != VLC_SUCCESS) Close(filter); return ret; }
static int OpenDecoder(decoder_t *dec) { int ret = VLC_SUCCESS; decoder_sys_t *sys; MMAL_PARAMETER_UINT32_T extra_buffers; MMAL_STATUS_T status; if (dec->fmt_in.i_cat != VIDEO_ES) return VLC_EGENERIC; if (dec->fmt_in.i_codec != VLC_CODEC_MPGV && dec->fmt_in.i_codec != VLC_CODEC_H264) return VLC_EGENERIC; sys = calloc(1, sizeof(decoder_sys_t)); if (!sys) { ret = VLC_ENOMEM; goto out; } dec->p_sys = sys; dec->b_need_packetized = true; sys->opaque = var_InheritBool(dec, MMAL_OPAQUE_NAME); bcm_host_init(); status = mmal_component_create(MMAL_COMPONENT_DEFAULT_VIDEO_DECODER, &sys->component); if (status != MMAL_SUCCESS) { msg_Err(dec, "Failed to create MMAL component %s (status=%"PRIx32" %s)", MMAL_COMPONENT_DEFAULT_VIDEO_DECODER, status, mmal_status_to_string(status)); ret = VLC_EGENERIC; goto out; } sys->component->control->userdata = (struct MMAL_PORT_USERDATA_T *)dec; status = mmal_port_enable(sys->component->control, control_port_cb); if (status != MMAL_SUCCESS) { msg_Err(dec, "Failed to enable control port %s (status=%"PRIx32" %s)", sys->component->control->name, status, mmal_status_to_string(status)); ret = VLC_EGENERIC; goto out; } sys->input = sys->component->input[0]; sys->input->userdata = (struct MMAL_PORT_USERDATA_T *)dec; if (dec->fmt_in.i_codec == VLC_CODEC_MPGV) sys->input->format->encoding = MMAL_ENCODING_MP2V; else sys->input->format->encoding = MMAL_ENCODING_H264; if (dec->fmt_in.i_codec == VLC_CODEC_H264) { if (dec->fmt_in.i_extra > 0) { status = mmal_format_extradata_alloc(sys->input->format, dec->fmt_in.i_extra); if (status == MMAL_SUCCESS) { memcpy(sys->input->format->extradata, dec->fmt_in.p_extra, dec->fmt_in.i_extra); sys->input->format->extradata_size = dec->fmt_in.i_extra; } else { msg_Err(dec, "Failed to allocate extra format data on input port %s (status=%"PRIx32" %s)", sys->input->name, status, mmal_status_to_string(status)); } } } status = mmal_port_format_commit(sys->input); if (status != MMAL_SUCCESS) { msg_Err(dec, "Failed to commit format for input port %s (status=%"PRIx32" %s)", sys->input->name, status, mmal_status_to_string(status)); ret = VLC_EGENERIC; goto out; } sys->input->buffer_size = sys->input->buffer_size_recommended; sys->input->buffer_num = sys->input->buffer_num_recommended; status = mmal_port_enable(sys->input, input_port_cb); if (status != MMAL_SUCCESS) { msg_Err(dec, "Failed to enable input port %s (status=%"PRIx32" %s)", sys->input->name, status, mmal_status_to_string(status)); ret = VLC_EGENERIC; goto out; } sys->output = sys->component->output[0]; sys->output->userdata = (struct MMAL_PORT_USERDATA_T *)dec; if (sys->opaque) { extra_buffers.hdr.id = MMAL_PARAMETER_EXTRA_BUFFERS; extra_buffers.hdr.size = sizeof(MMAL_PARAMETER_UINT32_T); extra_buffers.value = NUM_EXTRA_BUFFERS; status = mmal_port_parameter_set(sys->output, &extra_buffers.hdr); if (status != MMAL_SUCCESS) { msg_Err(dec, "Failed to set MMAL_PARAMETER_EXTRA_BUFFERS on output port (status=%"PRIx32" %s)", status, mmal_status_to_string(status)); ret = VLC_EGENERIC; goto out; } msg_Dbg(dec, "Activate zero-copy for output port"); MMAL_PARAMETER_BOOLEAN_T zero_copy = { { MMAL_PARAMETER_ZERO_COPY, sizeof(MMAL_PARAMETER_BOOLEAN_T) }, 1 }; status = mmal_port_parameter_set(sys->output, &zero_copy.hdr); if (status != MMAL_SUCCESS) { msg_Err(dec, "Failed to set zero copy on port %s (status=%"PRIx32" %s)", sys->output->name, status, mmal_status_to_string(status)); goto out; } } status = mmal_port_enable(sys->output, output_port_cb); if (status != MMAL_SUCCESS) { msg_Err(dec, "Failed to enable output port %s (status=%"PRIx32" %s)", sys->output->name, status, mmal_status_to_string(status)); ret = VLC_EGENERIC; goto out; } status = mmal_component_enable(sys->component); if (status != MMAL_SUCCESS) { msg_Err(dec, "Failed to enable component %s (status=%"PRIx32" %s)", sys->component->name, status, mmal_status_to_string(status)); ret = VLC_EGENERIC; goto out; } sys->input_pool = mmal_pool_create(sys->input->buffer_num, 0); sys->decoded_pictures = mmal_queue_create(); if (sys->opaque) { dec->fmt_out.i_codec = VLC_CODEC_MMAL_OPAQUE; dec->fmt_out.video.i_chroma = VLC_CODEC_MMAL_OPAQUE; } else { dec->fmt_out.i_codec = VLC_CODEC_I420; dec->fmt_out.video.i_chroma = VLC_CODEC_I420; } dec->fmt_out.i_cat = VIDEO_ES; dec->pf_decode_video = decode; vlc_mutex_init_recursive(&sys->mutex); vlc_sem_init(&sys->sem, 0); out: if (ret != VLC_SUCCESS) CloseDecoder(dec); return ret; }
bool CMMALVideo::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options, MMALVideoPtr myself) { if (g_advancedSettings.CanLogComponent(LOGVIDEO)) CLog::Log(LOGDEBUG, "%s::%s usemmal:%d software:%d %dx%d", CLASSNAME, __func__, CSettings::Get().GetBool("videoplayer.usemmal"), hints.software, hints.width, hints.height); // we always qualify even if DVDFactoryCodec does this too. if (!CSettings::Get().GetBool("videoplayer.usemmal") || hints.software) return false; m_hints = hints; MMAL_STATUS_T status; MMAL_PARAMETER_BOOLEAN_T error_concealment; m_myself = myself; m_decoded_width = hints.width; m_decoded_height = hints.height; // use aspect in stream if available if (m_hints.forced_aspect) m_aspect_ratio = m_hints.aspect; else m_aspect_ratio = 0.0; switch (hints.codec) { case AV_CODEC_ID_H264: // H.264 m_codingType = MMAL_ENCODING_H264; m_pFormatName = "mmal-h264"; break; case AV_CODEC_ID_H263: case AV_CODEC_ID_MPEG4: // MPEG-4, DivX 4/5 and Xvid compatible m_codingType = MMAL_ENCODING_MP4V; m_pFormatName = "mmal-mpeg4"; break; case AV_CODEC_ID_MPEG1VIDEO: case AV_CODEC_ID_MPEG2VIDEO: // MPEG-2 m_codingType = MMAL_ENCODING_MP2V; m_pFormatName = "mmal-mpeg2"; break; case AV_CODEC_ID_VP6: // this form is encoded upside down // fall through case AV_CODEC_ID_VP6F: case AV_CODEC_ID_VP6A: // VP6 m_codingType = MMAL_ENCODING_VP6; m_pFormatName = "mmal-vp6"; break; case AV_CODEC_ID_VP8: // VP8 m_codingType = MMAL_ENCODING_VP8; m_pFormatName = "mmal-vp8"; break; case AV_CODEC_ID_THEORA: // theora m_codingType = MMAL_ENCODING_THEORA; m_pFormatName = "mmal-theora"; break; case AV_CODEC_ID_MJPEG: case AV_CODEC_ID_MJPEGB: // mjpg m_codingType = MMAL_ENCODING_MJPEG; m_pFormatName = "mmal-mjpg"; break; case AV_CODEC_ID_VC1: case AV_CODEC_ID_WMV3: // VC-1, WMV9 m_codingType = MMAL_ENCODING_WVC1; m_pFormatName = "mmal-vc1"; break; default: CLog::Log(LOGERROR, "%s::%s : Video codec unknown: %x", CLASSNAME, __func__, hints.codec); return false; break; } if ( (m_codingType == MMAL_ENCODING_MP2V && !g_RBP.GetCodecMpg2() ) || (m_codingType == MMAL_ENCODING_WVC1 && !g_RBP.GetCodecWvc1() ) ) { CLog::Log(LOGWARNING, "%s::%s Codec %s is not supported", CLASSNAME, __func__, m_pFormatName); return false; } // initialize mmal. status = mmal_component_create(MMAL_COMPONENT_DEFAULT_VIDEO_DECODER, &m_dec); if (status != MMAL_SUCCESS) { CLog::Log(LOGERROR, "%s::%s Failed to create MMAL decoder component %s (status=%x %s)", CLASSNAME, __func__, MMAL_COMPONENT_DEFAULT_VIDEO_DECODER, status, mmal_status_to_string(status)); return false; } m_dec->control->userdata = (struct MMAL_PORT_USERDATA_T *)this; status = mmal_port_enable(m_dec->control, dec_control_port_cb_static); if (status != MMAL_SUCCESS) { CLog::Log(LOGERROR, "%s::%s Failed to enable decoder control port %s (status=%x %s)", CLASSNAME, __func__, MMAL_COMPONENT_DEFAULT_VIDEO_DECODER, status, mmal_status_to_string(status)); return false; } m_dec_input = m_dec->input[0]; m_dec_input->format->type = MMAL_ES_TYPE_VIDEO; m_dec_input->format->encoding = m_codingType; if (m_hints.width && m_hints.height) { m_dec_input->format->es->video.crop.width = m_hints.width; m_dec_input->format->es->video.crop.height = m_hints.height; m_dec_input->format->es->video.width = ALIGN_UP(m_hints.width, 32); m_dec_input->format->es->video.height = ALIGN_UP(m_hints.height, 16); } m_dec_input->format->flags |= MMAL_ES_FORMAT_FLAG_FRAMED; error_concealment.hdr.id = MMAL_PARAMETER_VIDEO_DECODE_ERROR_CONCEALMENT; error_concealment.hdr.size = sizeof(MMAL_PARAMETER_BOOLEAN_T); error_concealment.enable = MMAL_FALSE; status = mmal_port_parameter_set(m_dec_input, &error_concealment.hdr); if (status != MMAL_SUCCESS) CLog::Log(LOGERROR, "%s::%s Failed to disable error concealment on %s (status=%x %s)", CLASSNAME, __func__, m_dec_input->name, status, mmal_status_to_string(status)); status = mmal_port_parameter_set_uint32(m_dec_input, MMAL_PARAMETER_EXTRA_BUFFERS, NUM_BUFFERS); if (status != MMAL_SUCCESS) CLog::Log(LOGERROR, "%s::%s Failed to enable extra buffers on %s (status=%x %s)", CLASSNAME, __func__, m_dec_input->name, status, mmal_status_to_string(status)); status = mmal_port_format_commit(m_dec_input); if (status != MMAL_SUCCESS) { CLog::Log(LOGERROR, "%s::%s Failed to commit format for decoder input port %s (status=%x %s)", CLASSNAME, __func__, m_dec_input->name, status, mmal_status_to_string(status)); return false; } m_dec_input->buffer_size = m_dec_input->buffer_size_recommended; m_dec_input->buffer_num = m_dec_input->buffer_num_recommended; m_dec_input->userdata = (struct MMAL_PORT_USERDATA_T *)this; status = mmal_port_enable(m_dec_input, dec_input_port_cb); if (status != MMAL_SUCCESS) { CLog::Log(LOGERROR, "%s::%s Failed to enable decoder input port %s (status=%x %s)", CLASSNAME, __func__, m_dec_input->name, status, mmal_status_to_string(status)); return false; } m_dec_output = m_dec->output[0]; // set up initial decoded frame format - will likely change from this m_dec_output->format->encoding = MMAL_ENCODING_OPAQUE; mmal_format_copy(m_es_format, m_dec_output->format); status = mmal_port_format_commit(m_dec_output); if (status != MMAL_SUCCESS) { CLog::Log(LOGERROR, "%s::%s Failed to commit decoder output format (status=%x %s)", CLASSNAME, __func__, status, mmal_status_to_string(status)); return false; } m_dec_output->buffer_size = m_dec_output->buffer_size_min; m_dec_output->buffer_num = m_dec_output->buffer_num_recommended; m_dec_output->userdata = (struct MMAL_PORT_USERDATA_T *)this; status = mmal_port_enable(m_dec_output, dec_output_port_cb_static); if (status != MMAL_SUCCESS) { CLog::Log(LOGERROR, "%s::%s Failed to enable decoder output port (status=%x %s)", CLASSNAME, __func__, status, mmal_status_to_string(status)); return false; } status = mmal_component_enable(m_dec); if (status != MMAL_SUCCESS) { CLog::Log(LOGERROR, "%s::%s Failed to enable decoder component %s (status=%x %s)", CLASSNAME, __func__, m_dec->name, status, mmal_status_to_string(status)); return false; } m_dec_input_pool = mmal_pool_create(m_dec_input->buffer_num, m_dec_input->buffer_size); if (!m_dec_input_pool) { CLog::Log(LOGERROR, "%s::%s Failed to create pool for decoder input port (status=%x %s)", CLASSNAME, __func__, status, mmal_status_to_string(status)); return false; } m_dec_output_pool = mmal_pool_create(m_dec_output->buffer_num, m_dec_output->buffer_size); if(!m_dec_output_pool) { CLog::Log(LOGERROR, "%s::%s Failed to create pool for decode output port (status=%x %s)", CLASSNAME, __func__, status, mmal_status_to_string(status)); return false; } if (!SendCodecConfigData()) return false; m_drop_state = false; m_startframe = false; return true; }
bool CMMALVideo::CreateDeinterlace(EINTERLACEMETHOD interlace_method) { MMAL_STATUS_T status; if (g_advancedSettings.CanLogComponent(LOGVIDEO)) CLog::Log(LOGDEBUG, "%s::%s method:%d", CLASSNAME, __func__, interlace_method); assert(!m_deint); assert(m_dec_output == m_dec->output[0]); status = mmal_port_disable(m_dec_output); if (status != MMAL_SUCCESS) { CLog::Log(LOGERROR, "%s::%s Failed to disable decoder output port (status=%x %s)", CLASSNAME, __func__, status, mmal_status_to_string(status)); return false; } /* Create deinterlace filter */ status = mmal_component_create("vc.ril.image_fx", &m_deint); if (status != MMAL_SUCCESS) { CLog::Log(LOGERROR, "%s::%s Failed to create deinterlace component (status=%x %s)", CLASSNAME, __func__, status, mmal_status_to_string(status)); return false; } MMAL_PARAMETER_IMAGEFX_PARAMETERS_T imfx_param = {{MMAL_PARAMETER_IMAGE_EFFECT_PARAMETERS, sizeof(imfx_param)}, interlace_method == VS_INTERLACEMETHOD_MMAL_ADVANCED || interlace_method == VS_INTERLACEMETHOD_MMAL_ADVANCED_HALF ? MMAL_PARAM_IMAGEFX_DEINTERLACE_ADV : MMAL_PARAM_IMAGEFX_DEINTERLACE_FAST, 3, {3, 0, interlace_method == VS_INTERLACEMETHOD_MMAL_ADVANCED_HALF || interlace_method == VS_INTERLACEMETHOD_MMAL_BOB_HALF }}; status = mmal_port_parameter_set(m_deint->output[0], &imfx_param.hdr); if (status != MMAL_SUCCESS) { CLog::Log(LOGERROR, "%s::%s Failed to set deinterlace parameters (status=%x %s)", CLASSNAME, __func__, status, mmal_status_to_string(status)); return false; } MMAL_PORT_T *m_deint_input = m_deint->input[0]; m_deint_input->userdata = (struct MMAL_PORT_USERDATA_T *)this; // Now connect the decoder output port to deinterlace input port status = mmal_connection_create(&m_deint_connection, m_dec->output[0], m_deint->input[0], MMAL_CONNECTION_FLAG_TUNNELLING | MMAL_CONNECTION_FLAG_ALLOCATION_ON_INPUT); if (status != MMAL_SUCCESS) { CLog::Log(LOGERROR, "%s::%s Failed to connect deinterlacer component %s (status=%x %s)", CLASSNAME, __func__, m_deint->name, status, mmal_status_to_string(status)); return false; } status = mmal_connection_enable(m_deint_connection); if (status != MMAL_SUCCESS) { CLog::Log(LOGERROR, "%s::%s Failed to enable connection %s (status=%x %s)", CLASSNAME, __func__, m_deint->name, status, mmal_status_to_string(status)); return false; } mmal_format_copy(m_deint->output[0]->format, m_es_format); status = mmal_port_format_commit(m_deint->output[0]); if (status != MMAL_SUCCESS) { CLog::Log(LOGERROR, "%s::%s Failed to commit deint output format (status=%x %s)", CLASSNAME, __func__, status, mmal_status_to_string(status)); return false; } status = mmal_component_enable(m_deint); if (status != MMAL_SUCCESS) { CLog::Log(LOGERROR, "%s::%s Failed to enable deinterlacer component %s (status=%x %s)", CLASSNAME, __func__, m_deint->name, status, mmal_status_to_string(status)); return false; } m_deint->output[0]->buffer_size = m_deint->output[0]->buffer_size_min; m_deint->output[0]->buffer_num = m_deint->output[0]->buffer_num_recommended; m_deint->output[0]->userdata = (struct MMAL_PORT_USERDATA_T *)this; status = mmal_port_enable(m_deint->output[0], dec_output_port_cb_static); if (status != MMAL_SUCCESS) { CLog::Log(LOGERROR, "%s::%s Failed to enable decoder output port (status=%x %s)", CLASSNAME, __func__, status, mmal_status_to_string(status)); return false; } m_dec_output = m_deint->output[0]; m_interlace_method = interlace_method; return true; }
static int send_output_buffer(decoder_t *dec) { decoder_sys_t *sys = dec->p_sys; MMAL_BUFFER_HEADER_T *buffer; picture_sys_t *p_sys; picture_t *picture; MMAL_STATUS_T status; unsigned buffer_size = 0; int ret = 0; if (!sys->output->is_enabled) return VLC_EGENERIC; /* If local output pool is allocated, use it - this is only the case for * non-opaque modes */ if (sys->output_pool) { buffer = mmal_queue_get(sys->output_pool->queue); if (!buffer) { msg_Warn(dec, "Failed to get new buffer"); return VLC_EGENERIC; } } picture = decoder_NewPicture(dec); if (!picture) { msg_Warn(dec, "Failed to get new picture"); ret = -1; goto err; } p_sys = picture->p_sys; for (int i = 0; i < picture->i_planes; i++) buffer_size += picture->p[i].i_lines * picture->p[i].i_pitch; if (sys->output_pool) { mmal_buffer_header_reset(buffer); buffer->user_data = picture; buffer->alloc_size = sys->output->buffer_size; if (buffer_size < sys->output->buffer_size) { msg_Err(dec, "Retrieved picture with too small data block (%d < %d)", buffer_size, sys->output->buffer_size); ret = VLC_EGENERIC; goto err; } if (!sys->opaque) buffer->data = picture->p[0].p_pixels; } else { buffer = p_sys->buffer; if (!buffer) { msg_Warn(dec, "Picture has no buffer attached"); picture_Release(picture); return VLC_EGENERIC; } buffer->data = p_sys->buffer->data; } buffer->cmd = 0; status = mmal_port_send_buffer(sys->output, buffer); if (status != MMAL_SUCCESS) { msg_Err(dec, "Failed to send buffer to output port (status=%"PRIx32" %s)", status, mmal_status_to_string(status)); ret = -1; goto err; } atomic_fetch_add(&sys->output_in_transit, 1); return ret; err: if (picture) picture_Release(picture); if (sys->output_pool && buffer) { buffer->data = NULL; mmal_buffer_header_release(buffer); } return ret; }
static int change_output_format(decoder_t *dec) { MMAL_PARAMETER_VIDEO_INTERLACE_TYPE_T interlace_type; decoder_sys_t *sys = dec->p_sys; MMAL_STATUS_T status; int pool_size; int ret = 0; if (atomic_load(&sys->started)) { mmal_format_full_copy(sys->output->format, sys->output_format); status = mmal_port_format_commit(sys->output); if (status != MMAL_SUCCESS) { msg_Err(dec, "Failed to commit output format (status=%"PRIx32" %s)", status, mmal_status_to_string(status)); ret = -1; goto port_reset; } goto apply_fmt; } port_reset: msg_Dbg(dec, "%s: Do full port reset", __func__); status = mmal_port_disable(sys->output); if (status != MMAL_SUCCESS) { msg_Err(dec, "Failed to disable output port (status=%"PRIx32" %s)", status, mmal_status_to_string(status)); ret = -1; goto out; } mmal_format_full_copy(sys->output->format, sys->output_format); status = mmal_port_format_commit(sys->output); if (status != MMAL_SUCCESS) { msg_Err(dec, "Failed to commit output format (status=%"PRIx32" %s)", status, mmal_status_to_string(status)); ret = -1; goto out; } if (sys->opaque) { sys->output->buffer_num = NUM_ACTUAL_OPAQUE_BUFFERS; pool_size = NUM_DECODER_BUFFER_HEADERS; } else { sys->output->buffer_num = __MAX(sys->output->buffer_num_recommended, MIN_NUM_BUFFERS_IN_TRANSIT); pool_size = sys->output->buffer_num; } sys->output->buffer_size = sys->output->buffer_size_recommended; status = mmal_port_enable(sys->output, output_port_cb); if (status != MMAL_SUCCESS) { msg_Err(dec, "Failed to enable output port (status=%"PRIx32" %s)", status, mmal_status_to_string(status)); ret = -1; goto out; } if (!atomic_load(&sys->started)) { if (!sys->opaque) { sys->output_pool = mmal_port_pool_create(sys->output, pool_size, 0); msg_Dbg(dec, "Created output pool with %d pictures", sys->output_pool->headers_num); } atomic_store(&sys->started, true); /* we need one picture from vout for each buffer header on the output * port */ dec->i_extra_picture_buffers = pool_size; /* remove what VLC core reserves as it is part of the pool_size * already */ if (dec->fmt_in.i_codec == VLC_CODEC_H264) dec->i_extra_picture_buffers -= 19; else dec->i_extra_picture_buffers -= 3; msg_Dbg(dec, "Request %d extra pictures", dec->i_extra_picture_buffers); } apply_fmt: dec->fmt_out.video.i_width = sys->output->format->es->video.width; dec->fmt_out.video.i_height = sys->output->format->es->video.height; dec->fmt_out.video.i_x_offset = sys->output->format->es->video.crop.x; dec->fmt_out.video.i_y_offset = sys->output->format->es->video.crop.y; dec->fmt_out.video.i_visible_width = sys->output->format->es->video.crop.width; dec->fmt_out.video.i_visible_height = sys->output->format->es->video.crop.height; dec->fmt_out.video.i_sar_num = sys->output->format->es->video.par.num; dec->fmt_out.video.i_sar_den = sys->output->format->es->video.par.den; dec->fmt_out.video.i_frame_rate = sys->output->format->es->video.frame_rate.num; dec->fmt_out.video.i_frame_rate_base = sys->output->format->es->video.frame_rate.den; /* Query interlaced type */ interlace_type.hdr.id = MMAL_PARAMETER_VIDEO_INTERLACE_TYPE; interlace_type.hdr.size = sizeof(MMAL_PARAMETER_VIDEO_INTERLACE_TYPE_T); status = mmal_port_parameter_get(sys->output, &interlace_type.hdr); if (status != MMAL_SUCCESS) { msg_Warn(dec, "Failed to query interlace type from decoder output port (status=%"PRIx32" %s)", status, mmal_status_to_string(status)); } else { sys->b_progressive = (interlace_type.eMode == MMAL_InterlaceProgressive); sys->b_top_field_first = sys->b_progressive ? true : (interlace_type.eMode == MMAL_InterlaceFieldsInterleavedUpperFirst); msg_Dbg(dec, "Detected %s%s video (%d)", sys->b_progressive ? "progressive" : "interlaced", sys->b_progressive ? "" : (sys->b_top_field_first ? " tff" : " bff"), interlace_type.eMode); } out: mmal_format_free(sys->output_format); sys->output_format = NULL; return ret; }
void CMMALVideo::Recycle(MMAL_BUFFER_HEADER_T *buffer) { if (g_advancedSettings.CanLogComponent(LOGVIDEO)) CLog::Log(LOGDEBUG, "%s::%s %p", CLASSNAME, __func__, buffer); MMAL_STATUS_T status; mmal_buffer_header_reset(buffer); buffer->cmd = 0; if (g_advancedSettings.CanLogComponent(LOGVIDEO)) CLog::Log(LOGDEBUG, "%s::%s Send buffer %p from pool to decoder output port %p dts_queue(%d) ready_queue(%d) busy_queue(%d)", CLASSNAME, __func__, buffer, m_dec_output, m_dts_queue.size(), m_output_ready.size(), m_output_busy); status = mmal_port_send_buffer(m_dec_output, buffer); if (status != MMAL_SUCCESS) { CLog::Log(LOGERROR, "%s::%s - Failed send buffer to decoder output port (status=0%x %s)", CLASSNAME, __func__, status, mmal_status_to_string(status)); return; } }
bool CMMALVideo::DestroyDeinterlace() { MMAL_STATUS_T status; if (g_advancedSettings.CanLogComponent(LOGVIDEO)) CLog::Log(LOGDEBUG, "%s::%s", CLASSNAME, __func__); assert(m_deint); assert(m_dec_output == m_deint->output[0]); status = mmal_port_disable(m_dec_output); if (status != MMAL_SUCCESS) { CLog::Log(LOGERROR, "%s::%s Failed to disable decoder output port (status=%x %s)", CLASSNAME, __func__, status, mmal_status_to_string(status)); return false; } status = mmal_connection_destroy(m_deint_connection); if (status != MMAL_SUCCESS) { CLog::Log(LOGERROR, "%s::%s Failed to destroy deinterlace connection (status=%x %s)", CLASSNAME, __func__, status, mmal_status_to_string(status)); return false; } m_deint_connection = NULL; status = mmal_component_disable(m_deint); if (status != MMAL_SUCCESS) { CLog::Log(LOGERROR, "%s::%s Failed to disable deinterlace component (status=%x %s)", CLASSNAME, __func__, status, mmal_status_to_string(status)); return false; } status = mmal_component_destroy(m_deint); if (status != MMAL_SUCCESS) { CLog::Log(LOGERROR, "%s::%s Failed to destroy deinterlace component (status=%x %s)", CLASSNAME, __func__, status, mmal_status_to_string(status)); return false; } m_deint = NULL; m_dec->output[0]->buffer_size = m_dec->output[0]->buffer_size_min; m_dec->output[0]->buffer_num = m_dec->output[0]->buffer_num_recommended; m_dec->output[0]->userdata = (struct MMAL_PORT_USERDATA_T *)this; status = mmal_port_enable(m_dec->output[0], dec_output_port_cb_static); if (status != MMAL_SUCCESS) { CLog::Log(LOGERROR, "%s::%s Failed to enable decoder output port (status=%x %s)", CLASSNAME, __func__, status, mmal_status_to_string(status)); return false; } m_dec_output = m_dec->output[0]; m_interlace_method = VS_INTERLACEMETHOD_NONE; return true; }
static int do_mmal_stats(int argc, const char **argv) { unsigned comp_index = 0; MMAL_BOOL_T more_ports = MMAL_TRUE, reset = MMAL_FALSE; unsigned port_index = 0; MMAL_PORT_TYPE_T type = MMAL_PORT_TYPE_INPUT; if (argc >= 3) reset = strcasecmp(argv[2], "reset") == 0; printf("component\t\tport\t\tbuffers\t\tfps\tdelay\n"); while (more_ports) { int dir; const char *dirnames[] = {"rx","tx"}; MMAL_STATS_RESULT_T result; for (dir = MMAL_CORE_STATS_RX; dir <= MMAL_CORE_STATS_TX; dir++) { double framerate; MMAL_CORE_STATISTICS_T stats; char name[32]; MMAL_STATUS_T status = mmal_vc_get_core_stats(&stats, &result, name, sizeof(name), type, comp_index, port_index, dir, reset); if (status != MMAL_SUCCESS) { fprintf(stderr, "could not get core stats: %s\n", mmal_status_to_string(status)); exit(1); } if (result == MMAL_STATS_FOUND) { if (stats.first_buffer_time == stats.last_buffer_time) framerate = 0; else framerate = 1.0e6*(1+stats.buffer_count)/(stats.last_buffer_time-stats.first_buffer_time); printf("%-20s\t%d [%s]%2s\t%-10d\t%4.1f\t%d\n", name, port_index, type == MMAL_PORT_TYPE_INPUT ? "in " : "out", dirnames[dir], stats.buffer_count, framerate, stats.max_delay); } } switch (result) { case MMAL_STATS_FOUND: port_index++; break; case MMAL_STATS_COMPONENT_NOT_FOUND: more_ports = MMAL_FALSE; break; case MMAL_STATS_PORT_NOT_FOUND: port_index = 0; if (type == MMAL_PORT_TYPE_INPUT) { type = MMAL_PORT_TYPE_OUTPUT; } else { type = MMAL_PORT_TYPE_INPUT; comp_index++; } break; default: fprintf(stderr, "bad result from query: %d\n", result); vcos_assert(0); exit(1); } } return 0; }
static picture_t *decode(decoder_t *dec, block_t **pblock) { decoder_sys_t *sys = dec->p_sys; block_t *block; MMAL_BUFFER_HEADER_T *buffer; bool need_flush = false; uint32_t len; uint32_t flags = 0; MMAL_STATUS_T status; picture_t *ret = NULL; /* * Configure output port if necessary */ if (sys->output_format) { if (change_output_format(dec) < 0) msg_Err(dec, "Failed to change output port format"); } if (!pblock) goto out; block = *pblock; /* * Check whether full flush is required */ if (block && block->i_flags & BLOCK_FLAG_DISCONTINUITY) { flush_decoder(dec); block_Release(*pblock); return NULL; } /* * Send output buffers */ if (atomic_load(&sys->started)) { buffer = mmal_queue_get(sys->decoded_pictures); if (buffer) { ret = (picture_t *)buffer->user_data; ret->date = buffer->pts; ret->b_progressive = sys->b_progressive; ret->b_top_field_first = sys->b_top_field_first; if (sys->output_pool) { buffer->data = NULL; mmal_buffer_header_reset(buffer); mmal_buffer_header_release(buffer); } } fill_output_port(dec); } if (ret) goto out; /* * Process input */ if (!block) goto out; *pblock = NULL; if (block->i_flags & BLOCK_FLAG_CORRUPTED) flags |= MMAL_BUFFER_HEADER_FLAG_CORRUPTED; vlc_mutex_lock(&sys->mutex); while (block->i_buffer > 0) { buffer = mmal_queue_timedwait(sys->input_pool->queue, 2); if (!buffer) { msg_Err(dec, "Failed to retrieve buffer header for input data"); need_flush = true; break; } mmal_buffer_header_reset(buffer); buffer->cmd = 0; buffer->pts = block->i_pts != 0 ? block->i_pts : block->i_dts; buffer->dts = block->i_dts; buffer->alloc_size = sys->input->buffer_size; len = block->i_buffer; if (len > buffer->alloc_size) len = buffer->alloc_size; buffer->data = block->p_buffer; block->p_buffer += len; block->i_buffer -= len; buffer->length = len; if (block->i_buffer == 0) buffer->user_data = block; buffer->flags = flags; status = mmal_port_send_buffer(sys->input, buffer); if (status != MMAL_SUCCESS) { msg_Err(dec, "Failed to send buffer to input port (status=%"PRIx32" %s)", status, mmal_status_to_string(status)); break; } atomic_fetch_add(&sys->input_in_transit, 1); } vlc_mutex_unlock(&sys->mutex); out: if (need_flush) flush_decoder(dec); return ret; }
int CMMALVideo::Decode(uint8_t* pData, int iSize, double dts, double pts) { //if (g_advancedSettings.CanLogComponent(LOGVIDEO)) // CLog::Log(LOGDEBUG, "%s::%s - %-8p %-6d dts:%.3f pts:%.3f dts_queue(%d) ready_queue(%d) busy_queue(%d)", // CLASSNAME, __func__, pData, iSize, dts == DVD_NOPTS_VALUE ? 0.0 : dts*1e-6, pts == DVD_NOPTS_VALUE ? 0.0 : pts*1e-6, m_dts_queue.size(), m_output_ready.size(), m_output_busy); unsigned int demuxer_bytes = 0; uint8_t *demuxer_content = NULL; MMAL_BUFFER_HEADER_T *buffer; MMAL_STATUS_T status; while (buffer = mmal_queue_get(m_dec_output_pool->queue), buffer) Recycle(buffer); // we need to queue then de-queue the demux packet, seems silly but // mmal might not have an input buffer available when we are called // and we must store the demuxer packet and try again later. // try to send any/all demux packets to mmal decoder. unsigned space = mmal_queue_length(m_dec_input_pool->queue) * m_dec_input->buffer_size; if (pData && m_demux_queue.empty() && space >= (unsigned int)iSize) { demuxer_bytes = iSize; demuxer_content = pData; } else if (pData && iSize) { mmal_demux_packet demux_packet; demux_packet.dts = dts; demux_packet.pts = pts; demux_packet.size = iSize; demux_packet.buff = new uint8_t[iSize]; memcpy(demux_packet.buff, pData, iSize); m_demux_queue_length += demux_packet.size; m_demux_queue.push(demux_packet); } uint8_t *buffer_to_free = NULL; while (1) { while (buffer = mmal_queue_get(m_dec_output_pool->queue), buffer) Recycle(buffer); space = mmal_queue_length(m_dec_input_pool->queue) * m_dec_input->buffer_size; if (!demuxer_bytes && !m_demux_queue.empty()) { mmal_demux_packet &demux_packet = m_demux_queue.front(); if (space >= (unsigned int)demux_packet.size) { // need to lock here to retrieve an input buffer and pop the queue m_demux_queue_length -= demux_packet.size; m_demux_queue.pop(); demuxer_bytes = (unsigned int)demux_packet.size; demuxer_content = demux_packet.buff; buffer_to_free = demux_packet.buff; dts = demux_packet.dts; pts = demux_packet.pts; } } if (demuxer_content) { // 500ms timeout buffer = mmal_queue_timedwait(m_dec_input_pool->queue, 500); if (!buffer) { CLog::Log(LOGERROR, "%s::%s - mmal_queue_get failed", CLASSNAME, __func__); return VC_ERROR; } mmal_buffer_header_reset(buffer); buffer->cmd = 0; if (m_startframe && pts == DVD_NOPTS_VALUE) pts = 0; buffer->pts = pts == DVD_NOPTS_VALUE ? MMAL_TIME_UNKNOWN : pts; buffer->dts = dts == DVD_NOPTS_VALUE ? MMAL_TIME_UNKNOWN : dts; buffer->length = demuxer_bytes > buffer->alloc_size ? buffer->alloc_size : demuxer_bytes; buffer->user_data = (void *)m_decode_frame_number; // set a flag so we can identify primary frames from generated frames (deinterlace) buffer->flags = MMAL_BUFFER_HEADER_FLAG_USER0; // Request decode only (maintain ref frames, but don't return a picture) if (m_drop_state) buffer->flags |= MMAL_BUFFER_HEADER_FLAG_DECODEONLY; memcpy(buffer->data, demuxer_content, buffer->length); demuxer_bytes -= buffer->length; demuxer_content += buffer->length; if (demuxer_bytes == 0) buffer->flags |= MMAL_BUFFER_HEADER_FLAG_FRAME_END; if (g_advancedSettings.CanLogComponent(LOGVIDEO)) CLog::Log(LOGDEBUG, "%s::%s - %-8p %-6d/%-6d dts:%.3f pts:%.3f flags:%x dts_queue(%d) ready_queue(%d) busy_queue(%d) demux_queue(%d) space(%d)", CLASSNAME, __func__, buffer, buffer->length, demuxer_bytes, dts == DVD_NOPTS_VALUE ? 0.0 : dts*1e-6, pts == DVD_NOPTS_VALUE ? 0.0 : pts*1e-6, buffer->flags, m_dts_queue.size(), m_output_ready.size(), m_output_busy, m_demux_queue_length, mmal_queue_length(m_dec_input_pool->queue) * m_dec_input->buffer_size); assert((int)buffer->length > 0); status = mmal_port_send_buffer(m_dec_input, buffer); if (status != MMAL_SUCCESS) { CLog::Log(LOGERROR, "%s::%s Failed send buffer to decoder input port (status=%x %s)", CLASSNAME, __func__, status, mmal_status_to_string(status)); return VC_ERROR; } if (demuxer_bytes == 0) { m_decode_frame_number++; m_startframe = true; if (m_drop_state) { m_droppedPics += m_deint ? 2:1; } else { // only push if we are successful with feeding mmal pthread_mutex_lock(&m_output_mutex); m_dts_queue.push(dts); assert(m_dts_queue.size() < 5000); pthread_mutex_unlock(&m_output_mutex); } if (m_changed_count_dec != m_changed_count) { if (g_advancedSettings.CanLogComponent(LOGVIDEO)) CLog::Log(LOGDEBUG, "%s::%s format changed frame:%d(%d)", CLASSNAME, __func__, m_changed_count_dec, m_changed_count); m_changed_count_dec = m_changed_count; if (!change_dec_output_format()) { CLog::Log(LOGERROR, "%s::%s - change_dec_output_format() failed", CLASSNAME, __func__); return VC_ERROR; } } EDEINTERLACEMODE deinterlace_request = CMediaSettings::Get().GetCurrentVideoSettings().m_DeinterlaceMode; EINTERLACEMETHOD interlace_method = g_renderManager.AutoInterlaceMethod(CMediaSettings::Get().GetCurrentVideoSettings().m_InterlaceMethod); bool deinterlace = m_interlace_mode != MMAL_InterlaceProgressive; if (deinterlace_request == VS_DEINTERLACEMODE_OFF) deinterlace = false; else if (deinterlace_request == VS_DEINTERLACEMODE_FORCE) deinterlace = true; if (((deinterlace && interlace_method != m_interlace_method) || !deinterlace) && m_deint) DestroyDeinterlace(); if (deinterlace && !m_deint) CreateDeinterlace(interlace_method); if (buffer_to_free) { delete [] buffer_to_free; buffer_to_free = NULL; demuxer_content = NULL; continue; } while (buffer = mmal_queue_get(m_dec_output_pool->queue), buffer) Recycle(buffer); } } if (!demuxer_bytes) break; } int ret = 0; if (!m_output_ready.empty()) { if (g_advancedSettings.CanLogComponent(LOGVIDEO)) CLog::Log(LOGDEBUG, "%s::%s - got space for output: demux_queue(%d) space(%d)", CLASSNAME, __func__, m_demux_queue_length, mmal_queue_length(m_dec_input_pool->queue) * m_dec_input->buffer_size); ret |= VC_PICTURE; } if (mmal_queue_length(m_dec_input_pool->queue) > 0 && !m_demux_queue_length) { if (g_advancedSettings.CanLogComponent(LOGVIDEO)) CLog::Log(LOGDEBUG, "%s::%s - got output picture:%d", CLASSNAME, __func__, m_output_ready.size()); ret |= VC_BUFFER; } if (!ret) { if (g_advancedSettings.CanLogComponent(LOGVIDEO)) CLog::Log(LOGDEBUG, "%s::%s - Nothing to do: dts_queue(%d) ready_queue(%d) busy_queue(%d) demux_queue(%d) space(%d)", CLASSNAME, __func__, m_dts_queue.size(), m_output_ready.size(), m_output_busy, m_demux_queue_length, mmal_queue_length(m_dec_input_pool->queue) * m_dec_input->buffer_size); Sleep(10); // otherwise we busy spin } return ret; }
bool CMMALVideo::SendCodecConfigData() { MMAL_STATUS_T status; if (!m_dec_input_pool) return true; // send code config data MMAL_BUFFER_HEADER_T *buffer = mmal_queue_timedwait(m_dec_input_pool->queue, 500); if (!buffer) { CLog::Log(LOGERROR, "%s::%s - mmal_queue_get failed", CLASSNAME, __func__); return false; } mmal_buffer_header_reset(buffer); buffer->cmd = 0; buffer->length = std::min(m_hints.extrasize, buffer->alloc_size); memcpy(buffer->data, m_hints.extradata, buffer->length); buffer->flags |= MMAL_BUFFER_HEADER_FLAG_FRAME_END | MMAL_BUFFER_HEADER_FLAG_CONFIG; if (g_advancedSettings.CanLogComponent(LOGVIDEO)) CLog::Log(LOGDEBUG, "%s::%s - %-8p %-6d flags:%x", CLASSNAME, __func__, buffer, buffer->length, buffer->flags); status = mmal_port_send_buffer(m_dec_input, buffer); if (status != MMAL_SUCCESS) { CLog::Log(LOGERROR, "%s::%s Failed send buffer to decoder input port (status=%x %s)", CLASSNAME, __func__, status, mmal_status_to_string(status)); return false; } return true; }