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 <algorithm> | 5 #include <algorithm> |
6 #include <string> | 6 #include <string> |
7 | 7 |
8 #include "base/callback.h" | 8 #include "base/callback.h" |
9 #include "base/logging.h" | 9 #include "base/logging.h" |
10 #include "base/message_loop.h" | 10 #include "base/message_loop.h" |
11 #include "base/stl_util-inl.h" | 11 #include "base/stl_util-inl.h" |
12 #include "base/string_util.h" | 12 #include "base/string_util.h" |
13 #include "media/omx/omx_codec.h" | 13 #include "media/omx/omx_codec.h" |
14 #include "media/base/buffers.h" | 14 #include "media/base/buffers.h" |
15 #include "media/omx/omx_output_sink.h" | |
16 | 15 |
17 namespace media { | 16 namespace media { |
18 | 17 |
19 #if !defined(COMPILER_MSVC) | 18 #if !defined(COMPILER_MSVC) |
20 int const OmxCodec::kEosBuffer; | 19 int const OmxCodec::kEosBuffer; |
21 #endif | 20 #endif |
22 | 21 |
23 template <typename T> | 22 template <typename T> |
24 static void ResetPortHeader(const OmxCodec& dec, T* param) { | 23 static void ResetPortHeader(const OmxCodec& dec, T* param) { |
25 memset(param, 0, sizeof(T)); | 24 memset(param, 0, sizeof(T)); |
(...skipping 14 matching lines...) Expand all Loading... |
40 next_state_(kEmpty), | 39 next_state_(kEmpty), |
41 component_handle_(NULL), | 40 component_handle_(NULL), |
42 message_loop_(message_loop) { | 41 message_loop_(message_loop) { |
43 } | 42 } |
44 | 43 |
45 OmxCodec::~OmxCodec() { | 44 OmxCodec::~OmxCodec() { |
46 DCHECK(state_ == kError || state_ == kEmpty); | 45 DCHECK(state_ == kError || state_ == kEmpty); |
47 DCHECK_EQ(0u, input_buffers_.size()); | 46 DCHECK_EQ(0u, input_buffers_.size()); |
48 DCHECK_EQ(0u, output_buffers_.size()); | 47 DCHECK_EQ(0u, output_buffers_.size()); |
49 DCHECK(available_input_buffers_.empty()); | 48 DCHECK(available_input_buffers_.empty()); |
50 DCHECK(output_buffers_in_use_.empty()); | |
51 DCHECK(pending_input_queue_.empty()); | 49 DCHECK(pending_input_queue_.empty()); |
52 DCHECK(output_queue_.empty()); | 50 DCHECK(output_queue_.empty()); |
53 DCHECK(processing_input_queue_.empty()); | 51 DCHECK(processing_input_queue_.empty()); |
54 } | 52 } |
55 | 53 |
56 void OmxCodec::Setup(OmxConfigurator* configurator, | 54 void OmxCodec::Setup(OmxConfigurator* configurator) { |
57 OmxOutputSink* output_sink) { | |
58 DCHECK_EQ(kEmpty, state_); | 55 DCHECK_EQ(kEmpty, state_); |
59 | |
60 CHECK(configurator); | 56 CHECK(configurator); |
61 CHECK(output_sink); | |
62 | |
63 configurator_ = configurator; | 57 configurator_ = configurator; |
64 output_sink_ = output_sink; | |
65 } | 58 } |
66 | 59 |
67 void OmxCodec::SetErrorCallback(Callback* callback) { | 60 void OmxCodec::SetErrorCallback(Callback* callback) { |
68 DCHECK_EQ(kEmpty, state_); | 61 DCHECK_EQ(kEmpty, state_); |
69 error_callback_.reset(callback); | 62 error_callback_.reset(callback); |
70 } | 63 } |
71 | 64 |
72 void OmxCodec::SetFormatCallback(FormatCallback* callback) { | 65 void OmxCodec::SetFormatCallback(FormatCallback* callback) { |
73 DCHECK_EQ(kEmpty, state_); | 66 DCHECK_EQ(kEmpty, state_); |
74 format_callback_.reset(callback); | 67 format_callback_.reset(callback); |
75 } | 68 } |
76 | 69 |
77 void OmxCodec::Start() { | 70 void OmxCodec::Start() { |
78 CHECK(configurator_); | 71 CHECK(configurator_); |
79 CHECK(output_sink_); | |
80 | 72 |
81 message_loop_->PostTask( | 73 message_loop_->PostTask( |
82 FROM_HERE, | 74 FROM_HERE, |
83 NewRunnableMethod(this, &OmxCodec::StartTask)); | 75 NewRunnableMethod(this, &OmxCodec::StartTask)); |
84 } | 76 } |
85 | 77 |
86 void OmxCodec::Stop(Callback* callback) { | 78 void OmxCodec::Stop(Callback* callback) { |
87 message_loop_->PostTask( | 79 message_loop_->PostTask( |
88 FROM_HERE, | 80 FROM_HERE, |
89 NewRunnableMethod(this, &OmxCodec::StopTask, callback)); | 81 NewRunnableMethod(this, &OmxCodec::StopTask, callback)); |
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
159 StateTransitionTask(kLoaded); | 151 StateTransitionTask(kLoaded); |
160 else if (GetState() == kLoaded) | 152 else if (GetState() == kLoaded) |
161 StateTransitionTask(kEmpty); | 153 StateTransitionTask(kEmpty); |
162 } | 154 } |
163 | 155 |
164 void OmxCodec::ReadTask(ReadCallback* callback) { | 156 void OmxCodec::ReadTask(ReadCallback* callback) { |
165 DCHECK_EQ(message_loop_, MessageLoop::current()); | 157 DCHECK_EQ(message_loop_, MessageLoop::current()); |
166 | 158 |
167 // Don't accept read request on error state. | 159 // Don't accept read request on error state. |
168 if (!CanAcceptOutput()) { | 160 if (!CanAcceptOutput()) { |
169 callback->Run( | 161 callback->Run(static_cast<OMX_BUFFERHEADERTYPE*>(NULL)); |
170 kEosBuffer, | |
171 static_cast<OmxOutputSink::BufferUsedCallback*>(NULL)); | |
172 delete callback; | 162 delete callback; |
173 return; | 163 return; |
174 } | 164 } |
175 | 165 |
176 // If output has been reached then enqueue an end-of-stream buffer. | 166 // If output has been reached then enqueue an end-of-stream buffer. |
177 if (output_eos_) | 167 if (output_eos_) |
178 output_buffers_ready_.push(kEosBuffer); | 168 output_buffers_ready_.push(kEosBuffer); |
179 | 169 |
180 // Queue this request. | 170 // Queue this request. |
181 output_queue_.push(callback); | 171 output_queue_.push(callback); |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
225 } | 215 } |
226 | 216 |
227 // This method assumes OMX_AllocateBuffer() will allocate buffer | 217 // This method assumes OMX_AllocateBuffer() will allocate buffer |
228 // header internally. In additional to that memory that holds the | 218 // header internally. In additional to that memory that holds the |
229 // header, the same method call will allocate memory for holding | 219 // header, the same method call will allocate memory for holding |
230 // output data. If we use EGL images for holding output data, | 220 // output data. If we use EGL images for holding output data, |
231 // the memory allocation will be done externally. | 221 // the memory allocation will be done externally. |
232 bool OmxCodec::AllocateOutputBuffers() { | 222 bool OmxCodec::AllocateOutputBuffers() { |
233 DCHECK_EQ(message_loop_, MessageLoop::current()); | 223 DCHECK_EQ(message_loop_, MessageLoop::current()); |
234 | 224 |
235 if (output_sink_->ProvidesEGLImages()) { | 225 for (int i = 0; i < output_buffer_count_; ++i) { |
236 // TODO(hclam): Do the following things here: | 226 OMX_BUFFERHEADERTYPE* buffer; |
237 // 1. Call output_sink_->AllocateEGLImages() to allocate some | 227 OMX_ERRORTYPE error = |
238 // EGL images from the sink component. | 228 OMX_AllocateBuffer(component_handle_, &buffer, output_port_, |
239 // 2. Call OMX_UseEGLImage() to assign the images to the output | 229 NULL, output_buffer_size_); |
240 // port. | 230 if (error != OMX_ErrorNone) |
241 NOTIMPLEMENTED(); | 231 return false; |
242 } else { | 232 output_buffers_.push_back(buffer); |
243 for (int i = 0; i < output_buffer_count_; ++i) { | |
244 OMX_BUFFERHEADERTYPE* buffer; | |
245 OMX_ERRORTYPE error = | |
246 OMX_AllocateBuffer(component_handle_, &buffer, output_port_, | |
247 NULL, output_buffer_size_); | |
248 if (error != OMX_ErrorNone) | |
249 return false; | |
250 output_buffers_.push_back(buffer); | |
251 } | |
252 } | |
253 | |
254 // Tell the sink component to use the buffers for output. | |
255 for (size_t i = 0; i < output_buffers_.size(); ++i) { | |
256 output_sink_->UseThisBuffer(static_cast<int>(i), | |
257 output_buffers_[i]); | |
258 } | 233 } |
259 | 234 |
260 return true; | 235 return true; |
261 } | 236 } |
262 | 237 |
263 void OmxCodec::FreeInputBuffers() { | 238 void OmxCodec::FreeInputBuffers() { |
264 DCHECK_EQ(message_loop_, MessageLoop::current()); | 239 DCHECK_EQ(message_loop_, MessageLoop::current()); |
265 | 240 |
266 // Calls to OMX to free buffers. | 241 // Calls to OMX to free buffers. |
267 for (size_t i = 0; i < input_buffers_.size(); ++i) | 242 for (size_t i = 0; i < input_buffers_.size(); ++i) |
268 OMX_FreeBuffer(component_handle_, input_port_, input_buffers_[i]); | 243 OMX_FreeBuffer(component_handle_, input_port_, input_buffers_[i]); |
269 input_buffers_.clear(); | 244 input_buffers_.clear(); |
270 | 245 |
271 // Empty available buffer queue. | 246 // Empty available buffer queue. |
272 while (!available_input_buffers_.empty()) { | 247 while (!available_input_buffers_.empty()) { |
273 available_input_buffers_.pop(); | 248 available_input_buffers_.pop(); |
274 } | 249 } |
275 } | 250 } |
276 | 251 |
277 void OmxCodec::FreeOutputBuffers() { | 252 void OmxCodec::FreeOutputBuffers() { |
278 DCHECK_EQ(message_loop_, MessageLoop::current()); | 253 DCHECK_EQ(message_loop_, MessageLoop::current()); |
279 | 254 |
280 // First we need to make sure output sink is not using the buffer so | |
281 // tell it to stop using our buffer headers. | |
282 // TODO(hclam): We should make this an asynchronous call so that | |
283 // we'll wait until all buffers are not used. | |
284 for (size_t i = 0; i < output_buffers_.size(); ++i) | |
285 output_sink_->StopUsingThisBuffer(static_cast<int>(i)); | |
286 | |
287 // Calls to OMX to free buffers. | 255 // Calls to OMX to free buffers. |
288 for (size_t i = 0; i < output_buffers_.size(); ++i) | 256 for (size_t i = 0; i < output_buffers_.size(); ++i) |
289 OMX_FreeBuffer(component_handle_, output_port_, output_buffers_[i]); | 257 OMX_FreeBuffer(component_handle_, output_port_, output_buffers_[i]); |
290 output_buffers_.clear(); | 258 output_buffers_.clear(); |
291 | |
292 // If we have asked the sink component to provide us EGL images for | |
293 // output we need to tell it we are done with those images. | |
294 // TODO(hclam): Implement this correctly. | |
295 if (output_sink_->ProvidesEGLImages()) { | |
296 std::vector<EGLImageKHR> images; | |
297 output_sink_->ReleaseEGLImages(images); | |
298 } | |
299 } | 259 } |
300 | 260 |
301 void OmxCodec::FreeInputQueue() { | 261 void OmxCodec::FreeInputQueue() { |
302 DCHECK_EQ(message_loop_, MessageLoop::current()); | 262 DCHECK_EQ(message_loop_, MessageLoop::current()); |
303 | 263 |
304 while (!pending_input_queue_.empty()) { | 264 while (!pending_input_queue_.empty()) { |
305 scoped_refptr<Buffer> buffer = pending_input_queue_.front().first; | 265 scoped_refptr<Buffer> buffer = pending_input_queue_.front().first; |
306 FeedCallback* callback = pending_input_queue_.front().second; | 266 FeedCallback* callback = pending_input_queue_.front().second; |
307 callback->Run(buffer); | 267 callback->Run(buffer); |
308 delete callback; | 268 delete callback; |
(...skipping 803 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1112 | 1072 |
1113 if (!output_queue_.empty() && !output_buffers_ready_.empty()) { | 1073 if (!output_queue_.empty() && !output_buffers_ready_.empty()) { |
1114 int buffer_id = output_buffers_ready_.front(); | 1074 int buffer_id = output_buffers_ready_.front(); |
1115 output_buffers_ready_.pop(); | 1075 output_buffers_ready_.pop(); |
1116 ReadCallback* callback = output_queue_.front(); | 1076 ReadCallback* callback = output_queue_.front(); |
1117 output_queue_.pop(); | 1077 output_queue_.pop(); |
1118 | 1078 |
1119 // If the buffer is real then save it to the in-use list. | 1079 // If the buffer is real then save it to the in-use list. |
1120 // Otherwise if it is an end-of-stream buffer then just drop it. | 1080 // Otherwise if it is an end-of-stream buffer then just drop it. |
1121 if (buffer_id != kEosBuffer) { | 1081 if (buffer_id != kEosBuffer) { |
1122 output_buffers_in_use_.push_back(buffer_id); | 1082 callback->Run(output_buffers_[buffer_id]); |
1123 callback->Run(buffer_id, | 1083 BufferUsedCallback(buffer_id); //hack, we will change this really soon. |
1124 NewCallback(this, &OmxCodec::BufferUsedCallback)); | |
1125 } else { | 1084 } else { |
1126 callback->Run(kEosBuffer, | 1085 callback->Run(static_cast<OMX_BUFFERHEADERTYPE*>(NULL)); |
1127 static_cast<OmxOutputSink::BufferUsedCallback*>(NULL)); | |
1128 } | 1086 } |
1129 delete callback; | 1087 delete callback; |
1130 } | 1088 } |
1131 } | 1089 } |
1132 | 1090 |
1133 void OmxCodec::BufferUsedCallback(int buffer_id) { | 1091 void OmxCodec::BufferUsedCallback(int buffer_id) { |
1134 // If this method is called on the message loop where OmxCodec belongs, we | 1092 // If this method is called on the message loop where OmxCodec belongs, we |
1135 // execute the task directly to save posting another task. | 1093 // execute the task directly to save posting another task. |
1136 if (message_loop_ == MessageLoop::current()) { | 1094 if (message_loop_ == MessageLoop::current()) { |
1137 BufferUsedTask(buffer_id); | 1095 BufferUsedTask(buffer_id); |
(...skipping 13 matching lines...) Expand all Loading... |
1151 // receive end-of-stream buffers from OpenMAX. | 1109 // receive end-of-stream buffers from OpenMAX. |
1152 // It is possible to not submit FillThisBuffer() after the first | 1110 // It is possible to not submit FillThisBuffer() after the first |
1153 // end-of-stream buffer is received from OpenMAX, but that will complicate | 1111 // end-of-stream buffer is received from OpenMAX, but that will complicate |
1154 // the logic and so we rely on OpenMAX to do the right thing. | 1112 // the logic and so we rely on OpenMAX to do the right thing. |
1155 void OmxCodec::BufferUsedTask(int buffer_id) { | 1113 void OmxCodec::BufferUsedTask(int buffer_id) { |
1156 DCHECK_EQ(message_loop_, MessageLoop::current()); | 1114 DCHECK_EQ(message_loop_, MessageLoop::current()); |
1157 | 1115 |
1158 // Make sure an end-of-stream buffer id is not received here. | 1116 // Make sure an end-of-stream buffer id is not received here. |
1159 CHECK(buffer_id != kEosBuffer); | 1117 CHECK(buffer_id != kEosBuffer); |
1160 | 1118 |
1161 // The use of |output_buffers_in_use_| is just a precaution. So we can | |
1162 // actually move it to a debugging section. | |
1163 OutputBuffersInUseSet::iterator iter = | |
1164 std::find(output_buffers_in_use_.begin(), | |
1165 output_buffers_in_use_.end(), | |
1166 buffer_id); | |
1167 | |
1168 if (iter == output_buffers_in_use_.end()) { | |
1169 LOG(ERROR) << "Received an unknown buffer id: " << buffer_id; | |
1170 StateTransitionTask(kError); | |
1171 } | |
1172 output_buffers_in_use_.erase(iter); | |
1173 | |
1174 // We'll try to issue more FillThisBuffer() to the decoder. | 1119 // We'll try to issue more FillThisBuffer() to the decoder. |
1175 // If we can't do it now then just return. | 1120 // If we can't do it now then just return. |
1176 if (!CanFillBuffer()) | 1121 if (!CanFillBuffer()) |
1177 return; | 1122 return; |
1178 | 1123 |
1179 CHECK(buffer_id >= 0 && | 1124 CHECK(buffer_id >= 0 && |
1180 buffer_id < static_cast<int>(output_buffers_.size())); | 1125 buffer_id < static_cast<int>(output_buffers_.size())); |
1181 OMX_BUFFERHEADERTYPE* omx_buffer = output_buffers_[buffer_id]; | 1126 OMX_BUFFERHEADERTYPE* omx_buffer = output_buffers_[buffer_id]; |
1182 | 1127 |
1183 omx_buffer->nOutputPortIndex = output_port_; | 1128 omx_buffer->nOutputPortIndex = output_port_; |
(...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1305 OMX_ERRORTYPE OmxCodec::FillBufferCallback( | 1250 OMX_ERRORTYPE OmxCodec::FillBufferCallback( |
1306 OMX_HANDLETYPE component, | 1251 OMX_HANDLETYPE component, |
1307 OMX_PTR priv_data, | 1252 OMX_PTR priv_data, |
1308 OMX_BUFFERHEADERTYPE* buffer) { | 1253 OMX_BUFFERHEADERTYPE* buffer) { |
1309 OmxCodec* decoder = static_cast<OmxCodec*>(priv_data); | 1254 OmxCodec* decoder = static_cast<OmxCodec*>(priv_data); |
1310 decoder->FillBufferCallbackInternal(component, buffer); | 1255 decoder->FillBufferCallbackInternal(component, buffer); |
1311 return OMX_ErrorNone; | 1256 return OMX_ErrorNone; |
1312 } | 1257 } |
1313 | 1258 |
1314 } // namespace media | 1259 } // namespace media |
OLD | NEW |