Bug 872822 - Update WebVTT library to v0.5. r=rillian
authorCaitlin Potter <snowball@defpixel.com>
Thu, 16 May 2013 00:10:51 -0400
changeset 143650 eff959d2842c70a43bdb3b04b5efff464b394a38
parent 143649 d0dd7859a4227f5b3c8ab1ac15c2d8f28bad8445
child 143651 7abf0aab9cdec7332c154cacc6260235119b25fc
push id2697
push userbbajaj@mozilla.com
push dateMon, 05 Aug 2013 18:49:53 +0000
treeherdermozilla-beta@dfec938c7b63 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersrillian
bugs872822
milestone24.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 872822 - Update WebVTT library to v0.5. r=rillian Bug 872822 - Update WebVTT library to v0.5. r=rillian
media/webvtt/Makefile.in
media/webvtt/README_MOZILLA
media/webvtt/alloc.c
media/webvtt/cue.c
media/webvtt/cue_internal.h
media/webvtt/cuetext.c
media/webvtt/cuetext_internal.h
media/webvtt/include/webvtt/cue.h
media/webvtt/include/webvtt/error.h
media/webvtt/include/webvtt/node.h
media/webvtt/include/webvtt/parser.h
media/webvtt/include/webvtt/string.h
media/webvtt/include/webvtt/util.h
media/webvtt/lexer.c
media/webvtt/node.c
media/webvtt/node_internal.h
media/webvtt/parser.c
media/webvtt/parser_internal.h
media/webvtt/string.c
media/webvtt/string_internal.h
media/webvtt/update.sh
--- a/media/webvtt/Makefile.in
+++ b/media/webvtt/Makefile.in
@@ -7,17 +7,16 @@ topsrcdir       = @top_srcdir@
 srcdir          = @srcdir@
 VPATH           = @srcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
 LIBRARY_NAME      = webvtt
 
 DEFINES += \
-  -DWEBVTT_NO_CONFIG_H=1 \
   -DWEBVTT_STATIC=1 \
   $(NULL)
 
 CSRCS = \
   alloc.c \
   cue.c \
   cuetext.c \
   error.c \
--- a/media/webvtt/README_MOZILLA
+++ b/media/webvtt/README_MOZILLA
@@ -1,6 +1,6 @@
 These files are from the WebVTT library, and are extracted from rev
-c93accafb2087df7c678748e25bca21f1173979f of the git repository at
+aca1a4cc860141ea4759c87ecd906b365ffd89f0 of the git repository at
 https://github.com/mozilla/webvtt.
 
 The following CPPFLAGS are used in order to build and link in Mozilla
 -DWEBVTT_STATIC=1      -- Compile as a static library
