[Android] Add kkimlabs@ as enhanced bookmark ONWER.
[chromium-blink-merge.git] / media / base / stream_parser.cc
blob2412b8219fc4df639e84e6d1a9b9846dae9db619
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
3 // found in the LICENSE file.
5 #include "media/base/stream_parser.h"
7 #include "media/base/buffers.h"
8 #include "media/base/stream_parser_buffer.h"
10 namespace media {
12 StreamParser::InitParameters::InitParameters(base::TimeDelta duration)
13 : duration(duration),
14 auto_update_timestamp_offset(false),
15 liveness(DemuxerStream::LIVENESS_UNKNOWN) {
18 StreamParser::StreamParser() {}
20 StreamParser::~StreamParser() {}
22 static bool MergeBufferQueuesInternal(
23 const std::vector<const StreamParser::BufferQueue*>& buffer_queues,
24 StreamParser::BufferQueue* merged_buffers) {
25 // Instead of std::merge usage, this method implements a custom merge because:
26 // 1) |buffer_queues| may contain N queues,
27 // 2) we must detect and return false if any of the queues in |buffer_queues|
28 // is unsorted, and
29 // 3) we must detect and return false if any of the buffers in |buffer_queues|
30 // has a decode timestamp prior to the last, if any, buffer in
31 // |merged_buffers|.
32 // TODO(wolenetz/acolwell): Refactor stream parsers to eliminate need for
33 // this large grain merge. See http://crbug.com/338484.
35 // Done if no inputs to merge.
36 if (buffer_queues.empty())
37 return true;
39 // Build a vector of iterators, one for each input, to traverse inputs.
40 // The union of these iterators points to the set of candidate buffers
41 // for being appended to |merged_buffers|.
42 size_t num_itrs = buffer_queues.size();
43 std::vector<StreamParser::BufferQueue::const_iterator> itrs(num_itrs);
44 for (size_t i = 0; i < num_itrs; ++i)
45 itrs[i] = buffer_queues[i]->begin();
47 // |last_decode_timestamp| tracks the lower bound, if any, that all candidate
48 // buffers must not be less than. If |merged_buffers| already has buffers,
49 // initialize |last_decode_timestamp| to the decode timestamp of the last
50 // buffer in it.
51 DecodeTimestamp last_decode_timestamp = kNoDecodeTimestamp();
52 if (!merged_buffers->empty())
53 last_decode_timestamp = merged_buffers->back()->GetDecodeTimestamp();
55 // Repeatedly select and append the next buffer from the candidate buffers
56 // until either:
57 // 1) returning false, to indicate detection of decreasing DTS in some queue,
58 // when a candidate buffer has decode timestamp below
59 // |last_decode_timestamp|, which means either an input buffer wasn't
60 // sorted correctly or had a buffer with decode timestamp below the last
61 // buffer, if any, in |merged_buffers|, or
62 // 2) returning true when all buffers have been merged successfully;
63 // equivalently, when all of the iterators in |itrs| have reached the end
64 // of their respective queue from |buffer_queues|.
65 // TODO(wolenetz/acolwell): Ideally, we would use a heap to store the head of
66 // all queues and pop the head with lowest decode timestamp in log(N) time.
67 // However, N will typically be small and usage of this implementation is
68 // meant to be short-term. See http://crbug.com/338484.
69 while (true) {
70 // Tracks which queue's iterator is pointing to the candidate buffer to
71 // append next, or -1 if no candidate buffers found. This indexes |itrs|.
72 int index_of_queue_with_next_decode_timestamp = -1;
73 DecodeTimestamp next_decode_timestamp = kNoDecodeTimestamp();
75 // Scan each of the iterators for |buffer_queues| to find the candidate
76 // buffer, if any, that has the lowest decode timestamp.
77 for (size_t i = 0; i < num_itrs; ++i) {
78 if (itrs[i] == buffer_queues[i]->end())
79 continue;
81 // Extract the candidate buffer's decode timestamp.
82 DecodeTimestamp ts = (*itrs[i])->GetDecodeTimestamp();
84 if (last_decode_timestamp != kNoDecodeTimestamp() &&
85 ts < last_decode_timestamp)
86 return false;
88 if (ts < next_decode_timestamp ||
89 next_decode_timestamp == kNoDecodeTimestamp()) {
90 // Remember the decode timestamp and queue iterator index for this
91 // potentially winning candidate buffer.
92 next_decode_timestamp = ts;
93 index_of_queue_with_next_decode_timestamp = i;
97 // All done if no further candidate buffers exist.
98 if (index_of_queue_with_next_decode_timestamp == -1)
99 return true;
101 // Otherwise, append the winning candidate buffer to |merged_buffers|,
102 // remember its decode timestamp as |last_decode_timestamp| now that it is
103 // the last buffer in |merged_buffers|, advance the corresponding
104 // input BufferQueue iterator, and continue.
105 scoped_refptr<StreamParserBuffer> buffer =
106 *itrs[index_of_queue_with_next_decode_timestamp];
107 last_decode_timestamp = buffer->GetDecodeTimestamp();
108 merged_buffers->push_back(buffer);
109 ++itrs[index_of_queue_with_next_decode_timestamp];
113 bool MergeBufferQueues(const StreamParser::BufferQueue& audio_buffers,
114 const StreamParser::BufferQueue& video_buffers,
115 const StreamParser::TextBufferQueueMap& text_buffers,
116 StreamParser::BufferQueue* merged_buffers) {
117 DCHECK(merged_buffers);
119 // Prepare vector containing pointers to any provided non-empty buffer queues.
120 std::vector<const StreamParser::BufferQueue*> buffer_queues;
121 if (!audio_buffers.empty())
122 buffer_queues.push_back(&audio_buffers);
123 if (!video_buffers.empty())
124 buffer_queues.push_back(&video_buffers);
125 for (StreamParser::TextBufferQueueMap::const_iterator map_itr =
126 text_buffers.begin();
127 map_itr != text_buffers.end();
128 map_itr++) {
129 if (!map_itr->second.empty())
130 buffer_queues.push_back(&(map_itr->second));
133 // Do the merge.
134 return MergeBufferQueuesInternal(buffer_queues, merged_buffers);
137 } // namespace media