home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Chip 2005 June
/
ccd0605.iso
/
LINUX
/
gopchop-1.1.7.tar.tar
/
gopchop-1.1.7.tar
/
gopchop-1.1.7
/
src
/
Main.cpp
< prev
next >
Wrap
C/C++ Source or Header
|
2005-05-01
|
29KB
|
1,016 lines
/*
#
# Main interface tool for GOPchop. Implements multiple utility functions.
#
# $Id: Main.cpp,v 1.66 2005/05/01 17:59:23 keescook Exp $
#
# Copyright (C) 2001-2003 Kees Cook
# kees@outflux.net, http://outflux.net/
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
# http://www.gnu.org/copyleft/gpl.html
#
*/
/*
* Initial main.c file generated by Glade. Edit as required.
* Glade will not overwrite this file.
*/
#include "GOPchop.h"
#include <stdio.h>
#include <inttypes.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/uio.h>
#include <string.h>
#include <errno.h>
#include <time.h>
#ifdef ENABLE_NLS
# include <locale.h>
#endif
#include "Vector.h"
#include "List.h"
#include "ElementStream.h"
#include "Pack.h"
#include "GroupOfPictures.h"
#include "Picture.h"
#include "MPEG2Parser.h"
#include "mpeg2consts.h"
#include "widgets.h"
#include "FirstPack.h"
#include "GOPutils.h"
#ifdef __cplusplus
extern "C" {
#endif
/* libmpeg2 */
#include "video_out.h"
#include <mpeg2dec/mpeg2.h>
#ifdef __cplusplus
}
#endif
#include <gtk/gtk.h>
#include <gdk/gdkx.h>
#include <X11/Xlib.h>
#include <math.h>
#include "main.h"
#include "display.h"
#include <getopt.h>
/* */
/* globals for everyone to beat on */
/* */
// strings
char *GOPchop_cvsid = "$Id: Main.cpp,v 1.66 2005/05/01 17:59:23 keescook Exp $";
// objects
MPEG2Parser *mpeg2parser;
// command line options
char * opt_videoout = NULL; // default to the first libvo driver
char * opt_pipe = NULL; // default to no command
int opt_show_states = 0; // default to not reporting libmpeg2 states
// decode variables
int desired_output = GOPCHOP_OUTPUT_LIBVO;
/*
static mpeg2dec_t *mpeg2dec = NULL;
static vo_open_t *output_open = NULL;
static vo_instance_t *output = NULL;
*/
struct display_engine_t * engine = NULL;
// mark settings
gint main_clist_count = 0;
uint32_t mark_start = 0;
uint32_t mark_end = 0;
// pipe variables
int pipes[2];
int *client_pipe = NULL;
/* global preferences */
/*
* add new options below.
* If you want it saved to the rc file, add it to the "parsable_items" list.
* Update the "handle_rc" function below for rc options.
* Update the menu activation handler to auto-save the rc file.
*/
global_options options={
run_loop: 0, /* don't wrap arround by default */
run_speed: 1, /* one frame at a time by default */
default_run_speed: 1, /* one frame at a time by default */
auto_refresh: 1, /* show gop position changes by default */
ignore_errors: 0, /* don't ignore errors by default */
drop_orphaned_frames: 0, /* orphaned frame dropping can be nasty */
adjust_timestamps: 1, /* adjust by default */
video_driver_ptr: NULL, /* prefered video driver */
video_driver: "\0",
force_system_header: 0, /* force prepended system header pack */
drop_trailing_pack_with_system_header: 0, /* drop final pack if it has a system header */
ignore_endcode: 0, /* don't stop parsing when an End Code is seen */
};
rc_parse_item parsable_items[] = {
{ "run_loop", &options.run_loop, RC_TYPE_BOOLEAN },
{ "default_run_speed", &options.default_run_speed, RC_TYPE_INTEGER },
{ "auto_refresh", &options.auto_refresh, RC_TYPE_BOOLEAN },
{ "ignore_errors", &options.ignore_errors, RC_TYPE_BOOLEAN },
{ "drop_orphaned_frames", &options.drop_orphaned_frames, RC_TYPE_BOOLEAN },
{ "adjust_timestamps", &options.adjust_timestamps, RC_TYPE_BOOLEAN },
{ "video_driver_ptr", &options.video_driver_ptr, RC_TYPE_STRING },
{ "force_system_header", &options.force_system_header, RC_TYPE_BOOLEAN },
{ "drop_trailing_pack_with_system_header", &options.drop_trailing_pack_with_system_header, RC_TYPE_BOOLEAN },
{ "ignore_endcode", &options.ignore_endcode, RC_TYPE_BOOLEAN },
{ NULL, NULL, 0 }
};
///// My various supporting functions
void flush()
{
while (g_main_iteration(FALSE));
/*
while(gtk_events_pending())
gtk_main_iteration();
*/
}
void status_on(const gchar * owner, char *text)
{
guint context;
context = gtk_statusbar_get_context_id(GTK_STATUSBAR(main_statusbar),
owner);
gtk_statusbar_push(GTK_STATUSBAR(main_statusbar), context, text);
flush();
}
void status_off(const gchar * owner)
{
guint context;
context = gtk_statusbar_get_context_id(GTK_STATUSBAR(main_statusbar),
owner);
gtk_statusbar_pop(GTK_STATUSBAR(main_statusbar), context);
flush();
//gtk_main_iteration_do(0);
}
const gchar *fileops = "fileops";
void progress(char *task, float done)
{
static gchar *lasttask = NULL;
static float lastdone = 0.0;
float diff;
int tasksdiffer;
gint context;
context = gtk_statusbar_get_context_id(GTK_STATUSBAR(main_statusbar),
fileops);
if (lasttask)
{
tasksdiffer = strcmp(lasttask, task);
}
else
{
tasksdiffer = 1;
}
if (tasksdiffer)
{
if (lasttask)
gtk_statusbar_pop(GTK_STATUSBAR(main_statusbar), context);
lasttask = (char *) g_realloc(lasttask, strlen(task) + 1);
strcpy(lasttask, task);
gtk_statusbar_push(GTK_STATUSBAR(main_statusbar), context, lasttask);
flush();
}
diff = fabs(done - lastdone);
if (!tasksdiffer && diff < 0.01)
return;
lastdone = done;
gtk_progress_set_percentage(GTK_PROGRESS(main_progressbar), lastdone);
/* sending to stderr instead...
if (mpeg2parser->getError())
show_error(mpeg2parser->getError());
*/
flush();
}
void show_error(const gchar *text)
{
GtkTextIter iter;
GtkTextBuffer *buffer;
buffer=gtk_text_view_get_buffer(GTK_TEXT_VIEW(error_text_why));
gtk_text_buffer_get_end_iter(GTK_TEXT_BUFFER(buffer),&iter);
gtk_text_iter_forward_to_end(&iter);
gtk_text_buffer_insert(buffer,&iter,text,-1);
}
void get_clips_from_list(GtkTreeModel *model,
GtkTreeIter *iter,
struct clip_list_t * clips)
{
GValue list_GOP_first;
GValue list_GOP_last;
if (!model || !iter || !clips) return;
memset(&list_GOP_first,0,sizeof(list_GOP_first));
memset(&list_GOP_last, 0,sizeof(list_GOP_last));
gtk_tree_model_get_value(GTK_TREE_MODEL(model), iter,
ITEM_GOP_FIRST, &list_GOP_first);
gtk_tree_model_get_value(GTK_TREE_MODEL(model), iter,
ITEM_GOP_LAST, &list_GOP_last);
clips->GOP_first = g_value_get_uint(&list_GOP_first);
clips->GOP_last = g_value_get_uint(&list_GOP_last);
g_value_unset(&list_GOP_first);
g_value_unset(&list_GOP_last);
}
/* "foreach" functions used to walk the main_clist */
gboolean foreach_count_GOPs(GtkTreeModel *model,
GtkTreePath *path,
GtkTreeIter *iter,
gpointer data)
{
uint32_t * count = (uint32_t *)data;
struct clip_list_t clips;
if (!count) return TRUE;
get_clips_from_list(model,iter,&clips);
*count += clips.GOP_last - clips.GOP_first + 1;
return FALSE; /* keep traversing */
}
gboolean foreach_save_clips_to_file(GtkTreeModel *model,
GtkTreePath *path,
GtkTreeIter *iter,
gpointer data)
{
struct clip_list_t clips;
uint32_t i;
struct save_clip_info_t * clip_info = (struct save_clip_info_t*)data;
if (!clip_info) return TRUE; /* abort */
get_clips_from_list(model,iter,&clips);
for (i = clips.GOP_first; i <= clips.GOP_last; i++) {
progress(clip_info->progress_task,
(float)( (float) clip_info->count++ /
(float) clip_info->total ) );
clip_info->written_bytes +=
write_GOP(clip_info->file, mpeg2parser, i,
((clip_info->GOP_previous + 1) == i),
options.drop_orphaned_frames,
options.adjust_timestamps,
&clip_info->written_pictures,
//TI!
(clip_info->total - clip_info->count)==0,
options.drop_trailing_pack_with_system_header);
clip_info->GOP_previous = i;
}
return FALSE; /* keep on steppin */
}
void save_file(char *filename)
{
char buf[1024];
FILE *mpeg2;
struct save_clip_info_t clip_info;
clip_info.progress_task = _("Saving MPEG2");
if (!(mpeg2 = fopen(filename, "w")))
{
snprintf(buf, 1024, "%s: %s\n", filename, strerror(errno));
show_error(buf);
}
else
{
time_t begin, finish;
char report[REPORT_LENGTH];
time(&begin);
clip_info.total=0;
/* count up how many GOPs there are to write */
gtk_tree_model_foreach(GTK_TREE_MODEL(main_list_store),
foreach_count_GOPs,
&clip_info.total);
clip_info.file=mpeg2;
clip_info.count=0;
clip_info.written_pictures=0;
clip_info.written_bytes=0;
// make sure the first GOP is closed
clip_info.GOP_previous = (uint32_t) -2;
//TI! save first dummy pack with valid system header
if (options.force_system_header)
{
clip_info.written_bytes+=(mpeg2parser->getFirstPack())->saveFirstPack(mpeg2);
}
/* save each clip in the list */
gtk_tree_model_foreach(GTK_TREE_MODEL(main_list_store),
foreach_save_clips_to_file,
&clip_info);
progress(clip_info.progress_task, 1.0);
status_off(fileops);
// write an end-of-PS marker
fwrite(eos_buf, sizeof(eos_buf), 1, mpeg2);
fclose(mpeg2);
time(&finish);
finish -= begin;
clip_info.written_bytes /= 1048576;
if (finish > 0)
clip_info.written_bytes /= finish;
if (clip_info.written_bytes == 0)
clip_info.written_bytes = 1;
// FIXME: bad pluralization
snprintf(report,REPORT_LENGTH,finish == 1
? _("Wrote %s (GOPs: %u, pictures: %u) in %d second (%%%sMB/s)\n")
: _("Wrote %s (GOPs: %u, pictures: %u) in %d seconds (%%%sMB/s)\n"),
filename, clip_info.total, clip_info.written_pictures, finish, OFF_T_FORMAT);
fprintf(stderr, report, clip_info.written_bytes);
}
}
void open_file(char *filename)
{
time_t begin, finish;
char buf[128];
off_t speed;
char report[REPORT_LENGTH];
char * gop_cache_filename;
time(&begin);
if (!mpeg2parser->init(filename, progress))
{
show_error(mpeg2parser->getError());
}
else
{
mpeg2parser->parse(options.ignore_errors);
if (mpeg2parser->getError())
show_error(mpeg2parser->getError());
// make sure we actually HAVE something...
List *GOPs = mpeg2parser->getGOPs();
if (GOPs && GOPs->getNum())
file_is_loaded();
else
mpeg2parser->reset();
}
// load-time calculation
time(&finish);
finish -= begin;
speed = mpeg2parser->getSize() / 1048576; // max speed is max size
if (finish > 0)
speed /= finish;
if (speed == 0)
speed = 1; // claim at least 1MB/s
snprintf(report,REPORT_LENGTH,finish == 1
? _("Loaded %s in %d second (%%%sMB/s)\n")
: _("Loaded %s in %d seconds (%%%sMB/s)\n"),
filename, finish, OFF_T_FORMAT);
fprintf(stderr, report, speed);
progress(_("Caching"), 1.0);
/* write out the offset map */
if (!(gop_cache_filename=(char*)malloc(strlen(filename)+5))) {
perror("malloc");
}
else {
sprintf(gop_cache_filename,"%s.gop",filename);
if (write_gop_cache(gop_cache_filename,mpeg2parser)) {
printf("%s",_("Skipping offset cache writing.\n"));
}
}
progress(_("Done"), 1.0);
status_off(fileops);
}
/* gtk stupid: no way to get row count from a clist */
void update_GOP_slice_count(int count) {
gchar buf[128];
/* update the count of clips */
sprintf(buf, _("Clips: %d"), count);
gtk_label_set_text(GTK_LABEL(main_label_clips), buf);
}
void add_GOP_slice(uint32_t start, uint32_t end)
{
GtkTreeIter iter;
gchar *pathname;
pathname = mpeg2parser->getFilename();
if (!pathname)
pathname = _("unknown pathname");
gtk_list_store_append (main_list_store, &iter);
gtk_list_store_set (main_list_store, &iter,
ITEM_FILENAME, pathname,
ITEM_GOP_FIRST, start,
ITEM_GOP_LAST, end,
-1);
main_clist_count++;
update_GOP_slice_count(main_clist_count);
}
void clear_GOP_slices()
{
gchar buf[128];
gtk_list_store_clear(main_list_store);
main_clist_count=0;
update_GOP_slice_count(main_clist_count);
}
void remove_GOP_slice(GtkTreeIter *iter)
{
if (!iter) return;
gtk_list_store_remove(main_list_store,iter);
main_clist_count--;
update_GOP_slice_count(main_clist_count);
}
GdkFilterReturn filter_event(GdkXEvent *xevent,
GdkEvent *event,
gpointer data)
{
//report_event(event);
printf("got event\n");
return GDK_FILTER_CONTINUE;
}
const mpeg2_info_t *parser_info = NULL;
// decode_start
// decode_stop
void clear_GOP_info()
{
gtk_list_store_clear(GOP_list_store);
gtk_label_set_text(GTK_LABEL(GOP_label_filename), "");
gtk_label_set_text(GTK_LABEL(GOP_label_GOP), _("No GOP selected"));
gtk_label_set_text(GTK_LABEL(GOP_label_sequence_info),
_("No Sequence Info Found") );
}
void update_GOP_info(uint32_t num)
{
int i;
GroupOfPictures *GOP;
Bounds *picture_bounds;
Bounds *packet_bounds;
Picture *picture;
List *GOPs;
List *picture_list;
List *packet_list;
List *audio_list;
List *video_list;
Vector *head_vector;
uint32_t picture_index, picture_max;
uint32_t packet_min, packet_index, packet_max;
uint32_t audio_index, audio_max;
off_t gop_len, gop_start;
off_t audio_len;
//int aindex, amax;
uint8_t *head;
int drop, hour, min, sec, pictures, closed, broken;
GtkTreeIter iter;
gchar datatype[128];
gchar dataoffset[128];
gchar datasize[128];
gchar seqbuf[128];
struct sequence_info info;
/* wipe out the old list */
gtk_list_store_clear(GOP_list_store);
// wipe out labels
sprintf(seqbuf,_("GOP %u information:"),num);
gtk_label_set_text(GTK_LABEL(GOP_label_GOP), seqbuf);
gtk_label_set_text(GTK_LABEL(GOP_label_sequence_info),
_("No Sequence Info Found"));
if (!(GOPs = mpeg2parser->getGOPs()))
{
printf(_("no GOPs ?!\n"));
goto failure;
}
if (!(packet_list = mpeg2parser->getPackets()))
{
printf(_("NULL picture list ?!\n"));
goto failure;
}
if (!(picture_list = mpeg2parser->getPictures()))
{
printf(_("NULL picture list ?!\n"));
goto failure;
}
if (!(audio_list = mpeg2parser->getAudio()))
{
printf(_("NULL audio list ?!\n"));
goto failure;
}
if (!(video_list = mpeg2parser->getVideo()))
{
printf(_("NULL video list ?!\n"));
goto failure;
}
if (!(GOP = (GroupOfPictures *) GOPs->vector(num)))
{
printf(_("no such GOP %d ?!\n"), num);
goto failure;
}
if (!(head_vector = GOP->getHeader()))
{
printf(_("GOP header missing?!\n"));
goto failure;
}
if (!(head = mpeg2parser->bytesAvail(head_vector->getStart(), 8)))
{
printf(_("GOP header not available?!\n"));
goto failure;
}
// calculate GOP information
/*
4 5 6 7
| | | |
7 65432 107654 3 210765 432107 6 543210
1 11111 111111 1 111111 111111 1 1
d hour min m sec pic c b
r a l roken
o r osed
p k
*/
drop = ((head[4] & 0x80) > 0);
hour = ((head[4] & 0x7C) >> 2);
min = ((head[4] & 0x3) << 4) | ((head[5] & 0xF0) >> 4);
// sec/picture decoding corrected, care of Scott Smith
sec = ((head[5] & 0x7) << 3) | ((head[6] & 0xE0) >> 5);
pictures = ((head[6] & 0x1F) << 1) | ((head[7] & 0x80) >> 7);
closed = ((head[7] & 0x40) > 0);
broken = ((head[7] & 0x20) > 0);
if (!(picture_bounds = GOP->getPictureBounds()))
{
printf(_("NULL GOP picture bounds?!\n"));
goto failure;
}
// FIXME: technically, this loop does a lot of needless
// reassigning of values. However, this loop doesn't
// happen often, and it's the easiest way I could think
// of to sort by offset.
// get picture bounds
picture_index = picture_bounds->getFirst();
picture_max = picture_bounds->getMax();
for (; picture_index < picture_max; picture_index++)
{
Bounds *pic_bounds;
uint32_t ves, ves_min, ves_max;
Vector *pic_vector;
off_t pic_start;
off_t pic_len;
if (!(picture = (Picture *) picture_list->vector(picture_index)))
{
printf(_("NULL picture?!\n"));
goto failure;
}
if (!(pic_bounds = picture->getVideoBounds()))
{
printf(_("NULL picture bounds?!\n"));
goto failure;
}
ves_min = pic_bounds->getFirst();
ves_max = pic_bounds->getMax();
pic_len = 0;
for (ves = ves_min; ves < ves_max; ves++)
{
if (!(pic_vector = (Vector *) video_list->vector(ves)))
{
printf(_("NULL picture VES vector?!\n"));
goto failure;
}
if (ves == ves_min)
pic_start = pic_vector->getStart();
pic_len += pic_vector->getLen();
}
snprintf(datatype, 128, _(" Picture (%s: %02d)"),
frame_type_str(picture->getType()), picture->getTime());
snprintf(dataoffset, 128, "%" OFF_T_FORMAT, pic_start);
snprintf(datasize, 128, "%" OFF_T_FORMAT, pic_len);
gtk_list_store_append(GOP_list_store, &iter);
gtk_list_store_set(GOP_list_store, &iter,
ITEM_DATATYPE, datatype,
ITEM_OFFSET, dataoffset,
ITEM_SIZE, datasize,
-1);
}
// process GOP packets
if (!(packet_bounds = GOP->getPacketBounds()))
{
printf(_("NULL GOP packet bounds?!\n"));
goto failure;
}
packet_min = packet_bounds->getFirst();
packet_max = packet_bounds->getMax();
gop_len = 0;
audio_len = 0;
for (packet_index = packet_min; packet_index < packet_max; packet_index++)
{
Pack *packet;
if (!(packet = (Pack *) packet_list->vector(packet_index)))
{
printf(_("NULL GOP packet vector?!\n"));
goto failure;
}
if (packet_index == packet_min)
gop_start = packet->getStart();
gop_len += packet->getLen();
audio_index = packet->getAudioFirst();
audio_max = packet->getAudioMax();
for (; audio_index < audio_max; audio_index++)
{
Bounds *audio_bounds;
int aes, aes_min, aes_max;
Vector *audio_vector;
if (!(audio_vector = (Vector *) audio_list->vector(audio_index)))
{
printf(_("NULL GOP AES vector?!\n"));
goto failure;
}
audio_len += audio_vector->getLen();
}
}
// display GOP
snprintf(datatype, 128, _("GOP (%02d:%02d:%02d.%02d%s%s%s)"),
hour, min, sec, pictures,
drop ? _(" drop") : _(" keep"),
closed ? _(" closed") : _(" open"),
broken ? _(" broken") : _(" whole"));
snprintf(dataoffset, 128, "%" OFF_T_FORMAT, gop_start);
snprintf(datasize, 128, "%" OFF_T_FORMAT, gop_len);
gtk_list_store_prepend(GOP_list_store, &iter);
gtk_list_store_set(GOP_list_store, &iter,
ITEM_DATATYPE, datatype,
ITEM_OFFSET, dataoffset,
ITEM_SIZE, datasize,
-1);
// display audio info
snprintf(datatype, 128, "%s", _(" Audio"));
snprintf(dataoffset, 128, "%" OFF_T_FORMAT, gop_start);
snprintf(datasize, 128, "%" OFF_T_FORMAT, audio_len);
gtk_list_store_append(GOP_list_store, &iter);
gtk_list_store_set(GOP_list_store, &iter,
ITEM_DATATYPE, datatype,
ITEM_OFFSET, dataoffset,
ITEM_SIZE, datasize,
-1);
// update labels with info
GOP->get_sequence_info(&info);
snprintf(seqbuf,128,_("%dx%d: %s aspect, %s fps, %s%s"),
info.horizontal_size, info.vertical_size,
aspect_str[info.aspect_ratio],
frame_str[info.frame_rate],
speed_str(info.bit_rate * 400),
info.constrained ? _(", constrained") : "");
gtk_label_set_text(GTK_LABEL(GOP_label_sequence_info),seqbuf);
failure:
/* perform any cleanups */
while (0) {}; // keep compiler quiet
}
#define MAX_FRAME_TYPES 4
const char *frame_type_map[MAX_FRAME_TYPES] = {
N_("Bad Frame"),
N_("I-Frame"),
N_("P-Frame"),
N_("B-Frame")
};
const char *frame_type_str(int type)
{
if (type >= MAX_FRAME_TYPES || type < 0)
type = 0;
return _(frame_type_map[type]);
}
uint32_t get_GOP_selected()
{
return (uint32_t) gtk_range_get_value(GTK_RANGE(GOP_selector));
}
void set_GOP_selected(uint32_t num)
{
uint32_t max;
uint32_t old;
max = mpeg2parser->numGOPs();
// correct our bounds
if (num >= max)
num = max - 1;
if (num < 0)
num = 0;
// remember where we were
old = get_GOP_selected();
gtk_range_set_value(GTK_RANGE(GOP_selector), (gdouble) num);
}
void handle_rc_load()
{
if (rc_load(PACKAGE,parsable_items))
fprintf(stderr,"%s",_("Could not load rc file -- using defaults.\n"));
/* handle side-effects */
/* synchronize the loaded/default values to the slider */
options.run_speed = options.default_run_speed;
gtk_range_set_value(GTK_RANGE(slider_run_speed), options.run_speed);
mpeg2parser->set_ignore_endcode(options.ignore_endcode);
}
void Usage(char *title)
{
printf("Usage: %s [OPTIONS] [FILE]\n\
\n\
-h, --help This help\n\
-v, --vo DRIVER Choose internal output driver. Use 'help' for a list.\n\
-p, --pipe CMD Use external command for output. Recommended:\n\
'mplayer -nocache -novm -'\n\
-s, --states Report libmpeg2 states\n\
FILE MPEG2 to load on startup\n\
\n", title);
exit(1);
}
void handle_args(int argc, char *argv[])
{
static struct option long_options[] = {
{ "help", 0, NULL, 'h' }, // 0
{ "vo", 1, NULL, 'v' },
{ "pipe", 1, NULL, 'p' },
{ "states", 0, NULL, 's' },
{ "version",0, NULL, 'V' },
{ 0, 0, 0, 0 }
};
/* do our option handling */
while (1)
{
int c;
int index;
c = getopt_long(argc, argv, "Vhsv:p:", long_options, &index);
if (c == -1)
break; // done with args
switch (c)
{
case 0:
// got a matching long argument (with no short equiv)
switch (index)
{
default:
fprintf(stderr,
_("Unknown long argument index %d found!\n"),
index);
}
break;
case 'h':
Usage(argv[0]);
break;
case 'V':
printf("GOPchop %s (%s)\n", VERSION, __DATE__);
exit(0);
break;
case 's':
opt_show_states=1;
break;
case 'v':
opt_videoout=optarg;
if (strcmp(opt_videoout,"help")==0)
{
// display a list of libvo drivers
int i;
vo_driver_t const *drivers;
printf(_("Video output options:\n"));
drivers = vo_drivers();
for (i = 0; drivers[i].name; i++)
printf("\t%s\n",drivers[i].name);
exit(1);
}
else
{
// verify selected libvo driver
if (!find_libvo_driver(opt_videoout))
{
fprintf(stderr,_("No such video driver: '%s'\n"),
opt_videoout);
exit(1);
}
desired_output=GOPCHOP_OUTPUT_LIBVO;
}
break;
case 'p':
opt_pipe=optarg;
desired_output=GOPCHOP_OUTPUT_PIPE;
break;
default:
fprintf(stderr, _("Unknown short argument '%c' found?!\n"), c);
/* fall through to the Usage ... */
case '?':
Usage(argv[0]);
break;
}
}
}
/*
* There must be a way to hook up an event watcher to frame_window
* directly. Until I figure it out, this will have to do. Overkill,
* but it works.
*/
void gopchop_events(GdkEvent *event, gpointer data)
{
GdkEventExpose *expose = (GdkEventExpose*)event;
if (event)
switch (event->type)
{
// this doesn't catch window movement :(
case GDK_VISIBILITY_NOTIFY: // forces repaint of frame window
// don't attempt repaint while totally hidden
if (((GdkEventVisibility*)event)->state == GDK_VISIBILITY_FULLY_OBSCURED)
break;
if (display_is_window(engine,((GdkEventAny*)event)->window))
display_redraw(engine);
break;
/*
case GDK_EXPOSE: // forces repaint of frame window
if (display_is_window(engine,expose->window))
display_redraw(engine);
break;
*/
}
// process events normally
gtk_main_do_event(event);
return;
}
int main(int argc, char *argv[])
{
/* deal with internationalization support */
#ifdef ENABLE_NLS
setlocale(LC_ALL, "");
bindtextdomain(GETTEXT_PACKAGE, PACKAGE_DATA_DIR "/locale");
textdomain(GETTEXT_PACKAGE);
#endif
gtk_set_locale();
/* pass command line args to gtk (which may modify them) */
gtk_init(&argc, &argv);
/* handle our command line args */
handle_args(argc, argv);
/* setup the parsing object */
mpeg2parser = new MPEG2Parser;
/* set up all the gtk windows and widgets */
setup_gtk_stuff();
/* verify that we're working with largefile support
* (report to Gtk window)
*/
if (sizeof(off_t) < 8)
{
show_error(_("Type 'off_t' is less than 8 bytes.\n"
"Largefile support requires at least 8 bytes.\n"));
gtk_widget_show(error_dialog);
}
/* load any saved options (prior to opening the first file) */
handle_rc_load();
/* attempt to load the filename mentioned on the command line
* (requires MPEG2Parser and GTK loaded
*/
if (optind < argc)
open_file(argv[optind]);
/* start the event handler */
gdk_event_handler_set(gopchop_events,NULL,NULL);
gtk_main();
return 0;
}
/* vi:set ai ts=4 sw=4 expandtab: */