--- a/media/webvtt/alloc.c
+++ b/media/webvtt/alloc.c
@@ -29,20 +29,20 @@
 #include <stdlib.h>
 #include <string.h>
 
 static void *default_alloc( void *unused, webvtt_uint nb );
 static void default_free( void *unused, void *ptr );
 
 struct {
   /**
-   * Number of allocated objects. Forbid changing the allocator if this is not 
+   * Number of allocated objects. Forbid changing the allocator if this is not
    * equal to 0 
    */
-  webvtt_uint n_alloc; 
+  webvtt_uint n_alloc;
   webvtt_alloc_fn_ptr alloc;
   webvtt_free_fn_ptr free;
   void *alloc_data;
 } allocator = { 0, default_alloc, default_free, 0 };
 
 static void *WEBVTT_CALLBACK
 default_alloc( void *unused, webvtt_uint nb )
 {
@@ -53,21 +53,22 @@ default_alloc( void *unused, webvtt_uint
 static void WEBVTT_CALLBACK
 default_free( void *unused, void *ptr )
 {
   (void)unused;
   free( ptr );
 }
 
 WEBVTT_EXPORT void
-webvtt_set_allocator( webvtt_alloc_fn_ptr alloc, webvtt_free_fn_ptr free, void *userdata )
+webvtt_set_allocator( webvtt_alloc_fn_ptr alloc, webvtt_free_fn_ptr free,
+                      void *userdata )
 {
   /**
    * TODO:
-   * This really needs a lock. But then, so does all the allocation/free 
+   * This really needs a lock. But then, so does all the allocation/free
    * functions...
    * that could be a problem.
    */
   if( allocator.n_alloc == 0 ) {
     if( alloc && free ) {
       allocator.alloc = alloc;
       allocator.free = free;
       allocator.alloc_data = userdata;
--- a/media/webvtt/cue.c
+++ b/media/webvtt/cue.c
@@ -91,17 +91,17 @@ webvtt_release_cue( webvtt_cue **pcue )
   }
 }
 
 WEBVTT_EXPORT int
 webvtt_validate_cue( webvtt_cue *cue )
 {
   if( cue ) {
     /**
-     * validate cue-times (Can't do checks against previously parsed cuetimes. 
+     * validate cue-times (Can't do checks against previously parsed cuetimes.
      * That's the applications responsibility
      */
     if( BAD_TIMESTAMP(cue->from) || BAD_TIMESTAMP(cue->until) ) {
       goto error;
     }
 
     if( cue->until <= cue->from ) {
       goto error;
--- a/media/webvtt/cue_internal.h
+++ b/media/webvtt/cue_internal.h
@@ -42,11 +42,12 @@ enum {
   CUE_HAVE_SETTINGS = (CUE_HAVE_VERTICAL | CUE_HAVE_SIZE
     | CUE_HAVE_POSITION | CUE_HAVE_LINE | CUE_HAVE_ALIGN),
 
   CUE_HAVE_CUEPARAMS = 0x40000000,
   CUE_HAVE_ID = 0x80000000,
   CUE_HEADER_MASK = CUE_HAVE_CUEPARAMS|CUE_HAVE_ID,
 };
 
-WEBVTT_INTERN webvtt_bool cue_is_incomplete( const webvtt_cue *cue );
+WEBVTT_INTERN webvtt_bool
+cue_is_incomplete( const webvtt_cue *cue );
 
 #endif
--- a/media/webvtt/cuetext.c
+++ b/media/webvtt/cuetext.c
@@ -64,59 +64,61 @@ do \
   { \
     status_var = returned_status; \
     goto dealloc; \
   } \
 
 WEBVTT_INTERN webvtt_status
 webvtt_create_token( webvtt_cuetext_token **token, webvtt_token_type token_type )
 {
-  webvtt_cuetext_token *temp_token = (webvtt_cuetext_token *)webvtt_alloc0( sizeof(*temp_token) );
+  webvtt_cuetext_token *temp_token =
+    (webvtt_cuetext_token *)webvtt_alloc0( sizeof(*temp_token) );
 
   if( !temp_token ) {
     return WEBVTT_OUT_OF_MEMORY;
   }
 
   temp_token->token_type = token_type;
   *token = temp_token;
 
   return WEBVTT_SUCCESS;
 }
 
 WEBVTT_INTERN webvtt_status
-webvtt_create_start_token( webvtt_cuetext_token **token, webvtt_string *tag_name,
-    webvtt_stringlist *css_classes, webvtt_string *annotation )
+webvtt_create_start_token( webvtt_cuetext_token **token, webvtt_string
+                           *tag_name, webvtt_stringlist *css_classes,
+                           webvtt_string *annotation )
 {
   webvtt_status status;
   webvtt_start_token_data sd;
-  
+
   if( WEBVTT_FAILED( status = webvtt_create_token( token, START_TOKEN ) ) ) {
     return status;
   }
-  
+
   webvtt_copy_string( &(*token)->tag_name, tag_name );
   webvtt_copy_stringlist( &sd.css_classes, css_classes );
   webvtt_copy_string( &sd.annotations, annotation );
-  
+
   (*token)->start_token_data = sd;
-    
+
   return WEBVTT_SUCCESS;
 }
 
 WEBVTT_INTERN webvtt_status
 webvtt_create_end_token( webvtt_cuetext_token **token, webvtt_string *tag_name )
 {
   webvtt_status status;
 
   if( WEBVTT_FAILED( status = webvtt_create_token( token, END_TOKEN ) ) ) {
     return status;
   }
 
   webvtt_copy_string( &(*token)->tag_name, tag_name );
-  
+
   return WEBVTT_SUCCESS;
 }
 
 WEBVTT_INTERN webvtt_status
 webvtt_create_text_token( webvtt_cuetext_token **token, webvtt_string *text )
 {
   webvtt_status status;
 
@@ -125,46 +127,48 @@ webvtt_create_text_token( webvtt_cuetext
   }
 
   webvtt_copy_string( &(*token)->text, text);
 
   return WEBVTT_SUCCESS;
 }
 
 WEBVTT_INTERN webvtt_status
-webvtt_create_timestamp_token( webvtt_cuetext_token **token, webvtt_timestamp time_stamp )
+webvtt_create_timestamp_token( webvtt_cuetext_token **token,
+                               webvtt_timestamp time_stamp )
 {
   webvtt_status status;
 
-  if( WEBVTT_FAILED( status = webvtt_create_token( token, TIME_STAMP_TOKEN ) ) ) {
+  if( WEBVTT_FAILED( status = webvtt_create_token( token,
+                                                   TIME_STAMP_TOKEN ) ) ) {
     return status;
   }
 
   (*token)->time_stamp = time_stamp;
 
   return WEBVTT_SUCCESS;
 }
 
 WEBVTT_INTERN void
 webvtt_delete_token( webvtt_cuetext_token **token )
 {
   webvtt_start_token_data data;
   webvtt_cuetext_token *t;
-  
+
   if( !token ) {
     return;
   }
   if( !*token ) {
     return;
-  }  
+  }
   t = *token;
-  
-  /** 
-   * Note that time stamp tokens do not need to free any internal data because 
-   * they do not allocate anything. 
+
+  /**
+   * Note that time stamp tokens do not need to free any internal data because
+   * they do not allocate anything.
    */
   if( t->token_type == START_TOKEN ) {
     data = t->start_token_data;
     webvtt_release_stringlist( &data.css_classes );
     webvtt_release_string( &data.annotations );
     webvtt_release_string( &t->tag_name );
   } else if( t->token_type == END_TOKEN ) {
     webvtt_release_string( &t->tag_name );
@@ -173,95 +177,107 @@ webvtt_delete_token( webvtt_cuetext_toke
   }
   webvtt_free( t );
   *token = 0;
 }
 
 WEBVTT_INTERN int
 tag_accepts_annotation( webvtt_string *tag_name )
 {
-  return webvtt_string_is_equal( tag_name, ( webvtt_byte * )"v", 1 );
+  return webvtt_string_is_equal( tag_name, "v", 1 ) ||
+         webvtt_string_is_equal( tag_name, "lang", 4 );
 }
 
 WEBVTT_INTERN webvtt_status
-webvtt_node_kind_from_tag_name( webvtt_string *tag_name, webvtt_node_kind *kind )
+webvtt_node_kind_from_tag_name( webvtt_string *tag_name,
+                                webvtt_node_kind *kind )
 {
   if( !tag_name || !kind ) {
     return WEBVTT_INVALID_PARAM;
   }
 
   if( webvtt_string_length(tag_name) == 1 ) {
     switch( webvtt_string_text(tag_name)[0] ) {
-      case( 'b' ):
+      case 'b':
         *kind = WEBVTT_BOLD;
         break;
-      case( 'i' ):
+      case 'i':
         *kind = WEBVTT_ITALIC;
         break;
-      case( 'u' ):
+      case 'u':
         *kind = WEBVTT_UNDERLINE;
         break;
-      case( 'c' ):
+      case 'c':
         *kind = WEBVTT_CLASS;
         break;
-      case( 'v' ):
+      case 'v':
         *kind = WEBVTT_VOICE;
         break;
     }
-  } else if( webvtt_string_is_equal( tag_name, ( webvtt_byte * )"ruby", 4 ) ) {
+  } else if( webvtt_string_is_equal( tag_name, "ruby", 4 ) ) {
     *kind = WEBVTT_RUBY;
-  } else if( webvtt_string_is_equal( tag_name, ( webvtt_byte * )"rt", 2 ) ) {
+  } else if( webvtt_string_is_equal( tag_name, "rt", 2 ) ) {
     *kind = WEBVTT_RUBY_TEXT;
+  } else if ( webvtt_string_is_equal( tag_name, "lang", 4 ) ) {
+    *kind = WEBVTT_LANG;
   } else {
     return WEBVTT_INVALID_TAG_NAME;
   }
 
   return WEBVTT_SUCCESS;
 }
 
 WEBVTT_INTERN webvtt_status
-webvtt_create_node_from_token( webvtt_cuetext_token *token, webvtt_node **node, webvtt_node *parent )
+webvtt_create_node_from_token( webvtt_cuetext_token *token, webvtt_node **node,
+                               webvtt_node *parent )
 {
   webvtt_node_kind kind;
 
   if( !token || !node || !parent ) {
     return WEBVTT_INVALID_PARAM;
   }
 
-  /** 
+  /**
    * We've recieved a node that is not null.
-   * In order to prevent memory leaks caused by overwriting a node which the 
+   * In order to prevent memory leaks caused by overwriting a node which the
    * caller has not released return unsuccessful.
    */
   if( *node ) {
     return WEBVTT_UNSUCCESSFUL;
   }
-  
+
   switch ( token->token_type ) {
-    case( TEXT_TOKEN ):
+    case TEXT_TOKEN:
       return webvtt_create_text_node( node, parent, &token->text );
       break;
-    case( START_TOKEN ):
-
-      CHECK_MEMORY_OP( webvtt_node_kind_from_tag_name( &token->tag_name, &kind) );
-
-      return webvtt_create_internal_node( node, parent, kind,
-        token->start_token_data.css_classes, &token->start_token_data.annotations );
+    case START_TOKEN:
+      CHECK_MEMORY_OP( webvtt_node_kind_from_tag_name( &token->tag_name,
+                                                       &kind) );
+      if( kind == WEBVTT_LANG ) {
+        return webvtt_create_lang_node( node, parent,
+                                        token->start_token_data.css_classes,
+                                        &token->start_token_data.annotations );
+      }
+      else {
+        return webvtt_create_internal_node( node, parent, kind,
+                                        token->start_token_data.css_classes,
+                                        &token->start_token_data.annotations );
+      }
 
       break;
-    case ( TIME_STAMP_TOKEN ):
+    case TIME_STAMP_TOKEN:
       return webvtt_create_timestamp_node( node, parent, token->time_stamp );
       break;
     default:
       return WEBVTT_INVALID_TOKEN_TYPE;
   }
 }
 
 WEBVTT_INTERN webvtt_status
-webvtt_data_state( webvtt_byte **position, webvtt_token_state *token_state, 
+webvtt_data_state( const char **position, webvtt_token_state *token_state,
                    webvtt_string *result )
 {
   for ( ; *token_state == DATA; (*position)++ ) {
     switch( **position ) {
       case '&':
         *token_state = ESCAPE;
         break;
       case '<':
@@ -281,29 +297,29 @@ webvtt_data_state( webvtt_byte **positio
   }
 
   return WEBVTT_UNFINISHED;
 }
 
 /**
  * Definitions for escape sequence replacement strings.
  */
-#define RLM_REPLACE_LENGTH    3
-#define LRM_REPLACE_LENGTH    3
-#define NBSP_REPLACE_LENGTH   2
- 
-webvtt_byte rlm_replace[RLM_REPLACE_LENGTH] = { UTF8_RIGHT_TO_LEFT_1, 
-    UTF8_RIGHT_TO_LEFT_2, UTF8_RIGHT_TO_LEFT_3 };
-webvtt_byte lrm_replace[LRM_REPLACE_LENGTH] = { UTF8_LEFT_TO_RIGHT_1,
-  UTF8_LEFT_TO_RIGHT_2, UTF8_LEFT_TO_RIGHT_3 };
-webvtt_byte nbsp_replace[NBSP_REPLACE_LENGTH] = { UTF8_NO_BREAK_SPACE_1,
-  UTF8_NO_BREAK_SPACE_2 };
-  
+#define RLM_LENGTH    3
+#define LRM_LENGTH    3
+#define NBSP_LENGTH   2
+
+char rlm_replace[RLM_LENGTH] = { UTF8_RIGHT_TO_LEFT_1, UTF8_RIGHT_TO_LEFT_2,
+                                 UTF8_RIGHT_TO_LEFT_3 };
+char lrm_replace[LRM_LENGTH] = { UTF8_LEFT_TO_RIGHT_1, UTF8_LEFT_TO_RIGHT_2,
+                                 UTF8_LEFT_TO_RIGHT_3 };
+char nbsp_replace[NBSP_LENGTH] = { UTF8_NO_BREAK_SPACE_1,
+                                   UTF8_NO_BREAK_SPACE_2 };
+
 WEBVTT_INTERN webvtt_status
-webvtt_escape_state( webvtt_byte **position, webvtt_token_state *token_state, 
+webvtt_escape_state( const char **position, webvtt_token_state *token_state,
                      webvtt_string *result )
 {
   webvtt_string buffer;
   webvtt_status status = WEBVTT_SUCCESS;
 
   CHECK_MEMORY_OP_JUMP( status, webvtt_create_string( 1, &buffer ) );
 
   /**
@@ -313,51 +329,60 @@ webvtt_escape_state( webvtt_byte **posit
   CHECK_MEMORY_OP_JUMP( status, webvtt_string_putc( &buffer, '&' ) );
 
   for( ; *token_state == ESCAPE; (*position)++ ) {
     /**
      * We have encountered a token termination point.
      * Append buffer to result and return success.
      */
     if( **position == '\0' || **position == '<' ) {
-      CHECK_MEMORY_OP_JUMP( status, webvtt_string_append_string( result, &buffer ) );
+      CHECK_MEMORY_OP_JUMP( status, webvtt_string_append_string( result,
+                                                                 &buffer ) );
       goto dealloc;
     }
     /**
      * This means we have enocuntered a malformed escape character sequence.
      * This means that we need to add that malformed text to the result and
      * recreate the buffer to prepare for a new escape sequence.
      */
     else if( **position == '&' ) {
-      CHECK_MEMORY_OP_JUMP( status, webvtt_string_append_string( result, &buffer ) );
+      CHECK_MEMORY_OP_JUMP( status, webvtt_string_append_string( result,
+                                                                 &buffer ) );
       webvtt_release_string( &buffer );
       CHECK_MEMORY_OP_JUMP( status, webvtt_create_string( 1, &buffer ) );
-      CHECK_MEMORY_OP_JUMP( status, webvtt_string_putc( &buffer, *position[0] ) );
+      CHECK_MEMORY_OP_JUMP( status, webvtt_string_putc( &buffer,
+                                                        *position[0] ) );
     }
     /**
      * We've encountered the semicolon which is the end of an escape sequence.
      * Check if buffer contains a valid escape sequence and if it does append
      * the interpretation to result and change the state to DATA.
      */
     else if( **position == ';' ) {
-      if( webvtt_string_is_equal( &buffer, ( webvtt_byte * )"&amp", 4 ) ) {
+      if( webvtt_string_is_equal( &buffer, "&amp", 4 ) ) {
         CHECK_MEMORY_OP_JUMP( status, webvtt_string_putc( result, '&' ) );
-      } else if( webvtt_string_is_equal( &buffer, ( webvtt_byte * )"&lt", 3 ) ) {
+      } else if( webvtt_string_is_equal( &buffer, "&lt", 3 ) ) {
         CHECK_MEMORY_OP_JUMP( status, webvtt_string_putc( result, '<' ) );
-      } else if( webvtt_string_is_equal( &buffer, ( webvtt_byte * )"&gt", 3 ) ) {
+      } else if( webvtt_string_is_equal( &buffer, "&gt", 3 ) ) {
         CHECK_MEMORY_OP_JUMP( status, webvtt_string_putc( result, '>' ) );
-      } else if( webvtt_string_is_equal( &buffer, ( webvtt_byte * )"&rlm", 4 ) ) {
-        CHECK_MEMORY_OP_JUMP( status, webvtt_string_append( result, rlm_replace, RLM_REPLACE_LENGTH ) );
-      } else if( webvtt_string_is_equal( &buffer, ( webvtt_byte * )"&lrm", 4 ) ) {
-        CHECK_MEMORY_OP_JUMP( status, webvtt_string_append( result, lrm_replace, LRM_REPLACE_LENGTH ) );
-      } else if( webvtt_string_is_equal( &buffer, ( webvtt_byte * )"&nbsp", 5 ) ) {
-        CHECK_MEMORY_OP_JUMP( status, webvtt_string_append( result, nbsp_replace, NBSP_REPLACE_LENGTH ) );
+      } else if( webvtt_string_is_equal( &buffer, "&rlm", 4 ) ) {
+        CHECK_MEMORY_OP_JUMP( status, webvtt_string_append( result, rlm_replace,
+                                                            RLM_LENGTH ) );
+      } else if( webvtt_string_is_equal( &buffer, "&lrm", 4 ) ) {
+        CHECK_MEMORY_OP_JUMP( status, webvtt_string_append( result, lrm_replace,
+                                                            LRM_LENGTH ) );
+      } else if( webvtt_string_is_equal( &buffer, "&nbsp", 5 ) ) {
+        CHECK_MEMORY_OP_JUMP( status, webvtt_string_append( result,
+                                                            nbsp_replace,
+                                                            NBSP_LENGTH ) );
       } else {
-        CHECK_MEMORY_OP_JUMP( status, webvtt_string_append_string( result, &buffer ) );
-        CHECK_MEMORY_OP_JUMP( status, webvtt_string_putc( result, **position ) );
+        CHECK_MEMORY_OP_JUMP( status, webvtt_string_append_string( result,
+                                                                   &buffer ) );
+        CHECK_MEMORY_OP_JUMP( status, webvtt_string_putc( result,
+                                                          **position ) );
       }
 
       *token_state = DATA;
       status = WEBVTT_UNFINISHED;
     }
     /**
      * Character is alphanumeric. This means we are in the body of the escape
      * sequence.
@@ -366,31 +391,33 @@ webvtt_escape_state( webvtt_byte **posit
       CHECK_MEMORY_OP_JUMP( status, webvtt_string_putc( &buffer, **position ) );
     }
     /**
      * If we have not found an alphanumeric character then we have encountered
      * a malformed escape sequence. Add buffer to result and continue to parse
      * in DATA state.
      */
     else {
-      CHECK_MEMORY_OP_JUMP( status, webvtt_string_append_string( result, &buffer ) );
-      CHECK_MEMORY_OP_JUMP( status, webvtt_string_putc( result, **position ) );
+      CHECK_MEMORY_OP_JUMP( status, webvtt_string_append_string( result,
+                                                                 &buffer ) );
+      CHECK_MEMORY_OP_JUMP( status, webvtt_string_putc( result,
+                                                        **position ) );
       status = WEBVTT_UNFINISHED;
       *token_state = DATA;
     }
   }
 
 dealloc:
   webvtt_release_string( &buffer );
 
   return status;
 }
 
 WEBVTT_INTERN webvtt_status
-webvtt_tag_state( webvtt_byte **position, webvtt_token_state *token_state, 
+webvtt_tag_state( const char **position, webvtt_token_state *token_state,
                   webvtt_string *result )
 {
   for( ; *token_state == TAG; (*position)++ ) {
     if( **position == '\t' || **position == '\n' ||
         **position == '\r' || **position == '\f' ||
         **position == ' ' ) {
       *token_state = START_TAG_ANNOTATION;
     } else if( webvtt_isdigit( **position )  ) {
@@ -416,110 +443,115 @@ webvtt_tag_state( webvtt_byte **position
       }
     }
   }
 
   return WEBVTT_UNFINISHED;
 }
 
 WEBVTT_INTERN webvtt_status
-webvtt_start_tag_state( webvtt_byte **position, webvtt_token_state *token_state, 
+webvtt_start_tag_state( const char **position, webvtt_token_state *token_state,
                         webvtt_string *result )
 {
   for( ; *token_state == START_TAG; (*position)++ ) {
     if( **position == '\t' || **position == '\f' ||
         **position == ' ' || **position == '\n' ||
         **position == '\r' ) {
       *token_state = START_TAG_ANNOTATION;
     } else {
       switch( **position ) {
-        case '\t':
-          *token_state = START_TAG_ANNOTATION;
-          break;
         case '.':
           *token_state = START_TAG_CLASS;
           break;
+        case '\0':
+          return WEBVTT_SUCCESS;
         case '>':
           return WEBVTT_SUCCESS;
           break;
         default:
           CHECK_MEMORY_OP( webvtt_string_putc( result, **position ) );
           break;
       }
     }
   }
 
   return WEBVTT_UNFINISHED;
 }
 
 WEBVTT_INTERN webvtt_status
-webvtt_class_state( webvtt_byte **position, webvtt_token_state *token_state, 
+webvtt_class_state( const char **position, webvtt_token_state *token_state,
                     webvtt_stringlist *css_classes )
 {
   webvtt_string buffer;
   webvtt_status status = WEBVTT_SUCCESS;
 
   CHECK_MEMORY_OP( webvtt_create_string( 1, &buffer ) );
 
   for( ; *token_state == START_TAG_CLASS; (*position)++ ) {
     if( **position == '\t' || **position == '\f' ||
         **position == ' ' || **position == '\n' ||
         **position == '\r') {
-      CHECK_MEMORY_OP_JUMP( status, webvtt_stringlist_push( css_classes, &buffer ) );
+      if( webvtt_string_length( &buffer ) > 0 ) {
+        CHECK_MEMORY_OP_JUMP( status, webvtt_stringlist_push( css_classes,
+                                                              &buffer ) );
+      }
       *token_state = START_TAG_ANNOTATION;
+      webvtt_release_string( &buffer );
       return WEBVTT_SUCCESS;
     } else if( **position == '>' || **position == '\0' ) {
-      CHECK_MEMORY_OP_JUMP( status, webvtt_stringlist_push( css_classes, &buffer ) );
+      CHECK_MEMORY_OP_JUMP( status, webvtt_stringlist_push( css_classes,
+                                                            &buffer ) );
       webvtt_release_string( &buffer );
       return WEBVTT_SUCCESS;
     } else if( **position == '.' ) {
-      CHECK_MEMORY_OP_JUMP( status, webvtt_stringlist_push( css_classes, &buffer ) );
+      CHECK_MEMORY_OP_JUMP( status, webvtt_stringlist_push( css_classes,
+                                                            &buffer ) );
       webvtt_release_string( &buffer );
       CHECK_MEMORY_OP( webvtt_create_string( 1, &buffer ) );
     } else {
       CHECK_MEMORY_OP_JUMP( status, webvtt_string_putc( &buffer, **position ) );
     }
   }
 
 dealloc:
   webvtt_release_string( &buffer );
 
   return status;
 }
 
 WEBVTT_INTERN webvtt_status
-webvtt_annotation_state( webvtt_byte **position, webvtt_token_state *token_state, 
+webvtt_annotation_state( const char **position, webvtt_token_state *token_state,
                          webvtt_string *annotation )
 {
   for( ; *token_state == START_TAG_ANNOTATION; (*position)++ ) {
     if( **position == '\0' || **position == '>' ) {
       return WEBVTT_SUCCESS;
     }
     CHECK_MEMORY_OP( webvtt_string_putc( annotation, **position ) );
   }
 
   return WEBVTT_UNFINISHED;
 }
 
 WEBVTT_INTERN webvtt_status
-webvtt_end_tag_state( webvtt_byte **position, webvtt_token_state *token_state, 
+webvtt_end_tag_state( const char **position, webvtt_token_state *token_state,
                       webvtt_string *result )
 {
   for( ; *token_state == END_TAG; (*position)++ ) {
     if( **position == '>' || **position == '\0' ) {
       return WEBVTT_SUCCESS;
     }
     CHECK_MEMORY_OP( webvtt_string_putc( result, **position ) );
   }
 
   return WEBVTT_UNFINISHED;
 }
 
 WEBVTT_INTERN webvtt_status
-webvtt_timestamp_state( webvtt_byte **position, webvtt_token_state *token_state, 
+webvtt_timestamp_state( const char **position, webvtt_token_state *token_state,
                         webvtt_string *result )
 {
   for( ; *token_state == TIME_STAMP_TAG; (*position)++ ) {
     if( **position == '>' || **position == '\0' ) {
       return WEBVTT_SUCCESS;
     }
     CHECK_MEMORY_OP( webvtt_string_putc( result, **position ) );
   }
@@ -527,32 +559,32 @@ webvtt_timestamp_state( webvtt_byte **po
   return WEBVTT_UNFINISHED;
 }
 
 /**
  * Need to set up differently.
  * Get a status in order to return at end and release memeory.
  */
 WEBVTT_INTERN webvtt_status
-webvtt_cuetext_tokenizer( webvtt_byte **position, webvtt_cuetext_token **token )
+webvtt_cuetext_tokenizer( const char **position, webvtt_cuetext_token **token )
 {
   webvtt_token_state token_state = DATA;
   webvtt_string result, annotation;
   webvtt_stringlist *css_classes;
   webvtt_timestamp time_stamp = 0;
   webvtt_status status = WEBVTT_UNFINISHED;
 
   if( !position ) {
     return WEBVTT_INVALID_PARAM;
   }
 
   webvtt_create_string( 10, &result );
   webvtt_create_string( 10, &annotation );
   webvtt_create_stringlist( &css_classes );
-  
+
   /**
    * Loop while the tokenizer is not finished.
    * Based on the state of the tokenizer enter a function to handle that
    * particular tokenizer state. Those functions will loop until they either
    * change the state of the tokenizer or reach a valid token end point.
    */
   while( status == WEBVTT_UNFINISHED ) {
     switch( token_state ) {
@@ -580,69 +612,74 @@ webvtt_cuetext_tokenizer( webvtt_byte **
       case TIME_STAMP_TAG:
         status = webvtt_timestamp_state( position, &token_state, &result );
         break;
     }
   }
 
   if( **position == '>' )
   { (*position)++; }
-  
+
   if( status == WEBVTT_SUCCESS ) {
     /**
      * The state that the tokenizer left off on will tell us what kind of token
      * needs to be made.
      */
     if( token_state == DATA || token_state == ESCAPE ) {
       status = webvtt_create_text_token( token, &result );
-    } else if(token_state == TAG || token_state == START_TAG || token_state == START_TAG_CLASS ||
+    } else if( token_state == TAG || token_state == START_TAG ||
+               token_state == START_TAG_CLASS ||
               token_state == START_TAG_ANNOTATION) {
       /**
-      * If the tag does not accept an annotation then release the current 
+      * If the tag does not accept an annotation then release the current
       * annotation and intialize annotation to a safe empty state
       */
       if( !tag_accepts_annotation( &result ) ) {
         webvtt_release_string( &annotation );
         webvtt_init_string( &annotation );
       }
-      status = webvtt_create_start_token( token, &result, css_classes, &annotation );
+      status = webvtt_create_start_token( token, &result, css_classes,
+                                          &annotation );
     } else if( token_state == END_TAG ) {
       status = webvtt_create_end_token( token, &result );
     } else if( token_state == TIME_STAMP_TAG ) {
       parse_timestamp( webvtt_string_text( &result ), &time_stamp );
       status = webvtt_create_timestamp_token( token, time_stamp );
     } else {
       status = WEBVTT_INVALID_TOKEN_STATE;
     }
   }
-  
+
   webvtt_release_stringlist( &css_classes );
   webvtt_release_string( &result );
   webvtt_release_string( &annotation );
-  
+
   return status;
 }
 
 /**
  * Currently line and len are not being kept track of.
  * Don't think pnode_length is needed as nodes track there list count
  * internally.
  */
 WEBVTT_INTERN webvtt_status
-webvtt_parse_cuetext( webvtt_parser self, webvtt_cue *cue, webvtt_string *payload, int finished )
+webvtt_parse_cuetext( webvtt_parser self, webvtt_cue *cue,
+                      webvtt_string *payload, int finished )
 {
 
-  const webvtt_byte *cue_text;
+  const char *cue_text;
   webvtt_status status;
-  webvtt_byte *position;
+  const char *position;
   webvtt_node *node_head;
   webvtt_node *current_node;
   webvtt_node *temp_node;
   webvtt_cuetext_token *token;
   webvtt_node_kind kind;
+  webvtt_stringlist *lang_stack;
+  webvtt_string temp;
 
   /**
    *  TODO: Use these parameters! 'finished' isn't really important
    * here, but 'self' certainly is as it lets us report syntax errors.
    *
    * However, for the time being we can trick the compiler into not
    * warning us about unused variables by doing this.
    */
@@ -658,32 +695,33 @@ webvtt_parse_cuetext( webvtt_parser self
   if( !cue_text ) {
     return WEBVTT_INVALID_PARAM;
   }
 
   if ( WEBVTT_FAILED(status = webvtt_create_head_node( &cue->node_head ) ) ) {
     return status;
   }
 
-  position = (webvtt_byte *)cue_text;
+  position = cue_text;
   node_head = cue->node_head;
   current_node = node_head;
   temp_node = NULL;
   token = NULL;
+  webvtt_create_stringlist( &lang_stack );
 
   /**
    * Routine taken from the W3C specification
    * http://dev.w3.org/html5/webvtt/#webvtt-cue-text-parsing-rules
    */
   while( *position != '\0' ) {
-    webvtt_status status = WEBVTT_SUCCESS; 
+    webvtt_status status = WEBVTT_SUCCESS;
     webvtt_delete_token( &token );
 
     /* Step 7. */
-    if( WEBVTT_FAILED( status = webvtt_cuetext_tokenizer( &position, 
+    if( WEBVTT_FAILED( status = webvtt_cuetext_tokenizer( &position,
                                                           &token ) ) ) {
       /* Error here. */
     } else {
       /* Succeeded... Process token */
       if( token->token_type == END_TOKEN ) {
         /**
          * If we've found an end token which has a valid end token tag name and
          * a tag name that is equal to the current node then set current to the
@@ -693,51 +731,84 @@ webvtt_parse_cuetext( webvtt_parser self
           /**
            * We have encountered an end token but we are at the top of the list
            * and thus have not encountered any start tokens yet, throw away the
            * token.
            */
           continue;
         }
 
-        if( webvtt_node_kind_from_tag_name( &token->tag_name, &kind ) == WEBVTT_INVALID_TAG_NAME ) {
+        if( webvtt_node_kind_from_tag_name( &token->tag_name, &kind ) ==
+            WEBVTT_INVALID_TAG_NAME ) {
           /**
            * We have encountered an end token but it is not in a format that is
            * supported, throw away the token.
            */
           continue;
         }
 
-        if( current_node->kind == kind ) {
+        if( current_node->kind == kind ||
+            ( current_node->kind == WEBVTT_RUBY_TEXT
+              && kind == WEBVTT_RUBY ) ) {
           /**
-           * We have encountered an end token and it matches the start token of
-           * the node that we are currently on. Move back up the list of nodes
-           * and continue parsing.
+           * We have encountered a valid end tag to our current tag. Move back
+           * up the tree of nodes and continue parsing.
            */
           current_node = current_node->parent;
+
+          if( kind == WEBVTT_LANG ) {
+            webvtt_stringlist_pop( lang_stack, &temp );
+            webvtt_release_string( &temp );
+          }
         }
       } else {
         /**
          * Attempt to create a valid node from the token.
          * If successful then attach the node to the current nodes list and
          * also set current to the newly created node if it is an internal
          * node type.
          */
-        if( webvtt_create_node_from_token( token, &temp_node, current_node ) != WEBVTT_SUCCESS ) { 
-          /* Do something here? */ 
+        if( webvtt_create_node_from_token( token, &temp_node, current_node ) !=
+            WEBVTT_SUCCESS ) {
+          /* Do something here? */
         } else {
+          /**
+           * If the parsed node is ruby text and we are not currently on a ruby
+           * node then do not attach the ruby text node.
+           */
+          if( temp_node->kind == WEBVTT_RUBY_TEXT &&
+              current_node->kind != WEBVTT_RUBY ) {
+            webvtt_release_node( &temp_node );
+            continue;
+          }
+
           webvtt_attach_node( current_node, temp_node );
 
-          if( WEBVTT_IS_VALID_INTERNAL_NODE( temp_node->kind ) ) { 
-            current_node = temp_node; 
+          /**
+           * If the child node is a leaf node then we are done.
+           */
+          if( WEBVTT_IS_VALID_LEAF_NODE( temp_node->kind ) ) {
+            webvtt_release_node( &temp_node );
+            continue;
           }
-            
+
+          if( temp_node->kind == WEBVTT_LANG ) {
+            webvtt_stringlist_push( lang_stack,
+                                    &temp_node->data.internal_data->lang );
+          } else if( lang_stack->length >= 1 ) {
+            webvtt_release_string( &temp_node->data.internal_data->lang );
+            webvtt_copy_string( &temp_node->data.internal_data->lang,
+                                lang_stack->items + lang_stack->length - 1 );
+          }
+
+          current_node = temp_node;
           /* Release the node as attach internal node increases the count. */
           webvtt_release_node( &temp_node );
         }
       }
     }
   }
-  
+
   webvtt_delete_token( &token );
-  
+  webvtt_release_stringlist( &lang_stack );
+
   return WEBVTT_SUCCESS;
 }
--- a/media/webvtt/cuetext_internal.h
+++ b/media/webvtt/cuetext_internal.h
@@ -26,53 +26,48 @@
  */
 
 #ifndef __INTERN_CUETEXT_H__
 # define __INTERN_CUETEXT_H__
 # include <webvtt/util.h>
 # include <webvtt/string.h>
 # include <webvtt/cue.h>
 
-typedef enum webvtt_token_type_t webvtt_token_type;
-typedef enum webvtt_token_state_t webvtt_token_state;
-
 typedef struct webvtt_cuetext_token_t webvtt_cuetext_token;
 typedef struct webvtt_start_token_data_t webvtt_start_token_data;
 
 /**
  * Enumerates token types.
  */
-enum
-webvtt_token_type_t {
+typedef enum {
   START_TOKEN, /* Identifies a webvtt_cue_text_start_tag_token. */
   END_TOKEN, /* Identifies a webvtt_cue_text_end_tag_token. */
   TIME_STAMP_TOKEN, /* Identifies a webvtt_cue_text_time_stamp_token. */
   TEXT_TOKEN /* Identifies a webvtt_cue_text_text_token. */
-};
+} webvtt_token_type;
 
 /**
  * Enumerates possible states that the cue text tokenizer can be in.
  */
-enum
-webvtt_token_state_t {
+typedef enum {
   DATA, /* Initial state. */
   ESCAPE, /* Parsing an escape value. */
   TAG, /* Reached a '<' character, about to start parsing a tag. */
   START_TAG, /* Parsing the beginning of a tag i.e. the tag name. */
   START_TAG_CLASS, /* Parsing a tag class. Reached when the tokenizer in the
                       START_TAG
                       state reaches a '.' character. */
   START_TAG_ANNOTATION, /* Parsing a tag annotation. Reached when the tokenizer
                            in the START_TAG_CLASS state reaches a TAB, SPACE, or
                            FORM FEED character. */
   END_TAG, /* Parsing an end tag. Reached when a '<' character is follwed by a
               '/' character. */
   TIME_STAMP_TAG /* Parsing a time stamp tag. Reached when a '<' character is
                     follwed by an integer character. */
-};
+} webvtt_token_state;
 
 /**
  * Represents a start tag in the cue text.
  * These take the form of <[TAG_NAME].[CLASSES] [POSSIBLE_ANNOTATION]> in the
  * cue text.
  */
 struct
 webvtt_start_token_data_t {
@@ -94,102 +89,132 @@ webvtt_cuetext_token_t {
     webvtt_start_token_data start_token_data;
   };
 };
 
 /**
  * Routines for creating cue text tokens.
  * Sets the passed token to the new token.
  */
-WEBVTT_INTERN webvtt_status webvtt_create_token( webvtt_cuetext_token **token, webvtt_token_type token_type );
-WEBVTT_INTERN webvtt_status webvtt_create_start_token( webvtt_cuetext_token **token, webvtt_string *tag_name,
-    webvtt_stringlist *css_classes, webvtt_string *annotation );
-WEBVTT_INTERN webvtt_status webvtt_create_end_token( webvtt_cuetext_token **token, webvtt_string *tag_name );
-WEBVTT_INTERN webvtt_status webvtt_create_text_token( webvtt_cuetext_token **token, webvtt_string *text );
-WEBVTT_INTERN webvtt_status webvtt_create_timestamp_token( webvtt_cuetext_token **token,
-    webvtt_timestamp time_stamp );
+WEBVTT_INTERN webvtt_status
+webvtt_create_token( webvtt_cuetext_token **token,
+                     webvtt_token_type token_type );
+
+WEBVTT_INTERN webvtt_status
+webvtt_create_start_token( webvtt_cuetext_token **token,
+                           webvtt_string *tag_name,
+                           webvtt_stringlist *css_classes,
+                           webvtt_string *annotation );
+
+WEBVTT_INTERN webvtt_status
+webvtt_create_end_token( webvtt_cuetext_token **token,
+                         webvtt_string *tag_name );
+
+WEBVTT_INTERN webvtt_status
+webvtt_create_text_token( webvtt_cuetext_token **token, webvtt_string *text );
+
+WEBVTT_INTERN webvtt_status
+webvtt_create_timestamp_token( webvtt_cuetext_token **token,
+                               webvtt_timestamp time_stamp );
 
 /**
  * Returns true if the passed tag matches a tag name that accepts an annotation.
  */
-WEBVTT_INTERN int tag_accepts_annotation( webvtt_string *tag_name );
+WEBVTT_INTERN int
+tag_accepts_annotation( webvtt_string *tag_name );
 
 /**
  * Routines for deleting cue text tokens.
  */
-WEBVTT_INTERN void webvtt_delete_token( webvtt_cuetext_token **token );
+WEBVTT_INTERN void
+webvtt_delete_token( webvtt_cuetext_token **token );
 
 /**
  * Converts the textual representation of a node kind into a particular kind.
  * I.E. tag_name of 'ruby' would create a ruby kind, etc.
  * Returns a WEBVTT_NOT_SUPPORTED if it does not find a valid tag name.
  */
-WEBVTT_INTERN webvtt_status webvtt_node_kind_from_tag_name( webvtt_string *tag_name, webvtt_node_kind *kind );
+WEBVTT_INTERN webvtt_status
+webvtt_node_kind_from_tag_name( webvtt_string *tag_name,
+                                webvtt_node_kind *kind );
 
 /**
  * Creates a node from a valid token.
  * Returns WEBVTT_NOT_SUPPORTED if it does not find a valid tag name.
  */
-WEBVTT_INTERN webvtt_status webvtt_create_node_from_token( webvtt_cuetext_token *token, webvtt_node **node, webvtt_node *parent );
+WEBVTT_INTERN webvtt_status
+webvtt_create_node_from_token( webvtt_cuetext_token *token, webvtt_node **node,
+                               webvtt_node *parent );
 
 /**
  * Tokenizes the cue text into something that can be easily understood by the
  * cue text parser.
  * Referenced from - http://dev.w3.org/html5/webvtt/#webvtt-cue-text-tokenizer
  */
-WEBVTT_INTERN webvtt_status webvtt_tokenizer( webvtt_byte **position, webvtt_cuetext_token **token );
+WEBVTT_INTERN webvtt_status
+webvtt_tokenizer( const char **position, webvtt_cuetext_token **token );
 
 /**
  * Routines that take care of certain states in the webvtt cue text tokenizer.
  */
 
 /**
  * Referenced from http://dev.w3.org/html5/webvtt/#webvtt-data-state
  */
-WEBVTT_INTERN webvtt_status webvtt_data_state( webvtt_byte **position,
-  webvtt_token_state *token_state, webvtt_string *result );
+WEBVTT_INTERN webvtt_status
+webvtt_data_state( const char **position, webvtt_token_state *token_state,
+                   webvtt_string *result );
 
 /**
  * Referenced from http://dev.w3.org/html5/webvtt/#webvtt-escape-state
  */
-WEBVTT_INTERN webvtt_status webvtt_escape_state( webvtt_byte **position,
-  webvtt_token_state *token_state, webvtt_string *result );
+WEBVTT_INTERN webvtt_status
+webvtt_escape_state( const char **position, webvtt_token_state *token_state,
+                     webvtt_string *result );
 
 /**
  * Referenced from http://dev.w3.org/html5/webvtt/#webvtt-tag-state
  */
-WEBVTT_INTERN webvtt_status webvtt_tag_state( webvtt_byte **position,
-  webvtt_token_state *token_state, webvtt_string *result );
+WEBVTT_INTERN webvtt_status
+webvtt_tag_state( const char **position, webvtt_token_state *token_state,
+                  webvtt_string *result );
 
 /**
  * Referenced from http://dev.w3.org/html5/webvtt/#webvtt-start-tag-state
  */
-WEBVTT_INTERN webvtt_status webvtt_start_tag_state( webvtt_byte **position,
-  webvtt_token_state *token_state, webvtt_string *result );
+WEBVTT_INTERN webvtt_status
+webvtt_start_tag_state( const char **position, webvtt_token_state *token_state,
+                        webvtt_string *result );
 
 /**
  * Referenced from http://dev.w3.org/html5/webvtt/#webvtt-start-tag-class-state
  */
-WEBVTT_INTERN webvtt_status webvtt_class_state( webvtt_byte **position,
-  webvtt_token_state *token_state, webvtt_stringlist *css_classes );
+WEBVTT_INTERN webvtt_status
+webvtt_class_state( const char **position, webvtt_token_state *token_state,
+                    webvtt_stringlist *css_classes );
 
 /**
- * Referenced from 
+ * Referenced from
  * http://dev.w3.org/html5/webvtt/#webvtt-start-tag-annotation-state
  */
-WEBVTT_INTERN webvtt_status webvtt_annotation_state( webvtt_byte **position,
-  webvtt_token_state *token_state, webvtt_string *annotation );
+WEBVTT_INTERN webvtt_status
+webvtt_annotation_state( const char **position, webvtt_token_state *token_state,
+                         webvtt_string *annotation );
 
 /**
  * Referenced from http://dev.w3.org/html5/webvtt/#webvtt-end-tag-state
  */
-WEBVTT_INTERN webvtt_status webvtt_end_tag_state( webvtt_byte **position,
-  webvtt_token_state *token_state, webvtt_string *result );
+WEBVTT_INTERN webvtt_status
+webvtt_end_tag_state( const char **position, webvtt_token_state *token_state,
+                      webvtt_string *result );
 
 /**
  * Referenced from http://dev.w3.org/html5/webvtt/#webvtt-timestamp-tag-state
  */
-WEBVTT_INTERN webvtt_status webvtt_timestamp_state( webvtt_byte **position,
-  webvtt_token_state *token_state, webvtt_string *result );
+WEBVTT_INTERN webvtt_status
+webvtt_timestamp_state( const char **position, webvtt_token_state *token_state,
+                        webvtt_string *result );
 
-WEBVTT_INTERN webvtt_status webvtt_parse_cuetext( webvtt_parser self, webvtt_cue *cue, webvtt_string *payload, int finished );
+WEBVTT_INTERN webvtt_status
+webvtt_parse_cuetext( webvtt_parser self, webvtt_cue *cue,
+                      webvtt_string *payload, int finished );
 
 #endif
--- a/media/webvtt/include/webvtt/cue.h
+++ b/media/webvtt/include/webvtt/cue.h
@@ -84,18 +84,25 @@ webvtt_cue_t {
   webvtt_string body;
 
   /**
     * Parsed cue-text (NULL if has not been parsed)
     */
   webvtt_node *node_head;
 } webvtt_cue;
 
-WEBVTT_EXPORT webvtt_status webvtt_create_cue( webvtt_cue **pcue );
-WEBVTT_EXPORT void webvtt_ref_cue( webvtt_cue *cue );
-WEBVTT_EXPORT void webvtt_release_cue( webvtt_cue **pcue );
-WEBVTT_EXPORT int webvtt_validate_cue( webvtt_cue *cue );
+WEBVTT_EXPORT webvtt_status
+webvtt_create_cue( webvtt_cue **pcue );
+
+WEBVTT_EXPORT void
+webvtt_ref_cue( webvtt_cue *cue );
+
+WEBVTT_EXPORT void
+webvtt_release_cue( webvtt_cue **pcue );
+
+WEBVTT_EXPORT int
+webvtt_validate_cue( webvtt_cue *cue );
 
 #if defined(__cplusplus) || defined(c_plusplus)
 }
 #endif
 
 #endif
--- a/media/webvtt/include/webvtt/error.h
+++ b/media/webvtt/include/webvtt/error.h
@@ -33,18 +33,18 @@
 extern "C" {
 #endif
 
   enum
   webvtt_error_t
   {
     /* There was a problem allocating something */
     WEBVTT_ALLOCATION_FAILED = 0,
-    /** 
-     * 'WEBVTT' is not the first 6 characters in the file 
+    /**
+     * 'WEBVTT' is not the first 6 characters in the file
      * (not counting UTF8 BOM)
      */
     WEBVTT_MALFORMED_TAG,
     /* An end-of-line sequence was expected, but not found. */
     WEBVTT_EXPECTED_EOL,
     /* A string of whitespace was expected, but not found. */
     WEBVTT_EXPECTED_WHITESPACE,
     /**
--- a/media/webvtt/include/webvtt/node.h
+++ b/media/webvtt/include/webvtt/node.h
@@ -19,17 +19,17 @@
  * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
- 
+
 #ifndef __WEBVTT_NODE_H__
 # define __WEBVTT_NODE_H__
 # include <webvtt/string.h>
 
 #if defined(__cplusplus) || defined(c_plusplus)
 extern "C" {
 #endif
 
@@ -44,24 +44,25 @@ webvtt_node_kind_t {
   WEBVTT_NODE_INTERNAL_START = 0,
   WEBVTT_CLASS = 0 | WEBVTT_NODE_INTERNAL,
   WEBVTT_ITALIC = 1 | WEBVTT_NODE_INTERNAL,
   WEBVTT_BOLD = 2 | WEBVTT_NODE_INTERNAL,
   WEBVTT_UNDERLINE = 3 | WEBVTT_NODE_INTERNAL,
   WEBVTT_RUBY = 4 | WEBVTT_NODE_INTERNAL,
   WEBVTT_RUBY_TEXT = 5 | WEBVTT_NODE_INTERNAL,
   WEBVTT_VOICE = 6 | WEBVTT_NODE_INTERNAL,
+  WEBVTT_LANG = 7 | WEBVTT_NODE_INTERNAL,
 
   /**
     * This type of node has should not be rendered.
     * It is the top of the node list and only contains a list of nodes.
     */
-  WEBVTT_HEAD_NODE = 7,
+  WEBVTT_HEAD_NODE = 8,
 
-  WEBVTT_NODE_INTERNAL_END = 7,
+  WEBVTT_NODE_INTERNAL_END = 8,
 
   /**
     * Leaf Node objects
     */
   WEBVTT_NODE_LEAF_START = 256,
   WEBVTT_TEXT = 256 | WEBVTT_NODE_LEAF,
   WEBVTT_TIME_STAMP = 257 | WEBVTT_NODE_LEAF,
 
@@ -88,41 +89,47 @@ webvtt_node_kind_t {
 
 struct webvtt_internal_node_data_t;
 
 typedef struct
 webvtt_node_t {
 
   struct webvtt_refcount_t refs;
   /**
-    * The specification asks for uni directional linked list, but we have added 
-    * a parent node in order to facilitate an iterative cue text parsing 
+    * The specification asks for uni directional linked list, but we have added
+    * a parent node in order to facilitate an iterative cue text parsing
     * solution.
     */
   struct webvtt_node_t *parent;
   webvtt_node_kind kind;
 
   union {
     webvtt_string text;
     webvtt_timestamp timestamp;
     struct webvtt_internal_node_data_t *internal_data;
   } data;
 } webvtt_node;
 
 typedef struct
 webvtt_internal_node_data_t {
   webvtt_string annotation;
+  webvtt_string lang;
   webvtt_stringlist *css_classes;
 
   webvtt_uint alloc;
   webvtt_uint length;
   webvtt_node **children;
 } webvtt_internal_node_data;
 
-WEBVTT_EXPORT void webvtt_init_node( webvtt_node **node );
-WEBVTT_EXPORT void webvtt_ref_node( webvtt_node *node );
-WEBVTT_EXPORT void webvtt_release_node( webvtt_node **node );
+WEBVTT_EXPORT void
+webvtt_init_node( webvtt_node **node );
+
+WEBVTT_EXPORT void
+webvtt_ref_node( webvtt_node *node );
+
+WEBVTT_EXPORT void
+webvtt_release_node( webvtt_node **node );
 
 #if defined(__cplusplus) || defined(c_plusplus)
 }
 #endif
 
 #endif
--- a/media/webvtt/include/webvtt/parser.h
+++ b/media/webvtt/include/webvtt/parser.h
@@ -30,29 +30,40 @@
 # include "string.h"
 # include "cue.h"
 # include "error.h"
 
 #if defined(__cplusplus) || defined(c_plusplus)
 extern "C" {
 #endif
 
-  typedef struct webvtt_parser_t *webvtt_parser;
+typedef struct webvtt_parser_t *webvtt_parser;
 
-  /**
-   * Allows application to request error reporting
-   */
-  typedef int ( WEBVTT_CALLBACK *webvtt_error_fn )( void *userdata, webvtt_uint line, webvtt_uint col,
-      webvtt_error error );
-  typedef void ( WEBVTT_CALLBACK *webvtt_cue_fn )( void *userdata, webvtt_cue *cue );
+/**
+ * Allows application to request error reporting
+ */
+typedef int ( WEBVTT_CALLBACK *webvtt_error_fn )( void *userdata,
+                                                  webvtt_uint line,
+                                                  webvtt_uint col,
+                                                  webvtt_error error );
+
+typedef void ( WEBVTT_CALLBACK *webvtt_cue_fn )( void *userdata,
+                                                 webvtt_cue *cue );
 
 
-  WEBVTT_EXPORT webvtt_status webvtt_create_parser( webvtt_cue_fn on_read, webvtt_error_fn on_error, void *
-      userdata, webvtt_parser *ppout );
-  WEBVTT_EXPORT void webvtt_delete_parser( webvtt_parser parser );
-  WEBVTT_EXPORT webvtt_status webvtt_parse_chunk( webvtt_parser self, const void *buffer, webvtt_uint len );
-  WEBVTT_EXPORT webvtt_status webvtt_finish_parsing( webvtt_parser self );
-  
+WEBVTT_EXPORT webvtt_status
+webvtt_create_parser( webvtt_cue_fn on_read, webvtt_error_fn on_error,
+                      void * userdata, webvtt_parser *ppout );
+
+WEBVTT_EXPORT void
+webvtt_delete_parser( webvtt_parser parser );
+
+WEBVTT_EXPORT webvtt_status
+webvtt_parse_chunk( webvtt_parser self, const void *buffer, webvtt_uint len );
+
+WEBVTT_EXPORT webvtt_status
+webvtt_finish_parsing( webvtt_parser self );
+
 #if defined(__cplusplus) || defined(c_plusplus)
 }
 #endif
 
 #endif
--- a/media/webvtt/include/webvtt/string.h
+++ b/media/webvtt/include/webvtt/string.h
@@ -46,141 +46,179 @@ webvtt_string_t {
   webvtt_string_data *d;
 };
 
 /**
  * webvtt_init_string
  *
  * initialize a string to point to the empty string
  */
-WEBVTT_EXPORT void webvtt_init_string( webvtt_string *result );
+WEBVTT_EXPORT void
+webvtt_init_string( webvtt_string *result );
 
 /**
  * webvtt_string_is_empty
- * 
+ *
  * return whether or not the string is empty
- * qualifications for it being empty are it equaling &empty_string or its length equaling 0
+ * qualifications for it being empty are it equaling &empty_string or its
+ * length equaling 0
  */
-WEBVTT_EXPORT webvtt_uint webvtt_string_is_empty( const webvtt_string *str );
+WEBVTT_EXPORT webvtt_uint
+webvtt_string_is_empty( const webvtt_string *str );
 
 /**
  * webvtt_create_string
  *
  * allocate a new string object with an initial capacity of 'alloc'
- * (the string data of 'result' is not expected to contain string data, 
- * regardless of its value. be sure to release existing strings before using 
+ * (the string data of 'result' is not expected to contain string data,
+ * regardless of its value. be sure to release existing strings before using
  * webvtt_create_string)
  */
-WEBVTT_EXPORT webvtt_status webvtt_create_string( webvtt_uint32 alloc, webvtt_string *result );
+WEBVTT_EXPORT webvtt_status
+webvtt_create_string( webvtt_uint32 alloc, webvtt_string *result );
 
 /**
  * webvtt_create_init_string
  *
- * allocate and initialize a string with the contents of 'init_text' of length 
+ * allocate and initialize a string with the contents of 'init_text' of length
  * 'len' if 'len' < 0, assume init_text to be null-terminated.
  */
-WEBVTT_EXPORT webvtt_status webvtt_create_string_with_text( webvtt_string *result, const webvtt_byte *init_text, int len );
+WEBVTT_EXPORT webvtt_status
+webvtt_create_string_with_text( webvtt_string *out, const char *init_text,
+                                int len );
 
 /**
  * webvtt_ref_string
  *
  * increase the reference count of--or retain--a string
  *
  * when the reference count drops to zero, the string is deallocated.
  */
-WEBVTT_EXPORT void webvtt_ref_string( webvtt_string *str );
+WEBVTT_EXPORT void
+webvtt_ref_string( webvtt_string *str );
 
 /**
  * webvtt_release_string
  *
  * decrease the reference count of--or release--a string
  *
  * when the reference count drops to zero, the string is deallocated.
  */
-WEBVTT_EXPORT void webvtt_release_string( webvtt_string *str );
+WEBVTT_EXPORT void
+webvtt_release_string( webvtt_string *str );
 
 /**
  * webvtt_string_detach
  *
  * ensure that the reference count of a string is exactly 1
  *
  * if the reference count is greater than 1, allocate a new copy of the string
  * and return it.
  */
-WEBVTT_EXPORT webvtt_status webvtt_string_detach( webvtt_string *str );
+WEBVTT_EXPORT webvtt_status
+webvtt_string_detach( webvtt_string *str );
 
 /**
  * webvtt_copy_string
  *
  * shallow-clone 'right', storing the result in 'left'.
  */
-WEBVTT_EXPORT void webvtt_copy_string( webvtt_string *left, const webvtt_string *right );
+WEBVTT_EXPORT void
+webvtt_copy_string( webvtt_string *left, const webvtt_string *right );
 
 /**
  * webvtt_string_text
  *
  * return the text contents of a string
  */
-WEBVTT_EXPORT const webvtt_byte *webvtt_string_text( const webvtt_string *str );
+WEBVTT_EXPORT const char *
+webvtt_string_text( const webvtt_string *str );
 
 /**
  * webvtt_string_length
  *
  * return the length of a strings text
  */
-WEBVTT_EXPORT webvtt_uint32 webvtt_string_length( const webvtt_string *str );
+WEBVTT_EXPORT webvtt_uint32
+webvtt_string_length( const webvtt_string *str );
 
 /**
  * webvtt_string_capacity
  *
  * return the current capacity of a string
  */
-WEBVTT_EXPORT webvtt_uint32 webvtt_string_capacity( const webvtt_string *str );
+WEBVTT_EXPORT webvtt_uint32
+webvtt_string_capacity( const webvtt_string *str );
 
 /**
  * webvtt_string_getline
  *
- * collect a line of text (terminated by CR/LF/CRLF) from a buffer, without 
+ * collect a line of text (terminated by CR/LF/CRLF) from a buffer, without
  * including the terminating character(s)
  */
-WEBVTT_EXPORT int webvtt_string_getline( webvtt_string *str, const webvtt_byte *buffer,
-    webvtt_uint *pos, int len, int *truncate, webvtt_bool finish );
+WEBVTT_EXPORT int
+webvtt_string_getline( webvtt_string *str, const char *buffer,
+                       webvtt_uint *pos, int len, int *truncate,
+                       webvtt_bool finish );
 
 /**
  * webvtt_string_putc
  *
  * append a single byte to a webvtt string
  */
-WEBVTT_EXPORT webvtt_status webvtt_string_putc( webvtt_string *str, webvtt_byte to_append );
+WEBVTT_EXPORT webvtt_status
+webvtt_string_putc( webvtt_string *str, char to_append );
 
+/**
+ * webvtt_string_replace
+ *
+ * replace first instance of substring with replacement string.
+ */
+WEBVTT_EXPORT webvtt_status
+webvtt_string_replace( webvtt_string *str, const char *search, int search_len,
+                       const char *replace, int replace_len );
+
+/**
+ * webvtt_string_replace_all
+ *
+ * replace all instances of substring with replacement string
+ */
+WEBVTT_EXPORT webvtt_status
+webvtt_string_replace_all( webvtt_string *str, const char *search,
+                           int search_len, const char *replace,
+                           int replace_len );
 
 /**
  * webvtt_string_is_equal
  *
  * compare a string's text to a byte array
  *
  */
-WEBVTT_EXPORT webvtt_bool webvtt_string_is_equal( const webvtt_string *str, 
-    const webvtt_byte *to_compare, int len );
+WEBVTT_EXPORT webvtt_bool
+webvtt_string_is_equal( const webvtt_string *str, const char *to_compare,
+                        int len );
 
 /**
  * webvtt_string_append
  *
  * append a stream of bytes to the string.
  *
  * if 'len' is < 0, then buffer is expected to be null-terminated.
  */
-WEBVTT_EXPORT webvtt_status webvtt_string_append( webvtt_string *str, const webvtt_byte *buffer, int len );
+WEBVTT_EXPORT webvtt_status
+webvtt_string_append( webvtt_string *str, const char *buffer, int len );
 
 /**
  * webvtt_string_appendstr
  *
- * append the contents of a string object 'other' to a string object 'str'
+ * if 'len' is < 0 then the max length of the string will be taken to be the
+ * first occurence of a null byte character
  */
-WEBVTT_EXPORT webvtt_status webvtt_string_append_string( webvtt_string *str, const webvtt_string *other );
+WEBVTT_EXPORT webvtt_status
+webvtt_string_append_string( webvtt_string *str, const webvtt_string *other );
 
 /**
  * basic dynamic array of strings
  */
 struct
 webvtt_stringlist_t {
   struct webvtt_refcount_t refs;
   webvtt_uint alloc;
@@ -188,92 +226,106 @@ webvtt_stringlist_t {
   webvtt_string *items;
 };
 
 /**
  * webvtt_create_stringlist
  *
  * allocate a new, empty stringlist
  */
-WEBVTT_EXPORT webvtt_status webvtt_create_stringlist( webvtt_stringlist **result );
+WEBVTT_EXPORT webvtt_status
+webvtt_create_stringlist( webvtt_stringlist **result );
 
 /**
  * webvtt_ref_stringlist
  *
  * Increase the ref count of the stringlist
  */
-WEBVTT_EXPORT void webvtt_ref_stringlist( webvtt_stringlist *list );
+WEBVTT_EXPORT void
+webvtt_ref_stringlist( webvtt_stringlist *list );
 
 /**
  * webvtt_copy_stringlist
  *
  * create a copy shallow of right from left
  */
-WEBVTT_EXPORT void webvtt_copy_stringlist( webvtt_stringlist **left, webvtt_stringlist *right );
+WEBVTT_EXPORT void
+webvtt_copy_stringlist( webvtt_stringlist **left, webvtt_stringlist *right );
 
 /**
  * webvtt_release_stringlist
  *
  * Decrease the ref count of the stringlist and delete it if the ref count is 0
  */
-WEBVTT_EXPORT void webvtt_release_stringlist( webvtt_stringlist **list );
+WEBVTT_EXPORT void
+webvtt_release_stringlist( webvtt_stringlist **list );
 
 /**
  * webvtt_stringlist_push
  *
  * add a new string to the end of the stringlist
  */
-WEBVTT_EXPORT webvtt_status webvtt_stringlist_push( webvtt_stringlist *list, webvtt_string *str );
+WEBVTT_EXPORT webvtt_status
+webvtt_stringlist_push( webvtt_stringlist *list, webvtt_string *str );
+
+/**
+ * webvtt_stringlist_pop
+ *
+ * pop the top of the string list
+ */
+WEBVTT_EXPORT webvtt_bool
+webvtt_stringlist_pop( webvtt_stringlist *list, webvtt_string *out );
 
 /**
  * Helper functions
  */
 
 /**
  * webvtt_next_utf8
  *
  * move the 'begin' pointer to the beginning of the next utf8 character
  * sequence.
  */
-WEBVTT_EXPORT webvtt_bool webvtt_next_utf8( const webvtt_byte **begin,
-  const webvtt_byte *end );
+WEBVTT_EXPORT webvtt_bool
+webvtt_next_utf8( const char **begin, const char *end );
 
 /**
  * webvtt_skip_utf8
  *
  * move the 'begin' pointer to the beginning of the utf8 character
  * 'n_chars' away.
  *
  * if 'end' is less than 'begin', will seek backwards.
  */
-WEBVTT_EXPORT webvtt_bool webvtt_skip_utf8( const webvtt_byte **begin,
-  const webvtt_byte *end, int n_chars );
+WEBVTT_EXPORT webvtt_bool
+webvtt_skip_utf8( const char **begin, const char *end, int n_chars );
 
 /**
  * webvtt_utf8_to_utf16
  *
  * return the utf16 value of a given character
  */
-WEBVTT_EXPORT webvtt_uint16 webvtt_utf8_to_utf16( const webvtt_byte *utf8,
-  const webvtt_byte *end, webvtt_uint16 *high_surrogate );
+WEBVTT_EXPORT webvtt_uint16
+webvtt_utf8_to_utf16( const char *utf8, const char *end, webvtt_uint16 *high );
 
 /**
  * webvtt_utf8_chcount
  *
- * return the number of Unicode characters (as opposed to units) 
+ * return the number of Unicode characters (as opposed to units)
  * in a utf8 string
  */
-WEBVTT_EXPORT int webvtt_utf8_chcount( const webvtt_byte *utf8,
-  const webvtt_byte *end );
+WEBVTT_EXPORT int
+webvtt_utf8_chcount( const char *utf8, const char *end );
 
 /**
  * webvtt_utf8_length
  *
  * if 'utf8' points to a lead byte, return the length of the sequence.
  * if 'utf8' is null, return 0.
  * if 'utf8' points to a trail byte, return -1
  */
-WEBVTT_EXPORT int webvtt_utf8_length( const webvtt_byte *utf8 );
+WEBVTT_EXPORT int
+webvtt_utf8_length( const char *utf8 );
 
 #if defined(__cplusplus) || defined(c_plusplus)
 }
 #endif
 #endif
--- a/media/webvtt/include/webvtt/util.h
+++ b/media/webvtt/include/webvtt/util.h
@@ -27,32 +27,32 @@
 
 #ifndef __WEBVTT_UTIL_H__
 # define __WEBVTT_UTIL_H__
 
 #if defined(__cplusplus) || defined(c_plusplus)
 extern "C" {
 #endif
 
+/**
+ * Assuming that libc provides stdint.h unless we have a good reason to believe
+ * it doesn't... MSVC does not ship stdint.h prior to MSVC2010.
+ */
 # if !defined(_MSC_VER) || _MSC_VER >= 1600
-/**
- * For non-MSVC compilers, or MSVC2010 or later, assume we have
- * stdint.h
- */
 #   define WEBVTT_HAVE_STDINT 1
 #   include <stdint.h>
 # endif
 
-# if defined(_WIN32) || defined(__WIN32__) || defined(__TOS_WIN__) ||\
+# if defined(_WIN32) || defined(__WIN32__) || defined(__TOS_WIN__) || \
      defined(__WINDOWS__)
 #   define WEBVTT_OS_WIN32 1
 #   if defined(_WIN64)
 #     define WEBVTT_OS_WIN64 1
 #   endif
-# endif
+# endif 
 
 # if defined(_MSC_VER)
 #   define WEBVTT_CC_MSVC 1
 #   define WEBVTT_CALLBACK __cdecl
 #   if WEBVTT_BUILD_LIBRARY
 #     define WEBVTT_EXPORT __declspec(dllexport)
 #   elif !WEBVTT_STATIC
 #     define WEBVTT_EXPORT __declspec(dllimport)
@@ -74,16 +74,20 @@ extern "C" {
 #       define WEBVTT_EXPORT __attribute__((visibility("default")))
 #       define WEBVTT_INTERN __attribute__((visibility("hidden")))
 #     endif
 #   endif
 # else
 #   define WEBVTT_CC_UNKNOWN 1
 # endif
 
+# ifndef WEBVTT_HAVE_STDINT
+#   define WEBVTT_HAVE_STDINT 0
+# endif
+
 # ifndef WEBVTT_CALLBACK
 #   define WEBVTT_CALLBACK
 # endif
 # ifndef WEBVTT_EXPORT
 #   define WEBVTT_EXPORT
 # endif
 # ifndef WEBVTT_INTERN
 #   define WEBVTT_INTERN
@@ -92,17 +96,17 @@ extern "C" {
 # if defined(__cplusplus) || defined(c_plusplus)
 #   define WEBVTT_INLINE inline
 # elif WEBVTT_CC_MSVC
 #   define WEBVTT_INLINE __inline
 # elif WEBVTT_CC_GCC
 #   define WEBVTT_INLINE __inline__
 # endif
 
-# ifdef WEBVTT_HAVE_STDINT
+# if WEBVTT_HAVE_STDINT
   typedef int8_t webvtt_int8;
   typedef int16_t webvtt_int16;
   typedef int32_t webvtt_int32;
   typedef int64_t webvtt_int64;
   typedef uint8_t webvtt_uint8;
   typedef uint16_t webvtt_uint16;
   typedef uint32_t webvtt_uint32;
   typedef uint64_t webvtt_uint64;
@@ -132,47 +136,51 @@ extern "C" {
   typedef signed short webvtt_short;
   typedef signed long webvtt_long;
   typedef signed long long webvtt_longlong;
   typedef unsigned int webvtt_uint;
   typedef unsigned char webvtt_uchar;
   typedef unsigned short webvtt_ushort;
   typedef unsigned long webvtt_ulong;
   typedef unsigned long long webvtt_ulonglong;
-  typedef webvtt_uint8 webvtt_byte;
   typedef webvtt_int webvtt_bool;
   typedef webvtt_uint32 webvtt_length;
   typedef webvtt_uint64 webvtt_timestamp;
 
   /**
-   * Memory allocation callbacks, which allow overriding the allocation strategy.
+   * Memory allocation callbacks, which allow overriding the allocation
+   * strategy.
    */
-  typedef void *(WEBVTT_CALLBACK *webvtt_alloc_fn_ptr)( void *userdata, webvtt_uint nbytes );
-  typedef void (WEBVTT_CALLBACK *webvtt_free_fn_ptr)( void *userdata, void *pmem );
+  typedef void *(WEBVTT_CALLBACK *webvtt_alloc_fn_ptr)( void *userdata,
+                                                        webvtt_uint nbytes );
+  typedef void (WEBVTT_CALLBACK *webvtt_free_fn_ptr)( void *userdata,
+                                                      void *pmem );
 
   /**
-   * Allocation functions. webvtt_set_allocator() should really be the first 
-   * function called. However, it will do nothing (and not report error) if 
-   * objects have already been allocated and not freed. Therefore, it is NOT 
+   * Allocation functions. webvtt_set_allocator() should really be the first
+   * function called. However, it will do nothing (and not report error) if
+   * objects have already been allocated and not freed. Therefore, it is NOT
    * safe to assume that it worked and use the supplied
    * function pointers directly.
    *
-   * Currently, set_allocator (and the other allocation functions) do not use 
-   * any locking mechanism, so the library cannot be considered to be 
+   * Currently, set_allocator (and the other allocation functions) do not use
+   * any locking mechanism, so the library cannot be considered to be
    * thread-safe at this time if changing the allocator is used.
    *
-   * I don't believe there is much of a reason to worry about the overhead of 
+   * I don't believe there is much of a reason to worry about the overhead of
    * using function pointers for allocation, as it is negligible compared to the
-   * act of allocating memory itself, and having a configurable allocation 
+   * act of allocating memory itself, and having a configurable allocation
    * strategy could be very useful.
    */
   WEBVTT_EXPORT void *webvtt_alloc( webvtt_uint nb );
   WEBVTT_EXPORT void *webvtt_alloc0( webvtt_uint nb );
   WEBVTT_EXPORT void webvtt_free( void *data );
-  WEBVTT_EXPORT void webvtt_set_allocator( webvtt_alloc_fn_ptr alloc, webvtt_free_fn_ptr free, void *userdata );
+  WEBVTT_EXPORT void webvtt_set_allocator( webvtt_alloc_fn_ptr alloc,
+                                           webvtt_free_fn_ptr free,
+                                           void *userdata );
 
   enum
   webvtt_status_t {
     WEBVTT_SUCCESS = 0,
     WEBVTT_UNFINISHED = -1,
     WEBVTT_PARSE_ERROR = -2,
     WEBVTT_OUT_OF_MEMORY = -3,
     WEBVTT_INVALID_PARAM = -4,
@@ -180,17 +188,17 @@ extern "C" {
     WEBVTT_UNSUCCESSFUL = -6,
     WEBVTT_INVALID_TAG_NAME = -7,
     WEBVTT_INVALID_TOKEN_TYPE = -8,
     WEBVTT_INVALID_TOKEN_STATE = -9,
     WEBVTT_FAIL = -10, /* This is not very specific! */
 
     /**
      * A failure that requires the parser to completely skip beyond a cue.
-     */ 
+     */
     WEBVTT_SKIP_CUE = -11,
 
     /**
      * Parser should move to the next cuesetting.
      */
     WEBVTT_NEXT_CUESETTING = -12,
 
     /*
--- a/media/webvtt/lexer.c
+++ b/media/webvtt/lexer.c
@@ -23,24 +23,27 @@
  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
 #include "parser_internal.h"
 
 /**
- * There are probably enough jumps and stack pops here to fill up quite a few caches but it may still
+ * There are probably enough jumps and stack pops here to fill up quite a few
+ * caches but it may still
  * be much smaller than a gigantic table-based solution.
  *
- * TODO: Replace all char literals with hex values, just in case compiling on a machine which uses an
+ * TODO: Replace all char literals with hex values, just in case compiling on a
+ * machine which uses an
  * incompatible character set
  */
 
-#define U_DIGIT case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: case 0x37: case 0x38: case 0x39:
+#define U_DIGIT case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: \
+                case 0x35: case 0x36: case 0x37: case 0x38: case 0x39:
 #define U_WHITESPACE case 0x0D: case 0x0A: case 0x20: case 0x09:
 #define U_SPACE case 0x20:
 #define U_TAB case 0x09:
 #define U_CR case 0x0D:
 #define U_LF case 0x0A:
 
 #define U_DASH case 0x2D:
 #define U_PERIOD case 0x2E:
@@ -129,35 +132,40 @@
   if( self->token_pos >= (sizeof(self->token) - 1 ) ) \
   { \
     RETURN(X) \
   }
 
 #define BEGIN_STATE(state) case state: { switch(c) {
 #define END_STATE DEFAULT BACKUP return BADTOKEN; } } break;
 #define END_STATE_EX } } break;
-
-#define BACKUP (*pos)--; --self->column; self->token[--self->token_pos] = 0; self->tstate = L_START;
 #define SET_STATE(X) self->tstate = X; break;
 #define RETURN(X) self->tstate = L_START; return X;
 #define SET_NEWLINE self->line++; self->column = 1; RETURN(NEWLINE)
 #define CONTINUE continue;
+#define BREAK break;
 
-#define RESET self->column = 1; self->bytes = self->token_pos = 0; self->tstate = L_START;
-#define BREAK break;
+#define BACKUP (*pos)--; \
+               --self->column; \
+               self->token[--self->token_pos] = 0; \
+               self->tstate = L_START;
+#define RESET self->column = 1; \
+              self->bytes = self->token_pos = 0; \
+              self->tstate = L_START;
 
 #define CHECK_BROKEN_TIMESTAMP \
 if(self->token_pos == sizeof(self->token) - 1 ) \
 { \
   ERROR(WEBVTT_MALFORMED_TIMESTAMP); \
   return BADTOKEN; \
 }
 
 WEBVTT_INTERN webvtt_status
-webvtt_lex_word( webvtt_parser self, webvtt_string *str, const webvtt_byte *buffer, webvtt_uint *ppos, webvtt_uint length, webvtt_bool finish )
+webvtt_lex_word( webvtt_parser self, webvtt_string *str, const char *buffer,
+                 webvtt_uint *ppos, webvtt_uint length, webvtt_bool finish )
 {
   webvtt_status status = WEBVTT_SUCCESS;
   webvtt_uint pos = *ppos;
   if( !str ) {
     return WEBVTT_INVALID_PARAM;
   }
 
   webvtt_init_string( str );
@@ -195,26 +203,26 @@ webvtt_lex_word( webvtt_parser self, web
 /**
  * webvtt_lex_newline
  *
  * Get newline sequence in re-entrant fashion. self->tstate must be
  * L_START or L_NEWLINE0 for this function to behave correctly.
  */
 WEBVTT_INTERN webvtt_token
 webvtt_lex_newline( webvtt_parser self, const
-  webvtt_byte *buffer, webvtt_uint *pos, webvtt_uint length,
+  char *buffer, webvtt_uint *pos, webvtt_uint length,
   webvtt_bool finish )
 {
   webvtt_uint p = *pos;
 
   /* Ensure that we've got a valid token-state for this use-case. */
   DIE_IF( self->tstate != L_START && self->tstate != L_NEWLINE0 );
 
   while( p < length ) {
-    webvtt_byte c = buffer[ p++ ];
+    unsigned char c = (unsigned char)buffer[ p++ ];
     self->token[ self->token_pos++ ] = c;
     self->token[ self->token_pos ] = 0;
     self->bytes++;
 
     switch( self->tstate ) {
       case L_START:
         if( c == '\n' ) {
           *pos = p;
@@ -265,20 +273,21 @@ backup:
   if( self->tstate == L_NEWLINE0 ) {
     self->tstate = L_START;
     return NEWLINE;
   }
   return BADTOKEN;
 }
 
 WEBVTT_INTERN webvtt_token
-webvtt_lex( webvtt_parser self, const webvtt_byte *buffer, webvtt_uint *pos, webvtt_uint length, webvtt_bool finish )
+webvtt_lex( webvtt_parser self, const char *buffer, webvtt_uint *pos,
+            webvtt_uint length, webvtt_bool finish )
 {
   while( *pos < length ) {
-    webvtt_byte c = buffer[(*pos)++];
+    unsigned char c = (unsigned char)buffer[(*pos)++];
     self->token[ self->token_pos++ ] = c;
     self->token[ self->token_pos ] = 0;
     self->column++;
     self->bytes++;
     switch( self->tstate ) {
         BEGIN_STATE(L_START)
           U_DIGIT { SET_STATE(L_DIGIT0) }
           U_W  { SET_STATE(L_WEBVTT0) }
--- a/media/webvtt/node.c
+++ b/media/webvtt/node.c
@@ -19,50 +19,51 @@
  * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
- 
+
  #include <string.h>
  #include <stdlib.h>
  #include "node_internal.h"
- 
+
  static webvtt_node empty_node = {
   { 1 }, /* init ref count */
   0, /* parent */
   WEBVTT_EMPTY_NODE, /* node kind */
   { { 0 } } /* value */
 };
 
 WEBVTT_EXPORT void
 webvtt_ref_node( webvtt_node *node )
 {
   if( node ) {
     webvtt_ref( &node->refs );
   }
 }
 
-WEBVTT_EXPORT void 
+WEBVTT_EXPORT void
 webvtt_init_node( webvtt_node **node )
 {
   if( *node != &empty_node ) {
-    if( node && *node ) { 
+    if( node && *node ) {
       webvtt_release_node( node );
     }
     *node = &empty_node;
     webvtt_ref_node( *node );
   }
 }
 
 WEBVTT_INTERN webvtt_status
-webvtt_create_node( webvtt_node **node, webvtt_node_kind kind, webvtt_node *parent )
+webvtt_create_node( webvtt_node **node, webvtt_node_kind kind,
+                    webvtt_node *parent )
 {
   webvtt_node *temp_node;
 
   if( !node ) {
     return WEBVTT_INVALID_PARAM;
   }
 
   if( !( temp_node = (webvtt_node *)webvtt_alloc0(sizeof(*temp_node)) ) )
@@ -74,101 +75,135 @@ webvtt_create_node( webvtt_node **node, 
   temp_node->kind = kind;
   temp_node->parent = parent;
   *node = temp_node;
 
   return WEBVTT_SUCCESS;
 }
 
 WEBVTT_INTERN webvtt_status
-webvtt_create_internal_node( webvtt_node **node, webvtt_node *parent, webvtt_node_kind kind, 
-  webvtt_stringlist *css_classes, webvtt_string *annotation )
+webvtt_create_internal_node( webvtt_node **node, webvtt_node *parent,
+                             webvtt_node_kind kind,
+                             webvtt_stringlist *css_classes,
+                             webvtt_string *annotation )
 {
   webvtt_status status;
   webvtt_internal_node_data *node_data;
 
   if( WEBVTT_FAILED( status = webvtt_create_node( node, kind, parent ) ) ) {
     return status;
   }
 
-  if ( !( node_data = (webvtt_internal_node_data *)webvtt_alloc0( sizeof(*node_data) ) ) )
+  if ( !( node_data =
+         (webvtt_internal_node_data *)webvtt_alloc0( sizeof(*node_data) ) ) )
   {
     return WEBVTT_OUT_OF_MEMORY;
   }
 
   webvtt_copy_stringlist( &node_data->css_classes, css_classes );
   webvtt_copy_string( &node_data->annotation, annotation );
+  webvtt_init_string( &node_data->lang );
   node_data->children = NULL;
   node_data->length = 0;
   node_data->alloc = 0;
 
   (*node)->data.internal_data = node_data;
 
   return WEBVTT_SUCCESS;
 }
 
 WEBVTT_INTERN webvtt_status
+webvtt_create_lang_node( webvtt_node **node, webvtt_node *parent,
+                         webvtt_stringlist *css_classes,
+                         webvtt_string *lang )
+{
+  webvtt_string empty_annotation;
+  webvtt_status status;
+
+  webvtt_init_string( &empty_annotation );
+  status = webvtt_create_internal_node( node, parent, WEBVTT_LANG, css_classes,
+                                        &empty_annotation );
+  webvtt_release_string( &empty_annotation );
+
+  /* We need to release as create internal node put a default value in. */
+  webvtt_release_string( &(*node)->data.internal_data->lang );
+  webvtt_copy_string( &(*node)->data.internal_data->lang, lang );
+
+  return status;
+}
+
+WEBVTT_INTERN webvtt_status
 webvtt_create_head_node( webvtt_node **node )
 {
   webvtt_status status;
-  webvtt_string temp_annotation;
+  webvtt_string empty_annotation;
 
-  webvtt_init_string( &temp_annotation );
-  if( WEBVTT_FAILED( status = webvtt_create_internal_node( node, NULL, WEBVTT_HEAD_NODE, NULL, &temp_annotation ) ) ) {
+  webvtt_init_string( &empty_annotation );
+  if( WEBVTT_FAILED( status =
+                   webvtt_create_internal_node( node, NULL, WEBVTT_HEAD_NODE,
+                                                NULL, &empty_annotation ) ) ) {
     return status;
   }
 
+  webvtt_release_string( &empty_annotation );
   return WEBVTT_SUCCESS;
 }
 
 WEBVTT_INTERN webvtt_status
-webvtt_create_timestamp_node( webvtt_node **node, webvtt_node *parent, webvtt_timestamp time_stamp )
+webvtt_create_timestamp_node( webvtt_node **node, webvtt_node *parent,
+                              webvtt_timestamp time_stamp )
 {
   webvtt_status status;
 
-  if( WEBVTT_FAILED( status = webvtt_create_node( node, WEBVTT_TIME_STAMP, parent ) ) ) {
+  if( WEBVTT_FAILED( status = webvtt_create_node( node,
+                                                  WEBVTT_TIME_STAMP,
+                                                  parent ) ) ) {
     return status;
   }
 
   (*node)->data.timestamp = time_stamp;
 
   return WEBVTT_SUCCESS;
 }
 
 WEBVTT_INTERN webvtt_status
-webvtt_create_text_node( webvtt_node **node, webvtt_node *parent, webvtt_string *text )
+webvtt_create_text_node( webvtt_node **node, webvtt_node *parent,
+                         webvtt_string *text )
 {
   webvtt_status status;
 
-  if( WEBVTT_FAILED( status = webvtt_create_node( node, WEBVTT_TEXT, parent ) ) ) {
+  if( WEBVTT_FAILED( status = webvtt_create_node( node, WEBVTT_TEXT,
+                                                  parent ) ) ) {
     return status;
   }
 
   webvtt_copy_string( &(*node)->data.text, text );
 
   return WEBVTT_SUCCESS;
 
 }
 
-WEBVTT_EXPORT void 
+WEBVTT_EXPORT void
 webvtt_release_node( webvtt_node **node )
 {
   webvtt_uint i;
   webvtt_node *n;
-  
+
   if( !node || !*node ) {
     return;
   }
   n = *node;
 
   if( webvtt_deref( &n->refs )  == 0 ) {
     if( n->kind == WEBVTT_TEXT ) {
         webvtt_release_string( &n->data.text );
-    } else if( WEBVTT_IS_VALID_INTERNAL_NODE( n->kind ) && n->data.internal_data ) {
+    } else if( WEBVTT_IS_VALID_INTERNAL_NODE( n->kind ) &&
+               n->data.internal_data ) {
       webvtt_release_stringlist( &n->data.internal_data->css_classes );
+      webvtt_release_string( &n->data.internal_data->lang );
       webvtt_release_string( &n->data.internal_data->annotation );
       for( i = 0; i < n->data.internal_data->length; i++ ) {
         webvtt_release_node( n->data.internal_data->children + i );
       }
       webvtt_free( n->data.internal_data->children );
       webvtt_free( n->data.internal_data );
     }
     webvtt_free( n );
@@ -176,37 +211,37 @@ webvtt_release_node( webvtt_node **node 
   *node = 0;
 }
 
 WEBVTT_INTERN webvtt_status
 webvtt_attach_node( webvtt_node *parent, webvtt_node *to_attach )
 {
   webvtt_node **next = 0;
   webvtt_internal_node_data *nd = 0;
-  
+
   if( !parent || !to_attach || !parent->data.internal_data ) {
     return WEBVTT_INVALID_PARAM;
   }
   nd = parent->data.internal_data;
-  
+
   if( nd->alloc == 0 ) {
     next = (webvtt_node **)webvtt_alloc0( sizeof( webvtt_node * ) * 8 );
-    
+
     if( !next ) {
       return WEBVTT_OUT_OF_MEMORY;
     }
-    
+
     nd->children = next;
     nd->alloc = 8;
   }
-  
+
   if( nd->length + 1 >= ( nd->alloc / 3 ) * 2 ) {
 
     next = (webvtt_node **)webvtt_alloc0( sizeof( *next ) * nd->alloc * 2 );
-    
+
     if( !next ) {
       return WEBVTT_OUT_OF_MEMORY;
     }
 
     nd->alloc *= 2;
     memcpy( next, nd->children, nd->length * sizeof( webvtt_node * ) );
     webvtt_free( nd->children );
     nd->children = next;
--- a/media/webvtt/node_internal.h
+++ b/media/webvtt/node_internal.h
@@ -19,32 +19,53 @@
  * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
- 
+
 #ifndef __WEBVTT_NODE_INTERNAL_H__
 # define __WEBVTT_NODE_INTERNAL_H__
 # include <webvtt/node.h>
 
 /**
  * Routines for creating nodes.
  */
-WEBVTT_INTERN webvtt_status webvtt_create_node( webvtt_node **node, webvtt_node_kind kind, webvtt_node *parent );
-WEBVTT_INTERN webvtt_status webvtt_create_internal_node( webvtt_node **node, webvtt_node *parent, webvtt_node_kind kind, webvtt_stringlist *css_classes, webvtt_string *annotation );
+WEBVTT_INTERN webvtt_status
+webvtt_create_node( webvtt_node **node, webvtt_node_kind kind,
+                    webvtt_node *parent );
+
+WEBVTT_INTERN webvtt_status
+webvtt_create_internal_node( webvtt_node **node, webvtt_node *parent,
+                             webvtt_node_kind kind,
+                             webvtt_stringlist *css_classes,
+                             webvtt_string *annotation );
+
+WEBVTT_INTERN webvtt_status
+webvtt_create_lang_node( webvtt_node **node, webvtt_node *parent,
+                         webvtt_stringlist *css_classes,
+                         webvtt_string *lang );
+
 /**
  * We probably shouldn't have a 'head node' type.
  * We should just return a list of node trees...
  */
-WEBVTT_INTERN webvtt_status webvtt_create_head_node( webvtt_node **node );
-WEBVTT_INTERN webvtt_status webvtt_create_timestamp_node( webvtt_node **node, webvtt_node *parent, webvtt_timestamp time_stamp );
-WEBVTT_INTERN webvtt_status webvtt_create_text_node( webvtt_node **node, webvtt_node *parent, webvtt_string *text );
+WEBVTT_INTERN webvtt_status
+webvtt_create_head_node( webvtt_node **node );
+
+WEBVTT_INTERN webvtt_status
+webvtt_create_timestamp_node( webvtt_node **node, webvtt_node *parent,
+                              webvtt_timestamp time_stamp );
+
+WEBVTT_INTERN webvtt_status
+webvtt_create_text_node( webvtt_node **node, webvtt_node *parent,
+                         webvtt_string *text );
 
 /**
  * Attaches a node to the internal node list of another node.
  */
-WEBVTT_INTERN webvtt_status webvtt_attach_node( webvtt_node *parent, webvtt_node *to_attach );
+WEBVTT_INTERN webvtt_status
+webvtt_attach_node( webvtt_node *parent, webvtt_node *to_attach );
 
 #endif
--- a/media/webvtt/parser.c
+++ b/media/webvtt/parser.c
@@ -27,31 +27,34 @@
 
 #include "parser_internal.h"
 #include "cuetext_internal.h"
 #include "cue_internal.h"
 #include <string.h>
 
 #define _ERROR(X) do { if( skip_error == 0 ) { ERROR(X); } } while(0)
 
-static const webvtt_byte separator[] = {
+static const char separator[] = {
   '-', '-', '>'
 };
+/* UTF8 encoding of U+FFFD REPLACEMENT CHAR */
+static const char replacement[] = { 0xEF, 0xBF, 0xBD };
 
 #define MSECS_PER_HOUR (3600000)
 #define MSECS_PER_MINUTE (60000)
 #define MSECS_PER_SECOND (1000)
 #define BUFFER (self->buffer + self->position)
 #define MALFORMED_TIME ((webvtt_timestamp_t)-1.0)
 
-static webvtt_status find_bytes( const webvtt_byte *buffer, webvtt_uint len, const webvtt_byte *sbytes, webvtt_uint slen );
-static webvtt_int64 parse_int( const webvtt_byte **pb, int *pdigits );
-static void skip_spacetab( const webvtt_byte *text, webvtt_uint *pos,
+static webvtt_status find_bytes( const char *buffer, webvtt_uint len,
+                                 const char *sbytes, webvtt_uint slen );
+static webvtt_int64 parse_int( const char **pb, int *pdigits );
+static void skip_spacetab( const char *text, webvtt_uint *pos,
   webvtt_uint len, webvtt_uint *column );
-static void skip_until_white( const webvtt_byte *text, webvtt_uint *pos,
+static void skip_until_white( const char *text, webvtt_uint *pos,
   webvtt_uint len, webvtt_uint *column );
 
 WEBVTT_EXPORT webvtt_status
 webvtt_create_parser( webvtt_cue_fn on_read,
                       webvtt_error_fn on_error, void *
                       userdata,
                       webvtt_parser *ppout )
 {
@@ -155,17 +158,17 @@ cleanup_stack( webvtt_parser self )
 
 /**
  *
  */
 WEBVTT_EXPORT webvtt_status
 webvtt_finish_parsing( webvtt_parser self )
 {
   webvtt_status status = WEBVTT_SUCCESS;
-  const webvtt_byte buffer[] = "\0";
+  const char buffer[] = "\0";
   const webvtt_uint len = 0;
   webvtt_uint pos = 0;
 
   if( !self->finished ) {
     self->finished = 1;
 
 retry:
     switch( self->mode ) {
@@ -212,19 +215,16 @@ retry:
        * application if possible.
        */
       case M_CUETEXT:
         status = webvtt_proc_cuetext( self, buffer, &pos, len, self->finished );
         break;
       case M_SKIP_CUE:
         /* Nothing to do here. */
         break;
-      case M_READ_LINE:
-        /* Nothing to do here. */
-        break;
     }
     cleanup_stack( self );
   }
 
   return status;
 }
 
 WEBVTT_EXPORT void
@@ -246,73 +246,73 @@ webvtt_delete_parser( webvtt_parser self
 #define BEGIN_TOKEN switch(token) {
 #define END_TOKEN }
 #define IF_TRANSITION(Token,State) if( token == Token ) { self->state = State;
 #define ELIF_TRANSITION(Token,State) } else IF_TRANSITION(Token,State)
 #define ENDIF }
 #define ELSE } else {
 
 static int
-find_newline( const webvtt_byte *buffer, webvtt_uint *pos, webvtt_uint len )
+find_newline( const char *buffer, webvtt_uint *pos, webvtt_uint len )
 {
   while( *pos < len ) {
     if( buffer[ *pos ] == '\r' || buffer[ *pos ] == '\n' ) {
       return 1;
     } else {
       ( *pos )++;
     }
   }
   return -1;
 }
 
 static void
-skip_spacetab( const webvtt_byte *text, webvtt_uint *pos, webvtt_uint len,
+skip_spacetab( const char *text, webvtt_uint *pos, webvtt_uint len,
   webvtt_uint *column )
 {
   webvtt_uint c = 0;
   if( !column ) {
     column = &c;
   }
   while( *pos < len ) {
-    webvtt_byte ch = text[ *pos ];
+    char ch = text[ *pos ];
     if( ch == ' ' || ch == '\t' ) {
       ++( *pos );
       ++( *column );
     } else {
       break;
     }
   }
 }
 
 static void
-skip_until_white( const webvtt_byte *text, webvtt_uint *pos, webvtt_uint len,
+skip_until_white( const char *text, webvtt_uint *pos, webvtt_uint len,
   webvtt_uint *column )
 {
   webvtt_uint c = 0;
   if( !column ) {
     column = &c;
   }
   while( *pos < len ) {
-    webvtt_byte ch = text[ *pos ];
+    char ch = text[ *pos ];
     if( ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r' ) {
       break;
     } else {
       int length = webvtt_utf8_length( text + *pos );
       *pos += length;
       ++( *column );
     }
   }
 }
 
 /**
  * basic strnstr-ish routine
  */
 static webvtt_status
-find_bytes( const webvtt_byte *buffer, webvtt_uint len,
-    const webvtt_byte *sbytes, webvtt_uint slen )
+find_bytes( const char *buffer, webvtt_uint len,
+    const char *sbytes, webvtt_uint slen )
 {
   webvtt_uint slen2;
   // check params for integrity
   if( !buffer || len < 1 || !sbytes || slen < 1 ) {
     return WEBVTT_INVALID_PARAM;
   }
 
   slen2 = slen - 1;
@@ -336,20 +336,24 @@ find_bytes( const webvtt_byte *buffer, w
 #define FRAME(i) (self->top - (i))
 #define FRAMEUP(i) (self->top + (i))
 #define RECHECK goto _recheck;
 #define BACK (SP->back)
 /**
  * More state stack helpers
  */
 WEBVTT_INTERN webvtt_status
-do_push( webvtt_parser self, webvtt_uint token, webvtt_uint back, webvtt_uint state, void *data, webvtt_state_value_type type, webvtt_uint line, webvtt_uint column )
+do_push( webvtt_parser self, webvtt_uint token, webvtt_uint back,
+         webvtt_uint state, void *data, webvtt_state_value_type type,
+         webvtt_uint line, webvtt_uint column )
 {
   if( STACK_SIZE + 1 >= self->stack_alloc ) {
-    webvtt_state *stack = ( webvtt_state * )webvtt_alloc0( sizeof( webvtt_state ) * ( self->stack_alloc << 1 ) ), *tmp;
+    webvtt_state *stack =
+        ( webvtt_state * )webvtt_alloc0( sizeof( webvtt_state ) *
+                                         ( self->stack_alloc << 1 ) ), *tmp;
     if( !stack ) {
       ERROR( WEBVTT_ALLOCATION_FAILED );
       return WEBVTT_OUT_OF_MEMORY;
     }
     memcpy( stack, self->stack, sizeof( webvtt_state ) * self->stack_alloc );
     tmp = self->stack;
     self->stack = stack;
     self->top = stack + ( self->top - tmp );
@@ -398,17 +402,17 @@ do { \
 do \
 { \
   --(self->top); \
   self->popped = 1; \
 } while(0)
 #define POPBACK() do_pop(self)
 
 static webvtt_status
-webvtt_parse_cuesetting( webvtt_parser self, const webvtt_byte *text,
+webvtt_parse_cuesetting( webvtt_parser self, const char *text,
   webvtt_uint *pos, webvtt_uint len, webvtt_error bv, webvtt_token
   keyword, webvtt_token values[], webvtt_uint *value_column ) {
   enum webvtt_param_mode
   {
     P_KEYWORD,
     P_COLON,
     P_VALUE
   };
@@ -441,17 +445,17 @@ webvtt_parse_cuesetting( webvtt_parser s
           case LINE:
             if( tk != keyword ) {
               *pos -= tp;
               self->column -= tp;
               return WEBVTT_NEXT_CUESETTING;
             }
             if( *pos < len ) {
               webvtt_uint column = last_column;
-              webvtt_byte ch = text[ *pos ];
+              char ch = text[ *pos ];
               if( ch != ':' ) {
                 webvtt_error e = WEBVTT_INVALID_CUESETTING;
                 if( ch == ' ' || ch == '\t' ) {
                   column = self->column;
                   e = WEBVTT_UNEXPECTED_WHITESPACE;
                   skip_spacetab( text, pos, len, &self->column );
                   if( text[ *pos ] == ':' ) {
                     skip_until_white( text, pos, len, &self->column );
@@ -514,26 +518,26 @@ get_value:
         if( tk == WHITESPACE && !prevws ) {
           ERROR_AT( WEBVTT_UNEXPECTED_WHITESPACE, last_line,
             last_column );
         } else if( ( i = find_token( tk, values ) ) >= 0 ) {
           webvtt_token t = values[ i ] & TF_TOKEN_MASK;
           int flags = values[ i ] & TF_FLAGS_MASK;
           *value_column = last_column;
           if( *pos < len ) {
-            webvtt_byte ch = text[ *pos ];
+            char ch = text[ *pos ];
             if( ch != ' ' && ch != '\t' && ch != '\r' && ch != '\n' ) {
               goto bad_value;
             }
           }
           switch( t ) {
             case INTEGER:
             case PERCENTAGE:
               if( ( flags & TF_SIGN_MASK ) != TF_SIGN_MASK ) {
-                const webvtt_byte p = self->token[ 0 ];
+                const char p = self->token[ 0 ];
                 if( ( ( flags & TF_NEGATIVE ) && p != '-' )
                   || ( ( flags & TF_POSITIVE ) && p == '-' ) ) {
                   goto bad_value;
                 }
               }
               break;
 
             default: /* Currently, other types don't need these checks */
@@ -562,17 +566,17 @@ bad_value_eol:
     ERROR( bv );
     goto bad_value_eol;
   }
   return WEBVTT_NEXT_CUESETTING;
 }
 
 WEBVTT_INTERN webvtt_status
 webvtt_parse_align( webvtt_parser self, webvtt_cue *cue,
-                    const webvtt_byte *text, webvtt_uint *pos, webvtt_uint len )
+                    const char *text, webvtt_uint *pos, webvtt_uint len )
 {
   webvtt_uint last_line = self->line;
   webvtt_uint last_column = self->column;
   webvtt_status v;
   webvtt_uint vc;
   webvtt_token tokens[] = { START, MIDDLE, END, LEFT, RIGHT, 0 };
   webvtt_align_type values[] = {
     WEBVTT_ALIGN_START, WEBVTT_ALIGN_MIDDLE, WEBVTT_ALIGN_END,
@@ -585,30 +589,30 @@ webvtt_parse_align( webvtt_parser self, 
     }
     cue->flags |= CUE_HAVE_ALIGN;
     cue->settings.align = values[ v - 1 ];
   }
   return v >= 0 ? WEBVTT_SUCCESS : v;
 }
 
 WEBVTT_INTERN webvtt_status
-webvtt_parse_line( webvtt_parser self, webvtt_cue *cue, const webvtt_byte *text,
+webvtt_parse_line( webvtt_parser self, webvtt_cue *cue, const char *text,
                    webvtt_uint *pos, webvtt_uint len )
 {
   webvtt_uint last_line = self->line;
   webvtt_uint last_column = self->column;
   webvtt_status v;
   webvtt_uint vc;
   webvtt_bool first_flag = 0;
   webvtt_token values[] = { INTEGER, PERCENTAGE|TF_POSITIVE, 0 };
   if( ( v = webvtt_parse_cuesetting( self, text, pos, len,
     WEBVTT_LINE_BAD_VALUE, LINE, values, &vc ) ) > 0 ) {
     int digits;
     webvtt_int64 value;
-    const webvtt_byte *t = self->token;
+    const char *t = self->token;
     if( cue->flags & CUE_HAVE_LINE ) {
       ERROR_AT( WEBVTT_LINE_ALREADY_SET, last_line, last_column );
     } else {
       first_flag = 1;
     }
     cue->flags |= CUE_HAVE_LINE;
     value = parse_int( &t, &digits );
     switch( values[ v - 1 ] & TF_TOKEN_MASK ) {
@@ -631,30 +635,30 @@ webvtt_parse_line( webvtt_parser self, w
       } break;
     }
   }
   return v >= 0 ? WEBVTT_SUCCESS : v;
 }
 
 WEBVTT_INTERN webvtt_status
 webvtt_parse_position( webvtt_parser self, webvtt_cue *cue,
-                       const webvtt_byte *text, webvtt_uint *pos,
+                       const char *text, webvtt_uint *pos,
                        webvtt_uint len )
 {
   webvtt_uint last_line = self->line;
   webvtt_uint last_column = self->column;
   webvtt_status v;
   webvtt_uint vc;
   webvtt_bool first_flag = 0;
   webvtt_token values[] = { PERCENTAGE|TF_POSITIVE, 0 };
   if( ( v = webvtt_parse_cuesetting( self, text, pos, len,
     WEBVTT_POSITION_BAD_VALUE, POSITION, values, &vc ) ) > 0 ) {
     int digits;
     webvtt_int64 value;
-    const webvtt_byte *t = self->token;
+    const char *t = self->token;
     if( cue->flags & CUE_HAVE_LINE ) {
       ERROR_AT( WEBVTT_POSITION_ALREADY_SET, last_line, last_column );
     } else {
       first_flag = 1;
     }
     cue->flags |= CUE_HAVE_POSITION;
     value = parse_int( &t, &digits );
     if( value < 0 || value > 100 ) {
@@ -665,49 +669,49 @@ webvtt_parse_position( webvtt_parser sel
       return WEBVTT_SUCCESS;
     }
     cue->settings.position = ( int )value;
   }
   return v >= 0 ? WEBVTT_SUCCESS : v;
 }
 
 WEBVTT_INTERN webvtt_status
-webvtt_parse_size( webvtt_parser self, webvtt_cue *cue, const webvtt_byte *text,
+webvtt_parse_size( webvtt_parser self, webvtt_cue *cue, const char *text,
                    webvtt_uint *pos, webvtt_uint len )
 {
   webvtt_uint last_line = self->line;
   webvtt_uint last_column = self->column;
   webvtt_status v;
   webvtt_uint vc;
   webvtt_token tokens[] = { PERCENTAGE|TF_POSITIVE, 0 };
   if( ( v = webvtt_parse_cuesetting( self, text, pos, len,
     WEBVTT_SIZE_BAD_VALUE, SIZE, tokens, &vc ) ) > 0 ) {
     if( cue->flags & CUE_HAVE_SIZE ) {
       ERROR_AT( WEBVTT_SIZE_ALREADY_SET, last_line, last_column );
     }
     cue->flags |= CUE_HAVE_SIZE;
     if( tokens[ v - 1 ] ) {
       int digits;
-      const webvtt_byte *t = self->token;
+      const char *t = self->token;
       webvtt_int64 value;
       self->token_pos = 0;
       value = parse_int( &t, &digits );
       if( value < 0 || value > 100 ) {
         ERROR_AT_COLUMN( WEBVTT_SIZE_BAD_VALUE, vc );
       } else {
         cue->settings.size = ( int )value;
       }
     }
   }
   return v >= 0 ? WEBVTT_SUCCESS : v;
 }
 
 WEBVTT_INTERN webvtt_status
 webvtt_parse_vertical( webvtt_parser self, webvtt_cue *cue,
-                       const webvtt_byte *text, webvtt_uint *pos,
+                       const char *text, webvtt_uint *pos,
                        webvtt_uint len )
 {
   webvtt_uint last_line = self->line;
   webvtt_uint last_column = self->column;
   webvtt_status v;
   webvtt_uint vc;
   webvtt_token tokens[] = { RL, LR, 0 };
   webvtt_vertical_type values[] = { WEBVTT_VERTICAL_RL, WEBVTT_VERTICAL_LR };
@@ -727,17 +731,17 @@ webvtt_parse_vertical( webvtt_parser sel
  * http://dev.w3.org/html5/webvtt/#collect-webvtt-cue-timings-and-settings
  *
  * - Ignore whitespace
  * - Return immediately after having parsed a timestamp
  * - Return error if timestamp invalid.
  */
 WEBVTT_INTERN webvtt_status
 webvtt_get_timestamp( webvtt_parser self, webvtt_timestamp *result,
-                      const webvtt_byte *text, webvtt_uint *pos,
+                      const char *text, webvtt_uint *pos,
                       webvtt_uint len, const char *accepted )
 {
   webvtt_uint last_column = self->column;
   webvtt_uint last_line = self->line;
   webvtt_token token;
   while( *pos < len ) {
     last_column = self->column;
     last_line = self->line;
@@ -776,17 +780,17 @@ webvtt_get_timestamp( webvtt_parser self
   ERROR_AT( WEBVTT_EXPECTED_TIMESTAMP, last_line, last_column );
   return WEBVTT_PARSE_ERROR;
 }
 
 WEBVTT_INTERN webvtt_status
 webvtt_proc_cueline( webvtt_parser self, webvtt_cue *cue,
                      webvtt_string *line )
 {
-  const webvtt_byte *text;
+  const char *text;
   webvtt_uint length;
   DIE_IF( line == NULL );
   length = webvtt_string_length( line );
   text = webvtt_string_text( line );
   /* backup the column */
   self->column = 1;
   if( find_bytes( text, length, separator, sizeof( separator ) )
       == WEBVTT_SUCCESS) {
@@ -837,17 +841,17 @@ webvtt_proc_cueline( webvtt_parser self,
     }
   }
 
   webvtt_release_string( line );
   return WEBVTT_SUCCESS;
 }
 
 WEBVTT_INTERN int
-parse_cueparams( webvtt_parser self, const webvtt_byte *buffer,
+parse_cueparams( webvtt_parser self, const char *buffer,
                  webvtt_uint len, webvtt_cue *cue )
 {
   webvtt_uint pos = 0;
 
   enum cp_state {
     CP_STARTTIME = 0, /* Start timestamp */
     CP_SEPARATOR, /* --> */
     CP_ENDTIME, /* End timestamp */
@@ -1012,17 +1016,17 @@ parse_cueparams( webvtt_parser self, con
       ERROR( e );
     }
   }
 #undef SETST
   return 0;
 }
 
 static webvtt_status
-parse_webvtt( webvtt_parser self, const webvtt_byte *buffer, webvtt_uint *ppos,
+parse_webvtt( webvtt_parser self, const char *buffer, webvtt_uint *ppos,
               webvtt_uint len, int finish )
 {
   webvtt_status status = WEBVTT_SUCCESS;
   webvtt_token token = 0;
   webvtt_uint pos = *ppos;
   int skip_error = 0;
 
   while( pos < len ) {
@@ -1044,16 +1048,27 @@ parse_webvtt( webvtt_parser self, const 
           if( v < 0 ) {
             webvtt_release_string( &SP->v.text );
             SP->type = V_NONE;
             POP();
             ERROR( WEBVTT_ALLOCATION_FAILED );
             status = WEBVTT_OUT_OF_MEMORY;
             goto _finish;
           }
+          /* replace '\0' with u+fffd */
+          if( WEBVTT_FAILED( status = webvtt_string_replace_all( &SP->v.text,
+                                                                 "\0", 1,
+                                                                 replacement,
+                                                                 3 ) ) ) {
+            webvtt_release_string( &SP->v.text );
+            SP->type = V_NONE;
+            POP();
+            ERROR( WEBVTT_ALLOCATION_FAILED );
+            goto _finish;
+          }
           SP->flags = 1;
         }
       }
       if( SP->flags ) {
         webvtt_token token = webvtt_lex_newline( self, buffer, &pos, len,
                                                  self->finished );
         if( token == NEWLINE ) {
           POP();
@@ -1066,17 +1081,18 @@ parse_webvtt( webvtt_parser self, const 
      * Get the next token from the stream
      *
      * If the token is 'UNFINISHED', but we are at the end of our input
      * data, change it to BADTOKEN because it will never be finished.
      *
      * Otherwise, if we are expecting further data at some point, and have
      * an unfinished token, return and let the next chunk deal with it.
      */
-    if( SP->state != T_CUE || !( self->popped && FRAMEUP( 1 )->state == T_CUEREAD ) ) {
+    if( SP->state != T_CUE ||
+        !( self->popped && FRAMEUP( 1 )->state == T_CUEREAD ) ) {
       /**
        * We don't tokenize in certain states
        */
       token = webvtt_lex( self, buffer, &pos, len, finish );
       if( token == UNFINISHED ) {
         if( finish ) {
           token = BADTOKEN;
         } else if( pos == len ) {
@@ -1275,17 +1291,17 @@ parse_webvtt( webvtt_parser self, const 
   if( status == WEBVTT_OUT_OF_MEMORY ) {
     cleanup_stack( self );
   }
   *ppos = pos;
   return status;
 }
 
 WEBVTT_INTERN webvtt_status
-webvtt_read_cuetext( webvtt_parser self, const webvtt_byte *b,
+webvtt_read_cuetext( webvtt_parser self, const char *b,
                      webvtt_uint *ppos, webvtt_uint len, webvtt_bool finish )
 {
   webvtt_status status = WEBVTT_SUCCESS;
   webvtt_uint pos = *ppos;
   int finished = 0;
   int flags = 0;
   webvtt_cue *cue;
 
@@ -1305,19 +1321,29 @@ webvtt_read_cuetext( webvtt_parser self,
 
   do {
     if( !flags ) {
       int v;
       if( ( v = webvtt_string_getline( &self->line_buffer, b, &pos, len,
                                        &self->truncate, finish ) ) ) {
         if( v < 0 || WEBVTT_FAILED( webvtt_string_putc( &self->line_buffer,
                                                         '\n' ) ) ) {
+          ERROR( WEBVTT_ALLOCATION_FAILED );
           status = WEBVTT_OUT_OF_MEMORY;
           goto _finish;
         }
+        /* replace '\0' with u+fffd */
+        if( WEBVTT_FAILED( status =
+                           webvtt_string_replace_all( &self->line_buffer,
+                                                      "\0", 1, replacement,
+                                                      3 ) ) ) {
+          ERROR( WEBVTT_ALLOCATION_FAILED );
+          goto _finish;
+        }
+
         flags = 1;
       }
     }
     if( flags ) {
       webvtt_token token = webvtt_lex_newline( self, b, &pos, len, finish );
       if( token == NEWLINE ) {
         self->token_pos = 0;
         self->line++;
@@ -1376,17 +1402,17 @@ webvtt_read_cuetext( webvtt_parser self,
    */
   if( !finish && pos >= len && !WEBVTT_FAILED( status ) && !finished ) {
     status = WEBVTT_UNFINISHED;
   }
   return status;
 }
 
 WEBVTT_INTERN webvtt_status
-webvtt_proc_cuetext( webvtt_parser self, const webvtt_byte *b,
+webvtt_proc_cuetext( webvtt_parser self, const char *b,
                      webvtt_uint *ppos, webvtt_uint len, webvtt_bool finish )
 {
   webvtt_status status;
   webvtt_cue *cue;
   SAFE_ASSERT( ( self->mode == M_CUETEXT || self->mode == M_SKIP_CUE )
                && self->top->type == V_CUE );
   cue = self->top->v.cue;
   SAFE_ASSERT( cue != 0 );
@@ -1431,69 +1457,52 @@ webvtt_proc_cuetext( webvtt_parser self,
   return status;
 }
 
 WEBVTT_EXPORT webvtt_status
 webvtt_parse_chunk( webvtt_parser self, const void *buffer, webvtt_uint len )
 {
   webvtt_status status;
   webvtt_uint pos = 0;
-  const webvtt_byte *b = ( const webvtt_byte * )buffer;
+  const char *b = ( const char * )buffer;
 
   while( pos < len ) {
     switch( self->mode ) {
       case M_WEBVTT:
-        if( WEBVTT_FAILED( status = parse_webvtt( self, b, &pos, len, self->finished ) ) ) {
+        if( WEBVTT_FAILED( status = parse_webvtt( self, b, &pos, len,
+                                                  self->finished ) ) ) {
           return status;
         }
         break;
 
       case M_CUETEXT:
         /**
          * read in cuetext
          */
         if( WEBVTT_FAILED( status = webvtt_proc_cuetext( self, b, &pos, len,
-                                                  self->finished ) ) ) {
+                                                         self->finished ) ) ) {
           if( status == WEBVTT_UNFINISHED ) {
             /* Make an exception here, because this isn't really a failure. */
             return WEBVTT_SUCCESS;
           }
           return status;
         }
 
         /* If we failed to parse cuetext, return the error */
         if( WEBVTT_FAILED( status ) ) {
           return status;
         }
         break;
 
       case M_SKIP_CUE:
         if( WEBVTT_FAILED( status = webvtt_proc_cuetext( self, b, &pos, len,
-                                                  self->finished ) ) ) {
+                                                         self->finished ) ) ) {
           return status;
         }
         break;
-
-      case M_READ_LINE: {
-        /**
-         * Read in a line of text into the line-buffer,
-         * we will and depending on our state, do something with it.
-         */
-        int ret;
-        if( ( ret = webvtt_string_getline( &self->line_buffer, b, &pos, len,
-                                           &self->truncate,
-                                           self->finished ) ) ) {
-          if( ret < 0 ) {
-            ERROR( WEBVTT_ALLOCATION_FAILED );
-            return WEBVTT_OUT_OF_MEMORY;
-          }
-          self->mode = M_WEBVTT;
-        }
-        break;
-      }
     }
   }
 
   return WEBVTT_SUCCESS;
 }
 
 #undef SP
 #undef AT_BOTTOM
@@ -1502,24 +1511,24 @@ webvtt_parse_chunk( webvtt_parser self, 
 #undef FRAME
 #undef PUSH
 #undef POP
 
 /**
  * Get an integer value from a series of digits.
  */
 static webvtt_int64
-parse_int( const webvtt_byte **pb, int *pdigits )
+parse_int( const char **pb, int *pdigits )
 {
   int digits = 0;
   webvtt_int64 result = 0;
   webvtt_int64 mul = 1;
-  const webvtt_byte *b = *pb;
+  const char *b = *pb;
   while( *b ) {
-    webvtt_byte ch = *b;
+    char ch = *b;
     if( webvtt_isdigit( ch ) ) {
       /**
        * Digit character, carry on
        */
       result = result * 10 + ( ch - '0' );
       ++digits;
     } else if( mul == 1 && digits == 0 && ch == '-' ) {
       mul = -1;
@@ -1535,17 +1544,17 @@ parse_int( const webvtt_byte **pb, int *
   return result * mul;
 }
 
 /**
  * Turn the token of a TIMESTAMP tag into something useful, and returns non-zero
  * returns 0 if it fails
  */
 WEBVTT_INTERN int
-parse_timestamp( const webvtt_byte *b, webvtt_timestamp *result )
+parse_timestamp( const char *b, webvtt_timestamp *result )
 {
   webvtt_int64 tmp;
   int have_hours = 0;
   int digits;
   int malformed = 0;
   webvtt_int64 v[4];
   if ( !webvtt_isdigit( *b ) ) {
     goto _malformed;
--- a/media/webvtt/parser_internal.h
+++ b/media/webvtt/parser_internal.h
@@ -83,17 +83,16 @@ webvtt_state_value_type_t {
   V_TOKEN,
 } webvtt_state_value_type;
 
 typedef enum
 webvtt_parse_mode_t {
   M_WEBVTT = 0,
   M_CUETEXT,
   M_SKIP_CUE,
-  M_READ_LINE,
 } webvtt_parse_mode;
 
 
 typedef enum
 webvtt_parse_state_t {
   /**
    * WEBVTT parse states
    */
@@ -101,20 +100,24 @@ webvtt_parse_state_t {
   T_TAG,
   T_TAGCOMMENT,
   T_EOL,
   T_BODY,
 
   T_CUEREAD, /* Read a line of text for a cue */
   T_CUE, /* T_CUEID T_CUEPARAMS T_CUETEXT NEWLINE */
   T_CUEID, /* T_LINE !~ SEPARATOR && LINE !~ ^NOTE NEWLINE */
-  T_CUEPARAMS, /* TIMESTAMP WHITESPACE? SEPARATOR WHITESPACE? T_CUESETTING* NEWLINE */
+  T_CUEPARAMS, /* TIMESTAMP WHITESPACE? SEPARATOR WHITESPACE?
+                * T_CUESETTING* NEWLINE
+                */
   T_CUETEXT, /* T_LINE !~ SEPARATOR NEWLINE NEWLINE */
 
-  T_TIMESTAMP, /* This looked like a timestamp to the lexer, may or may not be valid. */
+  T_TIMESTAMP, /* This looked like a timestamp to the lexer,
+                * may or may not be valid.
+                */
 
   /**
    * NOTE comments
    */
   T_COMMENT,
 
   /**
    * Cue times
@@ -196,17 +199,17 @@ webvtt_parser_t {
   webvtt_uint state;
   webvtt_uint bytes; /* number of bytes read. */
   webvtt_uint line;
   webvtt_uint column;
   webvtt_cue_fn read;
   webvtt_error_fn error;
   void *userdata;
   webvtt_bool finished;
-  
+
   webvtt_uint cuetext_line; /* start line of cuetext */
 
   /**
    * 'mode' can have several states, it is not boolean.
    */
   webvtt_parse_mode mode;
 
   webvtt_state *top; /* Top parse state */
@@ -222,63 +225,77 @@ webvtt_parser_t {
   webvtt_uint line_pos;
   webvtt_string line_buffer;
 
   /**
    * tokenizer
    */
   webvtt_lexer_state tstate;
   webvtt_uint token_pos;
-  webvtt_byte token[0x100];
+  char token[0x100];
 };
 
-WEBVTT_INTERN webvtt_token webvtt_lex( webvtt_parser self, const webvtt_byte *buffer, webvtt_uint *pos, webvtt_uint length, webvtt_bool finish );
-WEBVTT_INTERN webvtt_status webvtt_lex_word( webvtt_parser self, webvtt_string *pba, const webvtt_byte *buffer, webvtt_uint *pos, webvtt_uint length, webvtt_bool finish );
+WEBVTT_INTERN webvtt_token
+webvtt_lex( webvtt_parser self, const char *buffer, webvtt_uint *pos,
+            webvtt_uint length, webvtt_bool finish );
+
+WEBVTT_INTERN webvtt_status
+webvtt_lex_word( webvtt_parser self, webvtt_string *pba, const char *buffer,
+                 webvtt_uint *pos, webvtt_uint length, webvtt_bool finish );
 
 /* Tokenize newline sequence, without incrementing 'self->line'. Returns
  * BAD_TOKEN when a newline sequence is not found. */
-WEBVTT_INTERN webvtt_token webvtt_lex_newline( webvtt_parser self, const
-  webvtt_byte *buffer, webvtt_uint *pos, webvtt_uint length, webvtt_bool finish );
+WEBVTT_INTERN webvtt_token
+webvtt_lex_newline( webvtt_parser self, const char *buffer, webvtt_uint *pos,
+                    webvtt_uint length, webvtt_bool finish );
 
-WEBVTT_INTERN webvtt_status webvtt_proc_cueline( webvtt_parser self,
-  webvtt_cue *cue, webvtt_string *line );
+WEBVTT_INTERN webvtt_status
+webvtt_proc_cueline( webvtt_parser self, webvtt_cue *cue, webvtt_string *line );
 
-WEBVTT_INTERN webvtt_status webvtt_parse_align( webvtt_parser self,
-  webvtt_cue *cue, const webvtt_byte *text, webvtt_uint *pos, webvtt_uint len );
+WEBVTT_INTERN webvtt_status
+webvtt_parse_align( webvtt_parser self, webvtt_cue *cue, const char *text,
+                    webvtt_uint *pos, webvtt_uint len );
 
-WEBVTT_INTERN webvtt_status webvtt_parse_line( webvtt_parser self,
-  webvtt_cue *cue, const webvtt_byte *text, webvtt_uint *pos, webvtt_uint len );
+WEBVTT_INTERN webvtt_status
+webvtt_parse_line( webvtt_parser self, webvtt_cue *cue, const char *text,
+                   webvtt_uint *pos, webvtt_uint len );
 
-WEBVTT_INTERN webvtt_status webvtt_parse_position( webvtt_parser self,
-  webvtt_cue *cue, const webvtt_byte *text, webvtt_uint *pos, webvtt_uint len );
+WEBVTT_INTERN webvtt_status
+webvtt_parse_position( webvtt_parser self, webvtt_cue *cue, const char *text,
+                       webvtt_uint *pos, webvtt_uint len );
 
-WEBVTT_INTERN webvtt_status webvtt_parse_size( webvtt_parser self,
-  webvtt_cue *cue, const webvtt_byte *text, webvtt_uint *pos, webvtt_uint len );
+WEBVTT_INTERN webvtt_status
+webvtt_parse_size( webvtt_parser self, webvtt_cue *cue, const char *text,
+                   webvtt_uint *pos, webvtt_uint len );
 
-WEBVTT_INTERN webvtt_status webvtt_parse_vertical( webvtt_parser self,
-  webvtt_cue *cue, const webvtt_byte *text, webvtt_uint *pos, webvtt_uint len );
+WEBVTT_INTERN webvtt_status
+webvtt_parse_vertical( webvtt_parser self, webvtt_cue *cue, const char *text,
+                       webvtt_uint *pos, webvtt_uint len );
 
-WEBVTT_INTERN int parse_timestamp( const webvtt_byte *b, webvtt_timestamp *result );
+WEBVTT_INTERN int
+parse_timestamp( const char *b, webvtt_timestamp *result );
 
-WEBVTT_INTERN webvtt_status do_push( webvtt_parser self, webvtt_uint token,
-  webvtt_uint back, webvtt_uint state, void *data, webvtt_state_value_type type,
-  webvtt_uint line, webvtt_uint column );
+WEBVTT_INTERN webvtt_status
+do_push( webvtt_parser self, webvtt_uint token, webvtt_uint back,
+         webvtt_uint state, void *data, webvtt_state_value_type type,
+         webvtt_uint line, webvtt_uint column );
 
-WEBVTT_INTERN webvtt_status webvtt_read_cuetext( webvtt_parser self,
-  const webvtt_byte *b, webvtt_uint *ppos, webvtt_uint len,
-  webvtt_bool finish );
+WEBVTT_INTERN webvtt_status
+webvtt_read_cuetext( webvtt_parser self, const char *b, webvtt_uint *ppos,
+                    webvtt_uint len, webvtt_bool finish );
 
-WEBVTT_INTERN webvtt_status webvtt_proc_cuetext( webvtt_parser self,
-  const webvtt_byte *b, webvtt_uint *ppos, webvtt_uint len,
-  webvtt_bool finish );
+WEBVTT_INTERN webvtt_status
+webvtt_proc_cuetext( webvtt_parser self, const char *b, webvtt_uint *ppos,
+                    webvtt_uint len, webvtt_bool finish );
 
-WEBVTT_INTERN int parse_cueparams( webvtt_parser self, const webvtt_byte *text,
-  webvtt_uint len, webvtt_cue *cue );
+WEBVTT_INTERN int
+parse_cueparams( webvtt_parser self, const char *text, webvtt_uint len,
+                 webvtt_cue *cue );
 
-/** 
+/**
  * Flags which can apply additional meaning to a token. find_token() will
  * test for only the actual token and ignore the additional flags.
  */
 typedef
 enum webvtt_token_flags_t
 {
   /* Number can be positive */
   TF_POSITIVE = 0x80000000,
@@ -300,31 +317,31 @@ enum webvtt_token_flags_t
 
 /**
  * Return non-zero if a token is found in a NULL-terminated array of tokens, or
  * zero if not.
  *
  * Unlike find_token(), token_in_list() does not make use of
  * webvtt_token_flags and thus requiers an exact match.
  */
-WEBVTT_INTERN webvtt_bool token_in_list( webvtt_token search_for,
-  const webvtt_token token_list[] );
+WEBVTT_INTERN webvtt_bool
+token_in_list( webvtt_token search_for, const webvtt_token token_list[] );
 
 /**
  * Return the index of a token in a NULL-terminated array of tokens,
  * or -1 if the token is not found.
  *
  * find_token() will search for an occurrence of `token' in a list
  * where webvtt_token_flags are used. For instance, if the list of
  * tokens contains { TF_POSITIVE | INTEGER, TF_POSITIVE | PERCENTAGE,
  * 0 }, find_token() will return a match for INTEGER or PERCENTAGE if
  * either is searched for.
  */
-WEBVTT_INTERN int find_token( webvtt_token search_for,
-  const webvtt_token token_list[] );
+WEBVTT_INTERN int
+find_token( webvtt_token search_for, const webvtt_token token_list[] );
 
 #define BAD_TIMESTAMP(ts) ( ( ts ) == 0xFFFFFFFFFFFFFFFF )
 
 #ifdef FATAL_ASSERTION
 #  define SAFE_ASSERT(condition) assert(condition)
 #  define DIE_IF(condition) assert( !(condition) )
 #else
 #  ifdef BREAK_ON_ASSERTION
--- a/media/webvtt/string.c
+++ b/media/webvtt/string.c
@@ -24,16 +24,50 @@
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
 #include "string_internal.h"
 #include <stdlib.h>
 #include <string.h>
 
+/* TODO: Use libc implementation if we have one */
+
+void *
+memmem(const void *l, size_t l_len, const void *s, size_t s_len)
+{
+  register char *cur, *last;
+  const char *cl = ( const char * )l;
+  const char *cs = ( const char * )s;
+
+  /* we need something to compare */
+  if ( l_len == 0 || s_len == 0 ) {
+    return NULL;
+  }
+
+  /* "s" must be smaller or equal to "l" */
+  if ( l_len < s_len ) {
+    return NULL;
+  }
+
+  /* special case where s_len == 1 */
+  if ( s_len == 1 ) {
+    return ( void * )memchr( l, ( int )*cs, l_len );
+  }
+
+  /* the last position where its possible to find "s" in "l" */
+  last = (char *)cl + l_len - s_len;
+
+  for ( cur = ( char * )cl; cur <= last; cur++ ) {
+    if ( cur[0] == cs[0] && memcmp( cur, cs, s_len ) == 0 ) {
+      return cur;
+    }
+  }
+  return NULL;
+}
 
 static webvtt_string_data empty_string = {
   { 1 }, /* init refcount */
   0, /* length */
   0, /* capacity */
   empty_string.array, /* text */
   { '\0' } /* array */
 };
@@ -59,17 +93,18 @@ WEBVTT_EXPORT webvtt_status
 webvtt_create_string( webvtt_uint32 alloc, webvtt_string *result )
 {
   webvtt_string_data *d;
 
   if( !result ) {
     return WEBVTT_INVALID_PARAM;
   }
 
-  d = ( webvtt_string_data * )webvtt_alloc( sizeof( webvtt_string_data ) + ( alloc * sizeof( webvtt_byte ) ) );
+  d = ( webvtt_string_data * )webvtt_alloc( sizeof( webvtt_string_data ) +
+                                            ( alloc * sizeof( char ) ) );
 
   if( !d ) {
     return WEBVTT_OUT_OF_MEMORY;
   }
 
   d->refs.value = 1;
   d->alloc = alloc;
   d->length = 0;
@@ -77,45 +112,45 @@ webvtt_create_string( webvtt_uint32 allo
   d->text[0] = 0;
 
   result->d = d;
 
   return WEBVTT_SUCCESS;
 }
 
 WEBVTT_EXPORT webvtt_status
-webvtt_create_string_with_text( webvtt_string *result, const webvtt_byte *init_text, int len )
+webvtt_create_string_with_text( webvtt_string *out, const char *init_text,
+                                int len )
 {
-  if( !result ) {
+  if( !out ) {
     return WEBVTT_INVALID_PARAM;
   }
-  
+
   if( !init_text ) {
-    webvtt_init_string( result );
+    webvtt_init_string( out );
     return WEBVTT_SUCCESS;
   }
 
   if( len < 0 ) {
-    len = strlen( ( const char * )init_text );
+    len = strlen( init_text );
   }
-  
-  if( len == 0 ) {
-    webvtt_init_string( result );
-    return WEBVTT_SUCCESS;
-  }
-  
+
   /**
    * initialize the string by referencing empty_string
    */
-  webvtt_init_string( result );
+  webvtt_init_string( out );
+
+  if( len == 0 ) {
+    return WEBVTT_SUCCESS;
+  }
 
   /**
    * append the appropriate data to the empty string
    */
-  return webvtt_string_append( result, init_text, len );
+  return webvtt_string_append( out, init_text, len );
 }
 
 /**
  * reference counting
  */
 WEBVTT_EXPORT void
 webvtt_ref_string( webvtt_string *str )
 {
@@ -152,17 +187,18 @@ webvtt_string_detach( /* in, out */ webv
   }
 
   q = str->d;
 
   if( q->refs.value == 1 ) {
     return WEBVTT_SUCCESS;
   }
 
-  d = ( webvtt_string_data * )webvtt_alloc( sizeof( webvtt_string_data ) + ( sizeof( webvtt_byte ) * str->d->alloc ) );
+  d = ( webvtt_string_data * )webvtt_alloc( sizeof( webvtt_string_data ) +
+                                           ( sizeof( char ) * str->d->alloc ) );
 
   d->refs.value = 1;
   d->text = d->array;
   d->alloc = q->alloc;
   d->length = q->length;
   memcpy( d->text, q->text, q->length );
 
   str->d = d;
@@ -182,17 +218,17 @@ webvtt_copy_string( webvtt_string *left,
       left->d = right->d;
     } else {
       left->d = &empty_string;
     }
     webvtt_ref( &left->d->refs );
   }
 }
 
-WEBVTT_EXPORT const webvtt_byte *
+WEBVTT_EXPORT const char *
 webvtt_string_text(const webvtt_string *str)
 {
   if( !str || !str->d )
   {
     return 0;
   }
 
   return str->d->text;
@@ -238,17 +274,17 @@ grow( webvtt_string *str, webvtt_uint ne
   }
 
   if( ( str->d->length + need ) <= str->d->alloc )
   {
     return WEBVTT_SUCCESS;
   }
 
   p = d = str->d;
-  grow = sizeof( *d ) + ( sizeof( webvtt_byte ) * ( d->length + need ) );
+  grow = sizeof( *d ) + ( sizeof( char ) * ( d->length + need ) );
 
   if( grow < page ) {
     n = page;
     do {
       n = n / 2;
     } while( n > grow );
     if( n < 1 << 6 ) {
       n = 1 << 6;
@@ -264,41 +300,41 @@ grow( webvtt_string *str, webvtt_uint ne
 
   p = ( webvtt_string_data * )webvtt_alloc( n );
 
   if( !p ) {
     return WEBVTT_OUT_OF_MEMORY;
   }
 
   p->refs.value = 1;
-  p->alloc = ( n - sizeof( *p ) ) / sizeof( webvtt_byte );
+  p->alloc = ( n - sizeof( *p ) ) / sizeof( char );
   p->length = d->length;
   p->text = p->array;
-  memcpy( p->text, d->text, sizeof( webvtt_byte ) * p->length );
+  memcpy( p->text, d->text, sizeof( char ) * p->length );
   p->text[ p->length ] = 0;
   str->d = p;
 
   if( webvtt_deref( &d->refs ) == 0 ) {
     webvtt_free( d );
   }
 
   return WEBVTT_SUCCESS;
 }
 
 WEBVTT_EXPORT int
-webvtt_string_getline( webvtt_string *src, const webvtt_byte *buffer,
+webvtt_string_getline( webvtt_string *src, const char *buffer,
                        webvtt_uint *pos, int len, int *truncate,
                        webvtt_bool finish )
 {
   int ret = 0;
   webvtt_string *str = src;
   webvtt_string_data *d = 0;
-  const webvtt_byte *s = buffer + *pos;
-  const webvtt_byte *p = s;
-  const webvtt_byte *n;
+  const char *s = buffer + *pos;
+  const char *p = s;
+  const char *n;
 
   /**
    *if this is public now, maybe we should return webvtt_status so we can
    * differentiate between WEBVTT_OUT_OF_MEMORY and WEBVTT_INVALID_PARAM
    */
   if( !str ) {
     return -1;
   }
@@ -307,17 +343,17 @@ webvtt_string_getline( webvtt_string *sr
   d = str->d;
   if( !str->d ) {
     if(WEBVTT_FAILED(webvtt_create_string( 0x100, str ))) {
       return -1;
     }
     d = str->d;
   }
   if( len < 0 ) {
-    len = strlen( (const char *)buffer );
+    len = strlen( buffer );
   }
   n = buffer + len;
 
   while( p < n && *p != '\r' && *p != '\n' ) {
     ++p;
   }
 
   if( p < n || finish ) {
@@ -343,17 +379,17 @@ webvtt_string_getline( webvtt_string *sr
     d->length += len;
     d->text[ d->length ] = 0;
   }
 
   return ret;
 }
 
 WEBVTT_EXPORT webvtt_status
-webvtt_string_putc( webvtt_string *str, webvtt_byte to_append )
+webvtt_string_putc( webvtt_string *str, char to_append )
 {
   webvtt_status result;
 
   if( !str ) {
     return WEBVTT_INVALID_PARAM;
   }
 
   if( WEBVTT_FAILED( result = webvtt_string_detach( str ) ) ) {
@@ -365,48 +401,48 @@ webvtt_string_putc( webvtt_string *str, 
     str->d->text[ str->d->length++ ] = to_append;
     str->d->text[ str->d->length ] = 0;
   }
 
   return result;
 }
 
 WEBVTT_EXPORT webvtt_bool
-webvtt_string_is_equal( const webvtt_string *str, const webvtt_byte *to_compare,
+webvtt_string_is_equal( const webvtt_string *str, const char *to_compare,
                         int len )
 {
   if( !str || !to_compare ) {
     return 0;
   }
 
   if( len < 0 ) {
-    len = strlen( (const char *)to_compare );
+    len = strlen( to_compare );
   }
 
   if( str->d->length != (unsigned)len ) {
     return 0;
   }
 
   return memcmp( webvtt_string_text( str ), to_compare, len ) == 0;
 }
 
 WEBVTT_EXPORT webvtt_status
-webvtt_string_append( webvtt_string *str, const webvtt_byte *buffer, int len )
+webvtt_string_append( webvtt_string *str, const char *buffer, int len )
 {
   webvtt_status result;
 
   if( !str || !buffer ) {
     return WEBVTT_INVALID_PARAM;
   }
   if( !str->d ) {
     webvtt_init_string( str );
   }
 
   if( len < 0 ) {
-    len = strlen( ( const char * )buffer );
+    len = strlen( buffer );
   }
 
   if( len == 0 ) {
     return WEBVTT_SUCCESS;
   }
 
   if( !WEBVTT_FAILED( result = grow( str, str->d->length + len ) ) ) {
     memcpy( str->d->text + str->d->length, buffer, len );
@@ -423,16 +459,83 @@ WEBVTT_EXPORT webvtt_status
 {
   if( !str || !other ) {
     return WEBVTT_INVALID_PARAM;
   }
 
   return webvtt_string_append( str, other->d->text, other->d->length );
 }
 
+WEBVTT_EXPORT webvtt_status
+webvtt_string_replace( webvtt_string *str, const char *search, int search_len,
+                       const char *replace, int replace_len )
+{
+  webvtt_status status = WEBVTT_SUCCESS;
+  char *p;
+  if( !str || !search || !replace ) {
+    return WEBVTT_INVALID_PARAM;
+  }
+
+  if( search_len < 0 ) {
+    search_len = ( int )strlen( search );
+  }
+
+  if( replace_len < 0 ) {
+    replace_len = ( int )strlen( replace );
+  }
+
+  if( ( p = (char *)memmem( str->d->text, str->d->length, search,
+                            search_len ) ) ) {
+    const char *end;
+    size_t pos = p - str->d->text;
+    if( WEBVTT_FAILED( status = grow( str, replace_len ) ) ) {
+      return status;
+    }
+    p = str->d->text + pos;
+    end = str->d->text + str->d->length - 1; /* Don't worry about the NULL
+                                              * byte. */
+    if( search_len != replace_len ) {
+      memmove( p + replace_len, p + search_len, end - p );
+    }
+    memcpy( p, replace, replace_len );
+    str->d->length = ( str->d->length - search_len ) + replace_len;
+    str->d->text[ str->d->length ] = 0;
+    status = ( webvtt_status )1;
+  }
+  return status;
+}
+
+/**
+ * webvtt_string_replace_all
+ *
+ * replace all instances of substring with replacement string
+ */
+WEBVTT_EXPORT webvtt_status
+webvtt_string_replace_all( webvtt_string *str, const char *search,
+                           int search_len, const char *replace,
+                           int replace_len )
+{
+  webvtt_status status = WEBVTT_SUCCESS;
+  if( !str || !search || !replace ) {
+    return WEBVTT_INVALID_PARAM;
+  }
+
+  if( search_len < 0 ) {
+    search_len = ( int )strlen( search );
+  }
+
+  if( replace_len < 0 ) {
+    replace_len = ( int )strlen( replace );
+  }
+
+  while( ( status = webvtt_string_replace( str, search, search_len, replace,
+                                           replace_len ) ) == 1 );
+  return status;
+}
+
 /**
  * String lists
  */
 WEBVTT_EXPORT webvtt_status
 webvtt_create_stringlist( webvtt_stringlist **result )
 {
   webvtt_stringlist *list;
 
@@ -443,56 +546,57 @@ webvtt_create_stringlist( webvtt_stringl
   list = ( webvtt_stringlist * )webvtt_alloc0( sizeof( *list ) );
 
   if( !list ) {
     return WEBVTT_OUT_OF_MEMORY;
   }
   list->alloc = 0;
   list->length = 0;
   webvtt_ref_stringlist( list );
-  
+
   *result = list;
 
   return WEBVTT_SUCCESS;
 }
 
-WEBVTT_EXPORT void 
-webvtt_ref_stringlist( webvtt_stringlist *list ) 
+WEBVTT_EXPORT void
+webvtt_ref_stringlist( webvtt_stringlist *list )
 {
   if( list ) {
     webvtt_ref( &list->refs );
   }
 }
 
-WEBVTT_EXPORT void 
+WEBVTT_EXPORT void
 webvtt_copy_stringlist( webvtt_stringlist **left, webvtt_stringlist *right )
 {
   if( !left || !right ) {
     return;
   }
   *left = right;
   webvtt_ref_stringlist( *left );
 }
+
 WEBVTT_EXPORT void
 webvtt_release_stringlist( webvtt_stringlist **list )
 {
   webvtt_stringlist *l;
   webvtt_uint i;
 
   if( !list || !*list ) {
     return;
   }
   l = *list;
-  
+
   if( webvtt_deref( &l->refs ) == 0 ) {
     if( l->items ) {
       for( i = 0; i < l->length; i++ ) {
         webvtt_release_string( &l->items[ i ] );
       }
-      webvtt_free( l->items );      
+      webvtt_free( l->items );
     }
     webvtt_free( l );
   }
   *list = 0;
 }
 
 WEBVTT_EXPORT webvtt_status
 webvtt_stringlist_push( webvtt_stringlist *list, webvtt_string *str )
@@ -500,17 +604,18 @@ webvtt_stringlist_push( webvtt_stringlis
   if( !list || !str ) {
     return WEBVTT_INVALID_PARAM;
   }
 
   if( list->length + 1 >= ( ( list->alloc / 3 ) * 2 ) ) {
     webvtt_string *arr, *old;
 
     list->alloc = list->alloc == 0 ? 8 : list->alloc * 2;
-    arr = ( webvtt_string * )webvtt_alloc0( sizeof( webvtt_string ) * list->alloc );
+    arr = ( webvtt_string * )webvtt_alloc0( sizeof( webvtt_string ) *
+                                            list->alloc );
 
     if( !arr ) {
       return WEBVTT_OUT_OF_MEMORY;
     }
 
     memcpy( arr, list->items, sizeof( webvtt_string ) * list->length );
     old = list->items;
     list->items = arr;
@@ -520,129 +625,143 @@ webvtt_stringlist_push( webvtt_stringlis
 
   list->items[list->length].d = str->d;
   webvtt_ref_string( list->items + list->length++ );
 
   return WEBVTT_SUCCESS;
 }
 
 WEBVTT_EXPORT webvtt_bool
-webvtt_next_utf8( const webvtt_byte **begin, const webvtt_byte *end )
+webvtt_stringlist_pop( webvtt_stringlist *list, webvtt_string *out )
+{
+  if( !list || !out || list->length < 1 ) {
+    return 0;
+  }
+
+  list->length--;
+  webvtt_copy_string( out, list->items + list->length );
+  webvtt_release_string( list->items + list->length );
+
+  return 1;
+}
+
+WEBVTT_EXPORT webvtt_bool
+webvtt_next_utf8( const char **begin, const char *end )
 {
   int c;
-  const webvtt_byte *p;
+  const char *p;
   if( !begin || !*begin || !**begin || ( end && ( end <= *begin ) ) ) {
     /* Either begin is null, or end is null, or end <= begin */
     return 0;
   }
 
   p = *begin;
 
   if( !end ) {
-    end = p + strlen( ( const char * )p );
+    end = p + strlen( p );
   }
 
   c = webvtt_utf8_length( p );
   if( c > 0 ) {
     p += c;
   } else if( ( *p & 0xC0 ) == 0x80 ) {
-    const webvtt_byte *pc = p + 1;
+    const char *pc = p + 1;
     while( pc < end && ( ( *pc & 0xC0 ) == 0x80 ) ) {
       ++pc;
     }
     if( pc <= end ) {
       p = pc;
     }
   }
-  
+
   if( *begin != p && p <= end ) {
     *begin = p;
     return 1;
   }
   return 0;
 }
 
 WEBVTT_EXPORT webvtt_bool
-webvtt_skip_utf8( const webvtt_byte **begin, const webvtt_byte *end, int n_chars )
+webvtt_skip_utf8( const char **begin, const char *end, int n_chars )
 {
-  const webvtt_byte *first;
+  const char *first;
   if( !begin || !*begin ) {
     return 0;
   }
 
   if( n_chars < 0 ) {
     return 0;
   }
 
   first = *begin;
   if( !end ) {
-    end = first + strlen( ( const char * )first );
+    end = first + strlen( first );
   }
 
   if( end > first ) {
     /* forwards */
     while( n_chars && end > *begin ) {
       if( webvtt_next_utf8( begin, end ) ) {
         --n_chars;
       }
-    } 
+    }
   }
 
   return n_chars == 0;
 }
 
 WEBVTT_EXPORT webvtt_uint16
-webvtt_utf8_to_utf16( const webvtt_byte *utf8, const webvtt_byte *end,
+webvtt_utf8_to_utf16( const char *utf8, const char *end,
   webvtt_uint16 *high_surrogate )
 {
   int need = 0;
   webvtt_uint32 uc = 0, min = 0;
-  
+
   /* We're missing our pointers */
   if( !utf8 ) {
     return 0;
   }
   if( !end ) {
-    end = utf8 + strlen( ( const char * )utf8 );
+    end = utf8 + strlen( utf8 );
   }
   if( utf8 >= end ) {
     return 0;
   }
 
   /* If we are returning a surrogate pair, initialize it to 0 */
   if( high_surrogate ) {
     *high_surrogate = 0;
   }
 
   /* We're not at the start of a character */
   if( ( *utf8 & 0xC0 ) == 0x80 ) {
     return 0;
   }
 
-  if( *utf8 < 0x80 ) {
+  if( (unsigned char)*utf8 < 0x80 ) {
     return ( webvtt_uint32 )( *utf8 );
   }
   while( utf8 < end ) {
-    webvtt_byte ch = *utf8;
+    char ch = *utf8;
     utf8++;
     if( need ) {
       if( ( ch & 0xC0 ) == 0x80 ) {
         uc = ( uc << 6 ) | ( ch & 0x3F );
         if (!--need) {
           int nc;
           if ( !( nc = UTF_IS_NONCHAR( uc ) ) && uc > 0xFFFF && uc < 0x110000) {
             /* Surrogate pair */
             if( high_surrogate ) {
               *high_surrogate = UTF_HIGH_SURROGATE( uc );
             }
             return UTF_LOW_SURROGATE( uc );
           } else if ( ( uc < min ) || ( uc >= 0xD800 && uc <= 0xDFFF ) || nc
                       || uc >= 0x110000) {
             /* Non-character, overlong sequence, or utf16 surrogate */
-            return 0xFFFD;  
+            return 0xFFFD;
           } else {
             /* Non-surrogate */
             return uc;
           }
         }
       }
     } else {
       if ( ( ch & 0xE0 ) == 0xC0 ) {
@@ -663,47 +782,47 @@ webvtt_utf8_to_utf16( const webvtt_byte 
         return 0xFFFD;
       }
     }
   }
   return 0;
 }
 
 WEBVTT_EXPORT int
-webvtt_utf8_chcount( const webvtt_byte *utf8, const webvtt_byte *end )
+webvtt_utf8_chcount( const char *utf8, const char *end )
 {
   int n = 0;
-  const webvtt_byte *p;
+  const char *p;
   if( !utf8 || !*utf8 || ( end != 0 && end < utf8 ) ) {
     return 0;
   }
   if( !end ) {
-    end = utf8 + strlen( ( const char * )utf8 );
+    end = utf8 + strlen( utf8 );
   }
-  
+
   for( p = utf8; p < end; ++n ) {
     int c = webvtt_utf8_length( p );
     if( c < 1 ) {
       break;
     }
     p += c;
   }
 
   return n;
 }
 
 WEBVTT_EXPORT int
-webvtt_utf8_length( const webvtt_byte *utf8 )
+webvtt_utf8_length( const char *utf8 )
 {
-  webvtt_byte ch;
-  if( !utf8 ) { 
+  char ch;
+  if( !utf8 ) {
     return 0;
   }
   ch = *utf8;
-  if( ch < 0x80 ) {
+  if( (unsigned char)ch < 0x80 ) {
     return 1;
   } else if( ( ch & 0xE0 ) == 0xC0 ) {
     return 2;
   } else if( ( ch & 0xF0 ) == 0xE0 ) {
     return 3;
   } else if( ( ch & 0xF8 ) == 0xF0 ) {
     return 4;
   } else if( ( ch & 0xFE ) == 0xFC ) {
--- a/media/webvtt/string_internal.h
+++ b/media/webvtt/string_internal.h
@@ -60,38 +60,39 @@
 #   define __WEBVTT_STRING_INLINE
 # endif
 
 struct
 webvtt_string_data_t {
   struct webvtt_refcount_t refs;
   webvtt_uint32 alloc;
   webvtt_uint32 length;
-  webvtt_byte *text;
-  webvtt_byte array[1];
+  char *text;
+  char array[1];
 };
 
 static __WEBVTT_STRING_INLINE  int
-webvtt_isalpha( webvtt_byte ch )
+webvtt_isalpha( char ch )
 {
-  return ( ( ( ch >= 'A' ) && ( ch <= 'Z' ) ) || ( ( ch >= 'a' ) && ( ch <= 'z' ) ) );
+  return ( ( ( ch >= 'A' ) && ( ch <= 'Z' ) ) || ( ( ch >= 'a' ) &&
+                                                   ( ch <= 'z' ) ) );
 }
 static __WEBVTT_STRING_INLINE int
-webvtt_isdigit( webvtt_byte ch )
+webvtt_isdigit( char ch )
 {
   return ( ( ch >= '0' ) && ( ch <= '9' ) );
 }
 
 static __WEBVTT_STRING_INLINE int
-webvtt_isalphanum( webvtt_byte ch )
+webvtt_isalphanum( char ch )
 {
   return ( webvtt_isalpha( ch ) || webvtt_isdigit( ch ) );
 }
 
 static __WEBVTT_STRING_INLINE int
-webvtt_iswhite( webvtt_byte ch )
+webvtt_iswhite( char ch )
 {
   return ( ( ch == '\r' ) || ( ch == '\n' ) || ( ch == '\f' )
            || ( ch == '\t' ) || ( ch == ' ' ) ) ;
 }
 
 # undef __WEBVTT_STRING_INLINE
 #endif
--- a/media/webvtt/update.sh
+++ b/media/webvtt/update.sh
@@ -75,11 +75,12 @@ rm -rf ${repo_dir}
 
 # addremove automatically if mercurial is used
 if [ ${have_hg} -eq 0 -a -d ${start_dir}/.hg ]; then
   hg addremove ${webvtt_dir}/
 fi
 
 # apply patches
 cd ${webvtt_dir}
-patch -p3 < 868629.patch
+
+# patches go here
 
 cd ${start_dir}