* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include "omnplay.h"
#include "ui.h"
#include "opts.h"
+#include "timecode.h"
#include "omplrclnt.h"
-static char* frames2tc( int f, float fps, char* buf )
-{
- int tc[4] = { 0, 0, 0, 0 };
- float d;
- int t;
-
- if ( fps && f >= 0)
- {
- d = f / fps;
- t = d;
-
- tc[0] = (d - t) * fps;
- tc[1] = t % 60; t /= 60;
- tc[2] = t % 60; t /= 60;
- tc[3] = t % 24;
- }
-
- sprintf(buf, "%.2d:%.2d:%.2d:%.2d", tc[3], tc[2], tc[1], tc[0]);
-
- return buf;
-}
-
-
static gboolean on_main_window_delete_event( GtkWidget *widget, GdkEvent *event, gpointer user_data )
{
gtk_exit(0);
free(app);
};
+static int find_index_of_playlist_item(omnplay_instance_t* app, int start, int idx)
+{
+ while(1)
+ {
+ if(app->playlist.item[start].omn_idx == idx)
+ return start;
+
+ if(app->playlist.item[start].type & OMNPLAY_PLAYLIST_BLOCK_END)
+ break;
+
+ start++;
+ };
+
+ return -1;
+};
+
static void omnplay_update_status(omnplay_player_t* player, OmPlrStatus *prev , OmPlrStatus *curr)
{
+ int idx;
char tc_cur[32], tc_rem[32], state[32], status[32];
const char *clip;
strcpy(status, "OFFLINE");
};
+ /* update status in status page */
gdk_threads_enter();
gtk_label_set_text(GTK_LABEL (player->label_tc_cur), tc_cur);
gtk_label_set_text(GTK_LABEL (player->label_tc_rem), tc_rem);
gdk_flush();
gdk_threads_leave();
+ /* update remaining time */
+ gdk_threads_enter();
+ pthread_mutex_lock(&player->app->playlist.lock);
+ pthread_mutex_lock(&player->app->players.lock);
+ if(curr->state == omPlrStatePlay || curr->state == omPlrStateCuePlay)
+ {
+ idx = find_index_of_playlist_item(player->app, player->playlist_start, curr->currClipNum);
+ if(idx >= 0)
+ {
+ frames2tc(curr->currClipStartPos + curr->currClipLen - curr->pos, 25.0, tc_rem);
+ omnplay_playlist_draw_item_rem(player->app, idx, tc_rem);
+ }
+ if(curr->currClipNum != prev->currClipNum && 1 != prev->numClips)
+ {
+ tc_rem[0] = 0;
+ idx = find_index_of_playlist_item(player->app, player->playlist_start, prev->currClipNum);
+ if(idx >= 0)
+ omnplay_playlist_draw_item_rem(player->app, idx, tc_rem);
+ };
+ }
+ else
+ {
+ tc_rem[0] = 0;
+ idx = find_index_of_playlist_item(player->app, player->playlist_start, curr->currClipNum);
+ if(idx >= 0)
+ omnplay_playlist_draw_item_rem(player->app, idx, tc_rem);
+ idx = find_index_of_playlist_item(player->app, player->playlist_start, prev->currClipNum);
+ if(idx >= 0)
+ omnplay_playlist_draw_item_rem(player->app, idx, tc_rem);
+ };
+ pthread_mutex_unlock(&player->app->players.lock);
+ pthread_mutex_unlock(&player->app->playlist.lock);
+ gdk_flush();
+ gdk_threads_leave();
+
+
memcpy(prev, curr, sizeof(OmPlrStatus));
};
omnplay_player_t* player = (omnplay_player_t*)data;
/* connect */
- pthread_mutex_lock(&player->lock);
+ pthread_mutex_lock(&player->app->players.lock);
r = OmPlrOpen(player->host, player->name, (OmPlrHandle*)&player->handle);
- pthread_mutex_unlock(&player->lock);
+ pthread_mutex_unlock(&player->app->players.lock);
if(r)
{
fprintf(stderr, "ERROR: OmPlrOpen(%s, %s) failed with 0x%.8X\n",
};
/* setup to do not reconnect */
- pthread_mutex_lock(&player->lock);
+ pthread_mutex_lock(&player->app->players.lock);
OmPlrSetRetryOpen((OmPlrHandle)player->handle, 0);
- pthread_mutex_unlock(&player->lock);
+ pthread_mutex_unlock(&player->app->players.lock);
/* setup directory */
if(player->app->players.path[0])
{
- pthread_mutex_lock(&player->lock);
-// r = OmPlrClipSetDirectory((OmPlrHandle)player->handle, player->app->players.path);
- pthread_mutex_unlock(&player->lock);
+ pthread_mutex_lock(&player->app->players.lock);
+ r = OmPlrClipSetDirectory((OmPlrHandle)player->handle, player->app->players.path);
+ pthread_mutex_unlock(&player->app->players.lock);
if(r)
{
fprintf(stderr, "ERROR: OmPlrClipSetDirectory(%s) failed with 0x%.8X\n",
player->app->players.path, r);
- pthread_mutex_lock(&player->lock);
+ pthread_mutex_lock(&player->app->players.lock);
OmPlrClose((OmPlrHandle)player->handle);
- pthread_mutex_unlock(&player->lock);
+ pthread_mutex_unlock(&player->app->players.lock);
return (void*)r;
};
usleep(100000);
/* get status */
- pthread_mutex_lock(&player->lock);
+ pthread_mutex_lock(&player->app->players.lock);
st_curr.size = sizeof(OmPlrStatus);
r = OmPlrGetPlayerStatus((OmPlrHandle)player->handle, &st_curr);
- pthread_mutex_unlock(&player->lock);
+ pthread_mutex_unlock(&player->app->players.lock);
if(r)
fprintf(stderr, "ERROR: OmPlrGetPlayerStatus failed with 0x%.8X\n", r);
omnplay_update_status(player, &st_prev , &st_curr);
};
- pthread_mutex_lock(&player->lock);
+ pthread_mutex_lock(&player->app->players.lock);
OmPlrClose((OmPlrHandle)player->handle);
- pthread_mutex_unlock(&player->lock);
+ pthread_mutex_unlock(&player->app->players.lock);
+
+ return NULL;
+};
+
+void get_selected_items_playlist_proc(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
+{
+ int idx, *list = (int*)data;
+ gtk_tree_model_get(model, iter, 7, &idx, -1);
+ list[list[0] + 1] = idx;
+ list[0] = list[0] + 1;
+};
+
+static int* get_selected_items_playlist(omnplay_instance_t* app)
+{
+ int* list = NULL;
+ GtkTreeSelection *selection;
+
+ selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(app->playlist_grid));
+ if(selection)
+ {
+ list = (int*)malloc(sizeof(int) * (MAX_PLAYLIST_ITEMS + 1));
+ memset(list, 0, sizeof(int) * (MAX_PLAYLIST_ITEMS + 1));
+
+ gtk_tree_selection_selected_foreach(
+ selection,
+ get_selected_items_playlist_proc,
+ list);
+
+ if(!list[0])
+ {
+ free(list);
+ list = NULL;
+ };
+ };
+
+ return list;
+};
+
+static int get_first_selected_item_playlist(omnplay_instance_t* app)
+{
+ int idx;
+ int* list = get_selected_items_playlist(app);
+ if(!list) return -1;
+ idx = list[1];
+ free(list);
+ return idx;
+};
+
+static int get_playlist_block(omnplay_instance_t* app, int idx, int* start_ptr, int* stop_ptr)
+{
+ int start, stop;
+
+ for(start = idx; start >= 0; start--)
+ if(app->playlist.item[start].type & OMNPLAY_PLAYLIST_BLOCK_BEGIN)
+ break;
+
+ for(stop = idx; stop < app->playlist.count; stop++)
+ if(app->playlist.item[stop].type & OMNPLAY_PLAYLIST_BLOCK_END)
+ break;
+
+ fprintf(stderr, "get_playlist_block: range %d -> %d\n", start, stop);
+
+ /* check block range */
+ if(start >= 0 && stop < app->playlist.count)
+ {
+ *start_ptr = start;
+ *stop_ptr = stop;
+ return (stop - start + 1);
+ };
+
+ return -1;
+};
+
+static omnplay_player_t *get_player_at_pos(omnplay_instance_t* app, int pos)
+{
+ /* check player range */
+ if(app->playlist.item[pos].player > -1 && app->playlist.item[pos].player < app->players.count)
+ return &app->players.item[app->playlist.item[pos].player];
return NULL;
};
+static void omnplay_ctl(omnplay_instance_t* app, control_buttons_t button)
+{
+ int i, r;
+ int idx, start, stop;
+ omnplay_player_t *player;
+
+ pthread_mutex_lock(&app->playlist.lock);
+
+ idx = get_first_selected_item_playlist(app);
+
+ if(idx < 0)
+ {
+ pthread_mutex_unlock(&app->playlist.lock);
+ return;
+ };
+
+ fprintf(stderr, "cue: selected item is %d\n", idx);
+
+ if(get_playlist_block(app, idx, &start, &stop) < 0)
+ {
+ pthread_mutex_unlock(&app->playlist.lock);
+ return;
+ };
+
+ fprintf(stderr, "cue: range %d -> %d\n", start, stop);
+
+ player = get_player_at_pos(app, start);
+
+ if(!player)
+ {
+ pthread_mutex_unlock(&app->playlist.lock);
+ return;
+ };
+
+ pthread_mutex_lock(&app->players.lock);
+
+ if(BUTTON_PLAYER_STOP == button || BUTTON_PLAYER_CUE == button)
+ {
+ /* stop */
+ OmPlrStop((OmPlrHandle)player->handle);
+
+ /* detach previous clips */
+// player->playlist_start = -1;
+// player->playlist_count = -1;
+ OmPlrDetachAllClips((OmPlrHandle)player->handle);
+ };
+
+ if(BUTTON_PLAYER_CUE == button)
+ {
+ int o, c, p = 0;
+
+ /* Attach clips to timeline */
+ for(i = start, c = 0, o = 0; i <= stop; i++)
+ {
+ OmPlrClipInfo clip;
+
+ /* get clip info */
+ clip.maxMsTracks = 0;
+ clip.size = sizeof(clip);
+ r = OmPlrClipGetInfo((OmPlrHandle)player->handle, app->playlist.item[i].id, &clip);
+
+ if(!r)
+ {
+ unsigned int l;
+
+ fprintf(stderr, "OmPlrClipGetInfo(%s): firstFrame=%d, lastFrame=%d\n",
+ app->playlist.item[i].id, clip.firstFrame, clip.lastFrame);
+
+ /* should we fix playlist clip timings */
+ if(!(
+ app->playlist.item[i].in >= clip.firstFrame &&
+ app->playlist.item[i].in + app->playlist.item[i].dur <= clip.lastFrame) ||
+ !app->playlist.item[i].dur)
+ {
+ fprintf(stderr, "cue: item [%s] will be updated [%d;%d]->[%d;%d]\n",
+ app->playlist.item[i].id,
+ app->playlist.item[i].in, app->playlist.item[i].dur,
+ clip.firstFrame, clip.lastFrame - clip.firstFrame);
+
+ app->playlist.item[i].in = clip.firstFrame;
+ app->playlist.item[i].dur = clip.lastFrame - clip.firstFrame;
+ omnplay_playlist_draw_item(app, i);
+ };
+
+ r = OmPlrAttach((OmPlrHandle)player->handle,
+ app->playlist.item[i].id,
+ app->playlist.item[i].in,
+ app->playlist.item[i].in + app->playlist.item[i].dur,
+ 0, omPlrShiftModeAfter, &l);
+ };
+
+ if(r)
+ {
+ fprintf(stderr, "cue: failed with %d, %s\n", r, OmPlrGetErrorString((OmPlrError)r));
+ app->playlist.item[i].omn_idx = -1;
+ app->playlist.item[i].omn_offset = -1;
+ }
+ else
+ {
+ app->playlist.item[i].omn_idx = c;
+ app->playlist.item[i].omn_offset = o;
+
+ /* save selected item offset */
+ if(i == idx) p = o;
+
+ c++;
+ o += app->playlist.item[i].dur;
+ };
+ };
+
+ if(c)
+ {
+ OmPlrStatus hs;
+
+ /* Set timeline min/max */
+ OmPlrSetMinPosMin((OmPlrHandle)player->handle);
+ OmPlrSetMaxPosMax((OmPlrHandle)player->handle);
+
+ /* Set timeline position */
+ hs.minPos = 0;
+ hs.size = sizeof(OmPlrStatus);
+ OmPlrGetPlayerStatus((OmPlrHandle)player->handle, &hs);
+ OmPlrSetPos((OmPlrHandle)player->handle, hs.minPos + p);
+
+ /* setup loop */
+ if(app->playlist.item[start].type & OMNPLAY_PLAYLIST_BLOCK_LOOP)
+ OmPlrLoop((OmPlrHandle)player->handle, hs.minPos, hs.maxPos);
+
+ player->playlist_start = start;
+
+ /* Cue */
+ OmPlrCuePlay((OmPlrHandle)player->handle, 0.0);
+ OmPlrPlay((OmPlrHandle)player->handle, 0.0);
+ };
+ };
+
+ if(BUTTON_PLAYER_PLAY == button)
+ {
+ /* play */
+ OmPlrPlay((OmPlrHandle)player->handle, 1.0);
+ };
+
+ if(BUTTON_PLAYER_PAUSE == button)
+ /* pause */
+ OmPlrPlay((OmPlrHandle)player->handle, 0.0);
+
+ pthread_mutex_unlock(&app->players.lock);
+
+ pthread_mutex_unlock(&app->playlist.lock);
+};
+
static gboolean omnplay_button_click(omnplay_instance_t* app, control_buttons_t button)
{
switch(button)
case BUTTON_PLAYLIST_ITEM_ADD:
case BUTTON_PLAYLIST_ITEM_DEL:
case BUTTON_PLAYLIST_ITEM_EDIT:
+ break;
case BUTTON_PLAYLIST_LOAD:
omnplay_playlist_load(app);
break;
break;
case BUTTON_PLAYLIST_BLOCK_SINGLE:
case BUTTON_PLAYLIST_BLOCK_LOOP:
+ break;
case BUTTON_PLAYLIST_ITEM_UP:
case BUTTON_PLAYLIST_ITEM_DOWN:
+ break;
case BUTTON_PLAYER_CUE:
case BUTTON_PLAYER_PLAY:
case BUTTON_PLAYER_PAUSE:
case BUTTON_PLAYER_STOP:
+ omnplay_ctl(app, button);
+ break;
case BUTTON_LIBRARY_ADD:
case BUTTON_LIBRARY_REFRESH:
break;
void omnplay_init(omnplay_instance_t* app)
{
int i;
+ pthread_mutexattr_t attr;
+
+ pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
gtk_signal_connect( GTK_OBJECT( app->window ), "destroy",
GTK_SIGNAL_FUNC(on_main_window_delete_event), app);
- for(i = 0; i < app->players.count; i++)
- {
- /* create lock */
- pthread_mutex_init(&app->players.item[i].lock, NULL);
+ /* create lock */
+ pthread_mutex_init(&app->players.lock, &attr);
- /* create a omneon status thread */
+ /* create a omneon status thread */
+ for(i = 0; i < app->players.count; i++)
pthread_create(&app->players.item[i].thread, NULL,
omnplay_thread_proc, &app->players.item[i]);
- };
/* create lock */
- pthread_mutex_init(&app->playlist.lock, NULL);
+ pthread_mutex_init(&app->playlist.lock, &attr);
/* attach buttons click */
for(i = 1; i < BUTTON_LAST; i++)
app->f_exit = 1;
for(i = 0; i < app->players.count; i++)
- {
/* create a omneon status thread */
pthread_join(app->players.item[i].thread, &r);
- /* create lock */
- pthread_mutex_destroy(&app->players.item[i].lock);
+ /* destroy lock */
+ pthread_mutex_destroy(&app->players.lock);
- };
-
- /* create lock */
+ /* destroy lock */
pthread_mutex_destroy(&app->playlist.lock);
};