Created
March 29, 2014 10:31
-
-
Save dennis-hamester/9852055 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #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