Home | History | Annotate | Download | only in webm
      1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "media/webm/webm_stream_parser.h"
      6 
      7 #include <string>
      8 
      9 #include "base/callback.h"
     10 #include "base/logging.h"
     11 #include "media/webm/webm_cluster_parser.h"
     12 #include "media/webm/webm_constants.h"
     13 #include "media/webm/webm_content_encodings.h"
     14 #include "media/webm/webm_crypto_helpers.h"
     15 #include "media/webm/webm_info_parser.h"
     16 #include "media/webm/webm_tracks_parser.h"
     17 
     18 namespace media {
     19 
     20 WebMStreamParser::WebMStreamParser()
     21     : state_(kWaitingForInit),
     22       waiting_for_buffers_(false) {
     23 }
     24 
     25 WebMStreamParser::~WebMStreamParser() {
     26 }
     27 
     28 void WebMStreamParser::Init(const InitCB& init_cb,
     29                             const NewConfigCB& config_cb,
     30                             const NewBuffersCB& new_buffers_cb,
     31                             const NewTextBuffersCB& text_cb,
     32                             const NeedKeyCB& need_key_cb,
     33                             const NewMediaSegmentCB& new_segment_cb,
     34                             const base::Closure& end_of_segment_cb,
     35                             const LogCB& log_cb) {
     36   DCHECK_EQ(state_, kWaitingForInit);
     37   DCHECK(init_cb_.is_null());
     38   DCHECK(!init_cb.is_null());
     39   DCHECK(!config_cb.is_null());
     40   DCHECK(!new_buffers_cb.is_null());
     41   DCHECK(!need_key_cb.is_null());
     42   DCHECK(!new_segment_cb.is_null());
     43   DCHECK(!end_of_segment_cb.is_null());
     44 
     45   ChangeState(kParsingHeaders);
     46   init_cb_ = init_cb;
     47   config_cb_ = config_cb;
     48   new_buffers_cb_ = new_buffers_cb;
     49   text_cb_ = text_cb;
     50   need_key_cb_ = need_key_cb;
     51   new_segment_cb_ = new_segment_cb;
     52   end_of_segment_cb_ = end_of_segment_cb;
     53   log_cb_ = log_cb;
     54 }
     55 
     56 void WebMStreamParser::Flush() {
     57   DCHECK_NE(state_, kWaitingForInit);
     58 
     59   byte_queue_.Reset();
     60 
     61   if (state_ != kParsingClusters)
     62     return;
     63 
     64   cluster_parser_->Reset();
     65 }
     66 
     67 bool WebMStreamParser::Parse(const uint8* buf, int size) {
     68   DCHECK_NE(state_, kWaitingForInit);
     69 
     70   if (state_ == kError)
     71     return false;
     72 
     73   byte_queue_.Push(buf, size);
     74 
     75   int result = 0;
     76   int bytes_parsed = 0;
     77   const uint8* cur = NULL;
     78   int cur_size = 0;
     79 
     80   byte_queue_.Peek(&cur, &cur_size);
     81   while (cur_size > 0) {
     82     State oldState = state_;
     83     switch (state_) {
     84       case kParsingHeaders:
     85         result = ParseInfoAndTracks(cur, cur_size);
     86         break;
     87 
     88       case kParsingClusters:
     89         result = ParseCluster(cur, cur_size);
     90         break;
     91 
     92       case kWaitingForInit:
     93       case kError:
     94         return false;
     95     }
     96 
     97     if (result < 0) {
     98       ChangeState(kError);
     99       return false;
    100     }
    101 
    102     if (state_ == oldState && result == 0)
    103       break;
    104 
    105     DCHECK_GE(result, 0);
    106     cur += result;
    107     cur_size -= result;
    108     bytes_parsed += result;
    109   }
    110 
    111   byte_queue_.Pop(bytes_parsed);
    112   return true;
    113 }
    114 
    115 void WebMStreamParser::ChangeState(State new_state) {
    116   DVLOG(1) << "ChangeState() : " << state_ << " -> " << new_state;
    117   state_ = new_state;
    118 }
    119 
    120 int WebMStreamParser::ParseInfoAndTracks(const uint8* data, int size) {
    121   DVLOG(2) << "ParseInfoAndTracks()";
    122   DCHECK(data);
    123   DCHECK_GT(size, 0);
    124 
    125   const uint8* cur = data;
    126   int cur_size = size;
    127   int bytes_parsed = 0;
    128 
    129   int id;
    130   int64 element_size;
    131   int result = WebMParseElementHeader(cur, cur_size, &id, &element_size);
    132 
    133   if (result <= 0)
    134     return result;
    135 
    136   switch (id) {
    137     case kWebMIdEBMLHeader:
    138     case kWebMIdSeekHead:
    139     case kWebMIdVoid:
    140     case kWebMIdCRC32:
    141     case kWebMIdCues:
    142     case kWebMIdChapters:
    143       if (cur_size < (result + element_size)) {
    144         // We don't have the whole element yet. Signal we need more data.
    145         return 0;
    146       }
    147       // Skip the element.
    148       return result + element_size;
    149       break;
    150     case kWebMIdSegment:
    151       // Just consume the segment header.
    152       return result;
    153       break;
    154     case kWebMIdInfo:
    155       // We've found the element we are looking for.
    156       break;
    157     default: {
    158       MEDIA_LOG(log_cb_) << "Unexpected element ID 0x" << std::hex << id;
    159       return -1;
    160     }
    161   }
    162 
    163   WebMInfoParser info_parser;
    164   result = info_parser.Parse(cur, cur_size);
    165 
    166   if (result <= 0)
    167     return result;
    168 
    169   cur += result;
    170   cur_size -= result;
    171   bytes_parsed += result;
    172 
    173   WebMTracksParser tracks_parser(log_cb_, text_cb_.is_null());
    174   result = tracks_parser.Parse(cur, cur_size);
    175 
    176   if (result <= 0)
    177     return result;
    178 
    179   bytes_parsed += result;
    180 
    181   base::TimeDelta duration = kInfiniteDuration();
    182 
    183   if (info_parser.duration() > 0) {
    184     double mult = info_parser.timecode_scale() / 1000.0;
    185     int64 duration_in_us = info_parser.duration() * mult;
    186     duration = base::TimeDelta::FromMicroseconds(duration_in_us);
    187   }
    188 
    189   const AudioDecoderConfig& audio_config = tracks_parser.audio_decoder_config();
    190   if (audio_config.is_encrypted())
    191     FireNeedKey(tracks_parser.audio_encryption_key_id());
    192 
    193   const VideoDecoderConfig& video_config = tracks_parser.video_decoder_config();
    194   if (video_config.is_encrypted())
    195     FireNeedKey(tracks_parser.video_encryption_key_id());
    196 
    197   if (!config_cb_.Run(audio_config,
    198                       video_config,
    199                       tracks_parser.text_tracks())) {
    200     DVLOG(1) << "New config data isn't allowed.";
    201     return -1;
    202   }
    203 
    204   cluster_parser_.reset(new WebMClusterParser(
    205       info_parser.timecode_scale(),
    206       tracks_parser.audio_track_num(),
    207       tracks_parser.video_track_num(),
    208       tracks_parser.text_tracks(),
    209       tracks_parser.ignored_tracks(),
    210       tracks_parser.audio_encryption_key_id(),
    211       tracks_parser.video_encryption_key_id(),
    212       log_cb_));
    213 
    214   ChangeState(kParsingClusters);
    215 
    216   if (!init_cb_.is_null()) {
    217     init_cb_.Run(true, duration);
    218     init_cb_.Reset();
    219   }
    220 
    221   return bytes_parsed;
    222 }
    223 
    224 int WebMStreamParser::ParseCluster(const uint8* data, int size) {
    225   if (!cluster_parser_)
    226     return -1;
    227 
    228   int id;
    229   int64 element_size;
    230   int result = WebMParseElementHeader(data, size, &id, &element_size);
    231 
    232   if (result <= 0)
    233     return result;
    234 
    235   if (id == kWebMIdCluster)
    236     waiting_for_buffers_ = true;
    237 
    238   // TODO(matthewjheaney): implement support for chapters
    239   if (id == kWebMIdCues || id == kWebMIdChapters) {
    240     if (size < (result + element_size)) {
    241       // We don't have the whole element yet. Signal we need more data.
    242       return 0;
    243     }
    244     // Skip the element.
    245     return result + element_size;
    246   }
    247 
    248   if (id == kWebMIdEBMLHeader) {
    249     ChangeState(kParsingHeaders);
    250     return 0;
    251   }
    252 
    253   int bytes_parsed = cluster_parser_->Parse(data, size);
    254 
    255   if (bytes_parsed <= 0)
    256     return bytes_parsed;
    257 
    258   const BufferQueue& audio_buffers = cluster_parser_->audio_buffers();
    259   const BufferQueue& video_buffers = cluster_parser_->video_buffers();
    260   bool cluster_ended = cluster_parser_->cluster_ended();
    261 
    262   if (waiting_for_buffers_ &&
    263       cluster_parser_->cluster_start_time() != kNoTimestamp()) {
    264     new_segment_cb_.Run();
    265     waiting_for_buffers_ = false;
    266   }
    267 
    268   if ((!audio_buffers.empty() || !video_buffers.empty()) &&
    269       !new_buffers_cb_.Run(audio_buffers, video_buffers)) {
    270     return -1;
    271   }
    272 
    273   WebMClusterParser::TextTrackIterator text_track_iter =
    274     cluster_parser_->CreateTextTrackIterator();
    275 
    276   int text_track_num;
    277   const BufferQueue* text_buffers;
    278 
    279   while (text_track_iter(&text_track_num, &text_buffers)) {
    280     if (!text_buffers->empty() && !text_cb_.Run(text_track_num, *text_buffers))
    281       return -1;
    282   }
    283 
    284   if (cluster_ended)
    285     end_of_segment_cb_.Run();
    286 
    287   return bytes_parsed;
    288 }
    289 
    290 void WebMStreamParser::FireNeedKey(const std::string& key_id) {
    291   std::vector<uint8> key_id_vector(key_id.begin(), key_id.end());
    292   need_key_cb_.Run(kWebMEncryptInitDataType, key_id_vector);
    293 }
    294 
    295 }  // namespace media
    296