servo: Merge #12186 - Implement video-metadata check (from GuillaumeGomez:video-metadata); r=larsbergstrom,jdm,KiChjang
authorGuillaume Gomez <guillaume1.gomez@gmail.com>
Fri, 29 Jul 2016 17:46:42 -0500
changeset 388382 1412dadcb1c89ca7acd1ee94d8396d6bf5f7e003
parent 388381 0f4557f79f7ac3e3fa3d061aaf03629daa899cc5
child 388383 60800b3100008abe7509d11022d39d075eae6c04
push id1468
push userasasaki@mozilla.com
push dateMon, 05 Jun 2017 19:31:07 +0000
treeherdermozilla-release@0641fc6ee9d1 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerslarsbergstrom, jdm, KiChjang
servo: Merge #12186 - Implement video-metadata check (from GuillaumeGomez:video-metadata); r=larsbergstrom,jdm,KiChjang Source-Repo: https://github.com/servo/servo Source-Revision: d053fb16f6519726c14ac4580301df4883e4af23
servo/.travis.yml
servo/README.md
servo/appveyor.yml
servo/components/script/Cargo.toml
servo/components/script/dom/bindings/trace.rs
servo/components/script/dom/htmlmediaelement.rs
servo/components/script/lib.rs
servo/components/servo/Cargo.lock
servo/ports/cef/Cargo.lock
--- a/servo/.travis.yml
+++ b/servo/.travis.yml
@@ -31,16 +31,19 @@ matrix:
             - freeglut3-dev
             - gperf
             - libosmesa6-dev
             - libgles2-mesa-dev
             - python-virtualenv
             - xorg-dev
             - ccache
             - libdbus-glib-1-dev
+            - libavformat-dev
+            - libavcodec-dev
+            - libavutil-dev
 
 branches:
   only:
     - master
 
 notifications:
   webhooks:
     - https://buildtimetrend.herokuapp.com/travis
