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