void playlist_row_deleted_handler( GtkTreeModel *tree_model, GtkTreePath *path, gpointer data ) { gmpv_handle *ctx = data; const gchar *cmd[] = {"playlist_move", NULL, NULL, NULL}; gchar *src_str; gchar *dest_str; gint src; gint dest; src = gtk_tree_path_get_indices(path)[0]; dest = ctx->playlist_move_dest; if(dest >= 0) { src_str = g_strdup_printf("%d", (src > dest)?--src:src); dest_str = g_strdup_printf("%d", dest); ctx->playlist_move_dest = -1; cmd[1] = src_str; cmd[2] = dest_str; mpv_command(ctx->mpv_ctx, cmd); g_free(src_str); g_free(dest_str); } }
void MpvHandler::Command(const char *args[]) { if(mpv) mpv_command(mpv, args); else NotInitialized(); }
static void stop(GtPlayerBackendMpvOpenGL* self) { GtPlayerBackendMpvOpenGLPrivate* priv = gt_player_backend_mpv_opengl_get_instance_private(self); const gchar* mpv_cmd[] = {"stop", NULL}; check_mpv_error(mpv_command(priv->mpv, mpv_cmd)); }
inline void KNMusicBackendMpvThread::exeCommand(const char *args[]) { //Check mpv pointer first. if(m_mpvHandle) { //Launch mpv command. mpv_command(m_mpvHandle, args); } }
void remove_current_playlist_entry(gmpv_handle *ctx) { const gchar *cmd[] = {"playlist_remove", NULL, NULL}; PlaylistWidget *playlist; GtkTreePath *path; playlist = PLAYLIST_WIDGET(ctx->gui->playlist); gtk_tree_view_get_cursor ( GTK_TREE_VIEW(playlist->tree_view), &path, NULL ); if(path) { gint index; gchar *index_str; index = gtk_tree_path_get_indices(path)[0]; index_str = g_strdup_printf("%d", index); cmd[1] = index_str; g_signal_handlers_block_matched ( playlist->list_store, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, ctx ); playlist_widget_remove(playlist, index); if(ctx->loaded) { mpv_check_error(mpv_command(ctx->mpv_ctx, cmd)); } if(playlist_widget_empty(playlist)) { control_box_set_enabled (CONTROL_BOX(ctx->gui->control_box), FALSE); } g_signal_handlers_unblock_matched ( playlist->list_store, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, ctx ); g_free(index_str); } }
static void play(GtPlayerBackendMpvOpenGL* self) { GtPlayerBackendMpvOpenGLPrivate* priv = gt_player_backend_mpv_opengl_get_instance_private(self); if (priv->uri) { const gchar* mpv_cmd[] = {"loadfile", priv->uri, "replace", NULL}; check_mpv_error(mpv_command(priv->mpv, mpv_cmd)); } }
static void play(GtPlayer* player) { GtPlayerMpv* self = GT_PLAYER_MPV(player); GtPlayerMpvPrivate* priv = gt_player_mpv_get_instance_private(self); const gchar* mpv_cmd[] = {"loadfile", priv->current_uri, "replace", NULL}; check_mpv_error(mpv_command(priv->mpv, mpv_cmd)); priv->playing = TRUE; g_object_notify_by_pspec(G_OBJECT(self), props[PROP_PLAYING]); }
static void stop(GtPlayer* player) { GtPlayerMpv* self = GT_PLAYER_MPV(player); GtPlayerMpvPrivate* priv = gt_player_mpv_get_instance_private(self); const gchar* mpv_cmd[] = {"stop", NULL}; check_mpv_error(mpv_command(priv->mpv, mpv_cmd)); priv->playing = FALSE; g_object_notify_by_pspec(G_OBJECT(self), props[PROP_PLAYING]); }
static gboolean key_press_handler( GtkWidget *widget, GdkEvent *event, gpointer data ) { gmpv_handle *ctx = data; guint keyval = ((GdkEventKey*)event)->keyval; guint state = ((GdkEventKey*)event)->state; gchar **command; const guint mod_mask = GDK_MODIFIER_MASK &~(GDK_SHIFT_MASK |GDK_LOCK_MASK |GDK_MOD2_MASK |GDK_MOD3_MASK |GDK_MOD4_MASK |GDK_MOD5_MASK); /* Ignore insignificant modifiers (eg. numlock) */ state &= mod_mask; command = keybind_get_command(ctx, FALSE, state, keyval); /* Try user-specified keys first, then fallback to hard-coded keys */ if(command) { mpv_command(ctx->mpv_ctx, (const char **)command); } else if((state&mod_mask) == 0) { /* Accept F11 and f for entering/exiting fullscreen mode. ESC is * only used for exiting fullscreen mode. F11 is handled via * accelrator. */ if((ctx->gui->fullscreen && keyval == GDK_KEY_Escape) || keyval == GDK_KEY_f) { GAction *action ; action = g_action_map_lookup_action (G_ACTION_MAP(ctx->app), "fullscreen"); g_action_activate(action, NULL); } else if(keyval == GDK_KEY_Delete && main_window_get_playlist_visible(ctx->gui)) { remove_current_playlist_entry(ctx); } } return FALSE; }
int main(int argc, char *argv[]) { if (argc != 2) { printf("pass a single media file as argument\n"); return 1; } mpv_handle *ctx = mpv_create(); if (!ctx) { printf("failed creating context\n"); return 1; } // Enable default key bindings, so the user can actually interact with // the player (and e.g. close the window). check_error(mpv_set_option_string(ctx, "input-default-bindings", "yes")); mpv_set_option_string(ctx, "input-vo-keyboard", "yes"); int val = 1; check_error(mpv_set_option(ctx, "osc", MPV_FORMAT_FLAG, &val)); // Done setting up options. check_error(mpv_initialize(ctx)); check_error(mpv_request_log_messages(ctx, "v")); check_error(mpv_stream_cb_add_ro(ctx, "myprotocol", argv[1], open_fn)); // Play this file. const char *cmd[] = {"loadfile", "myprotocol://fake", NULL}; check_error(mpv_command(ctx, cmd)); // Let it play, and wait until the user quits. while (1) { mpv_event *event = mpv_wait_event(ctx, 10000); if (event->event_id == MPV_EVENT_LOG_MESSAGE) { struct mpv_event_log_message *msg = (struct mpv_event_log_message *)event->data; printf("[%s] %s: %s", msg->prefix, msg->level, msg->text); continue; } printf("event: %s\n", mpv_event_name(event->event_id)); if (event->event_id == MPV_EVENT_SHUTDOWN) break; } mpv_terminate_destroy(ctx); return 0; }
static gboolean mouse_press_handler( GtkWidget *widget, GdkEvent *event, gpointer data ) { gmpv_handle *ctx = data; GdkEventButton *btn_event = (GdkEventButton *)event; gchar **command; command = keybind_get_command( ctx, TRUE, btn_event->type == GDK_2BUTTON_PRESS, btn_event->button ); if(command) { mpv_command(ctx->mpv_ctx, (const char **)command); } return TRUE; }
void seek(gmpv_handle *ctx, gdouble time) { const gchar *cmd[] = {"seek", NULL, "absolute", NULL}; if(!ctx->loaded) { mpv_load(ctx, NULL, FALSE, TRUE); } else { gchar *value_str = g_strdup_printf("%.2f", time); cmd[1] = value_str; mpv_command(ctx->mpv_ctx, cmd); update_seek_bar(ctx); g_free(value_str); } }
gint gmpv_mpv_obj_command(GmpvMpvObj *mpv, const gchar **cmd) { gint rc = MPV_ERROR_UNINITIALIZED; if(mpv->mpv_ctx) { rc = mpv_command(mpv->mpv_ctx, cmd); } if(rc < 0) { gchar *cmd_str = g_strjoinv(" ", (gchar **)cmd); g_warning( "Failed to run mpv command \"%s\". Reason: %s.", cmd_str, mpv_error_string(rc) ); g_free(cmd_str); } return rc; }
gboolean quit(gpointer data) { const gchar *cmd[] = {"quit", NULL}; gmpv_handle *ctx = data; if(ctx->mpv_ctx) { mpv_command(ctx->mpv_ctx, cmd); mpv_quit(ctx); ctx->mpv_ctx = NULL; } if(!ctx->gui->fullscreen) { main_window_save_state(ctx->gui); } g_application_quit(G_APPLICATION(ctx->app)); return FALSE; }
int main(int argc, char *argv[]) { if (argc != 2) { printf("pass a single media file as argument\n"); return 1; } mpv_handle *ctx = mpv_create(); if (!ctx) { printf("failed creating context\n"); return 1; } // Enable default key bindings, so the user can actually interact with // the player (and e.g. close the window). check_error(mpv_set_option_string(ctx, "input-default-bindings", "yes")); mpv_set_option_string(ctx, "input-x11-keyboard", "yes"); int val = 1; check_error(mpv_set_option(ctx, "osc", MPV_FORMAT_FLAG, &val)); // Done setting up options. check_error(mpv_initialize(ctx)); // Play this file. const char *cmd[] = {"loadfile", argv[1], NULL}; check_error(mpv_command(ctx, cmd)); // Let it play, and wait until the user quits. while (1) { mpv_event *event = mpv_wait_event(ctx, 10000); printf("event: %s\n", mpv_event_name(event->event_id)); if (event->event_id == MPV_EVENT_SHUTDOWN) break; } mpv_terminate_destroy(ctx); return 0; }
int main(int argc, char **argv) { /** * Parse options */ bool verbose = false; bool debug = false; bool opt_track_number = false; bool opt_chapter_number = false; bool opt_widescreen = false; bool opt_pan_scan = false; bool opt_no_video = false; bool opt_no_audio = false; uint16_t arg_track_number = 0; uint8_t arg_first_chapter = 1; uint8_t arg_last_chapter = 99; struct dvd_player dvd_player; struct dvd_playback dvd_playback; char dvd_mpv_args[13] = {'\0'}; mpv_handle *dvd_mpv = NULL; mpv_event *dvd_mpv_event = NULL; struct mpv_event_log_message *dvd_mpv_log_message = NULL; const char *home_dir = getenv("HOME"); const char *lang = getenv("LANG"); // Video Title Set struct dvd_vts dvd_vts[99]; // DVD player default options snprintf(dvd_player.config_dir, 20, "/.config/dvd_player"); memset(dvd_player.mpv_config_dir, '\0', sizeof(dvd_player.mpv_config_dir)); if(home_dir != NULL) snprintf(dvd_player.mpv_config_dir, PATH_MAX - 1, "%s%s", home_dir, dvd_player.config_dir); // DVD playback default options dvd_playback.track = 1; dvd_playback.first_chapter = 1; dvd_playback.last_chapter = 99; dvd_playback.fullscreen = false; dvd_playback.deinterlace = false; dvd_playback.subtitles = false; snprintf(dvd_playback.mpv_chapters_range, 8, "%u-%u", 1, 99); memset(dvd_playback.audio_lang, '\0', sizeof(dvd_playback.audio_lang)); if(strlen(lang) >= 2) snprintf(dvd_playback.audio_lang, 3, "%s", strndup(lang, 2)); memset(dvd_playback.audio_aid, '\0', sizeof(dvd_playback.audio_aid)); memset(dvd_playback.subtitles_lang, '\0', sizeof(dvd_playback.subtitles_lang)); if(strlen(lang) >= 2) snprintf(dvd_playback.subtitles_lang, 3, "%s", strndup(lang, 2)); memset(dvd_playback.subtitles_sid, '\0', sizeof(dvd_playback.subtitles_sid)); const char str_options[] = "Aa:c:dfhpSs:t:Vvwz"; struct option long_options[] = { { "track", required_argument, 0, 't' }, { "chapters", required_argument, 0, 'c' }, { "fullscreen", no_argument, 0, 'f' }, { "deinterlace", no_argument, 0, 'd' }, { "alang", required_argument, 0, 'a' }, { "slang", required_argument, 0, 's' }, { "aid", required_argument, 0, 'A' }, { "sid", required_argument, 0, 'S' }, { "help", no_argument, 0, 'h' }, { "version", no_argument, 0, 'V' }, { "widescreen", no_argument, 0, 'w' }, { "pan-scan", no_argument, 0, 'p' }, { "verbose", no_argument, 0, 'v' }, { "debug", no_argument, 0, 'z' }, { 0, 0, 0, 0 } }; int long_index = 0; int opt = 0; opterr = 1; char *token = NULL; while((opt = getopt_long(argc, argv, str_options, long_options, &long_index )) != -1) { switch(opt) { case 'A': strncpy(dvd_playback.audio_aid, optarg, 3); break; case 'a': strncpy(dvd_playback.audio_lang, optarg, 2); break; case 'c': opt_chapter_number = true; token = strtok(optarg, "-"); { if(strlen(token) > 2) { fprintf(stderr, "Chapter range must be between 1 and 99\n"); return 1; } arg_first_chapter = (uint8_t)strtoumax(token, NULL, 0); } token = strtok(NULL, "-"); if(token != NULL) { if(strlen(token) > 2) { fprintf(stderr, "Chapter range must be between 1 and 99\n"); return 1; } arg_last_chapter = (uint8_t)strtoumax(token, NULL, 0); } if(arg_first_chapter == 0) arg_first_chapter = 1; if(arg_last_chapter < arg_first_chapter) arg_last_chapter = arg_first_chapter; if(arg_first_chapter > arg_last_chapter) arg_first_chapter = arg_last_chapter; break; case 'd': dvd_playback.deinterlace = true; break; case 'f': dvd_playback.fullscreen = true; break; case 'h': print_usage(DVD_INFO_PROGRAM); return 0; case 'p': opt_pan_scan = true; break; case 's': strncpy(dvd_playback.subtitles_lang, optarg, 2); dvd_playback.subtitles = true; break; case 'S': strncpy(dvd_playback.subtitles_sid, optarg, 3); dvd_playback.subtitles = true; break; case 't': opt_track_number = true; arg_track_number = (uint16_t)strtoumax(optarg, NULL, 0); break; case 'V': print_version("dvd_player"); return 0; case 'v': verbose = true; break; case 'w': opt_widescreen = true; break; case 'z': verbose = true; debug = true; break; // ignore unknown arguments case '?': print_usage("dvd_player"); return 1; // let getopt_long set the variable case 0: default: break; } } if(opt_pan_scan && opt_widescreen) opt_pan_scan = false; const char *device_filename = DEFAULT_DVD_DEVICE; if (argv[optind]) device_filename = argv[optind]; if(access(device_filename, F_OK) != 0) { fprintf(stderr, "cannot access %s\n", device_filename); return 1; } // Check to see if device can be opened int dvd_fd = 0; dvd_fd = dvd_device_open(device_filename); if(dvd_fd < 0) { fprintf(stderr, "dvd_player: error opening %s\n", device_filename); return 1; } dvd_device_close(dvd_fd); #ifdef __linux__ // Poll drive status if it is hardware if(dvd_device_is_hardware(device_filename)) { // Wait for the drive to become ready if(!dvd_drive_has_media(device_filename)) { fprintf(stderr, "drive status: "); dvd_drive_display_status(device_filename); return 1; } } #endif dvd_reader_t *dvdread_dvd = NULL; dvdread_dvd = DVDOpen(device_filename); if(!dvdread_dvd) { fprintf(stderr, "* dvdread could not open %s\n", device_filename); return 1; } ifo_handle_t *vmg_ifo = NULL; vmg_ifo = ifoOpen(dvdread_dvd, 0); if(vmg_ifo == NULL) { fprintf(stderr, "* Could not open IFO zero\n"); DVDClose(dvdread_dvd); return 1; } // DVD struct dvd_info dvd_info; memset(dvd_info.dvdread_id, '\0', sizeof(dvd_info.dvdread_id)); dvd_info.video_title_sets = dvd_video_title_sets(vmg_ifo); dvd_info.side = 1; memset(dvd_info.title, '\0', sizeof(dvd_info.title)); memset(dvd_info.provider_id, '\0', sizeof(dvd_info.provider_id)); memset(dvd_info.vmg_id, '\0', sizeof(dvd_info.vmg_id)); dvd_info.tracks = dvd_tracks(vmg_ifo); dvd_info.longest_track = 1; dvd_title(dvd_info.title, device_filename); printf("Disc title: %s\n", dvd_info.title); uint16_t num_ifos = 1; num_ifos = vmg_ifo->vts_atrt->nr_of_vtss; if(num_ifos < 1) { fprintf(stderr, "* DVD has no title IFOs?!\n"); fprintf(stderr, "* Most likely a bug in libdvdread or a bad master or problems reading the disc\n"); ifoClose(vmg_ifo); DVDClose(dvdread_dvd); return 1; } // Track struct dvd_track dvd_track; memset(&dvd_track, 0, sizeof(dvd_track)); struct dvd_track dvd_tracks[DVD_MAX_TRACKS]; memset(&dvd_tracks, 0, sizeof(dvd_track) * dvd_info.tracks); // Open first IFO uint16_t vts = 1; ifo_handle_t *vts_ifo = NULL; vts_ifo = ifoOpen(dvdread_dvd, vts); if(vts_ifo == NULL) { fprintf(stderr, "* Could not open VTS_IFO for track %u\n", 1); return 1; } ifoClose(vts_ifo); vts_ifo = NULL; // Create an array of all the IFOs ifo_handle_t *vts_ifos[DVD_MAX_VTS_IFOS]; vts_ifos[0] = NULL; for(vts = 1; vts < dvd_info.video_title_sets + 1; vts++) { dvd_vts[vts].vts = vts; dvd_vts[vts].valid = false; dvd_vts[vts].blocks = 0; dvd_vts[vts].filesize = 0; dvd_vts[vts].vobs = 0; dvd_vts[vts].tracks = 0; dvd_vts[vts].valid_tracks = 0; dvd_vts[vts].invalid_tracks = 0; vts_ifos[vts] = ifoOpen(dvdread_dvd, vts); if(vts_ifos[vts] == NULL) { dvd_vts[vts].valid = false; vts_ifos[vts] = NULL; } else if(!ifo_is_vts(vts_ifos[vts])) { dvd_vts[vts].valid = false; ifoClose(vts_ifos[vts]); vts_ifos[vts] = NULL; } else { dvd_vts[vts].valid = true; } } // Exit if track number requested does not exist if(opt_track_number && (arg_track_number > dvd_info.tracks)) { fprintf(stderr, "dvd_player: Invalid track number %d\n", arg_track_number); fprintf(stderr, "dvd_player: Valid track numbers: 1 to %u\n", dvd_info.tracks); ifoClose(vmg_ifo); DVDClose(dvdread_dvd); return 1; } else if(opt_track_number) { dvd_playback.track = arg_track_number; } uint16_t ix = 0; uint16_t track = 1; uint32_t longest_msecs = 0; uint16_t longest_widescreen_track = 0; uint32_t longest_widescreen_msecs = 0; uint16_t longest_pan_scan_track = 0; uint32_t longest_pan_scan_msecs = 0; for(ix = 0, track = 1; ix < dvd_info.tracks; ix++, track++) { vts = dvd_vts_ifo_number(vmg_ifo, ix + 1); vts_ifo = vts_ifos[vts]; dvd_track_info(&dvd_tracks[ix], track, vmg_ifo, vts_ifo); if(dvd_tracks[ix].msecs > longest_msecs) { dvd_info.longest_track = track; longest_msecs = dvd_tracks[ix].msecs; } if(dvd_track_aspect_ratio_16x9(vts_ifo) && dvd_tracks[ix].msecs > longest_widescreen_msecs) { longest_widescreen_msecs = dvd_tracks[ix].msecs; longest_widescreen_track = track; } else if(dvd_track_aspect_ratio_4x3(vts_ifo) && dvd_tracks[ix].msecs > longest_pan_scan_msecs) { longest_pan_scan_msecs = dvd_tracks[ix].msecs; longest_pan_scan_track = track; } } if(opt_widescreen && longest_widescreen_track != 0) dvd_info.longest_track = longest_widescreen_track; else if(opt_pan_scan && longest_pan_scan_track != 0) dvd_info.longest_track = longest_pan_scan_track; // TODO if there is another track that is active, within ~1 seconds of longest track, and // the first is pan & scan, and the second is widescreen, switch to the widescreen one. // A more intelligent search might also see if the second one has audio tracks. Need to // find a reference DVD. // Set the track number to play if none is passed as an argument if(!opt_track_number) dvd_playback.track = dvd_info.longest_track; dvd_track = dvd_tracks[dvd_playback.track - 1]; // Set the proper chapter range if(opt_chapter_number) { if(arg_first_chapter > dvd_track.chapters) { dvd_playback.first_chapter = dvd_track.chapters; } else dvd_playback.first_chapter = arg_first_chapter; if(arg_last_chapter > dvd_track.chapters) { dvd_playback.last_chapter = dvd_track.chapters; } else dvd_playback.last_chapter = arg_last_chapter; } else { dvd_playback.first_chapter = 1; dvd_playback.last_chapter = dvd_track.chapters; } /** * File descriptors and filenames */ dvd_file_t *dvdread_vts_file = NULL; vts = dvd_vts_ifo_number(vmg_ifo, dvd_playback.track); vts_ifo = vts_ifos[vts]; // Open the VTS VOB dvdread_vts_file = DVDOpenFile(dvdread_dvd, vts, DVD_READ_TITLE_VOBS); printf("Track: %02u, Length: %s, Chapters: %02u, Cells: %02u, Audio streams: %02u, Subpictures: %02u, Filesize: %lu, Blocks: %lu\n", dvd_track.track, dvd_track.length, dvd_track.chapters, dvd_track.cells, dvd_track.audio_tracks, dvd_track.subtitles, dvd_track.filesize, dvd_track.blocks); // Check for track issues dvd_track.valid = true; if(dvd_vts[vts].valid == false) { dvd_track.valid = false; } if(dvd_track.msecs == 0) { printf(" Error: track has zero length\n"); dvd_track.valid = false; } if(dvd_track.chapters == 0) { printf(" Error: track has zero chapters\n"); dvd_track.valid = false; } if(dvd_track.cells == 0) { printf(" Error: track has zero cells\n"); dvd_track.valid = false; } if(dvd_track.valid == false) { printf("Track has been marked as invalid, quitting\n"); DVDCloseFile(dvdread_vts_file); if(vts_ifo) ifoClose(vts_ifo); if(vmg_ifo) ifoClose(vmg_ifo); if(dvdread_dvd) DVDClose(dvdread_dvd); return 1; } // DVD playback using libmpv dvd_mpv = mpv_create(); // Terminal output mpv_set_option_string(dvd_mpv, "terminal", "yes"); mpv_set_option_string(dvd_mpv, "term-osd-bar", "yes"); if(debug) { mpv_request_log_messages(dvd_mpv, "debug"); } else if(verbose) { mpv_request_log_messages(dvd_mpv, "v"); } else { mpv_request_log_messages(dvd_mpv, "none"); // Skip "[ffmpeg/audio] ac3: frame sync error" which are normal when seeking on DVDs mpv_set_option_string(dvd_mpv, "msg-level", "ffmpeg/audio=none"); } // mpv zero-indexes tracks snprintf(dvd_mpv_args, 13, "dvdread://%u", dvd_playback.track - 1); // MPV uses zero-indexing for tracks, dvd_info uses one instead const char *dvd_mpv_commands[] = { "loadfile", dvd_mpv_args, NULL }; // Load user's mpv configuration in ~/.config/dvd_player/mpv.conf (and friends) if(strlen(dvd_player.mpv_config_dir) > 0) { mpv_set_option_string(dvd_mpv, "config-dir", dvd_player.mpv_config_dir); mpv_set_option_string(dvd_mpv, "config", "yes"); } // When choosing a chapter range, mpv will add 1 to the last one requested snprintf(dvd_playback.mpv_chapters_range, 8, "%u-%u", dvd_playback.first_chapter, dvd_playback.last_chapter + 1); // Playback options and default configuration mpv_set_option_string(dvd_mpv, "dvd-device", device_filename); if(strlen(dvd_info.title) > 0) mpv_set_option_string(dvd_mpv, "title", dvd_info.title); else mpv_set_option_string(dvd_mpv, "title", "dvd_player"); mpv_set_option_string(dvd_mpv, "chapter", dvd_playback.mpv_chapters_range); mpv_set_option_string(dvd_mpv, "input-default-bindings", "yes"); mpv_set_option_string(dvd_mpv, "input-vo-keyboard", "yes"); if(strlen(dvd_playback.audio_aid) > 0) mpv_set_option_string(dvd_mpv, "aid", dvd_playback.audio_aid); else if(strlen(dvd_playback.audio_lang) > 0) mpv_set_option_string(dvd_mpv, "alang", dvd_playback.audio_lang); if(dvd_playback.subtitles && strlen(dvd_playback.subtitles_sid) > 0) mpv_set_option_string(dvd_mpv, "sid", dvd_playback.subtitles_sid); else if(dvd_playback.subtitles && strlen(dvd_playback.subtitles_lang) > 0) mpv_set_option_string(dvd_mpv, "slang", dvd_playback.subtitles_lang); if(dvd_playback.fullscreen) mpv_set_option_string(dvd_mpv, "fullscreen", NULL); if(dvd_playback.deinterlace) mpv_set_option_string(dvd_mpv, "deinterlace", "yes"); if(opt_no_video) mpv_set_option_string(dvd_mpv, "video", "no"); if(opt_no_audio) mpv_set_option_string(dvd_mpv, "audio", "no"); // start mpv mpv_initialize(dvd_mpv); mpv_command(dvd_mpv, dvd_mpv_commands); while(true) { dvd_mpv_event = mpv_wait_event(dvd_mpv, -1); // Goodbye :) if(dvd_mpv_event->event_id == MPV_EVENT_SHUTDOWN || dvd_mpv_event->event_id == MPV_EVENT_END_FILE) break; if(debug && dvd_mpv_event->event_id != MPV_EVENT_LOG_MESSAGE) printf("dvd_player [mpv_event_name]: %s\n", mpv_event_name(dvd_mpv_event->event_id)); // Logging output if((verbose || debug) && dvd_mpv_event->event_id == MPV_EVENT_LOG_MESSAGE) { dvd_mpv_log_message = (struct mpv_event_log_message *)dvd_mpv_event->data; printf("mpv [%s]: %s", dvd_mpv_log_message->level, dvd_mpv_log_message->text); } } mpv_terminate_destroy(dvd_mpv); DVDCloseFile(dvdread_vts_file); if(vts_ifo) ifoClose(vts_ifo); if(vmg_ifo) ifoClose(vmg_ifo); if(dvdread_dvd) DVDClose(dvdread_dvd); return 0; }
void MpvHandler::Command(const char *args[]) { HandleErrorCode(mpv_command(mpv, args)); }
int main(int argc, char **argv) { /** * Parse options */ bool verbose = false; bool debug = false; bool opt_track_number = false; bool opt_chapter_number = false; bool opt_filename = false; bool valid_preset = false; uint16_t arg_track_number = 0; int long_index = 0; int opt = 0; opterr = 1; uint8_t arg_first_chapter = 1; uint8_t arg_last_chapter = 99; char *token = NULL; char *token_filename = NULL; char tmp_filename[5] = {'\0'}; char dvd_mpv_args[13] = {'\0'}; char dvd_mpv_first_chapter[5] = {'\0'}; char dvd_mpv_last_chapter[5] = {'\0'}; mpv_handle *dvd_mpv = NULL; mpv_event *dvd_mpv_event = NULL; struct mpv_event_log_message *dvd_mpv_log_message = NULL; // Video Title Set struct dvd_vts dvd_vts[99]; const char str_options[] = "Ac:dehl:o:p:t:Vvz"; struct option long_options[] = { { "chapters", required_argument, 0, 'c' }, { "track", required_argument, 0, 't' }, { "alang", required_argument, 0, 'l' }, { "aid", required_argument, 0, 'A' }, { "deinterlace", no_argument, 0, 'd' }, { "detelecine", no_argument, 0, 'e' }, { "preset", required_argument, 0, 'p' }, { "output", required_argument, 0, 'o' }, { "help", no_argument, 0, 'h' }, { "version", no_argument, 0, 'V' }, { "verbose", no_argument, 0, 'v' }, { "debug", no_argument, 0, 'z' }, { 0, 0, 0, 0 } }; struct dvd_trip dvd_trip; dvd_trip.track = 1; dvd_trip.first_chapter = 1; dvd_trip.last_chapter = 99; memset(dvd_mpv_first_chapter, '\0', sizeof(dvd_mpv_first_chapter)); memset(dvd_mpv_last_chapter, '\0', sizeof(dvd_mpv_last_chapter)); memset(dvd_trip.filename, '\0', sizeof(dvd_trip.filename)); memset(dvd_trip.container, '\0', sizeof(dvd_trip.container)); strcpy(dvd_trip.container, "mkv"); memset(dvd_trip.preset, '\0', sizeof(dvd_trip.preset)); strcpy(dvd_trip.preset, "medium"); memset(dvd_trip.vcodec, '\0', sizeof(dvd_trip.vcodec)); memset(dvd_trip.vcodec_preset, '\0', sizeof(dvd_trip.vcodec_preset)); memset(dvd_trip.vcodec_opts, '\0', sizeof(dvd_trip.vcodec_opts)); memset(dvd_trip.vcodec_log_level, '\0', sizeof(dvd_trip.vcodec_log_level)); memset(dvd_trip.color_opts, '\0', sizeof(dvd_trip.color_opts)); memset(dvd_trip.acodec, '\0', sizeof(dvd_trip.acodec)); memset(dvd_trip.acodec_opts, '\0', sizeof(dvd_trip.acodec_opts)); memset(dvd_trip.audio_lang, '\0', sizeof(dvd_trip.audio_lang)); memset(dvd_trip.audio_aid, '\0', sizeof(dvd_trip.audio_aid)); memset(dvd_trip.vf_opts, '\0', sizeof(dvd_trip.vf_opts)); dvd_trip.crf = 28; memset(dvd_trip.fps, '\0', sizeof(dvd_trip.fps)); dvd_trip.deinterlace = false; dvd_trip.detelecine = false; dvd_trip.pass = 1; while((opt = getopt_long(argc, argv, str_options, long_options, &long_index )) != -1) { switch(opt) { case 'A': strncpy(dvd_trip.audio_aid, optarg, 3); break; case 'c': opt_chapter_number = true; token = strtok(optarg, "-"); { if(strlen(token) > 2) { fprintf(stderr, "Chapter range must be between 1 and 99\n"); return 1; } arg_first_chapter = (uint8_t)strtoumax(token, NULL, 0); } token = strtok(NULL, "-"); if(token != NULL) { if(strlen(token) > 2) { fprintf(stderr, "Chapter range must be between 1 and 99\n"); return 1; } arg_last_chapter = (uint8_t)strtoumax(token, NULL, 0); } if(arg_first_chapter == 0) arg_first_chapter = 1; if(arg_last_chapter < arg_first_chapter) arg_last_chapter = arg_first_chapter; break; case 'd': dvd_trip.deinterlace = true; break; case 'e': dvd_trip.detelecine = true; break; case 'h': print_usage(DVD_INFO_PROGRAM); return 0; case 'l': strncpy(dvd_trip.audio_lang, optarg, 2); break; case 'p': if(strncmp(optarg, "low", 3) == 0) { strcpy(dvd_trip.preset, "low"); } else if(strncmp(optarg, "medium", 6) == 0) { strcpy(dvd_trip.preset, "medium"); } else if(strncmp(optarg, "high", 4) == 0) { strcpy(dvd_trip.preset, "high"); } else if(strncmp(optarg, "insane", 6) == 0) { strcpy(dvd_trip.preset, "insane"); } else { printf("dvd_trip [error]: valid presets - low medium high insane\n"); return 1; } break; case 'o': opt_filename = true; strncpy(dvd_trip.filename, optarg, PATH_MAX - 1); token_filename = strtok(optarg, "."); // Choose preset from file extension while(token_filename != NULL) { snprintf(tmp_filename, 5, "%s", token_filename); token_filename = strtok(NULL, "."); if(token_filename == NULL && strlen(tmp_filename) == 3 && strncmp(tmp_filename, "mkv", 3) == 0) { strncpy(dvd_trip.container, "mkv", 4); valid_preset = true; } else if(token_filename == NULL && strlen(tmp_filename) == 3 && strncmp(tmp_filename, "mp4", 3) == 0) { strncpy(dvd_trip.container, "mp4", 4); valid_preset = true; } else if(token_filename == NULL && strlen(tmp_filename) == 4 && strncmp(tmp_filename, "webm", 4) == 0) { strncpy(dvd_trip.container, "webm", 5); valid_preset = true; } } if(!valid_preset) { printf("dvd_trip [error]: output filename extension must be one of: .mkv, .mp4, .webm\n"); return 1; } break; case 't': opt_track_number = true; arg_track_number = (uint16_t)strtoumax(optarg, NULL, 0); break; case 'V': print_version("dvd_trip"); return 0; case 'v': verbose = true; break; case 'z': verbose = true; debug = true; break; // ignore unknown arguments case '?': print_usage("dvd_trip"); return 1; // let getopt_long set the variable case 0: default: break; } } const char *device_filename = DEFAULT_DVD_DEVICE; if (argv[optind]) device_filename = argv[optind]; if(access(device_filename, F_OK) != 0) { fprintf(stderr, "cannot access %s\n", device_filename); return 1; } // Check to see if device can be opened int dvd_fd = 0; dvd_fd = dvd_device_open(device_filename); if(dvd_fd < 0) { fprintf(stderr, "dvd_trip: error opening %s\n", device_filename); return 1; } dvd_device_close(dvd_fd); #ifdef __linux__ // Poll drive status if it is hardware if(dvd_device_is_hardware(device_filename)) { // Wait for the drive to become ready if(!dvd_drive_has_media(device_filename)) { fprintf(stderr, "drive status: "); dvd_drive_display_status(device_filename); return 1; } } #endif dvd_reader_t *dvdread_dvd = NULL; dvdread_dvd = DVDOpen(device_filename); if(!dvdread_dvd) { fprintf(stderr, "* dvdread could not open %s\n", device_filename); return 1; } ifo_handle_t *vmg_ifo = NULL; vmg_ifo = ifoOpen(dvdread_dvd, 0); if(vmg_ifo == NULL) { fprintf(stderr, "* Could not open IFO zero\n"); DVDClose(dvdread_dvd); return 1; } // DVD struct dvd_info dvd_info; memset(dvd_info.dvdread_id, '\0', sizeof(dvd_info.dvdread_id)); dvd_info.video_title_sets = dvd_video_title_sets(vmg_ifo); dvd_info.side = 1; memset(dvd_info.title, '\0', sizeof(dvd_info.title)); memset(dvd_info.provider_id, '\0', sizeof(dvd_info.provider_id)); memset(dvd_info.vmg_id, '\0', sizeof(dvd_info.vmg_id)); dvd_info.tracks = dvd_tracks(vmg_ifo); dvd_info.longest_track = 1; dvd_title(dvd_info.title, device_filename); printf("Disc title: %s\n", dvd_info.title); uint16_t num_ifos = 1; num_ifos = vmg_ifo->vts_atrt->nr_of_vtss; if(num_ifos < 1) { fprintf(stderr, "* DVD has no title IFOs?!\n"); fprintf(stderr, "* Most likely a bug in libdvdread or a bad master or problems reading the disc\n"); ifoClose(vmg_ifo); DVDClose(dvdread_dvd); return 1; } // Track struct dvd_track dvd_track; memset(&dvd_track, 0, sizeof(dvd_track)); struct dvd_track dvd_tracks[DVD_MAX_TRACKS]; memset(&dvd_tracks, 0, sizeof(dvd_track) * dvd_info.tracks); // Cells struct dvd_cell dvd_cell; dvd_cell.cell = 1; memset(dvd_cell.length, '\0', sizeof(dvd_cell.length)); snprintf(dvd_cell.length, DVD_CELL_LENGTH + 1, "00:00:00.000"); dvd_cell.msecs = 0; // Open first IFO uint16_t vts = 1; ifo_handle_t *vts_ifo = NULL; vts_ifo = ifoOpen(dvdread_dvd, vts); if(vts_ifo == NULL) { fprintf(stderr, "* Could not open VTS_IFO for track %u\n", 1); return 1; } ifoClose(vts_ifo); vts_ifo = NULL; // Create an array of all the IFOs ifo_handle_t *vts_ifos[DVD_MAX_VTS_IFOS]; vts_ifos[0] = NULL; for(vts = 1; vts < dvd_info.video_title_sets + 1; vts++) { dvd_vts[vts].vts = vts; dvd_vts[vts].valid = false; dvd_vts[vts].blocks = 0; dvd_vts[vts].filesize = 0; dvd_vts[vts].vobs = 0; dvd_vts[vts].tracks = 0; dvd_vts[vts].valid_tracks = 0; dvd_vts[vts].invalid_tracks = 0; vts_ifos[vts] = ifoOpen(dvdread_dvd, vts); if(vts_ifos[vts] == NULL) { dvd_vts[vts].valid = false; vts_ifos[vts] = NULL; } else if(!ifo_is_vts(vts_ifos[vts])) { dvd_vts[vts].valid = false; ifoClose(vts_ifos[vts]); vts_ifos[vts] = NULL; } else { dvd_vts[vts].valid = true; } } // Exit if track number requested does not exist if(opt_track_number && (arg_track_number > dvd_info.tracks)) { fprintf(stderr, "dvd_trip: Invalid track number %d\n", arg_track_number); fprintf(stderr, "dvd_trip: Valid track numbers: 1 to %u\n", dvd_info.tracks); ifoClose(vmg_ifo); DVDClose(dvdread_dvd); return 1; } else if(opt_track_number) { dvd_trip.track = arg_track_number; } uint16_t ix = 0; uint16_t track = 1; uint32_t longest_msecs = 0; for(ix = 0, track = 1; ix < dvd_info.tracks; ix++, track++) { vts = dvd_vts_ifo_number(vmg_ifo, ix + 1); vts_ifo = vts_ifos[vts]; dvd_track_info(&dvd_tracks[ix], track, vmg_ifo, vts_ifo); dvd_tracks[ix].valid = true; if(dvd_tracks[ix].msecs > longest_msecs) { dvd_info.longest_track = track; longest_msecs = dvd_tracks[ix].msecs; } } // Set the track number to rip if none is passed as an argument if(!opt_track_number) dvd_trip.track = dvd_info.longest_track; dvd_track = dvd_tracks[dvd_trip.track - 1]; // Set the proper chapter range if(opt_chapter_number) { if(arg_first_chapter > dvd_track.chapters) { dvd_trip.first_chapter = dvd_track.chapters; fprintf(stderr, "Resetting first chapter to %u\n", dvd_trip.first_chapter); } else dvd_trip.first_chapter = arg_first_chapter; if(arg_last_chapter > dvd_track.chapters) { dvd_trip.last_chapter = dvd_track.chapters; fprintf(stderr, "Resetting last chapter to %u\n", dvd_trip.last_chapter); } else dvd_trip.last_chapter = arg_last_chapter; } else { dvd_trip.first_chapter = 1; dvd_trip.last_chapter = dvd_track.chapters; } /** * File descriptors and filenames */ dvd_file_t *dvdread_vts_file = NULL; vts = dvd_vts_ifo_number(vmg_ifo, dvd_trip.track); vts_ifo = vts_ifos[vts]; // Open the VTS VOB dvdread_vts_file = DVDOpenFile(dvdread_dvd, vts, DVD_READ_TITLE_VOBS); printf("Track: %02u, Length: %s, Chapters: %02u, Cells: %02u, Audio streams: %02u, Subpictures: %02u, Filesize: %lu, Blocks: %lu\n", dvd_track.track, dvd_track.length, dvd_track.chapters, dvd_track.cells, dvd_track.audio_tracks, dvd_track.subtitles, dvd_track.filesize, dvd_track.blocks); // Check for track issues dvd_track.valid = true; if(dvd_vts[vts].valid == false) { dvd_track.valid = false; } if(dvd_track.msecs == 0) { printf(" Error: track has zero length\n"); dvd_track.valid = false; } if(dvd_track.chapters == 0) { printf(" Error: track has zero chapters\n"); dvd_track.valid = false; } if(dvd_track.cells == 0) { printf(" Error: track has zero cells\n"); dvd_track.valid = false; } if(dvd_track.valid == false) { printf("Track has been marked as invalid, quitting\n"); DVDCloseFile(dvdread_vts_file); if(vts_ifo) ifoClose(vts_ifo); if(vmg_ifo) ifoClose(vmg_ifo); if(dvdread_dvd) DVDClose(dvdread_dvd); return 1; } // MPV zero-indexes tracks sprintf(dvd_mpv_args, "dvdread://%u", dvd_trip.track - 1); const char *dvd_mpv_commands[] = { "loadfile", dvd_mpv_args, NULL }; // DVD playback using libmpv dvd_mpv = mpv_create(); // Terminal output mpv_set_option_string(dvd_mpv, "terminal", "yes"); if(!debug) mpv_set_option_string(dvd_mpv, "term-osd-bar", "yes"); if (debug) { mpv_request_log_messages(dvd_mpv, "debug"); strcpy(dvd_trip.vcodec_log_level, "full"); } else if(verbose) { mpv_request_log_messages(dvd_mpv, "v"); strcpy(dvd_trip.vcodec_log_level, "info"); } else { mpv_request_log_messages(dvd_mpv, "info"); strcpy(dvd_trip.vcodec_log_level, "info"); } /** Video **/ // Set output frames per second and color spaces based on source (NTSC or PAL) if(dvd_track_pal_video(vts_ifo)) { strcpy(dvd_trip.fps, "25"); strcpy(dvd_trip.color_opts, "color_primaries=bt470bg,color_trc=gamma28,colorspace=bt470bg"); } else { strcpy(dvd_trip.fps, "30000/1001"); strcpy(dvd_trip.color_opts, "color_primaries=smpte170m,color_trc=smpte170m,colorspace=smpte170m"); } /** Containers and Presets **/ // Set preset defaults if(strncmp(dvd_trip.container, "mkv", 3) == 0) { if(!opt_filename) strcpy(dvd_trip.filename, "trip_encode.mkv"); strcpy(dvd_trip.vcodec, "libx265"); strcpy(dvd_trip.vcodec_preset, "medium"); strcpy(dvd_trip.acodec, "libfdk_aac"); if(strncmp(dvd_trip.preset, "low", 3) == 0) { strcpy(dvd_trip.vcodec_preset, "fast"); dvd_trip.crf = 28; } else if(strncmp(dvd_trip.preset, "medium", 6) == 0) { strcpy(dvd_trip.vcodec_preset, "medium"); dvd_trip.crf = 24; } else if(strncmp(dvd_trip.preset, "high", 4) == 0) { strcpy(dvd_trip.vcodec_preset, "slow"); strcpy(dvd_trip.acodec_opts, "b=192k"); dvd_trip.crf = 20; } else if(strncmp(dvd_trip.preset, "insane", 6) == 0) { strcpy(dvd_trip.vcodec_preset, "slower"); strcpy(dvd_trip.acodec_opts, "b=256k"); dvd_trip.crf = 14; } sprintf(dvd_trip.vcodec_opts, "%s,preset=%s,crf=%u,x265-params=log-level=%s", dvd_trip.color_opts, dvd_trip.vcodec_preset, dvd_trip.crf, dvd_trip.vcodec_log_level); } if(strncmp(dvd_trip.container, "mp4", 3) == 0) { if(!opt_filename) strcpy(dvd_trip.filename, "trip_encode.mp4"); strcpy(dvd_trip.vcodec, "libx264"); strcpy(dvd_trip.vcodec_preset, "medium"); strcpy(dvd_trip.acodec, "libfdk_aac"); strcpy(dvd_trip.acodec_opts, ""); if(strncmp(dvd_trip.preset, "low", 3) == 0) { strcpy(dvd_trip.vcodec_preset, "fast"); dvd_trip.crf = 28; } else if(strncmp(dvd_trip.preset, "medium", 6) == 0) { strcpy(dvd_trip.vcodec_preset, "medium"); dvd_trip.crf = 22; } else if(strncmp(dvd_trip.preset, "high", 4) == 0) { strcpy(dvd_trip.vcodec_preset, "slow"); strcpy(dvd_trip.acodec_opts, "b=192k"); dvd_trip.crf = 20; } else if(strncmp(dvd_trip.preset, "insane", 6) == 0) { strcpy(dvd_trip.vcodec_preset, "slower"); strcpy(dvd_trip.acodec_opts, "b=256k"); dvd_trip.crf = 16; } // x264 doesn't allow passing log level (that I can see) sprintf(dvd_trip.vcodec_opts, "%s,preset=%s,crf=%u", dvd_trip.color_opts, dvd_trip.vcodec_preset, dvd_trip.crf); } if(strncmp(dvd_trip.container, "webm", 4) == 0) { if(!opt_filename) strcpy(dvd_trip.filename, "trip_encode.webm"); strcpy(dvd_trip.vcodec, "libvpx-vp9"); strcpy(dvd_trip.acodec, "libopus"); strcpy(dvd_trip.acodec_opts, "application=audio"); if(strncmp(dvd_trip.preset, "low", 3) == 0) { dvd_trip.crf = 34; sprintf(dvd_trip.vcodec_opts, "%s,b=0,crf=%u,keyint_min=0,g=360", dvd_trip.color_opts, dvd_trip.crf); strcpy(dvd_trip.acodec_opts, "application=audio,b=96000"); } if(strncmp(dvd_trip.preset, "medium", 6) == 0) { dvd_trip.crf = 32; sprintf(dvd_trip.vcodec_opts, "%s,b=0,crf=%u,keyint_min=0,g=360", dvd_trip.color_opts, dvd_trip.crf); strcpy(dvd_trip.acodec_opts, "application=audio,b=144000"); } if(strncmp(dvd_trip.preset, "high", 4) == 0) { dvd_trip.crf = 22; sprintf(dvd_trip.vcodec_opts, "%s,b=0,crf=%u,keyint_min=0,g=360", dvd_trip.color_opts, dvd_trip.crf); strcpy(dvd_trip.acodec_opts, "application=audio,b=192000"); } if(strncmp(dvd_trip.preset, "insane", 6) == 0) { dvd_trip.crf = 16; sprintf(dvd_trip.vcodec_opts, "%s,b=0,crf=%u,keyint_min=0,g=360", dvd_trip.color_opts, dvd_trip.crf); strcpy(dvd_trip.acodec_opts, "application=audio,b=256000"); } } mpv_set_option_string(dvd_mpv, "o", dvd_trip.filename); mpv_set_option_string(dvd_mpv, "ovc", dvd_trip.vcodec); mpv_set_option_string(dvd_mpv, "ovcopts", dvd_trip.vcodec_opts); mpv_set_option_string(dvd_mpv, "oac", dvd_trip.acodec); if(strlen(dvd_trip.acodec_opts) > 0) mpv_set_option_string(dvd_mpv, "oacopts", dvd_trip.acodec_opts); mpv_set_option_string(dvd_mpv, "dvd-device", device_filename); mpv_set_option_string(dvd_mpv, "track-auto-selection", "yes"); mpv_set_option_string(dvd_mpv, "input-default-bindings", "yes"); mpv_set_option_string(dvd_mpv, "input-vo-keyboard", "yes"); mpv_set_option_string(dvd_mpv, "resume-playback", "no"); // MPV's chapter range starts at the first one, and ends at the last one plus one // fex: to play chapter 1 only, mpv --start '#1' --end '#2' sprintf(dvd_mpv_first_chapter, "#%u", dvd_trip.first_chapter); sprintf(dvd_mpv_last_chapter, "#%u", dvd_trip.last_chapter + 1); mpv_set_option_string(dvd_mpv, "start", dvd_mpv_first_chapter); mpv_set_option_string(dvd_mpv, "end", dvd_mpv_last_chapter); if(strlen(dvd_trip.audio_aid) > 0) mpv_set_option_string(dvd_mpv, "aid", dvd_trip.audio_aid); else if(strlen(dvd_trip.audio_lang) > 0) mpv_set_option_string(dvd_mpv, "alang", dvd_trip.audio_lang); /** Video Filters **/ if(mpv_client_api_version() <= MPV_MAKE_VERSION(1, 25)) { // Syntax up to 0.27.2 mpv_set_option_string(dvd_mpv, "ofps", dvd_trip.fps); if(dvd_trip.detelecine && dvd_trip.deinterlace) sprintf(dvd_trip.vf_opts, "lavfi=yadif,lavfi=pullup,lavfi=dejudder"); else if(dvd_trip.deinterlace) sprintf(dvd_trip.vf_opts, "lavfi=yadif"); else if(dvd_trip.detelecine) sprintf(dvd_trip.vf_opts, "lavfi=pullup,lavfi=dejudder"); } else { // Syntax starting in 0.29.1 if(dvd_trip.detelecine && dvd_trip.deinterlace) sprintf(dvd_trip.vf_opts, "lavfi-yadif,lavfi-pullup,lavfi-dejudder,fps=%s", dvd_trip.fps); else if(dvd_trip.deinterlace) sprintf(dvd_trip.vf_opts, "lavfi-yadif,fps=%s", dvd_trip.fps); else if(dvd_trip.detelecine) sprintf(dvd_trip.vf_opts, "lavfi-pullup,lavfi-dejudder,fps=%s", dvd_trip.fps); else sprintf(dvd_trip.vf_opts, "fps=%s", dvd_trip.fps); } mpv_set_option_string(dvd_mpv, "vf", dvd_trip.vf_opts); if(dvd_trip.pass == 1) { fprintf(stderr, "dvd_trip [info]: dvd track %u\n", dvd_trip.track); fprintf(stderr, "dvd_trip [info]: chapters %u to %u\n", dvd_trip.first_chapter, dvd_trip.last_chapter); fprintf(stderr, "dvd_trip [info]: saving to %s\n", dvd_trip.filename); fprintf(stderr, "dvd_trip [info]: vcodec %s\n", dvd_trip.vcodec); fprintf(stderr, "dvd_trip [info]: acodec %s\n", dvd_trip.acodec); fprintf(stderr, "dvd_trip [info]: ovcopts %s\n", dvd_trip.vcodec_opts); fprintf(stderr, "dvd_trip [info]: oacopts %s\n", dvd_trip.acodec_opts); if(strlen(dvd_trip.vf_opts)) fprintf(stderr, "dvd_trip [info]: vf %s\n", dvd_trip.vf_opts); fprintf(stderr, "dvd_trip [info]: output fps %s\n", dvd_trip.fps); if(dvd_trip.deinterlace) fprintf(stderr, "dvd_trip [info]: deinterlacing video\n"); if(dvd_trip.detelecine) fprintf(stderr, "dvd_trip [info]: detelecining video\n"); } mpv_initialize(dvd_mpv); mpv_command(dvd_mpv, dvd_mpv_commands); while(true) { dvd_mpv_event = mpv_wait_event(dvd_mpv, -1); if(dvd_mpv_event->event_id == MPV_EVENT_SHUTDOWN || dvd_mpv_event->event_id == MPV_EVENT_END_FILE) break; // Logging output if((verbose || debug) && dvd_mpv_event->event_id == MPV_EVENT_LOG_MESSAGE) { dvd_mpv_log_message = (struct mpv_event_log_message *)dvd_mpv_event->data; printf("mpv [%s]: %s", dvd_mpv_log_message->level, dvd_mpv_log_message->text); } } mpv_terminate_destroy(dvd_mpv); DVDCloseFile(dvdread_vts_file); if(vts_ifo) ifoClose(vts_ifo); if(vmg_ifo) ifoClose(vmg_ifo); if(dvdread_dvd) DVDClose(dvdread_dvd); return 0; }
void gmpv_mpv_obj_load( GmpvMpvObj *mpv, const gchar *uri, gboolean append, gboolean update ) { const gchar *load_cmd[] = {"loadfile", NULL, NULL, NULL}; GtkListStore *playlist_store = gmpv_playlist_get_store(mpv->playlist); GtkTreeIter iter; gboolean empty; g_info( "Loading file (append=%s, update=%s): %s", append?"TRUE":"FALSE", update?"TRUE":"FALSE", uri?:"<PLAYLIST_ITEMS>" ); empty = !gtk_tree_model_get_iter_first (GTK_TREE_MODEL(playlist_store), &iter); load_cmd[2] = (append && !empty)?"append":"replace"; if(!append && uri && update) { gmpv_playlist_clear(mpv->playlist); mpv->state.new_file = TRUE; mpv->state.loaded = FALSE; } if(!uri) { gboolean append = FALSE; gboolean rc; if(!mpv->state.init_load) { gmpv_mpv_obj_set_property_flag(mpv, "pause", FALSE); } rc = gtk_tree_model_get_iter_first (GTK_TREE_MODEL(playlist_store), &iter); while(rc) { gchar *uri; gtk_tree_model_get( GTK_TREE_MODEL(playlist_store), &iter, PLAYLIST_URI_COLUMN, &uri, -1 ); /* append = FALSE only on first iteration */ gmpv_mpv_obj_load(mpv, uri, append, FALSE); append = TRUE; rc = gtk_tree_model_iter_next (GTK_TREE_MODEL(playlist_store), &iter); g_free(uri); } } if(uri && playlist_store) { gchar *path = get_path_from_uri(uri); load_cmd[1] = path; if(!append) { mpv->state.loaded = FALSE; if(!mpv->state.init_load) { gmpv_mpv_obj_set_property_flag (mpv, "pause", FALSE); } } if(update) { gchar *name = get_name_from_path(path); gmpv_playlist_append(mpv->playlist, name, uri); g_free(name); } g_assert(mpv->mpv_ctx); mpv_check_error(mpv_request_event( mpv->mpv_ctx, MPV_EVENT_END_FILE, 0 )); mpv_check_error(mpv_command(mpv->mpv_ctx, load_cmd)); mpv_check_error(mpv_request_event( mpv->mpv_ctx, MPV_EVENT_END_FILE, 1 )); g_free(path); } }