OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "media/formats/mp2t/mp2t_stream_parser.h" | 5 #include "media/formats/mp2t/mp2t_stream_parser.h" |
6 | 6 |
7 #include <memory> | 7 #include <memory> |
8 #include <utility> | 8 #include <utility> |
9 | 9 |
10 #include "base/bind.h" | 10 #include "base/bind.h" |
11 #include "base/callback_helpers.h" | 11 #include "base/callback_helpers.h" |
12 #include "base/stl_util.h" | |
13 #include "media/base/media_tracks.h" | 12 #include "media/base/media_tracks.h" |
14 #include "media/base/stream_parser_buffer.h" | 13 #include "media/base/stream_parser_buffer.h" |
15 #include "media/base/text_track_config.h" | 14 #include "media/base/text_track_config.h" |
16 #include "media/base/timestamp_constants.h" | 15 #include "media/base/timestamp_constants.h" |
17 #include "media/formats/mp2t/es_parser.h" | 16 #include "media/formats/mp2t/es_parser.h" |
18 #include "media/formats/mp2t/es_parser_adts.h" | 17 #include "media/formats/mp2t/es_parser_adts.h" |
19 #include "media/formats/mp2t/es_parser_h264.h" | 18 #include "media/formats/mp2t/es_parser_h264.h" |
20 #include "media/formats/mp2t/es_parser_mpeg1audio.h" | 19 #include "media/formats/mp2t/es_parser_mpeg1audio.h" |
21 #include "media/formats/mp2t/mp2t_common.h" | 20 #include "media/formats/mp2t/mp2t_common.h" |
22 #include "media/formats/mp2t/ts_packet.h" | 21 #include "media/formats/mp2t/ts_packet.h" |
(...skipping 15 matching lines...) Expand all Loading... |
38 class PidState { | 37 class PidState { |
39 public: | 38 public: |
40 enum PidType { | 39 enum PidType { |
41 kPidPat, | 40 kPidPat, |
42 kPidPmt, | 41 kPidPmt, |
43 kPidAudioPes, | 42 kPidAudioPes, |
44 kPidVideoPes, | 43 kPidVideoPes, |
45 }; | 44 }; |
46 | 45 |
47 PidState(int pid, | 46 PidState(int pid, |
48 PidType pid_tyoe, | 47 PidType pid_type, |
49 std::unique_ptr<TsSection> section_parser); | 48 std::unique_ptr<TsSection> section_parser); |
50 | 49 |
51 // Extract the content of the TS packet and parse it. | 50 // Extract the content of the TS packet and parse it. |
52 // Return true if successful. | 51 // Return true if successful. |
53 bool PushTsPacket(const TsPacket& ts_packet); | 52 bool PushTsPacket(const TsPacket& ts_packet); |
54 | 53 |
55 // Flush the PID state (possibly emitting some pending frames) | 54 // Flush the PID state (possibly emitting some pending frames) |
56 // and reset its state. | 55 // and reset its state. |
57 void Flush(); | 56 void Flush(); |
58 | 57 |
(...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
161 | 160 |
162 Mp2tStreamParser::Mp2tStreamParser(bool sbr_in_mimetype) | 161 Mp2tStreamParser::Mp2tStreamParser(bool sbr_in_mimetype) |
163 : sbr_in_mimetype_(sbr_in_mimetype), | 162 : sbr_in_mimetype_(sbr_in_mimetype), |
164 selected_audio_pid_(-1), | 163 selected_audio_pid_(-1), |
165 selected_video_pid_(-1), | 164 selected_video_pid_(-1), |
166 is_initialized_(false), | 165 is_initialized_(false), |
167 segment_started_(false) { | 166 segment_started_(false) { |
168 } | 167 } |
169 | 168 |
170 Mp2tStreamParser::~Mp2tStreamParser() { | 169 Mp2tStreamParser::~Mp2tStreamParser() { |
171 base::STLDeleteValues(&pids_); | |
172 } | 170 } |
173 | 171 |
174 void Mp2tStreamParser::Init( | 172 void Mp2tStreamParser::Init( |
175 const InitCB& init_cb, | 173 const InitCB& init_cb, |
176 const NewConfigCB& config_cb, | 174 const NewConfigCB& config_cb, |
177 const NewBuffersCB& new_buffers_cb, | 175 const NewBuffersCB& new_buffers_cb, |
178 bool /* ignore_text_tracks */, | 176 bool /* ignore_text_tracks */, |
179 const EncryptedMediaInitDataCB& encrypted_media_init_data_cb, | 177 const EncryptedMediaInitDataCB& encrypted_media_init_data_cb, |
180 const NewMediaSegmentCB& new_segment_cb, | 178 const NewMediaSegmentCB& new_segment_cb, |
181 const EndMediaSegmentCB& end_of_segment_cb, | 179 const EndMediaSegmentCB& end_of_segment_cb, |
(...skipping 13 matching lines...) Expand all Loading... |
195 encrypted_media_init_data_cb_ = encrypted_media_init_data_cb; | 193 encrypted_media_init_data_cb_ = encrypted_media_init_data_cb; |
196 new_segment_cb_ = new_segment_cb; | 194 new_segment_cb_ = new_segment_cb; |
197 end_of_segment_cb_ = end_of_segment_cb; | 195 end_of_segment_cb_ = end_of_segment_cb; |
198 media_log_ = media_log; | 196 media_log_ = media_log; |
199 } | 197 } |
200 | 198 |
201 void Mp2tStreamParser::Flush() { | 199 void Mp2tStreamParser::Flush() { |
202 DVLOG(1) << "Mp2tStreamParser::Flush"; | 200 DVLOG(1) << "Mp2tStreamParser::Flush"; |
203 | 201 |
204 // Flush the buffers and reset the pids. | 202 // Flush the buffers and reset the pids. |
205 for (std::map<int, PidState*>::iterator it = pids_.begin(); | 203 for (const auto& pid_pair : pids_) { |
206 it != pids_.end(); ++it) { | 204 DVLOG(1) << "Flushing PID: " << pid_pair.first; |
207 DVLOG(1) << "Flushing PID: " << it->first; | 205 pid_pair.second->Flush(); |
208 PidState* pid_state = it->second; | |
209 pid_state->Flush(); | |
210 delete pid_state; | |
211 } | 206 } |
212 pids_.clear(); | 207 pids_.clear(); |
213 | 208 |
214 // Flush is invoked from SourceBuffer.abort/SourceState::ResetParserState, and | 209 // Flush is invoked from SourceBuffer.abort/SourceState::ResetParserState, and |
215 // MSE spec prohibits emitting new configs in ResetParserState algorithm (see | 210 // MSE spec prohibits emitting new configs in ResetParserState algorithm (see |
216 // https://w3c.github.io/media-source/#sourcebuffer-reset-parser-state, | 211 // https://w3c.github.io/media-source/#sourcebuffer-reset-parser-state, |
217 // 3.5.2 Reset Parser State states that new frames might be processed only in | 212 // 3.5.2 Reset Parser State states that new frames might be processed only in |
218 // PARSING_MEDIA_SEGMENT and therefore doesn't allow emitting new configs, | 213 // PARSING_MEDIA_SEGMENT and therefore doesn't allow emitting new configs, |
219 // since that might need to run "init segment received" algorithm). | 214 // since that might need to run "init segment received" algorithm). |
220 // So before we emit remaining buffers here, we need to trim our buffer queue | 215 // So before we emit remaining buffers here, we need to trim our buffer queue |
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
277 if (!ts_packet) { | 272 if (!ts_packet) { |
278 DVLOG(1) << "Error: invalid TS packet"; | 273 DVLOG(1) << "Error: invalid TS packet"; |
279 ts_byte_queue_.Pop(1); | 274 ts_byte_queue_.Pop(1); |
280 continue; | 275 continue; |
281 } | 276 } |
282 DVLOG(LOG_LEVEL_TS) | 277 DVLOG(LOG_LEVEL_TS) |
283 << "Processing PID=" << ts_packet->pid() | 278 << "Processing PID=" << ts_packet->pid() |
284 << " start_unit=" << ts_packet->payload_unit_start_indicator(); | 279 << " start_unit=" << ts_packet->payload_unit_start_indicator(); |
285 | 280 |
286 // Parse the section. | 281 // Parse the section. |
287 std::map<int, PidState*>::iterator it = pids_.find(ts_packet->pid()); | 282 auto it = pids_.find(ts_packet->pid()); |
288 if (it == pids_.end() && | 283 if (it == pids_.end() && |
289 ts_packet->pid() == TsSection::kPidPat) { | 284 ts_packet->pid() == TsSection::kPidPat) { |
290 // Create the PAT state here if needed. | 285 // Create the PAT state here if needed. |
291 std::unique_ptr<TsSection> pat_section_parser(new TsSectionPat( | 286 std::unique_ptr<TsSection> pat_section_parser(new TsSectionPat( |
292 base::Bind(&Mp2tStreamParser::RegisterPmt, base::Unretained(this)))); | 287 base::Bind(&Mp2tStreamParser::RegisterPmt, base::Unretained(this)))); |
293 std::unique_ptr<PidState> pat_pid_state(new PidState( | 288 std::unique_ptr<PidState> pat_pid_state(new PidState( |
294 ts_packet->pid(), PidState::kPidPat, std::move(pat_section_parser))); | 289 ts_packet->pid(), PidState::kPidPat, std::move(pat_section_parser))); |
295 pat_pid_state->Enable(); | 290 pat_pid_state->Enable(); |
296 it = pids_.insert( | 291 it = pids_ |
297 std::pair<int, PidState*>(ts_packet->pid(), | 292 .insert( |
298 pat_pid_state.release())).first; | 293 std::make_pair(ts_packet->pid(), std::move(pat_pid_state))) |
| 294 .first; |
299 } | 295 } |
300 | 296 |
301 if (it != pids_.end()) { | 297 if (it != pids_.end()) { |
302 if (!it->second->PushTsPacket(*ts_packet)) | 298 if (!it->second->PushTsPacket(*ts_packet)) |
303 return false; | 299 return false; |
304 } else { | 300 } else { |
305 DVLOG(LOG_LEVEL_TS) << "Ignoring TS packet for pid: " << ts_packet->pid(); | 301 DVLOG(LOG_LEVEL_TS) << "Ignoring TS packet for pid: " << ts_packet->pid(); |
306 } | 302 } |
307 | 303 |
308 // Go to the next packet. | 304 // Go to the next packet. |
309 ts_byte_queue_.Pop(TsPacket::kPacketSize); | 305 ts_byte_queue_.Pop(TsPacket::kPacketSize); |
310 } | 306 } |
311 | 307 |
312 RCHECK(FinishInitializationIfNeeded()); | 308 RCHECK(FinishInitializationIfNeeded()); |
313 | 309 |
314 // Emit the A/V buffers that kept accumulating during TS parsing. | 310 // Emit the A/V buffers that kept accumulating during TS parsing. |
315 return EmitRemainingBuffers(); | 311 return EmitRemainingBuffers(); |
316 } | 312 } |
317 | 313 |
318 void Mp2tStreamParser::RegisterPmt(int program_number, int pmt_pid) { | 314 void Mp2tStreamParser::RegisterPmt(int program_number, int pmt_pid) { |
319 DVLOG(1) << "RegisterPmt:" | 315 DVLOG(1) << "RegisterPmt:" |
320 << " program_number=" << program_number | 316 << " program_number=" << program_number |
321 << " pmt_pid=" << pmt_pid; | 317 << " pmt_pid=" << pmt_pid; |
322 | 318 |
323 // Only one TS program is allowed. Ignore the incoming program map table, | 319 // Only one TS program is allowed. Ignore the incoming program map table, |
324 // if there is already one registered. | 320 // if there is already one registered. |
325 for (std::map<int, PidState*>::iterator it = pids_.begin(); | 321 for (const auto& pid_pair : pids_) { |
326 it != pids_.end(); ++it) { | 322 PidState* pid_state = pid_pair.second.get(); |
327 PidState* pid_state = it->second; | |
328 if (pid_state->pid_type() == PidState::kPidPmt) { | 323 if (pid_state->pid_type() == PidState::kPidPmt) { |
329 DVLOG_IF(1, pmt_pid != it->first) << "More than one program is defined"; | 324 DVLOG_IF(1, pmt_pid != pid_pair.first) |
| 325 << "More than one program is defined"; |
330 return; | 326 return; |
331 } | 327 } |
332 } | 328 } |
333 | 329 |
334 // Create the PMT state here if needed. | 330 // Create the PMT state here if needed. |
335 DVLOG(1) << "Create a new PMT parser"; | 331 DVLOG(1) << "Create a new PMT parser"; |
336 std::unique_ptr<TsSection> pmt_section_parser(new TsSectionPmt(base::Bind( | 332 std::unique_ptr<TsSection> pmt_section_parser(new TsSectionPmt(base::Bind( |
337 &Mp2tStreamParser::RegisterPes, base::Unretained(this), pmt_pid))); | 333 &Mp2tStreamParser::RegisterPes, base::Unretained(this), pmt_pid))); |
338 std::unique_ptr<PidState> pmt_pid_state( | 334 std::unique_ptr<PidState> pmt_pid_state( |
339 new PidState(pmt_pid, PidState::kPidPmt, std::move(pmt_section_parser))); | 335 new PidState(pmt_pid, PidState::kPidPmt, std::move(pmt_section_parser))); |
340 pmt_pid_state->Enable(); | 336 pmt_pid_state->Enable(); |
341 pids_.insert(std::pair<int, PidState*>(pmt_pid, pmt_pid_state.release())); | 337 pids_.insert(std::make_pair(pmt_pid, std::move(pmt_pid_state))); |
342 } | 338 } |
343 | 339 |
344 void Mp2tStreamParser::RegisterPes(int pmt_pid, | 340 void Mp2tStreamParser::RegisterPes(int pmt_pid, |
345 int pes_pid, | 341 int pes_pid, |
346 int stream_type) { | 342 int stream_type) { |
347 // TODO(damienv): check there is no mismatch if the entry already exists. | 343 // TODO(damienv): check there is no mismatch if the entry already exists. |
348 DVLOG(1) << "RegisterPes:" | 344 DVLOG(1) << "RegisterPes:" |
349 << " pes_pid=" << pes_pid | 345 << " pes_pid=" << pes_pid |
350 << " stream_type=" << std::hex << stream_type << std::dec; | 346 << " stream_type=" << std::hex << stream_type << std::dec; |
351 std::map<int, PidState*>::iterator it = pids_.find(pes_pid); | 347 auto it = pids_.find(pes_pid); |
352 if (it != pids_.end()) | 348 if (it != pids_.end()) |
353 return; | 349 return; |
354 | 350 |
355 // Create a stream parser corresponding to the stream type. | 351 // Create a stream parser corresponding to the stream type. |
356 bool is_audio = false; | 352 bool is_audio = false; |
357 std::unique_ptr<EsParser> es_parser; | 353 std::unique_ptr<EsParser> es_parser; |
358 if (stream_type == kStreamTypeAVC) { | 354 if (stream_type == kStreamTypeAVC) { |
359 es_parser.reset( | 355 es_parser.reset( |
360 new EsParserH264( | 356 new EsParserH264( |
361 base::Bind(&Mp2tStreamParser::OnVideoConfigChanged, | 357 base::Bind(&Mp2tStreamParser::OnVideoConfigChanged, |
(...skipping 26 matching lines...) Expand all Loading... |
388 } | 384 } |
389 | 385 |
390 // Create the PES state here. | 386 // Create the PES state here. |
391 DVLOG(1) << "Create a new PES state"; | 387 DVLOG(1) << "Create a new PES state"; |
392 std::unique_ptr<TsSection> pes_section_parser( | 388 std::unique_ptr<TsSection> pes_section_parser( |
393 new TsSectionPes(std::move(es_parser), ×tamp_unroller_)); | 389 new TsSectionPes(std::move(es_parser), ×tamp_unroller_)); |
394 PidState::PidType pid_type = | 390 PidState::PidType pid_type = |
395 is_audio ? PidState::kPidAudioPes : PidState::kPidVideoPes; | 391 is_audio ? PidState::kPidAudioPes : PidState::kPidVideoPes; |
396 std::unique_ptr<PidState> pes_pid_state( | 392 std::unique_ptr<PidState> pes_pid_state( |
397 new PidState(pes_pid, pid_type, std::move(pes_section_parser))); | 393 new PidState(pes_pid, pid_type, std::move(pes_section_parser))); |
398 pids_.insert(std::pair<int, PidState*>(pes_pid, pes_pid_state.release())); | 394 pids_.insert(std::make_pair(pes_pid, std::move(pes_pid_state))); |
399 | 395 |
400 // A new PES pid has been added, the PID filter might change. | 396 // A new PES pid has been added, the PID filter might change. |
401 UpdatePidFilter(); | 397 UpdatePidFilter(); |
402 } | 398 } |
403 | 399 |
404 void Mp2tStreamParser::UpdatePidFilter() { | 400 void Mp2tStreamParser::UpdatePidFilter() { |
405 // Applies the HLS rule to select the default audio/video PIDs: | 401 // Applies the HLS rule to select the default audio/video PIDs: |
406 // select the audio/video streams with the lowest PID. | 402 // select the audio/video streams with the lowest PID. |
407 // TODO(damienv): this can be changed when the StreamParser interface | 403 // TODO(damienv): this can be changed when the StreamParser interface |
408 // supports multiple audio/video streams. | 404 // supports multiple audio/video streams. |
409 PidMap::iterator lowest_audio_pid = pids_.end(); | 405 auto lowest_audio_pid = pids_.end(); |
410 PidMap::iterator lowest_video_pid = pids_.end(); | 406 auto lowest_video_pid = pids_.end(); |
411 for (PidMap::iterator it = pids_.begin(); it != pids_.end(); ++it) { | 407 for (auto it = pids_.begin(); it != pids_.end(); ++it) { |
412 int pid = it->first; | 408 int pid = it->first; |
413 PidState* pid_state = it->second; | 409 PidState* pid_state = it->second.get(); |
414 if (pid_state->pid_type() == PidState::kPidAudioPes && | 410 if (pid_state->pid_type() == PidState::kPidAudioPes && |
415 (lowest_audio_pid == pids_.end() || pid < lowest_audio_pid->first)) | 411 (lowest_audio_pid == pids_.end() || pid < lowest_audio_pid->first)) |
416 lowest_audio_pid = it; | 412 lowest_audio_pid = it; |
417 if (pid_state->pid_type() == PidState::kPidVideoPes && | 413 if (pid_state->pid_type() == PidState::kPidVideoPes && |
418 (lowest_video_pid == pids_.end() || pid < lowest_video_pid->first)) | 414 (lowest_video_pid == pids_.end() || pid < lowest_video_pid->first)) |
419 lowest_video_pid = it; | 415 lowest_video_pid = it; |
420 } | 416 } |
421 | 417 |
422 // Enable both the lowest audio and video PIDs. | 418 // Enable both the lowest audio and video PIDs. |
423 if (lowest_audio_pid != pids_.end()) { | 419 if (lowest_audio_pid != pids_.end()) { |
424 DVLOG(1) << "Enable audio pid: " << lowest_audio_pid->first; | 420 DVLOG(1) << "Enable audio pid: " << lowest_audio_pid->first; |
425 lowest_audio_pid->second->Enable(); | 421 lowest_audio_pid->second->Enable(); |
426 selected_audio_pid_ = lowest_audio_pid->first; | 422 selected_audio_pid_ = lowest_audio_pid->first; |
427 } | 423 } |
428 if (lowest_video_pid != pids_.end()) { | 424 if (lowest_video_pid != pids_.end()) { |
429 DVLOG(1) << "Enable video pid: " << lowest_video_pid->first; | 425 DVLOG(1) << "Enable video pid: " << lowest_video_pid->first; |
430 lowest_video_pid->second->Enable(); | 426 lowest_video_pid->second->Enable(); |
431 selected_video_pid_ = lowest_video_pid->first; | 427 selected_video_pid_ = lowest_video_pid->first; |
432 } | 428 } |
433 | 429 |
434 // Disable all the other audio and video PIDs. | 430 // Disable all the other audio and video PIDs. |
435 for (PidMap::iterator it = pids_.begin(); it != pids_.end(); ++it) { | 431 for (auto it = pids_.begin(); it != pids_.end(); ++it) { |
436 PidState* pid_state = it->second; | 432 PidState* pid_state = it->second.get(); |
437 if (it != lowest_audio_pid && it != lowest_video_pid && | 433 if (it != lowest_audio_pid && it != lowest_video_pid && |
438 (pid_state->pid_type() == PidState::kPidAudioPes || | 434 (pid_state->pid_type() == PidState::kPidAudioPes || |
439 pid_state->pid_type() == PidState::kPidVideoPes)) | 435 pid_state->pid_type() == PidState::kPidVideoPes)) |
440 pid_state->Disable(); | 436 pid_state->Disable(); |
441 } | 437 } |
442 } | 438 } |
443 | 439 |
444 void Mp2tStreamParser::OnVideoConfigChanged( | 440 void Mp2tStreamParser::OnVideoConfigChanged( |
445 int pes_pid, | 441 int pes_pid, |
446 const VideoDecoderConfig& video_decoder_config) { | 442 const VideoDecoderConfig& video_decoder_config) { |
(...skipping 228 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
675 // so that buffers with the same config can be added later on. | 671 // so that buffers with the same config can be added later on. |
676 BufferQueueWithConfig queue_with_config( | 672 BufferQueueWithConfig queue_with_config( |
677 true, last_audio_config, last_video_config); | 673 true, last_audio_config, last_video_config); |
678 buffer_queue_chain_.push_back(queue_with_config); | 674 buffer_queue_chain_.push_back(queue_with_config); |
679 | 675 |
680 return true; | 676 return true; |
681 } | 677 } |
682 | 678 |
683 } // namespace mp2t | 679 } // namespace mp2t |
684 } // namespace media | 680 } // namespace media |
OLD | NEW |