| OLD | NEW |
| 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 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 "chrome/gpu/gpu_video_decoder.h" | 5 #include "chrome/gpu/gpu_video_decoder.h" |
| 6 | 6 |
| 7 #include "chrome/common/gpu_messages.h" | 7 #include "chrome/common/gpu_messages.h" |
| 8 #include "chrome/gpu/gpu_channel.h" | 8 #include "chrome/gpu/gpu_channel.h" |
| 9 #include "chrome/gpu/media/fake_gl_video_decode_engine.h" |
| 9 #include "media/base/data_buffer.h" | 10 #include "media/base/data_buffer.h" |
| 10 #include "media/base/video_frame.h" | 11 #include "media/base/video_frame.h" |
| 11 | 12 |
| 12 void GpuVideoDecoder::OnChannelConnected(int32 peer_pid) { | 13 void GpuVideoDecoder::OnChannelConnected(int32 peer_pid) { |
| 13 } | 14 } |
| 14 | 15 |
| 15 void GpuVideoDecoder::OnChannelError() { | 16 void GpuVideoDecoder::OnChannelError() { |
| 16 } | 17 } |
| 17 | 18 |
| 18 void GpuVideoDecoder::OnMessageReceived(const IPC::Message& msg) { | 19 void GpuVideoDecoder::OnMessageReceived(const IPC::Message& msg) { |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 71 return true; | 72 return true; |
| 72 } | 73 } |
| 73 | 74 |
| 74 void GpuVideoDecoder::CreateVideoFrameOnTransferBuffer() { | 75 void GpuVideoDecoder::CreateVideoFrameOnTransferBuffer() { |
| 75 const base::TimeDelta kZero; | 76 const base::TimeDelta kZero; |
| 76 uint8* data[media::VideoFrame::kMaxPlanes]; | 77 uint8* data[media::VideoFrame::kMaxPlanes]; |
| 77 int32 strides[media::VideoFrame::kMaxPlanes]; | 78 int32 strides[media::VideoFrame::kMaxPlanes]; |
| 78 memset(data, 0, sizeof(data)); | 79 memset(data, 0, sizeof(data)); |
| 79 memset(strides, 0, sizeof(strides)); | 80 memset(strides, 0, sizeof(strides)); |
| 80 data[0] = static_cast<uint8*>(output_transfer_buffer_->memory()); | 81 data[0] = static_cast<uint8*>(output_transfer_buffer_->memory()); |
| 81 data[1] = data[0] + config_.width_ * config_.height_; | 82 data[1] = data[0] + config_.width * config_.height; |
| 82 data[2] = data[1] + config_.width_ * config_.height_ / 4; | 83 data[2] = data[1] + config_.width * config_.height / 4; |
| 83 strides[0] = config_.width_; | 84 strides[0] = config_.width; |
| 84 strides[1] = strides[2] = config_.width_ >> 1; | 85 strides[1] = strides[2] = config_.width >> 1; |
| 85 media::VideoFrame:: CreateFrameExternal( | 86 media::VideoFrame:: CreateFrameExternal( |
| 86 media::VideoFrame::TYPE_SYSTEM_MEMORY, | 87 media::VideoFrame::TYPE_SYSTEM_MEMORY, |
| 87 media::VideoFrame::YV12, | 88 media::VideoFrame::YV12, |
| 88 config_.width_, config_.height_, 3, | 89 config_.width, config_.height, 3, |
| 89 data, strides, | 90 data, strides, |
| 90 kZero, kZero, | 91 kZero, kZero, |
| 91 NULL, | 92 NULL, |
| 92 &frame_); | 93 &frame_); |
| 93 } | 94 } |
| 94 | 95 |
| 95 void GpuVideoDecoder::OnInitializeComplete(const VideoCodecInfo& info) { | 96 void GpuVideoDecoder::OnInitializeComplete(const VideoCodecInfo& info) { |
| 96 info_ = info; | 97 info_ = info; |
| 97 GpuVideoDecoderInitDoneParam param; | 98 GpuVideoDecoderInitDoneParam param; |
| 98 param.success_ = false; | 99 param.success = false; |
| 99 param.input_buffer_handle_ = base::SharedMemory::NULLHandle(); | 100 param.input_buffer_handle = base::SharedMemory::NULLHandle(); |
| 100 param.output_buffer_handle_ = base::SharedMemory::NULLHandle(); | 101 param.output_buffer_handle = base::SharedMemory::NULLHandle(); |
| 101 | 102 |
| 102 if (!info.success_) { | 103 if (!info.success) { |
| 103 SendInitializeDone(param); | 104 SendInitializeDone(param); |
| 104 return; | 105 return; |
| 105 } | 106 } |
| 106 | 107 |
| 107 // Translate surface type. | 108 // Translate surface type. |
| 108 switch (info.stream_info_.surface_type_) { | 109 param.surface_type = static_cast<GpuVideoDecoderInitDoneParam::SurfaceType>( |
| 109 case VideoFrame::TYPE_SYSTEM_MEMORY: | 110 info.stream_info.surface_type); |
| 110 param.surface_type_ = | |
| 111 GpuVideoDecoderInitDoneParam::SurfaceTypeSystemMemory; | |
| 112 break; | |
| 113 default: | |
| 114 NOTREACHED(); | |
| 115 } | |
| 116 | 111 |
| 117 // Translate surface format. | 112 // Translate surface format. |
| 118 switch (info.stream_info_.surface_format_) { | 113 switch (info.stream_info.surface_format) { |
| 119 case VideoFrame::YV12: | 114 case VideoFrame::YV12: |
| 120 param.format_ = GpuVideoDecoderInitDoneParam::SurfaceFormat_YV12; | 115 param.format = GpuVideoDecoderInitDoneParam::SurfaceFormat_YV12; |
| 121 break; | 116 break; |
| 117 case VideoFrame::RGBA: |
| 118 param.format = GpuVideoDecoderInitDoneParam::SurfaceFormat_RGBA; |
| 122 default: | 119 default: |
| 123 NOTREACHED(); | 120 NOTREACHED(); |
| 124 } | 121 } |
| 125 | 122 |
| 126 // TODO(jiesun): Check the assumption of input size < original size. | 123 // TODO(jiesun): Check the assumption of input size < original size. |
| 127 param.input_buffer_size_ = config_.width_ * config_.height_ * 3 / 2; | 124 param.input_buffer_size = config_.width * config_.height * 3 / 2; |
| 128 if (!CreateInputTransferBuffer(param.input_buffer_size_, | 125 if (!CreateInputTransferBuffer(param.input_buffer_size, |
| 129 ¶m.input_buffer_handle_)) { | 126 ¶m.input_buffer_handle)) { |
| 130 SendInitializeDone(param); | 127 SendInitializeDone(param); |
| 131 return; | 128 return; |
| 132 } | 129 } |
| 133 | 130 |
| 134 if (info.stream_info_.surface_type_ == VideoFrame::TYPE_SYSTEM_MEMORY) { | 131 if (info.stream_info.surface_type == VideoFrame::TYPE_SYSTEM_MEMORY) { |
| 135 // TODO(jiesun): Allocate this according to the surface format. | 132 // TODO(jiesun): Allocate this according to the surface format. |
| 136 // The format actually could change during streaming, we need to | 133 // The format actually could change during streaming, we need to |
| 137 // notify GpuVideoDecoderHost side when this happened and renegotiate | 134 // notify GpuVideoDecoderHost side when this happened and renegotiate |
| 138 // the transfer buffer. | 135 // the transfer buffer. |
| 139 | 136 switch (info.stream_info.surface_format) { |
| 140 switch (info.stream_info_.surface_format_) { | |
| 141 case VideoFrame::YV12: | 137 case VideoFrame::YV12: |
| 142 // TODO(jiesun): take stride into account. | 138 // TODO(jiesun): take stride into account. |
| 143 param.output_buffer_size_ = | 139 param.output_buffer_size = |
| 144 config_.width_ * config_.height_ * 3 / 2; | 140 config_.width * config_.height * 3 / 2; |
| 145 break; | 141 break; |
| 146 default: | 142 default: |
| 147 NOTREACHED(); | 143 NOTREACHED(); |
| 148 } | 144 } |
| 149 | 145 |
| 150 if (!CreateOutputTransferBuffer(param.output_buffer_size_, | 146 if (!CreateOutputTransferBuffer(param.output_buffer_size, |
| 151 ¶m.output_buffer_handle_)) { | 147 ¶m.output_buffer_handle)) { |
| 152 SendInitializeDone(param); | 148 SendInitializeDone(param); |
| 153 return; | 149 return; |
| 154 } | 150 } |
| 155 | |
| 156 CreateVideoFrameOnTransferBuffer(); | 151 CreateVideoFrameOnTransferBuffer(); |
| 157 } | 152 } |
| 158 | 153 |
| 159 param.success_ = true; | 154 param.success = true; |
| 160 | 155 |
| 161 SendInitializeDone(param); | 156 SendInitializeDone(param); |
| 162 } | 157 } |
| 163 | 158 |
| 164 void GpuVideoDecoder::OnUninitializeComplete() { | 159 void GpuVideoDecoder::OnUninitializeComplete() { |
| 165 SendUninitializeDone(); | 160 SendUninitializeDone(); |
| 166 } | 161 } |
| 167 | 162 |
| 168 void GpuVideoDecoder::OnFlushComplete() { | 163 void GpuVideoDecoder::OnFlushComplete() { |
| 169 SendFlushDone(); | 164 SendFlushDone(); |
| (...skipping 10 matching lines...) Expand all Loading... |
| 180 void GpuVideoDecoder::OnFormatChange(VideoStreamInfo stream_info) { | 175 void GpuVideoDecoder::OnFormatChange(VideoStreamInfo stream_info) { |
| 181 NOTIMPLEMENTED(); | 176 NOTIMPLEMENTED(); |
| 182 } | 177 } |
| 183 | 178 |
| 184 void GpuVideoDecoder::ProduceVideoSample(scoped_refptr<Buffer> buffer) { | 179 void GpuVideoDecoder::ProduceVideoSample(scoped_refptr<Buffer> buffer) { |
| 185 SendEmptyBufferDone(); | 180 SendEmptyBufferDone(); |
| 186 } | 181 } |
| 187 | 182 |
| 188 void GpuVideoDecoder::ConsumeVideoFrame(scoped_refptr<VideoFrame> frame) { | 183 void GpuVideoDecoder::ConsumeVideoFrame(scoped_refptr<VideoFrame> frame) { |
| 189 GpuVideoDecoderOutputBufferParam output_param; | 184 GpuVideoDecoderOutputBufferParam output_param; |
| 190 output_param.timestamp_ = frame->GetTimestamp().InMicroseconds(); | 185 output_param.timestamp = frame->GetTimestamp().InMicroseconds(); |
| 191 output_param.duration_ = frame->GetDuration().InMicroseconds(); | 186 output_param.duration = frame->GetDuration().InMicroseconds(); |
| 192 output_param.flags_ = frame->IsEndOfStream() ? | 187 output_param.flags = frame->IsEndOfStream() ? |
| 193 GpuVideoDecoderOutputBufferParam::kFlagsEndOfStream : 0; | 188 GpuVideoDecoderOutputBufferParam::kFlagsEndOfStream : 0; |
| 189 // TODO(hclam): We should have the conversion between VideoFrame and the |
| 190 // IPC transport param done in GpuVideoDecodeContext. |
| 191 // This is a hack to pass texture back as a param. |
| 192 output_param.texture = frame->gl_texture(media::VideoFrame::kRGBPlane); |
| 194 SendFillBufferDone(output_param); | 193 SendFillBufferDone(output_param); |
| 195 } | 194 } |
| 196 | 195 |
| 197 GpuVideoDecoder::GpuVideoDecoder( | 196 GpuVideoDecoder::GpuVideoDecoder( |
| 198 const GpuVideoDecoderInfoParam* param, | 197 const GpuVideoDecoderInfoParam* param, |
| 199 GpuChannel* channel, | 198 GpuChannel* channel, |
| 200 base::ProcessHandle handle, | 199 base::ProcessHandle handle, |
| 201 gpu::gles2::GLES2Decoder* decoder) | 200 gpu::gles2::GLES2Decoder* decoder) |
| 202 : decoder_host_route_id_(param->decoder_host_route_id), | 201 : decoder_host_route_id_(param->decoder_host_route_id), |
| 203 output_transfer_buffer_busy_(false), | 202 output_transfer_buffer_busy_(false), |
| 204 pending_output_requests_(0), | 203 pending_output_requests_(0), |
| 205 channel_(channel), | 204 channel_(channel), |
| 206 renderer_handle_(handle), | 205 renderer_handle_(handle), |
| 207 gles2_decoder_(decoder) { | 206 gles2_decoder_(decoder) { |
| 208 memset(&config_, 0, sizeof(config_)); | 207 memset(&config_, 0, sizeof(config_)); |
| 209 memset(&info_, 0, sizeof(info_)); | 208 memset(&info_, 0, sizeof(info_)); |
| 210 #if defined(OS_WIN) && defined(ENABLE_GPU_DECODER) | 209 |
| 211 // TODO(jiesun): find a better way to determine which GpuVideoDecoder | 210 // TODO(jiesun): find a better way to determine which VideoDecodeEngine |
| 212 // to return on current platform. | 211 // to return on current platform. |
| 213 decode_engine_.reset(new GpuVideoDecoderMFT()); | 212 decode_engine_.reset(new FakeGlVideoDecodeEngine()); |
| 214 #else | |
| 215 #endif | |
| 216 } | 213 } |
| 217 | 214 |
| 218 void GpuVideoDecoder::OnInitialize(const GpuVideoDecoderInitParam& param) { | 215 void GpuVideoDecoder::OnInitialize(const GpuVideoDecoderInitParam& param) { |
| 216 // TODO(hclam): Initialize the VideoDecodeContext first. |
| 217 |
| 219 // TODO(jiesun): codec id should come from |param|. | 218 // TODO(jiesun): codec id should come from |param|. |
| 220 config_.codec_ = media::kCodecH264; | 219 config_.codec = media::kCodecH264; |
| 221 config_.width_ = param.width_; | 220 config_.width = param.width; |
| 222 config_.height_ = param.height_; | 221 config_.height = param.height; |
| 223 config_.opaque_context_ = NULL; | 222 config_.opaque_context = NULL; |
| 224 decode_engine_->Initialize(NULL, this, config_); | 223 decode_engine_->Initialize(NULL, this, config_); |
| 225 } | 224 } |
| 226 | 225 |
| 227 void GpuVideoDecoder::OnUninitialize() { | 226 void GpuVideoDecoder::OnUninitialize() { |
| 228 decode_engine_->Uninitialize(); | 227 decode_engine_->Uninitialize(); |
| 229 } | 228 } |
| 230 | 229 |
| 231 void GpuVideoDecoder::OnFlush() { | 230 void GpuVideoDecoder::OnFlush() { |
| 232 // TODO(jiesun): this is wrong?? | 231 // TODO(jiesun): this is wrong?? |
| 233 output_transfer_buffer_busy_ = false; | 232 output_transfer_buffer_busy_ = false; |
| 234 pending_output_requests_ = 0; | 233 pending_output_requests_ = 0; |
| 235 | 234 |
| 236 decode_engine_->Flush(); | 235 decode_engine_->Flush(); |
| 237 } | 236 } |
| 238 | 237 |
| 239 void GpuVideoDecoder::OnEmptyThisBuffer( | 238 void GpuVideoDecoder::OnEmptyThisBuffer( |
| 240 const GpuVideoDecoderInputBufferParam& buffer) { | 239 const GpuVideoDecoderInputBufferParam& buffer) { |
| 241 DCHECK(input_transfer_buffer_->memory()); | 240 DCHECK(input_transfer_buffer_->memory()); |
| 242 | 241 |
| 243 uint8* src = static_cast<uint8*>(input_transfer_buffer_->memory()); | 242 uint8* src = static_cast<uint8*>(input_transfer_buffer_->memory()); |
| 244 | 243 |
| 245 scoped_refptr<Buffer> input_buffer; | 244 scoped_refptr<Buffer> input_buffer; |
| 246 uint8* dst = buffer.size_ ? new uint8[buffer.size_] : NULL; | 245 uint8* dst = buffer.size ? new uint8[buffer.size] : NULL; |
| 247 input_buffer = new media::DataBuffer(dst, buffer.size_); | 246 input_buffer = new media::DataBuffer(dst, buffer.size); |
| 248 memcpy(dst, src, buffer.size_); | 247 memcpy(dst, src, buffer.size); |
| 249 SendEmptyBufferACK(); | 248 SendEmptyBufferACK(); |
| 250 | 249 |
| 251 decode_engine_->ConsumeVideoSample(input_buffer); | 250 decode_engine_->ConsumeVideoSample(input_buffer); |
| 252 } | 251 } |
| 252 |
| 253 void GpuVideoDecoder::OnFillThisBuffer( | 253 void GpuVideoDecoder::OnFillThisBuffer( |
| 254 const GpuVideoDecoderOutputBufferParam& frame) { | 254 const GpuVideoDecoderOutputBufferParam& param) { |
| 255 if (info_.stream_info_.surface_type_ == VideoFrame::TYPE_SYSTEM_MEMORY) { | 255 // Switch context before calling to the decode engine. |
| 256 // TODO(hclam): This is temporary to allow FakeGlVideoDecodeEngine to issue |
| 257 // GL commands correctly. |
| 258 bool ret = gles2_decoder_->MakeCurrent(); |
| 259 DCHECK(ret) << "Failed to switch context"; |
| 260 |
| 261 if (info_.stream_info.surface_type == VideoFrame::TYPE_SYSTEM_MEMORY) { |
| 256 pending_output_requests_++; | 262 pending_output_requests_++; |
| 257 if (!output_transfer_buffer_busy_) { | 263 if (!output_transfer_buffer_busy_) { |
| 258 output_transfer_buffer_busy_ = true; | 264 output_transfer_buffer_busy_ = true; |
| 259 decode_engine_->ProduceVideoFrame(frame_); | 265 decode_engine_->ProduceVideoFrame(frame_); |
| 260 } | 266 } |
| 261 } else { | 267 } else { |
| 262 decode_engine_->ProduceVideoFrame(frame_); | 268 // TODO(hclam): I need to rethink how to delegate calls to |
| 269 // VideoDecodeEngine, I may need to create a GpuVideoDecodeContext that |
| 270 // provides a method for me to make calls to VideoDecodeEngine with the |
| 271 // correct VideoFrame. |
| 272 DCHECK_EQ(VideoFrame::TYPE_GL_TEXTURE, info_.stream_info.surface_type); |
| 273 |
| 274 scoped_refptr<media::VideoFrame> frame; |
| 275 VideoFrame::GlTexture textures[3] = { param.texture, 0, 0 }; |
| 276 |
| 277 media::VideoFrame:: CreateFrameGlTexture( |
| 278 media::VideoFrame::RGBA, config_.width, config_.height, textures, |
| 279 base::TimeDelta(), base::TimeDelta(), &frame); |
| 280 decode_engine_->ProduceVideoFrame(frame); |
| 263 } | 281 } |
| 264 } | 282 } |
| 265 | 283 |
| 266 void GpuVideoDecoder::OnFillThisBufferDoneACK() { | 284 void GpuVideoDecoder::OnFillThisBufferDoneACK() { |
| 267 if (info_.stream_info_.surface_type_ == VideoFrame::TYPE_SYSTEM_MEMORY) { | 285 if (info_.stream_info.surface_type == VideoFrame::TYPE_SYSTEM_MEMORY) { |
| 268 output_transfer_buffer_busy_ = false; | 286 output_transfer_buffer_busy_ = false; |
| 269 pending_output_requests_--; | 287 pending_output_requests_--; |
| 270 if (pending_output_requests_) { | 288 if (pending_output_requests_) { |
| 271 output_transfer_buffer_busy_ = true; | 289 output_transfer_buffer_busy_ = true; |
| 272 decode_engine_->ProduceVideoFrame(frame_); | 290 decode_engine_->ProduceVideoFrame(frame_); |
| 273 } | 291 } |
| 274 } | 292 } |
| 275 } | 293 } |
| 276 | 294 |
| 277 void GpuVideoDecoder::SendInitializeDone( | 295 void GpuVideoDecoder::SendInitializeDone( |
| (...skipping 24 matching lines...) Expand all Loading... |
| 302 } | 320 } |
| 303 | 321 |
| 304 void GpuVideoDecoder::SendEmptyBufferACK() { | 322 void GpuVideoDecoder::SendEmptyBufferACK() { |
| 305 if (!channel_->Send( | 323 if (!channel_->Send( |
| 306 new GpuVideoDecoderHostMsg_EmptyThisBufferACK(route_id()))) { | 324 new GpuVideoDecoderHostMsg_EmptyThisBufferACK(route_id()))) { |
| 307 LOG(ERROR) << "GpuVideoDecoderMsg_EmptyThisBufferACK failed"; | 325 LOG(ERROR) << "GpuVideoDecoderMsg_EmptyThisBufferACK failed"; |
| 308 } | 326 } |
| 309 } | 327 } |
| 310 | 328 |
| 311 void GpuVideoDecoder::SendFillBufferDone( | 329 void GpuVideoDecoder::SendFillBufferDone( |
| 312 const GpuVideoDecoderOutputBufferParam& frame) { | 330 const GpuVideoDecoderOutputBufferParam& param) { |
| 313 if (!channel_->Send( | 331 if (!channel_->Send( |
| 314 new GpuVideoDecoderHostMsg_FillThisBufferDone(route_id(), frame))) { | 332 new GpuVideoDecoderHostMsg_FillThisBufferDone(route_id(), param))) { |
| 315 LOG(ERROR) << "GpuVideoDecoderMsg_FillThisBufferDone failed"; | 333 LOG(ERROR) << "GpuVideoDecoderMsg_FillThisBufferDone failed"; |
| 316 } | 334 } |
| 317 } | 335 } |
| OLD | NEW |