• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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