/* Parse a string of the form: "fourcc:widthxheight" */ static int get_format(const char *name, uint32_t *fourcc, unsigned int *width, unsigned int *height) { char *delim, fcc[4] = {' ', ' ', ' ', ' '}; unsigned int value_u1, value_u2; size_t size; *width = *height = 0; *fourcc = MMAL_ENCODING_UNKNOWN; /* Fourcc is the first element */ delim = strchr(name, ':'); size = delim ? (size_t)(delim - name) : strlen(name); memcpy(fcc, name, MMAL_MIN(size, sizeof(fcc))); if (size == sizeof("yuv420")-1 && !memcmp(name, "yuv420", size)) *fourcc = MMAL_ENCODING_I420; else if (size == sizeof("yuvuv")-1 && !memcmp(name, "yuvuv", size)) *fourcc = MMAL_ENCODING_YUVUV128; else if (size == sizeof("opaque")-1 && !memcmp(name, "opaque", size)) *fourcc = MMAL_ENCODING_OPAQUE; else if (size > 0 && size <= 4) *fourcc = MMAL_FOURCC(fcc[0], fcc[1], fcc[2], fcc[3]); else return 1; if (!delim) return 0; /* Nothing more to parse */ /* Width/height are next */ /* coverity[secure_coding] Only reading integers, so can't overflow */ if (sscanf(delim+1, "%ux%u", &value_u1, &value_u2) != 2) return 1; *width = value_u1; *height = value_u2; return 0; }
/** Create an instance of mmalplay. * Note: this is test code. Do not use it in your app. It *will* change or even be removed without notice. */ MMALPLAY_T *mmalplay_create(const char *uri, MMALPLAY_OPTIONS_T *opts, MMAL_STATUS_T *pstatus) { MMAL_STATUS_T status = MMAL_SUCCESS, status_audio, status_video, status_clock; MMALPLAY_T *ctx; MMAL_COMPONENT_T *component; MMALPLAY_CONNECTIONS_T connections; unsigned int i; LOG_TRACE("%s", uri); if (pstatus) *pstatus = MMAL_ENOMEM; /* Allocate and initialise context */ ctx = malloc(sizeof(MMALPLAY_T)); if (!ctx) return NULL; memset(ctx, 0, sizeof(*ctx)); memset(&connections, 0, sizeof(connections)); if (vcos_semaphore_create(&ctx->event, "MMALTest", 1) != VCOS_SUCCESS) { free(ctx); return NULL; } ctx->uri = uri; if (opts) ctx->options = *opts; ctx->options.output_num = MMAL_MAX(ctx->options.output_num, 1); ctx->options.output_num = MMAL_MIN(ctx->options.output_num, MMALPLAY_MAX_RENDERERS); connections.num = 0; /* Create and setup the container reader component */ component = mmalplay_component_create(ctx, MMAL_COMPONENT_DEFAULT_CONTAINER_READER, &status); if (!component) goto error; status_video = mmalplay_pipeline_video_create(ctx, ctx->reader_video, &connections); status_audio = mmalplay_pipeline_audio_create(ctx, ctx->reader_audio, &connections); status_clock = mmalplay_pipeline_clock_create(ctx, &connections); if (status_video != MMAL_SUCCESS && status_audio != MMAL_SUCCESS && status_clock != MMAL_SUCCESS) { status = status_video; goto error; } /* Create our connections */ for (i = 0; i < connections.num; i++) { status = mmalplay_connection_create(ctx, connections.connection[i].out, connections.connection[i].in, connections.connection[i].flags); if (status != MMAL_SUCCESS) goto error; } /* Enable our connections */ for (i = 0; i < ctx->connection_num; i++) { status = mmal_connection_enable(ctx->connection[i]); if (status != MMAL_SUCCESS) goto error; } if (pstatus) *pstatus = MMAL_SUCCESS; return ctx; error: mmalplay_destroy(ctx); if (status == MMAL_SUCCESS) status = MMAL_ENOSPC; if (pstatus) *pstatus = status; return NULL; }
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 BRCMIMAGE_STATUS_T brcmimage_encode(BRCMIMAGE_T *ctx, BRCMIMAGE_REQUEST_T *je) { BRCMIMAGE_STATUS_T err; MMAL_STATUS_T status = MMAL_SUCCESS; MMAL_BUFFER_HEADER_T *in, *out; MMAL_BOOL_T eos = MMAL_FALSE; const uint8_t *outBuf = je->output; unsigned int loop = 0, slices = 0, outBufSize = je->output_alloc_size; MMAL_PORT_T *port_in = ctx->mmal->input[0]; MMAL_PORT_T *port_out = ctx->mmal->output[0]; je->output_size = 0; err = brcmimage_configure_encoder(ctx, je); if (err != BRCMIMAGE_SUCCESS) return err; /* Then we read the encoded data back from the encoder */ while (!eos && status == MMAL_SUCCESS) { /* send buffers to be filled */ while (mmal_wrapper_buffer_get_empty(port_out, &out, 0) == MMAL_SUCCESS) { out->data = (uint8_t *)outBuf; out->alloc_size = MMAL_MIN(port_out->buffer_size, outBufSize); outBufSize -= out->alloc_size; outBuf += out->alloc_size; status = mmal_port_send_buffer(port_out, out); CHECK_MMAL_STATUS(status, EXECUTE, "failed to send buffer"); } /* Send slices to be encoded */ if (slices * ctx->slice_height < port_in->format->es->video.height && mmal_wrapper_buffer_get_empty(port_in, &in, 0) == MMAL_SUCCESS) { if (je->input_handle) { in->data = (uint8_t *)je->input_handle; in->length = in->alloc_size = je->input_size; } else { in->length = brcmimage_copy_pixels(in->data, in->alloc_size, je->input, je->input_size, je->pixel_format, port_in->format->es->video.width, ctx->slice_height, je->buffer_width, je->buffer_height, slices * ctx->slice_height, 1); if (!in->length) status = MMAL_EINVAL; CHECK_MMAL_STATUS(status, INPUT_BUFFER, "input buffer too small"); } slices++; if (slices * ctx->slice_height >= port_in->format->es->video.height) in->flags = MMAL_BUFFER_HEADER_FLAG_EOS; status = mmal_port_send_buffer(port_in, in); CHECK_MMAL_STATUS(status, EXECUTE, "failed to send buffer"); } status = mmal_wrapper_buffer_get_full(port_out, &out, 0); if (status == MMAL_EAGAIN) { status = MMAL_SUCCESS; WAIT(ctx); continue; } CHECK_MMAL_STATUS(status, EXECUTE, "failed to get full buffer"); LOG_DEBUG("received %i bytes\n", out->length); je->output_size += out->length; eos = out->flags & MMAL_BUFFER_HEADER_FLAG_EOS; /* Detect when the encoder is running out of space for its output */ if (++loop >= port_out->buffer_num && !eos && !out->length) { LOG_ERROR("no more output space for encoder"); status = MMAL_EINVAL; } mmal_buffer_header_release(out); } /* Check if buffer was too small */ CHECK_MMAL_STATUS(status, OUTPUT_BUFFER, "output buffer too small"); LOG_DEBUG("encoded W:%ixH:%i:%i (%i bytes) in %i slices\n", je->width, je->height, je->pixel_format, je->output_size, slices); mmal_port_flush(port_out); return BRCMIMAGE_SUCCESS; error: mmal_wrapper_port_disable(port_in); mmal_wrapper_port_disable(port_out); return err; }