Search for SPS NALU rather than assuming its position

Summary:
The implementation of H264AnnexBBufferHasVideoFormatDescription was
assuming that the SPS NALU is either the first NALU in the stream, or
the second one, in case an AUD NALU is present in the first location.
This change removes this assumption and instead searches for the SPS
NALU, failing only if we can't find one.

In addition, it cleans up some binary buffer manipulation code, using the
the parsed NALU indices we already have in AnnexBBufferReader instead.

Test Plan: Unit tests

Change-Id: Id9715aa1d751f0ba1a1992def2b690607896df56

bug: webrtc:8922
Change-Id: Id9715aa1d751f0ba1a1992def2b690607896df56
Reviewed-on: https://webrtc-review.googlesource.com/49982
Commit-Queue: Mirko Bonadei <mbonadei@webrtc.org>
Reviewed-by: Kári Helgason <kthelgason@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#22205}
This commit is contained in:
Guy Hershenbaum
2018-02-20 21:33:36 -08:00
committed by Commit Bot
parent 0efa941d2f
commit 2fcb834bb4
4 changed files with 98 additions and 81 deletions

View File

@ -167,11 +167,10 @@ bool H264AnnexBBufferToCMSampleBuffer(const uint8_t* annexb_buffer,
*out_sample_buffer = nullptr;
AnnexBBufferReader reader(annexb_buffer, annexb_buffer_size);
if (H264AnnexBBufferHasVideoFormatDescription(annexb_buffer,
annexb_buffer_size)) {
// Advance past the SPS and PPS.
const uint8_t* data = nullptr;
size_t data_len = 0;
if (reader.SeekToNextNaluOfType(kSps)) {
// Buffer contains an SPS NALU - skip it and the following PPS
const uint8_t* data;
size_t data_len;
if (!reader.ReadNalu(&data, &data_len)) {
RTC_LOG(LS_ERROR) << "Failed to read SPS";
return false;
@ -180,6 +179,9 @@ bool H264AnnexBBufferToCMSampleBuffer(const uint8_t* annexb_buffer,
RTC_LOG(LS_ERROR) << "Failed to read PPS";
return false;
}
} else {
// No SPS NALU - start reading from the first NALU in the buffer
reader.SeekToStart();
}
// Allocate memory as a block buffer.
@ -246,47 +248,15 @@ bool H264AnnexBBufferToCMSampleBuffer(const uint8_t* annexb_buffer,
return true;
}
bool H264AnnexBBufferHasVideoFormatDescription(const uint8_t* annexb_buffer,
size_t annexb_buffer_size) {
RTC_DCHECK(annexb_buffer);
RTC_DCHECK_GT(annexb_buffer_size, 4);
// The buffer we receive via RTP has 00 00 00 01 start code artifically
// embedded by the RTP depacketizer. Extract NALU information.
// TODO(tkchin): handle potential case where sps and pps are delivered
// separately.
NaluType first_nalu_type = ParseNaluType(annexb_buffer[4]);
bool is_first_nalu_type_sps = first_nalu_type == kSps;
if (is_first_nalu_type_sps)
return true;
bool is_first_nalu_type_aud = first_nalu_type == kAud;
// Start code + access unit delimiter + start code = 4 + 2 + 4 = 10.
if (!is_first_nalu_type_aud || annexb_buffer_size <= 10u)
return false;
NaluType second_nalu_type = ParseNaluType(annexb_buffer[10]);
bool is_second_nalu_type_sps = second_nalu_type == kSps;
return is_second_nalu_type_sps;
}
CMVideoFormatDescriptionRef CreateVideoFormatDescription(
const uint8_t* annexb_buffer,
size_t annexb_buffer_size) {
if (!H264AnnexBBufferHasVideoFormatDescription(annexb_buffer,
annexb_buffer_size)) {
return nullptr;
}
AnnexBBufferReader reader(annexb_buffer, annexb_buffer_size);
CMVideoFormatDescriptionRef description = nullptr;
OSStatus status = noErr;
// Parse the SPS and PPS into a CMVideoFormatDescription.
const uint8_t* param_set_ptrs[2] = {};
size_t param_set_sizes[2] = {};
// Skip AUD.
if (ParseNaluType(annexb_buffer[4]) == kAud) {
if (!reader.ReadNalu(&param_set_ptrs[0], &param_set_sizes[0])) {
RTC_LOG(LS_ERROR) << "Failed to read AUD";
return nullptr;
}
AnnexBBufferReader reader(annexb_buffer, annexb_buffer_size);
// Skip everyting before the SPS, then read the SPS and PPS
if (!reader.SeekToNextNaluOfType(kSps)) {
return nullptr;
}
if (!reader.ReadNalu(&param_set_ptrs[0], &param_set_sizes[0])) {
RTC_LOG(LS_ERROR) << "Failed to read SPS";
@ -296,9 +266,11 @@ CMVideoFormatDescriptionRef CreateVideoFormatDescription(
RTC_LOG(LS_ERROR) << "Failed to read PPS";
return nullptr;
}
status = CMVideoFormatDescriptionCreateFromH264ParameterSets(
kCFAllocatorDefault, 2, param_set_ptrs, param_set_sizes, 4,
&description);
// Parse the SPS and PPS into a CMVideoFormatDescription.
CMVideoFormatDescriptionRef description = nullptr;
OSStatus status = CMVideoFormatDescriptionCreateFromH264ParameterSets(
kCFAllocatorDefault, 2, param_set_ptrs, param_set_sizes, 4, &description);
if (status != noErr) {
RTC_LOG(LS_ERROR) << "Failed to create video format description.";
return nullptr;
@ -337,6 +309,19 @@ size_t AnnexBBufferReader::BytesRemaining() const {
return length_ - offset_->start_offset;
}
void AnnexBBufferReader::SeekToStart() {
offset_ = offsets_.begin();
}
bool AnnexBBufferReader::SeekToNextNaluOfType(NaluType type) {
for (; offset_ != offsets_.end(); ++offset_) {
if (offset_->payload_size < 1)
continue;
if (ParseNaluType(*(start_ + offset_->payload_start_offset)) == type)
return true;
}
return false;
}
AvccBufferWriter::AvccBufferWriter(uint8_t* const avcc_buffer, size_t length)
: start_(avcc_buffer), offset_(0), length_(length) {
RTC_DCHECK(avcc_buffer);