Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 /* | 1 /* |
| 2 * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. | 2 * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. |
| 3 * | 3 * |
| 4 * Use of this source code is governed by a BSD-style license | 4 * Use of this source code is governed by a BSD-style license |
| 5 * that can be found in the LICENSE file in the root of the source | 5 * that can be found in the LICENSE file in the root of the source |
| 6 * tree. An additional intellectual property rights grant can be found | 6 * tree. An additional intellectual property rights grant can be found |
| 7 * in the file PATENTS. All contributing project authors may | 7 * in the file PATENTS. All contributing project authors may |
| 8 * be found in the AUTHORS file in the root of the source tree. | 8 * be found in the AUTHORS file in the root of the source tree. |
| 9 */ | 9 */ |
| 10 | 10 |
| (...skipping 19 matching lines...) Expand all Loading... | |
| 30 | 30 |
| 31 H264SpsPpsTracker::PacketAction H264SpsPpsTracker::CopyAndFixBitstream( | 31 H264SpsPpsTracker::PacketAction H264SpsPpsTracker::CopyAndFixBitstream( |
| 32 VCMPacket* packet) { | 32 VCMPacket* packet) { |
| 33 RTC_DCHECK(packet->codec == kVideoCodecH264); | 33 RTC_DCHECK(packet->codec == kVideoCodecH264); |
| 34 | 34 |
| 35 const uint8_t* data = packet->dataPtr; | 35 const uint8_t* data = packet->dataPtr; |
| 36 const size_t data_size = packet->sizeBytes; | 36 const size_t data_size = packet->sizeBytes; |
| 37 const RTPVideoHeader& video_header = packet->video_header; | 37 const RTPVideoHeader& video_header = packet->video_header; |
| 38 const RTPVideoHeaderH264& codec_header = video_header.codecHeader.H264; | 38 const RTPVideoHeaderH264& codec_header = video_header.codecHeader.H264; |
| 39 | 39 |
| 40 int pps_id = -1; | 40 bool append_sps_pps = false; |
| 41 int sps_id = -1; | 41 auto sps = sps_data_.end(); |
| 42 bool append_sps_pps = codec_header.nalus_length == 0; | 42 auto pps = pps_data_.end(); |
| 43 size_t required_size = 0; | 43 |
| 44 for (size_t i = 0; i < codec_header.nalus_length; ++i) { | 44 for (size_t i = 0; i < codec_header.nalus_length; ++i) { |
| 45 const NaluInfo& nalu = codec_header.nalus[i]; | 45 const NaluInfo& nalu = codec_header.nalus[i]; |
| 46 switch (nalu.type) { | 46 switch (nalu.type) { |
| 47 case H264::NaluType::kSps: { | 47 case H264::NaluType::kSps: { |
| 48 // Save SPS. | |
| 49 sps_data_[nalu.sps_id].size = nalu.size; | |
| 50 sps_data_[nalu.sps_id].data.reset(new uint8_t[nalu.size]); | |
| 51 memcpy(sps_data_[nalu.sps_id].data.get(), data + nalu.offset, | |
| 52 nalu.size); | |
| 53 sps_data_[nalu.sps_id].width = packet->width; | 48 sps_data_[nalu.sps_id].width = packet->width; |
| 54 sps_data_[nalu.sps_id].height = packet->height; | 49 sps_data_[nalu.sps_id].height = packet->height; |
| 55 break; | 50 break; |
| 56 } | 51 } |
| 57 case H264::NaluType::kPps: { | 52 case H264::NaluType::kPps: { |
| 58 // Save PPS. | |
| 59 pps_data_[nalu.pps_id].sps_id = nalu.sps_id; | 53 pps_data_[nalu.pps_id].sps_id = nalu.sps_id; |
| 60 pps_data_[nalu.pps_id].size = nalu.size; | |
| 61 pps_data_[nalu.pps_id].data.reset(new uint8_t[nalu.size]); | |
| 62 memcpy(pps_data_[nalu.pps_id].data.get(), data + nalu.offset, | |
| 63 nalu.size); | |
| 64 break; | 54 break; |
| 65 } | 55 } |
| 66 case H264::NaluType::kIdr: { | 56 case H264::NaluType::kIdr: { |
| 67 // If this is the first packet of an IDR, make sure we have the required | 57 // If this is the first packet of an IDR, make sure we have the required |
| 68 // SPS/PPS and also calculate how much extra space we need in the buffer | 58 // SPS/PPS and also calculate how much extra space we need in the buffer |
| 69 // to prepend the SPS/PPS to the bitstream with start codes. | 59 // to prepend the SPS/PPS to the bitstream with start codes. |
| 70 if (video_header.is_first_packet_in_frame) { | 60 if (video_header.is_first_packet_in_frame) { |
| 71 if (nalu.pps_id == -1) { | 61 if (nalu.pps_id == -1) { |
| 72 LOG(LS_WARNING) << "No PPS id in IDR nalu."; | 62 LOG(LS_WARNING) << "No PPS id in IDR nalu."; |
| 73 return kRequestKeyframe; | 63 return kRequestKeyframe; |
| 74 } | 64 } |
| 75 | 65 |
| 76 auto pps = pps_data_.find(nalu.pps_id); | 66 pps = pps_data_.find(nalu.pps_id); |
| 77 if (pps == pps_data_.end()) { | 67 if (pps == pps_data_.end()) { |
| 78 LOG(LS_WARNING) << "No PPS with id << " << nalu.pps_id | 68 LOG(LS_WARNING) << "No PPS with id << " << nalu.pps_id |
| 79 << " received"; | 69 << " received"; |
| 80 return kRequestKeyframe; | 70 return kRequestKeyframe; |
| 81 } | 71 } |
| 82 | 72 |
| 83 sps_id = pps->second.sps_id; | 73 sps = sps_data_.find(pps->second.sps_id); |
| 84 auto sps = sps_data_.find(sps_id); | |
| 85 if (sps == sps_data_.end()) { | 74 if (sps == sps_data_.end()) { |
| 86 LOG(LS_WARNING) << "No SPS with id << " | 75 LOG(LS_WARNING) |
| 87 << pps_data_[nalu.pps_id].sps_id << " received"; | 76 << "No SPS with id << " << pps->second.sps_id << " received"; |
| 88 return kRequestKeyframe; | 77 return kRequestKeyframe; |
| 89 } | 78 } |
| 90 | 79 |
| 91 pps_id = nalu.pps_id; | 80 if (sps->second.data && pps->second.data) { |
| 92 required_size += pps->second.size + sizeof(start_code_h264); | 81 RTC_DCHECK_LE(0, sps->second.size); |
| 93 required_size += sps->second.size + sizeof(start_code_h264); | 82 RTC_DCHECK_LE(0, pps->second.size); |
|
stefan-webrtc
2017/06/20 08:56:31
I'd prefer RTC_DCHECK_GT(sps->second.size, 0)
philipel
2017/06/20 11:27:34
Done.
| |
| 83 append_sps_pps = true; | |
| 84 } | |
| 94 } | 85 } |
| 95 FALLTHROUGH(); | 86 FALLTHROUGH(); |
|
stefan-webrtc
2017/06/20 08:56:31
No point in FALLTHROUGH now, right? Might as well
philipel
2017/06/20 11:27:34
Done.
| |
| 96 } | 87 } |
| 97 default: { | 88 default: { break; } |
|
stefan-webrtc
2017/06/20 08:56:31
Remove {}
philipel
2017/06/20 11:27:34
Done.
| |
| 98 // Something other than an SPS/PPS nalu in this packet, then the SPS/PPS | |
| 99 // should be appended. | |
| 100 append_sps_pps = true; | |
| 101 } | |
| 102 } | 89 } |
| 103 } | 90 } |
| 104 | 91 |
| 105 if (!append_sps_pps) { | 92 RTC_CHECK(!append_sps_pps || |
| 106 // Two things: Firstly, when we receive a packet the data pointed at by | 93 (sps != sps_data_.end() && pps != pps_data_.end())); |
| 107 // |dataPtr| is volatile, meaning we have to copy the data into our own | 94 |
| 108 // buffer if we want to use it at a later stage. Secondly, when a packet is | 95 // Calculate how much space we need for the rest of the bitstream. |
| 109 // inserted into the PacketBuffer it expects the packet to own its own | 96 size_t required_size = 0; |
| 110 // buffer, and this function copies (and fix) the bitstream of the packet | 97 if (append_sps_pps) { |
| 111 // into its own buffer. | 98 required_size += sps->second.size + sizeof(start_code_h264); |
| 112 // | 99 required_size += pps->second.size + sizeof(start_code_h264); |
| 113 // SPS/PPS packets is a special case. Since we save the SPS/PPS NALU and | |
| 114 // append it to the first packet of every IDR frame the SPS/PPS packet | |
| 115 // doesn't actually need to contain any bitstream data. | |
| 116 packet->dataPtr = nullptr; | |
| 117 packet->sizeBytes = 0; | |
| 118 return kInsert; | |
| 119 } | 100 } |
| 120 | 101 |
| 121 // Calculate how much space we need for the rest of the bitstream. | |
| 122 if (codec_header.packetization_type == kH264StapA) { | 102 if (codec_header.packetization_type == kH264StapA) { |
| 123 const uint8_t* nalu_ptr = data + 1; | 103 const uint8_t* nalu_ptr = data + 1; |
| 124 while (nalu_ptr < data + data_size) { | 104 while (nalu_ptr < data + data_size) { |
| 125 RTC_DCHECK(video_header.is_first_packet_in_frame); | 105 RTC_DCHECK(video_header.is_first_packet_in_frame); |
| 126 required_size += sizeof(start_code_h264); | 106 required_size += sizeof(start_code_h264); |
| 127 | 107 |
| 128 // The first two bytes describe the length of a segment. | 108 // The first two bytes describe the length of a segment. |
| 129 uint16_t segment_length = nalu_ptr[0] << 8 | nalu_ptr[1]; | 109 uint16_t segment_length = nalu_ptr[0] << 8 | nalu_ptr[1]; |
| 130 nalu_ptr += 2; | 110 nalu_ptr += 2; |
| 131 | 111 |
| 132 required_size += segment_length; | 112 required_size += segment_length; |
| 133 nalu_ptr += segment_length; | 113 nalu_ptr += segment_length; |
| 134 } | 114 } |
| 135 } else { | 115 } else { |
| 136 if (video_header.is_first_packet_in_frame) | 116 if (video_header.is_first_packet_in_frame) |
| 137 required_size += sizeof(start_code_h264); | 117 required_size += sizeof(start_code_h264); |
| 138 required_size += data_size; | 118 required_size += data_size; |
| 139 } | 119 } |
| 140 | 120 |
| 141 // Then we copy to the new buffer. | 121 // Then we copy to the new buffer. |
| 142 uint8_t* buffer = new uint8_t[required_size]; | 122 uint8_t* buffer = new uint8_t[required_size]; |
| 143 uint8_t* insert_at = buffer; | 123 uint8_t* insert_at = buffer; |
| 144 | 124 |
| 145 // If pps_id != -1 then we have the SPS/PPS and they should be prepended | 125 if (append_sps_pps) { |
| 146 // to the bitstream with start codes inserted. | |
| 147 if (pps_id != -1) { | |
| 148 // Insert SPS. | 126 // Insert SPS. |
| 149 memcpy(insert_at, start_code_h264, sizeof(start_code_h264)); | 127 memcpy(insert_at, start_code_h264, sizeof(start_code_h264)); |
| 150 insert_at += sizeof(start_code_h264); | 128 insert_at += sizeof(start_code_h264); |
| 151 memcpy(insert_at, sps_data_[pps_data_[pps_id].sps_id].data.get(), | 129 memcpy(insert_at, sps->second.data.get(), sps->second.size); |
| 152 sps_data_[pps_data_[pps_id].sps_id].size); | 130 insert_at += sps->second.size; |
| 153 insert_at += sps_data_[pps_data_[pps_id].sps_id].size; | |
| 154 | 131 |
| 155 // Insert PPS. | 132 // Insert PPS. |
| 156 memcpy(insert_at, start_code_h264, sizeof(start_code_h264)); | 133 memcpy(insert_at, start_code_h264, sizeof(start_code_h264)); |
| 157 insert_at += sizeof(start_code_h264); | 134 insert_at += sizeof(start_code_h264); |
| 158 memcpy(insert_at, pps_data_[pps_id].data.get(), pps_data_[pps_id].size); | 135 memcpy(insert_at, pps->second.data.get(), pps->second.size); |
| 159 insert_at += pps_data_[pps_id].size; | 136 insert_at += pps->second.size; |
| 160 } | 137 } |
| 161 | 138 |
| 162 // Copy the rest of the bitstream and insert start codes. | 139 // Copy the rest of the bitstream and insert start codes. |
| 163 if (codec_header.packetization_type == kH264StapA) { | 140 if (codec_header.packetization_type == kH264StapA) { |
| 164 const uint8_t* nalu_ptr = data + 1; | 141 const uint8_t* nalu_ptr = data + 1; |
| 165 while (nalu_ptr < data + data_size) { | 142 while (nalu_ptr < data + data_size) { |
| 166 memcpy(insert_at, start_code_h264, sizeof(start_code_h264)); | 143 memcpy(insert_at, start_code_h264, sizeof(start_code_h264)); |
| 167 insert_at += sizeof(start_code_h264); | 144 insert_at += sizeof(start_code_h264); |
| 168 | 145 |
| 169 // The first two bytes describe the length of a segment. | 146 // The first two bytes describe the length of a segment. |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 181 nalu_ptr += segment_length; | 158 nalu_ptr += segment_length; |
| 182 } | 159 } |
| 183 } else { | 160 } else { |
| 184 if (video_header.is_first_packet_in_frame) { | 161 if (video_header.is_first_packet_in_frame) { |
| 185 memcpy(insert_at, start_code_h264, sizeof(start_code_h264)); | 162 memcpy(insert_at, start_code_h264, sizeof(start_code_h264)); |
| 186 insert_at += sizeof(start_code_h264); | 163 insert_at += sizeof(start_code_h264); |
| 187 } | 164 } |
| 188 memcpy(insert_at, data, data_size); | 165 memcpy(insert_at, data, data_size); |
| 189 } | 166 } |
| 190 | 167 |
| 191 if (sps_id != -1) { | 168 if (sps != sps_data_.end()) { |
| 192 packet->width = sps_data_[sps_id].width; | 169 packet->width = sps->second.width; |
| 193 packet->height = sps_data_[sps_id].height; | 170 packet->height = sps->second.height; |
|
stefan-webrtc
2017/06/20 08:56:31
Should this be moved up lines 125-137? Maybe also
philipel
2017/06/20 11:27:34
Done.
| |
| 194 } | 171 } |
| 195 | 172 |
| 196 packet->dataPtr = buffer; | 173 packet->dataPtr = buffer; |
| 197 packet->sizeBytes = required_size; | 174 packet->sizeBytes = required_size; |
| 198 return kInsert; | 175 return kInsert; |
| 199 } | 176 } |
| 200 | 177 |
| 201 void H264SpsPpsTracker::InsertSpsPpsNalus(const std::vector<uint8_t>& sps, | 178 void H264SpsPpsTracker::InsertSpsPpsNalus(const std::vector<uint8_t>& sps, |
| 202 const std::vector<uint8_t>& pps) { | 179 const std::vector<uint8_t>& pps) { |
| 203 constexpr size_t kNaluHeaderOffset = 1; | 180 constexpr size_t kNaluHeaderOffset = 1; |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 253 pps_info.data.reset(pps_data); | 230 pps_info.data.reset(pps_data); |
| 254 pps_data_[parsed_pps->id] = std::move(pps_info); | 231 pps_data_[parsed_pps->id] = std::move(pps_info); |
| 255 | 232 |
| 256 LOG(LS_INFO) << "Inserted SPS id " << parsed_sps->id << " and PPS id " | 233 LOG(LS_INFO) << "Inserted SPS id " << parsed_sps->id << " and PPS id " |
| 257 << parsed_pps->id << " (referencing SPS " << parsed_pps->sps_id | 234 << parsed_pps->id << " (referencing SPS " << parsed_pps->sps_id |
| 258 << ")"; | 235 << ")"; |
| 259 } | 236 } |
| 260 | 237 |
| 261 } // namespace video_coding | 238 } // namespace video_coding |
| 262 } // namespace webrtc | 239 } // namespace webrtc |
| OLD | NEW |