DASH Media Packaging SDK
 All Classes Namespaces Functions Variables Typedefs Enumerator
webm_media_parser.cc
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 "packager/media/formats/webm/webm_media_parser.h"
6 
7 #include <string>
8 
9 #include "packager/base/callback.h"
10 #include "packager/base/callback_helpers.h"
11 #include "packager/base/logging.h"
12 #include "packager/media/base/buffer_writer.h"
13 #include "packager/media/base/timestamp.h"
14 #include "packager/media/base/widevine_pssh_data.pb.h"
15 #include "packager/media/formats/webm/webm_cluster_parser.h"
16 #include "packager/media/formats/webm/webm_constants.h"
17 #include "packager/media/formats/webm/webm_content_encodings.h"
18 #include "packager/media/formats/webm/webm_info_parser.h"
19 #include "packager/media/formats/webm/webm_tracks_parser.h"
20 
21 namespace edash_packager {
22 namespace media {
23 
24 WebMMediaParser::WebMMediaParser()
25  : state_(kWaitingForInit), unknown_segment_size_(false) {}
26 
27 WebMMediaParser::~WebMMediaParser() {}
28 
29 void WebMMediaParser::Init(const InitCB& init_cb,
30  const NewSampleCB& new_sample_cb,
31  KeySource* decryption_key_source) {
32  DCHECK_EQ(state_, kWaitingForInit);
33  DCHECK(init_cb_.is_null());
34  DCHECK(!init_cb.is_null());
35  DCHECK(!new_sample_cb.is_null());
36 
37  ChangeState(kParsingHeaders);
38  init_cb_ = init_cb;
39  new_sample_cb_ = new_sample_cb;
40  decryption_key_source_ = decryption_key_source;
41  ignore_text_tracks_ = true;
42 }
43 
45  DCHECK_NE(state_, kWaitingForInit);
46 
47  byte_queue_.Reset();
48  if (cluster_parser_)
49  cluster_parser_->Flush();
50  if (state_ == kParsingClusters) {
51  ChangeState(kParsingHeaders);
52  }
53 }
54 
55 bool WebMMediaParser::Parse(const uint8_t* buf, int size) {
56  DCHECK_NE(state_, kWaitingForInit);
57 
58  if (state_ == kError)
59  return false;
60 
61  byte_queue_.Push(buf, size);
62 
63  int result = 0;
64  int bytes_parsed = 0;
65  const uint8_t* cur = NULL;
66  int cur_size = 0;
67 
68  byte_queue_.Peek(&cur, &cur_size);
69  while (cur_size > 0) {
70  State oldState = state_;
71  switch (state_) {
72  case kParsingHeaders:
73  result = ParseInfoAndTracks(cur, cur_size);
74  break;
75 
76  case kParsingClusters:
77  result = ParseCluster(cur, cur_size);
78  break;
79 
80  case kWaitingForInit:
81  case kError:
82  return false;
83  }
84 
85  if (result < 0) {
86  ChangeState(kError);
87  return false;
88  }
89 
90  if (state_ == oldState && result == 0)
91  break;
92 
93  DCHECK_GE(result, 0);
94  cur += result;
95  cur_size -= result;
96  bytes_parsed += result;
97  }
98 
99  byte_queue_.Pop(bytes_parsed);
100  return true;
101 }
102 
103 void WebMMediaParser::ChangeState(State new_state) {
104  DVLOG(1) << "ChangeState() : " << state_ << " -> " << new_state;
105  state_ = new_state;
106 }
107 
108 int WebMMediaParser::ParseInfoAndTracks(const uint8_t* data, int size) {
109  DVLOG(2) << "ParseInfoAndTracks()";
110  DCHECK(data);
111  DCHECK_GT(size, 0);
112 
113  const uint8_t* cur = data;
114  int cur_size = size;
115  int bytes_parsed = 0;
116 
117  int id;
118  int64_t element_size;
119  int result = WebMParseElementHeader(cur, cur_size, &id, &element_size);
120 
121  if (result <= 0)
122  return result;
123 
124  switch (id) {
125  case kWebMIdEBMLHeader:
126  case kWebMIdSeekHead:
127  case kWebMIdVoid:
128  case kWebMIdCRC32:
129  case kWebMIdCues:
130  case kWebMIdChapters:
131  case kWebMIdTags:
132  case kWebMIdAttachments:
133  // TODO: Implement support for chapters.
134  if (cur_size < (result + element_size)) {
135  // We don't have the whole element yet. Signal we need more data.
136  return 0;
137  }
138  // Skip the element.
139  return result + element_size;
140  break;
141  case kWebMIdCluster:
142  if (!cluster_parser_) {
143  LOG(ERROR) << "Found Cluster element before Info.";
144  return -1;
145  }
146  ChangeState(kParsingClusters);
147  return 0;
148  break;
149  case kWebMIdSegment:
150  // Segment of unknown size indicates live stream.
151  if (element_size == kWebMUnknownSize)
152  unknown_segment_size_ = true;
153  // Just consume the segment header.
154  return result;
155  break;
156  case kWebMIdInfo:
157  // We've found the element we are looking for.
158  break;
159  default: {
160  LOG(ERROR) << "Unexpected element ID 0x" << std::hex << id;
161  return -1;
162  }
163  }
164 
165  WebMInfoParser info_parser;
166  result = info_parser.Parse(cur, cur_size);
167 
168  if (result <= 0)
169  return result;
170 
171  cur += result;
172  cur_size -= result;
173  bytes_parsed += result;
174 
175  WebMTracksParser tracks_parser(ignore_text_tracks_);
176  result = tracks_parser.Parse(cur, cur_size);
177 
178  if (result <= 0)
179  return result;
180 
181  bytes_parsed += result;
182 
183  double timecode_scale_in_us = info_parser.timecode_scale() / 1000.0;
184  int64_t duration_in_us = info_parser.duration() * timecode_scale_in_us;
185 
186  scoped_refptr<AudioStreamInfo> audio_stream_info =
187  tracks_parser.audio_stream_info();
188  if (audio_stream_info) {
189  audio_stream_info->set_duration(duration_in_us);
190  } else {
191  VLOG(1) << "No audio track info found.";
192  }
193 
194  scoped_refptr<VideoStreamInfo> video_stream_info =
195  tracks_parser.video_stream_info();
196  if (video_stream_info) {
197  video_stream_info->set_duration(duration_in_us);
198  } else {
199  VLOG(1) << "No video track info found.";
200  }
201 
202  if (!FetchKeysIfNecessary(tracks_parser.audio_encryption_key_id(),
203  tracks_parser.video_encryption_key_id())) {
204  return -1;
205  }
206 
207  cluster_parser_.reset(new WebMClusterParser(
208  info_parser.timecode_scale(), audio_stream_info, video_stream_info,
209  tracks_parser.GetAudioDefaultDuration(timecode_scale_in_us),
210  tracks_parser.GetVideoDefaultDuration(timecode_scale_in_us),
211  tracks_parser.text_tracks(), tracks_parser.ignored_tracks(),
212  tracks_parser.audio_encryption_key_id(),
213  tracks_parser.video_encryption_key_id(), new_sample_cb_, init_cb_,
214  decryption_key_source_));
215 
216  return bytes_parsed;
217 }
218 
219 int WebMMediaParser::ParseCluster(const uint8_t* data, int size) {
220  if (!cluster_parser_)
221  return -1;
222 
223  int bytes_parsed = cluster_parser_->Parse(data, size);
224  if (bytes_parsed < 0)
225  return bytes_parsed;
226 
227  bool cluster_ended = cluster_parser_->cluster_ended();
228  if (cluster_ended) {
229  ChangeState(kParsingHeaders);
230  }
231 
232  return bytes_parsed;
233 }
234 
235 bool WebMMediaParser::FetchKeysIfNecessary(
236  const std::string& audio_encryption_key_id,
237  const std::string& video_encryption_key_id) {
238  if (audio_encryption_key_id.empty() && video_encryption_key_id.empty())
239  return true;
240  // An error will be returned later if the samples need to be derypted.
241  if (!decryption_key_source_)
242  return true;
243 
244  // Generate WidevinePsshData from key_id.
245  WidevinePsshData widevine_pssh_data;
246  if (!audio_encryption_key_id.empty())
247  widevine_pssh_data.add_key_id(audio_encryption_key_id);
248  if (!video_encryption_key_id.empty())
249  widevine_pssh_data.add_key_id(video_encryption_key_id);
250 
251  const std::string serialized_string = widevine_pssh_data.SerializeAsString();
252  Status status = decryption_key_source_->FetchKeys(
253  std::vector<uint8_t>(serialized_string.begin(), serialized_string.end()));
254  if (!status.ok()) {
255  LOG(ERROR) << "Error fetching decryption keys: " << status;
256  return false;
257  }
258  return true;
259 }
260 
261 } // namespace media
262 } // namespace edash_packager
bool Parse(const uint8_t *buf, int size) override
void Init(const InitCB &init_cb, const NewSampleCB &new_sample_cb, KeySource *decryption_key_source) override
StreamParser implementation.
void Push(const uint8_t *data, int size)
Append new bytes to the end of the queue.
Definition: byte_queue.cc:29
virtual Status FetchKeys(const std::vector< uint8_t > &content_id, const std::string &policy)
Definition: key_source.cc:30
base::Callback< bool(uint32_t track_id, const scoped_refptr< MediaSample > &media_sample)> NewSampleCB
Definition: media_parser.h:43
KeySource is responsible for encryption key acquisition.
Definition: key_source.h:29
void Reset()
Reset the queue to the empty state.
Definition: byte_queue.cc:24
void Peek(const uint8_t **data, int *size) const
Definition: byte_queue.cc:63