media.c 12.5 KB
Newer Older
Pierre's avatar
Pierre committed
1 2 3 4 5 6 7
/*
 * media_player.c - libvlc smoke test
 *
 * $Id$
 */

/**********************************************************************
Pierre's avatar
Pierre committed
8
 *  Copyright (C) 2010 Pierre d'Herbemont.                            *
Pierre's avatar
Pierre committed
9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
 *  This program is free software; you can redistribute and/or modify *
 *  it under the terms of the GNU General Public License as published *
 *  by the Free Software Foundation; 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, you can get it from:             *
 *  http://www.gnu.org/copyleft/gpl.html                              *
 **********************************************************************/

#include "test.h"
25 26 27 28 29
#include "../lib/libvlc_internal.h"

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
Pierre's avatar
Pierre committed
30

31
#include <vlc_threads.h>
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
32
#include <vlc_fs.h>
33 34
#include <vlc_input_item.h>
#include <vlc_events.h>
35

36
static void media_parse_ended(const libvlc_event_t *event, void *user_data)
Pierre's avatar
Pierre committed
37 38
{
    (void)event;
Thomas Guillem's avatar
Thomas Guillem committed
39 40
    vlc_sem_t *sem = user_data;
    vlc_sem_post (sem);
Pierre's avatar
Pierre committed
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
static void print_media(libvlc_media_t *media)
{
    libvlc_media_track_t **pp_tracks;
    unsigned i_count = libvlc_media_tracks_get(media, &pp_tracks);
    if (i_count > 0)
    {
        for (unsigned i = 0; i < i_count; ++i)
        {
            libvlc_media_track_t *p_track = pp_tracks[i];
            log("\ttrack(%d/%d): codec: %4.4s/%4.4s, ", i, p_track->i_id,
                (const char *)&p_track->i_codec,
                (const char *)&p_track->i_original_fourcc);
            switch (p_track->i_type)
            {
            case libvlc_track_audio:
                printf("audio: channels: %u, rate: %u\n",
                       p_track->audio->i_channels, p_track->audio->i_rate);
                break;
            case libvlc_track_video:
                printf("video: %ux%u, sar: %u/%u, fps: %u/%u\n",
                       p_track->video->i_width, p_track->video->i_height,
                       p_track->video->i_sar_num, p_track->video->i_sar_den,
                       p_track->video->i_frame_rate_num, p_track->video->i_frame_rate_den);
                break;
            case libvlc_track_text:
                printf("text: %s\n", p_track->subtitle->psz_encoding);
                break;
            case libvlc_track_unknown:
                printf("unknown\n");
                break;
            default:
                vlc_assert_unreachable();
            }
        }
        libvlc_media_tracks_release(pp_tracks, i_count);
    }
    else
        log("\tmedia doesn't have any tracks\n");

    for (enum libvlc_meta_t i = libvlc_meta_Title;
         i <= libvlc_meta_DiscTotal; ++i)
    {
        char *psz_meta = libvlc_media_get_meta(media, i);
        if (psz_meta != NULL)
            log("\tmeta(%d): '%s'\n", i, psz_meta);
        free(psz_meta);
    }
}

92
static void test_media_preparsed(libvlc_instance_t *vlc, const char *path,
93
                                 const char *location,
94
                                 libvlc_media_parse_flag_t parse_flags,
95
                                 libvlc_media_parsed_status_t i_expected_status)
Pierre's avatar
Pierre committed
96
{
97 98
    log ("test_media_preparsed: %s, expected: %d\n", path ? path : location,
         i_expected_status);
Pierre's avatar
Pierre committed
99

100 101 102 103 104
    libvlc_media_t *media;
    if (path != NULL)
        media = libvlc_media_new_path (vlc, path);
    else
        media = libvlc_media_new_location (vlc, location);
Pierre's avatar
Pierre committed
105 106
    assert (media != NULL);

Thomas Guillem's avatar
Thomas Guillem committed
107 108
    vlc_sem_t sem;
    vlc_sem_init (&sem, 0);
Pierre's avatar
Pierre committed
109

Pierre's avatar
Pierre committed
110
    // Check to see if we are properly receiving the event.
Pierre's avatar
Pierre committed
111
    libvlc_event_manager_t *em = libvlc_media_event_manager (media);
112
    libvlc_event_attach (em, libvlc_MediaParsedChanged, media_parse_ended, &sem);
Pierre's avatar
Pierre committed
113

Pierre's avatar
Pierre committed
114
    // Parse the media. This is synchronous.
115
    int i_ret = libvlc_media_parse_with_options(media, parse_flags, -1);
116
    assert(i_ret == 0);
Pierre's avatar
Pierre committed
117

118
    // Wait for preparsed event
Thomas Guillem's avatar
Thomas Guillem committed
119 120
    vlc_sem_wait (&sem);
    vlc_sem_destroy (&sem);
Pierre's avatar
Pierre committed
121 122

    // We are good, now check Elementary Stream info.
123
    assert (libvlc_media_get_parsed_status(media) == i_expected_status);
124 125
    if (i_expected_status == libvlc_media_parsed_status_done)
        print_media(media);
126

Pierre's avatar
Pierre committed
127 128 129
    libvlc_media_release (media);
}

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
static void input_item_preparse_timeout( const vlc_event_t *p_event,
                                         void *user_data )
{
    vlc_sem_t *p_sem = user_data;

    assert( p_event->u.input_item_preparse_ended.new_status == ITEM_PREPARSE_TIMEOUT );
    vlc_sem_post(p_sem);
}

static void test_input_metadata_timeout(libvlc_instance_t *vlc, int timeout,
                                        int wait_and_cancel)
{
    log ("test_input_metadata_timeout: timeout: %d, wait_and_cancel: %d\n",
         timeout, wait_and_cancel);

    int i_ret, p_pipe[2];
    i_ret = vlc_pipe(p_pipe);
    assert(i_ret == 0 && p_pipe[1] >= 0);

    char psz_fd_uri[strlen("fd://") + 11];
    sprintf(psz_fd_uri, "fd://%u", (unsigned) p_pipe[1]);
    input_item_t *p_item = input_item_NewFile(psz_fd_uri, "test timeout", 0,
                                              ITEM_LOCAL);
    assert(p_item != NULL);

    vlc_sem_t sem;
    vlc_sem_init (&sem, 0);
    i_ret = vlc_event_attach(&p_item->event_manager, vlc_InputItemPreparseEnded,
                             input_item_preparse_timeout, &sem);
    assert(i_ret == 0);
    i_ret = libvlc_MetadataRequest(vlc->p_libvlc_int, p_item,
                                   META_REQUEST_OPTION_SCOPE_LOCAL, timeout, vlc);
    assert(i_ret == 0);

    if (wait_and_cancel > 0)
    {
        msleep(wait_and_cancel * 1000);
        libvlc_MetadataCancel(vlc->p_libvlc_int, vlc);

    }
    vlc_sem_wait(&sem);

    input_item_Release(p_item);
    vlc_sem_destroy(&sem);
    vlc_close(p_pipe[0]);
    vlc_close(p_pipe[1]);
}

178
#define TEST_SUBITEMS_COUNT 6
179
static struct
180 181 182 183 184 185 186 187 188 189 190 191 192
{
    const char *file;
    libvlc_media_type_t type;
} test_media_subitems_list[TEST_SUBITEMS_COUNT] =
{
    { "directory", libvlc_media_type_directory, },
    { "file.jpg", libvlc_media_type_file },
    { "file.mkv", libvlc_media_type_file },
    { "file.mp3", libvlc_media_type_file },
    { "file.png", libvlc_media_type_file },
    { "file.ts", libvlc_media_type_file },
};

193
static void subitem_parse_ended(const libvlc_event_t *event, void *user_data)
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 219 220 221 222 223 224 225 226 227 228 229 230 231
{
    (void)event;
    vlc_sem_t *sem = user_data;
    vlc_sem_post (sem);
}

static void subitem_added(const libvlc_event_t *event, void *user_data)
{
#ifdef _WIN32
#define FILE_SEPARATOR   '\\'
#else
#define FILE_SEPARATOR   '/'
#endif
    bool *subitems_found = user_data;
    libvlc_media_t *m = event->u.media_subitem_added.new_child;
    assert (m);

    char *mrl = libvlc_media_get_mrl (m);
    assert (mrl);

    const char *file = strrchr (mrl, FILE_SEPARATOR);
    assert (file);
    file++;
    log ("subitem_added, file: %s\n", file);

    for (unsigned i = 0; i < TEST_SUBITEMS_COUNT; ++i)
    {
        if (strcmp (test_media_subitems_list[i].file, file) == 0)
        {
            assert (!subitems_found[i]);
            assert (libvlc_media_get_type(m) == test_media_subitems_list[i].type);
            subitems_found[i] = true;
        }
    }
    free (mrl);
#undef FILE_SEPARATOR
}

232 233
static void test_media_subitems_media(libvlc_media_t *media, bool play,
                                      bool b_items_expected)
234 235 236 237 238 239 240 241 242 243 244 245
{
    libvlc_media_add_option(media, ":ignore-filetypes= ");

    bool subitems_found[TEST_SUBITEMS_COUNT] = { 0 };
    vlc_sem_t sem;
    vlc_sem_init (&sem, 0);

    libvlc_event_manager_t *em = libvlc_media_event_manager (media);
    libvlc_event_attach (em, libvlc_MediaSubItemAdded, subitem_added, subitems_found);

    if (play)
    {
246 247 248 249 250
        /* XXX: libvlc_media_parse_with_options won't work with fd, since it
         * won't be preparsed because fd:// is an unknown type, so play the
         * file to force parsing. */
        libvlc_event_attach (em, libvlc_MediaSubItemTreeAdded, subitem_parse_ended, &sem);

251 252 253 254 255 256 257 258
        libvlc_media_player_t *mp = libvlc_media_player_new_from_media (media);
        assert (mp);
        assert (libvlc_media_player_play (mp) != -1);
        vlc_sem_wait (&sem);
        libvlc_media_player_release (mp);
    }
    else
    {
259
        libvlc_event_attach (em, libvlc_MediaParsedChanged, subitem_parse_ended, &sem);
260

261
        int i_ret = libvlc_media_parse_with_options(media, libvlc_media_parse_local, -1);
262
        assert(i_ret == 0);
263 264 265 266 267
        vlc_sem_wait (&sem);
    }

    vlc_sem_destroy (&sem);

268 269 270
    if (!b_items_expected)
        return;

271 272 273 274 275 276 277
    for (unsigned i = 0; i < TEST_SUBITEMS_COUNT; ++i)
    {
        log ("test if %s was added\n", test_media_subitems_list[i].file);
        assert (subitems_found[i]);
    }
}

278
static void test_media_subitems(libvlc_instance_t *vlc)
279 280 281 282 283 284 285 286
{
    const char *subitems_path = SRCDIR"/samples/subitems";

    libvlc_media_t *media;

    log ("Testing media_subitems: path: '%s'\n", subitems_path);
    media = libvlc_media_new_path (vlc, subitems_path);
    assert (media != NULL);
287
    test_media_subitems_media (media, false, true);
288 289
    libvlc_media_release (media);

290
    #define NB_LOCATIONS 2
291 292
    char *subitems_realpath = realpath (subitems_path, NULL);
    assert (subitems_realpath != NULL);
293
    const char *schemes[NB_LOCATIONS] = { "file://", "dir://" };
294 295 296 297 298 299 300
    for (unsigned i = 0; i < NB_LOCATIONS; ++i)
    {
        char *location;
        assert (asprintf (&location, "%s%s", schemes[i], subitems_realpath) != -1);
        log ("Testing media_subitems: location: '%s'\n", location);
        media = libvlc_media_new_location (vlc, location);
        assert (media != NULL);
301
        test_media_subitems_media (media, false, true);
302 303 304 305 306
        free (location);
        libvlc_media_release (media);
    }
    free (subitems_realpath);

307 308
#ifdef HAVE_OPENAT
    /* listing directory via a fd works only if HAVE_OPENAT is defined */
309 310 311 312 313
    int fd = open (subitems_path, O_RDONLY);
    log ("Testing media_subitems: fd: '%d'\n", fd);
    assert (fd >= 0);
    media = libvlc_media_new_fd (vlc, fd);
    assert (media != NULL);
314
    test_media_subitems_media (media, true, true);
315
    libvlc_media_release (media);
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
316
    vlc_close (fd);
317 318 319
#else
#warning not testing subitems list via a fd location
#endif
320

321 322 323 324 325
    log ("Testing media_subitems failure\n");
    media = libvlc_media_new_location (vlc, "wrongfile://test");
    assert (media != NULL);
    test_media_subitems_media (media, false, false);
    libvlc_media_release (media);
326 327
}

328
int main(int i_argc, char *ppsz_argv[])
Pierre's avatar
Pierre committed
329 330 331
{
    test_init();

332 333 334 335
    libvlc_instance_t *vlc = libvlc_new (test_defaults_nargs,
                                         test_defaults_args);
    assert (vlc != NULL);

336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351
    char *psz_test_arg = i_argc > 1 ? ppsz_argv[1] : NULL;
    if (psz_test_arg != NULL)
    {
        alarm(0);
        const char *psz_test_url;
        const char *psz_test_path;
        if (strstr(psz_test_arg, "://") != NULL)
        {
            psz_test_url = psz_test_arg;
            psz_test_path = NULL;
        }
        else
        {
            psz_test_url = NULL;
            psz_test_path = psz_test_arg;
        }
352 353
        test_media_preparsed (vlc, psz_test_path, psz_test_url,
                              libvlc_media_parse_network,
354 355 356 357
                              libvlc_media_parsed_status_done);
        return 0;
    }

358
    test_media_preparsed (vlc, SRCDIR"/samples/image.jpg", NULL,
359
                          libvlc_media_parse_local,
360
                          libvlc_media_parsed_status_done);
361
    test_media_preparsed (vlc, NULL, "http://parsing_should_be_skipped.org/video.mp4",
362
                          libvlc_media_parse_local,
363
                          libvlc_media_parsed_status_skipped);
364
    test_media_preparsed (vlc, NULL, "unknown://parsing_should_be_skipped.org/video.mp4",
365
                          libvlc_media_parse_local,
366
                          libvlc_media_parsed_status_skipped);
367 368
    test_media_subitems (vlc);

369 370 371 372 373 374 375 376
    /* Testing libvlc_MetadataRequest timeout and libvlc_MetadataCancel. For
     * that, we need to create a local input_item_t based on a pipe. There is
     * no way to do that with a libvlc_media_t, that's why we don't use
     * libvlc_media_parse*() */

    test_input_metadata_timeout (vlc, 100, 0);
    test_input_metadata_timeout (vlc, 0, 100);

377
    libvlc_release (vlc);
Pierre's avatar
Pierre committed
378 379 380

    return 0;
}