Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(123)

Side by Side Diff: webrtc/modules/audio_coding/neteq/payload_splitter.cc

Issue 2281453002: Moved codec-specific audio packet splitting into decoders. (Closed)
Patch Set: Created 4 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 /* 1 /*
2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. 2 * Copyright (c) 2012 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 214 matching lines...) Expand 10 before | Expand all | Expand 10 after
225 // Iterate through all packets in |packet_list|. 225 // Iterate through all packets in |packet_list|.
226 while (it != packet_list->end()) { 226 while (it != packet_list->end()) {
227 Packet* packet = (*it); // Just to make the notation more intuitive. 227 Packet* packet = (*it); // Just to make the notation more intuitive.
228 // Get codec type for this payload. 228 // Get codec type for this payload.
229 const DecoderDatabase::DecoderInfo* info = 229 const DecoderDatabase::DecoderInfo* info =
230 decoder_database.GetDecoderInfo(packet->header.payloadType); 230 decoder_database.GetDecoderInfo(packet->header.payloadType);
231 if (!info) { 231 if (!info) {
232 LOG(LS_WARNING) << "SplitAudio unknown payload type"; 232 LOG(LS_WARNING) << "SplitAudio unknown payload type";
233 return kUnknownPayloadType; 233 return kUnknownPayloadType;
234 } 234 }
235 // No splitting for a sync-packet. 235 // No splitting for a sync-packet nor for any format handled internally.
236 if (packet->sync_packet) { 236 if (packet->sync_packet ||
237 info->IsComfortNoise() || info->IsDtmf() || info->IsRed()) {
237 ++it; 238 ++it;
238 continue; 239 continue;
239 } 240 }
240 PacketList new_packets; 241 const AudioDecoder* decoder = info->GetDecoder();
241 switch (info->codec_type) { 242 RTC_DCHECK(decoder);
242 case NetEqDecoder::kDecoderPCMu: 243 AudioDecoder::PacketSplits splits =
243 case NetEqDecoder::kDecoderPCMa: { 244 decoder->SplitPacket(packet->payload, packet->payload_length);
244 // 8 bytes per ms; 8 timestamps per ms. 245 if (splits.empty()) {
245 SplitBySamples(packet, 8, 8, &new_packets); 246 return kFrameSplitError;
246 break; 247 } else if (splits.size() == 1 &&
248 splits[0].byte_offset == 0 &&
249 splits[0].num_bytes == packet->payload_length &&
250 splits[0].timestamp_offset == 0) {
251 // No splitting necessary; move on to the next packet
kwiberg-webrtc 2016/08/26 12:39:25 Hmm. Wouldn't it be better to test just the first
ossu 2016/08/26 13:05:30 Nah, I think it's fine if you can figure out that
252 ++it;
253 } else {
254 PacketList new_packets;
255 for (const auto& split : splits) {
256 Packet* new_packet = new Packet;
kwiberg-webrtc 2016/08/26 12:39:25 Ew. Consider using unique_ptr in this block, and u
ossu 2016/08/26 13:05:30 Hello. I'm the messenger. Please don't shoot me! :
257 const uint8_t* payload_ptr = packet->payload + split.byte_offset;
258 new_packet->payload_length = split.num_bytes;
259 new_packet->header = packet->header;
260 new_packet->header.timestamp += split.timestamp_offset;
261 new_packet->primary = packet->primary;
262 new_packet->payload = new uint8_t[split.num_bytes];
263 memcpy(new_packet->payload, payload_ptr, split.num_bytes);
264 new_packets.push_back(new_packet);
247 } 265 }
248 case NetEqDecoder::kDecoderPCMu_2ch: 266
249 case NetEqDecoder::kDecoderPCMa_2ch: { 267 // Insert new packets into original list, before the element pointed to by
250 // 2 * 8 bytes per ms; 8 timestamps per ms. 268 // iterator |it|.
251 SplitBySamples(packet, 2 * 8, 8, &new_packets); 269 packet_list->splice(it, new_packets, new_packets.begin(),
252 break; 270 new_packets.end());
253 } 271 // Delete old packet payload.
254 case NetEqDecoder::kDecoderG722: { 272 delete [] (*it)->payload;
255 // 8 bytes per ms; 16 timestamps per ms. 273 delete (*it);
256 SplitBySamples(packet, 8, 16, &new_packets); 274 // Remove |it| from the packet list. This operation effectively moves the
257 break; 275 // iterator |it| to the next packet in the list. Thus, we do not have to
258 } 276 // increment it manually.
259 case NetEqDecoder::kDecoderPCM16B: { 277 it = packet_list->erase(it);
260 // 16 bytes per ms; 8 timestamps per ms.
261 SplitBySamples(packet, 16, 8, &new_packets);
262 break;
263 }
264 case NetEqDecoder::kDecoderPCM16Bwb: {
265 // 32 bytes per ms; 16 timestamps per ms.
266 SplitBySamples(packet, 32, 16, &new_packets);
267 break;
268 }
269 case NetEqDecoder::kDecoderPCM16Bswb32kHz: {
270 // 64 bytes per ms; 32 timestamps per ms.
271 SplitBySamples(packet, 64, 32, &new_packets);
272 break;
273 }
274 case NetEqDecoder::kDecoderPCM16Bswb48kHz: {
275 // 96 bytes per ms; 48 timestamps per ms.
276 SplitBySamples(packet, 96, 48, &new_packets);
277 break;
278 }
279 case NetEqDecoder::kDecoderPCM16B_2ch: {
280 // 2 * 16 bytes per ms; 8 timestamps per ms.
281 SplitBySamples(packet, 2 * 16, 8, &new_packets);
282 break;
283 }
284 case NetEqDecoder::kDecoderPCM16Bwb_2ch: {
285 // 2 * 32 bytes per ms; 16 timestamps per ms.
286 SplitBySamples(packet, 2 * 32, 16, &new_packets);
287 break;
288 }
289 case NetEqDecoder::kDecoderPCM16Bswb32kHz_2ch: {
290 // 2 * 64 bytes per ms; 32 timestamps per ms.
291 SplitBySamples(packet, 2 * 64, 32, &new_packets);
292 break;
293 }
294 case NetEqDecoder::kDecoderPCM16Bswb48kHz_2ch: {
295 // 2 * 96 bytes per ms; 48 timestamps per ms.
296 SplitBySamples(packet, 2 * 96, 48, &new_packets);
297 break;
298 }
299 case NetEqDecoder::kDecoderPCM16B_5ch: {
300 // 5 * 16 bytes per ms; 8 timestamps per ms.
301 SplitBySamples(packet, 5 * 16, 8, &new_packets);
302 break;
303 }
304 case NetEqDecoder::kDecoderILBC: {
305 size_t bytes_per_frame;
306 int timestamps_per_frame;
307 if (packet->payload_length >= 950) {
308 LOG(LS_WARNING) << "SplitAudio too large iLBC payload";
309 return kTooLargePayload;
310 }
311 if (packet->payload_length % 38 == 0) {
312 // 20 ms frames.
313 bytes_per_frame = 38;
314 timestamps_per_frame = 160;
315 } else if (packet->payload_length % 50 == 0) {
316 // 30 ms frames.
317 bytes_per_frame = 50;
318 timestamps_per_frame = 240;
319 } else {
320 LOG(LS_WARNING) << "SplitAudio invalid iLBC payload";
321 return kFrameSplitError;
322 }
323 int ret = SplitByFrames(packet, bytes_per_frame, timestamps_per_frame,
324 &new_packets);
325 if (ret < 0) {
326 return ret;
327 } else if (ret == kNoSplit) {
328 // Do not split at all. Simply advance to the next packet in the list.
329 ++it;
330 // We do not have any new packets to insert, and should not delete the
331 // old one. Skip the code after the switch case, and jump straight to
332 // the next packet in the while loop.
333 continue;
334 }
335 break;
336 }
337 default: {
338 // Do not split at all. Simply advance to the next packet in the list.
339 ++it;
340 // We do not have any new packets to insert, and should not delete the
341 // old one. Skip the code after the switch case, and jump straight to
342 // the next packet in the while loop.
343 continue;
344 }
345 } 278 }
346 // Insert new packets into original list, before the element pointed to by
347 // iterator |it|.
348 packet_list->splice(it, new_packets, new_packets.begin(),
349 new_packets.end());
350 // Delete old packet payload.
351 delete [] (*it)->payload;
352 delete (*it);
353 // Remove |it| from the packet list. This operation effectively moves the
354 // iterator |it| to the next packet in the list. Thus, we do not have to
355 // increment it manually.
356 it = packet_list->erase(it);
357 } 279 }
358 return kOK; 280 return kOK;
359 } 281 }
360
361 void PayloadSplitter::SplitBySamples(const Packet* packet,
362 size_t bytes_per_ms,
363 uint32_t timestamps_per_ms,
364 PacketList* new_packets) {
365 assert(packet);
366 assert(new_packets);
367
368 size_t split_size_bytes = packet->payload_length;
369
370 // Find a "chunk size" >= 20 ms and < 40 ms.
371 size_t min_chunk_size = bytes_per_ms * 20;
372 // Reduce the split size by half as long as |split_size_bytes| is at least
373 // twice the minimum chunk size (so that the resulting size is at least as
374 // large as the minimum chunk size).
375 while (split_size_bytes >= 2 * min_chunk_size) {
376 split_size_bytes >>= 1;
377 }
378 uint32_t timestamps_per_chunk = static_cast<uint32_t>(
379 split_size_bytes * timestamps_per_ms / bytes_per_ms);
380 uint32_t timestamp = packet->header.timestamp;
381
382 uint8_t* payload_ptr = packet->payload;
383 size_t len = packet->payload_length;
384 while (len >= (2 * split_size_bytes)) {
385 Packet* new_packet = new Packet;
386 new_packet->payload_length = split_size_bytes;
387 new_packet->header = packet->header;
388 new_packet->header.timestamp = timestamp;
389 timestamp += timestamps_per_chunk;
390 new_packet->primary = packet->primary;
391 new_packet->payload = new uint8_t[split_size_bytes];
392 memcpy(new_packet->payload, payload_ptr, split_size_bytes);
393 payload_ptr += split_size_bytes;
394 new_packets->push_back(new_packet);
395 len -= split_size_bytes;
396 }
397
398 if (len > 0) {
399 Packet* new_packet = new Packet;
400 new_packet->payload_length = len;
401 new_packet->header = packet->header;
402 new_packet->header.timestamp = timestamp;
403 new_packet->primary = packet->primary;
404 new_packet->payload = new uint8_t[len];
405 memcpy(new_packet->payload, payload_ptr, len);
406 new_packets->push_back(new_packet);
407 }
408 }
409
410 int PayloadSplitter::SplitByFrames(const Packet* packet,
411 size_t bytes_per_frame,
412 uint32_t timestamps_per_frame,
413 PacketList* new_packets) {
414 if (packet->payload_length % bytes_per_frame != 0) {
415 LOG(LS_WARNING) << "SplitByFrames length mismatch";
416 return kFrameSplitError;
417 }
418
419 if (packet->payload_length == bytes_per_frame) {
420 // Special case. Do not split the payload.
421 return kNoSplit;
422 }
423
424 uint32_t timestamp = packet->header.timestamp;
425 uint8_t* payload_ptr = packet->payload;
426 size_t len = packet->payload_length;
427 while (len > 0) {
428 assert(len >= bytes_per_frame);
429 Packet* new_packet = new Packet;
430 new_packet->payload_length = bytes_per_frame;
431 new_packet->header = packet->header;
432 new_packet->header.timestamp = timestamp;
433 timestamp += timestamps_per_frame;
434 new_packet->primary = packet->primary;
435 new_packet->payload = new uint8_t[bytes_per_frame];
436 memcpy(new_packet->payload, payload_ptr, bytes_per_frame);
437 payload_ptr += bytes_per_frame;
438 new_packets->push_back(new_packet);
439 len -= bytes_per_frame;
440 }
441 return kOK;
442 }
443 282
444 } // namespace webrtc 283 } // namespace webrtc
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698