OLD | NEW |
---|---|
(Empty) | |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "webkit/media/crypto/ppapi/libvpx_cdm_video_decoder.h" | |
6 | |
7 #include "base/logging.h" | |
8 #include "base/memory/scoped_ptr.h" | |
9 #include "media/base/buffers.h" | |
10 #include "media/base/limits.h" | |
11 #include "webkit/media/crypto/ppapi/content_decryption_module.h" | |
12 | |
13 // Include libvpx header files. | |
14 #define VPX_CODEC_DISABLE_COMPAT 1 | |
ddorwin
2012/12/04 22:38:15
Please add a comment about why we set this.
Tom Finegan
2012/12/04 23:17:39
Done.
| |
15 extern "C" { | |
16 #include "third_party/libvpx/libvpx.h" | |
17 } | |
18 | |
19 // Enable USE_COPYPLANE_WITH_LIBVPX to use |CopyPlane()| instead of memcpy to | |
20 // copy video frame data. | |
21 // #define USE_COPYPLANE_WITH_LIBVPX 1 | |
22 | |
23 namespace webkit_media { | |
24 | |
25 static const int kDecodeThreads = 1; | |
26 | |
27 static void CopyPlane(const uint8_t* source, | |
28 int32_t source_stride, | |
29 int32_t target_stride, | |
30 int32_t rows, | |
31 int32_t copy_bytes_per_row, | |
32 uint8_t* target) { | |
33 DCHECK(source); | |
34 DCHECK(target); | |
35 DCHECK_LE(copy_bytes_per_row, source_stride); | |
36 DCHECK_LE(copy_bytes_per_row, target_stride); | |
37 | |
38 for (int i = 0; i < rows; ++i) { | |
39 const int source_offset = i * source_stride; | |
40 const int target_offset = i * target_stride; | |
41 memcpy(target + target_offset, | |
42 source + source_offset, | |
43 copy_bytes_per_row); | |
44 } | |
45 } | |
46 | |
47 LibvpxCdmVideoDecoder::LibvpxCdmVideoDecoder(cdm::Allocator* allocator) | |
48 : is_initialized_(false), | |
49 allocator_(allocator), | |
50 vpx_codec_(NULL), | |
51 vpx_image_(NULL) { | |
52 } | |
53 | |
54 LibvpxCdmVideoDecoder::~LibvpxCdmVideoDecoder() { | |
55 Deinitialize(); | |
56 } | |
57 | |
58 bool LibvpxCdmVideoDecoder::Initialize(const cdm::VideoDecoderConfig& config) { | |
59 DVLOG(1) << "Initialize()"; | |
60 | |
61 if (!IsValidOutputConfig(config.format, config.coded_size)) { | |
62 LOG(ERROR) << "Initialize(): invalid video decoder configuration."; | |
63 return false; | |
64 } | |
65 | |
66 if (is_initialized_) { | |
67 LOG(ERROR) << "Initialize(): Already initialized."; | |
68 return false; | |
69 } | |
70 | |
71 vpx_codec_ = new vpx_codec_ctx(); | |
72 vpx_codec_dec_cfg_t vpx_config = {0}; | |
73 vpx_config.w = config.coded_size.width; | |
74 vpx_config.h = config.coded_size.height; | |
75 vpx_config.threads = kDecodeThreads; | |
76 | |
77 vpx_codec_err_t status = vpx_codec_dec_init(vpx_codec_, | |
78 vpx_codec_vp8_dx(), | |
79 &vpx_config, | |
80 0); | |
81 if (status != VPX_CODEC_OK) { | |
82 LOG(ERROR) << "InitializeLibvpx(): vpx_codec_dec_init failed, ret=" | |
83 << status; | |
84 delete vpx_codec_; | |
85 vpx_codec_ = NULL; | |
86 } | |
87 | |
88 is_initialized_ = true; | |
89 return true; | |
90 } | |
91 | |
92 void LibvpxCdmVideoDecoder::Deinitialize() { | |
93 DVLOG(1) << "Deinitialize()"; | |
94 | |
95 if (vpx_codec_) { | |
96 vpx_codec_destroy(vpx_codec_); | |
97 vpx_codec_ = NULL; | |
98 } | |
99 | |
100 is_initialized_ = false; | |
101 } | |
102 | |
103 void LibvpxCdmVideoDecoder::Reset() { | |
104 DVLOG(1) << "Reset()"; | |
105 } | |
106 | |
107 // static | |
108 bool LibvpxCdmVideoDecoder::IsValidOutputConfig(cdm::VideoFormat format, | |
109 const cdm::Size& data_size) { | |
110 return ((format == cdm::kYv12 || format == cdm::kI420) && | |
111 (data_size.width % 2) == 0 && (data_size.height % 2) == 0 && | |
112 data_size.width > 0 && data_size.height > 0 && | |
113 data_size.width <= media::limits::kMaxDimension && | |
114 data_size.height <= media::limits::kMaxDimension && | |
115 data_size.width * data_size.height <= media::limits::kMaxCanvas); | |
116 } | |
117 | |
118 cdm::Status LibvpxCdmVideoDecoder::DecodeFrame( | |
119 const uint8_t* compressed_frame, | |
120 int32_t compressed_frame_size, | |
121 int64_t timestamp, | |
122 cdm::VideoFrame* decoded_frame) { | |
123 DVLOG(1) << "DecodeFrame()"; | |
124 DCHECK(decoded_frame); | |
125 | |
126 // Pass |compressed_frame| to libvpx. | |
127 void* user_priv = reinterpret_cast<void*>(×tamp); | |
128 vpx_codec_err_t status = vpx_codec_decode(vpx_codec_, | |
129 compressed_frame, | |
130 compressed_frame_size, | |
131 user_priv, | |
132 0); | |
133 if (status != VPX_CODEC_OK) { | |
134 LOG(ERROR) << "DecodeFrameLibvpx(): vpx_codec_decode failed, status=" | |
135 << status; | |
136 return cdm::kDecodeError; | |
137 } | |
138 | |
139 // Gets pointer to decoded data. | |
140 vpx_codec_iter_t iter = NULL; | |
141 vpx_image_ = vpx_codec_get_frame(vpx_codec_, &iter); | |
142 if (!vpx_image_) | |
143 return cdm::kNeedMoreData; | |
144 | |
145 if (vpx_image_->user_priv != reinterpret_cast<void*>(×tamp)) { | |
146 LOG(ERROR) << "DecodeFrameLibvpx() invalid output timestamp."; | |
147 return cdm::kDecodeError; | |
148 } | |
149 decoded_frame->set_timestamp(timestamp); | |
150 | |
151 if (!CopyVpxImageTo(decoded_frame)) { | |
152 LOG(ERROR) << "DecodeFrameLibvpx() could not copy vpx image to output " | |
153 << "buffer."; | |
154 return cdm::kDecodeError; | |
155 } | |
156 | |
157 return cdm::kSuccess; | |
158 | |
159 } | |
160 | |
161 bool LibvpxCdmVideoDecoder::CopyVpxImageTo(cdm::VideoFrame* cdm_video_frame) { | |
162 DCHECK(cdm_video_frame); | |
163 DCHECK_EQ(vpx_image_->fmt, VPX_IMG_FMT_I420); | |
164 DCHECK_EQ(vpx_image_->d_w % 2, 0U); | |
165 DCHECK_EQ(vpx_image_->d_h % 2, 0U); | |
166 | |
167 #if defined(USE_COPYPLANE_WITH_LIBVPX) | |
168 const int y_size = vpx_image_->d_w * vpx_image_->d_h; | |
169 const int uv_size = y_size / 2; | |
170 const int space_required = y_size + (uv_size * 2); | |
171 | |
172 DCHECK(!cdm_video_frame->frame_buffer()); | |
173 cdm_video_frame->set_frame_buffer(allocator_->Allocate(space_required)); | |
174 if (!cdm_video_frame->frame_buffer()) { | |
175 LOG(ERROR) << "CopyVpxImageTo() cdm::Allocator::Allocate failed."; | |
176 return false; | |
177 } | |
178 | |
179 CopyPlane(vpx_image_->planes[VPX_PLANE_Y], | |
180 vpx_image_->stride[VPX_PLANE_Y], | |
181 vpx_image_->d_w, | |
182 vpx_image_->d_h, | |
183 vpx_image_->d_w, | |
184 cdm_video_frame->frame_buffer()->data()); | |
185 | |
186 const int uv_stride = vpx_image_->d_w / 2; | |
187 const int uv_rows = vpx_image_->d_h / 2; | |
188 CopyPlane(vpx_image_->planes[VPX_PLANE_U], | |
189 vpx_image_->stride[VPX_PLANE_U], | |
190 uv_stride, | |
191 uv_rows, | |
192 uv_stride, | |
193 cdm_video_frame->frame_buffer()->data() + y_size); | |
194 | |
195 CopyPlane(vpx_image_->planes[VPX_PLANE_V], | |
196 vpx_image_->stride[VPX_PLANE_V], | |
197 uv_stride, | |
198 uv_rows, | |
199 uv_stride, | |
200 cdm_video_frame->frame_buffer()->data() + y_size + uv_size); | |
201 | |
202 cdm_video_frame->set_format(cdm::kYv12); | |
203 | |
204 cdm::Size video_frame_size; | |
205 video_frame_size.width = vpx_image_->d_w; | |
206 video_frame_size.height = vpx_image_->d_h; | |
207 cdm_video_frame->set_size(video_frame_size); | |
208 | |
209 cdm_video_frame->set_plane_offset(cdm::VideoFrame::kYPlane, 0); | |
210 cdm_video_frame->set_plane_offset(cdm::VideoFrame::kUPlane, y_size); | |
211 cdm_video_frame->set_plane_offset(cdm::VideoFrame::kVPlane, | |
212 y_size + uv_size); | |
213 | |
214 cdm_video_frame->set_stride(cdm::VideoFrame::kYPlane, vpx_image_->d_w); | |
215 cdm_video_frame->set_stride(cdm::VideoFrame::kUPlane, uv_stride); | |
216 cdm_video_frame->set_stride(cdm::VideoFrame::kVPlane, uv_stride); | |
217 #else | |
218 const int y_size = vpx_image_->stride[VPX_PLANE_Y] * vpx_image_->d_h; | |
219 const int uv_rows = vpx_image_->d_h / 2; | |
220 const int u_size = vpx_image_->stride[VPX_PLANE_U] * uv_rows; | |
221 const int v_size = vpx_image_->stride[VPX_PLANE_V] * uv_rows; | |
222 const int space_required = y_size + u_size + v_size; | |
223 | |
224 DCHECK(!cdm_video_frame->frame_buffer()); | |
225 cdm_video_frame->set_frame_buffer(allocator_->Allocate(space_required)); | |
226 if (!cdm_video_frame->frame_buffer()) { | |
227 LOG(ERROR) << "CopyVpxImageTo() cdm::Allocator::Allocate failed."; | |
228 return false; | |
229 } | |
230 | |
231 memcpy(cdm_video_frame->frame_buffer()->data(), | |
232 vpx_image_->planes[VPX_PLANE_Y], | |
233 y_size); | |
234 memcpy(cdm_video_frame->frame_buffer()->data() + y_size, | |
235 vpx_image_->planes[VPX_PLANE_U], | |
236 u_size); | |
237 memcpy(cdm_video_frame->frame_buffer()->data() + y_size + u_size, | |
238 vpx_image_->planes[VPX_PLANE_V], | |
239 v_size); | |
240 | |
241 cdm_video_frame->set_format(cdm::kYv12); | |
242 | |
243 cdm::Size video_frame_size; | |
244 video_frame_size.width = vpx_image_->d_w; | |
245 video_frame_size.height = vpx_image_->d_h; | |
246 cdm_video_frame->set_size(video_frame_size); | |
247 | |
248 cdm_video_frame->set_plane_offset(cdm::VideoFrame::kYPlane, 0); | |
249 cdm_video_frame->set_plane_offset(cdm::VideoFrame::kUPlane, y_size); | |
250 cdm_video_frame->set_plane_offset(cdm::VideoFrame::kVPlane, | |
251 y_size + u_size); | |
252 | |
253 cdm_video_frame->set_stride(cdm::VideoFrame::kYPlane, | |
254 vpx_image_->stride[VPX_PLANE_Y]); | |
255 cdm_video_frame->set_stride(cdm::VideoFrame::kUPlane, | |
256 vpx_image_->stride[VPX_PLANE_U]); | |
257 cdm_video_frame->set_stride(cdm::VideoFrame::kVPlane, | |
258 vpx_image_->stride[VPX_PLANE_V]); | |
259 #endif // USE_COPYPLANE_WITH_LIBVPX | |
260 | |
261 return true; | |
262 } | |
263 | |
264 } // namespace webkit_media | |
OLD | NEW |