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 |