| OLD | NEW |
| 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2015 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 "content/common/gpu/media/android_video_decode_accelerator.h" | 5 #include "content/common/gpu/media/android_video_decode_accelerator_impl.h" |
| 6 | 6 |
| 7 #include "base/bind.h" | 7 #include "base/bind.h" |
| 8 #include "base/logging.h" | 8 #include "base/logging.h" |
| 9 #include "base/message_loop/message_loop.h" | 9 #include "base/message_loop/message_loop.h" |
| 10 #include "base/metrics/histogram.h" | 10 #include "base/metrics/histogram.h" |
| 11 #include "content/common/gpu/gpu_channel.h" | 11 #include "content/common/gpu/gpu_channel.h" |
| 12 #include "content/common/gpu/media/avda_return_on_failure.h" |
| 12 #include "gpu/command_buffer/service/gles2_cmd_decoder.h" | 13 #include "gpu/command_buffer/service/gles2_cmd_decoder.h" |
| 13 #include "media/base/bitstream_buffer.h" | 14 #include "media/base/bitstream_buffer.h" |
| 14 #include "media/base/limits.h" | 15 #include "media/base/limits.h" |
| 15 #include "media/base/video_decoder_config.h" | 16 #include "media/base/video_decoder_config.h" |
| 16 #include "media/video/picture.h" | 17 #include "media/video/picture.h" |
| 17 #include "ui/gl/android/scoped_java_surface.h" | 18 #include "ui/gl/android/scoped_java_surface.h" |
| 18 #include "ui/gl/android/surface_texture.h" | 19 #include "ui/gl/android/surface_texture.h" |
| 19 #include "ui/gl/gl_bindings.h" | 20 #include "ui/gl/gl_bindings.h" |
| 20 | 21 |
| 21 namespace content { | 22 namespace content { |
| 22 | 23 |
| 23 // Helper macros for dealing with failure. If |result| evaluates false, emit | 24 class InstantiatableAndroidVideoDecodeAcceleratorImpl |
| 24 // |log| to ERROR, register |error| with the decoder, and return. | 25 : public AndroidVideoDecodeAcceleratorImpl { |
| 25 #define RETURN_ON_FAILURE(result, log, error) \ | 26 public: |
| 26 do { \ | 27 InstantiatableAndroidVideoDecodeAcceleratorImpl( |
| 27 if (!(result)) { \ | 28 const base::WeakPtr<gpu::gles2::GLES2Decoder> decoder, |
| 28 DLOG(ERROR) << log; \ | 29 const base::Callback<bool(void)>& make_context_current, |
| 29 base::MessageLoop::current()->PostTask( \ | 30 scoped_refptr<BackingStrategy> strategy) : |
| 30 FROM_HERE, \ | 31 AndroidVideoDecodeAcceleratorImpl(decoder, make_context_current, |
| 31 base::Bind(&AndroidVideoDecodeAccelerator::NotifyError, \ | 32 strategy) {} |
| 32 weak_this_factory_.GetWeakPtr(), \ | 33 }; |
| 33 error)); \ | |
| 34 state_ = ERROR; \ | |
| 35 return; \ | |
| 36 } \ | |
| 37 } while (0) | |
| 38 | 34 |
| 39 // TODO(dwkang): We only need kMaxVideoFrames to pass media stack's prerolling | 35 AndroidVideoDecodeAccelerator* AndroidVideoDecodeAccelerator::Create( |
| 40 // phase, but 1 is added due to crbug.com/176036. This should be tuned when we | 36 const base::WeakPtr<gpu::gles2::GLES2Decoder> decoder, |
| 41 // have actual use case. | 37 const base::Callback<bool(void)>& make_context_current, |
| 42 enum { kNumPictureBuffers = media::limits::kMaxVideoFrames + 1 }; | 38 scoped_refptr<AndroidVideoDecodeAccelerator::BackingStrategy> strategy) |
| 39 { |
| 40 return new InstantiatableAndroidVideoDecodeAcceleratorImpl(decoder, |
| 41 make_context_current, strategy); |
| 42 } |
| 43 | 43 |
| 44 // Max number of bitstreams notified to the client with | 44 // Max number of bitstreams notified to the client with |
| 45 // NotifyEndOfBitstreamBuffer() before getting output from the bitstream. | 45 // NotifyEndOfBitstreamBuffer() before getting output from the bitstream. |
| 46 enum { kMaxBitstreamsNotifiedInAdvance = 32 }; | 46 enum { kMaxBitstreamsNotifiedInAdvance = 32 }; |
| 47 | 47 |
| 48 #if defined(ENABLE_MEDIA_PIPELINE_ON_ANDROID) | 48 #if defined(ENABLE_MEDIA_PIPELINE_ON_ANDROID) |
| 49 // MediaCodec is only guaranteed to support baseline, but some devices may | 49 // MediaCodec is only guaranteed to support baseline, but some devices may |
| 50 // support others. Advertise support for all H264 profiles and let the | 50 // support others. Advertise support for all H264 profiles and let the |
| 51 // MediaCodec fail when decoding if it's not actually supported. It's assumed | 51 // MediaCodec fail when decoding if it's not actually supported. It's assumed |
| 52 // that consumers won't have software fallback for H264 on Android anyway. | 52 // that consumers won't have software fallback for H264 on Android anyway. |
| (...skipping 27 matching lines...) Expand all Loading... |
| 80 // pictures have been fed to saturate any internal buffering). This is | 80 // pictures have been fed to saturate any internal buffering). This is |
| 81 // speculative and it's unclear that this would be a win (nor that there's a | 81 // speculative and it's unclear that this would be a win (nor that there's a |
| 82 // reasonably device-agnostic way to fill in the "believes" above). | 82 // reasonably device-agnostic way to fill in the "believes" above). |
| 83 return base::TimeDelta::FromMilliseconds(10); | 83 return base::TimeDelta::FromMilliseconds(10); |
| 84 } | 84 } |
| 85 | 85 |
| 86 static inline const base::TimeDelta NoWaitTimeOut() { | 86 static inline const base::TimeDelta NoWaitTimeOut() { |
| 87 return base::TimeDelta::FromMicroseconds(0); | 87 return base::TimeDelta::FromMicroseconds(0); |
| 88 } | 88 } |
| 89 | 89 |
| 90 AndroidVideoDecodeAccelerator::AndroidVideoDecodeAccelerator( | 90 AndroidVideoDecodeAcceleratorImpl::AndroidVideoDecodeAcceleratorImpl( |
| 91 const base::WeakPtr<gpu::gles2::GLES2Decoder> decoder, | 91 const base::WeakPtr<gpu::gles2::GLES2Decoder> decoder, |
| 92 const base::Callback<bool(void)>& make_context_current) | 92 const base::Callback<bool(void)>& make_context_current, |
| 93 scoped_refptr<BackingStrategy> strategy) |
| 93 : client_(NULL), | 94 : client_(NULL), |
| 94 make_context_current_(make_context_current), | 95 make_context_current_(make_context_current), |
| 95 codec_(media::kCodecH264), | 96 codec_(media::kCodecH264), |
| 96 state_(NO_ERROR), | 97 state_(NO_ERROR), |
| 97 surface_texture_id_(0), | 98 surface_texture_id_(0), |
| 98 picturebuffers_requested_(false), | 99 picturebuffers_requested_(false), |
| 99 gl_decoder_(decoder), | 100 gl_decoder_(decoder), |
| 101 strategy_(strategy), |
| 100 weak_this_factory_(this) {} | 102 weak_this_factory_(this) {} |
| 101 | 103 |
| 102 AndroidVideoDecodeAccelerator::~AndroidVideoDecodeAccelerator() { | 104 AndroidVideoDecodeAcceleratorImpl::~AndroidVideoDecodeAcceleratorImpl() { |
| 103 DCHECK(thread_checker_.CalledOnValidThread()); | 105 DCHECK(thread_checker_.CalledOnValidThread()); |
| 104 } | 106 } |
| 105 | 107 |
| 106 bool AndroidVideoDecodeAccelerator::Initialize(media::VideoCodecProfile profile, | 108 bool AndroidVideoDecodeAcceleratorImpl::Initialize( |
| 107 Client* client) { | 109 media::VideoCodecProfile profile, |
| 110 Client* client) { |
| 108 DCHECK(!media_codec_); | 111 DCHECK(!media_codec_); |
| 109 DCHECK(thread_checker_.CalledOnValidThread()); | 112 DCHECK(thread_checker_.CalledOnValidThread()); |
| 110 | 113 |
| 111 client_ = client; | 114 client_ = client; |
| 112 codec_ = VideoCodecProfileToVideoCodec(profile); | 115 codec_ = VideoCodecProfileToVideoCodec(profile); |
| 113 | 116 |
| 117 strategy_->SetStateProvider(this); |
| 118 |
| 114 bool profile_supported = codec_ == media::kCodecVP8; | 119 bool profile_supported = codec_ == media::kCodecVP8; |
| 115 #if defined(ENABLE_MEDIA_PIPELINE_ON_ANDROID) | 120 #if defined(ENABLE_MEDIA_PIPELINE_ON_ANDROID) |
| 116 profile_supported |= | 121 profile_supported |= |
| 117 (codec_ == media::kCodecVP9 || codec_ == media::kCodecH264); | 122 (codec_ == media::kCodecVP9 || codec_ == media::kCodecH264); |
| 118 #endif | 123 #endif |
| 119 | 124 |
| 120 if (!profile_supported) { | 125 if (!profile_supported) { |
| 121 LOG(ERROR) << "Unsupported profile: " << profile; | 126 LOG(ERROR) << "Unsupported profile: " << profile; |
| 122 return false; | 127 return false; |
| 123 } | 128 } |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 157 surface_texture_ = gfx::SurfaceTexture::Create(surface_texture_id_); | 162 surface_texture_ = gfx::SurfaceTexture::Create(surface_texture_id_); |
| 158 | 163 |
| 159 if (!ConfigureMediaCodec()) { | 164 if (!ConfigureMediaCodec()) { |
| 160 LOG(ERROR) << "Failed to create MediaCodec instance."; | 165 LOG(ERROR) << "Failed to create MediaCodec instance."; |
| 161 return false; | 166 return false; |
| 162 } | 167 } |
| 163 | 168 |
| 164 return true; | 169 return true; |
| 165 } | 170 } |
| 166 | 171 |
| 167 void AndroidVideoDecodeAccelerator::DoIOTask() { | 172 void AndroidVideoDecodeAcceleratorImpl::DoIOTask() { |
| 168 DCHECK(thread_checker_.CalledOnValidThread()); | 173 DCHECK(thread_checker_.CalledOnValidThread()); |
| 169 if (state_ == ERROR) { | 174 if (state_ == ERROR) { |
| 170 return; | 175 return; |
| 171 } | 176 } |
| 172 | 177 |
| 173 QueueInput(); | 178 QueueInput(); |
| 174 DequeueOutput(); | 179 DequeueOutput(); |
| 175 } | 180 } |
| 176 | 181 |
| 177 void AndroidVideoDecodeAccelerator::QueueInput() { | 182 void AndroidVideoDecodeAcceleratorImpl::QueueInput() { |
| 178 DCHECK(thread_checker_.CalledOnValidThread()); | 183 DCHECK(thread_checker_.CalledOnValidThread()); |
| 179 if (bitstreams_notified_in_advance_.size() > kMaxBitstreamsNotifiedInAdvance) | 184 if (bitstreams_notified_in_advance_.size() > kMaxBitstreamsNotifiedInAdvance) |
| 180 return; | 185 return; |
| 181 if (pending_bitstream_buffers_.empty()) | 186 if (pending_bitstream_buffers_.empty()) |
| 182 return; | 187 return; |
| 183 | 188 |
| 184 int input_buf_index = 0; | 189 int input_buf_index = 0; |
| 185 media::MediaCodecStatus status = media_codec_->DequeueInputBuffer( | 190 media::MediaCodecStatus status = media_codec_->DequeueInputBuffer( |
| 186 NoWaitTimeOut(), &input_buf_index); | 191 NoWaitTimeOut(), &input_buf_index); |
| 187 if (status != media::MEDIA_CODEC_OK) { | 192 if (status != media::MEDIA_CODEC_OK) { |
| (...skipping 16 matching lines...) Expand all Loading... |
| 204 | 209 |
| 205 // Abuse the presentation time argument to propagate the bitstream | 210 // Abuse the presentation time argument to propagate the bitstream |
| 206 // buffer ID to the output, so we can report it back to the client in | 211 // buffer ID to the output, so we can report it back to the client in |
| 207 // PictureReady(). | 212 // PictureReady(). |
| 208 base::TimeDelta timestamp = | 213 base::TimeDelta timestamp = |
| 209 base::TimeDelta::FromMicroseconds(bitstream_buffer.id()); | 214 base::TimeDelta::FromMicroseconds(bitstream_buffer.id()); |
| 210 | 215 |
| 211 scoped_ptr<base::SharedMemory> shm( | 216 scoped_ptr<base::SharedMemory> shm( |
| 212 new base::SharedMemory(bitstream_buffer.handle(), true)); | 217 new base::SharedMemory(bitstream_buffer.handle(), true)); |
| 213 | 218 |
| 214 RETURN_ON_FAILURE(shm->Map(bitstream_buffer.size()), | 219 RETURN_ON_FAILURE(this, |
| 220 shm->Map(bitstream_buffer.size()), |
| 215 "Failed to SharedMemory::Map()", | 221 "Failed to SharedMemory::Map()", |
| 216 UNREADABLE_INPUT); | 222 UNREADABLE_INPUT); |
| 217 | 223 |
| 218 status = | 224 status = |
| 219 media_codec_->QueueInputBuffer(input_buf_index, | 225 media_codec_->QueueInputBuffer(input_buf_index, |
| 220 static_cast<const uint8*>(shm->memory()), | 226 static_cast<const uint8*>(shm->memory()), |
| 221 bitstream_buffer.size(), | 227 bitstream_buffer.size(), |
| 222 timestamp); | 228 timestamp); |
| 223 RETURN_ON_FAILURE(status == media::MEDIA_CODEC_OK, | 229 RETURN_ON_FAILURE(this, |
| 230 status == media::MEDIA_CODEC_OK, |
| 224 "Failed to QueueInputBuffer: " << status, | 231 "Failed to QueueInputBuffer: " << status, |
| 225 PLATFORM_FAILURE); | 232 PLATFORM_FAILURE); |
| 226 | 233 |
| 227 // We should call NotifyEndOfBitstreamBuffer(), when no more decoded output | 234 // We should call NotifyEndOfBitstreamBuffer(), when no more decoded output |
| 228 // will be returned from the bitstream buffer. However, MediaCodec API is | 235 // will be returned from the bitstream buffer. However, MediaCodec API is |
| 229 // not enough to guarantee it. | 236 // not enough to guarantee it. |
| 230 // So, here, we calls NotifyEndOfBitstreamBuffer() in advance in order to | 237 // So, here, we calls NotifyEndOfBitstreamBuffer() in advance in order to |
| 231 // keep getting more bitstreams from the client, and throttle them by using | 238 // keep getting more bitstreams from the client, and throttle them by using |
| 232 // |bitstreams_notified_in_advance_|. | 239 // |bitstreams_notified_in_advance_|. |
| 233 // TODO(dwkang): check if there is a way to remove this workaround. | 240 // TODO(dwkang): check if there is a way to remove this workaround. |
| 234 base::MessageLoop::current()->PostTask( | 241 base::MessageLoop::current()->PostTask( |
| 235 FROM_HERE, | 242 FROM_HERE, |
| 236 base::Bind(&AndroidVideoDecodeAccelerator::NotifyEndOfBitstreamBuffer, | 243 base::Bind(&AndroidVideoDecodeAcceleratorImpl::NotifyEndOfBitstreamBuffer, |
| 237 weak_this_factory_.GetWeakPtr(), | 244 weak_this_factory_.GetWeakPtr(), |
| 238 bitstream_buffer.id())); | 245 bitstream_buffer.id())); |
| 239 bitstreams_notified_in_advance_.push_back(bitstream_buffer.id()); | 246 bitstreams_notified_in_advance_.push_back(bitstream_buffer.id()); |
| 240 } | 247 } |
| 241 | 248 |
| 242 void AndroidVideoDecodeAccelerator::DequeueOutput() { | 249 void AndroidVideoDecodeAcceleratorImpl::DequeueOutput() { |
| 243 DCHECK(thread_checker_.CalledOnValidThread()); | 250 DCHECK(thread_checker_.CalledOnValidThread()); |
| 244 if (picturebuffers_requested_ && output_picture_buffers_.empty()) | 251 if (picturebuffers_requested_ && output_picture_buffers_.empty()) |
| 245 return; | 252 return; |
| 246 | 253 |
| 247 if (!output_picture_buffers_.empty() && free_picture_ids_.empty()) { | 254 if (!output_picture_buffers_.empty() && free_picture_ids_.empty()) { |
| 248 // Don't have any picture buffer to send. Need to wait more. | 255 // Don't have any picture buffer to send. Need to wait more. |
| 249 return; | 256 return; |
| 250 } | 257 } |
| 251 | 258 |
| 252 bool eos = false; | 259 bool eos = false; |
| (...skipping 12 matching lines...) Expand all Loading... |
| 265 | 272 |
| 266 case media::MEDIA_CODEC_OUTPUT_FORMAT_CHANGED: { | 273 case media::MEDIA_CODEC_OUTPUT_FORMAT_CHANGED: { |
| 267 int32 width, height; | 274 int32 width, height; |
| 268 media_codec_->GetOutputFormat(&width, &height); | 275 media_codec_->GetOutputFormat(&width, &height); |
| 269 | 276 |
| 270 if (!picturebuffers_requested_) { | 277 if (!picturebuffers_requested_) { |
| 271 picturebuffers_requested_ = true; | 278 picturebuffers_requested_ = true; |
| 272 size_ = gfx::Size(width, height); | 279 size_ = gfx::Size(width, height); |
| 273 base::MessageLoop::current()->PostTask( | 280 base::MessageLoop::current()->PostTask( |
| 274 FROM_HERE, | 281 FROM_HERE, |
| 275 base::Bind(&AndroidVideoDecodeAccelerator::RequestPictureBuffers, | 282 base::Bind(&AndroidVideoDecodeAcceleratorImpl:: |
| 283 RequestPictureBuffers, |
| 276 weak_this_factory_.GetWeakPtr())); | 284 weak_this_factory_.GetWeakPtr())); |
| 277 } else { | 285 } else { |
| 278 // Dynamic resolution change support is not specified by the Android | 286 // Dynamic resolution change support is not specified by the Android |
| 279 // platform at and before JB-MR1, so it's not possible to smoothly | 287 // platform at and before JB-MR1, so it's not possible to smoothly |
| 280 // continue playback at this point. Instead, error out immediately, | 288 // continue playback at this point. Instead, error out immediately, |
| 281 // expecting clients to Reset() as appropriate to avoid this. | 289 // expecting clients to Reset() as appropriate to avoid this. |
| 282 // b/7093648 | 290 // b/7093648 |
| 283 RETURN_ON_FAILURE(size_ == gfx::Size(width, height), | 291 RETURN_ON_FAILURE(this, |
| 292 size_ == gfx::Size(width, height), |
| 284 "Dynamic resolution change is not supported.", | 293 "Dynamic resolution change is not supported.", |
| 285 PLATFORM_FAILURE); | 294 PLATFORM_FAILURE); |
| 286 } | 295 } |
| 287 return; | 296 return; |
| 288 } | 297 } |
| 289 | 298 |
| 290 case media::MEDIA_CODEC_OUTPUT_BUFFERS_CHANGED: | 299 case media::MEDIA_CODEC_OUTPUT_BUFFERS_CHANGED: |
| 291 break; | 300 break; |
| 292 | 301 |
| 293 case media::MEDIA_CODEC_OK: | 302 case media::MEDIA_CODEC_OK: |
| 294 DCHECK_GE(buf_index, 0); | 303 DCHECK_GE(buf_index, 0); |
| 295 break; | 304 break; |
| 296 | 305 |
| 297 default: | 306 default: |
| 298 NOTREACHED(); | 307 NOTREACHED(); |
| 299 break; | 308 break; |
| 300 } | 309 } |
| 301 } while (buf_index < 0); | 310 } while (buf_index < 0); |
| 302 | 311 |
| 303 // This ignores the emitted ByteBuffer and instead relies on rendering to the | |
| 304 // codec's SurfaceTexture and then copying from that texture to the client's | |
| 305 // PictureBuffer's texture. This means that each picture's data is written | |
| 306 // three times: once to the ByteBuffer, once to the SurfaceTexture, and once | |
| 307 // to the client's texture. It would be nicer to either: | |
| 308 // 1) Render directly to the client's texture from MediaCodec (one write); or | |
| 309 // 2) Upload the ByteBuffer to the client's texture (two writes). | |
| 310 // Unfortunately neither is possible: | |
| 311 // 1) MediaCodec's use of SurfaceTexture is a singleton, and the texture | |
| 312 // written to can't change during the codec's lifetime. b/11990461 | |
| 313 // 2) The ByteBuffer is likely to contain the pixels in a vendor-specific, | |
| 314 // opaque/non-standard format. It's not possible to negotiate the decoder | |
| 315 // to emit a specific colorspace, even using HW CSC. b/10706245 | |
| 316 // So, we live with these two extra copies per picture :( | |
| 317 media_codec_->ReleaseOutputBuffer(buf_index, true); | |
| 318 | |
| 319 if (eos) { | 312 if (eos) { |
| 313 media_codec_->ReleaseOutputBuffer(buf_index, false); |
| 320 base::MessageLoop::current()->PostTask( | 314 base::MessageLoop::current()->PostTask( |
| 321 FROM_HERE, | 315 FROM_HERE, |
| 322 base::Bind(&AndroidVideoDecodeAccelerator::NotifyFlushDone, | 316 base::Bind(&AndroidVideoDecodeAcceleratorImpl::NotifyFlushDone, |
| 323 weak_this_factory_.GetWeakPtr())); | 317 weak_this_factory_.GetWeakPtr())); |
| 324 } else { | 318 } else { |
| 325 int64 bitstream_buffer_id = timestamp.InMicroseconds(); | 319 int64 bitstream_buffer_id = timestamp.InMicroseconds(); |
| 326 SendCurrentSurfaceToClient(static_cast<int32>(bitstream_buffer_id)); | 320 SendCurrentSurfaceToClient(buf_index, |
| 321 static_cast<int32>(bitstream_buffer_id)); |
| 327 | 322 |
| 328 // Removes ids former or equal than the id from decoder. Note that | 323 // Removes ids former or equal than the id from decoder. Note that |
| 329 // |bitstreams_notified_in_advance_| does not mean bitstream ids in decoder | 324 // |bitstreams_notified_in_advance_| does not mean bitstream ids in decoder |
| 330 // because of frame reordering issue. We just maintain this roughly and use | 325 // because of frame reordering issue. We just maintain this roughly and use |
| 331 // for the throttling purpose. | 326 // for the throttling purpose. |
| 332 std::list<int32>::iterator it; | 327 std::list<int32>::iterator it; |
| 333 for (it = bitstreams_notified_in_advance_.begin(); | 328 for (it = bitstreams_notified_in_advance_.begin(); |
| 334 it != bitstreams_notified_in_advance_.end(); | 329 it != bitstreams_notified_in_advance_.end(); |
| 335 ++it) { | 330 ++it) { |
| 336 if (*it == bitstream_buffer_id) { | 331 if (*it == bitstream_buffer_id) { |
| 337 bitstreams_notified_in_advance_.erase( | 332 bitstreams_notified_in_advance_.erase( |
| 338 bitstreams_notified_in_advance_.begin(), ++it); | 333 bitstreams_notified_in_advance_.begin(), ++it); |
| 339 break; | 334 break; |
| 340 } | 335 } |
| 341 } | 336 } |
| 342 } | 337 } |
| 343 } | 338 } |
| 344 | 339 |
| 345 void AndroidVideoDecodeAccelerator::SendCurrentSurfaceToClient( | 340 void AndroidVideoDecodeAcceleratorImpl::SendCurrentSurfaceToClient( |
| 341 int32 codec_buffer_index, |
| 346 int32 bitstream_id) { | 342 int32 bitstream_id) { |
| 347 DCHECK(thread_checker_.CalledOnValidThread()); | 343 DCHECK(thread_checker_.CalledOnValidThread()); |
| 348 DCHECK_NE(bitstream_id, -1); | 344 DCHECK_NE(bitstream_id, -1); |
| 349 DCHECK(!free_picture_ids_.empty()); | 345 DCHECK(!free_picture_ids_.empty()); |
| 350 | 346 |
| 351 RETURN_ON_FAILURE(make_context_current_.Run(), | 347 RETURN_ON_FAILURE(this, |
| 348 make_context_current_.Run(), |
| 352 "Failed to make this decoder's GL context current.", | 349 "Failed to make this decoder's GL context current.", |
| 353 PLATFORM_FAILURE); | 350 PLATFORM_FAILURE); |
| 354 | 351 |
| 355 int32 picture_buffer_id = free_picture_ids_.front(); | 352 int32 picture_buffer_id = free_picture_ids_.front(); |
| 356 free_picture_ids_.pop(); | 353 free_picture_ids_.pop(); |
| 357 | 354 |
| 358 float transfrom_matrix[16]; | |
| 359 surface_texture_->UpdateTexImage(); | |
| 360 surface_texture_->GetTransformMatrix(transfrom_matrix); | |
| 361 | |
| 362 OutputBufferMap::const_iterator i = | 355 OutputBufferMap::const_iterator i = |
| 363 output_picture_buffers_.find(picture_buffer_id); | 356 output_picture_buffers_.find(picture_buffer_id); |
| 364 RETURN_ON_FAILURE(i != output_picture_buffers_.end(), | 357 RETURN_ON_FAILURE(this, |
| 358 i != output_picture_buffers_.end(), |
| 365 "Can't find a PictureBuffer for " << picture_buffer_id, | 359 "Can't find a PictureBuffer for " << picture_buffer_id, |
| 366 PLATFORM_FAILURE); | 360 PLATFORM_FAILURE); |
| 367 uint32 picture_buffer_texture_id = i->second.texture_id(); | |
| 368 | 361 |
| 369 RETURN_ON_FAILURE(gl_decoder_.get(), | 362 // Connect the PictureBuffer to the decoded frame, via whatever |
| 370 "Failed to get gles2 decoder instance.", | 363 // mechanism the strategy likes. |
| 371 ILLEGAL_STATE); | 364 strategy_->AssignCurrentSurfaceToPictureBuffer(codec_buffer_index, |
| 372 // Defer initializing the CopyTextureCHROMIUMResourceManager until it is | 365 i->second); |
| 373 // needed because it takes 10s of milliseconds to initialize. | |
| 374 if (!copier_) { | |
| 375 copier_.reset(new gpu::CopyTextureCHROMIUMResourceManager()); | |
| 376 copier_->Initialize(gl_decoder_.get()); | |
| 377 } | |
| 378 | |
| 379 // Here, we copy |surface_texture_id_| to the picture buffer instead of | |
| 380 // setting new texture to |surface_texture_| by calling attachToGLContext() | |
| 381 // because: | |
| 382 // 1. Once we call detachFrameGLContext(), it deletes the texture previous | |
| 383 // attached. | |
| 384 // 2. SurfaceTexture requires us to apply a transform matrix when we show | |
| 385 // the texture. | |
| 386 // TODO(hkuang): get the StreamTexture transform matrix in GPU process | |
| 387 // instead of using default matrix crbug.com/226218. | |
| 388 const static GLfloat default_matrix[16] = {1.0f, 0.0f, 0.0f, 0.0f, | |
| 389 0.0f, 1.0f, 0.0f, 0.0f, | |
| 390 0.0f, 0.0f, 1.0f, 0.0f, | |
| 391 0.0f, 0.0f, 0.0f, 1.0f}; | |
| 392 copier_->DoCopyTextureWithTransform( | |
| 393 gl_decoder_.get(), GL_TEXTURE_EXTERNAL_OES, surface_texture_id_, | |
| 394 GL_TEXTURE_2D, picture_buffer_texture_id, GL_RGBA, GL_UNSIGNED_BYTE, | |
| 395 size_.width(), size_.height(), false, false, false, nullptr, | |
| 396 default_matrix); | |
| 397 | 366 |
| 398 // TODO(henryhsu): Pass (0, 0) as visible size will cause several test | 367 // TODO(henryhsu): Pass (0, 0) as visible size will cause several test |
| 399 // cases failed. We should make sure |size_| is coded size or visible size. | 368 // cases failed. We should make sure |size_| is coded size or visible size. |
| 400 base::MessageLoop::current()->PostTask( | 369 base::MessageLoop::current()->PostTask( |
| 401 FROM_HERE, base::Bind(&AndroidVideoDecodeAccelerator::NotifyPictureReady, | 370 FROM_HERE, |
| 402 weak_this_factory_.GetWeakPtr(), | 371 base::Bind(&AndroidVideoDecodeAcceleratorImpl::NotifyPictureReady, |
| 403 media::Picture(picture_buffer_id, bitstream_id, | 372 weak_this_factory_.GetWeakPtr(), |
| 404 gfx::Rect(size_), false))); | 373 media::Picture(picture_buffer_id, bitstream_id, |
| 374 gfx::Rect(size_), false))); |
| 405 } | 375 } |
| 406 | 376 |
| 407 void AndroidVideoDecodeAccelerator::Decode( | 377 void AndroidVideoDecodeAcceleratorImpl::Decode( |
| 408 const media::BitstreamBuffer& bitstream_buffer) { | 378 const media::BitstreamBuffer& bitstream_buffer) { |
| 409 DCHECK(thread_checker_.CalledOnValidThread()); | 379 DCHECK(thread_checker_.CalledOnValidThread()); |
| 410 if (bitstream_buffer.id() != -1 && bitstream_buffer.size() == 0) { | 380 if (bitstream_buffer.id() != -1 && bitstream_buffer.size() == 0) { |
| 411 base::MessageLoop::current()->PostTask( | 381 base::MessageLoop::current()->PostTask( |
| 412 FROM_HERE, | 382 FROM_HERE, |
| 413 base::Bind(&AndroidVideoDecodeAccelerator::NotifyEndOfBitstreamBuffer, | 383 base::Bind(&AndroidVideoDecodeAcceleratorImpl:: |
| 384 NotifyEndOfBitstreamBuffer, |
| 414 weak_this_factory_.GetWeakPtr(), | 385 weak_this_factory_.GetWeakPtr(), |
| 415 bitstream_buffer.id())); | 386 bitstream_buffer.id())); |
| 416 return; | 387 return; |
| 417 } | 388 } |
| 418 | 389 |
| 419 pending_bitstream_buffers_.push( | 390 pending_bitstream_buffers_.push( |
| 420 std::make_pair(bitstream_buffer, base::Time::Now())); | 391 std::make_pair(bitstream_buffer, base::Time::Now())); |
| 421 | 392 |
| 422 DoIOTask(); | 393 DoIOTask(); |
| 423 } | 394 } |
| 424 | 395 |
| 425 void AndroidVideoDecodeAccelerator::AssignPictureBuffers( | 396 void AndroidVideoDecodeAcceleratorImpl::RequestPictureBuffers() { |
| 397 client_->ProvidePictureBuffers(strategy_->GetNumPictureBuffers(), |
| 398 size_, strategy_->GetTextureTarget()); |
| 399 } |
| 400 |
| 401 void AndroidVideoDecodeAcceleratorImpl::AssignPictureBuffers( |
| 426 const std::vector<media::PictureBuffer>& buffers) { | 402 const std::vector<media::PictureBuffer>& buffers) { |
| 427 DCHECK(thread_checker_.CalledOnValidThread()); | 403 DCHECK(thread_checker_.CalledOnValidThread()); |
| 428 DCHECK(output_picture_buffers_.empty()); | 404 DCHECK(output_picture_buffers_.empty()); |
| 429 DCHECK(free_picture_ids_.empty()); | 405 DCHECK(free_picture_ids_.empty()); |
| 430 | 406 |
| 431 for (size_t i = 0; i < buffers.size(); ++i) { | 407 for (size_t i = 0; i < buffers.size(); ++i) { |
| 432 RETURN_ON_FAILURE(buffers[i].size() == size_, | 408 RETURN_ON_FAILURE(this, |
| 409 buffers[i].size() == size_, |
| 433 "Invalid picture buffer size was passed.", | 410 "Invalid picture buffer size was passed.", |
| 434 INVALID_ARGUMENT); | 411 INVALID_ARGUMENT); |
| 435 int32 id = buffers[i].id(); | 412 int32 id = buffers[i].id(); |
| 436 output_picture_buffers_.insert(std::make_pair(id, buffers[i])); | 413 output_picture_buffers_.insert(std::make_pair(id, buffers[i])); |
| 437 free_picture_ids_.push(id); | 414 free_picture_ids_.push(id); |
| 438 // Since the client might be re-using |picture_buffer_id| values, forget | 415 // Since the client might be re-using |picture_buffer_id| values, forget |
| 439 // about previously-dismissed IDs now. See ReusePictureBuffer() comment | 416 // about previously-dismissed IDs now. See ReusePictureBuffer() comment |
| 440 // about "zombies" for why we maintain this set in the first place. | 417 // about "zombies" for why we maintain this set in the first place. |
| 441 dismissed_picture_ids_.erase(id); | 418 dismissed_picture_ids_.erase(id); |
| 442 } | 419 } |
| 443 | 420 |
| 444 RETURN_ON_FAILURE(output_picture_buffers_.size() >= kNumPictureBuffers, | 421 RETURN_ON_FAILURE(this, |
| 422 output_picture_buffers_.size() >= |
| 423 strategy_->GetNumPictureBuffers(), |
| 445 "Invalid picture buffers were passed.", | 424 "Invalid picture buffers were passed.", |
| 446 INVALID_ARGUMENT); | 425 INVALID_ARGUMENT); |
| 447 | 426 |
| 448 DoIOTask(); | 427 DoIOTask(); |
| 449 } | 428 } |
| 450 | 429 |
| 451 void AndroidVideoDecodeAccelerator::ReusePictureBuffer( | 430 void AndroidVideoDecodeAcceleratorImpl::ReusePictureBuffer( |
| 452 int32 picture_buffer_id) { | 431 int32 picture_buffer_id) { |
| 453 DCHECK(thread_checker_.CalledOnValidThread()); | 432 DCHECK(thread_checker_.CalledOnValidThread()); |
| 454 | 433 |
| 455 // This ReusePictureBuffer() might have been in a pipe somewhere (queued in | 434 // This ReusePictureBuffer() might have been in a pipe somewhere (queued in |
| 456 // IPC, or in a PostTask either at the sender or receiver) when we sent a | 435 // IPC, or in a PostTask either at the sender or receiver) when we sent a |
| 457 // DismissPictureBuffer() for this |picture_buffer_id|. Account for such | 436 // DismissPictureBuffer() for this |picture_buffer_id|. Account for such |
| 458 // potential "zombie" IDs here. | 437 // potential "zombie" IDs here. |
| 459 if (dismissed_picture_ids_.erase(picture_buffer_id)) | 438 if (dismissed_picture_ids_.erase(picture_buffer_id)) |
| 460 return; | 439 return; |
| 461 | 440 |
| 462 free_picture_ids_.push(picture_buffer_id); | 441 free_picture_ids_.push(picture_buffer_id); |
| 463 | 442 |
| 464 DoIOTask(); | 443 DoIOTask(); |
| 465 } | 444 } |
| 466 | 445 |
| 467 void AndroidVideoDecodeAccelerator::Flush() { | 446 void AndroidVideoDecodeAcceleratorImpl::Flush() { |
| 468 DCHECK(thread_checker_.CalledOnValidThread()); | 447 DCHECK(thread_checker_.CalledOnValidThread()); |
| 469 | 448 |
| 470 Decode(media::BitstreamBuffer(-1, base::SharedMemoryHandle(), 0)); | 449 Decode(media::BitstreamBuffer(-1, base::SharedMemoryHandle(), 0)); |
| 471 } | 450 } |
| 472 | 451 |
| 473 bool AndroidVideoDecodeAccelerator::ConfigureMediaCodec() { | 452 bool AndroidVideoDecodeAcceleratorImpl::ConfigureMediaCodec() { |
| 474 DCHECK(thread_checker_.CalledOnValidThread()); | 453 DCHECK(thread_checker_.CalledOnValidThread()); |
| 475 DCHECK(surface_texture_.get()); | 454 DCHECK(surface_texture_.get()); |
| 476 | 455 |
| 477 gfx::ScopedJavaSurface surface(surface_texture_.get()); | 456 gfx::ScopedJavaSurface surface(surface_texture_.get()); |
| 478 | 457 |
| 479 // Pass a dummy 320x240 canvas size and let the codec signal the real size | 458 // Pass a dummy 320x240 canvas size and let the codec signal the real size |
| 480 // when it's known from the bitstream. | 459 // when it's known from the bitstream. |
| 481 media_codec_.reset(media::VideoCodecBridge::CreateDecoder( | 460 media_codec_.reset(media::VideoCodecBridge::CreateDecoder( |
| 482 codec_, false, gfx::Size(320, 240), surface.j_surface().obj(), NULL)); | 461 codec_, false, gfx::Size(320, 240), surface.j_surface().obj(), NULL)); |
| 483 if (!media_codec_) | 462 if (!media_codec_) |
| 484 return false; | 463 return false; |
| 485 | 464 |
| 486 io_timer_.Start(FROM_HERE, | 465 io_timer_.Start(FROM_HERE, |
| 487 DecodePollDelay(), | 466 DecodePollDelay(), |
| 488 this, | 467 this, |
| 489 &AndroidVideoDecodeAccelerator::DoIOTask); | 468 &AndroidVideoDecodeAcceleratorImpl::DoIOTask); |
| 490 return true; | 469 return true; |
| 491 } | 470 } |
| 492 | 471 |
| 493 void AndroidVideoDecodeAccelerator::Reset() { | 472 void AndroidVideoDecodeAcceleratorImpl::Reset() { |
| 494 DCHECK(thread_checker_.CalledOnValidThread()); | 473 DCHECK(thread_checker_.CalledOnValidThread()); |
| 495 | 474 |
| 496 while (!pending_bitstream_buffers_.empty()) { | 475 while (!pending_bitstream_buffers_.empty()) { |
| 497 int32 bitstream_buffer_id = pending_bitstream_buffers_.front().first.id(); | 476 int32 bitstream_buffer_id = pending_bitstream_buffers_.front().first.id(); |
| 498 pending_bitstream_buffers_.pop(); | 477 pending_bitstream_buffers_.pop(); |
| 499 | 478 |
| 500 if (bitstream_buffer_id != -1) { | 479 if (bitstream_buffer_id != -1) { |
| 501 base::MessageLoop::current()->PostTask( | 480 base::MessageLoop::current()->PostTask( |
| 502 FROM_HERE, | 481 FROM_HERE, |
| 503 base::Bind(&AndroidVideoDecodeAccelerator::NotifyEndOfBitstreamBuffer, | 482 base::Bind(&AndroidVideoDecodeAcceleratorImpl:: |
| 483 NotifyEndOfBitstreamBuffer, |
| 504 weak_this_factory_.GetWeakPtr(), | 484 weak_this_factory_.GetWeakPtr(), |
| 505 bitstream_buffer_id)); | 485 bitstream_buffer_id)); |
| 506 } | 486 } |
| 507 } | 487 } |
| 508 bitstreams_notified_in_advance_.clear(); | 488 bitstreams_notified_in_advance_.clear(); |
| 509 | 489 |
| 510 for (OutputBufferMap::iterator it = output_picture_buffers_.begin(); | 490 for (OutputBufferMap::iterator it = output_picture_buffers_.begin(); |
| 511 it != output_picture_buffers_.end(); | 491 it != output_picture_buffers_.end(); |
| 512 ++it) { | 492 ++it) { |
| 513 client_->DismissPictureBuffer(it->first); | 493 client_->DismissPictureBuffer(it->first); |
| 514 dismissed_picture_ids_.insert(it->first); | 494 dismissed_picture_ids_.insert(it->first); |
| 515 } | 495 } |
| 516 output_picture_buffers_.clear(); | 496 output_picture_buffers_.clear(); |
| 517 std::queue<int32> empty; | 497 std::queue<int32> empty; |
| 518 std::swap(free_picture_ids_, empty); | 498 std::swap(free_picture_ids_, empty); |
| 519 CHECK(free_picture_ids_.empty()); | 499 CHECK(free_picture_ids_.empty()); |
| 520 picturebuffers_requested_ = false; | 500 picturebuffers_requested_ = false; |
| 521 | 501 |
| 522 // On some devices, and up to at least JB-MR1, | 502 // On some devices, and up to at least JB-MR1, |
| 523 // - flush() can fail after EOS (b/8125974); and | 503 // - flush() can fail after EOS (b/8125974); and |
| 524 // - mid-stream resolution change is unsupported (b/7093648). | 504 // - mid-stream resolution change is unsupported (b/7093648). |
| 525 // To cope with these facts, we always stop & restart the codec on Reset(). | 505 // To cope with these facts, we always stop & restart the codec on Reset(). |
| 526 io_timer_.Stop(); | 506 io_timer_.Stop(); |
| 527 media_codec_->Stop(); | 507 media_codec_->Stop(); |
| 528 ConfigureMediaCodec(); | 508 ConfigureMediaCodec(); |
| 529 state_ = NO_ERROR; | 509 state_ = NO_ERROR; |
| 530 | 510 |
| 531 base::MessageLoop::current()->PostTask( | 511 base::MessageLoop::current()->PostTask( |
| 532 FROM_HERE, | 512 FROM_HERE, |
| 533 base::Bind(&AndroidVideoDecodeAccelerator::NotifyResetDone, | 513 base::Bind(&AndroidVideoDecodeAcceleratorImpl::NotifyResetDone, |
| 534 weak_this_factory_.GetWeakPtr())); | 514 weak_this_factory_.GetWeakPtr())); |
| 535 } | 515 } |
| 536 | 516 |
| 537 void AndroidVideoDecodeAccelerator::Destroy() { | 517 void AndroidVideoDecodeAcceleratorImpl::Destroy() { |
| 538 DCHECK(thread_checker_.CalledOnValidThread()); | 518 DCHECK(thread_checker_.CalledOnValidThread()); |
| 539 | 519 |
| 520 strategy_->Cleanup(); |
| 521 |
| 540 weak_this_factory_.InvalidateWeakPtrs(); | 522 weak_this_factory_.InvalidateWeakPtrs(); |
| 541 if (media_codec_) { | 523 if (media_codec_) { |
| 542 io_timer_.Stop(); | 524 io_timer_.Stop(); |
| 543 media_codec_->Stop(); | 525 media_codec_->Stop(); |
| 544 } | 526 } |
| 545 if (surface_texture_id_) | 527 if (surface_texture_id_) |
| 546 glDeleteTextures(1, &surface_texture_id_); | 528 glDeleteTextures(1, &surface_texture_id_); |
| 547 if (copier_) | |
| 548 copier_->Destroy(); | |
| 549 delete this; | 529 delete this; |
| 550 } | 530 } |
| 551 | 531 |
| 552 bool AndroidVideoDecodeAccelerator::CanDecodeOnIOThread() { | 532 bool AndroidVideoDecodeAcceleratorImpl::CanDecodeOnIOThread() { |
| 553 return false; | 533 return false; |
| 554 } | 534 } |
| 555 | 535 |
| 556 void AndroidVideoDecodeAccelerator::RequestPictureBuffers() { | 536 const gfx::Size& AndroidVideoDecodeAcceleratorImpl::GetSize() const { |
| 557 client_->ProvidePictureBuffers(kNumPictureBuffers, size_, GL_TEXTURE_2D); | 537 return size_; |
| 558 } | 538 } |
| 559 | 539 |
| 560 void AndroidVideoDecodeAccelerator::NotifyPictureReady( | 540 const base::ThreadChecker& |
| 541 AndroidVideoDecodeAcceleratorImpl::ThreadChecker() const { |
| 542 return thread_checker_; |
| 543 } |
| 544 |
| 545 gfx::SurfaceTexture* |
| 546 AndroidVideoDecodeAcceleratorImpl::GetSurfaceTexture() const { |
| 547 return surface_texture_.get(); |
| 548 } |
| 549 |
| 550 uint32 AndroidVideoDecodeAcceleratorImpl::GetSurfaceTextureId() const { |
| 551 return surface_texture_id_; |
| 552 } |
| 553 |
| 554 gpu::gles2::GLES2Decoder* |
| 555 AndroidVideoDecodeAcceleratorImpl::GetGlDecoder() const { |
| 556 return gl_decoder_.get(); |
| 557 } |
| 558 |
| 559 media::VideoCodecBridge* AndroidVideoDecodeAcceleratorImpl::GetMediaCodec() { |
| 560 return media_codec_.get(); |
| 561 } |
| 562 |
| 563 void AndroidVideoDecodeAcceleratorImpl::PostError( |
| 564 const ::tracked_objects::Location& from_here, |
| 565 media::VideoDecodeAccelerator::Error error) { |
| 566 base::MessageLoop::current()->PostTask(from_here, |
| 567 base::Bind(&AndroidVideoDecodeAcceleratorImpl::NotifyError, |
| 568 weak_this_factory_.GetWeakPtr(), |
| 569 error)); |
| 570 state_ = ERROR; |
| 571 } |
| 572 |
| 573 void AndroidVideoDecodeAcceleratorImpl::NotifyPictureReady( |
| 561 const media::Picture& picture) { | 574 const media::Picture& picture) { |
| 562 client_->PictureReady(picture); | 575 client_->PictureReady(picture); |
| 563 } | 576 } |
| 564 | 577 |
| 565 void AndroidVideoDecodeAccelerator::NotifyEndOfBitstreamBuffer( | 578 void AndroidVideoDecodeAcceleratorImpl::NotifyEndOfBitstreamBuffer( |
| 566 int input_buffer_id) { | 579 int input_buffer_id) { |
| 567 client_->NotifyEndOfBitstreamBuffer(input_buffer_id); | 580 client_->NotifyEndOfBitstreamBuffer(input_buffer_id); |
| 568 } | 581 } |
| 569 | 582 |
| 570 void AndroidVideoDecodeAccelerator::NotifyFlushDone() { | 583 void AndroidVideoDecodeAcceleratorImpl::NotifyFlushDone() { |
| 571 client_->NotifyFlushDone(); | 584 client_->NotifyFlushDone(); |
| 572 } | 585 } |
| 573 | 586 |
| 574 void AndroidVideoDecodeAccelerator::NotifyResetDone() { | 587 void AndroidVideoDecodeAcceleratorImpl::NotifyResetDone() { |
| 575 client_->NotifyResetDone(); | 588 client_->NotifyResetDone(); |
| 576 } | 589 } |
| 577 | 590 |
| 578 void AndroidVideoDecodeAccelerator::NotifyError( | 591 void AndroidVideoDecodeAcceleratorImpl::NotifyError( |
| 579 media::VideoDecodeAccelerator::Error error) { | 592 media::VideoDecodeAccelerator::Error error) { |
| 580 client_->NotifyError(error); | 593 client_->NotifyError(error); |
| 581 } | 594 } |
| 582 | 595 |
| 583 // static | 596 // static |
| 584 media::VideoDecodeAccelerator::SupportedProfiles | 597 media::VideoDecodeAccelerator::SupportedProfiles |
| 585 AndroidVideoDecodeAccelerator::GetSupportedProfiles() { | 598 AndroidVideoDecodeAccelerator::GetSupportedProfiles() { |
| 586 SupportedProfiles profiles; | 599 SupportedProfiles profiles; |
| 587 | 600 |
| 588 if (!media::VideoCodecBridge::IsKnownUnaccelerated( | 601 if (!media::VideoCodecBridge::IsKnownUnaccelerated( |
| (...skipping 24 matching lines...) Expand all Loading... |
| 613 // software fallback for H264 on Android anyway. | 626 // software fallback for H264 on Android anyway. |
| 614 profile.max_resolution.SetSize(3840, 2160); | 627 profile.max_resolution.SetSize(3840, 2160); |
| 615 profiles.push_back(profile); | 628 profiles.push_back(profile); |
| 616 } | 629 } |
| 617 #endif | 630 #endif |
| 618 | 631 |
| 619 return profiles; | 632 return profiles; |
| 620 } | 633 } |
| 621 | 634 |
| 622 } // namespace content | 635 } // namespace content |
| OLD | NEW |