aboutsummaryrefslogtreecommitdiff
path: root/video_player/include/Args.hpp
blob: 610f0b0246765e723c77c79c876bdb3220e122c4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
#pragma once

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>

#include <string>
#include <vector>

struct MpvProperty {
    std::string key;
    std::string value;
};

struct Args {
    long wid_num = 0;
    long ipc_fd_num = 0;

    const char *ipc_fd = nullptr;
    const char *audio_file = nullptr;
    const char *file_to_play = nullptr;

    std::vector<MpvProperty> mpv_properties;
};

static void usage() {
    fprintf(stderr, "usage: quickmedia-video-player [--ipc-fd <fd>] [--audio-file <audio_file>] [--key=value...] <file>\n");
    fprintf(stderr, "  --ipc-fd <fd>                A bi-directional (socketpair) file descriptor to receive commands from. Optional\n");
    fprintf(stderr, "  --audio-file <audio_file>    Load the given audio file. Optional\n");
    fprintf(stderr, "  --key=value                  Additional options in the format --key=value are passed directly to mpv as string properties. Optional\n");
    fprintf(stderr, "examples:\n");
    fprintf(stderr, "  quickmedia-video-player video.mp4\n");
    fprintf(stderr, "  quickmedia-video-player --wid 30481231 -- video.mp4\n");
    exit(1);
}

static bool string_to_long(const char *str, long &result) {
    errno = 0;
    char *endptr = NULL;
    result = strtol(str, &endptr, 0);
    return endptr != str && errno == 0;
}

static bool string_to_double(const char *str, double &result) {
    errno = 0;
    char *endptr = NULL;
    result = strtod(str, &endptr);
    return endptr != str && errno == 0;
}

static bool fd_is_valid(int fd) {
    errno = 0;
    return fcntl(fd, F_GETFD) != -1 && errno != EBADF;
}

static Args parse_args(int argc, char **argv) {
    Args args;

    for(int i = 1; i < argc; ++i) {
        const char *arg = argv[i];
        if(strcmp(arg, "--audio-file") == 0) {
            if(args.audio_file) {
                fprintf(stderr, "Error: option --audio-file was specified multiple times\n");
                usage();
            }

            if(i + 1 == argc) {
                fprintf(stderr, "Error: missing audio file after option --audio-file\n");
                usage();
            }

            args.audio_file = argv[i + 1];
            ++i;
        } else if(strcmp(arg, "--ipc-fd") == 0) {
            if(args.ipc_fd) {
                fprintf(stderr, "Error: option --ipc-fd was specified multiple times\n");
                usage();
            }

            if(i + 1 == argc) {
                fprintf(stderr, "Error: missing fd after option --ipc-fd\n");
                usage();
            }

            args.ipc_fd = argv[i + 1];
            ++i;
        } else if(strcmp(arg, "--") == 0) {
            if(i + 1 == argc) {
                fprintf(stderr, "Error: missing file option after --\n");
                usage();
            } else if(i + 1 != argc - 1) {
                fprintf(stderr, "Error: more than one option was specified after --\n");
                usage();
            }

            args.file_to_play = argv[i + 1];
            ++i;
        } else if(strncmp(arg, "--", 2) == 0) {
            const char *equal_p = strchr(arg, '=');
            if(!equal_p) {
                fprintf(stderr, "Error: mpv option %s is missing \"=\"\n", arg);
                usage();
            }

            args.mpv_properties.push_back({ std::string(arg + 2, equal_p - (arg + 2)), equal_p + 1 });
        } else {
            if(args.file_to_play) {
                fprintf(stderr, "Error: file option was specified multiple times\n");
                usage();
            }

            args.file_to_play = arg;
        }
    }

    if(!args.file_to_play) {
        fprintf(stderr, "Error: missing file option\n");
        usage();
    }

    if(args.ipc_fd) {
        if(!string_to_long(args.ipc_fd, args.ipc_fd_num)) {
            fprintf(stderr, "Error: invalid number %s was specified for option --ipc-fd\n", args.ipc_fd);
            usage();
        }

        if(!fd_is_valid(args.ipc_fd_num)) {
            fprintf(stderr, "Error: invalid fd %s was specified for option --ipc-fd\n", args.ipc_fd);
            usage();
        }
    }

    return args;
}