Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(171)

Side by Side Diff: media/formats/mp2t/es_adapter_video.cc

Issue 364823008: Mpeg2TS - estimate duration for video frames. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Additional cleanup. Created 6 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
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
12 namespace media {
13 namespace mp2t {
14
15 // Arbitrary decision about the frame duration when there is no previous
16 // hint about what could be the frame duration.
17 static base::TimeDelta kDefaultFrameDuration(
18 base::TimeDelta::FromMilliseconds(40));
19
20 // To calculate the frame duration, we make an assumption
21 // that the timestamp of the next frame in presentation order
22 // is no further than 5 frames away in decode order.
23 // TODO(damienv): the previous assumption should cover most of the practical
24 // cases. However, the right way to calculate the frame duration would be
25 // to emulate the H264 dpb bumping process.
26 static const size_t kHistorySize = 5;
27
28 EsAdapterVideo::EsAdapterVideo(
29 const NewVideoConfigCB& new_video_config_cb,
30 const EmitBufferCB& emit_buffer_cb)
31 : new_video_config_cb_(new_video_config_cb),
32 emit_buffer_cb_(emit_buffer_cb),
33 has_valid_config_(false),
34 has_valid_frame_(false),
35 last_frame_duration_(kDefaultFrameDuration),
36 buffer_index_(0) {
37 }
38
39 EsAdapterVideo::~EsAdapterVideo() {
40 }
41
42 void EsAdapterVideo::Flush() {
43 ProcessPendingBuffers(true);
44 }
45
46 void EsAdapterVideo::OnConfigChanged(
47 const VideoDecoderConfig& video_decoder_config) {
48 config_list_.push_back(
49 ConfigEntry(buffer_index_ + buffer_list_.size(), video_decoder_config));
50 has_valid_config_ = true;
51 ProcessPendingBuffers(false);
52 }
53
54 void EsAdapterVideo::OnNewBuffer(
55 const scoped_refptr<StreamParserBuffer>& stream_parser_buffer) {
56 // Discard the incoming frame:
57 // - if it is not associated with any config,
58 // - or if only non-key frames have been added to a new segment.
59 if (!has_valid_config_ ||
60 (!has_valid_frame_ && !stream_parser_buffer->IsKeyframe())) {
61 if (discarded_frames_dts_.empty() ||
62 discarded_frames_min_pts_ > stream_parser_buffer->timestamp()) {
63 discarded_frames_min_pts_ = stream_parser_buffer->timestamp();
64 }
65 discarded_frames_dts_.push_back(
66 stream_parser_buffer->GetDecodeTimestamp());
67 return;
68 }
69
70 has_valid_frame_ = true;
71
72 if (!discarded_frames_dts_.empty())
73 ReplaceDiscardedFrames(stream_parser_buffer);
74
75 buffer_list_.push_back(stream_parser_buffer);
76 ProcessPendingBuffers(false);
77 }
78
79 void EsAdapterVideo::ProcessPendingBuffers(bool flush) {
80 DCHECK(has_valid_config_);
81
82 while (!buffer_list_.empty() &&
83 (flush || buffer_list_.size() > kHistorySize)) {
84 // Signal a config change, just before emitting the corresponding frame.
85 if (!config_list_.empty() && config_list_.front().first == buffer_index_) {
86 new_video_config_cb_.Run(config_list_.front().second);
87 config_list_.pop_front();
88 }
89
90 scoped_refptr<StreamParserBuffer> buffer = buffer_list_.front();
91 buffer_list_.pop_front();
92 buffer_index_++;
93
94 if (buffer->duration() == kNoTimestamp()) {
95 base::TimeDelta next_frame_pts = GetNextFramePts(buffer->timestamp());
96 if (next_frame_pts == kNoTimestamp()) {
97 // This can happen when emitting the very last buffer
98 // or if the stream do not meet the assumption behind |kHistorySize|.
99 buffer->set_duration(last_frame_duration_);
100 } else {
101 buffer->set_duration(next_frame_pts - buffer->timestamp());
102 }
103 }
104
105 emitted_pts_.push_back(buffer->timestamp());
106 if (emitted_pts_.size() > kHistorySize)
107 emitted_pts_.pop_front();
108
109 last_frame_duration_ = buffer->duration();
110 emit_buffer_cb_.Run(buffer);
111 }
112 }
113
114 base::TimeDelta EsAdapterVideo::GetNextFramePts(base::TimeDelta current_pts) {
115 base::TimeDelta next_pts = kNoTimestamp();
116
117 // Consider the timestamps of future frames (in decode order).
118 for (BufferQueue::const_iterator it = buffer_list_.begin();
acolwell GONE FROM CHROMIUM 2014/07/09 20:01:10 nit: Might want to call out B-frames here since pe
damienv1 2014/07/10 16:00:53 Done.
119 it != buffer_list_.end(); ++it) {
120 if ((*it)->timestamp() < current_pts)
121 continue;
122 if (next_pts == kNoTimestamp() || next_pts > (*it)->timestamp())
123 next_pts = (*it)->timestamp();
124 }
125
126 // Consider the timestamps of previous frames (in decode order).
127 for (std::list<base::TimeDelta>::const_iterator it = emitted_pts_.begin();
acolwell GONE FROM CHROMIUM 2014/07/09 20:01:10 This is for the duration of the last B frame in IP
damienv1 2014/07/10 16:00:53 Done.
128 it != emitted_pts_.end(); ++it) {
129 if (*it < current_pts)
130 continue;
131 if (next_pts == kNoTimestamp() || next_pts > *it)
132 next_pts = *it;
133 }
134
135 return next_pts;
136 }
137
138 void EsAdapterVideo::ReplaceDiscardedFrames(
139 const scoped_refptr<StreamParserBuffer>& stream_parser_buffer) {
140 DCHECK(!discarded_frames_dts_.empty());
141 DCHECK(stream_parser_buffer->IsKeyframe());
142
143 // PTS is interpolated between the min PTS of discarded frames
144 // and the PTS of the first valid buffer.
145 base::TimeDelta pts = discarded_frames_min_pts_;
146 base::TimeDelta pts_delta =
147 (stream_parser_buffer->timestamp() - pts) / discarded_frames_dts_.size();
148
149 while (!discarded_frames_dts_.empty()) {
150 scoped_refptr<StreamParserBuffer> frame =
151 StreamParserBuffer::CopyFrom(
152 stream_parser_buffer->data(),
153 stream_parser_buffer->data_size(),
154 stream_parser_buffer->IsKeyframe(),
155 stream_parser_buffer->type(),
156 stream_parser_buffer->track_id());
157 frame->SetDecodeTimestamp(discarded_frames_dts_.front());
158 frame->set_timestamp(pts);
159 frame->set_duration(pts_delta);
160 buffer_list_.push_back(frame);
161 pts += pts_delta;
162 discarded_frames_dts_.pop_front();
163 }
164 }
165
166 } // namespace mp2t
167 } // namespace media
168
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698