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 decoder job so that it |
wolenetz
2014/05/21 00:48:04
nit: pass to decoder job? we are the decoder job.
qinmin
2014/05/22 00:35:55
Fixed, should be |media_codec_bridge_|.
On 2014/05
| |
50 const base::Closure& release_resources_cb) | 48 // can detach from the current one. Otherwise, don't pass an unprotected |
51 : MediaDecoderJob(g_video_decoder_thread.Pointer()->message_loop_proxy(), | 49 // 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 |