static MMAL_STATUS_T mmalplay_event_handle(MMAL_CONNECTION_T *connection, MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer) { MMAL_STATUS_T status = MMAL_SUCCESS; LOG_INFO("%s(%p) received event %4.4s (%i bytes)", port->name, port, (char *)&buffer->cmd, (int)buffer->length); if (buffer->cmd == MMAL_EVENT_FORMAT_CHANGED && port->type == MMAL_PORT_TYPE_OUTPUT) { MMAL_EVENT_FORMAT_CHANGED_T *event = mmal_event_format_changed_get(buffer); if (event) { LOG_INFO("----------Port format changed----------"); log_format(port->format, port); LOG_INFO("-----------------to---------------------"); log_format(event->format, 0); LOG_INFO(" buffers num (opt %i, min %i), size (opt %i, min: %i)", event->buffer_num_recommended, event->buffer_num_min, event->buffer_size_recommended, event->buffer_size_min); LOG_INFO("----------------------------------------"); } status = mmal_connection_event_format_changed(connection, buffer); } mmal_buffer_header_release(buffer); return status; }
/** 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); } } }
void CMMALVideo::PortSettingsChanged(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer) { MMAL_EVENT_FORMAT_CHANGED_T *fmt = mmal_event_format_changed_get(buffer); mmal_format_copy(m_es_format, fmt->format); m_changed_count++; if (m_es_format->es->video.crop.width && m_es_format->es->video.crop.height) { if (m_es_format->es->video.par.num && m_es_format->es->video.par.den) m_aspect_ratio = (float)(m_es_format->es->video.par.num * m_es_format->es->video.crop.width) / (m_es_format->es->video.par.den * m_es_format->es->video.crop.height); m_decoded_width = m_es_format->es->video.crop.width; m_decoded_height = m_es_format->es->video.crop.height; if (g_advancedSettings.CanLogComponent(LOGVIDEO)) CLog::Log(LOGDEBUG, "%s::%s format changed: %dx%d %.2f frame:%d", CLASSNAME, __func__, m_decoded_width, m_decoded_height, m_aspect_ratio, m_changed_count); } else CLog::Log(LOGERROR, "%s::%s format changed: Unexpected %dx%d", CLASSNAME, __func__, m_es_format->es->video.crop.width, m_es_format->es->video.crop.height); }
static void output_port_cb(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer) { decoder_t *dec = (decoder_t *)port->userdata; decoder_sys_t *sys = dec->p_sys; picture_t *picture; MMAL_EVENT_FORMAT_CHANGED_T *fmt; MMAL_ES_FORMAT_T *format; if (buffer->cmd == 0) { if (buffer->length > 0) { mmal_queue_put(sys->decoded_pictures, buffer); } else { picture = (picture_t *)buffer->user_data; picture_Release(picture); if (sys->output_pool) { buffer->user_data = NULL; buffer->alloc_size = 0; buffer->data = NULL; mmal_buffer_header_release(buffer); } } atomic_fetch_sub(&sys->output_in_transit, 1); vlc_sem_post(&sys->sem); } else if (buffer->cmd == MMAL_EVENT_FORMAT_CHANGED) { fmt = mmal_event_format_changed_get(buffer); format = mmal_format_alloc(); mmal_format_full_copy(format, fmt->format); if (sys->opaque) format->encoding = MMAL_ENCODING_OPAQUE; sys->output_format = format; mmal_buffer_header_release(buffer); } else { mmal_buffer_header_release(buffer); } }
// Fetch a decoded buffer and place it into the frame parameter. static int ffmmal_read_frame(AVCodecContext *avctx, AVFrame *frame, int *got_frame) { MMALDecodeContext *ctx = avctx->priv_data; MMAL_BUFFER_HEADER_T *buffer = NULL; MMAL_STATUS_T status = 0; int ret = 0; if (ctx->eos_received) goto done; while (1) { // To ensure decoding in lockstep with a constant delay between fed packets // and output frames, we always wait until an output buffer is available. // Except during start we don't know after how many input packets the decoder // is going to return the first buffer, and we can't distinguish decoder // being busy from decoder waiting for input. So just poll at the start and // keep feeding new data to the buffer. // We are pretty sure the decoder will produce output if we sent more input // frames than what a H.264 decoder could logically delay. This avoids too // excessive buffering. // We also wait if we sent eos, but didn't receive it yet (think of decoding // stream with a very low number of frames). if (avpriv_atomic_int_get(&ctx->packets_buffered) > MAX_DELAYED_FRAMES || (ctx->packets_sent && ctx->eos_sent)) { // MMAL will ignore broken input packets, which means the frame we // expect here may never arrive. Dealing with this correctly is // complicated, so here's a hack to avoid that it freezes forever // in this unlikely situation. buffer = mmal_queue_timedwait(ctx->queue_decoded_frames, 100); if (!buffer) { av_log(avctx, AV_LOG_ERROR, "Did not get output frame from MMAL.\n"); ret = AVERROR_UNKNOWN; goto done; } } else { buffer = mmal_queue_get(ctx->queue_decoded_frames); if (!buffer) goto done; } ctx->eos_received |= !!(buffer->flags & MMAL_BUFFER_HEADER_FLAG_EOS); if (ctx->eos_received) goto done; if (buffer->cmd == MMAL_EVENT_FORMAT_CHANGED) { MMAL_COMPONENT_T *decoder = ctx->decoder; MMAL_EVENT_FORMAT_CHANGED_T *ev = mmal_event_format_changed_get(buffer); MMAL_BUFFER_HEADER_T *stale_buffer; av_log(avctx, AV_LOG_INFO, "Changing output format.\n"); if ((status = mmal_port_disable(decoder->output[0]))) goto done; while ((stale_buffer = mmal_queue_get(ctx->queue_decoded_frames))) mmal_buffer_header_release(stale_buffer); mmal_format_copy(decoder->output[0]->format, ev->format); if ((ret = ffmal_update_format(avctx)) < 0) goto done; if ((status = mmal_port_enable(decoder->output[0], output_callback))) goto done; if ((ret = ffmmal_fill_output_port(avctx)) < 0) goto done; if ((ret = ffmmal_fill_input_port(avctx)) < 0) goto done; mmal_buffer_header_release(buffer); continue; } else if (buffer->cmd) { char s[20]; av_get_codec_tag_string(s, sizeof(s), buffer->cmd); av_log(avctx, AV_LOG_WARNING, "Unknown MMAL event %s on output port\n", s); goto done; } else if (buffer->length == 0) { // Unused output buffer that got drained after format change. mmal_buffer_header_release(buffer); continue; } ctx->frames_output++; if ((ret = ffmal_copy_frame(avctx, frame, buffer)) < 0) goto done; *got_frame = 1; break; } done: if (buffer) mmal_buffer_header_release(buffer); if (status && ret >= 0) ret = AVERROR_UNKNOWN; return ret; }
static BRCMIMAGE_STATUS_T brcmimage_decode(BRCMIMAGE_T *ctx, BRCMIMAGE_REQUEST_T *jd) { BRCMIMAGE_STATUS_T err; MMAL_STATUS_T status; MMAL_BUFFER_HEADER_T *in, *out; MMAL_BOOL_T eos = MMAL_FALSE; const uint8_t *inBuf = jd->input; unsigned int slices = 0, inBufSize = jd->input_size; MMAL_PORT_T *port_in = ctx->mmal->input[0]; MMAL_PORT_T *port_out = ctx->mmal->output[0]; LOG_DEBUG("decode %i bytes\n", jd->input_size); jd->output_size = 0; err = brcmimage_configure_decoder(ctx, jd); if (err != BRCMIMAGE_SUCCESS) return err; while (!eos) { /* Send as many chunks of data to decode as we can */ while (inBufSize) { status = mmal_wrapper_buffer_get_empty(port_in, &in, 0); if (status == MMAL_EAGAIN) break; CHECK_MMAL_STATUS(status, EXECUTE, "failed to get empty buffer (%i)", status); in->data = (uint8_t *)inBuf; in->length = MMAL_MIN(port_in->buffer_size, inBufSize); in->alloc_size = in->length; inBufSize -= in->length; inBuf += in->length; in->flags = inBufSize ? 0 : MMAL_BUFFER_HEADER_FLAG_EOS; LOG_DEBUG("send decode in (%i bytes)\n", in->length); status = mmal_port_send_buffer(port_in, in); CHECK_MMAL_STATUS(status, EXECUTE, "failed to send input buffer"); } /* Check for decoded data */ status = mmal_wrapper_buffer_get_full(port_out, &out, 0); if (status == MMAL_EAGAIN) { WAIT(ctx); continue; } CHECK_MMAL_STATUS(status, EXECUTE, "error decoding"); /* Check if a new format has been auto-detected by the decoder */ if (out->cmd == MMAL_EVENT_FORMAT_CHANGED) { MMAL_EVENT_FORMAT_CHANGED_T *event = mmal_event_format_changed_get(out); if (event) mmal_format_copy(port_out->format, event->format); mmal_buffer_header_release(out); if (!event) status = MMAL_EINVAL; CHECK_MMAL_STATUS(status, EXECUTE, "invalid format change event"); LOG_DEBUG("new format (%4.4s:%ux%u|%ux%u)\n", (char *)&event->format->encoding, event->format->es->video.crop.width, event->format->es->video.crop.height, event->format->es->video.width, event->format->es->video.height); /* re-setup the output port for the new format */ status = mmal_wrapper_port_disable(port_out); CHECK_MMAL_STATUS(status, EXECUTE, "failed to disable output port"); ctx->slice_height = event->format->es->video.height; if (ENABLE_SLICE_MODE && !jd->output_handle) { /* setup slice mode */ if (port_out->format->encoding == MMAL_ENCODING_I420 || port_out->format->encoding == MMAL_ENCODING_I422) { if (port_out->format->encoding == MMAL_ENCODING_I420) port_out->format->encoding = MMAL_ENCODING_I420_SLICE; if (port_out->format->encoding == MMAL_ENCODING_I422) port_out->format->encoding = MMAL_ENCODING_I422_SLICE; ctx->slice_height = 16; port_out->buffer_num = 3; } } LOG_DEBUG("using slice size %u\n", ctx->slice_height); status = mmal_port_format_commit(port_out); CHECK_MMAL_STATUS(status, EXECUTE, "invalid format change event"); port_out->buffer_size = port_out->buffer_size_min; if (jd->output_handle) status = mmal_wrapper_port_enable(port_out, MMAL_WRAPPER_FLAG_PAYLOAD_USE_SHARED_MEMORY); else status = mmal_wrapper_port_enable(port_out, MMAL_WRAPPER_FLAG_PAYLOAD_ALLOCATE); CHECK_MMAL_STATUS(status, EXECUTE, "failed to enable output port"); /* send all our output buffers to the decoder */ while (mmal_wrapper_buffer_get_empty(port_out, &out, 0) == MMAL_SUCCESS) { if (jd->output_handle) { out->data = (uint8_t*)jd->output_handle; out->alloc_size = jd->output_alloc_size; } status = mmal_port_send_buffer(port_out, out); CHECK_MMAL_STATUS(status, EXECUTE, "failed to send output buffer"); } continue; } /* We have part of our output frame */ jd->width = port_out->format->es->video.crop.width; if (!jd->width) jd->width = port_out->format->es->video.width; if (jd->output_handle) jd->buffer_width = port_out->format->es->video.width; if (!jd->buffer_width) jd->buffer_width = jd->width; jd->height = port_out->format->es->video.crop.height; if (!jd->height) jd->height = port_out->format->es->video.height; if (jd->output_handle) jd->buffer_height = port_out->format->es->video.height; if (!jd->buffer_height) jd->buffer_height = jd->height; if (jd->output_handle) { jd->output_size += out->length; } else { jd->output_size = brcmimage_copy_pixels(jd->output, jd->output_alloc_size, out->data, out->length, jd->pixel_format, jd->buffer_width, jd->buffer_height, port_out->format->es->video.width, ctx->slice_height, slices * ctx->slice_height, 0); slices++; } eos = out->flags & MMAL_BUFFER_HEADER_FLAG_EOS; out->length = 0; if (eos) { mmal_buffer_header_release(out); } else { status = mmal_port_send_buffer(port_out, out); CHECK_MMAL_STATUS(status, EXECUTE, "failed to send output buffer"); } if (!jd->output_size) status = MMAL_EINVAL; CHECK_MMAL_STATUS(status, OUTPUT_BUFFER, "invalid output buffer"); } LOG_DEBUG("decoded W:%ixH%i:(W%ixH%i):%i in %i slices\n", jd->width, jd->height, jd->buffer_width, jd->buffer_height, jd->pixel_format, slices); mmal_port_flush(port_in); return BRCMIMAGE_SUCCESS; error: mmal_port_flush(port_in); return err; }
static MMAL_BOOL_T sdl_do_processing(MMAL_COMPONENT_T *component) { MMAL_PORT_T *port = component->input[0]; MMAL_COMPONENT_MODULE_T *module = component->priv->module; unsigned int width = port->format->es->video.width; unsigned int height = port->format->es->video.height; MMAL_BUFFER_HEADER_T *buffer; uint8_t *src_plane[3]; uint32_t *src_pitch; unsigned int i, line; MMAL_BOOL_T eos; SDL_Rect rect; buffer = mmal_queue_get(module->queue); if (!buffer) return 0; eos = buffer->flags & MMAL_BUFFER_HEADER_FLAG_EOS; /* Handle event buffers */ if (buffer->cmd) { MMAL_EVENT_FORMAT_CHANGED_T *event = mmal_event_format_changed_get(buffer); if (event) { mmal_format_copy(port->format, event->format); module->status = port->priv->pf_set_format(port); if (module->status != MMAL_SUCCESS) { LOG_ERROR("format not set on port %p", port); if (mmal_event_error_send(port->component, module->status) != MMAL_SUCCESS) LOG_ERROR("unable to send an error event buffer"); } } else { LOG_ERROR("discarding event %i on port %p", (int)buffer->cmd, port); } buffer->length = 0; mmal_port_buffer_header_callback(port, buffer); return 1; } if (module->status != MMAL_SUCCESS) return 1; /* Ignore empty buffers */ if (!buffer->length) goto end; // FIXME: sanity check the size of the buffer /* Blit the buffer onto the overlay. */ src_pitch = buffer->type->video.pitch; src_plane[0] = buffer->data + buffer->type->video.offset[0]; src_plane[1] = buffer->data + buffer->type->video.offset[2]; src_plane[2] = buffer->data + buffer->type->video.offset[1]; SDL_LockYUVOverlay(module->sdl_overlay); for (i=0; i<3; i++) { uint8_t *src = src_plane[i]; uint8_t *dst = module->sdl_overlay->pixels[i]; if(i == 1) {width /= 2; height /= 2;} for(line = 0; line < height; line++) { memcpy(dst, src, width); src += src_pitch[i]; dst += module->sdl_overlay->pitches[i]; } } SDL_UnlockYUVOverlay(module->sdl_overlay); width = port->format->es->video.width; height = port->format->es->video.height; rect.x = module->display_region.x; rect.w = module->display_region.width; height = rect.w * height / width; rect.y = module->display_region.y + (module->display_region.height - height) / 2; rect.h = height; SDL_DisplayYUVOverlay(module->sdl_overlay, &rect); end: buffer->offset = buffer->length = 0; mmal_port_buffer_header_callback(port, buffer); /* Generate EOS events */ if (eos) mmal_event_eos_send(port); return 1; }