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

Side by Side Diff: media/mpeg2/mpeg2ts_stream_parser.cc

Issue 23566013: Mpeg2 TS stream parser for media source. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 7 years, 3 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
OLDNEW
(Empty)
1 // Copyright (c) 2013 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/mpeg2/mpeg2ts_stream_parser.h"
6
7 #include "base/bind.h"
8 #include "base/memory/scoped_ptr.h"
9 #include "media/base/audio_decoder_config.h"
10 #include "media/base/stream_parser_buffer.h"
11 #include "media/base/video_decoder_config.h"
12 #include "media/mpeg2/es_parser.h"
13 #include "media/mpeg2/es_parser_adts.h"
14 #include "media/mpeg2/es_parser_h264.h"
15 #include "media/mpeg2/mpeg2ts_common.h"
16 #include "media/mpeg2/mpeg2ts_pat.h"
17 #include "media/mpeg2/mpeg2ts_pes.h"
18 #include "media/mpeg2/mpeg2ts_pmt.h"
19 #include "media/mpeg2/mpeg2ts_section_parser.h"
20 #include "media/mpeg2/ts_packet.h"
21
22 namespace {
23
24 enum StreamType {
acolwell GONE FROM CHROMIUM 2013/08/29 20:44:24 nit: Please add spec reference for these magic num
damienv1 2013/09/04 01:37:13 Done.
25 kStreamTypeMpeg1Audio = 0x3,
26 kStreamTypeAAC = 0xf,
27 kStreamTypeAVC = 0x1b,
28 };
29
30 }
31
32 namespace media {
33 namespace mpeg2ts {
34
35 class PidState {
36 public:
37 int pid;
38 int continuity_counter;
39 scoped_ptr<Mpeg2TsSectionParser> section_parser;
40 };
41
42 Mpeg2TsStreamParser::Mpeg2TsStreamParser()
43 : pids_deleter_(&pids_),
44 selected_pmt_pid_(-1),
45 selected_audio_pid_(-1),
46 selected_video_pid_(-1),
47 is_initialized_(false),
48 segment_started_(false) {
49 LOG(INFO) << "Mpeg2TsStreamParser::Mpeg2TsStreamParser";
50 }
51
52 Mpeg2TsStreamParser::~Mpeg2TsStreamParser() {
53 }
54
55 void Mpeg2TsStreamParser::Init(
56 const InitCB& init_cb,
57 const NewConfigCB& config_cb,
58 const NewBuffersCB& new_buffers_cb,
59 const NewTextBuffersCB& text_cb,
60 const NeedKeyCB& need_key_cb,
61 const AddTextTrackCB& add_text_track_cb,
62 const NewMediaSegmentCB& new_segment_cb,
63 const base::Closure& end_of_segment_cb,
64 const LogCB& log_cb) {
65 DCHECK(init_cb_.is_null());
acolwell GONE FROM CHROMIUM 2013/08/29 20:44:24 nit:DCHECK(!is_initialized_)?
damienv1 2013/09/04 01:37:13 Done.
66 DCHECK(!init_cb.is_null());
67 DCHECK(!config_cb.is_null());
68 DCHECK(!new_buffers_cb.is_null());
69 DCHECK(!need_key_cb.is_null());
70 DCHECK(!end_of_segment_cb.is_null());
71
72 init_cb_ = init_cb;
73 config_cb_ = config_cb;
74 new_buffers_cb_ = new_buffers_cb;
75 need_key_cb_ = need_key_cb;
76 new_segment_cb_ = new_segment_cb;
77 end_of_segment_cb_ = end_of_segment_cb;
78 log_cb_ = log_cb;
79 }
80
81 void Mpeg2TsStreamParser::Flush() {
82 LOG(INFO) << "Mpeg2TsStreamParser::Flush()";
acolwell GONE FROM CHROMIUM 2013/08/29 20:44:24 nit: Use DVLOG everywhere instead of LOG. DVLOG(1)
damienv1 2013/09/04 01:37:13 Done.
83
84 // Flush the buffers and reset the pids.
85 for (std::map<int, PidState*>::iterator it = pids_.begin();
86 it != pids_.end(); ++it) {
87 LOG(INFO) << "Flushing PID: " << it->first;
88 PidState* pid_state = it->second;
89 pid_state->section_parser->Flush();
90 delete pid_state;
acolwell GONE FROM CHROMIUM 2013/08/29 20:44:24 If you are deleting the pid_state, why do you need
damienv1 2013/09/04 01:37:13 For video, there might be some pending buffers: a
91 }
92 pids_.clear();
93 EmitRemainingBuffers();
94
95 // End of the segment.
96 end_of_segment_cb_.Run();
acolwell GONE FROM CHROMIUM 2013/08/29 20:44:24 You shouldn't need to make this call. Are you runn
damienv1 2013/09/04 01:37:13 I was thinking it was needed. Checked without, it
97 segment_started_ = false;
98
99 // Remove any bytes left in the TS buffer.
100 // (i.e. any partial TS packet => less than 188 bytes).
101 ts_buffer_.clear();
102
103 // Remove the programs and the corresponding PIDs.
104 programs_.clear();
105
106 // Reset the selected PIDs.
107 selected_pmt_pid_ = -1;
108 selected_audio_pid_ = -1;
109 selected_video_pid_ = -1;
110
111 // Reset the audio and video configs.
112 audio_config_.reset();
113 video_config_.reset();
114
115 // TODO(damienv): What to do with the remaining audio/video buffer queues ?
116 // Note: there should not be any.
117 LOG_IF(WARNING, !audio_buffer_queue_.empty())
118 << "Flush: audio buffer queue not empty";
acolwell GONE FROM CHROMIUM 2013/08/29 20:44:24 nit: Make these DCHECKS and place them right after
damienv1 2013/09/04 01:37:13 Done.
119 LOG_IF(WARNING, !video_buffer_queue_.empty())
120 << "Flush: video buffer queue not empty";
121 audio_buffer_queue_.clear();
122 video_buffer_queue_.clear();
123 }
124
125 bool Mpeg2TsStreamParser::Parse(const uint8* buf, int size) {
126 LOG(INFO) << "Mpeg2TsStreamParser::Parse size=" << size;
127
128 // Add the data to the parser state.
129 int old_size = ts_buffer_.size();
130 ts_buffer_.resize(old_size + size);
acolwell GONE FROM CHROMIUM 2013/08/29 20:44:24 Convert ts_buffer_ to a media::ByteQueue so you do
damienv1 2013/09/04 01:37:13 Done.
131 memcpy(&ts_buffer_[old_size], buf, size);
132
133 int remaining_size = ts_buffer_.size();
134 int pos = 0;
135 while (remaining_size >= TsPacket::kPacketSize) {
136 // Synchronization.
137 int skipped_bytes = TsPacket::Sync(&ts_buffer_[pos], remaining_size);
138 if (skipped_bytes > 0) {
139 LOG(WARNING) << "Packet not aligned on a TS syncword:"
140 << " skipped_bytes=" << skipped_bytes;
141 pos += skipped_bytes;
142 remaining_size -= skipped_bytes;
143 continue;
144 }
145
146 // Parse the TS header.
147 scoped_ptr<TsPacket> ts_packet(
148 TsPacket::Parse(&ts_buffer_[pos], remaining_size));
149 if (!ts_packet.get()) {
acolwell GONE FROM CHROMIUM 2013/08/29 20:44:24 nit: You shouldn't need the get().
damienv1 2013/09/04 01:37:13 Done.
150 LOG(WARNING) << "Error: invalid TS packet";
151 pos += 1;
152 remaining_size -= 1;
acolwell GONE FROM CHROMIUM 2013/08/29 20:44:24 nit: You should probably put an upper bound on inv
damienv1 2013/09/04 01:37:13 Not sure if this is the right behavior yet. I woul
153 continue;
154 }
155
156 VLOG(LOG_LEVEL_TS)
acolwell GONE FROM CHROMIUM 2013/08/29 20:44:24 nit: Use DVLOG instead of VLOG here and everywhere
damienv1 2013/09/04 01:37:13 Done.
157 << "Processing PID=" << ts_packet->pid()
158 << " start_unit=" << ts_packet->payload_unit_start_indicator();
159
160 // Parse the section.
161 std::map<int, PidState*>::iterator it =
162 pids_.find(ts_packet->pid());
acolwell GONE FROM CHROMIUM 2013/08/29 20:44:24 nit: This should fit on the line above.
damienv1 2013/09/04 01:37:13 Done.
163 if (it == pids_.end() && ts_packet->pid() == 0) {
164 // Create the PAT state here if needed.
165 LOG(INFO) << "Create a new PAT parser";
166 PidState* pat_state = new PidState;
acolwell GONE FROM CHROMIUM 2013/08/29 20:44:24 nit: Use scoped_ptr<PidState> here and .release()
damienv1 2013/09/04 01:37:13 Done.
167 pat_state->section_parser.reset(
168 new Mpeg2TsPatParser(
169 base::Bind(&Mpeg2TsStreamParser::RegisterPmt,
170 base::Unretained(this))));
171 it = pids_.insert(
172 std::pair<int, PidState*>(ts_packet->pid(), pat_state)).first;
173 }
174
175 LOG_IF(WARNING, it == pids_.end()) << "Ignoring TS packet for pid: "
acolwell GONE FROM CHROMIUM 2013/08/29 20:44:24 nit: Just place an unconditional log statement in
damienv1 2013/09/04 01:37:13 Done.
176 << ts_packet->pid();
177 if (it != pids_.end()) {
178 it->second->section_parser->Parse(
179 ts_packet->payload_unit_start_indicator(),
180 &ts_buffer_[pos+ts_packet->GetPayloadOffset()],
181 ts_packet->GetPayloadSize());
182 }
183
184 // Go to the next packet.
185 pos += TsPacket::kPacketSize;
186 remaining_size -= TsPacket::kPacketSize;
187 }
188
189 // Check whether we are on a TS packet boundary.
acolwell GONE FROM CHROMIUM 2013/08/29 20:44:24 nit: This comment seems stale. It doesn't appear t
damienv1 2013/09/04 01:37:13 Done.
190 if (remaining_size > 0) {
191 memmove(&ts_buffer_[0], &ts_buffer_[pos], remaining_size);
192 ts_buffer_.resize(remaining_size);
193 } else {
194 ts_buffer_.resize(0);
195 }
196
197 EmitRemainingBuffers();
198
199 return true;
200 }
201
202 void Mpeg2TsStreamParser::RegisterPmt(int program_number, int pmt_pid) {
203 LOG(INFO) << "RegisterPmt:"
204 << " program_number=" << program_number
205 << " pmt_pid=" << pmt_pid;
206 std::map<int, PidState*>::iterator it = pids_.find(pmt_pid);
207 if (it != pids_.end()) {
acolwell GONE FROM CHROMIUM 2013/08/29 20:44:24 nit: remove {} here and on other 1 line statements
damienv1 2013/09/04 01:37:13 Done.
208 return;
209 }
210
211 if (selected_pmt_pid_ < 0) {
212 selected_pmt_pid_ = pmt_pid;
213 }
214 LOG_IF(WARNING, selected_pmt_pid_ != pmt_pid)
215 << "More than one program is defined";
acolwell GONE FROM CHROMIUM 2013/08/29 20:44:24 If more than one program is present then an error
damienv1 2013/09/04 01:37:13 When there are multiple programs, the Mpeg2 TS str
acolwell GONE FROM CHROMIUM 2013/09/05 18:29:09 Multiple programs are not allowed by the spec. Sig
216
217 // Create the PMT state here if needed.
218 LOG(INFO) << "Create a new PMT parser";
219 PidState* pmt_state = new PidState;
acolwell GONE FROM CHROMIUM 2013/08/29 20:44:24 nit: Use scoped_ptr<PidState> here and release() b
damienv1 2013/09/04 01:37:13 Done.
220 pmt_state->section_parser.reset(
221 new Mpeg2TsPmtParser(
222 base::Bind(&Mpeg2TsStreamParser::RegisterPes,
223 base::Unretained(this), pmt_pid)));
224 pids_.insert(std::pair<int, PidState*>(pmt_pid, pmt_state));
225 }
226
227 void Mpeg2TsStreamParser::RegisterPes(int pmt_pid,
228 int pes_pid,
229 int stream_type) {
230 // TODO(damienv): check there is no mismatch if the entry already exists.
231 LOG(INFO) << "RegisterPes:"
232 << " pes_pid=" << pes_pid
233 << " stream_type=" << std::hex << stream_type << std::dec;
234 std::map<int, PidState*>::iterator it = pids_.find(pes_pid);
235 if (it != pids_.end()) {
236 return;
237 }
238
239 // TODO(damienv): add other formats if needed.
240 bool is_audio = (stream_type == kStreamTypeAAC);
241 bool is_video = (stream_type == kStreamTypeAVC);
242
243 // Update the active tracks.
244 // Select the audio/video tracks with the lowest PID.
245 if (pmt_pid == selected_pmt_pid_) {
acolwell GONE FROM CHROMIUM 2013/08/29 20:44:24 nit: reverse condition and early return. We only r
damienv1 2013/09/04 01:37:13 Done. I changed the behavior of the automatic PID
246 if (is_audio &&
247 (selected_audio_pid_ < 0 || pes_pid < selected_audio_pid_)) {
acolwell GONE FROM CHROMIUM 2013/08/29 20:44:24 If the selected_xxx_pid_ changes downward, shouldn
damienv1 2013/09/04 01:37:13 I changed the behavior of the PidState. The PidSta
248 selected_audio_pid_ = pes_pid;
249 }
250 if (is_video &&
251 (selected_video_pid_ < 0 || pes_pid < selected_video_pid_)) {
252 selected_video_pid_ = pes_pid;
253 }
254 }
255
256 // Create a stream parser corresponding to the stream type.
257 scoped_ptr<EsParser> es_parser;
258 if (stream_type == kStreamTypeAVC) {
259 es_parser.reset(
260 new EsParserH264(
261 base::Bind(&Mpeg2TsStreamParser::OnVideoConfigChanged,
262 base::Unretained(this),
263 pes_pid),
264 base::Bind(&Mpeg2TsStreamParser::OnEmitVideoBuffer,
265 base::Unretained(this),
266 pes_pid)));
267 } else if (stream_type == kStreamTypeAAC) {
268 es_parser.reset(
269 new EsParserAdts(
270 base::Bind(&Mpeg2TsStreamParser::OnAudioConfigChanged,
271 base::Unretained(this),
272 pes_pid),
273 base::Bind(&Mpeg2TsStreamParser::OnEmitAudioBuffer,
274 base::Unretained(this),
275 pes_pid)));
276 }
acolwell GONE FROM CHROMIUM 2013/08/29 20:44:24 nit: else return. We don't need state for a strem_
damienv1 2013/09/04 01:37:13 Done.
277
278 // Create the PES state here.
279 LOG(INFO) << "Create a new PES state";
280 PidState* pes_state = new PidState;
acolwell GONE FROM CHROMIUM 2013/08/29 20:44:24 ditto. Perhaps an AddPidParser(pid, parser) helper
damienv1 2013/09/04 01:37:13 Code has been slightly refactored, and this helper
281 pes_state->section_parser.reset(
282 new Mpeg2TsPesParser(es_parser.release()));
283 pids_.insert(std::pair<int, PidState*>(pes_pid, pes_state));
284 }
285
286 void Mpeg2TsStreamParser::OnVideoConfigChanged(
287 int pes_pid,
288 const VideoDecoderConfig& video_decoder_config) {
289 DCHECK_GT(selected_video_pid_, 0);
290 LOG(INFO) << "OnVideoConfigChanged for pid=" << pes_pid;
291 if (pes_pid != selected_video_pid_) {
acolwell GONE FROM CHROMIUM 2013/08/29 20:44:24 nit: It seems like this should be a DCHECK_NE(pes_
damienv1 2013/09/04 01:37:13 Done.
292 return;
293 }
294
295 video_config_.reset(new VideoDecoderConfig());
296 *video_config_ = video_decoder_config;
297
298 OnAudioVideoConfigChanged();
299 }
300
301 void Mpeg2TsStreamParser::OnAudioConfigChanged(
302 int pes_pid,
303 const AudioDecoderConfig& audio_decoder_config) {
304 LOG(INFO) << "OnAudioConfigChanged";
305 if (pes_pid != selected_audio_pid_) {
306 return;
307 }
308
309 audio_config_.reset(new AudioDecoderConfig());
acolwell GONE FROM CHROMIUM 2013/08/29 20:44:24 nit: You shouldn't need a pointer here. You can ju
damienv1 2013/09/04 01:37:13 Done.
310 *audio_config_ = audio_decoder_config;
311
312 OnAudioVideoConfigChanged();
313 }
314
315 void Mpeg2TsStreamParser::OnAudioVideoConfigChanged() {
316 if (selected_audio_pid_ > 0 && !audio_config_) {
acolwell GONE FROM CHROMIUM 2013/08/29 20:44:24 It seems like this should be DCHECK(!audio_config_
damienv1 2013/09/04 01:37:13 I slightly changed the design so this comment shou
317 // Need to get the audio config as well before going any further.
318 return;
319 }
320 if (selected_video_pid_ > 0 && !video_config_) {
acolwell GONE FROM CHROMIUM 2013/08/29 20:44:24 ditto for video.
damienv1 2013/09/04 01:37:13 Ditto
321 // Need to get the video config as well before going any further.
322 return;
323 }
324
325 // Emit pending buffers only if already initialized.
326 // Buffers need to be emitted since these buffers do not necesseraly
acolwell GONE FROM CHROMIUM 2013/08/29 20:44:24 nit: s/ necesseraly/necessarily/
damienv1 2013/09/04 01:37:13 Not relevant anymore.
327 // have the same config.
328 if (is_initialized_) {
329 EmitRemainingBuffers();
330 }
331
332 if (selected_audio_pid_ > 0 && selected_video_pid_ > 0) {
acolwell GONE FROM CHROMIUM 2013/08/29 20:44:24 Removing the pointer usage would remove the need f
damienv1 2013/09/04 01:37:13 Done.
333 // Streams with both audio and video.
334 config_cb_.Run(*audio_config_, *video_config_);
335 } else if (selected_video_pid_ > 0) {
336 // Video stream only.
337 AudioDecoderConfig audio_config;
338 config_cb_.Run(audio_config, *video_config_);
339 } else if (selected_audio_pid_ > 0) {
340 // Audio stream only.
341 VideoDecoderConfig video_config;
342 config_cb_.Run(*audio_config_, video_config);
343 } else {
344 // At least one audio or video config should be set.
345 NOTREACHED();
acolwell GONE FROM CHROMIUM 2013/08/29 20:44:24 This should be a DCHECK(audio_config_.IsValidConfi
damienv1 2013/09/04 01:37:13 Removed.
346 }
347
348 if (!is_initialized_) {
acolwell GONE FROM CHROMIUM 2013/08/29 20:44:24 nit: reverse condition and return early.
damienv1 2013/09/04 01:37:13 I usually use "early return" for the exceptional f
acolwell GONE FROM CHROMIUM 2013/09/05 18:29:09 In this case, it isn't about exceptional flow. It
349 // For Mpeg2 TS we don't know the stream duration.
350 LOG(INFO) << "Mpeg2TS stream parser initialization done";
351 init_cb_.Run(true, base::TimeDelta());
acolwell GONE FROM CHROMIUM 2013/08/29 20:44:24 nit: kInfiniteDuration() should be used here inste
damienv1 2013/09/04 01:37:13 Done.
352 is_initialized_ = true;
353 }
354 }
355
356 void Mpeg2TsStreamParser::OnEmitAudioBuffer(
357 int pes_pid,
358 scoped_refptr<StreamParserBuffer> stream_parser_buffer) {
359 // Since ChunkDemuxer currently handle only one audio and one video,
acolwell GONE FROM CHROMIUM 2013/08/29 20:44:24 nit: Do not reference ChunkDemuxer here. "Since St
damienv1 2013/09/04 01:37:13 Done.
360 // the PID filter must be done inside the TS parser.
361 // Eventually, the PID filter will be done on the JS application side
362 // (using the HTML5 video element track selection).
363 if (pes_pid != selected_audio_pid_) {
acolwell GONE FROM CHROMIUM 2013/08/29 20:44:24 nit: It seems like this should be a DCHECK. We sho
damienv1 2013/09/04 01:37:13 Done.
364 return;
365 }
366
367 VLOG(LOG_LEVEL_ES)
368 << "OnEmitAudioBuffer: "
369 << " size="
370 << stream_parser_buffer->data_size()
371 << " dts="
372 << stream_parser_buffer->GetDecodeTimestamp().InMilliseconds()
373 << " pts="
374 << stream_parser_buffer->timestamp().InMilliseconds();
375 stream_parser_buffer->set_timestamp(
376 stream_parser_buffer->timestamp() - time_offset_);
377 stream_parser_buffer->SetDecodeTimestamp(
378 stream_parser_buffer->GetDecodeTimestamp() - time_offset_);
379 audio_buffer_queue_.push_back(stream_parser_buffer);
380 }
381
382 void Mpeg2TsStreamParser::OnEmitVideoBuffer(
383 int pes_pid,
384 scoped_refptr<StreamParserBuffer> stream_parser_buffer) {
385 // Since ChunkDemuxer currently handle only one audio and one video,
386 // the PID filter must be done inside the TS parser.
387 // Eventually, the PID filter will be done on the JS application side
388 // (using the HTML5 video element track selection).
389 if (pes_pid != selected_video_pid_) {
acolwell GONE FROM CHROMIUM 2013/08/29 20:44:24 ditto
damienv1 2013/09/04 01:37:13 Done.
390 return;
391 }
392
393 VLOG(LOG_LEVEL_ES)
394 << "OnEmitVideoBuffer"
395 << " size="
396 << stream_parser_buffer->data_size()
397 << " dts="
398 << stream_parser_buffer->GetDecodeTimestamp().InMilliseconds()
399 << " pts="
400 << stream_parser_buffer->timestamp().InMilliseconds()
401 << " IsKeyframe="
402 << stream_parser_buffer->IsKeyframe();
403 stream_parser_buffer->set_timestamp(
404 stream_parser_buffer->timestamp() - time_offset_);
405 stream_parser_buffer->SetDecodeTimestamp(
406 stream_parser_buffer->GetDecodeTimestamp() - time_offset_);
407 video_buffer_queue_.push_back(stream_parser_buffer);
408 }
409
410 void Mpeg2TsStreamParser::EmitRemainingBuffers() {
411 LOG(INFO) << "Mpeg2TsStreamParser::EmitRemainingBuffers";
412 // Segment cannot start with non key frames
413 // so replace non key frames with the 1st IDR.
414 // TODO(damienv): Non key frames could be replaced with a stuffing NAL
415 // as well, the most important is to avoid any gap between frames
416 // as MSE does not allow sparse video/audio buffers.
417 if (!segment_started_) {
418 StreamParser::BufferQueue::iterator it = video_buffer_queue_.begin();
acolwell GONE FROM CHROMIUM 2013/08/29 20:44:24 I don't think this is the right solution. The pars
damienv1 2013/09/04 01:37:13 I removed this section but I don't really see how
419 for ( ; it != video_buffer_queue_.end(); ++it) {
420 if ((*it)->IsKeyframe()) {
421 break;
422 }
423 }
424 if (it != video_buffer_queue_.end()) {
425 StreamParser::BufferQueue::iterator it2 = video_buffer_queue_.begin();
426 while (!(*it2)->IsKeyframe()) {
427 base::TimeDelta dts = (*it2)->GetDecodeTimestamp();
428 base::TimeDelta pts = (*it2)->timestamp();
429 scoped_refptr<StreamParserBuffer> stream_parser_buffer =
430 StreamParserBuffer::CopyFrom(
431 (*it)->data(), (*it)->data_size(), true);
432 stream_parser_buffer->set_timestamp(pts);
433 stream_parser_buffer->SetDecodeTimestamp(dts);
434 LOG(WARNING) << "Replacing frame with an IDR @ pts="
435 << pts.InMilliseconds();
436 *it2 = stream_parser_buffer;
437 ++it2;
438 }
439 } else {
440 LOG(WARNING) << "Only non key frames in the buffer queue";
441 // video_buffer_queue_.clear();
442 }
443 }
444
445 // Possibly start a segment if not done yet.
446 StartSegmentIfNeeded();
acolwell GONE FROM CHROMIUM 2013/08/29 20:44:24 nit: Just move this into the block below and inlin
damienv1 2013/09/04 01:37:13 Done.
447
448 // Finally, add the video and audio buffers.
449 if (!video_buffer_queue_.empty() ||
450 !audio_buffer_queue_.empty()) {
acolwell GONE FROM CHROMIUM 2013/08/29 20:44:24 nit: reverse condition and return early.
damienv1 2013/09/04 01:37:13 Done.
451 new_buffers_cb_.Run(audio_buffer_queue_, video_buffer_queue_);
452 audio_buffer_queue_.clear();
453 video_buffer_queue_.clear();
454 }
455 }
456
457 void Mpeg2TsStreamParser::StartSegmentIfNeeded() {
458 if (segment_started_) {
459 return;
460 }
461 if (video_buffer_queue_.empty() && audio_buffer_queue_.empty()) {
462 LOG(WARNING) << "Start a new segment but no buffer is available";
463 return;
464 }
465 LOG(INFO) << "Starting a new segment";
466 segment_started_ = true;
467 new_segment_cb_.Run();
468 }
469
470 } // namespace mpeg2ts
471 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698