1 /* GStreamer
2 * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
3 * Copyright (C) <2012> Collabora Ltd.
4 * Author: Sebastian Dröge <sebastian.droege@collabora.co.uk>
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Library General Public License for more details.
15 *
16 * You should have received a copy of the GNU Library General Public
17 * License along with this library; if not, write to the
18 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
19 * Boston, MA 02110-1301, USA.
20 */
21
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25
26 #include <assert.h>
27 #include <string.h>
28 /* for stats file handling */
29 #include <stdio.h>
30 #include <glib/gstdio.h>
31 #include <errno.h>
32
33 #include <libavcodec/avcodec.h>
34 #include <libavutil/opt.h>
35
36 #include <gst/gst.h>
37
38 #include "gstav.h"
39 #include "gstavcfg.h"
40 #include "gstavcodecmap.h"
41 #include "gstavutils.h"
42 #include "gstavaudenc.h"
43
44 enum
45 {
46 PROP_0,
47 PROP_CFG_BASE,
48 };
49
50 static void gst_ffmpegaudenc_class_init (GstFFMpegAudEncClass * klass);
51 static void gst_ffmpegaudenc_base_init (GstFFMpegAudEncClass * klass);
52 static void gst_ffmpegaudenc_init (GstFFMpegAudEnc * ffmpegaudenc);
53 static void gst_ffmpegaudenc_finalize (GObject * object);
54
55 static gboolean gst_ffmpegaudenc_set_format (GstAudioEncoder * encoder,
56 GstAudioInfo * info);
57 static GstFlowReturn gst_ffmpegaudenc_handle_frame (GstAudioEncoder * encoder,
58 GstBuffer * inbuf);
59 static gboolean gst_ffmpegaudenc_start (GstAudioEncoder * encoder);
60 static gboolean gst_ffmpegaudenc_stop (GstAudioEncoder * encoder);
61 static void gst_ffmpegaudenc_flush (GstAudioEncoder * encoder);
62
63 static void gst_ffmpegaudenc_set_property (GObject * object,
64 guint prop_id, const GValue * value, GParamSpec * pspec);
65 static void gst_ffmpegaudenc_get_property (GObject * object,
66 guint prop_id, GValue * value, GParamSpec * pspec);
67
68 #define GST_FFENC_PARAMS_QDATA g_quark_from_static_string("avenc-params")
69
70 static GstElementClass *parent_class = NULL;
71
72 static void
gst_ffmpegaudenc_base_init(GstFFMpegAudEncClass * klass)73 gst_ffmpegaudenc_base_init (GstFFMpegAudEncClass * klass)
74 {
75 GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
76 AVCodec *in_plugin;
77 GstPadTemplate *srctempl = NULL, *sinktempl = NULL;
78 GstCaps *srccaps = NULL, *sinkcaps = NULL;
79 gchar *longname, *description;
80
81 in_plugin =
82 (AVCodec *) g_type_get_qdata (G_OBJECT_CLASS_TYPE (klass),
83 GST_FFENC_PARAMS_QDATA);
84 g_assert (in_plugin != NULL);
85
86 /* construct the element details struct */
87 longname = g_strdup_printf ("libav %s encoder", in_plugin->long_name);
88 description = g_strdup_printf ("libav %s encoder", in_plugin->name);
89 gst_element_class_set_metadata (element_class, longname,
90 "Codec/Encoder/Audio", description,
91 "Wim Taymans <wim.taymans@gmail.com>, "
92 "Ronald Bultje <rbultje@ronald.bitfreak.net>");
93 g_free (longname);
94 g_free (description);
95
96 if (!(srccaps = gst_ffmpeg_codecid_to_caps (in_plugin->id, NULL, TRUE))) {
97 GST_DEBUG ("Couldn't get source caps for encoder '%s'", in_plugin->name);
98 srccaps = gst_caps_new_empty_simple ("unknown/unknown");
99 }
100
101 sinkcaps = gst_ffmpeg_codectype_to_audio_caps (NULL,
102 in_plugin->id, TRUE, in_plugin);
103 if (!sinkcaps) {
104 GST_DEBUG ("Couldn't get sink caps for encoder '%s'", in_plugin->name);
105 sinkcaps = gst_caps_new_empty_simple ("unknown/unknown");
106 }
107
108 /* pad templates */
109 sinktempl = gst_pad_template_new ("sink", GST_PAD_SINK,
110 GST_PAD_ALWAYS, sinkcaps);
111 srctempl = gst_pad_template_new ("src", GST_PAD_SRC, GST_PAD_ALWAYS, srccaps);
112
113 gst_element_class_add_pad_template (element_class, srctempl);
114 gst_element_class_add_pad_template (element_class, sinktempl);
115
116 gst_caps_unref (sinkcaps);
117 gst_caps_unref (srccaps);
118
119 klass->in_plugin = in_plugin;
120 klass->srctempl = srctempl;
121 klass->sinktempl = sinktempl;
122
123 return;
124 }
125
126 static void
gst_ffmpegaudenc_class_init(GstFFMpegAudEncClass * klass)127 gst_ffmpegaudenc_class_init (GstFFMpegAudEncClass * klass)
128 {
129 GObjectClass *gobject_class;
130 GstAudioEncoderClass *gstaudioencoder_class;
131
132 gobject_class = (GObjectClass *) klass;
133 gstaudioencoder_class = (GstAudioEncoderClass *) klass;
134
135 parent_class = g_type_class_peek_parent (klass);
136
137 gobject_class->set_property = gst_ffmpegaudenc_set_property;
138 gobject_class->get_property = gst_ffmpegaudenc_get_property;
139
140 gst_ffmpeg_cfg_install_properties (gobject_class, klass->in_plugin,
141 PROP_CFG_BASE, AV_OPT_FLAG_ENCODING_PARAM | AV_OPT_FLAG_AUDIO_PARAM);
142
143 gobject_class->finalize = gst_ffmpegaudenc_finalize;
144
145 gstaudioencoder_class->start = GST_DEBUG_FUNCPTR (gst_ffmpegaudenc_start);
146 gstaudioencoder_class->stop = GST_DEBUG_FUNCPTR (gst_ffmpegaudenc_stop);
147 gstaudioencoder_class->flush = GST_DEBUG_FUNCPTR (gst_ffmpegaudenc_flush);
148 gstaudioencoder_class->set_format =
149 GST_DEBUG_FUNCPTR (gst_ffmpegaudenc_set_format);
150 gstaudioencoder_class->handle_frame =
151 GST_DEBUG_FUNCPTR (gst_ffmpegaudenc_handle_frame);
152 }
153
154 static void
gst_ffmpegaudenc_init(GstFFMpegAudEnc * ffmpegaudenc)155 gst_ffmpegaudenc_init (GstFFMpegAudEnc * ffmpegaudenc)
156 {
157 GstFFMpegAudEncClass *klass =
158 (GstFFMpegAudEncClass *) G_OBJECT_GET_CLASS (ffmpegaudenc);
159
160 GST_PAD_SET_ACCEPT_TEMPLATE (GST_AUDIO_ENCODER_SINK_PAD (ffmpegaudenc));
161
162 /* ffmpeg objects */
163 ffmpegaudenc->context = avcodec_alloc_context3 (klass->in_plugin);
164 ffmpegaudenc->refcontext = avcodec_alloc_context3 (klass->in_plugin);
165 ffmpegaudenc->opened = FALSE;
166 ffmpegaudenc->frame = av_frame_alloc ();
167
168 gst_audio_encoder_set_drainable (GST_AUDIO_ENCODER (ffmpegaudenc), TRUE);
169 }
170
171 static void
gst_ffmpegaudenc_finalize(GObject * object)172 gst_ffmpegaudenc_finalize (GObject * object)
173 {
174 GstFFMpegAudEnc *ffmpegaudenc = (GstFFMpegAudEnc *) object;
175
176 /* clean up remaining allocated data */
177 av_frame_free (&ffmpegaudenc->frame);
178 avcodec_free_context (&ffmpegaudenc->context);
179 avcodec_free_context (&ffmpegaudenc->refcontext);
180
181 G_OBJECT_CLASS (parent_class)->finalize (object);
182 }
183
184 static gboolean
gst_ffmpegaudenc_start(GstAudioEncoder * encoder)185 gst_ffmpegaudenc_start (GstAudioEncoder * encoder)
186 {
187 GstFFMpegAudEnc *ffmpegaudenc = (GstFFMpegAudEnc *) encoder;
188 GstFFMpegAudEncClass *oclass =
189 (GstFFMpegAudEncClass *) G_OBJECT_GET_CLASS (ffmpegaudenc);
190
191 ffmpegaudenc->opened = FALSE;
192 ffmpegaudenc->need_reopen = FALSE;
193
194 avcodec_free_context (&ffmpegaudenc->context);
195 ffmpegaudenc->context = avcodec_alloc_context3 (oclass->in_plugin);
196 if (ffmpegaudenc->context == NULL) {
197 GST_DEBUG_OBJECT (ffmpegaudenc, "Failed to set context defaults");
198 return FALSE;
199 }
200
201 return TRUE;
202 }
203
204 static gboolean
gst_ffmpegaudenc_stop(GstAudioEncoder * encoder)205 gst_ffmpegaudenc_stop (GstAudioEncoder * encoder)
206 {
207 GstFFMpegAudEnc *ffmpegaudenc = (GstFFMpegAudEnc *) encoder;
208
209 /* close old session */
210 gst_ffmpeg_avcodec_close (ffmpegaudenc->context);
211 ffmpegaudenc->opened = FALSE;
212 ffmpegaudenc->need_reopen = FALSE;
213
214 return TRUE;
215 }
216
217 static void
gst_ffmpegaudenc_flush(GstAudioEncoder * encoder)218 gst_ffmpegaudenc_flush (GstAudioEncoder * encoder)
219 {
220 GstFFMpegAudEnc *ffmpegaudenc = (GstFFMpegAudEnc *) encoder;
221
222 if (ffmpegaudenc->opened) {
223 avcodec_flush_buffers (ffmpegaudenc->context);
224 }
225 }
226
227 static gboolean
gst_ffmpegaudenc_set_format(GstAudioEncoder * encoder,GstAudioInfo * info)228 gst_ffmpegaudenc_set_format (GstAudioEncoder * encoder, GstAudioInfo * info)
229 {
230 GstFFMpegAudEnc *ffmpegaudenc = (GstFFMpegAudEnc *) encoder;
231 GstCaps *other_caps;
232 GstCaps *allowed_caps;
233 GstCaps *icaps;
234 gsize frame_size;
235 GstFFMpegAudEncClass *oclass =
236 (GstFFMpegAudEncClass *) G_OBJECT_GET_CLASS (ffmpegaudenc);
237
238 ffmpegaudenc->need_reopen = FALSE;
239
240 /* close old session */
241 if (ffmpegaudenc->opened) {
242 avcodec_free_context (&ffmpegaudenc->context);
243 ffmpegaudenc->opened = FALSE;
244 ffmpegaudenc->context = avcodec_alloc_context3 (oclass->in_plugin);
245 if (ffmpegaudenc->context == NULL) {
246 GST_DEBUG_OBJECT (ffmpegaudenc, "Failed to set context defaults");
247 return FALSE;
248 }
249 }
250
251 gst_ffmpeg_cfg_fill_context (G_OBJECT (ffmpegaudenc), ffmpegaudenc->context);
252
253 /* fetch pix_fmt and so on */
254 gst_ffmpeg_audioinfo_to_context (info, ffmpegaudenc->context);
255 if (!ffmpegaudenc->context->time_base.den) {
256 ffmpegaudenc->context->time_base.den = GST_AUDIO_INFO_RATE (info);
257 ffmpegaudenc->context->time_base.num = 1;
258 ffmpegaudenc->context->ticks_per_frame = 1;
259 }
260
261 if (ffmpegaudenc->context->channel_layout) {
262 gst_ffmpeg_channel_layout_to_gst (ffmpegaudenc->context->channel_layout,
263 ffmpegaudenc->context->channels, ffmpegaudenc->ffmpeg_layout);
264 ffmpegaudenc->needs_reorder =
265 (memcmp (ffmpegaudenc->ffmpeg_layout, info->position,
266 sizeof (GstAudioChannelPosition) *
267 ffmpegaudenc->context->channels) != 0);
268 }
269
270 /* some codecs support more than one format, first auto-choose one */
271 GST_DEBUG_OBJECT (ffmpegaudenc, "picking an output format ...");
272 allowed_caps = gst_pad_get_allowed_caps (GST_AUDIO_ENCODER_SRC_PAD (encoder));
273 if (!allowed_caps) {
274 GST_DEBUG_OBJECT (ffmpegaudenc, "... but no peer, using template caps");
275 /* we need to copy because get_allowed_caps returns a ref, and
276 * get_pad_template_caps doesn't */
277 allowed_caps =
278 gst_pad_get_pad_template_caps (GST_AUDIO_ENCODER_SRC_PAD (encoder));
279 }
280 GST_DEBUG_OBJECT (ffmpegaudenc, "chose caps %" GST_PTR_FORMAT, allowed_caps);
281 gst_ffmpeg_caps_with_codecid (oclass->in_plugin->id,
282 oclass->in_plugin->type, allowed_caps, ffmpegaudenc->context);
283
284 /* open codec */
285 if (gst_ffmpeg_avcodec_open (ffmpegaudenc->context, oclass->in_plugin) < 0) {
286 gst_caps_unref (allowed_caps);
287 avcodec_free_context (&ffmpegaudenc->context);
288 GST_DEBUG_OBJECT (ffmpegaudenc, "avenc_%s: Failed to open FFMPEG codec",
289 oclass->in_plugin->name);
290 ffmpegaudenc->context = avcodec_alloc_context3 (oclass->in_plugin);
291 if (ffmpegaudenc->context == NULL)
292 GST_DEBUG_OBJECT (ffmpegaudenc, "Failed to set context defaults");
293
294 if ((oclass->in_plugin->capabilities & AV_CODEC_CAP_EXPERIMENTAL) &&
295 ffmpegaudenc->context->strict_std_compliance !=
296 FF_COMPLIANCE_EXPERIMENTAL) {
297 GST_ELEMENT_ERROR (ffmpegaudenc, LIBRARY, SETTINGS,
298 ("Codec is experimental, but settings don't allow encoders to "
299 "produce output of experimental quality"),
300 ("This codec may not create output that is conformant to the specs "
301 "or of good quality. If you must use it anyway, set the "
302 "compliance property to experimental"));
303 }
304 return FALSE;
305 }
306
307 /* try to set this caps on the other side */
308 other_caps = gst_ffmpeg_codecid_to_caps (oclass->in_plugin->id,
309 ffmpegaudenc->context, TRUE);
310
311 if (!other_caps) {
312 gst_caps_unref (allowed_caps);
313 avcodec_free_context (&ffmpegaudenc->context);
314 GST_DEBUG ("Unsupported codec - no caps found");
315 ffmpegaudenc->context = avcodec_alloc_context3 (oclass->in_plugin);
316 if (ffmpegaudenc->context == NULL)
317 GST_DEBUG_OBJECT (ffmpegaudenc, "Failed to set context defaults");
318 return FALSE;
319 }
320
321 icaps = gst_caps_intersect (allowed_caps, other_caps);
322 gst_caps_unref (allowed_caps);
323 gst_caps_unref (other_caps);
324 if (gst_caps_is_empty (icaps)) {
325 gst_caps_unref (icaps);
326 return FALSE;
327 }
328 icaps = gst_caps_fixate (icaps);
329
330 if (!gst_audio_encoder_set_output_format (GST_AUDIO_ENCODER (ffmpegaudenc),
331 icaps)) {
332 avcodec_free_context (&ffmpegaudenc->context);
333 gst_caps_unref (icaps);
334 ffmpegaudenc->context = avcodec_alloc_context3 (oclass->in_plugin);
335 if (ffmpegaudenc->context == NULL)
336 GST_DEBUG_OBJECT (ffmpegaudenc, "Failed to set context defaults");
337 return FALSE;
338 }
339 gst_caps_unref (icaps);
340
341 frame_size = ffmpegaudenc->context->frame_size;
342 if (frame_size > 1) {
343 gst_audio_encoder_set_frame_samples_min (GST_AUDIO_ENCODER (ffmpegaudenc),
344 frame_size);
345 gst_audio_encoder_set_frame_samples_max (GST_AUDIO_ENCODER (ffmpegaudenc),
346 frame_size);
347 gst_audio_encoder_set_frame_max (GST_AUDIO_ENCODER (ffmpegaudenc), 1);
348 } else {
349 gst_audio_encoder_set_frame_samples_min (GST_AUDIO_ENCODER (ffmpegaudenc),
350 0);
351 gst_audio_encoder_set_frame_samples_max (GST_AUDIO_ENCODER (ffmpegaudenc),
352 0);
353 gst_audio_encoder_set_frame_max (GST_AUDIO_ENCODER (ffmpegaudenc), 0);
354 }
355
356 /* Store some tags */
357 {
358 GstTagList *tags = gst_tag_list_new_empty ();
359 const gchar *codec;
360
361 gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_NOMINAL_BITRATE,
362 (guint) ffmpegaudenc->context->bit_rate, NULL);
363
364 if ((codec =
365 gst_ffmpeg_get_codecid_longname (ffmpegaudenc->context->codec_id)))
366 gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_AUDIO_CODEC, codec,
367 NULL);
368
369 gst_audio_encoder_merge_tags (encoder, tags, GST_TAG_MERGE_REPLACE);
370 gst_tag_list_unref (tags);
371 }
372
373 /* success! */
374 ffmpegaudenc->opened = TRUE;
375 ffmpegaudenc->need_reopen = FALSE;
376
377 return TRUE;
378 }
379
380 static void
gst_ffmpegaudenc_free_avpacket(gpointer pkt)381 gst_ffmpegaudenc_free_avpacket (gpointer pkt)
382 {
383 av_packet_unref ((AVPacket *) pkt);
384 g_slice_free (AVPacket, pkt);
385 }
386
387 typedef struct
388 {
389 GstBuffer *buffer;
390 GstMapInfo map;
391
392 guint8 **ext_data_array, *ext_data;
393 } BufferInfo;
394
395 static void
buffer_info_free(void * opaque,guint8 * data)396 buffer_info_free (void *opaque, guint8 * data)
397 {
398 BufferInfo *info = opaque;
399
400 if (info->buffer) {
401 gst_buffer_unmap (info->buffer, &info->map);
402 gst_buffer_unref (info->buffer);
403 } else {
404 av_freep (&info->ext_data);
405 av_freep (&info->ext_data_array);
406 }
407 g_slice_free (BufferInfo, info);
408 }
409
410 static GstFlowReturn
gst_ffmpegaudenc_send_frame(GstFFMpegAudEnc * ffmpegaudenc,GstBuffer * buffer)411 gst_ffmpegaudenc_send_frame (GstFFMpegAudEnc * ffmpegaudenc, GstBuffer * buffer)
412 {
413 GstAudioEncoder *enc;
414 AVCodecContext *ctx;
415 GstFlowReturn ret;
416 gint res;
417 GstAudioInfo *info;
418 AVFrame *frame = ffmpegaudenc->frame;
419 gboolean planar;
420 gint nsamples = -1;
421
422 enc = GST_AUDIO_ENCODER (ffmpegaudenc);
423
424 ctx = ffmpegaudenc->context;
425
426 if (buffer != NULL) {
427 BufferInfo *buffer_info = g_slice_new0 (BufferInfo);
428 guint8 *audio_in;
429 guint in_size;
430
431 buffer_info->buffer = buffer;
432 gst_buffer_map (buffer, &buffer_info->map, GST_MAP_READ);
433 audio_in = buffer_info->map.data;
434 in_size = buffer_info->map.size;
435
436 GST_LOG_OBJECT (ffmpegaudenc, "encoding buffer %p size:%u", audio_in,
437 in_size);
438
439 info = gst_audio_encoder_get_audio_info (enc);
440 planar = av_sample_fmt_is_planar (ffmpegaudenc->context->sample_fmt);
441 frame->format = ffmpegaudenc->context->sample_fmt;
442 frame->sample_rate = ffmpegaudenc->context->sample_rate;
443 frame->channels = ffmpegaudenc->context->channels;
444 frame->channel_layout = ffmpegaudenc->context->channel_layout;
445
446 if (planar && info->channels > 1) {
447 gint channels;
448 gint i, j;
449
450 nsamples = frame->nb_samples = in_size / info->bpf;
451 channels = info->channels;
452
453 frame->buf[0] =
454 av_buffer_create (NULL, 0, buffer_info_free, buffer_info, 0);
455
456 if (info->channels > AV_NUM_DATA_POINTERS) {
457 buffer_info->ext_data_array = frame->extended_data =
458 av_malloc_array (info->channels, sizeof (uint8_t *));
459 } else {
460 frame->extended_data = frame->data;
461 }
462
463 buffer_info->ext_data = frame->extended_data[0] = av_malloc (in_size);
464 frame->linesize[0] = in_size / channels;
465 for (i = 1; i < channels; i++)
466 frame->extended_data[i] =
467 frame->extended_data[i - 1] + frame->linesize[0];
468
469 switch (info->finfo->width) {
470 case 8:{
471 const guint8 *idata = (const guint8 *) audio_in;
472
473 for (i = 0; i < nsamples; i++) {
474 for (j = 0; j < channels; j++) {
475 ((guint8 *) frame->extended_data[j])[i] = idata[j];
476 }
477 idata += channels;
478 }
479 break;
480 }
481 case 16:{
482 const guint16 *idata = (const guint16 *) audio_in;
483
484 for (i = 0; i < nsamples; i++) {
485 for (j = 0; j < channels; j++) {
486 ((guint16 *) frame->extended_data[j])[i] = idata[j];
487 }
488 idata += channels;
489 }
490 break;
491 }
492 case 32:{
493 const guint32 *idata = (const guint32 *) audio_in;
494
495 for (i = 0; i < nsamples; i++) {
496 for (j = 0; j < channels; j++) {
497 ((guint32 *) frame->extended_data[j])[i] = idata[j];
498 }
499 idata += channels;
500 }
501
502 break;
503 }
504 case 64:{
505 const guint64 *idata = (const guint64 *) audio_in;
506
507 for (i = 0; i < nsamples; i++) {
508 for (j = 0; j < channels; j++) {
509 ((guint64 *) frame->extended_data[j])[i] = idata[j];
510 }
511 idata += channels;
512 }
513
514 break;
515 }
516 default:
517 g_assert_not_reached ();
518 break;
519 }
520
521 gst_buffer_unmap (buffer, &buffer_info->map);
522 gst_buffer_unref (buffer);
523 buffer_info->buffer = NULL;
524 } else {
525 frame->data[0] = audio_in;
526 frame->extended_data = frame->data;
527 frame->linesize[0] = in_size;
528 frame->nb_samples = nsamples = in_size / info->bpf;
529 frame->buf[0] =
530 av_buffer_create (NULL, 0, buffer_info_free, buffer_info, 0);
531 }
532
533 /* we have a frame to feed the encoder */
534 res = avcodec_send_frame (ctx, frame);
535
536 av_frame_unref (frame);
537 } else {
538 GstFFMpegAudEncClass *oclass =
539 (GstFFMpegAudEncClass *) G_OBJECT_GET_CLASS (ffmpegaudenc);
540
541 GST_LOG_OBJECT (ffmpegaudenc, "draining");
542 /* flushing the encoder */
543 res = avcodec_send_frame (ctx, NULL);
544
545 /* If AV_CODEC_CAP_ENCODER_FLUSH wasn't set, we need to re-open
546 * encoder */
547 if (!(oclass->in_plugin->capabilities & AV_CODEC_CAP_ENCODER_FLUSH)) {
548 GST_DEBUG_OBJECT (ffmpegaudenc, "Encoder needs reopen later");
549
550 /* we will reopen later handle_frame() */
551 ffmpegaudenc->need_reopen = TRUE;
552 }
553 }
554
555 if (res == 0) {
556 ret = GST_FLOW_OK;
557 } else if (res == AVERROR_EOF) {
558 ret = GST_FLOW_EOS;
559 } else { /* Any other return value is an error in our context */
560 ret = GST_FLOW_OK;
561 GST_WARNING_OBJECT (ffmpegaudenc, "Failed to encode buffer");
562 }
563
564 return ret;
565 }
566
567 static GstFlowReturn
gst_ffmpegaudenc_receive_packet(GstFFMpegAudEnc * ffmpegaudenc,gboolean * got_packet)568 gst_ffmpegaudenc_receive_packet (GstFFMpegAudEnc * ffmpegaudenc,
569 gboolean * got_packet)
570 {
571 GstAudioEncoder *enc;
572 AVCodecContext *ctx;
573 gint res;
574 GstFlowReturn ret;
575 AVPacket *pkt;
576
577 enc = GST_AUDIO_ENCODER (ffmpegaudenc);
578
579 ctx = ffmpegaudenc->context;
580
581 pkt = g_slice_new0 (AVPacket);
582
583 res = avcodec_receive_packet (ctx, pkt);
584
585 if (res == 0) {
586 GstBuffer *outbuf;
587
588 GST_LOG_OBJECT (ffmpegaudenc, "pushing size %d", pkt->size);
589
590 outbuf =
591 gst_buffer_new_wrapped_full (GST_MEMORY_FLAG_READONLY, pkt->data,
592 pkt->size, 0, pkt->size, pkt, gst_ffmpegaudenc_free_avpacket);
593
594 ret =
595 gst_audio_encoder_finish_frame (enc, outbuf,
596 pkt->duration > 0 ? pkt->duration : -1);
597 *got_packet = TRUE;
598 } else {
599 GST_LOG_OBJECT (ffmpegaudenc, "no output produced");
600 g_slice_free (AVPacket, pkt);
601 ret = GST_FLOW_OK;
602 *got_packet = FALSE;
603 }
604
605 return ret;
606 }
607
608 static GstFlowReturn
gst_ffmpegaudenc_drain(GstFFMpegAudEnc * ffmpegaudenc)609 gst_ffmpegaudenc_drain (GstFFMpegAudEnc * ffmpegaudenc)
610 {
611 GstFlowReturn ret = GST_FLOW_OK;
612 gboolean got_packet;
613
614 ret = gst_ffmpegaudenc_send_frame (ffmpegaudenc, NULL);
615
616 if (ret == GST_FLOW_OK) {
617 do {
618 ret = gst_ffmpegaudenc_receive_packet (ffmpegaudenc, &got_packet);
619 if (ret != GST_FLOW_OK)
620 break;
621 } while (got_packet);
622 }
623
624 /* NOTE: this may or may not work depending on capability */
625 avcodec_flush_buffers (ffmpegaudenc->context);
626
627 /* FFMpeg will return AVERROR_EOF if it's internal was fully drained
628 * then we are translating it to GST_FLOW_EOS. However, because this behavior
629 * is fully internal stuff of this implementation and gstaudioencoder
630 * baseclass doesn't convert this GST_FLOW_EOS to GST_FLOW_OK,
631 * convert this flow returned here */
632 if (ret == GST_FLOW_EOS)
633 ret = GST_FLOW_OK;
634
635 return ret;
636 }
637
638 static GstFlowReturn
gst_ffmpegaudenc_handle_frame(GstAudioEncoder * encoder,GstBuffer * inbuf)639 gst_ffmpegaudenc_handle_frame (GstAudioEncoder * encoder, GstBuffer * inbuf)
640 {
641 GstFFMpegAudEnc *ffmpegaudenc;
642 GstFlowReturn ret;
643 gboolean got_packet;
644
645 ffmpegaudenc = (GstFFMpegAudEnc *) encoder;
646
647 if (G_UNLIKELY (!ffmpegaudenc->opened))
648 goto not_negotiated;
649
650 if (!inbuf)
651 return gst_ffmpegaudenc_drain (ffmpegaudenc);
652
653 /* endoder was drained or flushed, and ffmpeg encoder doesn't support
654 * flushing. We need to re-open encoder then */
655 if (ffmpegaudenc->need_reopen) {
656 GST_DEBUG_OBJECT (ffmpegaudenc, "Open encoder again");
657
658 if (!gst_ffmpegaudenc_set_format (encoder,
659 gst_audio_encoder_get_audio_info (encoder))) {
660 GST_ERROR_OBJECT (ffmpegaudenc, "Couldn't re-open encoder");
661 return GST_FLOW_NOT_NEGOTIATED;
662 }
663 }
664
665 inbuf = gst_buffer_ref (inbuf);
666
667 GST_DEBUG_OBJECT (ffmpegaudenc,
668 "Received time %" GST_TIME_FORMAT ", duration %" GST_TIME_FORMAT
669 ", size %" G_GSIZE_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (inbuf)),
670 GST_TIME_ARGS (GST_BUFFER_DURATION (inbuf)), gst_buffer_get_size (inbuf));
671
672 /* Reorder channels to the GStreamer channel order */
673 if (ffmpegaudenc->needs_reorder) {
674 GstAudioInfo *info = gst_audio_encoder_get_audio_info (encoder);
675
676 inbuf = gst_buffer_make_writable (inbuf);
677 gst_audio_buffer_reorder_channels (inbuf, info->finfo->format,
678 info->channels, info->position, ffmpegaudenc->ffmpeg_layout);
679 }
680
681 ret = gst_ffmpegaudenc_send_frame (ffmpegaudenc, inbuf);
682
683 if (ret != GST_FLOW_OK)
684 goto send_frame_failed;
685
686 do {
687 ret = gst_ffmpegaudenc_receive_packet (ffmpegaudenc, &got_packet);
688 } while (got_packet);
689
690 return GST_FLOW_OK;
691
692 /* ERRORS */
693 not_negotiated:
694 {
695 GST_ELEMENT_ERROR (ffmpegaudenc, CORE, NEGOTIATION, (NULL),
696 ("not configured to input format before data start"));
697 gst_buffer_unref (inbuf);
698 return GST_FLOW_NOT_NEGOTIATED;
699 }
700 send_frame_failed:
701 {
702 GST_DEBUG_OBJECT (ffmpegaudenc, "Failed to send frame %d (%s)", ret,
703 gst_flow_get_name (ret));
704 return ret;
705 }
706 }
707
708 static void
gst_ffmpegaudenc_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)709 gst_ffmpegaudenc_set_property (GObject * object,
710 guint prop_id, const GValue * value, GParamSpec * pspec)
711 {
712 GstFFMpegAudEnc *ffmpegaudenc;
713
714 ffmpegaudenc = (GstFFMpegAudEnc *) (object);
715
716 if (ffmpegaudenc->opened) {
717 GST_WARNING_OBJECT (ffmpegaudenc,
718 "Can't change properties once encoder is setup !");
719 return;
720 }
721
722 switch (prop_id) {
723 default:
724 if (!gst_ffmpeg_cfg_set_property (ffmpegaudenc->refcontext, value, pspec))
725 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
726 break;
727 }
728 }
729
730 static void
gst_ffmpegaudenc_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)731 gst_ffmpegaudenc_get_property (GObject * object,
732 guint prop_id, GValue * value, GParamSpec * pspec)
733 {
734 GstFFMpegAudEnc *ffmpegaudenc;
735
736 ffmpegaudenc = (GstFFMpegAudEnc *) (object);
737
738 switch (prop_id) {
739 default:
740 if (!gst_ffmpeg_cfg_get_property (ffmpegaudenc->refcontext, value, pspec))
741 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
742 break;
743 }
744 }
745
746 gboolean
gst_ffmpegaudenc_register(GstPlugin * plugin)747 gst_ffmpegaudenc_register (GstPlugin * plugin)
748 {
749 GTypeInfo typeinfo = {
750 sizeof (GstFFMpegAudEncClass),
751 (GBaseInitFunc) gst_ffmpegaudenc_base_init,
752 NULL,
753 (GClassInitFunc) gst_ffmpegaudenc_class_init,
754 NULL,
755 NULL,
756 sizeof (GstFFMpegAudEnc),
757 0,
758 (GInstanceInitFunc) gst_ffmpegaudenc_init,
759 };
760 GType type;
761 AVCodec *in_plugin;
762 void *i = 0;
763
764
765 GST_LOG ("Registering encoders");
766
767 while ((in_plugin = (AVCodec *) av_codec_iterate (&i))) {
768 gchar *type_name;
769 guint rank;
770
771 /* Skip non-AV codecs */
772 if (in_plugin->type != AVMEDIA_TYPE_AUDIO)
773 continue;
774
775 /* no quasi codecs, please */
776 if (in_plugin->id == AV_CODEC_ID_PCM_S16LE_PLANAR ||
777 (in_plugin->id >= AV_CODEC_ID_PCM_S16LE &&
778 in_plugin->id <= AV_CODEC_ID_PCM_BLURAY) ||
779 (in_plugin->id >= AV_CODEC_ID_PCM_S8_PLANAR &&
780 in_plugin->id <= AV_CODEC_ID_PCM_F24LE)) {
781 continue;
782 }
783
784 /* No encoders depending on external libraries (we don't build them, but
785 * people who build against an external ffmpeg might have them.
786 * We have native gstreamer plugins for all of those libraries anyway. */
787 if (!strncmp (in_plugin->name, "lib", 3)) {
788 GST_DEBUG
789 ("Not using external library encoder %s. Use the gstreamer-native ones instead.",
790 in_plugin->name);
791 continue;
792 }
793
794 /* only encoders */
795 if (!av_codec_is_encoder (in_plugin)) {
796 continue;
797 }
798
799 /* FIXME : We should have a method to know cheaply whether we have a mapping
800 * for the given plugin or not */
801
802 GST_DEBUG ("Trying plugin %s [%s]", in_plugin->name, in_plugin->long_name);
803
804 /* no codecs for which we're GUARANTEED to have better alternatives */
805 if (!strcmp (in_plugin->name, "vorbis")
806 || !strcmp (in_plugin->name, "flac")) {
807 GST_LOG ("Ignoring encoder %s", in_plugin->name);
808 continue;
809 }
810
811 /* construct the type */
812 type_name = g_strdup_printf ("avenc_%s", in_plugin->name);
813
814 type = g_type_from_name (type_name);
815
816 if (!type) {
817
818 /* create the glib type now */
819 type =
820 g_type_register_static (GST_TYPE_AUDIO_ENCODER, type_name, &typeinfo,
821 0);
822 /**
823 * ohos.opt.compat.0031
824 * Fix Flush at eos and flush opearte.
825 * Enable flush audenc cap to flush.
826 */
827 #ifdef OHOS_OPT_COMPAT
828 in_plugin->capabilities |= AV_CODEC_CAP_ENCODER_FLUSH;
829 #endif
830 g_type_set_qdata (type, GST_FFENC_PARAMS_QDATA, (gpointer) in_plugin);
831
832 {
833 static const GInterfaceInfo preset_info = {
834 NULL,
835 NULL,
836 NULL
837 };
838 g_type_add_interface_static (type, GST_TYPE_PRESET, &preset_info);
839 }
840 }
841
842 switch (in_plugin->id) {
843 /* avenc_aac: see https://bugzilla.gnome.org/show_bug.cgi?id=691617 */
844 case AV_CODEC_ID_AAC:
845 rank = GST_RANK_NONE;
846 break;
847 default:
848 rank = GST_RANK_SECONDARY;
849 break;
850 }
851
852 if (!gst_element_register (plugin, type_name, rank, type)) {
853 g_free (type_name);
854 return FALSE;
855 }
856
857 g_free (type_name);
858 }
859
860 GST_LOG ("Finished registering encoders");
861
862 return TRUE;
863 }
864