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 |