OLD | NEW |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "remoting/codec/video_decoder_vpx.h" | 5 #include "remoting/codec/video_decoder_vpx.h" |
6 | 6 |
7 #include <math.h> | 7 #include <math.h> |
8 #include <stdint.h> | 8 #include <stdint.h> |
9 | 9 |
10 #include "base/logging.h" | 10 #include "base/logging.h" |
(...skipping 10 matching lines...) Expand all Loading... |
21 #include "third_party/libvpx/source/libvpx/vpx/vp8dx.h" | 21 #include "third_party/libvpx/source/libvpx/vpx/vp8dx.h" |
22 #include "third_party/libvpx/source/libvpx/vpx/vpx_decoder.h" | 22 #include "third_party/libvpx/source/libvpx/vpx/vpx_decoder.h" |
23 } | 23 } |
24 | 24 |
25 namespace remoting { | 25 namespace remoting { |
26 | 26 |
27 namespace { | 27 namespace { |
28 | 28 |
29 void RenderRect(vpx_image_t* image, | 29 void RenderRect(vpx_image_t* image, |
30 webrtc::DesktopRect rect, | 30 webrtc::DesktopRect rect, |
| 31 VideoDecoder::PixelFormat pixel_format, |
31 webrtc::DesktopFrame* frame) { | 32 webrtc::DesktopFrame* frame) { |
| 33 auto yuv_to_rgb_function = libyuv::I420ToARGB; |
| 34 int u_offset; |
| 35 int v_offset; |
| 36 |
32 switch (image->fmt) { | 37 switch (image->fmt) { |
33 case VPX_IMG_FMT_I420: { | 38 case VPX_IMG_FMT_I420: { |
34 // Align position of the top left corner so that its coordinates are | 39 // Align position of the top left corner so that its coordinates are |
35 // always even. | 40 // always even. |
36 rect = webrtc::DesktopRect::MakeLTRB(rect.left() & ~1, rect.top() & ~1, | 41 rect = webrtc::DesktopRect::MakeLTRB(rect.left() & ~1, rect.top() & ~1, |
37 rect.right(), rect.bottom()); | 42 rect.right(), rect.bottom()); |
38 uint8_t* image_data_ptr = frame->GetFrameDataAtPos(rect.top_left()); | 43 u_offset = rect.top() / 2 * image->stride[1] + rect.left() / 2; |
39 int y_offset = rect.top() * image->stride[0] + rect.left(); | 44 v_offset = rect.top() / 2 * image->stride[2] + rect.left() / 2; |
40 int u_offset = rect.top() / 2 * image->stride[1] + rect.left() / 2; | 45 yuv_to_rgb_function = (pixel_format == VideoDecoder::PixelFormat::BGRA) |
41 int v_offset = rect.top() / 2 * image->stride[2] + rect.left() / 2; | 46 ? libyuv::I420ToARGB |
42 libyuv::I420ToARGB(image->planes[0] + y_offset, image->stride[0], | 47 : libyuv::I420ToABGR; |
43 image->planes[1] + u_offset, image->stride[1], | |
44 image->planes[2] + v_offset, image->stride[2], | |
45 image_data_ptr, frame->stride(), | |
46 rect.width(), rect.height()); | |
47 break; | 48 break; |
48 } | 49 } |
49 // VP8 only outputs I420 frames, but VP9 can also produce I444. | 50 // VP8 only outputs I420 frames, but VP9 can also produce I444. |
50 case VPX_IMG_FMT_I444: { | 51 case VPX_IMG_FMT_I444: { |
51 uint8_t* image_data_ptr = frame->GetFrameDataAtPos(rect.top_left()); | 52 u_offset = rect.top() * image->stride[1] + rect.left(); |
52 int y_offset = rect.top() * image->stride[0] + rect.left(); | 53 v_offset = rect.top() * image->stride[2] + rect.left(); |
53 int u_offset = rect.top() * image->stride[1] + rect.left(); | 54 yuv_to_rgb_function = (pixel_format == VideoDecoder::PixelFormat::BGRA) |
54 int v_offset = rect.top() * image->stride[2] + rect.left(); | 55 ? libyuv::I444ToARGB |
55 libyuv::I444ToARGB(image->planes[0] + y_offset, image->stride[0], | 56 : libyuv::I444ToABGR; |
56 image->planes[1] + u_offset, image->stride[1], | |
57 image->planes[2] + v_offset, image->stride[2], | |
58 image_data_ptr, frame->stride(), | |
59 rect.width(), rect.height()); | |
60 break; | 57 break; |
61 } | 58 } |
62 default: { | 59 default: { |
63 LOG(ERROR) << "Unsupported image format:" << image->fmt; | 60 LOG(ERROR) << "Unsupported image format:" << image->fmt; |
64 return; | 61 return; |
65 } | 62 } |
66 } | 63 } |
| 64 |
| 65 int y_offset = rect.top() * image->stride[0] + rect.left(); |
| 66 uint8_t* image_data_ptr = frame->GetFrameDataAtPos(rect.top_left()); |
| 67 yuv_to_rgb_function(image->planes[0] + y_offset, image->stride[0], |
| 68 image->planes[1] + u_offset, image->stride[1], |
| 69 image->planes[2] + v_offset, image->stride[2], |
| 70 image_data_ptr, frame->stride(), rect.width(), |
| 71 rect.height()); |
67 } | 72 } |
68 | 73 |
69 } // namespace | 74 } // namespace |
70 | 75 |
71 // static | 76 // static |
72 std::unique_ptr<VideoDecoderVpx> VideoDecoderVpx::CreateForVP8() { | 77 std::unique_ptr<VideoDecoderVpx> VideoDecoderVpx::CreateForVP8() { |
73 return base::WrapUnique(new VideoDecoderVpx(vpx_codec_vp8_dx())); | 78 return base::WrapUnique(new VideoDecoderVpx(vpx_codec_vp8_dx())); |
74 } | 79 } |
75 | 80 |
76 // static | 81 // static |
77 std::unique_ptr<VideoDecoderVpx> VideoDecoderVpx::CreateForVP9() { | 82 std::unique_ptr<VideoDecoderVpx> VideoDecoderVpx::CreateForVP9() { |
78 return base::WrapUnique(new VideoDecoderVpx(vpx_codec_vp9_dx())); | 83 return base::WrapUnique(new VideoDecoderVpx(vpx_codec_vp9_dx())); |
79 } | 84 } |
80 | 85 |
81 VideoDecoderVpx::~VideoDecoderVpx() {} | 86 VideoDecoderVpx::~VideoDecoderVpx() {} |
82 | 87 |
| 88 void VideoDecoderVpx::SetPixelFormat(PixelFormat pixel_format) { |
| 89 pixel_format_ = pixel_format; |
| 90 } |
| 91 |
83 bool VideoDecoderVpx::DecodePacket(const VideoPacket& packet, | 92 bool VideoDecoderVpx::DecodePacket(const VideoPacket& packet, |
84 webrtc::DesktopFrame* frame) { | 93 webrtc::DesktopFrame* frame) { |
85 // Pass the packet to the codec to process. | 94 // Pass the packet to the codec to process. |
86 vpx_codec_err_t ret = vpx_codec_decode( | 95 vpx_codec_err_t ret = vpx_codec_decode( |
87 codec_.get(), reinterpret_cast<const uint8_t*>(packet.data().data()), | 96 codec_.get(), reinterpret_cast<const uint8_t*>(packet.data().data()), |
88 packet.data().size(), nullptr, 0); | 97 packet.data().size(), nullptr, 0); |
89 if (ret != VPX_CODEC_OK) { | 98 if (ret != VPX_CODEC_OK) { |
90 const char* error = vpx_codec_error(codec_.get()); | 99 const char* error = vpx_codec_error(codec_.get()); |
91 const char* error_detail = vpx_codec_error_detail(codec_.get()); | 100 const char* error_detail = vpx_codec_error_detail(codec_.get()); |
92 LOG(ERROR) << "Decoding failed:" << (error ? error : "(NULL)") << "\n" | 101 LOG(ERROR) << "Decoding failed:" << (error ? error : "(NULL)") << "\n" |
(...skipping 15 matching lines...) Expand all Loading... |
108 | 117 |
109 // Determine which areas have been updated. | 118 // Determine which areas have been updated. |
110 webrtc::DesktopRegion* region = frame->mutable_updated_region(); | 119 webrtc::DesktopRegion* region = frame->mutable_updated_region(); |
111 region->Clear(); | 120 region->Clear(); |
112 for (int i = 0; i < packet.dirty_rects_size(); ++i) { | 121 for (int i = 0; i < packet.dirty_rects_size(); ++i) { |
113 Rect proto_rect = packet.dirty_rects(i); | 122 Rect proto_rect = packet.dirty_rects(i); |
114 webrtc::DesktopRect rect = | 123 webrtc::DesktopRect rect = |
115 webrtc::DesktopRect::MakeXYWH(proto_rect.x(), proto_rect.y(), | 124 webrtc::DesktopRect::MakeXYWH(proto_rect.x(), proto_rect.y(), |
116 proto_rect.width(), proto_rect.height()); | 125 proto_rect.width(), proto_rect.height()); |
117 region->AddRect(rect); | 126 region->AddRect(rect); |
118 RenderRect(image, rect, frame); | 127 RenderRect(image, rect, pixel_format_, frame); |
119 } | 128 } |
120 | 129 |
121 return true; | 130 return true; |
122 } | 131 } |
123 | 132 |
124 VideoDecoderVpx::VideoDecoderVpx(vpx_codec_iface_t* codec) { | 133 VideoDecoderVpx::VideoDecoderVpx(vpx_codec_iface_t* codec) { |
125 codec_.reset(new vpx_codec_ctx_t); | 134 codec_.reset(new vpx_codec_ctx_t); |
126 | 135 |
127 vpx_codec_dec_cfg config; | 136 vpx_codec_dec_cfg config; |
128 config.w = 0; | 137 config.w = 0; |
129 config.h = 0; | 138 config.h = 0; |
130 config.threads = 2; | 139 config.threads = 2; |
131 vpx_codec_err_t ret = vpx_codec_dec_init(codec_.get(), codec, &config, 0); | 140 vpx_codec_err_t ret = vpx_codec_dec_init(codec_.get(), codec, &config, 0); |
132 CHECK_EQ(VPX_CODEC_OK, ret); | 141 CHECK_EQ(VPX_CODEC_OK, ret); |
133 } | 142 } |
134 | 143 |
135 } // namespace remoting | 144 } // namespace remoting |
OLD | NEW |