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