Optimize ParseRbsp method in H264 bitstream parser.
After profiling, sakal@ found that this method was taking very long, and causing the bitstream parsing to take up to 1ms per frame. The culprit proved to be rtc::Buffer::AppendData, which was called for every byte and subsequently calls memcpy. BUG=webrtc:7293 Review-Url: https://codereview.webrtc.org/2728093002 Cr-Commit-Position: refs/heads/master@{#17051}
This commit is contained in:
parent
0a3e69a9a4
commit
156e3afa7f
@ -13,7 +13,6 @@
|
||||
#include <vector>
|
||||
|
||||
#include "webrtc/base/bitbuffer.h"
|
||||
#include "webrtc/base/bytebuffer.h"
|
||||
#include "webrtc/base/checks.h"
|
||||
|
||||
#include "webrtc/common_video/h264/h264_common.h"
|
||||
@ -46,13 +45,13 @@ H264BitstreamParser::Result H264BitstreamParser::ParseNonParameterSetNalu(
|
||||
return kInvalidStream;
|
||||
|
||||
last_slice_qp_delta_ = rtc::Optional<int32_t>();
|
||||
std::unique_ptr<rtc::Buffer> slice_rbsp(
|
||||
H264::ParseRbsp(source, source_length));
|
||||
if (slice_rbsp->size() < H264::kNaluTypeSize)
|
||||
const std::vector<uint8_t> slice_rbsp =
|
||||
H264::ParseRbsp(source, source_length);
|
||||
if (slice_rbsp.size() < H264::kNaluTypeSize)
|
||||
return kInvalidStream;
|
||||
|
||||
rtc::BitBuffer slice_reader(slice_rbsp->data() + H264::kNaluTypeSize,
|
||||
slice_rbsp->size() - H264::kNaluTypeSize);
|
||||
rtc::BitBuffer slice_reader(slice_rbsp.data() + H264::kNaluTypeSize,
|
||||
slice_rbsp.size() - H264::kNaluTypeSize);
|
||||
// Check to see if this is an IDR slice, which has an extra field to parse
|
||||
// out.
|
||||
bool is_idr = (source[0] & 0x0F) == H264::NaluType::kIdr;
|
||||
|
||||
@ -60,26 +60,27 @@ NaluType ParseNaluType(uint8_t data) {
|
||||
return static_cast<NaluType>(data & kNaluTypeMask);
|
||||
}
|
||||
|
||||
std::unique_ptr<rtc::Buffer> ParseRbsp(const uint8_t* data, size_t length) {
|
||||
std::unique_ptr<rtc::Buffer> rbsp_buffer(new rtc::Buffer(0, length));
|
||||
const char* sps_bytes = reinterpret_cast<const char*>(data);
|
||||
std::vector<uint8_t> ParseRbsp(const uint8_t* data, size_t length) {
|
||||
std::vector<uint8_t> out;
|
||||
out.reserve(length);
|
||||
|
||||
for (size_t i = 0; i < length;) {
|
||||
// Be careful about over/underflow here. byte_length_ - 3 can underflow, and
|
||||
// i + 3 can overflow, but byte_length_ - i can't, because i < byte_length_
|
||||
// above, and that expression will produce the number of bytes left in
|
||||
// the stream including the byte at i.
|
||||
if (length - i >= 3 && data[i] == 0 && data[i + 1] == 0 &&
|
||||
data[i + 2] == 3) {
|
||||
// Two rbsp bytes + the emulation byte.
|
||||
rbsp_buffer->AppendData(sps_bytes + i, 2);
|
||||
i += 3;
|
||||
if (length - i >= 3 && !data[i] && !data[i + 1] && data[i + 2] == 3) {
|
||||
// Two rbsp bytes.
|
||||
out.push_back(data[i++]);
|
||||
out.push_back(data[i++]);
|
||||
// Skip the emulation byte.
|
||||
i++;
|
||||
} else {
|
||||
// Single rbsp byte.
|
||||
rbsp_buffer->AppendData(sps_bytes[i]);
|
||||
++i;
|
||||
out.push_back(data[i++]);
|
||||
}
|
||||
}
|
||||
return rbsp_buffer;
|
||||
return out;
|
||||
}
|
||||
|
||||
void WriteRbsp(const uint8_t* bytes, size_t length, rtc::Buffer* destination) {
|
||||
|
||||
@ -76,7 +76,7 @@ NaluType ParseNaluType(uint8_t data);
|
||||
// the 03 emulation byte.
|
||||
|
||||
// Parse the given data and remove any emulation byte escaping.
|
||||
std::unique_ptr<rtc::Buffer> ParseRbsp(const uint8_t* data, size_t length);
|
||||
std::vector<uint8_t> ParseRbsp(const uint8_t* data, size_t length);
|
||||
|
||||
// Write the given data to the destination buffer, inserting and emulation
|
||||
// bytes in order to escape any data the could be interpreted as a start
|
||||
|
||||
@ -11,10 +11,10 @@
|
||||
#include "webrtc/common_video/h264/pps_parser.h"
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "webrtc/common_video/h264/h264_common.h"
|
||||
#include "webrtc/base/bitbuffer.h"
|
||||
#include "webrtc/base/buffer.h"
|
||||
#include "webrtc/base/logging.h"
|
||||
|
||||
#define RETURN_EMPTY_ON_FAIL(x) \
|
||||
@ -38,8 +38,8 @@ rtc::Optional<PpsParser::PpsState> PpsParser::ParsePps(const uint8_t* data,
|
||||
// First, parse out rbsp, which is basically the source buffer minus emulation
|
||||
// bytes (the last byte of a 0x00 0x00 0x03 sequence). RBSP is defined in
|
||||
// section 7.3.1 of the H.264 standard.
|
||||
std::unique_ptr<rtc::Buffer> unpacked_buffer = H264::ParseRbsp(data, length);
|
||||
rtc::BitBuffer bit_buffer(unpacked_buffer->data(), unpacked_buffer->size());
|
||||
std::vector<uint8_t> unpacked_buffer = H264::ParseRbsp(data, length);
|
||||
rtc::BitBuffer bit_buffer(unpacked_buffer.data(), unpacked_buffer.size());
|
||||
return ParseInternal(&bit_buffer);
|
||||
}
|
||||
|
||||
@ -52,15 +52,15 @@ bool PpsParser::ParsePpsIds(const uint8_t* data,
|
||||
// First, parse out rbsp, which is basically the source buffer minus emulation
|
||||
// bytes (the last byte of a 0x00 0x00 0x03 sequence). RBSP is defined in
|
||||
// section 7.3.1 of the H.264 standard.
|
||||
std::unique_ptr<rtc::Buffer> unpacked_buffer = H264::ParseRbsp(data, length);
|
||||
rtc::BitBuffer bit_buffer(unpacked_buffer->data(), unpacked_buffer->size());
|
||||
std::vector<uint8_t> unpacked_buffer = H264::ParseRbsp(data, length);
|
||||
rtc::BitBuffer bit_buffer(unpacked_buffer.data(), unpacked_buffer.size());
|
||||
return ParsePpsIdsInternal(&bit_buffer, pps_id, sps_id);
|
||||
}
|
||||
|
||||
rtc::Optional<uint32_t> PpsParser::ParsePpsIdFromSlice(const uint8_t* data,
|
||||
size_t length) {
|
||||
std::unique_ptr<rtc::Buffer> slice_rbsp(H264::ParseRbsp(data, length));
|
||||
rtc::BitBuffer slice_reader(slice_rbsp->data(), slice_rbsp->size());
|
||||
std::vector<uint8_t> unpacked_buffer = H264::ParseRbsp(data, length);
|
||||
rtc::BitBuffer slice_reader(unpacked_buffer.data(), unpacked_buffer.size());
|
||||
|
||||
uint32_t golomb_tmp;
|
||||
// first_mb_in_slice: ue(v)
|
||||
|
||||
@ -11,10 +11,10 @@
|
||||
#include "webrtc/common_video/h264/sps_parser.h"
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "webrtc/common_video/h264/h264_common.h"
|
||||
#include "webrtc/base/bitbuffer.h"
|
||||
#include "webrtc/base/bytebuffer.h"
|
||||
#include "webrtc/base/logging.h"
|
||||
|
||||
typedef rtc::Optional<webrtc::SpsParser::SpsState> OptionalSps;
|
||||
@ -33,8 +33,8 @@ namespace webrtc {
|
||||
// Unpack RBSP and parse SPS state from the supplied buffer.
|
||||
rtc::Optional<SpsParser::SpsState> SpsParser::ParseSps(const uint8_t* data,
|
||||
size_t length) {
|
||||
std::unique_ptr<rtc::Buffer> unpacked_buffer = H264::ParseRbsp(data, length);
|
||||
rtc::BitBuffer bit_buffer(unpacked_buffer->data(), unpacked_buffer->size());
|
||||
std::vector<uint8_t> unpacked_buffer = H264::ParseRbsp(data, length);
|
||||
rtc::BitBuffer bit_buffer(unpacked_buffer.data(), unpacked_buffer.size());
|
||||
return ParseSpsUpToVui(&bit_buffer);
|
||||
}
|
||||
|
||||
|
||||
@ -13,6 +13,7 @@
|
||||
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "webrtc/base/bitbuffer.h"
|
||||
#include "webrtc/base/checks.h"
|
||||
@ -74,8 +75,8 @@ SpsVuiRewriter::ParseResult SpsVuiRewriter::ParseAndRewriteSps(
|
||||
rtc::Buffer* destination) {
|
||||
// Create temporary RBSP decoded buffer of the payload (exlcuding the
|
||||
// leading nalu type header byte (the SpsParser uses only the payload).
|
||||
std::unique_ptr<rtc::Buffer> rbsp_buffer = H264::ParseRbsp(buffer, length);
|
||||
rtc::BitBuffer source_buffer(rbsp_buffer->data(), rbsp_buffer->size());
|
||||
std::vector<uint8_t> rbsp_buffer = H264::ParseRbsp(buffer, length);
|
||||
rtc::BitBuffer source_buffer(rbsp_buffer.data(), rbsp_buffer.size());
|
||||
rtc::Optional<SpsParser::SpsState> sps_state =
|
||||
SpsParser::ParseSpsUpToVui(&source_buffer);
|
||||
if (!sps_state)
|
||||
@ -97,7 +98,7 @@ SpsVuiRewriter::ParseResult SpsVuiRewriter::ParseAndRewriteSps(
|
||||
size_t byte_offset;
|
||||
size_t bit_offset;
|
||||
source_buffer.GetCurrentOffset(&byte_offset, &bit_offset);
|
||||
memcpy(out_buffer.data(), rbsp_buffer->data(),
|
||||
memcpy(out_buffer.data(), rbsp_buffer.data(),
|
||||
byte_offset + (bit_offset > 0 ? 1 : 0)); // OK to copy the last bits.
|
||||
|
||||
// SpsParser will have read the vui_params_present flag, which we want to
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user