Skip to content

Commit

Permalink
Reland "Copy video frames metadata between encoded and plain frames i…
Browse files Browse the repository at this point in the history
…n one place"

Reland with fixes.

Currently some video frames metadata like rotation or ntp timestamps are
copied in every encoder and decoder separately. This CL makes copying to
happen at a single place for send or receive side. This will make it
easier to add new metadata in the future.

Also, added some missing tests.

Original Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/133346

Bug: webrtc:10460
Change-Id: Ia71198685de7fbd990704b575231cdce94dc0645
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/134961
Reviewed-by: Johannes Kron <kron@webrtc.org>
Reviewed-by: Niels Moller <nisse@webrtc.org>
Reviewed-by: Ilya Nikolaevskiy <ilnik@webrtc.org>
Commit-Queue: Ilya Nikolaevskiy <ilnik@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#27828}
  • Loading branch information
Ilya Nikolaevskiy authored and Commit Bot committed May 2, 2019
1 parent cd936fd commit 4fb12b0
Show file tree
Hide file tree
Showing 16 changed files with 367 additions and 292 deletions.
7 changes: 7 additions & 0 deletions media/base/fake_video_renderer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,13 @@ void FakeVideoRenderer::OnFrame(const webrtc::VideoFrame& frame) {
height_ = frame.height();
rotation_ = frame.rotation();
timestamp_us_ = frame.timestamp_us();
ntp_timestamp_ms_ = frame.ntp_time_ms();
color_space_ = frame.color_space();
frame_rendered_event_.Set();
}

bool FakeVideoRenderer::WaitForRenderedFrame(int64_t timeout_ms) {
return frame_rendered_event_.Wait(timeout_ms);
}

} // namespace cricket
20 changes: 20 additions & 0 deletions media/base/fake_video_renderer.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include "api/video/video_rotation.h"
#include "api/video/video_sink_interface.h"
#include "rtc_base/critical_section.h"
#include "rtc_base/event.h"

