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