Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 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/base/stream_parser.h" | 5 #include "media/base/stream_parser.h" |
| 6 | 6 |
| 7 #include "media/base/buffers.h" | |
| 8 #include "media/base/stream_parser_buffer.h" | |
| 9 | |
| 7 namespace media { | 10 namespace media { |
| 8 | 11 |
| 9 StreamParser::StreamParser() {} | 12 StreamParser::StreamParser() {} |
| 10 | 13 |
| 11 StreamParser::~StreamParser() {} | 14 StreamParser::~StreamParser() {} |
| 12 | 15 |
| 16 static bool MergeBufferQueuesInternal( | |
| 17 const std::vector<const StreamParser::BufferQueue*>& buffer_queues, | |
| 18 StreamParser::BufferQueue* merged_buffers) { | |
| 19 // Instead of std::merge usage, this method implements a custom merge because: | |
| 20 // 1) |buffer_queues| may contain N queues, | |
| 21 // 2) we must detect and return false if any of the queues in |buffer_queues| | |
| 22 // is unsorted, and | |
| 23 // 3) we must detect and return false if any of the buffers in |buffer_queues| | |
| 24 // has a decode timestamp prior to the last, if any, buffer in | |
| 25 // |merged_buffers|. | |
| 26 // TODO(wolenetz/acolwell): Refactor stream parsers to eliminate need for | |
| 27 // this large grain merge. See http://crbug.com/338484. | |
| 28 | |
| 29 // Done if no inputs to merge. | |
| 30 if (buffer_queues.empty()) | |
| 31 return true; | |
| 32 | |
| 33 // Build a vector of iterators, one for each input, to traverse inputs. | |
| 34 // The union of these iterators points to the set of candidate buffers | |
| 35 // for being appended to |merged_buffers|. | |
| 36 std::vector<StreamParser::BufferQueue::const_iterator> itrs; | |
|
xhwang
2014/02/06 00:36:32
Use vector::vector(size_type n) to avoid expanding
wolenetz
2014/02/06 23:56:03
Done.
| |
| 37 for (size_t i = 0; i < buffer_queues.size(); ++i) | |
| 38 itrs.push_back(buffer_queues[i]->begin()); | |
| 39 | |
| 40 // |last_decode_timestamp| tracks the lower bound, if any, that all candidate | |
| 41 // buffers must not be less than. If |merged_buffers| already has buffers, | |
| 42 // initialize |last_decode_timestamp| to the decode timestamp of the last | |
| 43 // buffer in it. | |
| 44 base::TimeDelta last_decode_timestamp = kNoTimestamp(); | |
| 45 if (!merged_buffers->empty()) | |
| 46 last_decode_timestamp = merged_buffers->back()->GetDecodeTimestamp(); | |
| 47 | |
| 48 // Repeatedly select and append the next buffer from the candidate buffers | |
| 49 // until either: | |
| 50 // 1) returning false, to indicate detection of decreasing DTS in some queue, | |
| 51 // when a candidate buffer has decode timestamp below | |
| 52 // |last_decode_timestamp|, which means either an input buffer wasn't | |
| 53 // sorted correctly or had a buffer with decode timestamp below the last | |
| 54 // buffer, if any, in |merged_buffers|, or | |
| 55 // 2) returning true when all buffers have been merged successfully; | |
| 56 // equivalently, when all of the iterators in |itrs| have reached the end | |
| 57 // of their respective queue from |buffer_queues|. | |
| 58 while (true) { | |
| 59 // Tracks which queue's iterator is pointing to the candidate buffer to | |
| 60 // append next, or -1 if no candidate buffers found. This indexes |itrs|. | |
| 61 int index_of_queue_with_next_decode_timestamp = -1; | |
| 62 base::TimeDelta next_decode_timestamp = kNoTimestamp(); | |
| 63 | |
| 64 // Scan each of the iterators for |buffer_queues| to find the candidate | |
| 65 // buffer, if any, that has the lowest decode timestamp. | |
| 66 for (size_t i = 0; i < buffer_queues.size(); ++i) { | |
| 67 if (itrs[i] != buffer_queues[i]->end()) { | |
|
xhwang
2014/02/06 00:36:32
if (itrs[i] == buffer_queues[i]->end())
continue
wolenetz
2014/02/06 23:56:03
Done.
| |
| 68 // Extract the candidate buffer's decode timestamp. | |
| 69 base::TimeDelta ts = (*itrs[i])->GetDecodeTimestamp(); | |
| 70 | |
| 71 if (last_decode_timestamp != kNoTimestamp() && | |
| 72 ts < last_decode_timestamp) | |
| 73 return false; | |
| 74 | |
| 75 if (ts < next_decode_timestamp || | |
| 76 next_decode_timestamp == kNoTimestamp()) { | |
| 77 // Remember the decode timestamp and queue iterator index for this | |
| 78 // potentially winning candidate buffer. | |
| 79 next_decode_timestamp = ts; | |
| 80 index_of_queue_with_next_decode_timestamp = i; | |
| 81 } | |
| 82 } | |
| 83 } | |
|
xhwang
2014/02/06 00:36:32
This block is inefficient. Ideally, we should use
wolenetz
2014/02/06 23:56:03
Done.
| |
| 84 | |
| 85 // All done if no further candidate buffers exist. | |
| 86 if (index_of_queue_with_next_decode_timestamp == -1) | |
| 87 return true; | |
| 88 | |
| 89 // Otherwise, append the winning candidate buffer to |merged_buffers|, | |
| 90 // remember its decode timestamp as |last_decode_timestamp| now that it is | |
| 91 // the last buffer in |merged_buffers|, advance the corresponding | |
| 92 // input BufferQueue iterator, and continue. | |
| 93 scoped_refptr<StreamParserBuffer> buffer = | |
| 94 *itrs[index_of_queue_with_next_decode_timestamp]; | |
| 95 last_decode_timestamp = buffer->GetDecodeTimestamp(); | |
| 96 merged_buffers->push_back(buffer); | |
| 97 ++itrs[index_of_queue_with_next_decode_timestamp]; | |
| 98 } | |
| 99 } | |
| 100 | |
| 101 bool MergeBufferQueues(const StreamParser::BufferQueue& audio_buffers, | |
| 102 const StreamParser::BufferQueue& video_buffers, | |
| 103 const StreamParser::TextBufferQueueMap& text_buffers, | |
| 104 StreamParser::BufferQueue* merged_buffers) { | |
| 105 DCHECK(merged_buffers); | |
| 106 | |
| 107 // Prepare vector containing pointers to any provided non-empty buffer queues. | |
| 108 std::vector<const StreamParser::BufferQueue*> buffer_queues; | |
| 109 if (!audio_buffers.empty()) | |
| 110 buffer_queues.push_back(&audio_buffers); | |
| 111 if (!video_buffers.empty()) | |
| 112 buffer_queues.push_back(&video_buffers); | |
| 113 for (StreamParser::TextBufferQueueMap::const_iterator map_itr = | |
| 114 text_buffers.begin(); | |
| 115 map_itr != text_buffers.end(); | |
| 116 map_itr++) { | |
| 117 if (!map_itr->second.empty()) | |
| 118 buffer_queues.push_back(&(map_itr->second)); | |
| 119 } | |
| 120 | |
| 121 // Do the merge. | |
| 122 return MergeBufferQueuesInternal(buffer_queues, merged_buffers); | |
| 123 } | |
| 124 | |
| 13 } // namespace media | 125 } // namespace media |
| OLD | NEW |