namespace cricket {

Expand All @@ -30,6 +31,7 @@ class FakeVideoRenderer : public rtc::VideoSinkInterface<webrtc::VideoFrame> {
void OnFrame(const webrtc::VideoFrame& frame) override;

int errors() const { return errors_; }

int width() const {
rtc::CritScope cs(&crit_);
return width_;
Expand All @@ -38,6 +40,7 @@ class FakeVideoRenderer : public rtc::VideoSinkInterface<webrtc::VideoFrame> {
rtc::CritScope cs(&crit_);
return height_;
}

webrtc::VideoRotation rotation() const {
rtc::CritScope cs(&crit_);
return rotation_;
Expand All @@ -47,15 +50,29 @@ class FakeVideoRenderer : public rtc::VideoSinkInterface<webrtc::VideoFrame> {
rtc::CritScope cs(&crit_);
return timestamp_us_;
}

int num_rendered_frames() const {
rtc::CritScope cs(&crit_);
return num_rendered_frames_;
}

bool black_frame() const {
rtc::CritScope cs(&crit_);
return black_frame_;
}

int64_t ntp_time_ms() const {
rtc::CritScope cs(&crit_);
return ntp_timestamp_ms_;
}

absl::optional<webrtc::ColorSpace> color_space() const {
rtc::CritScope cs(&crit_);
return color_space_;
}

bool WaitForRenderedFrame(int64_t timeout_ms);

private:
static bool CheckFrameColorYuv(uint8_t y_min,
uint8_t y_max,
Expand Down Expand Up @@ -116,8 +133,11 @@ class FakeVideoRenderer : public rtc::VideoSinkInterface<webrtc::VideoFrame> {
webrtc::VideoRotation rotation_ = webrtc::kVideoRotation_0;
int64_t timestamp_us_ = 0;
int num_rendered_frames_ = 0;
int64_t ntp_timestamp_ms_ = 0;
bool black_frame_ = false;
rtc::CriticalSection crit_;
rtc::Event frame_rendered_event_;
absl::optional<webrtc::ColorSpace> color_space_;
};

} // namespace cricket
Expand Down
50 changes: 0 additions & 50 deletions modules/video_coding/codecs/h264/test/h264_impl_unittest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
#include "api/video_codecs/video_decoder.h"
#include "api/video_codecs/video_encoder.h"
#include "common_video/libyuv/include/webrtc_libyuv.h"
#include "common_video/test/utilities.h"
#include "media/base/codec.h"
#include "media/base/media_constants.h"
#include "modules/video_coding/codecs/h264/include/h264.h"
Expand Down Expand Up @@ -49,17 +48,9 @@ class TestH264Impl : public VideoCodecUnitTest {
#ifdef WEBRTC_USE_H264
#define MAYBE_EncodeDecode EncodeDecode
#define MAYBE_DecodedQpEqualsEncodedQp DecodedQpEqualsEncodedQp
#define MAYBE_EncodedColorSpaceEqualsInputColorSpace \
EncodedColorSpaceEqualsInputColorSpace
#define MAYBE_DecodedColorSpaceEqualsEncodedColorSpace \
DecodedColorSpaceEqualsEncodedColorSpace
#else
#define MAYBE_EncodeDecode DISABLED_EncodeDecode
#define MAYBE_DecodedQpEqualsEncodedQp DISABLED_DecodedQpEqualsEncodedQp
#define MAYBE_EncodedColorSpaceEqualsInputColorSpace \
DISABLED_EncodedColorSpaceEqualsInputColorSpace
#define MAYBE_DecodedColorSpaceEqualsEncodedColorSpace \
DISABLED_DecodedColorSpaceEqualsEncodedColorSpace
#endif

TEST_F(TestH264Impl, MAYBE_EncodeDecode) {
Expand Down Expand Up @@ -105,45 +96,4 @@ TEST_F(TestH264Impl, MAYBE_DecodedQpEqualsEncodedQp) {
EXPECT_EQ(encoded_frame.qp_, *decoded_qp);
}

TEST_F(TestH264Impl, MAYBE_EncodedColorSpaceEqualsInputColorSpace) {
VideoFrame* input_frame = NextInputFrame();
EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, encoder_->Encode(*input_frame, nullptr));
EncodedImage encoded_frame;
CodecSpecificInfo codec_specific_info;
ASSERT_TRUE(WaitForEncodedFrame(&encoded_frame, &codec_specific_info));
EXPECT_FALSE(encoded_frame.ColorSpace());

// Video frame with explicit color space information.
ColorSpace color_space = CreateTestColorSpace(/*with_hdr_metadata=*/false);
VideoFrame input_frame_w_color_space =
VideoFrame::Builder()
.set_video_frame_buffer(input_frame->video_frame_buffer())
.set_color_space(color_space)
.build();

EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK,
encoder_->Encode(input_frame_w_color_space, nullptr));
ASSERT_TRUE(WaitForEncodedFrame(&encoded_frame, &codec_specific_info));
ASSERT_TRUE(encoded_frame.ColorSpace());
EXPECT_EQ(*encoded_frame.ColorSpace(), color_space);
}

TEST_F(TestH264Impl, MAYBE_DecodedColorSpaceEqualsEncodedColorSpace) {
EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK,
encoder_->Encode(*NextInputFrame(), nullptr));
EncodedImage encoded_frame;
CodecSpecificInfo codec_specific_info;
ASSERT_TRUE(WaitForEncodedFrame(&encoded_frame, &codec_specific_info));
// Add color space to encoded frame.
ColorSpace color_space = CreateTestColorSpace(/*with_hdr_metadata=*/false);
encoded_frame.SetColorSpace(color_space);
EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, decoder_->Decode(encoded_frame, false, 0));
std::unique_ptr<VideoFrame> decoded_frame;
absl::optional<uint8_t> decoded_qp;
ASSERT_TRUE(WaitForDecodedFrame(&decoded_frame, &decoded_qp));
ASSERT_TRUE(decoded_frame);
ASSERT_TRUE(decoded_frame->color_space());
EXPECT_EQ(color_space, *decoded_frame->color_space());
}

} // namespace webrtc
60 changes: 0 additions & 60 deletions modules/video_coding/codecs/vp8/test/vp8_impl_unittest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -227,51 +227,10 @@ TEST_F(TestVp8Impl, OnEncodedImageReportsInfo) {
EncodeAndWaitForFrame(*input_frame, &encoded_frame, &codec_specific_info);

EXPECT_EQ(kInitialTimestampRtp, encoded_frame.Timestamp());
EXPECT_EQ(kInitialTimestampMs, encoded_frame.capture_time_ms_);
EXPECT_EQ(kWidth, static_cast<int>(encoded_frame._encodedWidth));
EXPECT_EQ(kHeight, static_cast<int>(encoded_frame._encodedHeight));
}

// We only test the encoder here, since the decoded frame rotation is set based
// on the CVO RTP header extension in VCMDecodedFrameCallback::Decoded.
// TODO(brandtr): Consider passing through the rotation flag through the decoder
// in the same way as done in the encoder.
TEST_F(TestVp8Impl, EncodedRotationEqualsInputRotation) {
VideoFrame* input_frame = NextInputFrame();
input_frame->set_rotation(kVideoRotation_0);

EncodedImage encoded_frame;
CodecSpecificInfo codec_specific_info;
EncodeAndWaitForFrame(*input_frame, &encoded_frame, &codec_specific_info);
EXPECT_EQ(kVideoRotation_0, encoded_frame.rotation_);

input_frame->set_rotation(kVideoRotation_90);
EncodeAndWaitForFrame(*input_frame, &encoded_frame, &codec_specific_info);
EXPECT_EQ(kVideoRotation_90, encoded_frame.rotation_);
}

TEST_F(TestVp8Impl, EncodedColorSpaceEqualsInputColorSpace) {
// Video frame without explicit color space information.
VideoFrame* input_frame = NextInputFrame();
EncodedImage encoded_frame;
CodecSpecificInfo codec_specific_info;
EncodeAndWaitForFrame(*input_frame, &encoded_frame, &codec_specific_info);
EXPECT_FALSE(encoded_frame.ColorSpace());

// Video frame with explicit color space information.
ColorSpace color_space = CreateTestColorSpace(/*with_hdr_metadata=*/false);
VideoFrame input_frame_w_color_space =
VideoFrame::Builder()
.set_video_frame_buffer(input_frame->video_frame_buffer())
.set_color_space(color_space)
.build();

EncodeAndWaitForFrame(input_frame_w_color_space, &encoded_frame,
&codec_specific_info);
ASSERT_TRUE(encoded_frame.ColorSpace());
EXPECT_EQ(*encoded_frame.ColorSpace(), color_space);
}

TEST_F(TestVp8Impl, DecodedQpEqualsEncodedQp) {
VideoFrame* input_frame = NextInputFrame();
EncodedImage encoded_frame;
Expand All @@ -290,24 +249,6 @@ TEST_F(TestVp8Impl, DecodedQpEqualsEncodedQp) {
EXPECT_EQ(encoded_frame.qp_, *decoded_qp);
}

TEST_F(TestVp8Impl, DecodedColorSpaceEqualsEncodedColorSpace) {
VideoFrame* input_frame = NextInputFrame();
EncodedImage encoded_frame;
CodecSpecificInfo codec_specific_info;
EncodeAndWaitForFrame(*input_frame, &encoded_frame, &codec_specific_info);

// Encoded frame with explicit color space information.
ColorSpace color_space = CreateTestColorSpace(/*with_hdr_metadata=*/false);
encoded_frame.SetColorSpace(color_space);
EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, decoder_->Decode(encoded_frame, false, -1));
std::unique_ptr<VideoFrame> decoded_frame;
absl::optional<uint8_t> decoded_qp;
ASSERT_TRUE(WaitForDecodedFrame(&decoded_frame, &decoded_qp));
ASSERT_TRUE(decoded_frame);
ASSERT_TRUE(decoded_frame->color_space());
EXPECT_EQ(color_space, *decoded_frame->color_space());
}

TEST_F(TestVp8Impl, ChecksSimulcastSettings) {
codec_settings_.numberOfSimulcastStreams = 2;
// Resolutions are not in ascending order, temporal layers do not match.
Expand Down Expand Up @@ -402,7 +343,6 @@ TEST_F(TestVp8Impl, MAYBE_AlignedStrideEncodeDecode) {
// Compute PSNR on all planes (faster than SSIM).
EXPECT_GT(I420PSNR(input_frame, decoded_frame.get()), 36);
EXPECT_EQ(kInitialTimestampRtp, decoded_frame->timestamp());
EXPECT_EQ(kTestNtpTimeMs, decoded_frame->ntp_time_ms());
}

#if defined(WEBRTC_ANDROID)
Expand Down
55 changes: 1 addition & 54 deletions modules/video_coding/codecs/vp9/test/vp9_impl_unittest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
#include "api/video/color_space.h"
#include "api/video/i420_buffer.h"
#include "common_video/libyuv/include/webrtc_libyuv.h"
#include "common_video/test/utilities.h"
#include "media/base/vp9_profile.h"
#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
#include "modules/video_coding/codecs/test/video_codec_unittest.h"
Expand Down Expand Up @@ -146,50 +145,7 @@ TEST_F(TestVp9Impl, EncodeDecode) {
color_space.chroma_siting_vertical());
}

// We only test the encoder here, since the decoded frame rotation is set based
// on the CVO RTP header extension in VCMDecodedFrameCallback::Decoded.
// TODO(brandtr): Consider passing through the rotation flag through the decoder
// in the same way as done in the encoder.
TEST_F(TestVp9Impl, EncodedRotationEqualsInputRotation) {
VideoFrame* input_frame = NextInputFrame();
input_frame->set_rotation(kVideoRotation_0);
EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, encoder_->Encode(*input_frame, nullptr));
EncodedImage encoded_frame;
CodecSpecificInfo codec_specific_info;
ASSERT_TRUE(WaitForEncodedFrame(&encoded_frame, &codec_specific_info));
EXPECT_EQ(kVideoRotation_0, encoded_frame.rotation_);

input_frame = NextInputFrame();
input_frame->set_rotation(kVideoRotation_90);
EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, encoder_->Encode(*input_frame, nullptr));
ASSERT_TRUE(WaitForEncodedFrame(&encoded_frame, &codec_specific_info));
EXPECT_EQ(kVideoRotation_90, encoded_frame.rotation_);
}

