| 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 |