| 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/es_parser_h264.h" | 5 #include "media/formats/mp2t/es_parser_h264.h" |
| 6 | 6 |
| 7 #include "base/basictypes.h" | 7 #include "base/basictypes.h" |
| 8 #include "base/logging.h" | 8 #include "base/logging.h" |
| 9 #include "base/numerics/safe_conversions.h" | 9 #include "base/numerics/safe_conversions.h" |
| 10 #include "media/base/buffers.h" | 10 #include "media/base/buffers.h" |
| (...skipping 10 matching lines...) Expand all Loading... |
| 21 namespace mp2t { | 21 namespace mp2t { |
| 22 | 22 |
| 23 // An AUD NALU is at least 4 bytes: | 23 // An AUD NALU is at least 4 bytes: |
| 24 // 3 bytes for the start code + 1 byte for the NALU type. | 24 // 3 bytes for the start code + 1 byte for the NALU type. |
| 25 const int kMinAUDSize = 4; | 25 const int kMinAUDSize = 4; |
| 26 | 26 |
| 27 EsParserH264::EsParserH264( | 27 EsParserH264::EsParserH264( |
| 28 const NewVideoConfigCB& new_video_config_cb, | 28 const NewVideoConfigCB& new_video_config_cb, |
| 29 const EmitBufferCB& emit_buffer_cb) | 29 const EmitBufferCB& emit_buffer_cb) |
| 30 : es_adapter_(new_video_config_cb, emit_buffer_cb), | 30 : es_adapter_(new_video_config_cb, emit_buffer_cb), |
| 31 es_queue_(new media::OffsetByteQueue()), | |
| 32 h264_parser_(new H264Parser()), | 31 h264_parser_(new H264Parser()), |
| 33 current_access_unit_pos_(0), | 32 current_access_unit_pos_(0), |
| 34 next_access_unit_pos_(0) { | 33 next_access_unit_pos_(0) { |
| 35 } | 34 } |
| 36 | 35 |
| 37 EsParserH264::~EsParserH264() { | 36 EsParserH264::~EsParserH264() { |
| 38 } | 37 } |
| 39 | 38 |
| 40 bool EsParserH264::Parse(const uint8* buf, int size, | |
| 41 base::TimeDelta pts, | |
| 42 DecodeTimestamp dts) { | |
| 43 // Note: Parse is invoked each time a PES packet has been reassembled. | |
| 44 // Unfortunately, a PES packet does not necessarily map | |
| 45 // to an h264 access unit, although the HLS recommendation is to use one PES | |
| 46 // for each access unit (but this is just a recommendation and some streams | |
| 47 // do not comply with this recommendation). | |
| 48 | |
| 49 // HLS recommendation: "In AVC video, you should have both a DTS and a | |
| 50 // PTS in each PES header". | |
| 51 // However, some streams do not comply with this recommendation. | |
| 52 DVLOG_IF(1, pts == kNoTimestamp()) << "Each video PES should have a PTS"; | |
| 53 if (pts != kNoTimestamp()) { | |
| 54 TimingDesc timing_desc; | |
| 55 timing_desc.pts = pts; | |
| 56 timing_desc.dts = (dts != kNoDecodeTimestamp()) ? dts : | |
| 57 DecodeTimestamp::FromPresentationTime(pts); | |
| 58 | |
| 59 // Link the end of the byte queue with the incoming timing descriptor. | |
| 60 timing_desc_list_.push_back( | |
| 61 std::pair<int64, TimingDesc>(es_queue_->tail(), timing_desc)); | |
| 62 } | |
| 63 | |
| 64 // Add the incoming bytes to the ES queue. | |
| 65 es_queue_->Push(buf, size); | |
| 66 return ParseInternal(); | |
| 67 } | |
| 68 | |
| 69 void EsParserH264::Flush() { | 39 void EsParserH264::Flush() { |
| 70 DVLOG(1) << "EsParserH264::Flush"; | 40 DVLOG(1) << __FUNCTION__; |
| 71 if (!FindAUD(¤t_access_unit_pos_)) | 41 if (!FindAUD(¤t_access_unit_pos_)) |
| 72 return; | 42 return; |
| 73 | 43 |
| 74 // Simulate an additional AUD to force emitting the last access unit | 44 // Simulate an additional AUD to force emitting the last access unit |
| 75 // which is assumed to be complete at this point. | 45 // which is assumed to be complete at this point. |
| 76 uint8 aud[] = { 0x00, 0x00, 0x01, 0x09 }; | 46 uint8 aud[] = { 0x00, 0x00, 0x01, 0x09 }; |
| 77 es_queue_->Push(aud, sizeof(aud)); | 47 es_queue_->Push(aud, sizeof(aud)); |
| 78 ParseInternal(); | 48 ParseFromEsQueue(); |
| 79 | 49 |
| 80 es_adapter_.Flush(); | 50 es_adapter_.Flush(); |
| 81 } | 51 } |
| 82 | 52 |
| 83 void EsParserH264::Reset() { | 53 void EsParserH264::ResetInternal() { |
| 84 DVLOG(1) << "EsParserH264::Reset"; | 54 DVLOG(1) << __FUNCTION__; |
| 85 es_queue_.reset(new media::OffsetByteQueue()); | |
| 86 h264_parser_.reset(new H264Parser()); | 55 h264_parser_.reset(new H264Parser()); |
| 87 current_access_unit_pos_ = 0; | 56 current_access_unit_pos_ = 0; |
| 88 next_access_unit_pos_ = 0; | 57 next_access_unit_pos_ = 0; |
| 89 timing_desc_list_.clear(); | |
| 90 last_video_decoder_config_ = VideoDecoderConfig(); | 58 last_video_decoder_config_ = VideoDecoderConfig(); |
| 91 es_adapter_.Reset(); | 59 es_adapter_.Reset(); |
| 92 } | 60 } |
| 93 | 61 |
| 94 bool EsParserH264::FindAUD(int64* stream_pos) { | 62 bool EsParserH264::FindAUD(int64* stream_pos) { |
| 95 while (true) { | 63 while (true) { |
| 96 const uint8* es; | 64 const uint8* es; |
| 97 int size; | 65 int size; |
| 98 es_queue_->PeekAt(*stream_pos, &es, &size); | 66 es_queue_->PeekAt(*stream_pos, &es, &size); |
| 99 | 67 |
| (...skipping 16 matching lines...) Expand all Loading... |
| 116 break; | 84 break; |
| 117 | 85 |
| 118 // The current NALU is not an AUD, skip the start code | 86 // The current NALU is not an AUD, skip the start code |
| 119 // and continue parsing the stream. | 87 // and continue parsing the stream. |
| 120 *stream_pos += start_code_size; | 88 *stream_pos += start_code_size; |
| 121 } | 89 } |
| 122 | 90 |
| 123 return true; | 91 return true; |
| 124 } | 92 } |
| 125 | 93 |
| 126 bool EsParserH264::ParseInternal() { | 94 bool EsParserH264::ParseFromEsQueue() { |
| 127 DCHECK_LE(es_queue_->head(), current_access_unit_pos_); | 95 DCHECK_LE(es_queue_->head(), current_access_unit_pos_); |
| 128 DCHECK_LE(current_access_unit_pos_, next_access_unit_pos_); | 96 DCHECK_LE(current_access_unit_pos_, next_access_unit_pos_); |
| 129 DCHECK_LE(next_access_unit_pos_, es_queue_->tail()); | 97 DCHECK_LE(next_access_unit_pos_, es_queue_->tail()); |
| 130 | 98 |
| 131 // Find the next AUD located at or after |current_access_unit_pos_|. This is | 99 // Find the next AUD located at or after |current_access_unit_pos_|. This is |
| 132 // needed since initially |current_access_unit_pos_| might not point to | 100 // needed since initially |current_access_unit_pos_| might not point to |
| 133 // an AUD. | 101 // an AUD. |
| 134 // Discard all the data before the updated |current_access_unit_pos_| | 102 // Discard all the data before the updated |current_access_unit_pos_| |
| 135 // since it won't be used again. | 103 // since it won't be used again. |
| 136 bool aud_found = FindAUD(¤t_access_unit_pos_); | 104 bool aud_found = FindAUD(¤t_access_unit_pos_); |
| (...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 225 is_key_frame, pps_id_for_access_unit)); | 193 is_key_frame, pps_id_for_access_unit)); |
| 226 current_access_unit_pos_ = next_access_unit_pos_; | 194 current_access_unit_pos_ = next_access_unit_pos_; |
| 227 es_queue_->Trim(current_access_unit_pos_); | 195 es_queue_->Trim(current_access_unit_pos_); |
| 228 | 196 |
| 229 return true; | 197 return true; |
| 230 } | 198 } |
| 231 | 199 |
| 232 bool EsParserH264::EmitFrame(int64 access_unit_pos, int access_unit_size, | 200 bool EsParserH264::EmitFrame(int64 access_unit_pos, int access_unit_size, |
| 233 bool is_key_frame, int pps_id) { | 201 bool is_key_frame, int pps_id) { |
| 234 // Get the access unit timing info. | 202 // Get the access unit timing info. |
| 235 TimingDesc current_timing_desc = {kNoDecodeTimestamp(), kNoTimestamp()}; | 203 TimingDesc current_timing_desc = GetTimingDescriptor(access_unit_pos); |
| 236 while (!timing_desc_list_.empty() && | |
| 237 timing_desc_list_.front().first <= access_unit_pos) { | |
| 238 current_timing_desc = timing_desc_list_.front().second; | |
| 239 timing_desc_list_.pop_front(); | |
| 240 } | |
| 241 if (current_timing_desc.pts == kNoTimestamp()) | 204 if (current_timing_desc.pts == kNoTimestamp()) |
| 242 return false; | 205 return false; |
| 243 | 206 |
| 207 if (current_timing_desc.dts == kNoDecodeTimestamp()) { |
| 208 current_timing_desc.dts = |
| 209 DecodeTimestamp::FromPresentationTime(current_timing_desc.pts); |
| 210 } |
| 211 |
| 244 // Update the video decoder configuration if needed. | 212 // Update the video decoder configuration if needed. |
| 245 const H264PPS* pps = h264_parser_->GetPPS(pps_id); | 213 const H264PPS* pps = h264_parser_->GetPPS(pps_id); |
| 246 if (!pps) { | 214 if (!pps) { |
| 247 // Only accept an invalid PPS at the beginning when the stream | 215 // Only accept an invalid PPS at the beginning when the stream |
| 248 // does not necessarily start with an SPS/PPS/IDR. | 216 // does not necessarily start with an SPS/PPS/IDR. |
| 249 // In this case, the initial frames are conveyed to the upper layer with | 217 // In this case, the initial frames are conveyed to the upper layer with |
| 250 // an invalid VideoDecoderConfig and it's up to the upper layer | 218 // an invalid VideoDecoderConfig and it's up to the upper layer |
| 251 // to process this kind of frame accordingly. | 219 // to process this kind of frame accordingly. |
| 252 if (last_video_decoder_config_.IsValidConfig()) | 220 if (last_video_decoder_config_.IsValidConfig()) |
| 253 return false; | 221 return false; |
| (...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 326 << " height=" << sps->sar_height; | 294 << " height=" << sps->sar_height; |
| 327 last_video_decoder_config_ = video_decoder_config; | 295 last_video_decoder_config_ = video_decoder_config; |
| 328 es_adapter_.OnConfigChanged(video_decoder_config); | 296 es_adapter_.OnConfigChanged(video_decoder_config); |
| 329 } | 297 } |
| 330 | 298 |
| 331 return true; | 299 return true; |
| 332 } | 300 } |
| 333 | 301 |
| 334 } // namespace mp2t | 302 } // namespace mp2t |
| 335 } // namespace media | 303 } // namespace media |
| OLD | NEW |