DASH Media Packaging SDK
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator
webm_cluster_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_cluster_parser.h"
6 
7 #include <vector>
8 
9 #include "packager/base/logging.h"
10 #include "packager/base/sys_byteorder.h"
11 #include "packager/media/base/decrypt_config.h"
12 #include "packager/media/base/timestamp.h"
13 #include "packager/media/codecs/vp8_parser.h"
14 #include "packager/media/codecs/vp9_parser.h"
15 #include "packager/media/codecs/webvtt_util.h"
16 #include "packager/media/formats/webm/webm_constants.h"
17 #include "packager/media/formats/webm/webm_crypto_helpers.h"
18 #include "packager/media/formats/webm/webm_webvtt_parser.h"
19 
20 namespace shaka {
21 namespace media {
22 namespace {
23 
24 const int64_t kMicrosecondsPerMillisecond = 1000;
25 
26 // Helper function used to inspect block data to determine if the
27 // block is a keyframe.
28 // |data| contains the bytes in the block.
29 // |size| indicates the number of bytes in |data|.
30 bool IsKeyframe(bool is_video,
31  VideoCodec codec,
32  const uint8_t* data,
33  int size) {
34  // For now, assume that all blocks are keyframes for datatypes other than
35  // video. This is a valid assumption for Vorbis, WebVTT, & Opus.
36  if (!is_video)
37  return true;
38 
39  switch (codec) {
40  case kCodecVP8:
41  return VP8Parser::IsKeyframe(data, size);
42  case kCodecVP9:
43  return VP9Parser::IsKeyframe(data, size);
44  default:
45  NOTIMPLEMENTED() << "Unsupported codec " << codec;
46  return false;
47  }
48 }
49 
50 } // namespace
51 
53  int64_t timecode_scale,
54  scoped_refptr<AudioStreamInfo> audio_stream_info,
55  scoped_refptr<VideoStreamInfo> video_stream_info,
56  int64_t audio_default_duration,
57  int64_t video_default_duration,
58  const WebMTracksParser::TextTracks& text_tracks,
59  const std::set<int64_t>& ignored_tracks,
60  const std::string& audio_encryption_key_id,
61  const std::string& video_encryption_key_id,
62  const MediaParser::NewSampleCB& new_sample_cb,
63  const MediaParser::InitCB& init_cb,
64  KeySource* decryption_key_source)
65  : timecode_multiplier_(timecode_scale / 1000.0),
66  audio_stream_info_(audio_stream_info),
67  video_stream_info_(video_stream_info),
68  ignored_tracks_(ignored_tracks),
69  audio_encryption_key_id_(audio_encryption_key_id),
70  video_encryption_key_id_(video_encryption_key_id),
71  parser_(kWebMIdCluster, this),
72  initialized_(false),
73  init_cb_(init_cb),
74  cluster_start_time_(kNoTimestamp),
75  audio_(audio_stream_info ? audio_stream_info->track_id() : -1,
76  false,
77  audio_default_duration,
78  new_sample_cb),
79  video_(video_stream_info ? video_stream_info->track_id() : -1,
80  true,
81  video_default_duration,
82  new_sample_cb) {
83  if (decryption_key_source)
84  decryptor_source_.reset(new DecryptorSource(decryption_key_source));
85  for (WebMTracksParser::TextTracks::const_iterator it = text_tracks.begin();
86  it != text_tracks.end();
87  ++it) {
88  text_track_map_.insert(std::make_pair(
89  it->first, Track(it->first, false, kNoTimestamp, new_sample_cb)));
90  }
91 }
92 
93 WebMClusterParser::~WebMClusterParser() {}
94 
96  last_block_timecode_ = -1;
97  cluster_timecode_ = -1;
98  cluster_start_time_ = kNoTimestamp;
99  cluster_ended_ = false;
100  parser_.Reset();
101  audio_.Reset();
102  video_.Reset();
103  ResetTextTracks();
104 }
105 
107  // Estimate the duration of the last frame if necessary.
108  bool audio_result = audio_.ApplyDurationEstimateIfNeeded();
109  bool video_result = video_.ApplyDurationEstimateIfNeeded();
110  Reset();
111  return audio_result && video_result;
112 }
113 
114 int WebMClusterParser::Parse(const uint8_t* buf, int size) {
115  int result = parser_.Parse(buf, size);
116 
117  if (result < 0) {
118  cluster_ended_ = false;
119  return result;
120  }
121 
122  cluster_ended_ = parser_.IsParsingComplete();
123  if (cluster_ended_) {
124  // If there were no buffers in this cluster, set the cluster start time to
125  // be the |cluster_timecode_|.
126  if (cluster_start_time_ == kNoTimestamp) {
127  // If the cluster did not even have a |cluster_timecode_|, signal parse
128  // error.
129  if (cluster_timecode_ < 0)
130  return -1;
131 
132  cluster_start_time_ = cluster_timecode_ * timecode_multiplier_;
133  }
134 
135  // Reset the parser if we're done parsing so that
136  // it is ready to accept another cluster on the next
137  // call.
138  parser_.Reset();
139 
140  last_block_timecode_ = -1;
141  cluster_timecode_ = -1;
142  }
143 
144  return result;
145 }
146 
147 WebMParserClient* WebMClusterParser::OnListStart(int id) {
148  if (id == kWebMIdCluster) {
149  cluster_timecode_ = -1;
150  cluster_start_time_ = kNoTimestamp;
151  } else if (id == kWebMIdBlockGroup) {
152  block_data_.reset();
153  block_data_size_ = -1;
154  block_duration_ = -1;
155  discard_padding_ = -1;
156  discard_padding_set_ = false;
157  } else if (id == kWebMIdBlockAdditions) {
158  block_add_id_ = -1;
159  block_additional_data_.reset();
160  block_additional_data_size_ = 0;
161  }
162 
163  return this;
164 }
165 
166 bool WebMClusterParser::OnListEnd(int id) {
167  if (id != kWebMIdBlockGroup)
168  return true;
169 
170  // Make sure the BlockGroup actually had a Block.
171  if (block_data_size_ == -1) {
172  LOG(ERROR) << "Block missing from BlockGroup.";
173  return false;
174  }
175 
176  bool result = ParseBlock(false, block_data_.get(), block_data_size_,
177  block_additional_data_.get(),
178  block_additional_data_size_, block_duration_,
179  discard_padding_set_ ? discard_padding_ : 0);
180  block_data_.reset();
181  block_data_size_ = -1;
182  block_duration_ = -1;
183  block_add_id_ = -1;
184  block_additional_data_.reset();
185  block_additional_data_size_ = 0;
186  discard_padding_ = -1;
187  discard_padding_set_ = false;
188  return result;
189 }
190 
191 bool WebMClusterParser::OnUInt(int id, int64_t val) {
192  int64_t* dst;
193  switch (id) {
194  case kWebMIdTimecode:
195  dst = &cluster_timecode_;
196  break;
197  case kWebMIdBlockDuration:
198  dst = &block_duration_;
199  break;
200  case kWebMIdBlockAddID:
201  dst = &block_add_id_;
202  break;
203  default:
204  return true;
205  }
206  if (*dst != -1)
207  return false;
208  *dst = val;
209  return true;
210 }
211 
212 bool WebMClusterParser::ParseBlock(bool is_simple_block,
213  const uint8_t* buf,
214  int size,
215  const uint8_t* additional,
216  int additional_size,
217  int duration,
218  int64_t discard_padding) {
219  if (size < 4)
220  return false;
221 
222  // Return an error if the trackNum > 127. We just aren't
223  // going to support large track numbers right now.
224  if (!(buf[0] & 0x80)) {
225  LOG(ERROR) << "TrackNumber over 127 not supported";
226  return false;
227  }
228 
229  int track_num = buf[0] & 0x7f;
230  int timecode = buf[1] << 8 | buf[2];
231  int flags = buf[3] & 0xff;
232  int lacing = (flags >> 1) & 0x3;
233 
234  if (lacing) {
235  LOG(ERROR) << "Lacing " << lacing << " is not supported yet.";
236  return false;
237  }
238 
239  // Sign extend negative timecode offsets.
240  if (timecode & 0x8000)
241  timecode |= ~0xffff;
242 
243  const uint8_t* frame_data = buf + 4;
244  int frame_size = size - (frame_data - buf);
245  return OnBlock(is_simple_block, track_num, timecode, duration, flags,
246  frame_data, frame_size, additional, additional_size,
247  discard_padding);
248 }
249 
250 bool WebMClusterParser::OnBinary(int id, const uint8_t* data, int size) {
251  switch (id) {
252  case kWebMIdSimpleBlock:
253  return ParseBlock(true, data, size, NULL, 0, -1, 0);
254 
255  case kWebMIdBlock:
256  if (block_data_) {
257  LOG(ERROR) << "More than 1 Block in a BlockGroup is not "
258  "supported.";
259  return false;
260  }
261  block_data_.reset(new uint8_t[size]);
262  memcpy(block_data_.get(), data, size);
263  block_data_size_ = size;
264  return true;
265 
266  case kWebMIdBlockAdditional: {
267  uint64_t block_add_id = base::HostToNet64(block_add_id_);
268  if (block_additional_data_) {
269  // TODO: Technically, more than 1 BlockAdditional is allowed as per
270  // matroska spec. But for now we don't have a use case to support
271  // parsing of such files. Take a look at this again when such a case
272  // arises.
273  LOG(ERROR) << "More than 1 BlockAdditional in a "
274  "BlockGroup is not supported.";
275  return false;
276  }
277  // First 8 bytes of side_data in DecoderBuffer is the BlockAddID
278  // element's value in Big Endian format. This is done to mimic ffmpeg
279  // demuxer's behavior.
280  block_additional_data_size_ = size + sizeof(block_add_id);
281  block_additional_data_.reset(new uint8_t[block_additional_data_size_]);
282  memcpy(block_additional_data_.get(), &block_add_id,
283  sizeof(block_add_id));
284  memcpy(block_additional_data_.get() + 8, data, size);
285  return true;
286  }
287  case kWebMIdDiscardPadding: {
288  if (discard_padding_set_ || size <= 0 || size > 8)
289  return false;
290  discard_padding_set_ = true;
291 
292  // Read in the big-endian integer.
293  discard_padding_ = static_cast<int8_t>(data[0]);
294  for (int i = 1; i < size; ++i)
295  discard_padding_ = (discard_padding_ << 8) | data[i];
296 
297  return true;
298  }
299  default:
300  return true;
301  }
302 }
303 
304 bool WebMClusterParser::OnBlock(bool is_simple_block,
305  int track_num,
306  int timecode,
307  int block_duration,
308  int flags,
309  const uint8_t* data,
310  int size,
311  const uint8_t* additional,
312  int additional_size,
313  int64_t discard_padding) {
314  DCHECK_GE(size, 0);
315  if (cluster_timecode_ == -1) {
316  LOG(ERROR) << "Got a block before cluster timecode.";
317  return false;
318  }
319 
320  // TODO: Should relative negative timecode offsets be rejected? Or only when
321  // the absolute timecode is negative? See http://crbug.com/271794
322  if (timecode < 0) {
323  LOG(ERROR) << "Got a block with negative timecode offset " << timecode;
324  return false;
325  }
326 
327  if (last_block_timecode_ != -1 && timecode < last_block_timecode_) {
328  LOG(ERROR) << "Got a block with a timecode before the previous block.";
329  return false;
330  }
331 
332  Track* track = NULL;
333  StreamType stream_type = kStreamUnknown;
334  std::string encryption_key_id;
335  if (track_num == audio_.track_num()) {
336  track = &audio_;
337  encryption_key_id = audio_encryption_key_id_;
338  stream_type = kStreamAudio;
339  } else if (track_num == video_.track_num()) {
340  track = &video_;
341  encryption_key_id = video_encryption_key_id_;
342  stream_type = kStreamVideo;
343  } else if (ignored_tracks_.find(track_num) != ignored_tracks_.end()) {
344  return true;
345  } else if (Track* const text_track = FindTextTrack(track_num)) {
346  if (is_simple_block) // BlockGroup is required for WebVTT cues
347  return false;
348  if (block_duration < 0) // not specified
349  return false;
350  track = text_track;
351  stream_type = kStreamText;
352  } else {
353  LOG(ERROR) << "Unexpected track number " << track_num;
354  return false;
355  }
356  DCHECK_NE(stream_type, kStreamUnknown);
357 
358  last_block_timecode_ = timecode;
359 
360  int64_t timestamp = (cluster_timecode_ + timecode) * timecode_multiplier_;
361 
362  scoped_refptr<MediaSample> buffer;
363  if (stream_type != kStreamText) {
364  // The first bit of the flags is set when a SimpleBlock contains only
365  // keyframes. If this is a Block, then inspection of the payload is
366  // necessary to determine whether it contains a keyframe or not.
367  // http://www.matroska.org/technical/specs/index.html
368  bool is_keyframe =
369  is_simple_block
370  ? (flags & 0x80) != 0
371  : IsKeyframe(stream_type == kStreamVideo,
372  video_stream_info_ ? video_stream_info_->codec()
373  : kUnknownVideoCodec,
374  data, size);
375 
376  // Every encrypted Block has a signal byte and IV prepended to it. Current
377  // encrypted WebM request for comments specification is here
378  // http://wiki.webmproject.org/encryption/webm-encryption-rfc
379  scoped_ptr<DecryptConfig> decrypt_config;
380  int data_offset = 0;
381  if (!encryption_key_id.empty() &&
382  !WebMCreateDecryptConfig(
383  data, size,
384  reinterpret_cast<const uint8_t*>(encryption_key_id.data()),
385  encryption_key_id.size(),
386  &decrypt_config, &data_offset)) {
387  return false;
388  }
389 
390  buffer = MediaSample::CopyFrom(data + data_offset, size - data_offset,
391  additional, additional_size, is_keyframe);
392 
393  // An empty iv indicates that this sample is not encrypted.
394  if (decrypt_config && !decrypt_config->iv().empty()) {
395  if (!decryptor_source_) {
396  LOG(ERROR) << "Encrypted media sample encountered, but decryption is "
397  "not enabled";
398  return false;
399  }
400  if (!decryptor_source_->DecryptSampleBuffer(decrypt_config.get(),
401  buffer->writable_data(),
402  buffer->data_size())) {
403  LOG(ERROR) << "Cannot decrypt samples";
404  return false;
405  }
406  }
407  } else {
408  std::string id, settings, content;
409  WebMWebVTTParser::Parse(data, size, &id, &settings, &content);
410 
411  std::vector<uint8_t> side_data;
412  MakeSideData(id.begin(), id.end(),
413  settings.begin(), settings.end(),
414  &side_data);
415 
416  buffer = MediaSample::CopyFrom(
417  reinterpret_cast<const uint8_t*>(content.data()), content.length(),
418  &side_data[0], side_data.size(), true);
419  }
420 
421  buffer->set_dts(timestamp);
422  buffer->set_pts(timestamp);
423  if (cluster_start_time_ == kNoTimestamp)
424  cluster_start_time_ = timestamp;
425  buffer->set_duration(block_duration > 0
426  ? (block_duration * timecode_multiplier_)
427  : kNoTimestamp);
428 
429  if (!init_cb_.is_null() && !initialized_) {
430  std::vector<scoped_refptr<StreamInfo>> streams;
431  if (audio_stream_info_)
432  streams.push_back(audio_stream_info_);
433  if (video_stream_info_) {
434  if (stream_type == kStreamVideo) {
435  scoped_ptr<VPxParser> vpx_parser;
436  switch (video_stream_info_->codec()) {
437  case kCodecVP8:
438  vpx_parser.reset(new VP8Parser);
439  break;
440  case kCodecVP9:
441  vpx_parser.reset(new VP9Parser);
442  break;
443  default:
444  NOTIMPLEMENTED() << "Unsupported codec "
445  << video_stream_info_->codec();
446  return false;
447  }
448  std::vector<VPxFrameInfo> vpx_frames;
449  if (!vpx_parser->Parse(buffer->data(), buffer->data_size(),
450  &vpx_frames)) {
451  LOG(ERROR) << "Failed to parse vpx frame.";
452  return false;
453  }
454  if (vpx_frames.size() != 1u || !vpx_frames[0].is_keyframe) {
455  LOG(ERROR) << "The first frame should be a key frame.";
456  return false;
457  }
458 
459  const VPCodecConfigurationRecord* codec_config =
460  &vpx_parser->codec_config();
461  video_stream_info_->set_codec_string(
462  codec_config->GetCodecString(video_stream_info_->codec()));
463  std::vector<uint8_t> extra_data;
464  codec_config->Write(&extra_data);
465  video_stream_info_->set_extra_data(extra_data);
466  streams.push_back(video_stream_info_);
467  init_cb_.Run(streams);
468  initialized_ = true;
469  }
470  } else {
471  init_cb_.Run(streams);
472  initialized_ = true;
473  }
474  }
475 
476  return track->EmitBuffer(buffer);
477 }
478 
479 WebMClusterParser::Track::Track(int track_num,
480  bool is_video,
481  int64_t default_duration,
482  const MediaParser::NewSampleCB& new_sample_cb)
483  : track_num_(track_num),
484  is_video_(is_video),
485  default_duration_(default_duration),
486  estimated_next_frame_duration_(kNoTimestamp),
487  new_sample_cb_(new_sample_cb) {
488  DCHECK(default_duration_ == kNoTimestamp || default_duration_ > 0);
489 }
490 
491 WebMClusterParser::Track::~Track() {}
492 
493 bool WebMClusterParser::Track::EmitBuffer(
494  const scoped_refptr<MediaSample>& buffer) {
495  DVLOG(2) << "EmitBuffer() : " << track_num_
496  << " ts " << buffer->pts()
497  << " dur " << buffer->duration()
498  << " kf " << buffer->is_key_frame()
499  << " size " << buffer->data_size();
500 
501  if (last_added_buffer_missing_duration_.get()) {
502  int64_t derived_duration =
503  buffer->pts() - last_added_buffer_missing_duration_->pts();
504  last_added_buffer_missing_duration_->set_duration(derived_duration);
505 
506  DVLOG(2) << "EmitBuffer() : applied derived duration to held-back buffer : "
507  << " ts "
508  << last_added_buffer_missing_duration_->pts()
509  << " dur "
510  << last_added_buffer_missing_duration_->duration()
511  << " kf " << last_added_buffer_missing_duration_->is_key_frame()
512  << " size " << last_added_buffer_missing_duration_->data_size();
513  scoped_refptr<MediaSample> updated_buffer =
514  last_added_buffer_missing_duration_;
515  last_added_buffer_missing_duration_ = NULL;
516  if (!EmitBufferHelp(updated_buffer))
517  return false;
518  }
519 
520  if (buffer->duration() == kNoTimestamp) {
521  last_added_buffer_missing_duration_ = buffer;
522  DVLOG(2) << "EmitBuffer() : holding back buffer that is missing duration";
523  return true;
524  }
525 
526  return EmitBufferHelp(buffer);
527 }
528 
529 bool WebMClusterParser::Track::ApplyDurationEstimateIfNeeded() {
530  if (!last_added_buffer_missing_duration_.get())
531  return true;
532 
533  int64_t estimated_duration = GetDurationEstimate();
534  last_added_buffer_missing_duration_->set_duration(estimated_duration);
535 
536  VLOG(1) << "Track " << track_num_ << ": Estimating WebM block duration to be "
537  << estimated_duration / 1000
538  << "ms for the last (Simple)Block in the Cluster for this Track. Use "
539  "BlockGroups with BlockDurations at the end of each Track in a "
540  "Cluster to avoid estimation.";
541 
542  DVLOG(2) << " new dur : ts " << last_added_buffer_missing_duration_->pts()
543  << " dur " << last_added_buffer_missing_duration_->duration()
544  << " kf " << last_added_buffer_missing_duration_->is_key_frame()
545  << " size " << last_added_buffer_missing_duration_->data_size();
546 
547  // Don't use the applied duration as a future estimation (don't use
548  // EmitBufferHelp() here.)
549  if (!new_sample_cb_.Run(track_num_, last_added_buffer_missing_duration_))
550  return false;
551  last_added_buffer_missing_duration_ = NULL;
552  return true;
553 }
554 
555 void WebMClusterParser::Track::Reset() {
556  last_added_buffer_missing_duration_ = NULL;
557 }
558 
559 bool WebMClusterParser::Track::EmitBufferHelp(
560  const scoped_refptr<MediaSample>& buffer) {
561  DCHECK(!last_added_buffer_missing_duration_.get());
562 
563  int64_t duration = buffer->duration();
564  if (duration < 0 || duration == kNoTimestamp) {
565  LOG(ERROR) << "Invalid buffer duration: " << duration;
566  return false;
567  }
568 
569  // The estimated frame duration is the maximum non-zero duration since the
570  // last initialization segment.
571  if (duration > 0) {
572  int64_t orig_duration_estimate = estimated_next_frame_duration_;
573  if (estimated_next_frame_duration_ == kNoTimestamp) {
574  estimated_next_frame_duration_ = duration;
575  } else {
576  estimated_next_frame_duration_ =
577  std::max(duration, estimated_next_frame_duration_);
578  }
579 
580  if (orig_duration_estimate != estimated_next_frame_duration_) {
581  DVLOG(3) << "Updated duration estimate:"
582  << orig_duration_estimate
583  << " -> "
584  << estimated_next_frame_duration_
585  << " at timestamp: "
586  << buffer->dts();
587  }
588  }
589 
590  return new_sample_cb_.Run(track_num_, buffer);
591 }
592 
593 int64_t WebMClusterParser::Track::GetDurationEstimate() {
594  int64_t duration = kNoTimestamp;
595  if (default_duration_ != kNoTimestamp) {
596  duration = default_duration_;
597  DVLOG(3) << __FUNCTION__ << " : using track default duration " << duration;
598  } else if (estimated_next_frame_duration_ != kNoTimestamp) {
599  duration = estimated_next_frame_duration_;
600  DVLOG(3) << __FUNCTION__ << " : using estimated duration " << duration;
601  } else {
602  if (is_video_) {
603  duration = kDefaultVideoBufferDurationInMs * kMicrosecondsPerMillisecond;
604  } else {
605  duration = kDefaultAudioBufferDurationInMs * kMicrosecondsPerMillisecond;
606  }
607  DVLOG(3) << __FUNCTION__ << " : using hardcoded default duration "
608  << duration;
609  }
610 
611  DCHECK_GT(duration, 0);
612  DCHECK_NE(duration, kNoTimestamp);
613  return duration;
614 }
615 
616 void WebMClusterParser::ResetTextTracks() {
617  for (TextTrackMap::iterator it = text_track_map_.begin();
618  it != text_track_map_.end();
619  ++it) {
620  it->second.Reset();
621  }
622 }
623 
624 WebMClusterParser::Track*
625 WebMClusterParser::FindTextTrack(int track_num) {
626  const TextTrackMap::iterator it = text_track_map_.find(track_num);
627 
628  if (it == text_track_map_.end())
629  return NULL;
630 
631  return &it->second;
632 }
633 
634 } // namespace media
635 } // namespace shaka
static bool IsKeyframe(const uint8_t *data, size_t data_size)
Definition: vp9_parser.cc:535
base::Callback< void(const std::vector< scoped_refptr< StreamInfo > > &stream_info)> InitCB
Definition: media_parser.h:35
int Parse(const uint8_t *buf, int size)
void Reset()
Resets the state of the parser so it can start parsing a new list.
Definition: webm_parser.cc:714
int Parse(const uint8_t *buf, int size)
Definition: webm_parser.cc:719
bool Flush() WARN_UNUSED_RESULT
static void Parse(const uint8_t *payload, int payload_size, std::string *id, std::string *settings, std::string *content)
Utility function to parse the WebVTT cue from a byte stream.
static bool IsKeyframe(const uint8_t *data, size_t data_size)
Definition: vp8_parser.cc:183
base::Callback< bool(uint32_t track_id, const scoped_refptr< MediaSample > &media_sample)> NewSampleCB
Definition: media_parser.h:44
KeySource is responsible for encryption key acquisition.
Definition: key_source.h:31
static scoped_refptr< MediaSample > CopyFrom(const uint8_t *data, size_t size, bool is_key_frame)
Definition: media_sample.cc:45
WebMClusterParser(int64_t timecode_scale, scoped_refptr< AudioStreamInfo > audio_stream_info, scoped_refptr< VideoStreamInfo > video_stream_info, int64_t audio_default_duration, int64_t video_default_duration, const WebMTracksParser::TextTracks &text_tracks, const std::set< int64_t > &ignored_tracks, const std::string &audio_encryption_key_id, const std::string &video_encryption_key_id, const MediaParser::NewSampleCB &new_sample_cb, const MediaParser::InitCB &init_cb, KeySource *decryption_key_source)
DecryptorSource wraps KeySource and is responsible for decryptor management.
void Reset()
Resets the parser state so it can accept a new cluster.