1 /*
2 * Copyright (C) 2018 Collabora Ltd.
3 * Author: Xavier Claessens <xavier.claessens@collabora.com>
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation
8 * version 2.1 of the License.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 *
19 */
20
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24
25 #include "gstamc-internal-ml.h"
26 #include "gstamc-surfacetexture-ml.h"
27 #include "../gstamc-codec.h"
28 #include "../gstamc-constants.h"
29
30 #include <ml_media_codec.h>
31
32 struct _GstAmcCodec
33 {
34 MLHandle handle;
35 GstAmcSurfaceTexture *surface_texture;
36 };
37
38 gboolean
gst_amc_codec_static_init(void)39 gst_amc_codec_static_init (void)
40 {
41 return TRUE;
42 }
43
44 void
gst_amc_buffer_free(GstAmcBuffer * buffer)45 gst_amc_buffer_free (GstAmcBuffer * buffer)
46 {
47 g_free (buffer);
48 }
49
50 gboolean
gst_amc_buffer_set_position_and_limit(GstAmcBuffer * buffer,GError ** err,gint position,gint limit)51 gst_amc_buffer_set_position_and_limit (GstAmcBuffer * buffer, GError ** err,
52 gint position, gint limit)
53 {
54 /* FIXME: Do we need to do something?
55 buffer->data = buffer->data + position;
56 buffer->size = limit;
57 */
58 return TRUE;
59 }
60
61 GstAmcCodec *
gst_amc_codec_new(const gchar * name,gboolean is_encoder,GError ** err)62 gst_amc_codec_new (const gchar * name, gboolean is_encoder, GError ** err)
63 {
64 GstAmcCodec *codec = NULL;
65 MLResult result;
66 MLMediaCodecType type;
67
68 g_return_val_if_fail (name != NULL, NULL);
69
70 codec = g_slice_new0 (GstAmcCodec);
71 codec->handle = ML_INVALID_HANDLE;
72 type = is_encoder ? MLMediaCodecType_Encoder : MLMediaCodecType_Decoder;
73 result =
74 MLMediaCodecCreateCodec (MLMediaCodecCreation_ByName, type, name,
75 &codec->handle);
76 if (result != MLResult_Ok) {
77 g_set_error (err, GST_LIBRARY_ERROR, GST_LIBRARY_ERROR_FAILED,
78 "Failed to create codec by name %s: %d", name, result);
79 gst_amc_codec_free (codec);
80 return NULL;
81 }
82
83 return codec;
84 }
85
86 void
gst_amc_codec_free(GstAmcCodec * codec)87 gst_amc_codec_free (GstAmcCodec * codec)
88 {
89 g_return_if_fail (codec != NULL);
90
91 if (codec->handle != ML_INVALID_HANDLE)
92 MLMediaCodecDestroy (codec->handle);
93 g_clear_object (&codec->surface_texture);
94 g_slice_free (GstAmcCodec, codec);
95 }
96
97 gboolean
gst_amc_codec_configure(GstAmcCodec * codec,GstAmcFormat * format,GstAmcSurfaceTexture * surface_texture,GError ** err)98 gst_amc_codec_configure (GstAmcCodec * codec, GstAmcFormat * format,
99 GstAmcSurfaceTexture * surface_texture, GError ** err)
100 {
101 MLResult result;
102 MLHandle surface_handle = ML_INVALID_HANDLE;
103
104 g_return_val_if_fail (codec != NULL, FALSE);
105 g_return_val_if_fail (format != NULL, FALSE);
106 g_return_val_if_fail (surface_texture == NULL
107 || GST_IS_AMC_SURFACE_TEXTURE_ML (surface_texture), FALSE);
108
109 g_set_object (&codec->surface_texture, surface_texture);
110 if (surface_texture != NULL)
111 surface_handle =
112 gst_amc_surface_texture_ml_get_handle ((GstAmcSurfaceTextureML *)
113 surface_texture);
114
115 result = MLMediaCodecConfigureWithSurface (codec->handle,
116 gst_amc_format_get_handle (format), surface_handle, 0);
117 if (result != MLResult_Ok) {
118 g_set_error (err, GST_LIBRARY_ERROR, GST_LIBRARY_ERROR_FAILED,
119 "Failed to configure codec %d", result);
120 return FALSE;
121 }
122
123 return TRUE;
124 }
125
126 GstAmcFormat *
gst_amc_codec_get_output_format(GstAmcCodec * codec,GError ** err)127 gst_amc_codec_get_output_format (GstAmcCodec * codec, GError ** err)
128 {
129 MLHandle format_handle;
130 MLResult result;
131
132 g_return_val_if_fail (codec != NULL, NULL);
133
134 result = MLMediaCodecGetOutputFormat (codec->handle, &format_handle);
135 if (result != MLResult_Ok) {
136 g_set_error (err, GST_LIBRARY_ERROR, GST_LIBRARY_ERROR_FAILED,
137 "Failed to get output format %d", result);
138 return NULL;
139 }
140
141 return gst_amc_format_new_handle (format_handle);
142 }
143
144 gboolean
gst_amc_codec_start(GstAmcCodec * codec,GError ** err)145 gst_amc_codec_start (GstAmcCodec * codec, GError ** err)
146 {
147 MLResult result;
148
149 g_return_val_if_fail (codec != NULL, FALSE);
150
151 result = MLMediaCodecStart (codec->handle);
152 if (result != MLResult_Ok) {
153 g_set_error (err, GST_LIBRARY_ERROR, GST_LIBRARY_ERROR_FAILED,
154 "Failed to start codec %d", result);
155 return FALSE;
156 }
157
158 return TRUE;
159 }
160
161 gboolean
gst_amc_codec_stop(GstAmcCodec * codec,GError ** err)162 gst_amc_codec_stop (GstAmcCodec * codec, GError ** err)
163 {
164 MLResult result;
165
166 g_return_val_if_fail (codec != NULL, FALSE);
167
168 result = MLMediaCodecStop (codec->handle);
169 if (result != MLResult_Ok) {
170 g_set_error (err, GST_LIBRARY_ERROR, GST_LIBRARY_ERROR_FAILED,
171 "Failed to stop codec %d", result);
172 return FALSE;
173 }
174
175 return TRUE;
176 }
177
178 gboolean
gst_amc_codec_flush(GstAmcCodec * codec,GError ** err)179 gst_amc_codec_flush (GstAmcCodec * codec, GError ** err)
180 {
181 MLResult result;
182
183 g_return_val_if_fail (codec != NULL, FALSE);
184
185 result = MLMediaCodecFlush (codec->handle);
186 if (result != MLResult_Ok) {
187 g_set_error (err, GST_LIBRARY_ERROR, GST_LIBRARY_ERROR_FAILED,
188 "Failed to flush codec %d", result);
189 return FALSE;
190 }
191
192 return TRUE;
193 }
194
195 gboolean
gst_amc_codec_request_key_frame(GstAmcCodec * codec,GError ** err)196 gst_amc_codec_request_key_frame (GstAmcCodec * codec, GError ** err)
197 {
198 /* If MagicLeap adds an API for requesting a keyframe, call it here */
199 g_set_error (err, GST_LIBRARY_ERROR, GST_LIBRARY_ERROR_FAILED,
200 "Keyframe requests are not available on MagicLeap");
201 return FALSE;
202 }
203
204 gboolean
gst_amc_codec_set_dynamic_bitrate(GstAmcCodec * codec,GError ** err,gint bitrate)205 gst_amc_codec_set_dynamic_bitrate (GstAmcCodec * codec, GError ** err,
206 gint bitrate)
207 {
208 g_set_error (err, GST_LIBRARY_ERROR, GST_LIBRARY_ERROR_FAILED,
209 "Dynamic bitrate control isn't available on MagicLeap");
210 return FALSE;
211 }
212
213 gboolean
gst_amc_codec_have_dynamic_bitrate()214 gst_amc_codec_have_dynamic_bitrate ()
215 {
216 /* If MagicLeap ever provides an API for scaling bitrate, change this to TRUE */
217 return FALSE;
218 }
219
220 gboolean
gst_amc_codec_release(GstAmcCodec * codec,GError ** err)221 gst_amc_codec_release (GstAmcCodec * codec, GError ** err)
222 {
223 g_return_val_if_fail (codec != NULL, FALSE);
224 return TRUE;
225 }
226
227 GstAmcBuffer *
gst_amc_codec_get_output_buffer(GstAmcCodec * codec,gint index,GError ** err)228 gst_amc_codec_get_output_buffer (GstAmcCodec * codec, gint index, GError ** err)
229 {
230 MLResult result;
231 GstAmcBuffer *ret;
232
233 g_return_val_if_fail (codec != NULL, NULL);
234 g_return_val_if_fail (index >= 0, NULL);
235
236 ret = g_new0 (GstAmcBuffer, 1);
237
238 /* When configured with a surface, getting the buffer pointer makes no sense,
239 * but on Android it's not an error, it just return NULL buffer.
240 * But MLMediaCodecGetInputBufferPointer() will return an error instead. */
241 if (codec->surface_texture != NULL) {
242 return ret;
243 }
244
245 result =
246 MLMediaCodecGetOutputBufferPointer (codec->handle, index,
247 (const uint8_t **) &ret->data, &ret->size);
248 if (result != MLResult_Ok) {
249 g_set_error (err, GST_LIBRARY_ERROR, GST_LIBRARY_ERROR_FAILED,
250 "Failed to get output buffer %d", result);
251 g_free (ret);
252 return NULL;
253 }
254
255 return ret;
256 }
257
258 GstAmcBuffer *
gst_amc_codec_get_input_buffer(GstAmcCodec * codec,gint index,GError ** err)259 gst_amc_codec_get_input_buffer (GstAmcCodec * codec, gint index, GError ** err)
260 {
261 MLResult result;
262 GstAmcBuffer *ret;
263
264 g_return_val_if_fail (codec != NULL, NULL);
265 g_return_val_if_fail (index >= 0, NULL);
266
267 ret = g_new0 (GstAmcBuffer, 1);
268
269 result =
270 MLMediaCodecGetInputBufferPointer (codec->handle, index, &ret->data,
271 &ret->size);
272 if (result != MLResult_Ok) {
273 g_set_error (err, GST_LIBRARY_ERROR, GST_LIBRARY_ERROR_FAILED,
274 "Failed to get input buffer %d", result);
275 g_free (ret);
276 return NULL;
277 }
278
279 return ret;
280 }
281
282 gint
gst_amc_codec_dequeue_input_buffer(GstAmcCodec * codec,gint64 timeoutUs,GError ** err)283 gst_amc_codec_dequeue_input_buffer (GstAmcCodec * codec, gint64 timeoutUs,
284 GError ** err)
285 {
286 MLResult result;
287 int64_t index;
288
289 g_return_val_if_fail (codec != NULL, G_MININT);
290
291 result = MLMediaCodecDequeueInputBuffer (codec->handle, timeoutUs, &index);
292 if (result != MLResult_Ok) {
293 g_set_error (err, GST_LIBRARY_ERROR, GST_LIBRARY_ERROR_FAILED,
294 "Failed to dequeue input buffer %d", result);
295 return G_MININT;
296 }
297
298 if (index == MLMediaCodec_TryAgainLater)
299 return INFO_TRY_AGAIN_LATER;
300
301 return index;
302 }
303
304 gint
gst_amc_codec_dequeue_output_buffer(GstAmcCodec * codec,GstAmcBufferInfo * info,gint64 timeoutUs,GError ** err)305 gst_amc_codec_dequeue_output_buffer (GstAmcCodec * codec,
306 GstAmcBufferInfo * info, gint64 timeoutUs, GError ** err)
307 {
308 MLMediaCodecBufferInfo info_;
309 MLResult result;
310 int64_t index;
311
312 g_return_val_if_fail (codec != NULL, G_MININT);
313
314 result =
315 MLMediaCodecDequeueOutputBuffer (codec->handle, &info_, timeoutUs,
316 &index);
317 if (result != MLResult_Ok) {
318 g_set_error (err, GST_LIBRARY_ERROR, GST_LIBRARY_ERROR_FAILED,
319 "Failed to dequeue output buffer %d", result);
320 return G_MININT;
321 }
322
323 if (index == MLMediaCodec_OutputBuffersChanged) {
324 return gst_amc_codec_dequeue_output_buffer (codec, info, timeoutUs, err);
325 } else if (index == MLMediaCodec_FormatChanged) {
326 return INFO_OUTPUT_FORMAT_CHANGED;
327 } else if (index == MLMediaCodec_TryAgainLater) {
328 return INFO_TRY_AGAIN_LATER;
329 }
330
331 info->flags = info_.flags;
332
333 info->offset = info_.offset;
334 info->presentation_time_us = info_.presentation_time_us;
335 info->size = info_.size;
336
337 return index;
338 }
339
340 gboolean
gst_amc_codec_queue_input_buffer(GstAmcCodec * codec,gint index,const GstAmcBufferInfo * info,GError ** err)341 gst_amc_codec_queue_input_buffer (GstAmcCodec * codec, gint index,
342 const GstAmcBufferInfo * info, GError ** err)
343 {
344 MLResult result;
345
346 g_return_val_if_fail (codec != NULL, FALSE);
347 g_return_val_if_fail (info != NULL, FALSE);
348
349 result = MLMediaCodecQueueInputBuffer (codec->handle, index, info->offset,
350 info->size, info->presentation_time_us, info->flags);
351 if (result != MLResult_Ok) {
352 g_set_error (err, GST_LIBRARY_ERROR, GST_LIBRARY_ERROR_FAILED,
353 "Failed to queue input buffer %d", result);
354 return FALSE;
355 }
356
357 return TRUE;
358 }
359
360 gboolean
gst_amc_codec_release_output_buffer(GstAmcCodec * codec,gint index,gboolean render,GError ** err)361 gst_amc_codec_release_output_buffer (GstAmcCodec * codec, gint index,
362 gboolean render, GError ** err)
363 {
364 MLResult result;
365
366 g_return_val_if_fail (codec != NULL, FALSE);
367
368 result = MLMediaCodecReleaseOutputBuffer (codec->handle, index, render);
369 if (result != MLResult_Ok) {
370 g_set_error (err, GST_LIBRARY_ERROR, GST_LIBRARY_ERROR_FAILED,
371 "Failed to release output buffer %d", result);
372 return FALSE;
373 }
374
375 return TRUE;
376 }
377
378 GstAmcSurfaceTexture *
gst_amc_codec_new_surface_texture(GError ** err)379 gst_amc_codec_new_surface_texture (GError ** err)
380 {
381 return (GstAmcSurfaceTexture *) gst_amc_surface_texture_ml_new (err);
382 }
383