Skip to content

Instantly share code, notes, and snippets.

@erinaceous erinaceous/ola_video.c
Last active Aug 29, 2015

Embed
What would you like to do?
// vim: set tabstop=4 shiftwidth=4 textwidth=79 cc=72,79:
/*
* Video player based off hello_video.c
* Listens for commands via a FIFO file.
*
* Owain Jones <github.com/erinaceous>
*
* Original hello_video:
* Copyright (c) 2012, Broadcom Europe Ltd
* All rights reserved.
*/
#pragma pack(1) // might fix some things in OMX/ILClient relating to structs?
#define BUFFER_BYTES (80 << 10)
#define SLEEP_LENGTH 100
//#define DEBUG;
#ifdef DEBUG
#define D if(1)
#else
#define D if(0)
#endif
#include <fcntl.h>
#include <poll.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/time.h>
#include "bcm_host.h"
#include "ilclient.h"
OMX_VIDEO_PARAM_PORTFORMATTYPE format;
OMX_TIME_CONFIG_CLOCKSTATETYPE cstate;
COMPONENT_T *video_decode = NULL, *video_scheduler = NULL, *video_render = NULL,
*video_clock = NULL;
COMPONENT_T *list[5];
TUNNEL_T tunnel[4];
ILCLIENT_T *client;
OMX_BUFFERHEADERTYPE *buf;
FILE* in;
FILE* fifo;
FILE* state;
int status = 0, running = 1, playing = 0, finished = 0, first_packet = 1;
unsigned int data_len = 0, video_size = 0;
int o_loop = 0, o_reverse = 0, o_hold = 0;
char* cmd = "";
char* current_filename = "";
char* state_filename = "";
int init() {
bcm_host_init();
memset(list, 0, sizeof(list));
memset(tunnel, 0, sizeof(tunnel));
if((client = ilclient_init()) == NULL) {
return -3;
}
if(OMX_Init() != OMX_ErrorNone) {
return -4;
}
if(ilclient_create_component(client, &video_decode, "video_decode",
ILCLIENT_DISABLE_ALL_PORTS |
ILCLIENT_ENABLE_INPUT_BUFFERS) != 0) {
return -14;
}
list[0] = video_decode;
if(ilclient_create_component(client, &video_render, "video_render",
ILCLIENT_DISABLE_ALL_PORTS) != 0) {
return -14;
}
list[1] = video_render;
if(ilclient_create_component(client, &video_clock, "clock",
ILCLIENT_DISABLE_ALL_PORTS) != 0) {
return -14;
}
list[2] = video_clock;
memset(&cstate, 0, sizeof(cstate));
cstate.nSize = sizeof(cstate);
cstate.nVersion.nVersion = OMX_VERSION;
cstate.eState = OMX_TIME_ClockStateWaitingForStartTime;
cstate.nWaitMask = 1;
if(video_clock != NULL && OMX_SetParameter(ILC_GET_HANDLE(video_clock),
OMX_IndexConfigTimeClockState,
&cstate) != 0) {
return -13;
}
if(ilclient_create_component(client, &video_scheduler, "video_scheduler",
ILCLIENT_DISABLE_ALL_PORTS) != 0) {
return -14;
}
list[3] = video_scheduler;
set_tunnel(tunnel, video_decode, 131, video_scheduler, 10);
set_tunnel(tunnel + 1, video_scheduler, 11, video_render, 90);
set_tunnel(tunnel + 2, video_clock, 80, video_scheduler, 12);
if(ilclient_setup_tunnel(tunnel + 2, 0, 0) != 0) {
return -15;
}
ilclient_change_component_state(video_clock, OMX_StateExecuting);
ilclient_change_component_state(video_decode, OMX_StateIdle);
memset(&format, 0, sizeof(OMX_VIDEO_PARAM_PORTFORMATTYPE));
format.nSize = sizeof(OMX_VIDEO_PARAM_PORTFORMATTYPE);
format.nVersion.nVersion = OMX_VERSION;
format.nPortIndex = 130;
format.eCompressionFormat = OMX_VIDEO_CodingAVC;
if(OMX_SetParameter(ILC_GET_HANDLE(video_decode),
OMX_IndexParamVideoPortFormat, &format) != OMX_ErrorNone ||
ilclient_enable_port_buffers(video_decode, 130, NULL, NULL, NULL) != 0) {
return -16;
}
ilclient_change_component_state(video_decode, OMX_StateExecuting);
buf = ilclient_get_input_buffer(video_decode, 130, 1);
D printf("initialized\n");
return 0;
}
FILE* make_fifo(char* name) {
mkfifo(name, 0666);
FILE* fp = fopen(name, "r+");
int fd = fileno(fp);
int flags = fcntl(fd, F_GETFL);
fcntl(fd, F_SETFL, flags | O_NONBLOCK);
return fp;
}
void stop_video() {
buf->nFlags = OMX_BUFFERFLAG_EOS;
ilclient_change_component_state(video_render, OMX_StatePause);
ilclient_change_component_state(video_scheduler, OMX_StatePause);
ilclient_change_component_state(video_clock, OMX_StateIdle);
//ilclient_change_component_state(video_clock, OMX_TIME_ClockStateWaitingForStartTime);
}
void start_video() {
// Reset clock
/*memset(&cstate, 0, sizeof(cstate));
cstate.nSize = sizeof(cstate);
cstate.nVersion.nVersion = OMX_VERSION;
cstate.eState = OMX_TIME_ClockStateWaitingForStartTime;
cstate.nWaitMask = 1;
OMX_TIME_CONFIG_TIMESTAMPTYPE ctime;
OMX_GetParameter(ILC_GET_HANDLE(video_clock),
OMX_IndexConfigTimeCurrentWallTime,
&ctime);
cstate.nStartTime = ctime.nTimestamp;
if(video_clock != NULL) {
OMX_SetParameter(ILC_GET_HANDLE(video_clock),
OMX_IndexConfigTimeClockState,
&cstate);
}*/
ilclient_change_component_state(video_render, OMX_StateExecuting);
ilclient_change_component_state(video_scheduler, OMX_StateExecuting);
ilclient_change_component_state(video_clock, OMX_StateExecuting);
first_packet = 1;
}
void open_video(char* name) {
D printf("Opening %s\n", name);
stop_video();
OMX_SendCommand(ILC_GET_HANDLE(video_decode), OMX_CommandFlush, -1, NULL);
ilclient_wait_for_event(video_decode, ILCLIENT_PORT_FLUSH,
131, 0, 0, 1, 0, 100);
D printf("Finished waiting for decode buffer to flush\n");
buf->nFlags = OMX_BUFFERFLAG_STARTTIME;
buf->nTimeStamp = omx_ticks_from_s64(0);
if(in != NULL) {
fclose(in);
}
in = fopen(name, "rb");
fseek(in, 0, SEEK_END);
video_size = ftell(in);
if(o_reverse == 1) {
// ...
} else {
rewind(in);
}
first_packet = 1;
}
void parse_cmd() {
strtok(cmd, "\n");
char filename[1024] = "";
int is_filename = 0;
int i = 0, x = 0;
for(i = 0; i < strlen(cmd); i++) {
if(is_filename == 1) {
if(cmd[i] == ';' || cmd[i] == ' ' || cmd[i] == NULL) {
open_video(filename);
current_filename = filename;
is_filename = 0;
} else {
filename[x] = cmd[i];
x++;
}
} else {
switch(cmd[i]) {
case 'o':
is_filename = 1;
i++;
break;
case ';':
is_filename = 0;
break;
case ' ':
break;
case 'q':
running = 0;
break;
/*case 'r': // reverse is broken
o_reverse = 1;
break;*/
case 'f':
o_reverse = 0;
break;
case 'h':
o_hold = 1;
o_loop = 0;
break;
case 'e':
o_hold = 0;
o_loop = 0;
break;
case 'l':
o_hold = 0;
o_loop = 1;
break;
case 'p':
playing = 1;
start_video();
break;
case 's':
playing = 0;
stop_video();
break;
case '?':
break;
default:
printf("Undefined command: %c\n", cmd[i]);
break;
}
}
}
printf("[file = %s, playing = %d, reverse = %d, hold = %d, loop = %d]\n",
filename, playing, o_reverse, o_hold, o_loop);
}
int main(int argc, char **argv) {
if(argc < 2) {
printf("Usage: %s <FIFO path> <State file path>\n", argv[0]);
exit(1);
}
int init_state = init();
D printf("init state = %d\n", init_state);
fifo = make_fifo(argv[1]);
state_filename = argv[2];
cmd = (char*) malloc(sizeof(char) * 1024);
int port_settings_changed = 0;
while(running == 1) {
int fifo_state = fread(cmd, sizeof(char), 1024, fifo);
if(fifo_state > 0) {
parse_cmd();
}
buf = ilclient_get_input_buffer(video_decode, 130, 1);
if(in != NULL && playing == 1) {
//buf = ilclient_get_input_buffer(video_decode, 130, 1);
unsigned char *dest = buf->pBuffer;
data_len += fread(dest, 1, buf->nAllocLen - data_len, in);
//data_len += fread(dest, sizeof(char), BUFFER_BYTES, in);
if(port_settings_changed == 0 &&
((data_len > 0 && ilclient_remove_event(video_decode,
OMX_EventPortSettingsChanged,
131, 0, 0, 1) == 0) ||
(data_len == 0 && ilclient_wait_for_event(video_decode,
OMX_EventPortSettingsChanged,
131, 0, 0, 1,
ILCLIENT_EVENT_ERROR |
ILCLIENT_PARAMETER_CHANGED,
SLEEP_LENGTH) == 0))) {
port_settings_changed = 1;
if(ilclient_setup_tunnel(tunnel, 0, 0) != 0) {
return 1;
break;
}
ilclient_change_component_state(video_scheduler, OMX_StateExecuting);
if(ilclient_setup_tunnel(tunnel + 1, 0, 100) != 0) {
return 1;
}
ilclient_change_component_state(video_render, OMX_StateExecuting);
}
if(!data_len) {
if(o_hold == 1) {
finished = 1;
} else if(o_loop == 1) {
if(o_reverse) {
fseek(in, -(BUFFER_BYTES * 2), SEEK_END);
buf->nFlags = OMX_BUFFERFLAG_STARTTIME;
} else {
rewind(in);
first_packet = 1;
}
}
}
buf->nFilledLen = data_len;
data_len = 0;
buf->nOffset = 0;
if(first_packet) {
buf->nFlags = OMX_BUFFERFLAG_STARTTIME;
buf->nTimeStamp = omx_ticks_from_s64(0);
first_packet = 0;
} else {
buf->nFlags = OMX_BUFFERFLAG_TIME_UNKNOWN;
}
buf->nTimeStamp = omx_ticks_from_s64(0);
//buf->nFlags = OMX_BUFFERFLAG_TIME_UNKNOWN;
/*if(OMX_EmptyThisBuffer(ILC_GET_HANDLE(video_decode), buf) != OMX_ErrorNone) {
return 1;
}*/
OMX_EmptyThisBuffer(ILC_GET_HANDLE(video_decode), buf);
if(finished == 1) {
playing = 0;
finished = 0;
ilclient_wait_for_event(video_decode, OMX_EventBufferFlag, 131, 0,
OMX_BUFFERFLAG_EOS, 0, ILCLIENT_BUFFER_FLAG_EOS,
0);
ilclient_wait_for_event(video_render, OMX_EventBufferFlag, 90, 0,
OMX_BUFFERFLAG_EOS, 0, ILCLIENT_BUFFER_FLAG_EOS,
0);
usleep(1000000);
// OMX_EmptyThisBuffer(ILC_GET_HANDLE(video_decode), buf);
FILE* state_file = fopen(state_filename, "w+");
fprintf(state_file, "%s\n", current_filename);
fclose(state_file);
stop_video();
}
} else {
D printf("Waiting for input\r");
usleep(100000);
}
OMX_EmptyThisBuffer(ILC_GET_HANDLE(video_decode), buf);
}
D printf("Left loop\n");
/*ilclient_wait_for_event(video_render, OMX_EventBufferFlag, 90, 0,
OMX_BUFFERFLAG_EOS, 0, ILCLIENT_BUFFER_FLAG_EOS,
SLEEP_LENGTH);*/
D printf("Flushing tunnels\n");
ilclient_flush_tunnels(tunnel, 0);
//D printf("Disabling decode port buffer\n");
//ilclient_disable_port_buffers(video_decode, 130, NULL, NULL, NULL);
fclose(fifo);
fclose(in);
D printf("Disabling tunnels\n");
ilclient_disable_tunnel(tunnel);
ilclient_disable_tunnel(tunnel+1);
ilclient_disable_tunnel(tunnel+2);
D printf("Teardown\n");
//ilclient_teardown_tunnels(tunnel);
//ilclient_state_transition(list, OMX_StateIdle);
//ilclient_state_transition(list, OMX_StateLoaded);
D printf("Cleanup\n");
ilclient_cleanup_components(list);
D printf("Destroying\n");
OMX_Deinit();
ilclient_destroy(client);
D printf("Quitting\n");
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.