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 |