Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / media / base / stream_parser.cc
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.
4
5 #include "media/base/stream_parser.h"
6
7 #include "media/base/buffers.h"
8 #include "media/base/stream_parser_buffer.h"
9
10 namespace media {
11
12 StreamParser::InitParameters::InitParameters(base::TimeDelta duration)
13     : duration(duration),
14       auto_update_timestamp_offset(false),
15       liveness(Demuxer::LIVENESS_UNKNOWN) {
16 }
17
18 StreamParser::StreamParser() {}
19
20 StreamParser::~StreamParser() {}
21
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.
34
35   // Done if no inputs to merge.
36   if (buffer_queues.empty())
37     return true;
38
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();
46
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   base::TimeDelta last_decode_timestamp = kNoTimestamp();
52   if (!merged_buffers->empty())
53     last_decode_timestamp = merged_buffers->back()->GetDecodeTimestamp();
54
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     base::TimeDelta next_decode_timestamp = kNoTimestamp();
74
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;
80
81       // Extract the candidate buffer's decode timestamp.
82       base::TimeDelta ts = (*itrs[i])->GetDecodeTimestamp();
83
84       if (last_decode_timestamp != kNoTimestamp() &&
85           ts < last_decode_timestamp)
86         return false;
87
88       if (ts < next_decode_timestamp ||
89           next_decode_timestamp == kNoTimestamp()) {
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;
94       }
95     }
96
97     // All done if no further candidate buffers exist.
98     if (index_of_queue_with_next_decode_timestamp == -1)
99       return true;
100
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];
110   }
111 }
112
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);
118
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));
131   }
132
133   // Do the merge.
134   return MergeBufferQueuesInternal(buffer_queues, merged_buffers);
135 }
136
137 }  // namespace media