blob: 36f1e02a1ebd93e6b0f58b3d922b6eaf8a174154 [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>
avi5a080f012015-12-22 23:15:438#include <stdint.h>
[email protected]82156e82011-12-20 07:09:019
[email protected]1e1cb3b2011-11-10 02:07:4110#include "base/logging.h"
dcheng0765c492016-04-06 22:41:5311#include "base/memory/ptr_util.h"
[email protected]c3af26f332010-10-06 22:46:0012#include "remoting/base/util.h"
sergeyuef92de202015-08-20 22:47:3713#include "remoting/proto/video.pb.h"
[email protected]0dd9fb62014-05-26 16:24:4914#include "third_party/libyuv/include/libyuv/convert_argb.h"
Frank Barchard638ac13f62016-07-12 22:43:0115#include "third_party/libyuv/include/libyuv/convert_from.h"
sergeyuef92de202015-08-20 22:47:3716#include "third_party/webrtc/modules/desktop_capture/desktop_frame.h"
17#include "third_party/webrtc/modules/desktop_capture/desktop_geometry.h"
18#include "third_party/webrtc/modules/desktop_capture/desktop_region.h"
[email protected]622b7882010-09-29 17:34:3219
20extern "C" {
21#define VPX_CODEC_DISABLE_COMPAT 1
johannkoenig8cdf03472016-03-02 13:54:3122#include "third_party/libvpx/source/libvpx/vpx/vp8dx.h"
23#include "third_party/libvpx/source/libvpx/vpx/vpx_decoder.h"
[email protected]622b7882010-09-29 17:34:3224}
25
26namespace remoting {
27
sergeyuef92de202015-08-20 22:47:3728namespace {
29
30void RenderRect(vpx_image_t* image,
31 webrtc::DesktopRect rect,
sergeyu4ba8b732016-06-24 05:51:3232 VideoDecoder::PixelFormat pixel_format,
sergeyuef92de202015-08-20 22:47:3733 webrtc::DesktopFrame* frame) {
sergeyu4ba8b732016-06-24 05:51:3234 auto yuv_to_rgb_function = libyuv::I420ToARGB;
35 int u_offset;
36 int v_offset;
37
sergeyuef92de202015-08-20 22:47:3738 switch (image->fmt) {
39 case VPX_IMG_FMT_I420: {
40 // Align position of the top left corner so that its coordinates are
41 // always even.
42 rect = webrtc::DesktopRect::MakeLTRB(rect.left() & ~1, rect.top() & ~1,
43 rect.right(), rect.bottom());
sergeyu4ba8b732016-06-24 05:51:3244 u_offset = rect.top() / 2 * image->stride[1] + rect.left() / 2;
45 v_offset = rect.top() / 2 * image->stride[2] + rect.left() / 2;
46 yuv_to_rgb_function = (pixel_format == VideoDecoder::PixelFormat::BGRA)
47 ? libyuv::I420ToARGB
48 : libyuv::I420ToABGR;
sergeyuef92de202015-08-20 22:47:3749 break;
50 }
51 // VP8 only outputs I420 frames, but VP9 can also produce I444.
52 case VPX_IMG_FMT_I444: {
sergeyu4ba8b732016-06-24 05:51:3253 u_offset = rect.top() * image->stride[1] + rect.left();
54 v_offset = rect.top() * image->stride[2] + rect.left();
55 yuv_to_rgb_function = (pixel_format == VideoDecoder::PixelFormat::BGRA)
56 ? libyuv::I444ToARGB
57 : libyuv::I444ToABGR;
sergeyuef92de202015-08-20 22:47:3758 break;
59 }
60 default: {
61 LOG(ERROR) << "Unsupported image format:" << image->fmt;
62 return;
63 }
64 }
sergeyu4ba8b732016-06-24 05:51:3265
66 int y_offset = rect.top() * image->stride[0] + rect.left();
67 uint8_t* image_data_ptr = frame->GetFrameDataAtPos(rect.top_left());
68 yuv_to_rgb_function(image->planes[0] + y_offset, image->stride[0],
69 image->planes[1] + u_offset, image->stride[1],
70 image->planes[2] + v_offset, image->stride[2],
71 image_data_ptr, frame->stride(), rect.width(),
72 rect.height());
sergeyuef92de202015-08-20 22:47:3773}
74
75} // namespace
76
[email protected]a43cfae2013-10-19 22:14:5477// static
dcheng0765c492016-04-06 22:41:5378std::unique_ptr<VideoDecoderVpx> VideoDecoderVpx::CreateForVP8() {
79 return base::WrapUnique(new VideoDecoderVpx(vpx_codec_vp8_dx()));
[email protected]a43cfae2013-10-19 22:14:5480}
81
[email protected]87196ce2013-10-22 01:53:3982// static
dcheng0765c492016-04-06 22:41:5383std::unique_ptr<VideoDecoderVpx> VideoDecoderVpx::CreateForVP9() {
84 return base::WrapUnique(new VideoDecoderVpx(vpx_codec_vp9_dx()));
[email protected]87196ce2013-10-22 01:53:3985}
86
Chris Watkins6fe52aa2017-11-28 03:24:0587VideoDecoderVpx::~VideoDecoderVpx() = default;
[email protected]a43cfae2013-10-19 22:14:5488
sergeyu4ba8b732016-06-24 05:51:3289void VideoDecoderVpx::SetPixelFormat(PixelFormat pixel_format) {
90 pixel_format_ = pixel_format;
91}
92
sergeyuef92de202015-08-20 22:47:3793bool VideoDecoderVpx::DecodePacket(const VideoPacket& packet,
94 webrtc::DesktopFrame* frame) {
wez070889b2015-07-17 03:19:1595 // Pass the packet to the codec to process.
[email protected]622b7882010-09-29 17:34:3296 vpx_codec_err_t ret = vpx_codec_decode(
avi5a080f012015-12-22 23:15:4397 codec_.get(), reinterpret_cast<const uint8_t*>(packet.data().data()),
wez9ad574b22015-07-14 16:24:5398 packet.data().size(), nullptr, 0);
[email protected]622b7882010-09-29 17:34:3299 if (ret != VPX_CODEC_OK) {
[email protected]1fd715b2014-04-09 04:13:04100 const char* error = vpx_codec_error(codec_.get());
101 const char* error_detail = vpx_codec_error_detail(codec_.get());
102 LOG(ERROR) << "Decoding failed:" << (error ? error : "(NULL)") << "\n"
103 << "Details: " << (error_detail ? error_detail : "(NULL)");
[email protected]41b93ad32013-09-23 18:53:52104 return false;
[email protected]622b7882010-09-29 17:34:32105 }
106
wez070889b2015-07-17 03:19:15107 // Fetch the decoded video frame.
wez9ad574b22015-07-14 16:24:53108 vpx_codec_iter_t iter = nullptr;
sergeyuef92de202015-08-20 22:47:37109 vpx_image_t* image = vpx_codec_get_frame(codec_.get(), &iter);
110 if (!image) {
111 LOG(ERROR) << "No video frame decoded.";
[email protected]41b93ad32013-09-23 18:53:52112 return false;
[email protected]622b7882010-09-29 17:34:32113 }
sergeyuef92de202015-08-20 22:47:37114 if (!webrtc::DesktopSize(image->d_w, image->d_h).equals(frame->size())) {
115 LOG(ERROR) << "Size of the encoded frame doesn't match size in the header.";
116 return false;
117 }
[email protected]622b7882010-09-29 17:34:32118
wez070889b2015-07-17 03:19:15119 // Determine which areas have been updated.
sergeyuef92de202015-08-20 22:47:37120 webrtc::DesktopRegion* region = frame->mutable_updated_region();
121 region->Clear();
[email protected]41b93ad32013-09-23 18:53:52122 for (int i = 0; i < packet.dirty_rects_size(); ++i) {
sergeyuef92de202015-08-20 22:47:37123 Rect proto_rect = packet.dirty_rects(i);
124 webrtc::DesktopRect rect =
125 webrtc::DesktopRect::MakeXYWH(proto_rect.x(), proto_rect.y(),
126 proto_rect.width(), proto_rect.height());
127 region->AddRect(rect);
sergeyu4ba8b732016-06-24 05:51:32128 RenderRect(image, rect, pixel_format_, frame);
[email protected]50686142011-02-04 02:08:32129 }
[email protected]da4daa7f2013-06-21 10:16:41130
[email protected]41b93ad32013-09-23 18:53:52131 return true;
[email protected]622b7882010-09-29 17:34:32132}
133
sergeyuef92de202015-08-20 22:47:37134VideoDecoderVpx::VideoDecoderVpx(vpx_codec_iface_t* codec) {
wez070889b2015-07-17 03:19:15135 codec_.reset(new vpx_codec_ctx_t);
136
137 vpx_codec_dec_cfg config;
138 config.w = 0;
139 config.h = 0;
140 config.threads = 2;
141 vpx_codec_err_t ret = vpx_codec_dec_init(codec_.get(), codec, &config, 0);
142 CHECK_EQ(VPX_CODEC_OK, ret);
[email protected]da4daa7f2013-06-21 10:16:41143}
144
[email protected]622b7882010-09-29 17:34:32145} // namespace remoting