Video: Avoid crashing when dump stream with IvfFileWriter.

Currently some RTPVideoHeaders are not filled with width and height
information, such as AV1. If we dump the stream with command line
“--force-fieldtrials=WebRTC-DecoderDataDumpDirectory/./”, and if
width and height are 0, it will crash soon.

This CL aims to avoid crashing when the |encoded_image._encodedWidth|
and |encoded_image._encodedHeight| are 0.

Bug: webrtc:13491
Change-Id: Ie5af58c03f09a9784ed67943dc5b5959850b4368
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/242500
Reviewed-by: Sergey Silkin <ssilkin@webrtc.org>
Reviewed-by: Erik Språng <sprang@webrtc.org>
Commit-Queue: Sergey Silkin <ssilkin@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#35576}
This commit is contained in:
Shuhai Peng
2021-12-21 22:04:22 +08:00
committed by WebRTC LUCI CQ
parent 34e1036829
commit 9753fbc380
2 changed files with 126 additions and 4 deletions

View File

@ -23,6 +23,12 @@
namespace webrtc {
namespace {
constexpr int kDefaultWidth = 1280;
constexpr int kDefaultHeight = 720;
} // namespace
IvfFileWriter::IvfFileWriter(FileWrapper file, size_t byte_limit)
: codec_type_(kVideoCodecGeneric),
bytes_written_(0),
@ -121,10 +127,14 @@ bool IvfFileWriter::WriteHeader() {
bool IvfFileWriter::InitFromFirstFrame(const EncodedImage& encoded_image,
VideoCodecType codec_type) {
width_ = encoded_image._encodedWidth;
height_ = encoded_image._encodedHeight;
RTC_CHECK_GT(width_, 0);
RTC_CHECK_GT(height_, 0);
if (encoded_image._encodedWidth == 0 || encoded_image._encodedHeight == 0) {
width_ = kDefaultWidth;
height_ = kDefaultHeight;
} else {
width_ = encoded_image._encodedWidth;
height_ = encoded_image._encodedHeight;
}
using_capture_timestamps_ = encoded_image.Timestamp() == 0;
codec_type_ = codec_type;

View File

@ -25,6 +25,10 @@ namespace {
static const int kHeaderSize = 32;
static const int kFrameHeaderSize = 12;
static uint8_t dummy_payload[4] = {0, 1, 2, 3};
// As the default parameter when the width and height of encodedImage are 0,
// the values are copied from ivf_file_writer.cc
constexpr int kDefaultWidth = 1280;
constexpr int kDefaultHeight = 720;
} // namespace
class IvfFileWriterTest : public ::testing::Test {
@ -196,4 +200,112 @@ TEST_F(IvfFileWriterTest, ClosesWhenReachesLimit) {
out_file.Close();
}
TEST_F(IvfFileWriterTest, UseDefaultValueWhenWidthAndHeightAreZero) {
const uint8_t fourcc[4] = {'V', 'P', '8', '0'};
const int kWidth = 0;
const int kHeight = 0;
const int kNumFramesToWrite = 2;
const int kNumFramesToFit = 1;
file_writer_ = IvfFileWriter::Wrap(
FileWrapper::OpenWriteOnly(file_name_),
kHeaderSize +
kNumFramesToFit * (kFrameHeaderSize + sizeof(dummy_payload)));
ASSERT_TRUE(file_writer_.get());
ASSERT_FALSE(WriteDummyTestFrames(kVideoCodecVP8, kWidth, kHeight,
kNumFramesToWrite, true));
ASSERT_FALSE(file_writer_->Close());
FileWrapper out_file = FileWrapper::OpenReadOnly(file_name_);
// When the width and height are zero, we should expect the width and height
// in IvfHeader to be kDefaultWidth and kDefaultHeight instead of kWidth and
// kHeight.
VerifyIvfHeader(&out_file, fourcc, kDefaultWidth, kDefaultHeight,
kNumFramesToFit, true);
VerifyDummyTestFrames(&out_file, kNumFramesToFit);
out_file.Close();
}
TEST_F(IvfFileWriterTest, UseDefaultValueWhenOnlyWidthIsZero) {
const uint8_t fourcc[4] = {'V', 'P', '8', '0'};
const int kWidth = 0;
const int kHeight = 360;
const int kNumFramesToWrite = 2;
const int kNumFramesToFit = 1;
file_writer_ = IvfFileWriter::Wrap(
FileWrapper::OpenWriteOnly(file_name_),
kHeaderSize +
kNumFramesToFit * (kFrameHeaderSize + sizeof(dummy_payload)));
ASSERT_TRUE(file_writer_.get());
ASSERT_FALSE(WriteDummyTestFrames(kVideoCodecVP8, kWidth, kHeight,
kNumFramesToWrite, true));
ASSERT_FALSE(file_writer_->Close());
FileWrapper out_file = FileWrapper::OpenReadOnly(file_name_);
// When the width and height are zero, we should expect the width and height
// in IvfHeader to be kDefaultWidth and kDefaultHeight instead of kWidth and
// kHeight.
VerifyIvfHeader(&out_file, fourcc, kDefaultWidth, kDefaultHeight,
kNumFramesToFit, true);
VerifyDummyTestFrames(&out_file, kNumFramesToFit);
out_file.Close();
}
TEST_F(IvfFileWriterTest, UseDefaultValueWhenOnlyHeightIsZero) {
const uint8_t fourcc[4] = {'V', 'P', '8', '0'};
const int kWidth = 240;
const int kHeight = 0;
const int kNumFramesToWrite = 2;
const int kNumFramesToFit = 1;
file_writer_ = IvfFileWriter::Wrap(
FileWrapper::OpenWriteOnly(file_name_),
kHeaderSize +
kNumFramesToFit * (kFrameHeaderSize + sizeof(dummy_payload)));
ASSERT_TRUE(file_writer_.get());
ASSERT_FALSE(WriteDummyTestFrames(kVideoCodecVP8, kWidth, kHeight,
kNumFramesToWrite, true));
ASSERT_FALSE(file_writer_->Close());
FileWrapper out_file = FileWrapper::OpenReadOnly(file_name_);
// When the width and height are zero, we should expect the width and height
// in IvfHeader to be kDefaultWidth and kDefaultHeight instead of kWidth and
// kHeight.
VerifyIvfHeader(&out_file, fourcc, kDefaultWidth, kDefaultHeight,
kNumFramesToFit, true);
VerifyDummyTestFrames(&out_file, kNumFramesToFit);
out_file.Close();
}
TEST_F(IvfFileWriterTest, UseDefaultValueWhenHeightAndWidthAreNotZero) {
const uint8_t fourcc[4] = {'V', 'P', '8', '0'};
const int kWidth = 360;
const int kHeight = 240;
const int kNumFramesToWrite = 2;
const int kNumFramesToFit = 1;
file_writer_ = IvfFileWriter::Wrap(
FileWrapper::OpenWriteOnly(file_name_),
kHeaderSize +
kNumFramesToFit * (kFrameHeaderSize + sizeof(dummy_payload)));
ASSERT_TRUE(file_writer_.get());
ASSERT_FALSE(WriteDummyTestFrames(kVideoCodecVP8, kWidth, kHeight,
kNumFramesToWrite, true));
ASSERT_FALSE(file_writer_->Close());
FileWrapper out_file = FileWrapper::OpenReadOnly(file_name_);
VerifyIvfHeader(&out_file, fourcc, kWidth, kHeight, kNumFramesToFit, true);
VerifyDummyTestFrames(&out_file, kNumFramesToFit);
out_file.Close();
}
} // namespace webrtc