Skip to content

Instantly share code, notes, and snippets.

@dennis-hamester
Created March 29, 2014 10:31
Show Gist options
  • Select an option

  • Save dennis-hamester/9852055 to your computer and use it in GitHub Desktop.

Select an option

Save dennis-hamester/9852055 to your computer and use it in GitHub Desktop.
#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <pthread.h>
#include <sys/time.h>
#include <interface/mmal/mmal.h>
#include <interface/mmal/util/mmal_util.h>
#include <interface/mmal/util/mmal_default_components.h>
struct data_t {
unsigned num_buffers;
unsigned max_buffers_in_transit;
MMAL_COMPONENT_T *dec;
MMAL_PORT_T *input;
MMAL_PORT_T *output;
MMAL_POOL_T *input_pool;
MMAL_POOL_T *output_pool;
MMAL_ES_FORMAT_T *format;
pthread_mutex_t mutex;
unsigned buffers_in_transit;
unsigned frame;
};
static volatile sig_atomic_t aborted = 0;
static void on_signal(int sig);
static int change_output_format(struct data_t *data);
static void dec_control_port_cb(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer);
static void dec_input_port_cb(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer);
static void dec_output_port_cb(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer);
static int send_buffer(struct data_t *data);
int main(int argc, char *argv[]) {
struct data_t data;
FILE *src;
MMAL_BUFFER_HEADER_T *buffer;
MMAL_STATUS_T status;
int i;
int ret = EXIT_SUCCESS;
signal(SIGINT, on_signal);
signal(SIGTERM, on_signal);
memset(&data, 0, sizeof(struct data_t));
pthread_mutex_init(&data.mutex, NULL);
if (argc < 3) {
printf("Specify num_buffers and max_buffers_in_transit\n");
ret = EXIT_FAILURE;
goto out;
}
data.num_buffers = atoi(argv[1]);
data.max_buffers_in_transit = atoi(argv[2]);
if (data.max_buffers_in_transit > data.num_buffers) {
printf("num_buffers must be >= than max_buffers_in_transit\n");
ret = EXIT_FAILURE;
goto out;
}
src = fopen("test.h264", "r");
if (!src) {
printf("Failed to open %s\n", argv[1]);
ret = EXIT_FAILURE;
goto out;
}
status = mmal_component_create(MMAL_COMPONENT_DEFAULT_VIDEO_DECODER, &data.dec);
if (status != MMAL_SUCCESS) {
printf("Failed to create MMAL decoder component %s (status=%"PRIx32" %s)\n", MMAL_COMPONENT_DEFAULT_VIDEO_DECODER, status, mmal_status_to_string(status));
ret = EXIT_FAILURE;
goto out;
}
data.dec->control->userdata = (struct MMAL_PORT_USERDATA_T *)&data;
status = mmal_port_enable(data.dec->control, dec_control_port_cb);
if (status != MMAL_SUCCESS) {
printf("Failed to enable decoder control port %s (status=%"PRIx32" %s)\n", data.dec->control->name, status, mmal_status_to_string(status));
ret = EXIT_FAILURE;
goto out;
}
data.input = data.dec->input[0];
data.input->userdata = (struct MMAL_PORT_USERDATA_T *)&data;
data.input->format->encoding = MMAL_ENCODING_H264;
status = mmal_port_format_commit(data.input);
if (status != MMAL_SUCCESS) {
printf("Failed to commit format for decoder input port %s (status=%"PRIx32" %s)\n", data.input->name, status, mmal_status_to_string(status));
ret = EXIT_FAILURE;
goto out;
}
data.input->buffer_size = data.input->buffer_size_recommended;
data.input->buffer_num = data.input->buffer_num_recommended;
status = mmal_port_enable(data.input, dec_input_port_cb);
if (status != MMAL_SUCCESS) {
printf("Failed to enable decoder input port %s (status=%"PRIx32" %s)\n", data.input->name, status, mmal_status_to_string(status));
ret = EXIT_FAILURE;
goto out;
}
data.output = data.dec->output[0];
data.output->userdata = (struct MMAL_PORT_USERDATA_T *)&data;
status = mmal_port_enable(data.output, dec_output_port_cb);
if (status != MMAL_SUCCESS) {
printf("Failed to enable decoder output port %s (status=%"PRIx32" %s)\n", data.output->name, status, mmal_status_to_string(status));
ret = EXIT_FAILURE;
goto out;
}
status = mmal_component_enable(data.dec);
if (status != MMAL_SUCCESS) {
printf("Failed to enable decoder component %s (status=%"PRIx32" %s)\n", data.dec->name, status, mmal_status_to_string(status));
ret = EXIT_FAILURE;
goto out;
}
data.input_pool = mmal_pool_create_with_allocator(data.input->buffer_num, data.input->buffer_size, data.input, (mmal_pool_allocator_alloc_t)mmal_port_payload_alloc, (mmal_pool_allocator_free_t)mmal_port_payload_free);
if (!data.input_pool) {
printf("Failed to create pool for decoder input port (%d, %s)\n", status, mmal_status_to_string(status));
ret = EXIT_FAILURE;
goto out;
}
if (data.max_buffers_in_transit + 5 < data.num_buffers)
printf("Expect deadlocking\n");
while (!aborted) {
buffer = mmal_queue_get(data.input_pool->queue);
if (buffer) {
mmal_buffer_header_reset(buffer);
buffer->cmd = 0;
buffer->pts = 1;
buffer->length = fread(buffer->data, 1, buffer->alloc_size, src);
if (buffer->length != buffer->alloc_size) {
aborted = 1;
}
status = mmal_port_send_buffer(data.input, buffer);
if (status != MMAL_SUCCESS) {
printf("Failed send buffer to decoder input port (%d, %s)\n", status, mmal_status_to_string(status));
ret = EXIT_FAILURE;
goto out;
}
}
if (!data.output_pool && data.format) {
if (change_output_format(&data) < 0)
goto out;
}
if (data.output_pool && data.buffers_in_transit == 0 && pthread_mutex_trylock(&data.mutex) == 0) {
for (i = 0; i < data.max_buffers_in_transit; ++i) {
if (send_buffer(&data) == 0) {
++data.buffers_in_transit;
}
else {
break;
}
}
pthread_mutex_unlock(&data.mutex);
}
}
out:
pthread_mutex_destroy(&data.mutex);
if (data.dec) {
mmal_component_disable(data.dec);
mmal_port_disable(data.dec->control);
}
if (data.input)
mmal_port_disable(data.input);
if (data.output)
mmal_port_disable(data.output);
if (data.input_pool)
mmal_pool_destroy(data.input_pool);
if (data.output_pool)
mmal_pool_destroy(data.output_pool);
if (data.dec)
mmal_component_release(data.dec);
if (data.format)
mmal_format_free(data.format);
return ret;
}
static void on_signal(int sig)
{
if (aborted) {
abort();
}
aborted = 1;
}
static int change_output_format(struct data_t *data)
{
MMAL_STATUS_T status;
int ret = 0;
status = mmal_port_disable(data->output);
if (status != MMAL_SUCCESS) {
printf("Failed to disable decoder output port (status=%"PRIx32" %s)\n", status, mmal_status_to_string(status));
ret = -1;
goto out;
}
mmal_format_full_copy(data->output->format, data->format);
status = mmal_port_format_commit(data->output);
if (status != MMAL_SUCCESS) {
printf("Failed to commit output format (status=%"PRIx32" %s)\n", status, mmal_status_to_string(status));
ret = -1;
goto out;
}
data->output->buffer_num = data->num_buffers;
data->output->buffer_size = data->output->buffer_size_min;
status = mmal_port_enable(data->output, dec_output_port_cb);
if (status != MMAL_SUCCESS) {
printf("Failed to enable output port (status=%"PRIx32" %s)\n", status, mmal_status_to_string(status));
ret = -1;
goto out;
}
printf("Creating %u opaque buffers\n", data->num_buffers);
data->output_pool = mmal_pool_create_with_allocator(data->output->buffer_num, data->output->buffer_size, data->output, (mmal_pool_allocator_alloc_t)mmal_port_payload_alloc, (mmal_pool_allocator_free_t)mmal_port_payload_free);
if (!data->output_pool) {
printf("Failed to create pool for decoder output port (%d, %s)\n", status, mmal_status_to_string(status));
ret = EXIT_FAILURE;
goto out;
}
out:
return ret;
}
static void dec_control_port_cb(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer) {
MMAL_STATUS_T status;
if (buffer->cmd == MMAL_EVENT_ERROR) {
status = *(uint32_t *)buffer->data;
printf("Decoder MMAL error %"PRIx32" \"%s\"\n", status, mmal_status_to_string(status));
}
mmal_buffer_header_release(buffer);
}
static void dec_input_port_cb(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer) {
mmal_buffer_header_release(buffer);
}
static void dec_output_port_cb(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer) {
struct data_t *data = (struct data_t *)port->userdata;
MMAL_EVENT_FORMAT_CHANGED_T *fmt;
MMAL_ES_FORMAT_T *format;
unsigned i;
int valid;
if (buffer->cmd == 0) {
pthread_mutex_lock(&data->mutex);
--data->buffers_in_transit;
valid = buffer->length > 0;
if (valid)
++data->frame;
mmal_buffer_header_release(buffer);
for (i = data->buffers_in_transit; i < data->max_buffers_in_transit; ++i) {
if (send_buffer(data) == 0) {
++data->buffers_in_transit;
}
else {
break;
}
}
if (valid)
printf("Frame %u decoded (decoder has %u buffers)\n", data->frame, data->buffers_in_transit);
pthread_mutex_unlock(&data->mutex);
}
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);
format->encoding = MMAL_ENCODING_OPAQUE;
data->format = format;
mmal_buffer_header_release(buffer);
}
else {
mmal_buffer_header_release(buffer);
}
}
static int send_buffer(struct data_t *data) {
MMAL_BUFFER_HEADER_T *buffer;
MMAL_STATUS_T status;
int ret = 0;
buffer = mmal_queue_get(data->output_pool->queue);
if (!buffer) {
ret = -1;
goto out;
}
mmal_buffer_header_reset(buffer);
buffer->cmd = 0;
status = mmal_port_send_buffer(data->output, buffer);
if (status != MMAL_SUCCESS) {
mmal_buffer_header_release(buffer);
ret = -1;
goto out;
}
out:
return ret;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment