blob: a304eecc93aa8c3e1415d480b04d39e6f60be0a1 [file] [log] [blame]
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "content/renderer/media/webrtc/webrtc_video_frame_adapter.h"
#include "base/logging.h"
#include "third_party/webrtc/common_video/include/video_frame_buffer.h"
#include "third_party/webrtc/rtc_base/ref_counted_object.h"
namespace {
template <typename Base>
class FrameAdapter : public Base {
public:
explicit FrameAdapter(scoped_refptr<media::VideoFrame> frame)
: frame_(std::move(frame)) {}
int width() const override { return frame_->visible_rect().width(); }
int height() const override { return frame_->visible_rect().height(); }
const uint8_t* DataY() const override {
return frame_->visible_data(media::VideoFrame::kYPlane);
}
const uint8_t* DataU() const override {
return frame_->visible_data(media::VideoFrame::kUPlane);
}
const uint8_t* DataV() const override {
return frame_->visible_data(media::VideoFrame::kVPlane);
}
int StrideY() const override {
return frame_->stride(media::VideoFrame::kYPlane);
}
int StrideU() const override {
return frame_->stride(media::VideoFrame::kUPlane);
}
int StrideV() const override {
return frame_->stride(media::VideoFrame::kVPlane);
}
protected:
scoped_refptr<media::VideoFrame> frame_;
};
template <typename BaseWithA>
class FrameAdapterWithA : public FrameAdapter<BaseWithA> {
public:
explicit FrameAdapterWithA(scoped_refptr<media::VideoFrame> frame)
: FrameAdapter<BaseWithA>(std::move(frame)) {}
const uint8_t* DataA() const override {
return FrameAdapter<BaseWithA>::frame_->visible_data(
media::VideoFrame::kAPlane);
}
int StrideA() const override {
return FrameAdapter<BaseWithA>::frame_->stride(media::VideoFrame::kAPlane);
}
};
void IsValidFrame(const media::VideoFrame& frame) {
// Paranoia checks.
DCHECK(media::VideoFrame::IsValidConfig(
frame.format(), frame.storage_type(), frame.coded_size(),
frame.visible_rect(), frame.natural_size()));
DCHECK(media::PIXEL_FORMAT_I420 == frame.format() ||
media::PIXEL_FORMAT_I420A == frame.format());
CHECK(reinterpret_cast<const void*>(frame.data(media::VideoFrame::kYPlane)));
CHECK(reinterpret_cast<const void*>(frame.data(media::VideoFrame::kUPlane)));
CHECK(reinterpret_cast<const void*>(frame.data(media::VideoFrame::kVPlane)));
CHECK(frame.stride(media::VideoFrame::kYPlane));
CHECK(frame.stride(media::VideoFrame::kUPlane));
CHECK(frame.stride(media::VideoFrame::kVPlane));
}
} // anonymous namespace
namespace content {
WebRtcVideoFrameAdapter::WebRtcVideoFrameAdapter(
const scoped_refptr<media::VideoFrame>& frame)
: frame_(frame) {}
WebRtcVideoFrameAdapter::~WebRtcVideoFrameAdapter() {
}
webrtc::VideoFrameBuffer::Type WebRtcVideoFrameAdapter::type() const {
return Type::kNative;
}
int WebRtcVideoFrameAdapter::width() const {
return frame_->visible_rect().width();
}
int WebRtcVideoFrameAdapter::height() const {
return frame_->visible_rect().height();
}
rtc::scoped_refptr<webrtc::I420BufferInterface>
WebRtcVideoFrameAdapter::ToI420() {
// We cant convert texture synchronously due to threading issues, see
// https://crbug.com/663452. Instead, return a black frame (yuv = {0, 0x80,
// 0x80}).
if (frame_->HasTextures()) {
DLOG(ERROR) << "Texture backed frame cannot be accessed.";
return new rtc::RefCountedObject<FrameAdapter<webrtc::I420BufferInterface>>(
media::VideoFrame::CreateColorFrame(frame_->visible_rect().size(), 0u,
0x80, 0x80, frame_->timestamp()));
}
IsValidFrame(*frame_);
if (media::PIXEL_FORMAT_I420A == frame_->format()) {
return new rtc::RefCountedObject<
FrameAdapterWithA<webrtc::I420ABufferInterface>>(frame_);
}
return new rtc::RefCountedObject<FrameAdapter<webrtc::I420BufferInterface>>(
frame_);
}
} // namespace content