1// Copyright 2014 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/formats/mp2t/es_adapter_video.h"
6
7#include "media/base/buffers.h"
8#include "media/base/stream_parser_buffer.h"
9#include "media/base/video_decoder_config.h"
10#include "media/formats/mp2t/mp2t_common.h"
11
12namespace media {
13namespace mp2t {
14
15// Arbitrary decision about the frame duration when there is no previous
16// hint about what could be the frame duration.
17static const int kDefaultFrameDurationMs = 40;
18
19// To calculate the frame duration, we make an assumption
20// that the timestamp of the next frame in presentation order
21// is no further than 5 frames away in decode order.
22// TODO(damienv): the previous assumption should cover most of the practical
23// cases. However, the right way to calculate the frame duration would be
24// to emulate the H264 dpb bumping process.
25static const size_t kHistorySize = 5;
26
27EsAdapterVideo::EsAdapterVideo(
28    const NewVideoConfigCB& new_video_config_cb,
29    const EmitBufferCB& emit_buffer_cb)
30    : new_video_config_cb_(new_video_config_cb),
31      emit_buffer_cb_(emit_buffer_cb),
32      has_valid_config_(false),
33      has_valid_frame_(false),
34      last_frame_duration_(
35          base::TimeDelta::FromMilliseconds(kDefaultFrameDurationMs)),
36      buffer_index_(0) {
37}
38
39EsAdapterVideo::~EsAdapterVideo() {
40}
41
42void EsAdapterVideo::Flush() {
43  ProcessPendingBuffers(true);
44}
45
46void EsAdapterVideo::Reset() {
47  has_valid_config_ = false;
48  has_valid_frame_ = false;
49
50  last_frame_duration_ =
51      base::TimeDelta::FromMilliseconds(kDefaultFrameDurationMs);
52
53  config_list_.clear();
54  buffer_index_ = 0;
55  buffer_list_.clear();
56  emitted_pts_.clear();
57
58  discarded_frames_min_pts_ = base::TimeDelta();
59  discarded_frames_dts_.clear();
60}
61
62void EsAdapterVideo::OnConfigChanged(
63    const VideoDecoderConfig& video_decoder_config) {
64  config_list_.push_back(
65      ConfigEntry(buffer_index_ + buffer_list_.size(), video_decoder_config));
66  has_valid_config_ = true;
67  ProcessPendingBuffers(false);
68}
69
70void EsAdapterVideo::OnNewBuffer(
71    const scoped_refptr<StreamParserBuffer>& stream_parser_buffer) {
72  // Discard the incoming frame:
73  // - if it is not associated with any config,
74  // - or if only non-key frames have been added to a new segment.
75  if (!has_valid_config_ ||
76      (!has_valid_frame_ && !stream_parser_buffer->IsKeyframe())) {
77    if (discarded_frames_dts_.empty() ||
78        discarded_frames_min_pts_ > stream_parser_buffer->timestamp()) {
79      discarded_frames_min_pts_ = stream_parser_buffer->timestamp();
80    }
81    discarded_frames_dts_.push_back(
82        stream_parser_buffer->GetDecodeTimestamp());
83    return;
84  }
85
86  has_valid_frame_ = true;
87
88  if (!discarded_frames_dts_.empty())
89    ReplaceDiscardedFrames(stream_parser_buffer);
90
91  buffer_list_.push_back(stream_parser_buffer);
92  ProcessPendingBuffers(false);
93}
94
95void EsAdapterVideo::ProcessPendingBuffers(bool flush) {
96  DCHECK(has_valid_config_);
97
98  while (!buffer_list_.empty() &&
99         (flush || buffer_list_.size() > kHistorySize)) {
100    // Signal a config change, just before emitting the corresponding frame.
101    if (!config_list_.empty() && config_list_.front().first == buffer_index_) {
102      new_video_config_cb_.Run(config_list_.front().second);
103      config_list_.pop_front();
104    }
105
106    scoped_refptr<StreamParserBuffer> buffer = buffer_list_.front();
107    buffer_list_.pop_front();
108    buffer_index_++;
109
110    if (buffer->duration() == kNoTimestamp()) {
111      base::TimeDelta next_frame_pts = GetNextFramePts(buffer->timestamp());
112      if (next_frame_pts == kNoTimestamp()) {
113        // This can happen when emitting the very last buffer
114        // or if the stream do not meet the assumption behind |kHistorySize|.
115        DVLOG(LOG_LEVEL_ES) << "Using last frame duration: "
116                            << last_frame_duration_.InMilliseconds();
117        buffer->set_duration(last_frame_duration_);
118      } else {
119        base::TimeDelta duration = next_frame_pts - buffer->timestamp();
120        DVLOG(LOG_LEVEL_ES) << "Frame duration: " << duration.InMilliseconds();
121        buffer->set_duration(duration);
122      }
123    }
124
125    emitted_pts_.push_back(buffer->timestamp());
126    if (emitted_pts_.size() > kHistorySize)
127      emitted_pts_.pop_front();
128
129    last_frame_duration_ = buffer->duration();
130    emit_buffer_cb_.Run(buffer);
131  }
132}
133
134base::TimeDelta EsAdapterVideo::GetNextFramePts(base::TimeDelta current_pts) {
135  base::TimeDelta next_pts = kNoTimestamp();
136
137  // Consider the timestamps of future frames (in decode order).
138  // Note: the next frame is not enough when the GOP includes some B frames.
139  for (BufferQueue::const_iterator it = buffer_list_.begin();
140       it != buffer_list_.end(); ++it) {
141    if ((*it)->timestamp() < current_pts)
142      continue;
143    if (next_pts == kNoTimestamp() || next_pts > (*it)->timestamp())
144      next_pts = (*it)->timestamp();
145  }
146
147  // Consider the timestamps of previous frames (in decode order).
148  // In a simple GOP structure with B frames, the frame next to the last B
149  // frame (in presentation order) is located before in decode order.
150  for (std::list<base::TimeDelta>::const_iterator it = emitted_pts_.begin();
151       it != emitted_pts_.end(); ++it) {
152    if (*it < current_pts)
153      continue;
154    if (next_pts == kNoTimestamp() || next_pts > *it)
155      next_pts = *it;
156  }
157
158  return next_pts;
159}
160
161void EsAdapterVideo::ReplaceDiscardedFrames(
162    const scoped_refptr<StreamParserBuffer>& stream_parser_buffer) {
163  DCHECK(!discarded_frames_dts_.empty());
164  DCHECK(stream_parser_buffer->IsKeyframe());
165
166  // PTS is interpolated between the min PTS of discarded frames
167  // and the PTS of the first valid buffer.
168  base::TimeDelta pts = discarded_frames_min_pts_;
169  base::TimeDelta pts_delta =
170      (stream_parser_buffer->timestamp() - pts) / discarded_frames_dts_.size();
171
172  while (!discarded_frames_dts_.empty()) {
173    scoped_refptr<StreamParserBuffer> frame =
174        StreamParserBuffer::CopyFrom(
175            stream_parser_buffer->data(),
176            stream_parser_buffer->data_size(),
177            stream_parser_buffer->IsKeyframe(),
178            stream_parser_buffer->type(),
179            stream_parser_buffer->track_id());
180    frame->SetDecodeTimestamp(discarded_frames_dts_.front());
181    frame->set_timestamp(pts);
182    frame->set_duration(pts_delta);
183    buffer_list_.push_back(frame);
184    pts += pts_delta;
185    discarded_frames_dts_.pop_front();
186  }
187}
188
189}  // namespace mp2t
190}  // namespace media
191