TEST_F(TestVp9Impl, EncodedColorSpaceEqualsInputColorSpace) {
// Video frame without explicit color space information.
VideoFrame* input_frame = NextInputFrame();
EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, encoder_->Encode(*input_frame, nullptr));
EncodedImage encoded_frame;
CodecSpecificInfo codec_specific_info;
ASSERT_TRUE(WaitForEncodedFrame(&encoded_frame, &codec_specific_info));
EXPECT_FALSE(encoded_frame.ColorSpace());

// Video frame with explicit color space information.
ColorSpace color_space = CreateTestColorSpace(/*with_hdr_metadata=*/true);
VideoFrame input_frame_w_hdr =
VideoFrame::Builder()
.set_video_frame_buffer(input_frame->video_frame_buffer())
.set_color_space(color_space)
.build();
EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK,
encoder_->Encode(input_frame_w_hdr, nullptr));
ASSERT_TRUE(WaitForEncodedFrame(&encoded_frame, &codec_specific_info));
ASSERT_TRUE(encoded_frame.ColorSpace());
EXPECT_EQ(*encoded_frame.ColorSpace(), color_space);
}

TEST_F(TestVp9Impl, DecodedColorSpaceEqualsEncodedColorSpace) {
TEST_F(TestVp9Impl, DecodedColorSpaceFromBitstream) {
EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK,
encoder_->Encode(*NextInputFrame(), nullptr));
EncodedImage encoded_frame;
Expand All @@ -206,15 +162,6 @@ TEST_F(TestVp9Impl, DecodedColorSpaceEqualsEncodedColorSpace) {
ASSERT_TRUE(decoded_frame->color_space());
// No HDR metadata present.
EXPECT_FALSE(decoded_frame->color_space()->hdr_metadata());

// Encoded frame with explicit color space information.
ColorSpace color_space = CreateTestColorSpace(/*with_hdr_metadata=*/true);
encoded_frame.SetColorSpace(color_space);
EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, decoder_->Decode(encoded_frame, false, 0));
ASSERT_TRUE(WaitForDecodedFrame(&decoded_frame, &decoded_qp));
ASSERT_TRUE(decoded_frame);
ASSERT_TRUE(decoded_frame->color_space());
EXPECT_EQ(color_space, *decoded_frame->color_space());
}

