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:
committed by
Commit Bot
parent
0efa941d2f
commit
2fcb834bb4
@ -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(¶m_set_ptrs[0], ¶m_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(¶m_set_ptrs[0], ¶m_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);
|
||||
|
||||
Reference in New Issue
Block a user