Last active
August 29, 2015 14:02
-
-
Save erinaceous/9ff14df424761073223b to your computer and use it in GitHub Desktop.
This file contains 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
// 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