TEST_F(TestVp9Impl, DecodedQpEqualsEncodedQp) {
Expand Down
2 changes: 2 additions & 0 deletions modules/video_coding/encoded_frame.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,10 @@ class VCMEncodedFrame : protected EncodedImage {
return static_cast<const webrtc::EncodedImage&>(*this);
}

using EncodedImage::ColorSpace;
using EncodedImage::data;
using EncodedImage::set_size;
using EncodedImage::SetColorSpace;
using EncodedImage::SetSpatialIndex;
using EncodedImage::SetTimestamp;
using EncodedImage::size;
Expand Down
10 changes: 9 additions & 1 deletion modules/video_coding/generic_decoder.cc
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,12 @@ void VCMDecodedFrameCallback::Decoded(VideoFrame& decodedImage,
return;
}

decodedImage.set_ntp_time_ms(frameInfo->ntp_time_ms);
if (frameInfo->color_space) {
decodedImage.set_color_space(*frameInfo->color_space);
}
decodedImage.set_rotation(frameInfo->rotation);

const int64_t now_ms = _clock->TimeInMilliseconds();
if (!decode_time_ms) {
decode_time_ms = now_ms - frameInfo->decodeStartTimeMs;
Expand Down Expand Up @@ -140,7 +146,6 @@ void VCMDecodedFrameCallback::Decoded(VideoFrame& decodedImage,

decodedImage.set_timestamp_us(frameInfo->renderTimeMs *
rtc::kNumMicrosecsPerMillisec);
decodedImage.set_rotation(frameInfo->rotation);
_receiveCallback->FrameToRender(decodedImage, qp, frameInfo->content_type);
}

Expand Down Expand Up @@ -199,6 +204,9 @@ int32_t VCMGenericDecoder::Decode(const VCMEncodedFrame& frame, int64_t nowMs) {
_frameInfos[_nextFrameInfoIdx].renderTimeMs = frame.RenderTimeMs();
_frameInfos[_nextFrameInfoIdx].rotation = frame.rotation();
_frameInfos[_nextFrameInfoIdx].timing = frame.video_timing();
_frameInfos[_nextFrameInfoIdx].ntp_time_ms =
frame.EncodedImage().ntp_time_ms_;
_frameInfos[_nextFrameInfoIdx].color_space = frame.ColorSpace();
// Set correctly only for key frames. Thus, use latest key frame
// content type. If the corresponding key frame was lost, decode will fail
// and content type will be ignored.
Expand Down
2 changes: 2 additions & 0 deletions modules/video_coding/generic_decoder.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ struct VCMFrameInformation {
VideoRotation rotation;
VideoContentType content_type;
EncodedImage::Timing timing;
int64_t ntp_time_ms;
const ColorSpace* color_space;
};

class VCMDecodedFrameCallback : public DecodedImageCallback {
Expand Down
13 changes: 7 additions & 6 deletions test/fake_decoder.cc
Original file line number Diff line number Diff line change
Expand Up @@ -45,12 +45,13 @@ int32_t FakeDecoder::Decode(const EncodedImage& input,
height_ = input._encodedHeight;
}

VideoFrame frame =
VideoFrame::Builder()
.set_video_frame_buffer(I420Buffer::Create(width_, height_))
.set_rotation(webrtc::kVideoRotation_0)
.set_timestamp_ms(render_time_ms)
.build();
rtc::scoped_refptr<I420Buffer> buffer = I420Buffer::Create(width_, height_);
I420Buffer::SetBlack(buffer);
VideoFrame frame = VideoFrame::Builder()
.set_video_frame_buffer(buffer)
.set_rotation(webrtc::kVideoRotation_0)
.set_timestamp_ms(render_time_ms)
.build();
frame.set_timestamp(input.Timestamp());
frame.set_ntp_time_ms(input.ntp_time_ms_);

Expand Down
Loading

0 comments on commit 4fb12b0

Please sign in to comment.