15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "media/base/stream_parser.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "media/base/buffers.h"
85d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "media/base/stream_parser_buffer.h"
95d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace media {
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
125c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo LiuStreamParser::InitParameters::InitParameters(base::TimeDelta duration)
135c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    : duration(duration),
145c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      auto_update_timestamp_offset(false),
155c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      liveness(Demuxer::LIVENESS_UNKNOWN) {
165c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}
175c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)StreamParser::StreamParser() {}
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)StreamParser::~StreamParser() {}
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)static bool MergeBufferQueuesInternal(
235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const std::vector<const StreamParser::BufferQueue*>& buffer_queues,
245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    StreamParser::BufferQueue* merged_buffers) {
255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Instead of std::merge usage, this method implements a custom merge because:
265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // 1) |buffer_queues| may contain N queues,
275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // 2) we must detect and return false if any of the queues in |buffer_queues|
285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // is unsorted, and
295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // 3) we must detect and return false if any of the buffers in |buffer_queues|
305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // has a decode timestamp prior to the last, if any, buffer in
315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // |merged_buffers|.
325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // TODO(wolenetz/acolwell): Refactor stream parsers to eliminate need for
335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // this large grain merge. See http://crbug.com/338484.
345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Done if no inputs to merge.
365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (buffer_queues.empty())
375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return true;
385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Build a vector of iterators, one for each input, to traverse inputs.
405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // The union of these iterators points to the set of candidate buffers
415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // for being appended to |merged_buffers|.
425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  size_t num_itrs = buffer_queues.size();
435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::vector<StreamParser::BufferQueue::const_iterator> itrs(num_itrs);
445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (size_t i = 0; i < num_itrs; ++i)
455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    itrs[i] = buffer_queues[i]->begin();
465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // |last_decode_timestamp| tracks the lower bound, if any, that all candidate
485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // buffers must not be less than. If |merged_buffers| already has buffers,
495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // initialize |last_decode_timestamp| to the decode timestamp of the last
505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // buffer in it.
516e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  DecodeTimestamp last_decode_timestamp = kNoDecodeTimestamp();
525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!merged_buffers->empty())
535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    last_decode_timestamp = merged_buffers->back()->GetDecodeTimestamp();
545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Repeatedly select and append the next buffer from the candidate buffers
565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // until either:
575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // 1) returning false, to indicate detection of decreasing DTS in some queue,
585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  //    when a candidate buffer has decode timestamp below
595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  //    |last_decode_timestamp|, which means either an input buffer wasn't
605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  //    sorted correctly or had a buffer with decode timestamp below the last
615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  //    buffer, if any, in |merged_buffers|, or
625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // 2) returning true when all buffers have been merged successfully;
635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  //    equivalently, when all of the iterators in |itrs| have reached the end
645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  //    of their respective queue from |buffer_queues|.
655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // TODO(wolenetz/acolwell): Ideally, we would use a heap to store the head of
665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // all queues and pop the head with lowest decode timestamp in log(N) time.
675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // However, N will typically be small and usage of this implementation is
685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // meant to be short-term. See http://crbug.com/338484.
695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  while (true) {
705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // Tracks which queue's iterator is pointing to the candidate buffer to
715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // append next, or -1 if no candidate buffers found. This indexes |itrs|.
725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    int index_of_queue_with_next_decode_timestamp = -1;
736e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    DecodeTimestamp next_decode_timestamp = kNoDecodeTimestamp();
745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // Scan each of the iterators for |buffer_queues| to find the candidate
765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // buffer, if any, that has the lowest decode timestamp.
775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    for (size_t i = 0; i < num_itrs; ++i) {
785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      if (itrs[i] == buffer_queues[i]->end())
795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        continue;
805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      // Extract the candidate buffer's decode timestamp.
826e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      DecodeTimestamp ts = (*itrs[i])->GetDecodeTimestamp();
835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
846e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      if (last_decode_timestamp != kNoDecodeTimestamp() &&
855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          ts < last_decode_timestamp)
865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        return false;
875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      if (ts < next_decode_timestamp ||
896e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)          next_decode_timestamp == kNoDecodeTimestamp()) {
905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        // Remember the decode timestamp and queue iterator index for this
915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        // potentially winning candidate buffer.
925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        next_decode_timestamp = ts;
935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        index_of_queue_with_next_decode_timestamp = i;
945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      }
955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // All done if no further candidate buffers exist.
985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (index_of_queue_with_next_decode_timestamp == -1)
995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return true;
1005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // Otherwise, append the winning candidate buffer to |merged_buffers|,
1025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // remember its decode timestamp as |last_decode_timestamp| now that it is
1035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // the last buffer in |merged_buffers|, advance the corresponding
1045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // input BufferQueue iterator, and continue.
1055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    scoped_refptr<StreamParserBuffer> buffer =
1065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        *itrs[index_of_queue_with_next_decode_timestamp];
1075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    last_decode_timestamp = buffer->GetDecodeTimestamp();
1085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    merged_buffers->push_back(buffer);
1095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    ++itrs[index_of_queue_with_next_decode_timestamp];
1105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
1115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool MergeBufferQueues(const StreamParser::BufferQueue& audio_buffers,
1145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                       const StreamParser::BufferQueue& video_buffers,
1155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                       const StreamParser::TextBufferQueueMap& text_buffers,
1165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                       StreamParser::BufferQueue* merged_buffers) {
1175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(merged_buffers);
1185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Prepare vector containing pointers to any provided non-empty buffer queues.
1205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::vector<const StreamParser::BufferQueue*> buffer_queues;
1215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!audio_buffers.empty())
1225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    buffer_queues.push_back(&audio_buffers);
1235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!video_buffers.empty())
1245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    buffer_queues.push_back(&video_buffers);
1255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (StreamParser::TextBufferQueueMap::const_iterator map_itr =
1265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)           text_buffers.begin();
1275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)       map_itr != text_buffers.end();
1285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)       map_itr++) {
1295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (!map_itr->second.empty())
1305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      buffer_queues.push_back(&(map_itr->second));
1315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
1325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Do the merge.
1345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return MergeBufferQueuesInternal(buffer_queues, merged_buffers);
1355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace media
138