Move SPS/PPS/IDR requirement from RtpFrameObject to PacketBuffer.

BUG=webrtc:8423

Change-Id: I0f0d59461afead700c20c9a2ed9b2bc991590b4a
Reviewed-on: https://webrtc-review.googlesource.com/15101
Reviewed-by: Stefan Holmer <stefan@webrtc.org>
Reviewed-by: Philip Eliasson <philipel@webrtc.org>
Commit-Queue: Rasmus Brandt <brandtr@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#20559}
This commit is contained in:
Rasmus Brandt
2017-11-02 14:28:06 +01:00
committed by Commit Bot
parent cdfbcd4068
commit 88f080ae9a
9 changed files with 185 additions and 106 deletions

View File

@ -12,6 +12,7 @@
#include <algorithm>
#include <limits>
#include <sstream>
#include <utility>
#include "common_video/h264/h264_common.h"
@ -20,6 +21,7 @@
#include "rtc_base/checks.h"
#include "rtc_base/logging.h"
#include "system_wrappers/include/clock.h"
#include "system_wrappers/include/field_trial.h"
namespace webrtc {
namespace video_coding {
@ -45,7 +47,9 @@ PacketBuffer::PacketBuffer(Clock* clock,
is_cleared_to_first_seq_num_(false),
data_buffer_(start_buffer_size),
sequence_buffer_(start_buffer_size),
received_frame_callback_(received_frame_callback) {
received_frame_callback_(received_frame_callback),
sps_pps_idr_is_h264_keyframe_(
field_trial::IsEnabled("WebRTC-SpsPpsIdrIsH264Keyframe")) {
RTC_DCHECK_LE(start_buffer_size, max_buffer_size);
// Buffer size must always be a power of 2.
RTC_DCHECK((start_buffer_size & (start_buffer_size - 1)) == 0);
@ -269,11 +273,15 @@ std::vector<std::unique_ptr<RtpFrameObject>> PacketBuffer::FindFrames(
// the |frame_begin| flag is set.
int start_index = index;
size_t tested_packets = 0;
bool is_h264 = data_buffer_[start_index].codec == kVideoCodecH264;
bool is_h264_keyframe = false;
int64_t frame_timestamp = data_buffer_[start_index].timestamp;
// Identify H.264 keyframes by means of SPS, PPS, and IDR.
bool is_h264 = data_buffer_[start_index].codec == kVideoCodecH264;
bool has_h264_sps = false;
bool has_h264_pps = false;
bool has_h264_idr = false;
bool is_h264_keyframe = false;
while (true) {
++tested_packets;
frame_size += data_buffer_[start_index].sizeBytes;
@ -287,12 +295,20 @@ std::vector<std::unique_ptr<RtpFrameObject>> PacketBuffer::FindFrames(
if (is_h264 && !is_h264_keyframe) {
const RTPVideoHeaderH264& header =
data_buffer_[start_index].video_header.codecHeader.H264;
for (size_t i = 0; i < header.nalus_length; ++i) {
if (header.nalus[i].type == H264::NaluType::kIdr) {
is_h264_keyframe = true;
break;
for (size_t j = 0; j < header.nalus_length; ++j) {
if (header.nalus[j].type == H264::NaluType::kSps) {
has_h264_sps = true;
} else if (header.nalus[j].type == H264::NaluType::kPps) {
has_h264_pps = true;
} else if (header.nalus[j].type == H264::NaluType::kIdr) {
has_h264_idr = true;
}
}
if ((sps_pps_idr_is_h264_keyframe_ && has_h264_idr && has_h264_sps &&
has_h264_pps) ||
(!sps_pps_idr_is_h264_keyframe_ && has_h264_idr)) {
is_h264_keyframe = true;
}
}
if (tested_packets == size_)
@ -315,18 +331,45 @@ std::vector<std::unique_ptr<RtpFrameObject>> PacketBuffer::FindFrames(
--start_seq_num;
}
// If this is H264 but not a keyframe, make sure there are no gaps in the
// packet sequence numbers up until this point.
if (is_h264 && !is_h264_keyframe &&
missing_packets_.upper_bound(start_seq_num) !=
missing_packets_.begin()) {
uint16_t stop_index = (index + 1) % size_;
while (start_index != stop_index) {
sequence_buffer_[start_index].frame_created = false;
start_index = (start_index + 1) % size_;
if (is_h264) {
// Warn if this is an unsafe frame.
if (has_h264_idr && (!has_h264_sps || !has_h264_pps)) {
std::stringstream ss;
ss << "Received H.264-IDR frame "
<< "(SPS: " << has_h264_sps << ", PPS: " << has_h264_pps << "). ";
if (sps_pps_idr_is_h264_keyframe_) {
ss << "Treating as delta frame since "
"WebRTC-SpsPpsIdrIsH264Keyframe is enabled.";
} else {
ss << "Treating as key frame since "
"WebRTC-SpsPpsIdrIsH264Keyframe is disabled.";
}
LOG(LS_WARNING) << ss.str();
}
return found_frames;
// Now that we have decided whether to treat this frame as a key frame
// or delta frame in the frame buffer, we update the field that
// determines if the RtpFrameObject is a key frame or delta frame.
const size_t first_packet_index = start_seq_num % size_;
RTC_CHECK_LT(first_packet_index, size_);
if (is_h264_keyframe) {
data_buffer_[first_packet_index].frameType = kVideoFrameKey;
} else {
data_buffer_[first_packet_index].frameType = kVideoFrameDelta;
}
// If this is not a keyframe, make sure there are no gaps in the
// packet sequence numbers up until this point.
if (!is_h264_keyframe && missing_packets_.upper_bound(start_seq_num) !=
missing_packets_.begin()) {
uint16_t stop_index = (index + 1) % size_;
while (start_index != stop_index) {
sequence_buffer_[start_index].frame_created = false;
start_index = (start_index + 1) % size_;
}
return found_frames;
}
}
missing_packets_.erase(missing_packets_.begin(),