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 "media/base/android/video_decoder_job.h" | 5 #include "media/base/android/video_decoder_job.h" |
6 | 6 |
7 #include "base/bind.h" | 7 #include "base/bind.h" |
8 #include "base/lazy_instance.h" | 8 #include "base/lazy_instance.h" |
9 #include "base/threading/thread.h" | 9 #include "base/threading/thread.h" |
10 #include "media/base/android/media_codec_bridge.h" | 10 #include "media/base/android/media_codec_bridge.h" |
| 11 #include "media/base/android/media_drm_bridge.h" |
11 | 12 |
12 namespace media { | 13 namespace media { |
13 | 14 |
14 class VideoDecoderThread : public base::Thread { | 15 class VideoDecoderThread : public base::Thread { |
15 public: | 16 public: |
16 VideoDecoderThread() : base::Thread("MediaSource_VideoDecoderThread") { | 17 VideoDecoderThread() : base::Thread("MediaSource_VideoDecoderThread") { |
17 Start(); | 18 Start(); |
18 } | 19 } |
19 }; | 20 }; |
20 | 21 |
21 // TODO(qinmin): Check if it is tolerable to use worker pool to handle all the | 22 // TODO(qinmin): Check if it is tolerable to use worker pool to handle all the |
22 // decoding tasks so that we don't need a global thread here. | 23 // decoding tasks so that we don't need a global thread here. |
23 // http://crbug.com/245750 | 24 // http://crbug.com/245750 |
24 base::LazyInstance<VideoDecoderThread>::Leaky | 25 base::LazyInstance<VideoDecoderThread>::Leaky |
25 g_video_decoder_thread = LAZY_INSTANCE_INITIALIZER; | 26 g_video_decoder_thread = LAZY_INSTANCE_INITIALIZER; |
26 | 27 |
27 VideoDecoderJob* VideoDecoderJob::Create( | 28 VideoDecoderJob::VideoDecoderJob( |
28 const VideoCodec video_codec, | |
29 bool is_secure, | |
30 const gfx::Size& size, | |
31 jobject surface, | |
32 jobject media_crypto, | |
33 const base::Closure& request_data_cb, | 29 const base::Closure& request_data_cb, |
34 const base::Closure& request_resources_cb, | 30 const base::Closure& request_resources_cb, |
35 const base::Closure& release_resources_cb) { | 31 const base::Closure& release_resources_cb, |
36 scoped_ptr<VideoCodecBridge> codec(VideoCodecBridge::CreateDecoder( | 32 const base::Closure& on_demuxer_config_changed_cb) |
37 video_codec, is_secure, size, surface, media_crypto)); | 33 : MediaDecoderJob(g_video_decoder_thread.Pointer()->message_loop_proxy(), |
38 if (codec) | 34 request_data_cb, |
39 return new VideoDecoderJob(codec.Pass(), request_data_cb, | 35 on_demuxer_config_changed_cb), |
40 request_resources_cb, release_resources_cb); | 36 video_codec_(kUnknownVideoCodec), |
41 | 37 width_(0), |
42 LOG(ERROR) << "Failed to create VideoDecoderJob."; | 38 height_(0), |
43 return NULL; | 39 request_resources_cb_(request_resources_cb), |
| 40 release_resources_cb_(release_resources_cb), |
| 41 next_video_data_is_iframe_(true) { |
44 } | 42 } |
45 | 43 |
46 VideoDecoderJob::VideoDecoderJob( | 44 VideoDecoderJob::~VideoDecoderJob() {} |
47 scoped_ptr<VideoCodecBridge> video_codec_bridge, | 45 |
48 const base::Closure& request_data_cb, | 46 bool VideoDecoderJob::SetVideoSurface(gfx::ScopedJavaSurface surface) { |
49 const base::Closure& request_resources_cb, | 47 // For an empty surface, always pass it to the |media_codec_bridge_| job so |
50 const base::Closure& release_resources_cb) | 48 // that it can detach from the current one. Otherwise, don't pass an |
51 : MediaDecoderJob(g_video_decoder_thread.Pointer()->message_loop_proxy(), | 49 // unprotected surface if the video content requires a protected one. |
52 video_codec_bridge.get(), request_data_cb), | 50 if (!surface.IsEmpty() && IsProtectedSurfaceRequired() && |
53 video_codec_bridge_(video_codec_bridge.Pass()), | 51 !surface.is_protected()) { |
54 release_resources_cb_(release_resources_cb) { | 52 return false; |
55 request_resources_cb.Run(); | 53 } |
| 54 |
| 55 surface_ = surface.Pass(); |
| 56 need_to_reconfig_decoder_job_ = true; |
| 57 return true; |
56 } | 58 } |
57 | 59 |
58 VideoDecoderJob::~VideoDecoderJob() { | 60 bool VideoDecoderJob::HasStream() const { |
59 release_resources_cb_.Run(); | 61 return video_codec_ != kUnknownVideoCodec; |
| 62 } |
| 63 |
| 64 void VideoDecoderJob::Flush() { |
| 65 MediaDecoderJob::Flush(); |
| 66 next_video_data_is_iframe_ = true; |
| 67 } |
| 68 |
| 69 void VideoDecoderJob::ReleaseDecoderResources() { |
| 70 MediaDecoderJob::ReleaseDecoderResources(); |
| 71 surface_ = gfx::ScopedJavaSurface(); |
60 } | 72 } |
61 | 73 |
62 void VideoDecoderJob::ReleaseOutputBuffer( | 74 void VideoDecoderJob::ReleaseOutputBuffer( |
63 int output_buffer_index, | 75 int output_buffer_index, |
64 size_t size, | 76 size_t size, |
65 bool render_output, | 77 bool render_output, |
66 base::TimeDelta current_presentation_timestamp, | 78 base::TimeDelta current_presentation_timestamp, |
67 const ReleaseOutputCompletionCallback& callback) { | 79 const ReleaseOutputCompletionCallback& callback) { |
68 video_codec_bridge_->ReleaseOutputBuffer(output_buffer_index, render_output); | 80 media_codec_bridge_->ReleaseOutputBuffer(output_buffer_index, render_output); |
69 callback.Run(current_presentation_timestamp, current_presentation_timestamp); | 81 callback.Run(current_presentation_timestamp, current_presentation_timestamp); |
70 } | 82 } |
71 | 83 |
72 bool VideoDecoderJob::ComputeTimeToRender() const { | 84 bool VideoDecoderJob::ComputeTimeToRender() const { |
73 return true; | 85 return true; |
74 } | 86 } |
75 | 87 |
| 88 void VideoDecoderJob::UpdateDemuxerConfigs(const DemuxerConfigs& configs) { |
| 89 video_codec_ = configs.video_codec; |
| 90 width_ = configs.video_size.width(); |
| 91 height_ = configs.video_size.height(); |
| 92 set_is_content_encrypted(configs.is_video_encrypted); |
| 93 } |
| 94 |
| 95 bool VideoDecoderJob::IsDemuxerConfigChanged( |
| 96 const DemuxerConfigs& configs) const { |
| 97 return video_codec_ != configs.video_codec || |
| 98 is_content_encrypted() != configs.is_video_encrypted || |
| 99 width_ != configs.video_size.width() || |
| 100 height_ != configs.video_size.height(); |
| 101 } |
| 102 |
| 103 bool VideoDecoderJob::CreateMediaCodecBridgeInternal() { |
| 104 if (surface_.IsEmpty()) { |
| 105 ReleaseMediaCodecBridge(); |
| 106 return false; |
| 107 } |
| 108 |
| 109 // If the next data is not iframe, return false so that the player need to |
| 110 // perform a browser seek. |
| 111 if (!next_video_data_is_iframe_) |
| 112 return false; |
| 113 |
| 114 bool is_secure = is_content_encrypted() && drm_bridge() && |
| 115 drm_bridge()->IsProtectedSurfaceRequired(); |
| 116 |
| 117 media_codec_bridge_.reset(VideoCodecBridge::CreateDecoder( |
| 118 video_codec_, is_secure, gfx::Size(width_, height_), |
| 119 surface_.j_surface().obj(), GetMediaCrypto().obj())); |
| 120 |
| 121 if (!media_codec_bridge_) |
| 122 return false; |
| 123 |
| 124 request_resources_cb_.Run(); |
| 125 return true; |
| 126 } |
| 127 |
| 128 void VideoDecoderJob::CurrentDataConsumed(bool is_config_change) { |
| 129 next_video_data_is_iframe_ = is_config_change; |
| 130 } |
| 131 |
| 132 void VideoDecoderJob::OnMediaCodecBridgeReleased() { |
| 133 release_resources_cb_.Run(); |
| 134 } |
| 135 |
| 136 bool VideoDecoderJob::IsProtectedSurfaceRequired() { |
| 137 return is_content_encrypted() && drm_bridge() && |
| 138 drm_bridge()->IsProtectedSurfaceRequired(); |
| 139 } |
| 140 |
76 } // namespace media | 141 } // namespace media |
OLD | NEW |