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_tracks_parser.h"
      6 
      7 #include "base/logging.h"
      8 #include "base/strings/string_util.h"
      9 #include "media/base/buffers.h"
     10 #include "media/webm/webm_constants.h"
     11 #include "media/webm/webm_content_encodings.h"
     12 
     13 namespace media {
     14 
     15 static TextKind CodecIdToTextKind(const std::string& codec_id) {
     16   if (codec_id == kWebMCodecSubtitles)
     17     return kTextSubtitles;
     18 
     19   if (codec_id == kWebMCodecCaptions)
     20     return kTextCaptions;
     21 
     22   if (codec_id == kWebMCodecDescriptions)
     23     return kTextDescriptions;
     24 
     25   if (codec_id == kWebMCodecMetadata)
     26     return kTextMetadata;
     27 
     28   return kTextNone;
     29 }
     30 
     31 WebMTracksParser::WebMTracksParser(const LogCB& log_cb, bool ignore_text_tracks)
     32     : track_type_(-1),
     33       track_num_(-1),
     34       audio_track_num_(-1),
     35       video_track_num_(-1),
     36       ignore_text_tracks_(ignore_text_tracks),
     37       log_cb_(log_cb),
     38       audio_client_(log_cb),
     39       video_client_(log_cb) {
     40 }
     41 
     42 WebMTracksParser::~WebMTracksParser() {}
     43 
     44 int WebMTracksParser::Parse(const uint8* buf, int size) {
     45   track_type_ =-1;
     46   track_num_ = -1;
     47   track_name_.clear();
     48   track_language_.clear();
     49   audio_track_num_ = -1;
     50   audio_decoder_config_ = AudioDecoderConfig();
     51   video_track_num_ = -1;
     52   video_decoder_config_ = VideoDecoderConfig();
     53   text_tracks_.clear();
     54   ignored_tracks_.clear();
     55 
     56   WebMListParser parser(kWebMIdTracks, this);
     57   int result = parser.Parse(buf, size);
     58 
     59   if (result <= 0)
     60     return result;
     61 
     62   // For now we do all or nothing parsing.
     63   return parser.IsParsingComplete() ? result : 0;
     64 }
     65 
     66 WebMParserClient* WebMTracksParser::OnListStart(int id) {
     67   if (id == kWebMIdContentEncodings) {
     68     DCHECK(!track_content_encodings_client_.get());
     69     track_content_encodings_client_.reset(
     70         new WebMContentEncodingsClient(log_cb_));
     71     return track_content_encodings_client_->OnListStart(id);
     72   }
     73 
     74   if (id == kWebMIdTrackEntry) {
     75     track_type_ = -1;
     76     track_num_ = -1;
     77     track_name_.clear();
     78     track_language_.clear();
     79     codec_id_ = "";
     80     codec_private_.clear();
     81     audio_client_.Reset();
     82     video_client_.Reset();
     83     return this;
     84   }
     85 
     86   if (id == kWebMIdAudio)
     87     return &audio_client_;
     88 
     89   if (id == kWebMIdVideo)
     90     return &video_client_;
     91 
     92   return this;
     93 }
     94 
     95 bool WebMTracksParser::OnListEnd(int id) {
     96   if (id == kWebMIdContentEncodings) {
     97     DCHECK(track_content_encodings_client_.get());
     98     return track_content_encodings_client_->OnListEnd(id);
     99   }
    100 
    101   if (id == kWebMIdTrackEntry) {
    102     if (track_type_ == -1 || track_num_ == -1) {
    103       MEDIA_LOG(log_cb_) << "Missing TrackEntry data for "
    104                          << " TrackType " << track_type_
    105                          << " TrackNum " << track_num_;
    106       return false;
    107     }
    108 
    109     if (track_type_ != kWebMTrackTypeAudio &&
    110         track_type_ != kWebMTrackTypeVideo &&
    111         track_type_ != kWebMTrackTypeSubtitlesOrCaptions &&
    112         track_type_ != kWebMTrackTypeDescriptionsOrMetadata) {
    113       MEDIA_LOG(log_cb_) << "Unexpected TrackType " << track_type_;
    114       return false;
    115     }
    116 
    117     TextKind text_track_kind = kTextNone;
    118     if (track_type_ == kWebMTrackTypeSubtitlesOrCaptions) {
    119       text_track_kind = CodecIdToTextKind(codec_id_);
    120       if (text_track_kind == kTextNone) {
    121         MEDIA_LOG(log_cb_) << "Missing TrackEntry CodecID"
    122                            << " TrackNum " << track_num_;
    123         return false;
    124       }
    125 
    126       if (text_track_kind != kTextSubtitles &&
    127           text_track_kind != kTextCaptions) {
    128         MEDIA_LOG(log_cb_) << "Wrong TrackEntry CodecID"
    129                            << " TrackNum " << track_num_;
    130         return false;
    131       }
    132     } else if (track_type_ == kWebMTrackTypeDescriptionsOrMetadata) {
    133       text_track_kind = CodecIdToTextKind(codec_id_);
    134       if (text_track_kind == kTextNone) {
    135         MEDIA_LOG(log_cb_) << "Missing TrackEntry CodecID"
    136                            << " TrackNum " << track_num_;
    137         return false;
    138       }
    139 
    140       if (text_track_kind != kTextDescriptions &&
    141           text_track_kind != kTextMetadata) {
    142         MEDIA_LOG(log_cb_) << "Wrong TrackEntry CodecID"
    143                            << " TrackNum " << track_num_;
    144         return false;
    145       }
    146     }
    147 
    148     std::string encryption_key_id;
    149     if (track_content_encodings_client_) {
    150       DCHECK(!track_content_encodings_client_->content_encodings().empty());
    151       // If we have multiple ContentEncoding in one track. Always choose the
    152       // key id in the first ContentEncoding as the key id of the track.
    153       encryption_key_id = track_content_encodings_client_->
    154           content_encodings()[0]->encryption_key_id();
    155     }
    156 
    157     if (track_type_ == kWebMTrackTypeAudio) {
    158       if (audio_track_num_ == -1) {
    159         audio_track_num_ = track_num_;
    160         audio_encryption_key_id_ = encryption_key_id;
    161 
    162         DCHECK(!audio_decoder_config_.IsValidConfig());
    163         if (!audio_client_.InitializeConfig(
    164                 codec_id_, codec_private_, !audio_encryption_key_id_.empty(),
    165                 &audio_decoder_config_)) {
    166           return false;
    167         }
    168       } else {
    169         MEDIA_LOG(log_cb_) << "Ignoring audio track " << track_num_;
    170         ignored_tracks_.insert(track_num_);
    171       }
    172     } else if (track_type_ == kWebMTrackTypeVideo) {
    173       if (video_track_num_ == -1) {
    174         video_track_num_ = track_num_;
    175         video_encryption_key_id_ = encryption_key_id;
    176 
    177         DCHECK(!video_decoder_config_.IsValidConfig());
    178         if (!video_client_.InitializeConfig(
    179                 codec_id_, codec_private_, !video_encryption_key_id_.empty(),
    180                 &video_decoder_config_)) {
    181           return false;
    182         }
    183       } else {
    184         MEDIA_LOG(log_cb_) << "Ignoring video track " << track_num_;
    185         ignored_tracks_.insert(track_num_);
    186       }
    187     } else if (track_type_ == kWebMTrackTypeSubtitlesOrCaptions ||
    188                track_type_ == kWebMTrackTypeDescriptionsOrMetadata) {
    189       if (ignore_text_tracks_) {
    190         MEDIA_LOG(log_cb_) << "Ignoring text track " << track_num_;
    191         ignored_tracks_.insert(track_num_);
    192       } else {
    193         TextTrackInfo& text_track_info = text_tracks_[track_num_];
    194         text_track_info.kind = text_track_kind;
    195         text_track_info.name = track_name_;
    196         text_track_info.language = track_language_;
    197       }
    198     } else {
    199       MEDIA_LOG(log_cb_) << "Unexpected TrackType " << track_type_;
    200       return false;
    201     }
    202 
    203     track_type_ = -1;
    204     track_num_ = -1;
    205     track_name_.clear();
    206     track_language_.clear();
    207     codec_id_ = "";
    208     codec_private_.clear();
    209     track_content_encodings_client_.reset();
    210 
    211     audio_client_.Reset();
    212     video_client_.Reset();
    213     return true;
    214   }
    215 
    216   return true;
    217 }
    218 
    219 bool WebMTracksParser::OnUInt(int id, int64 val) {
    220   int64* dst = NULL;
    221 
    222   switch (id) {
    223     case kWebMIdTrackNumber:
    224       dst = &track_num_;
    225       break;
    226     case kWebMIdTrackType:
    227       dst = &track_type_;
    228       break;
    229     default:
    230       return true;
    231   }
    232 
    233   if (*dst != -1) {
    234     MEDIA_LOG(log_cb_) << "Multiple values for id " << std::hex << id
    235                        << " specified";
    236     return false;
    237   }
    238 
    239   *dst = val;
    240   return true;
    241 }
    242 
    243 bool WebMTracksParser::OnFloat(int id, double val) {
    244   return true;
    245 }
    246 
    247 bool WebMTracksParser::OnBinary(int id, const uint8* data, int size) {
    248   if (id == kWebMIdCodecPrivate) {
    249     if (!codec_private_.empty()) {
    250       MEDIA_LOG(log_cb_) << "Multiple CodecPrivate fields in a track.";
    251       return false;
    252     }
    253 
    254     codec_private_.assign(data, data + size);
    255     return true;
    256   }
    257   return true;
    258 }
    259 
    260 bool WebMTracksParser::OnString(int id, const std::string& str) {
    261   if (id == kWebMIdCodecID) {
    262     if (!codec_id_.empty()) {
    263       MEDIA_LOG(log_cb_) << "Multiple CodecID fields in a track";
    264       return false;
    265     }
    266 
    267     codec_id_ = str;
    268     return true;
    269   }
    270 
    271   if (id == kWebMIdName) {
    272     track_name_ = str;
    273     return true;
    274   }
    275 
    276   if (id == kWebMIdLanguage) {
    277     track_language_ = str;
    278     return true;
    279   }
    280 
    281   return true;
    282 }
    283 
    284 }  // namespace media
    285