| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #ifndef CONTENT_COMMON_GPU_MEDIA_OMX_VIDEO_DECODE_ACCELERATOR_H_ | |
| 6 #define CONTENT_COMMON_GPU_MEDIA_OMX_VIDEO_DECODE_ACCELERATOR_H_ | |
| 7 | |
| 8 #include <dlfcn.h> | |
| 9 #include <map> | |
| 10 #include <queue> | |
| 11 #include <set> | |
| 12 #include <string> | |
| 13 #include <utility> | |
| 14 #include <vector> | |
| 15 | |
| 16 #include "base/compiler_specific.h" | |
| 17 #include "base/logging.h" | |
| 18 #include "base/memory/shared_memory.h" | |
| 19 #include "base/message_loop/message_loop.h" | |
| 20 #include "content/common/content_export.h" | |
| 21 #include "media/video/video_decode_accelerator.h" | |
| 22 #include "third_party/openmax/il/OMX_Component.h" | |
| 23 #include "third_party/openmax/il/OMX_Core.h" | |
| 24 #include "third_party/openmax/il/OMX_Video.h" | |
| 25 #include "ui/gl/gl_bindings.h" | |
| 26 | |
| 27 namespace content { | |
| 28 class Gles2TextureToEglImageTranslator; | |
| 29 | |
| 30 // Class to wrap OpenMAX IL accelerator behind VideoDecodeAccelerator interface. | |
| 31 // The implementation assumes an OpenMAX IL 1.1.2 implementation conforming to | |
| 32 // http://www.khronos.org/registry/omxil/specs/OpenMAX_IL_1_1_2_Specification.pd
f | |
| 33 // | |
| 34 // This class lives on a single thread (the GPU process ChildThread) and DCHECKs | |
| 35 // that it is never accessed from any other. OMX callbacks are trampolined from | |
| 36 // the OMX component's thread to maintain this invariant, using |weak_this()|. | |
| 37 class CONTENT_EXPORT OmxVideoDecodeAccelerator : | |
| 38 public media::VideoDecodeAccelerator { | |
| 39 public: | |
| 40 // Does not take ownership of |client| which must outlive |*this|. | |
| 41 OmxVideoDecodeAccelerator( | |
| 42 EGLDisplay egl_display, EGLContext egl_context, | |
| 43 media::VideoDecodeAccelerator::Client* client, | |
| 44 const base::Callback<bool(void)>& make_context_current); | |
| 45 virtual ~OmxVideoDecodeAccelerator(); | |
| 46 | |
| 47 // media::VideoDecodeAccelerator implementation. | |
| 48 bool Initialize(media::VideoCodecProfile profile) OVERRIDE; | |
| 49 void Decode(const media::BitstreamBuffer& bitstream_buffer) OVERRIDE; | |
| 50 virtual void AssignPictureBuffers( | |
| 51 const std::vector<media::PictureBuffer>& buffers) OVERRIDE; | |
| 52 void ReusePictureBuffer(int32 picture_buffer_id) OVERRIDE; | |
| 53 void Flush() OVERRIDE; | |
| 54 void Reset() OVERRIDE; | |
| 55 void Destroy() OVERRIDE; | |
| 56 | |
| 57 base::WeakPtr<OmxVideoDecodeAccelerator> weak_this() { return weak_this_; } | |
| 58 | |
| 59 // Do any necessary initialization before the sandbox is enabled. | |
| 60 static void PreSandboxInitialization(); | |
| 61 | |
| 62 private: | |
| 63 // Because OMX state-transitions are described solely by the "state reached" | |
| 64 // (3.1.2.9.1, table 3-7 of the spec), we track what transition was requested | |
| 65 // using this enum. Note that it is an error to request a transition while | |
| 66 // |*this| is in any state other than NO_TRANSITION, unless requesting | |
| 67 // DESTROYING or ERRORING. | |
| 68 enum CurrentStateChange { | |
| 69 NO_TRANSITION, // Not in the middle of a transition. | |
| 70 INITIALIZING, | |
| 71 FLUSHING, | |
| 72 RESETTING, | |
| 73 DESTROYING, | |
| 74 ERRORING, // Trumps all other transitions; no recovery is possible. | |
| 75 }; | |
| 76 | |
| 77 // Add codecs as we get HW that supports them (and which are supported by SW | |
| 78 // decode!). | |
| 79 enum Codec { | |
| 80 UNKNOWN, | |
| 81 H264, | |
| 82 VP8 | |
| 83 }; | |
| 84 | |
| 85 // Helper struct for keeping track of the relationship between an OMX output | |
| 86 // buffer and the PictureBuffer it points to. | |
| 87 struct OutputPicture { | |
| 88 OutputPicture(media::PictureBuffer p_b, OMX_BUFFERHEADERTYPE* o_b_h, | |
| 89 EGLImageKHR e_i) | |
| 90 : picture_buffer(p_b), omx_buffer_header(o_b_h), egl_image(e_i) {} | |
| 91 media::PictureBuffer picture_buffer; | |
| 92 OMX_BUFFERHEADERTYPE* omx_buffer_header; | |
| 93 EGLImageKHR egl_image; | |
| 94 }; | |
| 95 typedef std::map<int32, OutputPicture> OutputPictureById; | |
| 96 | |
| 97 base::MessageLoop* message_loop_; | |
| 98 OMX_HANDLETYPE component_handle_; | |
| 99 | |
| 100 // Create the Component for OMX. Handles all OMX initialization. | |
| 101 bool CreateComponent(); | |
| 102 // Buffer allocation/free methods for input and output buffers. | |
| 103 bool AllocateInputBuffers(); | |
| 104 bool AllocateFakeOutputBuffers(); | |
| 105 bool AllocateOutputBuffers(); | |
| 106 void FreeOMXBuffers(); | |
| 107 | |
| 108 // Methods to handle OMX state transitions. See section 3.1.1.2 of the spec. | |
| 109 // Request transitioning OMX component to some other state. | |
| 110 void BeginTransitionToState(OMX_STATETYPE new_state); | |
| 111 // The callback received when the OMX component has transitioned. | |
| 112 void DispatchStateReached(OMX_STATETYPE reached); | |
| 113 // Callbacks handling transitioning to specific states during state changes. | |
| 114 // These follow a convention of OnReached<STATE>In<CurrentStateChange>(), | |
| 115 // requiring that each pair of <reached-state>/CurrentStateChange is unique | |
| 116 // (i.e. the source state is uniquely defined by the pair). | |
| 117 void OnReachedIdleInInitializing(); | |
| 118 void OnReachedExecutingInInitializing(); | |
| 119 void OnReachedPauseInResetting(); | |
| 120 void OnReachedExecutingInResetting(); | |
| 121 void OnReachedIdleInDestroying(); | |
| 122 void OnReachedLoadedInDestroying(); | |
| 123 void OnReachedEOSInFlushing(); | |
| 124 void OnReachedInvalidInErroring(); | |
| 125 void ShutdownComponent(); | |
| 126 void BusyLoopInDestroying(scoped_ptr<OmxVideoDecodeAccelerator> self); | |
| 127 | |
| 128 // Port-flushing helpers. | |
| 129 void FlushIOPorts(); | |
| 130 void InputPortFlushDone(); | |
| 131 void OutputPortFlushDone(); | |
| 132 | |
| 133 // Stop the component when any error is detected. | |
| 134 void StopOnError(media::VideoDecodeAccelerator::Error error); | |
| 135 | |
| 136 // Determine whether we can issue fill buffer to the decoder based on the | |
| 137 // current state (and outstanding state change) of the component. | |
| 138 bool CanFillBuffer(); | |
| 139 | |
| 140 // Whenever port settings change, the first thing we must do is disable the | |
| 141 // port (see Figure 3-18 of the OpenMAX IL spec linked to above). When the | |
| 142 // port is disabled, the component will call us back here. We then re-enable | |
| 143 // the port once we have textures, and that's the second method below. | |
| 144 void OnOutputPortDisabled(); | |
| 145 void OnOutputPortEnabled(); | |
| 146 | |
| 147 // Decode bitstream buffers that were queued (see queued_bitstream_buffers_). | |
| 148 void DecodeQueuedBitstreamBuffers(); | |
| 149 | |
| 150 // Lazily initialize static data after sandbox is enabled. Return false on | |
| 151 // init failure. | |
| 152 static bool PostSandboxInitialization(); | |
| 153 | |
| 154 // Weak pointer to |this|; used to safely trampoline calls from the OMX thread | |
| 155 // to the ChildThread. Since |this| is kept alive until OMX is fully shut | |
| 156 // down, only the OMX->Child thread direction needs to be guarded this way. | |
| 157 base::WeakPtr<OmxVideoDecodeAccelerator> weak_this_; | |
| 158 | |
| 159 // True once Initialize() has returned true; before this point there's never a | |
| 160 // point in calling client_->NotifyError(). | |
| 161 bool init_begun_; | |
| 162 | |
| 163 // IL-client state. | |
| 164 OMX_STATETYPE client_state_; | |
| 165 // See comment on CurrentStateChange above. | |
| 166 CurrentStateChange current_state_change_; | |
| 167 | |
| 168 // Following are input port related variables. | |
| 169 int input_buffer_count_; | |
| 170 int input_buffer_size_; | |
| 171 OMX_U32 input_port_; | |
| 172 int input_buffers_at_component_; | |
| 173 | |
| 174 // Following are output port related variables. | |
| 175 OMX_U32 output_port_; | |
| 176 int output_buffers_at_component_; | |
| 177 | |
| 178 gfx::Size last_requested_picture_buffer_dimensions_; | |
| 179 | |
| 180 // NOTE: someday there may be multiple contexts for a single decoder. But not | |
| 181 // today. | |
| 182 // TODO(fischman,vrk): handle lost contexts? | |
| 183 EGLDisplay egl_display_; | |
| 184 EGLContext egl_context_; | |
| 185 base::Callback<bool(void)> make_context_current_; | |
| 186 | |
| 187 // Free input OpenMAX buffers that can be used to take bitstream from demuxer. | |
| 188 std::queue<OMX_BUFFERHEADERTYPE*> free_input_buffers_; | |
| 189 | |
| 190 // For output buffer recycling cases. | |
| 191 OutputPictureById pictures_; | |
| 192 | |
| 193 // To kick the component from Loaded to Idle before we know the real size of | |
| 194 // the video (so can't yet ask for textures) we populate it with fake output | |
| 195 // buffers. Keep track of them here. | |
| 196 // TODO(fischman): do away with this madness. | |
| 197 std::set<OMX_BUFFERHEADERTYPE*> fake_output_buffers_; | |
| 198 | |
| 199 // Encoded bitstream buffers awaiting decode, queued while the decoder was | |
| 200 // unable to accept them. | |
| 201 typedef std::vector<media::BitstreamBuffer> BitstreamBufferList; | |
| 202 BitstreamBufferList queued_bitstream_buffers_; | |
| 203 // Available output picture buffers released during Reset() and awaiting | |
| 204 // re-use once Reset is done. Is empty most of the time and drained right | |
| 205 // before NotifyResetDone is sent. | |
| 206 std::vector<int> queued_picture_buffer_ids_; | |
| 207 | |
| 208 // To expose client callbacks from VideoDecodeAccelerator. | |
| 209 // NOTE: all calls to these objects *MUST* be executed on | |
| 210 // message_loop_. | |
| 211 base::WeakPtrFactory<Client> client_ptr_factory_; | |
| 212 base::WeakPtr<Client> client_; | |
| 213 | |
| 214 scoped_ptr<Gles2TextureToEglImageTranslator> texture_to_egl_image_translator_; | |
| 215 | |
| 216 // These members are only used during Initialization. | |
| 217 Codec codec_; | |
| 218 uint32 h264_profile_; // OMX_AVCProfile requested during Initialization. | |
| 219 bool component_name_is_nvidia_; | |
| 220 | |
| 221 // Has static initialization of pre-sandbox components completed successfully? | |
| 222 static bool pre_sandbox_init_done_; | |
| 223 | |
| 224 // Method to handle events | |
| 225 void EventHandlerCompleteTask(OMX_EVENTTYPE event, | |
| 226 OMX_U32 data1, | |
| 227 OMX_U32 data2); | |
| 228 | |
| 229 // Method to receive buffers from component's input port | |
| 230 void EmptyBufferDoneTask(OMX_BUFFERHEADERTYPE* buffer); | |
| 231 | |
| 232 // Method to receive buffers from component's output port | |
| 233 void FillBufferDoneTask(OMX_BUFFERHEADERTYPE* buffer); | |
| 234 | |
| 235 // Send a command to an OMX port. Return false on failure (after logging and | |
| 236 // setting |this| to ERRORING state). | |
| 237 bool SendCommandToPort(OMX_COMMANDTYPE cmd, int port_index); | |
| 238 | |
| 239 // Callback methods for the OMX component. | |
| 240 // When these callbacks are received, the | |
| 241 // call is delegated to the three internal methods above. | |
| 242 static OMX_ERRORTYPE EventHandler(OMX_HANDLETYPE component, | |
| 243 OMX_PTR priv_data, | |
| 244 OMX_EVENTTYPE event, | |
| 245 OMX_U32 data1, OMX_U32 data2, | |
| 246 OMX_PTR event_data); | |
| 247 static OMX_ERRORTYPE EmptyBufferCallback(OMX_HANDLETYPE component, | |
| 248 OMX_PTR priv_data, | |
| 249 OMX_BUFFERHEADERTYPE* buffer); | |
| 250 static OMX_ERRORTYPE FillBufferCallback(OMX_HANDLETYPE component, | |
| 251 OMX_PTR priv_data, | |
| 252 OMX_BUFFERHEADERTYPE* buffer); | |
| 253 | |
| 254 // When we get a texture back via ReusePictureBuffer(), we want to ensure | |
| 255 // that its contents have been read out by rendering layer, before we start | |
| 256 // overwriting it with the decoder. This class is used to wait for a sync | |
| 257 // object inserted into the GPU command stream at the time of | |
| 258 // ReusePictureBuffer. This guarantees that the object gets into the stream | |
| 259 // after the corresponding texture commands have been inserted into it. Once | |
| 260 // the sync object is signalled, we are sure that the stream reached the sync | |
| 261 // object, which ensures that all commands related to the texture we are | |
| 262 // getting back have been finished as well. | |
| 263 class PictureSyncObject; | |
| 264 | |
| 265 // Check if the client is done reading out from the texture. If yes, queue | |
| 266 // it for reuse by the decoder. Otherwise post self as a delayed task | |
| 267 // to check later. | |
| 268 void CheckPictureStatus(int32 picture_buffer_id, | |
| 269 scoped_ptr<PictureSyncObject> egl_sync_obj); | |
| 270 | |
| 271 // Queue a picture for use by the decoder, either by sending it directly to it | |
| 272 // via OMX_FillThisBuffer, or by queueing it for later if we are RESETTING. | |
| 273 void QueuePictureBuffer(int32 picture_buffer_id); | |
| 274 | |
| 275 }; | |
| 276 | |
| 277 } // namespace content | |
| 278 | |
| 279 #endif // CONTENT_COMMON_GPU_MEDIA_OMX_VIDEO_DECODE_ACCELERATOR_H_ | |
| OLD | NEW |