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 // Since the first packet of every keyframe should have its width and |
92 required_size += pps->second.size + sizeof(start_code_h264); | 81 // height set we set it here in the case of it being supplied out of |
93 required_size += sps->second.size + sizeof(start_code_h264); | 82 // band. |
| 83 packet->width = sps->second.width; |
| 84 packet->height = sps->second.height; |
| 85 |
| 86 // If the SPS/PPS was supplied out of band then we will have saved |
| 87 // the actual bitstream in |data|. |
| 88 if (sps->second.data && pps->second.data) { |
| 89 RTC_DCHECK_GT(sps->second.size, 0); |
| 90 RTC_DCHECK_GT(pps->second.size, 0); |
| 91 append_sps_pps = true; |
| 92 } |
94 } | 93 } |
95 FALLTHROUGH(); | 94 break; |
96 } | 95 } |
97 default: { | 96 default: |
98 // Something other than an SPS/PPS nalu in this packet, then the SPS/PPS | 97 break; |
99 // should be appended. | |
100 append_sps_pps = true; | |
101 } | |
102 } | 98 } |
103 } | 99 } |
104 | 100 |
105 if (!append_sps_pps) { | 101 RTC_CHECK(!append_sps_pps || |
106 // Two things: Firstly, when we receive a packet the data pointed at by | 102 (sps != sps_data_.end() && pps != pps_data_.end())); |
107 // |dataPtr| is volatile, meaning we have to copy the data into our own | 103 |
108 // buffer if we want to use it at a later stage. Secondly, when a packet is | 104 // 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 | 105 size_t required_size = 0; |
110 // buffer, and this function copies (and fix) the bitstream of the packet | 106 |
111 // into its own buffer. | 107 if (append_sps_pps) { |
112 // | 108 required_size += sps->second.size + sizeof(start_code_h264); |
113 // SPS/PPS packets is a special case. Since we save the SPS/PPS NALU and | 109 required_size += pps->second.size + sizeof(start_code_h264); |
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 } | 110 } |
120 | 111 |
121 // Calculate how much space we need for the rest of the bitstream. | |
122 if (codec_header.packetization_type == kH264StapA) { | 112 if (codec_header.packetization_type == kH264StapA) { |
123 const uint8_t* nalu_ptr = data + 1; | 113 const uint8_t* nalu_ptr = data + 1; |
124 while (nalu_ptr < data + data_size) { | 114 while (nalu_ptr < data + data_size) { |
125 RTC_DCHECK(video_header.is_first_packet_in_frame); | 115 RTC_DCHECK(video_header.is_first_packet_in_frame); |
126 required_size += sizeof(start_code_h264); | 116 required_size += sizeof(start_code_h264); |
127 | 117 |
128 // The first two bytes describe the length of a segment. | 118 // The first two bytes describe the length of a segment. |
129 uint16_t segment_length = nalu_ptr[0] << 8 | nalu_ptr[1]; | 119 uint16_t segment_length = nalu_ptr[0] << 8 | nalu_ptr[1]; |
130 nalu_ptr += 2; | 120 nalu_ptr += 2; |
131 | 121 |
132 required_size += segment_length; | 122 required_size += segment_length; |
133 nalu_ptr += segment_length; | 123 nalu_ptr += segment_length; |
134 } | 124 } |
135 } else { | 125 } else { |
136 if (video_header.is_first_packet_in_frame) | 126 if (video_header.is_first_packet_in_frame) |
137 required_size += sizeof(start_code_h264); | 127 required_size += sizeof(start_code_h264); |
138 required_size += data_size; | 128 required_size += data_size; |
139 } | 129 } |
140 | 130 |
141 // Then we copy to the new buffer. | 131 // Then we copy to the new buffer. |
142 uint8_t* buffer = new uint8_t[required_size]; | 132 uint8_t* buffer = new uint8_t[required_size]; |
143 uint8_t* insert_at = buffer; | 133 uint8_t* insert_at = buffer; |
144 | 134 |
145 // If pps_id != -1 then we have the SPS/PPS and they should be prepended | 135 if (append_sps_pps) { |
146 // to the bitstream with start codes inserted. | |
147 if (pps_id != -1) { | |
148 // Insert SPS. | 136 // Insert SPS. |
149 memcpy(insert_at, start_code_h264, sizeof(start_code_h264)); | 137 memcpy(insert_at, start_code_h264, sizeof(start_code_h264)); |
150 insert_at += sizeof(start_code_h264); | 138 insert_at += sizeof(start_code_h264); |
151 memcpy(insert_at, sps_data_[pps_data_[pps_id].sps_id].data.get(), | 139 memcpy(insert_at, sps->second.data.get(), sps->second.size); |
152 sps_data_[pps_data_[pps_id].sps_id].size); | 140 insert_at += sps->second.size; |
153 insert_at += sps_data_[pps_data_[pps_id].sps_id].size; | |
154 | 141 |
155 // Insert PPS. | 142 // Insert PPS. |
156 memcpy(insert_at, start_code_h264, sizeof(start_code_h264)); | 143 memcpy(insert_at, start_code_h264, sizeof(start_code_h264)); |
157 insert_at += sizeof(start_code_h264); | 144 insert_at += sizeof(start_code_h264); |
158 memcpy(insert_at, pps_data_[pps_id].data.get(), pps_data_[pps_id].size); | 145 memcpy(insert_at, pps->second.data.get(), pps->second.size); |
159 insert_at += pps_data_[pps_id].size; | 146 insert_at += pps->second.size; |
160 } | 147 } |
161 | 148 |
162 // Copy the rest of the bitstream and insert start codes. | 149 // Copy the rest of the bitstream and insert start codes. |
163 if (codec_header.packetization_type == kH264StapA) { | 150 if (codec_header.packetization_type == kH264StapA) { |
164 const uint8_t* nalu_ptr = data + 1; | 151 const uint8_t* nalu_ptr = data + 1; |
165 while (nalu_ptr < data + data_size) { | 152 while (nalu_ptr < data + data_size) { |
166 memcpy(insert_at, start_code_h264, sizeof(start_code_h264)); | 153 memcpy(insert_at, start_code_h264, sizeof(start_code_h264)); |
167 insert_at += sizeof(start_code_h264); | 154 insert_at += sizeof(start_code_h264); |
168 | 155 |
169 // The first two bytes describe the length of a segment. | 156 // The first two bytes describe the length of a segment. |
(...skipping 11 matching lines...) Expand all Loading... |
181 nalu_ptr += segment_length; | 168 nalu_ptr += segment_length; |
182 } | 169 } |
183 } else { | 170 } else { |
184 if (video_header.is_first_packet_in_frame) { | 171 if (video_header.is_first_packet_in_frame) { |
185 memcpy(insert_at, start_code_h264, sizeof(start_code_h264)); | 172 memcpy(insert_at, start_code_h264, sizeof(start_code_h264)); |
186 insert_at += sizeof(start_code_h264); | 173 insert_at += sizeof(start_code_h264); |
187 } | 174 } |
188 memcpy(insert_at, data, data_size); | 175 memcpy(insert_at, data, data_size); |
189 } | 176 } |
190 | 177 |
191 if (sps_id != -1) { | |
192 packet->width = sps_data_[sps_id].width; | |
193 packet->height = sps_data_[sps_id].height; | |
194 } | |
195 | |
196 packet->dataPtr = buffer; | 178 packet->dataPtr = buffer; |
197 packet->sizeBytes = required_size; | 179 packet->sizeBytes = required_size; |
198 return kInsert; | 180 return kInsert; |
199 } | 181 } |
200 | 182 |
201 void H264SpsPpsTracker::InsertSpsPpsNalus(const std::vector<uint8_t>& sps, | 183 void H264SpsPpsTracker::InsertSpsPpsNalus(const std::vector<uint8_t>& sps, |
202 const std::vector<uint8_t>& pps) { | 184 const std::vector<uint8_t>& pps) { |
203 constexpr size_t kNaluHeaderOffset = 1; | 185 constexpr size_t kNaluHeaderOffset = 1; |
204 if (sps.size() < kNaluHeaderOffset) { | 186 if (sps.size() < kNaluHeaderOffset) { |
205 LOG(LS_WARNING) << "SPS size " << sps.size() << " is smaller than " | 187 LOG(LS_WARNING) << "SPS size " << sps.size() << " is smaller than " |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
253 pps_info.data.reset(pps_data); | 235 pps_info.data.reset(pps_data); |
254 pps_data_[parsed_pps->id] = std::move(pps_info); | 236 pps_data_[parsed_pps->id] = std::move(pps_info); |
255 | 237 |
256 LOG(LS_INFO) << "Inserted SPS id " << parsed_sps->id << " and PPS id " | 238 LOG(LS_INFO) << "Inserted SPS id " << parsed_sps->id << " and PPS id " |
257 << parsed_pps->id << " (referencing SPS " << parsed_pps->sps_id | 239 << parsed_pps->id << " (referencing SPS " << parsed_pps->sps_id |
258 << ")"; | 240 << ")"; |
259 } | 241 } |
260 | 242 |
261 } // namespace video_coding | 243 } // namespace video_coding |
262 } // namespace webrtc | 244 } // namespace webrtc |
OLD | NEW |