summaryrefslogtreecommitdiffstats
path: root/test/chmap.c
blob: 48af822e727f5247b3536b6ba4b02400d172d201 (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
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
#include "audio/chmap.h"
#include "audio/chmap_sel.h"
#include "config.h"
#include "test_utils.h"

#if HAVE_AV_CHANNEL_LAYOUT
#include "audio/chmap_avchannel.h"
#endif

#define LAYOUTS(...) (char*[]){__VA_ARGS__, NULL}

static void test_sel(const char *input, const char *expected_selection,
                     char **layouts)
{
    struct mp_chmap_sel s = {0};
    struct mp_chmap input_map;
    struct mp_chmap expected_map;

    assert_true(mp_chmap_from_str(&input_map, bstr0(input)));
    assert_true(mp_chmap_from_str(&expected_map, bstr0(expected_selection)));

    for (int n = 0; layouts[n]; n++) {
        struct mp_chmap tmp;
        assert_true(mp_chmap_from_str(&tmp, bstr0(layouts[n])));
        int count = s.num_chmaps;
        mp_chmap_sel_add_map(&s, &tmp);
        assert_true(s.num_chmaps > count); // assure validity and max. count
    }

    assert_true(mp_chmap_sel_fallback(&s, &input_map));
    // We convert expected_map to a chmap and then back to a string to avoid
    // problems with ambiguous layouts.
    assert_string_equal(mp_chmap_to_str(&input_map),
                        mp_chmap_to_str(&expected_map));
}

#if HAVE_AV_CHANNEL_LAYOUT
static bool layout_matches(const AVChannelLayout *av_layout,
                           const struct mp_chmap *mp_layout,
                           bool require_default_unspec)
{
    if (!mp_chmap_is_valid(mp_layout) ||
        !av_channel_layout_check(av_layout) ||
        av_layout->nb_channels != mp_layout->num ||
        mp_layout->num > MP_NUM_CHANNELS)
        return false;

    switch (av_layout->order) {
    case AV_CHANNEL_ORDER_UNSPEC:
    {
        if (!require_default_unspec)
            return true;

        // mp_chmap essentially does not have a concept of "unspecified"
        // so we check if the mp layout matches the default layout for such
        // channel count.
        struct mp_chmap default_layout = { 0 };
        mp_chmap_from_channels(&default_layout, mp_layout->num);
        return mp_chmap_equals(mp_layout, &default_layout);
    }
    case AV_CHANNEL_ORDER_NATIVE:
        return av_layout->u.mask == mp_chmap_to_lavc(mp_layout);
    default:
        // TODO: handle custom layouts
        return false;
    }

    return true;
}

static void test_mp_chmap_to_av_channel_layout(void)
{
    mp_ch_layout_tuple *mapping_array = NULL;
    void *iter = NULL;
    bool anything_failed = false;

    printf("Testing mp_chmap -> AVChannelLayout conversions\n");

    while ((mapping_array = mp_iterate_builtin_layouts(&iter))) {
        const char *mapping_name = (*mapping_array)[0];
        const char *mapping_str  = (*mapping_array)[1];
        struct mp_chmap mp_layout = { 0 };
        AVChannelLayout av_layout = { 0 };
        char layout_desc[128] = {0};

        assert_true(mp_chmap_from_str(&mp_layout, bstr0(mapping_str)));

        mp_chmap_to_av_layout(&av_layout, &mp_layout);

        assert_false(av_channel_layout_describe(&av_layout,
                                                layout_desc, 128) < 0);

        bool success =
            (strcmp(layout_desc, mp_chmap_to_str(&mp_layout)) == 0 ||
             layout_matches(&av_layout, &mp_layout, false));
        if (!success)
            anything_failed = true;

        printf("%s: %s (%s) -> %s\n",
               success ? "Success" : "Failure",
               mapping_str, mapping_name, layout_desc);

        av_channel_layout_uninit(&av_layout);
    }

    assert_false(anything_failed);
}

static void test_av_channel_layout_to_mp_chmap(void)
{
    const AVChannelLayout *av_layout = NULL;
    void *iter = NULL;
    bool anything_failed = false;

    printf("Testing AVChannelLayout -> mp_chmap conversions\n");

    while ((av_layout = av_channel_layout_standard(&iter))) {
        struct mp_chmap mp_layout = { 0 };
        char layout_desc[128] = {0};

        assert_false(av_channel_layout_describe(av_layout,
                                                layout_desc, 128) < 0);

        bool ret = mp_chmap_from_av_layout(&mp_layout, av_layout);
        if (!ret) {
            bool too_many_channels =
                av_layout->nb_channels > MP_NUM_CHANNELS;
            printf("Conversion from '%s' to mp_chmap failed (%s)!\n",
                   layout_desc,
                   too_many_channels ?
                   "channel count was over max, ignoring" :
                   "unexpected, failing");

            // we should for now only fail with things such as 22.2
            // due to mp_chmap being currently limited to 16 channels
            assert_true(too_many_channels);

            continue;
        }

        bool success =
            (strcmp(layout_desc, mp_chmap_to_str(&mp_layout)) == 0 ||
             layout_matches(av_layout, &mp_layout, true));
        if (!success)
            anything_failed = true;

        printf("%s: %s -> %s\n",
               success ? "Success" : "Failure",
               layout_desc, mp_chmap_to_str(&mp_layout));
    }

    assert_false(anything_failed);
}
#endif


int main(void)
{
    struct mp_chmap a;
    struct mp_chmap b;
    struct mp_chmap_sel s = {0};

    test_sel("5.1", "7.1", LAYOUTS("7.1"));
    test_sel("7.1", "5.1", LAYOUTS("5.1"));
    test_sel("7.1(wide-side)", "7.1", LAYOUTS("7.1"));
    test_sel("7.1(wide-side)", "5.1(side)", LAYOUTS("7.1", "5.1(side)"));
    test_sel("3.1", "5.1", LAYOUTS("7.1", "5.1", "2.1", "stereo", "mono"));
    test_sel("5.1", "7.1(rear)", LAYOUTS("7.1(rear)"));
    test_sel("5.1(side)", "5.1", LAYOUTS("5.1", "7.1"));
    test_sel("5.1", "7.1(alsa)", LAYOUTS("7.1(alsa)"));
    test_sel("mono", "stereo", LAYOUTS("stereo", "5.1"));
    test_sel("stereo", "stereo", LAYOUTS("stereo", "5.1"));
    test_sel("5.1(side)", "7.1(rear)", LAYOUTS("stereo", "7.1(rear)"));
    test_sel("7.1", "fl-fr-lfe-fc-bl-br-flc-frc",
             LAYOUTS("fl-fr-lfe-fc-bl-br-flc-frc", "3.0(back)"));

    mp_chmap_set_unknown(&a, 2);

    mp_chmap_from_str(&b, bstr0("5.1"));

    mp_chmap_sel_add_map(&s, &a);
    assert_false(mp_chmap_sel_fallback(&s, &b));
    assert_string_equal(mp_chmap_to_str(&b), "5.1");

    test_sel("quad", "quad(side)", LAYOUTS("quad(side)", "stereo"));
    test_sel("quad", "quad(side)", LAYOUTS("quad(side)", "7.0"));
    test_sel("quad", "quad(side)", LAYOUTS("7.0", "quad(side)"));
    test_sel("quad", "7.1(wide-side)", LAYOUTS("7.1(wide-side)", "stereo"));
    test_sel("quad", "7.1(wide-side)", LAYOUTS("stereo", "7.1(wide-side)"));
    test_sel("quad", "fl-fr-sl-sr",
             LAYOUTS("fl-fr-fc-bl-br", "fl-fr-sl-sr"));
    test_sel("quad", "fl-fr-bl-br-na-na-na-na",
             LAYOUTS("fl-fr-bl-br-na-na-na-na", "quad(side)", "stereo"));
    test_sel("quad", "fl-fr-bl-br-na-na-na-na",
             LAYOUTS("stereo", "quad(side)", "fl-fr-bl-br-na-na-na-na"));
    test_sel("fl-fr-fc-lfe-sl-sr", "fl-fr-lfe-fc-bl-br-na-na",
             LAYOUTS("fl-fr-lfe-fc-bl-br-na-na", "fl-fr-lfe-fc-bl-br-sdl-sdr"));
    test_sel("fl-fr-fc-lfe-sl-sr", "fl-fr-lfe-fc-bl-br-na-na",
             LAYOUTS("fl-fr-lfe-fc-bl-br-sdl-sdr", "fl-fr-lfe-fc-bl-br-na-na"));

    test_sel("na-fl-fr", "na-fl-fr", LAYOUTS("na-fl-fr-na", "fl-na-fr", "na-fl-fr",
                                             "fl-fr-na-na", "na-na-fl-fr"));

    mp_chmap_from_str(&a, bstr0("3.1"));
    mp_chmap_from_str(&b, bstr0("2.1"));

    assert_int_equal(mp_chmap_diffn(&a, &b), 1);

    mp_chmap_from_str(&b, bstr0("6.1(back)"));
    assert_int_equal(mp_chmap_diffn(&a, &b), 0);
    assert_int_equal(mp_chmap_diffn(&b, &a), 3);

#if HAVE_AV_CHANNEL_LAYOUT
    test_av_channel_layout_to_mp_chmap();
    test_mp_chmap_to_av_channel_layout();
#endif
    return 0;
}