blob: cba3b208c85d5cac92168b8a3ba1b1c31f67ba2e [file] [log] [blame]
[email protected]a43cfae2013-10-19 22:14:541// Copyright 2013 The Chromium Authors. All rights reserved.
[email protected]622b7882010-09-29 17:34:322// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
[email protected]a43cfae2013-10-19 22:14:545#include "remoting/codec/video_decoder_vpx.h"
[email protected]622b7882010-09-29 17:34:326
[email protected]82156e82011-12-20 07:09:017#include <math.h>
8
[email protected]1e1cb3b2011-11-10 02:07:419#include "base/logging.h"
[email protected]c3af26f332010-10-06 22:46:0010#include "remoting/base/util.h"
sergeyuef92de202015-08-20 22:47:3711#include "remoting/proto/video.pb.h"
[email protected]0dd9fb62014-05-26 16:24:4912#include "third_party/libyuv/include/libyuv/convert_argb.h"
sergeyuef92de202015-08-20 22:47:3713#include "third_party/webrtc/modules/desktop_capture/desktop_frame.h"
14#include "third_party/webrtc/modules/desktop_capture/desktop_geometry.h"
15#include "third_party/webrtc/modules/desktop_capture/desktop_region.h"
[email protected]622b7882010-09-29 17:34:3216
17extern "C" {
18#define VPX_CODEC_DISABLE_COMPAT 1
[email protected]d6ab6e852013-01-07 17:03:0419#include "third_party/libvpx/source/libvpx/vpx/vpx_decoder.h"
20#include "third_party/libvpx/source/libvpx/vpx/vp8dx.h"
[email protected]622b7882010-09-29 17:34:3221}
22
23namespace remoting {
24
sergeyuef92de202015-08-20 22:47:3725namespace {
26
27void RenderRect(vpx_image_t* image,
28 webrtc::DesktopRect rect,
29 webrtc::DesktopFrame* frame) {
30 switch (image->fmt) {
31 case VPX_IMG_FMT_I420: {
32 // Align position of the top left corner so that its coordinates are
33 // always even.
34 rect = webrtc::DesktopRect::MakeLTRB(rect.left() & ~1, rect.top() & ~1,
35 rect.right(), rect.bottom());
36 uint8_t* image_data_ptr = frame->GetFrameDataAtPos(rect.top_left());
37 int y_offset = rect.top() * image->stride[0] + rect.left();
38 int u_offset = rect.top() / 2 * image->stride[1] + rect.left() / 2;
39 int v_offset = rect.top() / 2 * image->stride[2] + rect.left() / 2;
40 libyuv::I420ToARGB(image->planes[0] + y_offset, image->stride[0],
41 image->planes[1] + u_offset, image->stride[1],
42 image->planes[2] + v_offset, image->stride[2],
43 image_data_ptr, frame->stride(),
44 rect.width(), rect.height());
45 break;
46 }
47 // VP8 only outputs I420 frames, but VP9 can also produce I444.
48 case VPX_IMG_FMT_I444: {
49 uint8_t* image_data_ptr = frame->GetFrameDataAtPos(rect.top_left());
50 int y_offset = rect.top() * image->stride[0] + rect.left();
51 int u_offset = rect.top() * image->stride[1] + rect.left();
52 int v_offset = rect.top() * image->stride[2] + rect.left();
53 libyuv::I444ToARGB(image->planes[0] + y_offset, image->stride[0],
54 image->planes[1] + u_offset, image->stride[1],
55 image->planes[2] + v_offset, image->stride[2],
56 image_data_ptr, frame->stride(),
57 rect.width(), rect.height());
58 break;
59 }
60 default: {
61 LOG(ERROR) << "Unsupported image format:" << image->fmt;
62 return;
63 }
64 }
65}
66
67} // namespace
68
[email protected]a43cfae2013-10-19 22:14:5469// static
70scoped_ptr<VideoDecoderVpx> VideoDecoderVpx::CreateForVP8() {
wez070889b2015-07-17 03:19:1571 return make_scoped_ptr(new VideoDecoderVpx(vpx_codec_vp8_dx()));
[email protected]a43cfae2013-10-19 22:14:5472}
73
[email protected]87196ce2013-10-22 01:53:3974// static
75scoped_ptr<VideoDecoderVpx> VideoDecoderVpx::CreateForVP9() {
wez070889b2015-07-17 03:19:1576 return make_scoped_ptr(new VideoDecoderVpx(vpx_codec_vp9_dx()));
[email protected]87196ce2013-10-22 01:53:3977}
78
[email protected]a43cfae2013-10-19 22:14:5479VideoDecoderVpx::~VideoDecoderVpx() {}
80
sergeyuef92de202015-08-20 22:47:3781bool VideoDecoderVpx::DecodePacket(const VideoPacket& packet,
82 webrtc::DesktopFrame* frame) {
wez070889b2015-07-17 03:19:1583 // Pass the packet to the codec to process.
[email protected]622b7882010-09-29 17:34:3284 vpx_codec_err_t ret = vpx_codec_decode(
[email protected]a43cfae2013-10-19 22:14:5485 codec_.get(), reinterpret_cast<const uint8*>(packet.data().data()),
wez9ad574b22015-07-14 16:24:5386 packet.data().size(), nullptr, 0);
[email protected]622b7882010-09-29 17:34:3287 if (ret != VPX_CODEC_OK) {
[email protected]1fd715b2014-04-09 04:13:0488 const char* error = vpx_codec_error(codec_.get());
89 const char* error_detail = vpx_codec_error_detail(codec_.get());
90 LOG(ERROR) << "Decoding failed:" << (error ? error : "(NULL)") << "\n"
91 << "Details: " << (error_detail ? error_detail : "(NULL)");
[email protected]41b93ad32013-09-23 18:53:5292 return false;
[email protected]622b7882010-09-29 17:34:3293 }
94
wez070889b2015-07-17 03:19:1595 // Fetch the decoded video frame.
wez9ad574b22015-07-14 16:24:5396 vpx_codec_iter_t iter = nullptr;
sergeyuef92de202015-08-20 22:47:3797 vpx_image_t* image = vpx_codec_get_frame(codec_.get(), &iter);
98 if (!image) {
99 LOG(ERROR) << "No video frame decoded.";
[email protected]41b93ad32013-09-23 18:53:52100 return false;
[email protected]622b7882010-09-29 17:34:32101 }
sergeyuef92de202015-08-20 22:47:37102 if (!webrtc::DesktopSize(image->d_w, image->d_h).equals(frame->size())) {
103 LOG(ERROR) << "Size of the encoded frame doesn't match size in the header.";
104 return false;
105 }
[email protected]622b7882010-09-29 17:34:32106
wez070889b2015-07-17 03:19:15107 // Determine which areas have been updated.
sergeyuef92de202015-08-20 22:47:37108 webrtc::DesktopRegion* region = frame->mutable_updated_region();
109 region->Clear();
[email protected]41b93ad32013-09-23 18:53:52110 for (int i = 0; i < packet.dirty_rects_size(); ++i) {
sergeyuef92de202015-08-20 22:47:37111 Rect proto_rect = packet.dirty_rects(i);
112 webrtc::DesktopRect rect =
113 webrtc::DesktopRect::MakeXYWH(proto_rect.x(), proto_rect.y(),
114 proto_rect.width(), proto_rect.height());
115 region->AddRect(rect);
116 RenderRect(image, rect, frame);
[email protected]50686142011-02-04 02:08:32117 }
[email protected]da4daa7f2013-06-21 10:16:41118
wez070889b2015-07-17 03:19:15119 // Process the frame shape, if supplied.
[email protected]41b93ad32013-09-23 18:53:52120 if (packet.has_use_desktop_shape()) {
wez070889b2015-07-17 03:19:15121 if (packet.use_desktop_shape()) {
122 if (!desktop_shape_)
123 desktop_shape_ = make_scoped_ptr(new webrtc::DesktopRegion);
124 desktop_shape_->Clear();
125 for (int i = 0; i < packet.desktop_shape_rects_size(); ++i) {
sergeyuef92de202015-08-20 22:47:37126 Rect proto_rect = packet.desktop_shape_rects(i);
wez070889b2015-07-17 03:19:15127 desktop_shape_->AddRect(webrtc::DesktopRect::MakeXYWH(
sergeyuef92de202015-08-20 22:47:37128 proto_rect.x(), proto_rect.y(), proto_rect.width(),
129 proto_rect.height()));
wez070889b2015-07-17 03:19:15130 }
131 } else {
132 desktop_shape_.reset();
[email protected]da4daa7f2013-06-21 10:16:41133 }
[email protected]da4daa7f2013-06-21 10:16:41134 }
135
sergeyuef92de202015-08-20 22:47:37136 if (desktop_shape_)
137 frame->set_shape(new webrtc::DesktopRegion(*desktop_shape_));
138
[email protected]41b93ad32013-09-23 18:53:52139 return true;
[email protected]622b7882010-09-29 17:34:32140}
141
sergeyuef92de202015-08-20 22:47:37142VideoDecoderVpx::VideoDecoderVpx(vpx_codec_iface_t* codec) {
wez070889b2015-07-17 03:19:15143 codec_.reset(new vpx_codec_ctx_t);
144
145 vpx_codec_dec_cfg config;
146 config.w = 0;
147 config.h = 0;
148 config.threads = 2;
149 vpx_codec_err_t ret = vpx_codec_dec_init(codec_.get(), codec, &config, 0);
150 CHECK_EQ(VPX_CODEC_OK, ret);
[email protected]da4daa7f2013-06-21 10:16:41151}
152
[email protected]622b7882010-09-29 17:34:32153} // namespace remoting