Home | History | Annotate | Download | only in base
      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   DecodeTimestamp last_decode_timestamp = kNoDecodeTimestamp();
     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     DecodeTimestamp next_decode_timestamp = kNoDecodeTimestamp();
     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       DecodeTimestamp ts = (*itrs[i])->GetDecodeTimestamp();
     83 
     84       if (last_decode_timestamp != kNoDecodeTimestamp() &&
     85           ts < last_decode_timestamp)
     86         return false;
     87 
     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;
     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
    138