--- a/servo/README.md
+++ b/servo/README.md
@@ -38,30 +38,31 @@ If you've already partially compiled ser
 
 On Debian-based Linuxes:
 
 ``` sh
 sudo apt-get install git curl freeglut3-dev autoconf \
     libfreetype6-dev libgl1-mesa-dri libglib2.0-dev xorg-dev \
     gperf g++ build-essential cmake virtualenv python-pip \
     libssl-dev libbz2-dev libosmesa6-dev libxmu6 libxmu-dev \
-    libglu1-mesa-dev libgles2-mesa-dev libegl1-mesa-dev libdbus-1-dev
+    libglu1-mesa-dev libgles2-mesa-dev libegl1-mesa-dev libdbus-1-dev \
+    libavformat-dev
 ```
 If you are on **Ubuntu 14.04** and encountered errors on installing these dependencies involving `libcheese`, see [#6158](https://github.com/servo/servo/issues/6158) for a workaround.
 
 If `virtualenv` does not exist, try `python-virtualenv`.
 
 On Fedora:
 
 ``` sh
 sudo dnf install curl freeglut-devel libtool gcc-c++ libXi-devel \
     freetype-devel mesa-libGL-devel mesa-libEGL-devel glib2-devel libX11-devel libXrandr-devel gperf \
     fontconfig-devel cabextract ttmkfdir python python-virtualenv python-pip expat-devel \
     rpm-build openssl-devel cmake bzip2-devel libXcursor-devel libXmu-devel mesa-libOSMesa-devel \
-    dbus-devel
+    dbus-devel ffmpeg-devel
 ```
 
 On Arch Linux:
 
 ``` sh
 sudo pacman -S --needed base-devel git python2 python2-virtualenv python2-pip mesa cmake bzip2 libxmu glu pkg-config
 ```
 
@@ -84,17 +85,17 @@ window and update the core libraries and
 downgrate GCC to 5.4, as the GCC6 versions in mingw currently fail to compile some of our
 dependencies. We are upgrading to a gcc-free build on Windows as soon as possible:
 
 ```sh
 pacman -Su
 pacman -Sy git mingw-w64-x86_64-toolchain mingw-w64-x86_64-freetype \
     mingw-w64-x86_64-icu mingw-w64-x86_64-nspr mingw-w64-x86_64-ca-certificates \
     mingw-w64-x86_64-expat mingw-w64-x86_64-cmake tar diffutils patch \
-    patchutils make python2-setuptools
+    patchutils make python2-setuptools mingw-w64-x86_64-ffmpeg
 export GCC_URL=http://repo.msys2.org/mingw/x86_64/mingw-w64-x86_64-gcc
 export GCC_EXT=5.4.0-1-any.pkg.tar.xz
 pacman -U --noconfirm $GCC_URL-$GCC_EXT $GCC_URL-ada-$GCC_EXT \
     $GCC_URL-fortran-$GCC_EXT $GCC_URL-libgfortran-$GCC_EXT $GCC_URL-libs-$GCC_EXT \
     $GCC_URL-objc-$GCC_EXT
 easy_install-2.7 pip virtualenv
 ```
 
--- a/servo/appveyor.yml
+++ b/servo/appveyor.yml
@@ -14,17 +14,17 @@ platform:
 
 cache:
   - .servo -> rust-nightly-date, cargo-nightly-build
   - .cargo -> rust-nightly-date, cargo-nightly-build
 
 install:
   - bash -lc "echo $MSYSTEM; pacman --needed --noconfirm -Sy pacman-mirrors"
   - bash -lc "pacman --noconfirm -Sy"
-  - bash -lc "pacman -Sy --needed --noconfirm git mingw-w64-x86_64-toolchain mingw-w64-x86_64-freetype mingw-w64-x86_64-icu mingw-w64-x86_64-nspr mingw-w64-x86_64-ca-certificates mingw-w64-x86_64-expat mingw-w64-x86_64-cmake tar diffutils patch patchutils make python2-setuptools"
+  - bash -lc "pacman -Sy --needed --noconfirm git mingw-w64-x86_64-toolchain mingw-w64-x86_64-freetype mingw-w64-x86_64-icu mingw-w64-x86_64-nspr mingw-w64-x86_64-ca-certificates mingw-w64-x86_64-expat mingw-w64-x86_64-cmake tar diffutils patch patchutils make python2-setuptools mingw-w64-x86_64-ffmpeg"
   - bash -lc "easy_install-2.7 pip virtualenv"
   - bash -lc "mv /mingw64/bin/python2.exe /mingw64/bin/python2-mingw64.exe"
   - bash -lc "mv /mingw64/bin/python2.7.exe /mingw64/bin/python2.7-mingw64.exe"
   # Downgrade GCC to 5.4.0-1 - https://github.com/servo/servo/issues/12512
   - set GCC_URL=http://repo.msys2.org/mingw/x86_64/mingw-w64-x86_64-gcc
   - set GCC_EXT=5.4.0-1-any.pkg.tar.xz
   - bash -lc "pacman -U --noconfirm $GCC_URL-$GCC_EXT $GCC_URL-ada-$GCC_EXT $GCC_URL-fortran-$GCC_EXT $GCC_URL-libgfortran-$GCC_EXT $GCC_URL-libs-$GCC_EXT $GCC_URL-objc-$GCC_EXT"
 
--- a/servo/components/script/Cargo.toml
+++ b/servo/components/script/Cargo.toml
@@ -12,16 +12,19 @@ name = "script"
 path = "lib.rs"
 
 [features]
 debugmozjs = ['js/debugmozjs']
 
 [target.'cfg(any(target_os = "macos", target_os = "linux", target_os = "windows"))'.dependencies]
 tinyfiledialogs = {git = "https://github.com/jdm/tinyfiledialogs"}
 
+[target.'cfg(not(any(target_os = "android", target_arch = "arm", target_arch = "aarch64")))'.dependencies]
+video-metadata = {git = "https://github.com/GuillaumeGomez/video-metadata-rs"}
+
 [dependencies]
 angle = {git = "https://github.com/servo/angle", branch = "servo"}
 app_units = "0.2.5"
 bitflags = "0.7"
 canvas_traits = {path = "../canvas_traits"}
 caseless = "0.1.0"
 cookie = { version = "0.2.5", features = ["serialize-serde", "serialize-rustc" ] }
 cssparser = {version = "0.5.4", features = ["heap_size", "serde-serialization"]}
--- a/servo/components/script/dom/bindings/trace.rs
+++ b/servo/components/script/dom/bindings/trace.rs
@@ -86,16 +86,17 @@ use std::sync::atomic::{AtomicBool, Atom
 use std::sync::mpsc::{Receiver, Sender};
 use std::time::SystemTime;
 use string_cache::{Atom, Namespace, QualName};
 use style::attr::{AttrIdentifier, AttrValue, LengthOrPercentageOrAuto};
 use style::element_state::*;
 use style::properties::PropertyDeclarationBlock;
 use style::selector_impl::{PseudoElement, ElementSnapshot};
 use style::values::specified::Length;
+use time::Duration;
 use url::Origin as UrlOrigin;
 use url::Url;
 use uuid::Uuid;
 use webrender_traits::{WebGLBufferId, WebGLError, WebGLFramebufferId, WebGLProgramId};
 use webrender_traits::{WebGLRenderbufferId, WebGLShaderId, WebGLTextureId};
 
 /// A trait to allow tracing (only) DOM objects.
 pub trait JSTraceable {
@@ -104,16 +105,18 @@ pub trait JSTraceable {
 }
 
 no_jsmanaged_fields!(CSSError);
 
 no_jsmanaged_fields!(EncodingRef);
 
 no_jsmanaged_fields!(Reflector);
 
+no_jsmanaged_fields!(Duration);
+
 /// Trace a `JSVal`.
 pub fn trace_jsval(tracer: *mut JSTracer, description: &str, val: &Heap<JSVal>) {
     unsafe {
         if !val.get().is_markable() {
             return;
         }
 
         debug!("tracing value {}", description);
--- a/servo/components/script/dom/htmlmediaelement.rs
+++ b/servo/components/script/dom/htmlmediaelement.rs
@@ -30,16 +30,18 @@ use net_traits::{AsyncResponseListener, 
 use network_listener::{NetworkListener, PreInvoke};
 use script_thread::{Runnable, ScriptThread};
 use std::cell::Cell;
 use std::sync::{Arc, Mutex};
 use string_cache::Atom;
 use task_source::TaskSource;
 use time::{self, Timespec, Duration};
 use url::Url;
+#[cfg(not(any(target_os = "android", target_arch = "arm", target_arch = "aarch64")))]
+use video_metadata;
 
 struct HTMLMediaElementContext {
     /// The element that initiated the request.
     elem: Trusted<HTMLMediaElement>,
     /// The response body received to date.
     data: Vec<u8>,
     /// The response metadata received to date.
     metadata: Option<Metadata>,
@@ -70,34 +72,29 @@ impl AsyncResponseListener for HTMLMedia
         if is_failure {
             // Ensure that the element doesn't receive any further notifications
             // of the aborted fetch. The dedicated failure steps will be executed
             // when response_complete runs.
             self.ignore_response = true;
         }
     }
 
-    fn data_available(&mut self, payload: Vec<u8>) {
+    fn data_available(&mut self, mut payload: Vec<u8>) {
         if self.ignore_response {
             return;
         }
 
-        let mut payload = payload;
         self.data.append(&mut payload);
 
         let elem = self.elem.root();
 
         // https://html.spec.whatwg.org/multipage/#media-data-processing-steps-list
         // => "Once enough of the media data has been fetched to determine the duration..."
         if !self.have_metadata {
-            //TODO: actually check if the payload contains the full metadata
-
-            // Step 6
-            elem.change_ready_state(HAVE_METADATA);
-            self.have_metadata = true;
+            self.check_metadata(&elem);
         } else {
             elem.change_ready_state(HAVE_CURRENT_DATA);
         }
 
         // https://html.spec.whatwg.org/multipage/#concept-media-load-resource step 4,
         // => "If mode is remote" step 2
         if time::get_time() > self.next_progress_event {
             elem.queue_fire_simple_event("progress");
@@ -157,29 +154,70 @@ impl HTMLMediaElementContext {
             metadata: None,
             generation_id: elem.generation_id.get(),
             next_progress_event: time::get_time() + Duration::milliseconds(350),
             url: url,
             have_metadata: false,
             ignore_response: false,
         }
     }
+
+    #[cfg(not(any(target_os = "android", target_arch = "arm", target_arch = "aarch64")))]
+    fn check_metadata(&mut self, elem: &HTMLMediaElement) {
+        match video_metadata::get_format_from_slice(&self.data) {
+            Ok(meta) => {
+                let dur = meta.duration.unwrap_or(::std::time::Duration::new(0, 0));
+                *elem.video.borrow_mut() = Some(VideoMedia {
+                    format: format!("{:?}", meta.format),
+                    duration: Duration::seconds(dur.as_secs() as i64) +
+                              Duration::nanoseconds(dur.subsec_nanos() as i64),
+                    width: meta.size.width,
+                    height: meta.size.height,
+                    video: meta.video,
+                    audio: meta.audio,
+                });
+                // Step 6
+                elem.change_ready_state(HAVE_METADATA);
+                self.have_metadata = true;
+            }
+            _ => {}
+        }
+    }
+
+    #[cfg(any(target_os = "android", target_arch = "arm", target_arch = "aarch64"))]
+    fn check_metadata(&mut self, elem: &HTMLMediaElement) {
+        // Step 6.
+        elem.change_ready_state(HAVE_METADATA);
+        self.have_metadata = true;
+    }
+}
+
+#[derive(JSTraceable, HeapSizeOf)]
+pub struct VideoMedia {
+    format: String,
+    #[ignore_heap_size_of = "defined in time"]
+    duration: Duration,
+    width: u32,
+    height: u32,
+    video: String,
+    audio: Option<String>,
 }
 
 #[dom_struct]
 pub struct HTMLMediaElement {
     htmlelement: HTMLElement,
     network_state: Cell<u16>,
     ready_state: Cell<u16>,
     current_src: DOMRefCell<String>,
     generation_id: Cell<u32>,
     first_data_load: Cell<bool>,
     error: MutNullableHeap<JS<MediaError>>,
     paused: Cell<bool>,
     autoplaying: Cell<bool>,
+    video: DOMRefCell<Option<VideoMedia>>,
 }
 
 impl HTMLMediaElement {
     pub fn new_inherited(tag_name: Atom,
                          prefix: Option<DOMString>, document: &Document)
                          -> HTMLMediaElement {
         HTMLMediaElement {
             htmlelement:
@@ -187,16 +225,17 @@ impl HTMLMediaElement {
             network_state: Cell::new(NETWORK_EMPTY),
             ready_state: Cell::new(HAVE_NOTHING),
             current_src: DOMRefCell::new("".to_owned()),
             generation_id: Cell::new(0),
             first_data_load: Cell::new(true),
             error: Default::default(),
             paused: Cell::new(true),
             autoplaying: Cell::new(true),
+            video: DOMRefCell::new(None),
         }
     }
 
     #[inline]
     pub fn htmlelement(&self) -> &HTMLElement {
         &self.htmlelement
     }
 
--- a/servo/components/script/lib.rs
+++ b/servo/components/script/lib.rs
@@ -82,16 +82,18 @@ extern crate smallvec;
 extern crate style;
 extern crate time;
 #[cfg(any(target_os = "macos", target_os = "linux", target_os = "windows"))]
 extern crate tinyfiledialogs;
 extern crate url;
 #[macro_use]
 extern crate util;
 extern crate uuid;
+#[cfg(not(any(target_os = "android", target_arch = "arm", target_arch = "aarch64")))]
+extern crate video_metadata;
 extern crate webrender_traits;
 extern crate websocket;
 extern crate xml5ever;
 
 pub mod bluetooth_blacklist;
 pub mod clipboard_provider;
 mod devtools;
 pub mod document_loader;
--- a/servo/components/servo/Cargo.lock
+++ b/servo/components/servo/Cargo.lock
@@ -1899,16 +1899,17 @@ dependencies = [
  "smallvec 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "string_cache 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)",
  "style 0.0.1",
  "time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
  "tinyfiledialogs 0.1.0 (git+https://github.com/jdm/tinyfiledialogs)",
  "url 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "util 0.0.1",
  "uuid 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "video-metadata 0.1.2 (git+https://github.com/GuillaumeGomez/video-metadata-rs)",
  "webrender_traits 0.2.0 (git+https://github.com/servo/webrender_traits)",
  "websocket 0.17.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "xml5ever 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "script_layout_interface"
 version = "0.0.1"
@@ -2438,16 +2439,26 @@ name = "uuid"
 version = "0.2.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
+name = "video-metadata"
+version = "0.1.2"
+source = "git+https://github.com/GuillaumeGomez/video-metadata-rs#bc7f45023765b0ff7a7235e02bac3bfe9f24acd7"
+dependencies = [
+ "gcc 0.3.28 (registry+https://github.com/rust-lang/crates.io-index)",
+ "lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
 name = "void"
 version = "1.0.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
 name = "walkdir"
 version = "0.1.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
--- a/servo/ports/cef/Cargo.lock
+++ b/servo/ports/cef/Cargo.lock
@@ -1753,16 +1753,17 @@ dependencies = [
  "smallvec 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "string_cache 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)",
  "style 0.0.1",
  "time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
  "tinyfiledialogs 0.1.0 (git+https://github.com/jdm/tinyfiledialogs)",
  "url 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "util 0.0.1",
  "uuid 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "video-metadata 0.1.2 (git+https://github.com/GuillaumeGomez/video-metadata-rs)",
  "webrender_traits 0.2.0 (git+https://github.com/servo/webrender_traits)",
  "websocket 0.17.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "xml5ever 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "script_layout_interface"
 version = "0.0.1"
@@ -2300,16 +2301,26 @@ name = "uuid"
 version = "0.2.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
+name = "video-metadata"
+version = "0.1.2"
+source = "git+https://github.com/GuillaumeGomez/video-metadata-rs#bc7f45023765b0ff7a7235e02bac3bfe9f24acd7"
+dependencies = [
+ "gcc 0.3.28 (registry+https://github.com/rust-lang/crates.io-index)",
+ "lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
 name = "void"
 version = "1.0.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
 name = "walkdir"
 version = "0.1.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"