Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(311)

Side by Side Diff: media/formats/webm/webm_cluster_parser.cc

Issue 213253006: MSE: Populate WebM missing duration with DefaultDuration, derived, or default (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 6 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "media/formats/webm/webm_cluster_parser.h" 5 #include "media/formats/webm/webm_cluster_parser.h"
6 6
7 #include <vector> 7 #include <vector>
8 8
9 #include "base/logging.h" 9 #include "base/logging.h"
10 #include "base/sys_byteorder.h" 10 #include "base/sys_byteorder.h"
11 #include "media/base/buffers.h" 11 #include "media/base/buffers.h"
12 #include "media/base/decrypt_config.h" 12 #include "media/base/decrypt_config.h"
13 #include "media/filters/webvtt_util.h" 13 #include "media/filters/webvtt_util.h"
14 #include "media/formats/webm/webm_constants.h" 14 #include "media/formats/webm/webm_constants.h"
15 #include "media/formats/webm/webm_crypto_helpers.h" 15 #include "media/formats/webm/webm_crypto_helpers.h"
16 #include "media/formats/webm/webm_webvtt_parser.h" 16 #include "media/formats/webm/webm_webvtt_parser.h"
17 17
18 // An arbitrarily-chosen number to estimate the duration of a buffer if none is
19 // set and there is not enough information to get a better estimate.
20 // TODO(wolenetz/acolwell): Parse audio codebook to determine missing audio
21 // frame durations. See http://crbug.com/351166.
22 static int kDefaultBufferDurationInMs = 50;
acolwell GONE FROM CHROMIUM 2014/03/26 23:32:04 nit: If we are assuming this will be audio, then I
wolenetz 2014/03/27 18:01:48 Done. I've now differentiated audio vs video defau
23
18 namespace media { 24 namespace media {
19 25
20 WebMClusterParser::WebMClusterParser( 26 WebMClusterParser::WebMClusterParser(
21 int64 timecode_scale, int audio_track_num, int video_track_num, 27 int64 timecode_scale,
28 int audio_track_num,
29 base::TimeDelta audio_default_duration,
30 int video_track_num,
31 base::TimeDelta video_default_duration,
22 const WebMTracksParser::TextTracks& text_tracks, 32 const WebMTracksParser::TextTracks& text_tracks,
23 const std::set<int64>& ignored_tracks, 33 const std::set<int64>& ignored_tracks,
24 const std::string& audio_encryption_key_id, 34 const std::string& audio_encryption_key_id,
25 const std::string& video_encryption_key_id, 35 const std::string& video_encryption_key_id,
26 const LogCB& log_cb) 36 const LogCB& log_cb)
27 : timecode_multiplier_(timecode_scale / 1000.0), 37 : timecode_multiplier_(timecode_scale / 1000.0),
28 ignored_tracks_(ignored_tracks), 38 ignored_tracks_(ignored_tracks),
29 audio_encryption_key_id_(audio_encryption_key_id), 39 audio_encryption_key_id_(audio_encryption_key_id),
30 video_encryption_key_id_(video_encryption_key_id), 40 video_encryption_key_id_(video_encryption_key_id),
31 parser_(kWebMIdCluster, this), 41 parser_(kWebMIdCluster, this),
32 last_block_timecode_(-1), 42 last_block_timecode_(-1),
33 block_data_size_(-1), 43 block_data_size_(-1),
34 block_duration_(-1), 44 block_duration_(-1),
35 block_add_id_(-1), 45 block_add_id_(-1),
36 block_additional_data_size_(-1), 46 block_additional_data_size_(-1),
37 discard_padding_(-1), 47 discard_padding_(-1),
38 cluster_timecode_(-1), 48 cluster_timecode_(-1),
39 cluster_start_time_(kNoTimestamp()), 49 cluster_start_time_(kNoTimestamp()),
40 cluster_ended_(false), 50 cluster_ended_(false),
41 audio_(audio_track_num, false), 51 audio_(audio_track_num, false, audio_default_duration),
42 video_(video_track_num, true), 52 video_(video_track_num, true, video_default_duration),
43 log_cb_(log_cb) { 53 log_cb_(log_cb) {
44 for (WebMTracksParser::TextTracks::const_iterator it = text_tracks.begin(); 54 for (WebMTracksParser::TextTracks::const_iterator it = text_tracks.begin();
45 it != text_tracks.end(); 55 it != text_tracks.end();
46 ++it) { 56 ++it) {
47 text_track_map_.insert(std::make_pair(it->first, Track(it->first, false))); 57 text_track_map_.insert(std::make_pair(
58 it->first, Track(it->first, false, kNoTimestamp())));
48 } 59 }
49 } 60 }
50 61
51 WebMClusterParser::~WebMClusterParser() {} 62 WebMClusterParser::~WebMClusterParser() {}
52 63
53 void WebMClusterParser::Reset() { 64 void WebMClusterParser::Reset() {
54 last_block_timecode_ = -1; 65 last_block_timecode_ = -1;
55 cluster_timecode_ = -1; 66 cluster_timecode_ = -1;
56 cluster_start_time_ = kNoTimestamp(); 67 cluster_start_time_ = kNoTimestamp();
57 cluster_ended_ = false; 68 cluster_ended_ = false;
58 parser_.Reset(); 69 parser_.Reset();
59 audio_.Reset(); 70 audio_.Flush();
acolwell GONE FROM CHROMIUM 2014/03/26 23:32:04 nit: I think Reset() should be "clear everything"
wolenetz 2014/03/27 18:01:48 Done.
60 video_.Reset(); 71 video_.Flush();
61 ResetTextTracks(); 72 ResetTextTracks();
62 } 73 }
63 74
64 int WebMClusterParser::Parse(const uint8* buf, int size) { 75 int WebMClusterParser::Parse(const uint8* buf, int size) {
65 audio_.Reset(); 76 audio_.Reset();
66 video_.Reset(); 77 video_.Reset();
67 ResetTextTracks(); 78 ResetTextTracks();
68 79
69 int result = parser_.Parse(buf, size); 80 int result = parser_.Parse(buf, size);
70 81
(...skipping 21 matching lines...) Expand all
92 // call. 103 // call.
93 parser_.Reset(); 104 parser_.Reset();
94 105
95 last_block_timecode_ = -1; 106 last_block_timecode_ = -1;
96 cluster_timecode_ = -1; 107 cluster_timecode_ = -1;
97 } 108 }
98 109
99 return result; 110 return result;
100 } 111 }
101 112
113 const WebMClusterParser::BufferQueue& WebMClusterParser::GetAudioBuffers() {
114 if (cluster_ended_)
115 audio_.ApplyDurationDefaultOrEstimateIfNeeded();
116 return audio_.buffers();
117 }
118
119 const WebMClusterParser::BufferQueue& WebMClusterParser::GetVideoBuffers() {
120 if (cluster_ended_)
121 video_.ApplyDurationDefaultOrEstimateIfNeeded();
122 return video_.buffers();
123 }
124
102 const WebMClusterParser::TextBufferQueueMap& 125 const WebMClusterParser::TextBufferQueueMap&
103 WebMClusterParser::GetTextBuffers() { 126 WebMClusterParser::GetTextBuffers() {
104 // Translate our |text_track_map_| into |text_buffers_map_|, inserting rows in 127 // Translate our |text_track_map_| into |text_buffers_map_|, inserting rows in
105 // the output only for non-empty text buffer queues in |text_track_map_|. 128 // the output only for non-empty text buffer queues in |text_track_map_|.
106 text_buffers_map_.clear(); 129 text_buffers_map_.clear();
107 for (TextTrackMap::const_iterator itr = text_track_map_.begin(); 130 for (TextTrackMap::const_iterator itr = text_track_map_.begin();
108 itr != text_track_map_.end(); 131 itr != text_track_map_.end();
109 ++itr) { 132 ++itr) {
133 // Per OnBlock(), all text buffers should already have valid durations, so
134 // there is no need to call
135 // itr->second.ApplyDurationDefaultOrEstimateIfNeeded() here.
110 const BufferQueue& text_buffers = itr->second.buffers(); 136 const BufferQueue& text_buffers = itr->second.buffers();
111 if (!text_buffers.empty()) 137 if (!text_buffers.empty())
112 text_buffers_map_.insert(std::make_pair(itr->first, text_buffers)); 138 text_buffers_map_.insert(std::make_pair(itr->first, text_buffers));
113 } 139 }
114 140
115 return text_buffers_map_; 141 return text_buffers_map_;
116 } 142 }
117 143
118 WebMParserClient* WebMClusterParser::OnListStart(int id) { 144 WebMParserClient* WebMClusterParser::OnListStart(int id) {
119 if (id == kWebMIdCluster) { 145 if (id == kWebMIdCluster) {
(...skipping 263 matching lines...) Expand 10 before | Expand all | Expand 10 after
383 } 409 }
384 410
385 if (discard_padding != 0) { 411 if (discard_padding != 0) {
386 buffer->set_discard_padding(base::TimeDelta::FromMicroseconds( 412 buffer->set_discard_padding(base::TimeDelta::FromMicroseconds(
387 discard_padding / 1000)); 413 discard_padding / 1000));
388 } 414 }
389 415
390 return track->AddBuffer(buffer); 416 return track->AddBuffer(buffer);
391 } 417 }
392 418
393 WebMClusterParser::Track::Track(int track_num, bool is_video) 419 WebMClusterParser::Track::Track(int track_num, bool is_video,
420 base::TimeDelta default_duration)
394 : track_num_(track_num), 421 : track_num_(track_num),
395 is_video_(is_video) { 422 is_video_(is_video),
423 default_duration_(default_duration),
424 estimated_next_frame_duration_(kNoTimestamp()) {
425 DCHECK(default_duration_ == kNoTimestamp() ||
426 default_duration_ > base::TimeDelta());
396 } 427 }
397 428
398 WebMClusterParser::Track::~Track() {} 429 WebMClusterParser::Track::~Track() {}
399 430
400 bool WebMClusterParser::Track::AddBuffer( 431 bool WebMClusterParser::Track::AddBuffer(
401 const scoped_refptr<StreamParserBuffer>& buffer) { 432 const scoped_refptr<StreamParserBuffer>& buffer) {
402 DVLOG(2) << "AddBuffer() : " << track_num_ 433 DVLOG(2) << "AddBuffer() : " << track_num_
403 << " ts " << buffer->timestamp().InSecondsF() 434 << " ts " << buffer->timestamp().InSecondsF()
404 << " dur " << buffer->duration().InSecondsF() 435 << " dur " << buffer->duration().InSecondsF()
405 << " kf " << buffer->IsKeyframe() 436 << " kf " << buffer->IsKeyframe()
406 << " size " << buffer->data_size(); 437 << " size " << buffer->data_size();
407 438
439 if (last_added_buffer_missing_duration_) {
440 base::TimeDelta derived_duration =
441 buffer->timestamp() - last_added_buffer_missing_duration_->timestamp();
442 if (derived_duration < base::TimeDelta()) {
443 DVLOG(2) << "AddBuffer() : Invalid derived duration: "
444 << derived_duration.InSecondsF();
445 return false;
446 }
447
448 last_added_buffer_missing_duration_->set_duration(derived_duration);
449
450 DVLOG(2) << "AddBuffer() : applied derived duration to held-back buffer : "
451 << " ts "
452 << last_added_buffer_missing_duration_->timestamp().InSecondsF()
453 << " dur "
454 << last_added_buffer_missing_duration_->duration().InSecondsF()
455 << " kf " << last_added_buffer_missing_duration_->IsKeyframe()
456 << " size " << last_added_buffer_missing_duration_->data_size();
457 estimated_next_frame_duration_ = std::max(derived_duration,
458 estimated_next_frame_duration_);
459 buffers_.push_back(last_added_buffer_missing_duration_);
460 last_added_buffer_missing_duration_ = NULL;
461 }
462
463 if (buffer->duration() == kNoTimestamp()) {
464 last_added_buffer_missing_duration_ = buffer;
465 DVLOG(2) << "AddBuffer() : holding back buffer that is missing duration";
466 return true;
467 }
468
469 DCHECK(!last_added_buffer_missing_duration_);
470 if (buffer->duration() < base::TimeDelta()) {
acolwell GONE FROM CHROMIUM 2014/03/26 23:32:04 nit: Looks like we could avoid some duplicate code
wolenetz 2014/03/27 18:01:48 Done.
471 DVLOG(2) << "AddBuffer() : Invalid negative duration: "
472 << buffer->duration().InSecondsF();
473 return false;
474 }
475
476 estimated_next_frame_duration_ = std::max(buffer->duration(),
477 estimated_next_frame_duration_);
408 buffers_.push_back(buffer); 478 buffers_.push_back(buffer);
409 return true; 479 return true;
410 } 480 }
411 481
482 void WebMClusterParser::Track::ApplyDurationDefaultOrEstimateIfNeeded() {
483 if (!last_added_buffer_missing_duration_)
484 return;
485
486 if (default_duration_ != kNoTimestamp()) {
487 DVLOG(3) << __FUNCTION__ << " : using TrackEntry DefaultDuration";
488 last_added_buffer_missing_duration_->set_duration(default_duration_);
489 } else if (estimated_next_frame_duration_ != kNoTimestamp()) {
490 DVLOG(3) << __FUNCTION__ << " : using estimated duration";
491 last_added_buffer_missing_duration_->set_duration(
492 estimated_next_frame_duration_);
493 } else {
494 DVLOG(3) << __FUNCTION__ << " : using hardcoded default duration";
495 last_added_buffer_missing_duration_->set_duration(
496 base::TimeDelta::FromMilliseconds(kDefaultBufferDurationInMs));
497 }
498
499 DVLOG(2) << "ApplyDurationDefaultOrEstimateIfNeeded() : new dur : "
500 << " ts "
501 << last_added_buffer_missing_duration_->timestamp().InSecondsF()
502 << " dur "
503 << last_added_buffer_missing_duration_->duration().InSecondsF()
504 << " kf " << last_added_buffer_missing_duration_->IsKeyframe()
505 << " size " << last_added_buffer_missing_duration_->data_size();
506 buffers_.push_back(last_added_buffer_missing_duration_);
507 last_added_buffer_missing_duration_ = NULL;
508 }
509
412 void WebMClusterParser::Track::Reset() { 510 void WebMClusterParser::Track::Reset() {
511 // Note that |estimated_next_frame_duration_| is not reset, so it can be
512 // reused on subsequent buffers added to this instance.
413 buffers_.clear(); 513 buffers_.clear();
414 } 514 }
415 515
516 void WebMClusterParser::Track::Flush() {
517 Reset();
518 last_added_buffer_missing_duration_ = NULL;
519 }
520
416 bool WebMClusterParser::Track::IsKeyframe(const uint8* data, int size) const { 521 bool WebMClusterParser::Track::IsKeyframe(const uint8* data, int size) const {
417 // For now, assume that all blocks are keyframes for datatypes other than 522 // For now, assume that all blocks are keyframes for datatypes other than
418 // video. This is a valid assumption for Vorbis, WebVTT, & Opus. 523 // video. This is a valid assumption for Vorbis, WebVTT, & Opus.
419 if (!is_video_) 524 if (!is_video_)
420 return true; 525 return true;
421 526
422 // Make sure the block is big enough for the minimal keyframe header size. 527 // Make sure the block is big enough for the minimal keyframe header size.
423 if (size < 7) 528 if (size < 7)
424 return false; 529 return false;
425 530
(...skipping 23 matching lines...) Expand all
449 WebMClusterParser::FindTextTrack(int track_num) { 554 WebMClusterParser::FindTextTrack(int track_num) {
450 const TextTrackMap::iterator it = text_track_map_.find(track_num); 555 const TextTrackMap::iterator it = text_track_map_.find(track_num);
451 556
452 if (it == text_track_map_.end()) 557 if (it == text_track_map_.end())
453 return NULL; 558 return NULL;
454 559
455 return &it->second; 560 return &it->second;
456 } 561 }
457 562
458 } // namespace media 563 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698