diff --git a/Cargo.lock b/Cargo.lock index 4faee7bf..f1a13e1b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -525,6 +525,17 @@ dependencies = [ "x11-dl 2.18.3 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "gobject-subclass" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "glib 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "glib-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "gobject-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "gobject-sys" version = "0.7.0" @@ -535,6 +546,24 @@ dependencies = [ "pkg-config 0.3.12 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "gst-plugin" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "byteorder 1.2.4 (registry+https://github.com/rust-lang/crates.io-index)", + "glib 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "glib-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "gobject-subclass 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "gobject-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "gstreamer 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", + "gstreamer-base 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", + "gstreamer-base-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "gstreamer-sys 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "gstreamer" version = "0.12.0" @@ -545,7 +574,7 @@ dependencies = [ "glib 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "glib-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "gobject-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "gstreamer-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "gstreamer-sys 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", "muldiv 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -565,7 +594,7 @@ dependencies = [ "gstreamer-app-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "gstreamer-base 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", "gstreamer-base-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "gstreamer-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "gstreamer-sys 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -576,7 +605,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "glib-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "gstreamer-base-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "gstreamer-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "gstreamer-sys 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", "pkg-config 0.3.12 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -593,7 +622,7 @@ dependencies = [ "gobject-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "gstreamer 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", "gstreamer-audio-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "gstreamer-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "gstreamer-sys 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -604,7 +633,7 @@ dependencies = [ "glib-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "gobject-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "gstreamer-base-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "gstreamer-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "gstreamer-sys 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", "pkg-config 0.3.12 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -620,7 +649,7 @@ dependencies = [ "gobject-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "gstreamer 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", "gstreamer-base-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "gstreamer-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "gstreamer-sys 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -630,7 +659,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "glib-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "gobject-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "gstreamer-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "gstreamer-sys 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", "pkg-config 0.3.12 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -646,7 +675,7 @@ dependencies = [ "gobject-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "gstreamer 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", "gstreamer-player-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "gstreamer-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "gstreamer-sys 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", "gstreamer-video 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -658,7 +687,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "glib-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "gobject-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "gstreamer-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "gstreamer-sys 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", "gstreamer-video-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", "pkg-config 0.3.12 (registry+https://github.com/rust-lang/crates.io-index)", @@ -666,7 +695,7 @@ dependencies = [ [[package]] name = "gstreamer-sys" -version = "0.6.0" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "glib-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -687,7 +716,7 @@ dependencies = [ "gstreamer 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", "gstreamer-base 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", "gstreamer-base-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "gstreamer-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "gstreamer-sys 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", "gstreamer-video-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -700,7 +729,7 @@ dependencies = [ "glib-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "gobject-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "gstreamer-base-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "gstreamer-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "gstreamer-sys 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", "pkg-config 0.3.12 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -713,6 +742,16 @@ dependencies = [ "quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "idna" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-normalization 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "iovec" version = "0.1.2" @@ -835,6 +874,11 @@ dependencies = [ "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "matches" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "memchr" version = "2.0.1" @@ -1269,15 +1313,21 @@ version = "0.1.0" dependencies = [ "byte-slice-cast 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "glib 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "glib-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "gobject-subclass 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "gobject-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "gst-plugin 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "gstreamer 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", "gstreamer-app 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", "gstreamer-audio 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", "gstreamer-player 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", + "gstreamer-sys 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", "gstreamer-video 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", "ipc-channel 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "regex 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "servo-media-audio 0.1.0", "servo-media-player 0.1.0", + "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)", "zip 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1438,6 +1488,19 @@ name = "ucd-util" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "unicode-bidi" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "unicode-normalization" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "unicode-xid" version = "0.1.0" @@ -1451,6 +1514,16 @@ dependencies = [ "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "url" +version = "1.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "utf8-ranges" version = "1.0.0" @@ -1751,7 +1824,9 @@ dependencies = [ "checksum glib 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "740f7fda8dde5f5e3944dabdb4a73ac6094a8a7fdf0af377468e98ca93733e61" "checksum glib-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3573351e846caed9f11207b275cd67bc07f0c2c94fb628e5d7c92ca056c7882d" "checksum glutin 0.19.0 (registry+https://github.com/rust-lang/crates.io-index)" = "535c6eda58adbb227604b2db10a022ffd6339d7ea3e970f338e7d98aeb24fcc3" +"checksum gobject-subclass 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "23a365ac97171d914fc0f2ccf86f3a05ae4ee870427eee9c82f6bb95bbf201b6" "checksum gobject-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "08475e4a08f27e6e2287005950114735ed61cec2cb8c1187682a5aec8c69b715" +"checksum gst-plugin 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c0211cec5228a72501a912a45b43d5450db7bc20d14e68631786ac8270908b8d" "checksum gstreamer 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "df451f98ea8b987b5fc1b647b9f038ca6ea106b08c3bccc1ef3126d4f0a687c1" "checksum gstreamer-app 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3f4f865cf7f22c66907372a2e3b0f0ced3d3fedab823641d6667d2568be71408" "checksum gstreamer-app-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f0b8319fe7a8a015412a76a56b248a3c68561a39225a3fa0fcbb58aab8e12392" @@ -1761,10 +1836,11 @@ dependencies = [ "checksum gstreamer-base-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1eb57a7d013604ab7af2b843b62b13b8fb30f22d066919f7e198f528c3296cd0" "checksum gstreamer-player 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1144c6c5c3af25dd1f89b4f9d2762f1c2d8789e65cdc79e2451dd24350d84dd2" "checksum gstreamer-player-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f0e642cb58d3733e2724def7186101bb00144fc97d45b2c379eba6d0c0662dec" -"checksum gstreamer-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "18e3ff41a9e0bc96d345f25b1dd00cfda31edcab2aa19535af5312fdb80d062b" +"checksum gstreamer-sys 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3aec69f30ab98a7b0cf4a29179eeffa8a1e7d6062f5ee55e9792917cb0980bda" "checksum gstreamer-video 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0c1f04816d7e183714830da26274f97e7aeff09ae6641058538d21443b4ec07d" "checksum gstreamer-video-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d0e2efb301a0b94fa4af503122faa04247085936dd888fd59fa4e21eab3cbd37" "checksum humantime 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0484fda3e7007f2a4a0d9c3a703ca38c71c54c55602ce4660c419fd32e188c9e" +"checksum idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "38f09e0f0b1fb55fdee1f17470ad800da77af5186a1a76c026b679358b7e844e" "checksum iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dbe6e417e7d0975db6512b90796e8ce223145ac4e33c377e4a42882a0e88bb08" "checksum ipc-channel 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "dd75debad4ffd295c00c6e3634d254df30050b0837a85e5cd039ac424365f24a" "checksum jni 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "cffc930ce6a38a4013e30567b559bdc79f601013ba4a81e65dbda9207263efd4" @@ -1780,6 +1856,7 @@ dependencies = [ "checksum log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e19e8d5c34a3e0e2223db8e060f9e8264aeeb5c5fc64a4ee9965c062211c024b" "checksum log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "d4fcce5fa49cc693c312001daf1d13411c4a5283796bac1084299ea3e567113f" "checksum malloc_buf 0.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb" +"checksum matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" "checksum memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "796fba70e76612589ed2ce7f45282f5af869e0fdd7cc6199fa1aa1f1d591ba9d" "checksum memmap 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e2ffa2c986de11a9df78620c01eeaaf27d94d3ff02bf81bfcca953102dd0c6ff" "checksum memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0f9dc261e2b62d7a622bf416ea3c5245cdd5d9a7fcc428c0d06804dfce1775b3" @@ -1843,8 +1920,11 @@ dependencies = [ "checksum thread_profiler 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "5920e77802b177479ab5795767fa48e68f61b2f516c2ac0041e2978dd8efe483" "checksum time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "d825be0eb33fda1a7e68012d51e9c7f451dc1a69391e7fdc197060bb8c56667b" "checksum ucd-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fd2be2d6639d0f8fe6cdda291ad456e23629558d466e2789d2c3e9892bda285d" +"checksum unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5" +"checksum unicode-normalization 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "6a0180bc61fc5a987082bfa111f4cc95c4caff7f9799f3e46df09163a937aa25" "checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" "checksum unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56" +"checksum url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dd4e7c0d531266369519a4aa4f399d748bd37043b00bde1e4ff1f60a120b355a" "checksum utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "662fab6525a98beff2921d7f61a39e7d59e0b425ebc7d0d9e66d316e55124122" "checksum uuid 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e1436e58182935dcd9ce0add9ea0b558e8a87befe01c1a301e6020aeb0876363" "checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" diff --git a/Cargo.toml b/Cargo.toml index ad4c9b37..cded2571 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,6 +6,5 @@ members = [ "examples/android/lib", "player", "servo-media", - "servo-media-derive" + "servo-media-derive", ] -license = "MPL-2.0" diff --git a/backends/gstreamer/Cargo.toml b/backends/gstreamer/Cargo.toml index 3347dcbd..7bbfe285 100644 --- a/backends/gstreamer/Cargo.toml +++ b/backends/gstreamer/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "servo-media-gstreamer" version = "0.1.0" -authors = ["Manish Goregaokar "] +authors = ["The Servo Project Developers"] [build-dependencies] regex = "1.0" @@ -13,6 +13,18 @@ version = "0.2" [dependencies.glib] version = "0.6" +[dependencies.glib-sys] +version = "0.7" + +[dependencies.gobject-subclass] +version = "0.2.1" + +[dependencies.gobject-sys] +version = "0.7" + +[dependencies.gst-plugin] +version = "0.3.1" + [dependencies.gstreamer] version = "0.12" @@ -25,6 +37,9 @@ version = "0.12" [dependencies.gstreamer-player] version = "0.12" +[dependencies.gstreamer-sys] +version = "0.6.1" + [dependencies.gstreamer-video] version = "0.12" @@ -36,3 +51,6 @@ path = "../../audio" [dependencies.servo-media-player] path = "../../player" + +[dependencies.url] +version = "1.7.2" diff --git a/backends/gstreamer/src/lib.rs b/backends/gstreamer/src/lib.rs index 59662bdb..7085d774 100644 --- a/backends/gstreamer/src/lib.rs +++ b/backends/gstreamer/src/lib.rs @@ -1,15 +1,22 @@ extern crate byte_slice_cast; +#[macro_use] extern crate glib; +extern crate glib_sys as glib_ffi; +extern crate gobject_sys as gobject_ffi; +#[macro_use] +extern crate gobject_subclass; +extern crate gst_plugin; extern crate gstreamer as gst; extern crate gstreamer_app as gst_app; extern crate gstreamer_audio as gst_audio; extern crate gstreamer_player as gst_player; +extern crate gstreamer_sys as gst_ffi; extern crate gstreamer_video as gst_video; extern crate ipc_channel; - extern crate servo_media_audio; extern crate servo_media_player; +extern crate url; use servo_media_audio::sink::AudioSinkError; use servo_media_audio::AudioBackend; @@ -18,6 +25,7 @@ use servo_media_player::PlayerBackend; pub mod audio_decoder; pub mod audio_sink; pub mod player; +mod source; pub struct GStreamerBackend; diff --git a/backends/gstreamer/src/player.rs b/backends/gstreamer/src/player.rs index 712b9845..218af738 100644 --- a/backends/gstreamer/src/player.rs +++ b/backends/gstreamer/src/player.rs @@ -1,6 +1,7 @@ use glib; use glib::*; -use gst; +use gst::GenericFormattedValue::Percent; +use gst::{self, ElementExtManual}; use gst_app::{self, AppSrcCallbacks, AppStreamType}; use gst_player; use gst_player::{PlayerMediaInfo, PlayerStreamInfoExt}; @@ -9,14 +10,16 @@ use ipc_channel::ipc::IpcSender; use servo_media_player::frame::{Frame, FrameRenderer}; use servo_media_player::metadata::Metadata; use servo_media_player::{PlaybackState, Player, PlayerError, PlayerEvent, StreamType}; +use source::{register_servo_src, ServoSrc}; use std::cell::RefCell; use std::error::Error; +use std::ops::Range; use std::sync::mpsc; use std::sync::{Arc, Mutex, Once}; use std::time; use std::u64; -const MAX_SRC_QUEUE_SIZE: u64 = 50 * 1024 * 1024; // 50 MB. +const MAX_BUFFER_SIZE: i32 = 500 * 1024 * 1024; fn frame_from_sample(sample: &gst::Sample) -> Result { let buffer = sample.get_buffer().ok_or_else(|| ())?; @@ -77,6 +80,7 @@ fn metadata_from_media_info(media_info: &PlayerMediaInfo) -> Result Result, + servosrc: Option, appsink: gst_app::AppSink, input_size: u64, rate: f64, @@ -104,11 +109,11 @@ impl PlayerInner { // Set input_size to proxy its value, since it // could be set by the user before calling .setup(). self.input_size = size; - if let Some(ref mut appsrc) = self.appsrc { + if let Some(ref mut servosrc) = self.servosrc { if size > 0 { - appsrc.set_size(size as i64); + servosrc.set_size(size as i64); } else { - appsrc.set_size(-1); // live source + servosrc.set_size(-1); // live source } } Ok(()) @@ -137,8 +142,8 @@ impl PlayerInner { // Set stream_type to proxy its value, since it // could be set by the user before calling .setup(). self.stream_type = Some(type_); - if let Some(ref appsrc) = self.appsrc { - appsrc.set_stream_type(type_); + if let Some(ref servosrc) = self.servosrc { + servosrc.set_stream_type(type_); } Ok(()) } @@ -151,7 +156,7 @@ impl PlayerInner { pub fn stop(&mut self) -> Result<(), PlayerError> { self.player.stop(); self.last_metadata = None; - self.appsrc = None; + self.servosrc = None; Ok(()) } @@ -161,8 +166,8 @@ impl PlayerInner { } pub fn end_of_stream(&mut self) -> Result<(), PlayerError> { - if let Some(ref mut appsrc) = self.appsrc { - if appsrc.end_of_stream() == gst::FlowReturn::Ok { + if let Some(ref mut servosrc) = self.servosrc { + if servosrc.end_of_stream() == gst::FlowReturn::Ok { return Ok(()); } } @@ -197,21 +202,50 @@ impl PlayerInner { } pub fn push_data(&mut self, data: Vec) -> Result<(), PlayerError> { - if let Some(ref mut appsrc) = self.appsrc { - if appsrc.get_current_level_bytes() + data.len() as u64 > appsrc.get_max_bytes() { + if let Some(ref mut servosrc) = self.servosrc { + if servosrc.get_current_level_bytes() + data.len() as u64 > servosrc.get_max_bytes() { return Err(PlayerError::EnoughData); } let buffer = gst::Buffer::from_slice(data).ok_or_else(|| PlayerError::BufferPushFailed)?; - if appsrc.push_buffer(buffer) == gst::FlowReturn::Ok { + if servosrc.push_buffer(buffer) == gst::FlowReturn::Ok { return Ok(()); } } Err(PlayerError::BufferPushFailed) } - pub fn set_app_src(&mut self, appsrc: gst_app::AppSrc) { - self.appsrc = Some(appsrc); + pub fn set_src(&mut self, servosrc: ServoSrc) { + self.servosrc = Some(servosrc); + } + + pub fn buffered(&mut self) -> Result>, PlayerError> { + let mut result = vec![]; + if let Some(ref metadata) = self.last_metadata { + if let Some(ref duration) = metadata.duration { + let pipeline = self.player.get_pipeline(); + let mut buffering = gst::Query::new_buffering(gst::Format::Percent); + if pipeline.query(&mut buffering) { + let ranges = buffering.get_ranges(); + for i in 0..ranges.len() { + let start = ranges[i].0; + let end = ranges[i].1; + let start = (if let Percent(start) = start { + start.unwrap() + } else { + 0 + } * duration.as_secs() as u32 / (gst::FORMAT_PERCENT_MAX)) as f64; + let end = (if let Percent(end) = end { + end.unwrap() + } else { + 0 + } * duration.as_secs() as u32 / (gst::FORMAT_PERCENT_MAX)) as f64; + result.push(Range { start, end }); + } + } + } + } + Ok(result) } } @@ -298,11 +332,58 @@ impl GStreamerPlayer { } } + if !register_servo_src() { + return Err(PlayerError::Backend( + "servosrc registration error".to_owned(), + )); + } + let player = gst_player::Player::new( /* video renderer */ None, /* signal dispatcher */ None, ); - // Set position interval update to 0.5 seconds. + let pipeline = player.get_pipeline(); + + // Set player to perform progressive downloading. This will make the + // player store the downloaded media in a local temporary file for + // faster playback of already-downloaded chunks. + let flags = pipeline + .get_property("flags") + .map_err(|e| PlayerError::Backend(e.to_string()))?; + let flags_class = match FlagsClass::new(flags.type_()) { + Some(flags) => flags, + None => { + return Err(PlayerError::Backend( + "FlagsClass creation failed".to_owned(), + )) + } + }; + let flags_class = match flags_class.builder_with_value(flags) { + Some(class) => class, + None => { + return Err(PlayerError::Backend( + "FlagsClass creation failed".to_owned(), + )) + } + }; + let flags = match flags_class.set_by_nick("download").build() { + Some(flags) => flags, + None => { + return Err(PlayerError::Backend( + "FlagsClass creation failed".to_owned(), + )) + } + }; + pipeline + .set_property("flags", &flags) + .map_err(|e| PlayerError::Backend(e.to_string()))?; + + // Set max size for the player buffer. + pipeline + .set_property("buffer-size", &MAX_BUFFER_SIZE) + .map_err(|e| PlayerError::Backend(e.to_string()))?; + + // Set player position interval update to 0.5 seconds. let mut config = player.get_config(); config.set_position_update_interval(500u32); player @@ -311,7 +392,6 @@ impl GStreamerPlayer { let video_sink = gst::ElementFactory::make("appsink", None) .ok_or(PlayerError::Backend("appsink creation failed".to_owned()))?; - let pipeline = player.get_pipeline(); pipeline .set_property("video-sink", &video_sink.to_value()) .map_err(|e| PlayerError::Backend(e.to_string()))?; @@ -332,12 +412,12 @@ impl GStreamerPlayer { // The estimated version for the fix is 1.14.5 / 1.15.1. // https://github.com/servo/servo/issues/22010#issuecomment-432599657 player - .set_property("uri", &Value::from("appsrc://")) + .set_property("uri", &Value::from("servosrc://")) .map_err(|e| PlayerError::Backend(e.to_string()))?; *self.inner.borrow_mut() = Some(Arc::new(Mutex::new(PlayerInner { player, - appsrc: None, + servosrc: None, appsink: video_sink, input_size: 0, rate: 1.0, @@ -348,6 +428,7 @@ impl GStreamerPlayer { let inner = self.inner.borrow(); let inner = inner.as_ref().unwrap(); let observers = self.observers.clone(); + // Handle `end-of-stream` signal. inner .lock() .unwrap() @@ -357,17 +438,20 @@ impl GStreamerPlayer { }); let observers = self.observers.clone(); + // Handle `error` signal inner.lock().unwrap().player.connect_error(move |_, _| { observers.lock().unwrap().notify(PlayerEvent::Error); }); let observers = self.observers.clone(); + // Handle `state-changed` signal. inner .lock() .unwrap() .player .connect_state_changed(move |_, player_state| { let state = match player_state { + gst_player::PlayerState::Buffering => Some(PlaybackState::Buffering), gst_player::PlayerState::Stopped => Some(PlaybackState::Stopped), gst_player::PlayerState::Paused => Some(PlaybackState::Paused), gst_player::PlayerState::Playing => Some(PlaybackState::Playing), @@ -382,6 +466,7 @@ impl GStreamerPlayer { }); let observers = self.observers.clone(); + // Handle `position-update` signal. inner .lock() .unwrap() @@ -396,6 +481,7 @@ impl GStreamerPlayer { }); let observers = self.observers.clone(); + // Handle `seek-done` signal. inner .lock() .unwrap() @@ -409,6 +495,7 @@ impl GStreamerPlayer { } }); + // Handle `media-info-updated` signal. let inner_clone = inner.clone(); let observers = self.observers.clone(); inner @@ -431,6 +518,7 @@ impl GStreamerPlayer { } }); + // Handle `duration-changed` signal. let inner_clone = inner.clone(); let observers = self.observers.clone(); inner @@ -472,6 +560,7 @@ impl GStreamerPlayer { let observers = self.observers.clone(); let renderers = self.renderers.clone(); + // Set appsink callbacks. inner.lock().unwrap().appsink.set_callbacks( gst_app::AppSinkCallbacks::new() .new_preroll(|_| gst::FlowReturn::Ok) @@ -504,31 +593,29 @@ impl GStreamerPlayer { let is_ready_clone = self.is_ready.clone(); let observers = self.observers.clone(); let connect_result = pipeline.connect("source-setup", false, move |args| { - let source = args[1].get::(); - if source.is_none() { - let _ = sender - .lock() - .unwrap() - .send(Err(PlayerError::Backend("Source setup failed".to_owned()))); - return None; - } - let source = source.unwrap(); + let source = match args[1].get::() { + Some(source) => source, + None => { + let _ = sender + .lock() + .unwrap() + .send(Err(PlayerError::Backend("Source setup failed".to_owned()))); + return None; + } + }; + let mut inner = inner_clone.lock().unwrap(); - let appsrc = source + let servosrc = source .clone() - .dynamic_cast::() - .expect("Source element is expected to be an appsrc!"); - - appsrc.set_max_bytes(MAX_SRC_QUEUE_SIZE); - appsrc.set_property_block(false); + .dynamic_cast::() + .expect("Source element is expected to be a servosrc!"); - appsrc.set_property_format(gst::Format::Bytes); if inner.input_size > 0 { - appsrc.set_size(inner.input_size as i64); + servosrc.set_size(inner.input_size as i64); } if let Some(ref stream_type) = inner.stream_type { - appsrc.set_stream_type(*stream_type); + servosrc.set_stream_type(*stream_type); } let sender_clone = sender.clone(); @@ -536,7 +623,7 @@ impl GStreamerPlayer { let observers_ = observers.clone(); let observers__ = observers.clone(); let observers___ = observers.clone(); - appsrc.set_callbacks( + servosrc.set_callbacks( AppSrcCallbacks::new() .need_data(move |_, _| { // We block the caller of the setup method until we get @@ -562,7 +649,7 @@ impl GStreamerPlayer { .build(), ); - inner.set_app_src(appsrc); + inner.set_src(servosrc); None }); @@ -594,8 +681,8 @@ impl GStreamerPlayer { } macro_rules! inner_player_proxy { - ($fn_name:ident) => ( - fn $fn_name(&self) -> Result<(), PlayerError> { + ($fn_name:ident, $return_type:ty) => ( + fn $fn_name(&self) -> Result<$return_type, PlayerError> { self.setup()?; let inner = self.inner.borrow(); let mut inner = inner.as_ref().unwrap().lock().unwrap(); @@ -614,16 +701,17 @@ macro_rules! inner_player_proxy { } impl Player for GStreamerPlayer { - inner_player_proxy!(play); - inner_player_proxy!(pause); - inner_player_proxy!(stop); - inner_player_proxy!(end_of_stream); + inner_player_proxy!(play, ()); + inner_player_proxy!(pause, ()); + inner_player_proxy!(stop, ()); + inner_player_proxy!(end_of_stream, ()); inner_player_proxy!(set_input_size, size, u64); inner_player_proxy!(set_rate, rate, f64); inner_player_proxy!(set_stream_type, type_, StreamType); inner_player_proxy!(push_data, data, Vec); inner_player_proxy!(seek, time, f64); inner_player_proxy!(set_volume, value, f64); + inner_player_proxy!(buffered, Vec>); fn register_event_handler(&self, sender: IpcSender) { self.observers.lock().unwrap().register(sender); diff --git a/backends/gstreamer/src/source.rs b/backends/gstreamer/src/source.rs new file mode 100644 index 00000000..a54eb682 --- /dev/null +++ b/backends/gstreamer/src/source.rs @@ -0,0 +1,231 @@ +use glib; +use glib::translate::*; +use glib_ffi; +use gobject_ffi; +use gobject_subclass::object::*; +use gst; +use gst::query::{QueryRef, QueryView}; +use gst_app::{self, AppSrc, AppSrcCallbacks, AppStreamType}; +use gst_ffi; +use gst_plugin::bin::*; +use gst_plugin::element::ElementImpl; +use gst_plugin::object::ElementInstanceStruct; +use gst_plugin::uri_handler::{register_uri_handler, URIHandlerImpl, URIHandlerImplStatic}; +use std::mem; +use std::ptr; +use std::sync::{Once, ONCE_INIT}; +use url::Url; + +const MAX_SRC_QUEUE_SIZE: u64 = 50 * 1024 * 1024; // 50 MB. + +mod imp { + use super::*; + use glib::prelude::*; + use gst::ElementExt; + use gst_plugin::element::ElementClassExt; + + macro_rules! inner_appsrc_proxy { + ($fn_name:ident, $return_type:ty) => ( + pub fn $fn_name(&self) -> $return_type { + self.appsrc.$fn_name() + } + ); + + ($fn_name:ident, $arg1:ident, $arg1_type:ty, $return_type:ty) => ( + pub fn $fn_name(&self, $arg1: $arg1_type) -> $return_type { + self.appsrc.$fn_name($arg1) + } + ) + } + + pub struct ServoSrc { + appsrc: gst_app::AppSrc, + } + + impl ServoSrc { + fn init(_bin: &Bin) -> Box> { + let appsrc = gst::ElementFactory::make("appsrc", None) + .map(|elem| elem.downcast::().unwrap()) + .expect("Could not create appsrc element"); + + appsrc.set_max_bytes(MAX_SRC_QUEUE_SIZE); + appsrc.set_property_block(false); + appsrc.set_property_format(gst::Format::Bytes); + + // At this point the bin is not completely created, + // so we cannot add anything to it yet. + // We have to wait until ObjectImpl::constructed. + Box::new(Self { appsrc }) + } + + pub fn get_type() -> glib::Type { + static ONCE: Once = ONCE_INIT; + static mut TYPE: glib::Type = glib::Type::Invalid; + + ONCE.call_once(|| { + let t = register_type(ServoSrcStatic); + unsafe { + TYPE = t; + } + }); + + unsafe { TYPE } + } + + fn class_init(klass: &mut BinClass) { + klass.set_metadata( + "Servo Media Source", + "Source/Audio/Video", + "Feed player with media data", + "Servo developers", + ); + } + + pub fn set_size(&self, size: i64) { + if self.appsrc.get_size() != -1 { + return; + } + self.appsrc.set_size(size); + } + + inner_appsrc_proxy!(end_of_stream, gst::FlowReturn); + inner_appsrc_proxy!(get_current_level_bytes, u64); + inner_appsrc_proxy!(get_max_bytes, u64); + inner_appsrc_proxy!(push_buffer, buffer, gst::Buffer, gst::FlowReturn); + inner_appsrc_proxy!(set_callbacks, callbacks, AppSrcCallbacks, ()); + inner_appsrc_proxy!(set_stream_type, type_, AppStreamType, ()); + } + + impl ObjectImpl for ServoSrc { + fn constructed(&self, bin: &Bin) { + bin.parent_constructed(); + + self.add_element(bin, &self.appsrc.clone().upcast()); + + let pad = self + .appsrc + .get_static_pad("src") + .expect("Could not get src pad"); + + let ghost_pad = + gst::GhostPad::new("src", &pad).expect("Could not create src ghost pad"); + + bin.add_pad(&ghost_pad) + .expect("Could not add src ghost pad to bin"); + } + } + + impl ElementImpl for ServoSrc { + fn query(&self, _element: &Bin, query: &mut QueryRef) -> bool { + // In order to make buffering/downloading work as we want, apart from + // setting the appropriate flags on the player playbin, + // the source needs to either: + // + // 1. be an http, mms, etc. scheme + // 2. report that it is "bandwidth limited". + // + // 1. is not straightforward because we are using a servosrc scheme for now. + // This may change in the future if we end up handling http/https/data + // URIs, which is what WebKit does. + // + // For 2. we need to make servosrc handle the scheduling properties query + // to report that it "is bandwidth limited". + if let QueryView::Scheduling(ref mut query) = query.view_mut() { + query.set( + gst::SchedulingFlags::SEQUENTIAL + | gst::SchedulingFlags::BANDWIDTH_LIMITED, + 1, + -1, + 0, + ); + query.add_scheduling_modes(&[gst::PadMode::Push]); + return true; + } + false + } + } + + impl BinImpl for ServoSrc {} + + impl URIHandlerImpl for ServoSrc { + fn get_uri(&self, _element: &gst::URIHandler) -> Option { + Some("servosrc://".to_string()) + } + + fn set_uri( + &self, + _element: &gst::URIHandler, + uri: Option, + ) -> Result<(), glib::Error> { + if let Some(ref uri) = uri { + if let Ok(uri) = Url::parse(uri) { + if uri.scheme() == "servosrc" { + return Ok(()) + } + } + } + Err(glib::Error::new( + gst::URIError::BadUri, + format!("Invalid URI '{:?}'", uri,).as_str(), + )) + } + } + + pub struct ServoSrcStatic; + + impl ImplTypeStatic for ServoSrcStatic { + fn get_name(&self) -> &str { + "ServoSrc" + } + + fn new(&self, bin: &Bin) -> Box> { + ServoSrc::init(bin) + } + + fn class_init(&self, klass: &mut BinClass) { + ServoSrc::class_init(klass); + } + + fn type_init(&self, token: &TypeInitToken, type_: glib::Type) { + register_uri_handler(token, type_, self); + } + } + + impl URIHandlerImplStatic for ServoSrcStatic { + fn get_impl<'a>(&self, imp: &'a Box>) -> &'a URIHandlerImpl { + imp.downcast_ref::().unwrap() + } + + fn get_type(&self) -> gst::URIType { + gst::URIType::Src + } + + fn get_protocols(&self) -> Vec { + vec!["servosrc".into()] + } + } +} + +glib_wrapper! { + pub struct ServoSrc(Object): + [Bin => ElementInstanceStruct, + gst::Bin => gst_ffi::GstBin, + gst::Element => gst_ffi::GstElement, + gst::Object => gst_ffi::GstObject]; + + match fn { + get_type => || imp::ServoSrc::get_type().to_glib(), + } +} + +gobject_subclass_deref!(ServoSrc, Bin); + +unsafe impl Send for ServoSrc {} +unsafe impl Sync for ServoSrc {} + +impl ServoSrc {} + +pub fn register_servo_src() -> bool { + let type_ = imp::ServoSrc::get_type(); + gst::Element::register(None, "servosrc", 0, type_) +} diff --git a/player/src/lib.rs b/player/src/lib.rs index 3f798b90..23dfb580 100644 --- a/player/src/lib.rs +++ b/player/src/lib.rs @@ -6,12 +6,13 @@ pub mod frame; pub mod metadata; use ipc_channel::ipc::IpcSender; +use std::ops::Range; use std::sync::{Arc, Mutex}; #[derive(Clone, Debug, Deserialize, Serialize)] pub enum PlaybackState { Stopped, - // Buffering, + Buffering, Paused, Playing, } @@ -76,6 +77,8 @@ pub trait Player: Send { fn set_stream_type(&self, type_: StreamType) -> Result<(), PlayerError>; fn push_data(&self, data: Vec) -> Result<(), PlayerError>; fn end_of_stream(&self) -> Result<(), PlayerError>; + /// Get the list of time ranges in seconds that have been buffered. + fn buffered(&self) -> Result>, PlayerError>; } pub struct DummyPlayer {} @@ -116,6 +119,9 @@ impl Player for DummyPlayer { fn end_of_stream(&self) -> Result<(), PlayerError> { Ok(()) } + fn buffered(&self) -> Result>, PlayerError> { + Ok(vec![]) + } } pub trait PlayerBackend { diff --git a/player/src/metadata.rs b/player/src/metadata.rs index 376ab26f..912cef33 100644 --- a/player/src/metadata.rs +++ b/player/src/metadata.rs @@ -10,4 +10,6 @@ pub struct Metadata { // TODO: Might be nice to move width and height along with each video track. pub video_tracks: Vec, pub audio_tracks: Vec, + // Whether the media comes from a live source or not. + pub is_live: bool, }