Linux: Depend on liberation-fonts package for RPMs.
[chromium-blink-merge.git] / media / base / stream_parser.cc
blobf63644a7755061ddca1800f73f0863b658fd97de
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"
9 namespace media {
11 StreamParser::InitParameters::InitParameters(base::TimeDelta duration)
12 : duration(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|
27 // is unsorted, and
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
30 // |merged_buffers|.
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())
36 return true;
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
49 // buffer in it.
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
55 // until either:
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.
68 while (true) {
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())
78 continue;
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)
85 return false;
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)
98 return true;
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();
127 map_itr++) {
128 if (!map_itr->second.empty())
129 buffer_queues.push_back(&(map_itr->second));
132 // Do the merge.
133 return MergeBufferQueuesInternal(buffer_queues, merged_buffers);
136 } // namespace media