webrtc/media/base/adapted_video_track_source.cc
Ilya Nikolaevskiy 4fc0855a39 Cleanup video frame metadata copying
In several places VideoFrame::Builder is used to create a new VideoFrame
when intent is to change only one or two fields of a const VideoFrame&.

This approach is bad because each and every metadata field have to be
added to all the places.

Instead, this CL adds missing setters and refactors the code to use
full copy of a VideoFrame and update required fields only.

Along the way few actual bugs are fixed, e.g. when ColorSpace isn't copied
when frame rotation or buffer is cropped or converted.

Bug: webrtc:10460
Change-Id: I2895a473ca938b150eed2916c689060bdf58cb25
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/140102
Reviewed-by: Niels Moller <nisse@webrtc.org>
Commit-Queue: Ilya Nikolaevskiy <ilnik@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#28170}
2019-06-05 15:05:57 +00:00

118 lines
3.9 KiB
C++

/*
* Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "media/base/adapted_video_track_source.h"
#include "api/scoped_refptr.h"
#include "api/video/i420_buffer.h"
#include "api/video/video_frame_buffer.h"
#include "api/video/video_rotation.h"
#include "rtc_base/checks.h"
#include "rtc_base/time_utils.h"
namespace rtc {
AdaptedVideoTrackSource::AdaptedVideoTrackSource() = default;
AdaptedVideoTrackSource::AdaptedVideoTrackSource(int required_alignment)
: video_adapter_(required_alignment) {}
AdaptedVideoTrackSource::~AdaptedVideoTrackSource() = default;
bool AdaptedVideoTrackSource::GetStats(Stats* stats) {
rtc::CritScope lock(&stats_crit_);
if (!stats_) {
return false;
}
*stats = *stats_;
return true;
}
void AdaptedVideoTrackSource::OnFrame(const webrtc::VideoFrame& frame) {
rtc::scoped_refptr<webrtc::VideoFrameBuffer> buffer(
frame.video_frame_buffer());
/* Note that this is a "best effort" approach to
wants.rotation_applied; apply_rotation_ can change from false to
true between the check of apply_rotation() and the call to
broadcaster_.OnFrame(), in which case we generate a frame with
pending rotation despite some sink with wants.rotation_applied ==
true was just added. The VideoBroadcaster enforces
synchronization for us in this case, by not passing the frame on
to sinks which don't want it. */
if (apply_rotation() && frame.rotation() != webrtc::kVideoRotation_0 &&
buffer->type() == webrtc::VideoFrameBuffer::Type::kI420) {
/* Apply pending rotation. */
webrtc::VideoFrame rotated_frame(frame);
rotated_frame.set_video_frame_buffer(
webrtc::I420Buffer::Rotate(*buffer->GetI420(), frame.rotation()));
rotated_frame.set_rotation(webrtc::kVideoRotation_0);
broadcaster_.OnFrame(rotated_frame);
} else {
broadcaster_.OnFrame(frame);
}
}
void AdaptedVideoTrackSource::AddOrUpdateSink(
rtc::VideoSinkInterface<webrtc::VideoFrame>* sink,
const rtc::VideoSinkWants& wants) {
broadcaster_.AddOrUpdateSink(sink, wants);
OnSinkWantsChanged(broadcaster_.wants());
}
void AdaptedVideoTrackSource::RemoveSink(
rtc::VideoSinkInterface<webrtc::VideoFrame>* sink) {
broadcaster_.RemoveSink(sink);
OnSinkWantsChanged(broadcaster_.wants());
}
bool AdaptedVideoTrackSource::apply_rotation() {
return broadcaster_.wants().rotation_applied;
}
void AdaptedVideoTrackSource::OnSinkWantsChanged(
const rtc::VideoSinkWants& wants) {
video_adapter_.OnResolutionFramerateRequest(
wants.target_pixel_count, wants.max_pixel_count, wants.max_framerate_fps);
}
bool AdaptedVideoTrackSource::AdaptFrame(int width,
int height,
int64_t time_us,
int* out_width,
int* out_height,
int* crop_width,
int* crop_height,
int* crop_x,
int* crop_y) {
{
rtc::CritScope lock(&stats_crit_);
stats_ = Stats{width, height};
}
if (!broadcaster_.frame_wanted()) {
return false;
}
if (!video_adapter_.AdaptFrameResolution(
width, height, time_us * rtc::kNumNanosecsPerMicrosec, crop_width,
crop_height, out_width, out_height)) {
broadcaster_.OnDiscardedFrame();
// VideoAdapter dropped the frame.
return false;
}
*crop_x = (width - *crop_width) / 2;
*crop_y = (height - *crop_height) / 2;
return true;
}
} // namespace rtc