2 * GStreamer codec plugin for Tizen Emulator.
4 * Copyright (C) 2013 Samsung Electronics Co., Ltd. All rights reserved.
7 * KiTae Kim <kt920.kim@samsung.com>
8 * SeokYeon Hwang <syeon.hwang@samsung.com>
9 * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
11 * This library is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Library General Public
13 * License as published by the Free Software Foundation; either
14 * version 2 of the License, or (at your option) any later version.
16 * This library is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Library General Public License for more details.
21 * You should have received a copy of the GNU Library General Public
22 * License along with this library; if not, write to the
23 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
24 * Boston, MA 02111-1307, USA.
31 #include "gstemulutils.h"
32 #include "gstemulapi.h"
33 #include "gstemuldev.h"
34 #include <gst/base/gstadapter.h>
36 #define GST_EMULENC_PARAMS_QDATA g_quark_from_static_string("maruenc-params")
38 typedef struct _GstEmulEnc
45 CodecContext *context;
48 GstClockTime adapter_ts;
49 guint64 adapter_consumed;
59 gulong working_buf_size;
65 typedef struct _GstEmulEncClass
67 GstElementClass parent_class;
70 GstPadTemplate *sinktempl;
71 GstPadTemplate *srctempl;
75 static GstElementClass *parent_class = NULL;
77 static void gst_emulenc_base_init (GstEmulEncClass *klass);
78 static void gst_emulenc_class_init (GstEmulEncClass *klass);
79 static void gst_emulenc_init (GstEmulEnc *emulenc);
80 static void gst_emulenc_finalize (GObject *object);
82 static gboolean gst_emulenc_setcaps (GstPad *pad, GstCaps *caps);
83 static GstCaps *gst_emulenc_getcaps (GstPad *pad);
85 static GstCaps *gst_emulenc_get_possible_sizes (GstEmulEnc *emulenc,
86 GstPad *pad, const GstCaps *caps);
88 static GstFlowReturn gst_emulenc_chain_video (GstPad *pad, GstBuffer *buffer);
89 static GstFlowReturn gst_emulenc_chain_audio (GstPad *pad, GstBuffer *buffer);
91 static gboolean gst_emulenc_event_video (GstPad *pad, GstEvent *event);
92 static gboolean gst_emulenc_event_src (GstPad *pad, GstEvent *event);
94 GstStateChangeReturn gst_emulenc_change_state (GstElement *element, GstStateChange transition);
96 #define DEFAULT_VIDEO_BITRATE 300000
97 #define DEFAULT_VIDEO_GOP_SIZE 15
98 #define DEFAULT_AUDIO_BITRATE 128000
100 #define DEFAULT_WIDTH 352
101 #define DEFAULT_HEIGHT 288
107 gst_emulenc_base_init (GstEmulEncClass *klass)
109 GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
110 GstPadTemplate *sinktempl = NULL, *srctempl = NULL;
111 GstCaps *sinkcaps = NULL, *srccaps = NULL;
113 gchar *longname, *classification, *description;
116 (CodecElement *)g_type_get_qdata (G_OBJECT_CLASS_TYPE (klass),
117 GST_EMULENC_PARAMS_QDATA);
119 longname = g_strdup_printf ("%s Encoder", codec->longname);
120 classification = g_strdup_printf ("Codec/Encoder/%s",
121 (codec->media_type == AVMEDIA_TYPE_VIDEO) ? "Video" : "Audio");
122 description = g_strdup_printf ("%s Encoder", codec->name);
124 gst_element_class_set_details_simple (element_class,
128 // "accelerated codec for Tizen Emulator",
129 "Kitae Kim <kt920.kim@samsung.com>");
132 g_free (classification);
135 if (!(srccaps = gst_emul_codecname_to_caps (codec->name, NULL, TRUE))) {
136 GST_DEBUG ("Couldn't get source caps for encoder '%s'", codec->name);
137 srccaps = gst_caps_new_simple ("unknown/unknown", NULL);
140 switch (codec->media_type) {
141 case AVMEDIA_TYPE_VIDEO:
142 sinkcaps = gst_caps_from_string ("video/x-raw-rgb; video/x-raw-yuv; video/x-raw-gray");
144 case AVMEDIA_TYPE_AUDIO:
145 sinkcaps = gst_emul_codectype_to_audio_caps (NULL, codec->name, TRUE, codec);
148 GST_LOG("unknown media type.\n");
153 GST_DEBUG ("Couldn't get sink caps for encoder '%s'", codec->name);
154 sinkcaps = gst_caps_new_simple ("unknown/unknown", NULL);
157 sinktempl = gst_pad_template_new ("sink", GST_PAD_SINK,
158 GST_PAD_ALWAYS, sinkcaps);
159 srctempl = gst_pad_template_new ("src", GST_PAD_SRC,
160 GST_PAD_ALWAYS, srccaps);
162 gst_element_class_add_pad_template (element_class, srctempl);
163 gst_element_class_add_pad_template (element_class, sinktempl);
165 klass->codec = codec;
166 klass->sinktempl = sinktempl;
167 klass->srctempl = srctempl;
168 klass->sinkcaps = NULL;
172 gst_emulenc_class_init (GstEmulEncClass *klass)
174 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
175 GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
177 parent_class = g_type_class_peek_parent (klass);
180 gobject_class->set_property = gst_emulenc_set_property
181 gobject_class->get_property = gst_emulenc_get_property
184 gstelement_class->change_state = gst_emulenc_change_state;
186 gobject_class->finalize = gst_emulenc_finalize;
190 gst_emulenc_init (GstEmulEnc *emulenc)
192 GstEmulEncClass *oclass;
193 oclass = (GstEmulEncClass*) (G_OBJECT_GET_CLASS(emulenc));
195 emulenc->sinkpad = gst_pad_new_from_template (oclass->sinktempl, "sink");
196 gst_pad_set_setcaps_function (emulenc->sinkpad,
197 GST_DEBUG_FUNCPTR(gst_emulenc_setcaps));
198 gst_pad_set_getcaps_function (emulenc->sinkpad,
199 GST_DEBUG_FUNCPTR(gst_emulenc_getcaps));
201 emulenc->srcpad = gst_pad_new_from_template (oclass->srctempl, "src");
202 gst_pad_use_fixed_caps (emulenc->srcpad);
204 if (oclass->codec->media_type == AVMEDIA_TYPE_VIDEO) {
205 gst_pad_set_chain_function (emulenc->sinkpad, gst_emulenc_chain_video);
206 gst_pad_set_event_function (emulenc->sinkpad, gst_emulenc_event_video);
207 gst_pad_set_event_function (emulenc->srcpad, gst_emulenc_event_src);
209 emulenc->bitrate = DEFAULT_VIDEO_BITRATE;
210 emulenc->buffer_size = 512 * 1024;
211 emulenc->gop_size = DEFAULT_VIDEO_GOP_SIZE;
216 } else if (oclass->codec->media_type == AVMEDIA_TYPE_AUDIO){
217 gst_pad_set_chain_function (emulenc->sinkpad, gst_emulenc_chain_audio);
218 emulenc->bitrate = DEFAULT_AUDIO_BITRATE;
221 gst_element_add_pad (GST_ELEMENT (emulenc), emulenc->sinkpad);
222 gst_element_add_pad (GST_ELEMENT (emulenc), emulenc->srcpad);
224 emulenc->context = g_malloc0 (sizeof(CodecContext));
225 emulenc->context->video.pix_fmt = PIX_FMT_NONE;
226 emulenc->context->audio.sample_fmt = SAMPLE_FMT_NONE;
228 emulenc->opened = FALSE;
231 emulenc->file = NULL;
233 emulenc->delay = g_queue_new ();
235 emulenc->dev = g_malloc0 (sizeof(CodecDevice));
237 printf("failed to allocate memory.\n");
240 // need to know what adapter does.
241 emulenc->adapter = gst_adapter_new ();
245 gst_emulenc_finalize (GObject *object)
248 GstEmulEnc *emulenc = (GstEmulEnc *) object;
250 if (emulenc->opened) {
251 gst_emul_avcodec_close (emulenc->context, emulenc->dev);
252 emulenc->opened = FALSE;
255 if (emulenc->context) {
256 g_free (emulenc->context);
257 emulenc->context = NULL;
260 g_queue_free (emulenc->delay);
262 g_free (emulenc->filename);
265 g_object_unref (emulenc->adapter);
267 G_OBJECT_CLASS (parent_class)->finalize (object);
271 gst_emulenc_get_possible_sizes (GstEmulEnc *emulenc, GstPad *pad,
274 GstCaps *othercaps = NULL;
275 GstCaps *tmpcaps = NULL;
276 GstCaps *intersect = NULL;
279 othercaps = gst_pad_peer_get_caps (emulenc->srcpad);
282 return gst_caps_copy (caps);
285 intersect = gst_caps_intersect (othercaps,
286 gst_pad_get_pad_template_caps (emulenc->srcpad));
287 gst_caps_unref (othercaps);
289 if (gst_caps_is_empty (intersect)) {
293 if (gst_caps_is_any (intersect)) {
294 return gst_caps_copy (caps);
297 tmpcaps = gst_caps_new_empty ();
299 for (i = 0; i <gst_caps_get_size (intersect); i++) {
300 GstStructure *s = gst_caps_get_structure (intersect, i);
301 const GValue *height = NULL;
302 const GValue *width = NULL;
303 const GValue *framerate = NULL;
306 height = gst_structure_get_value (s, "height");
307 width = gst_structure_get_value (s, "width");
308 framerate = gst_structure_get_value (s, "framerate");
310 tmps = gst_structure_new ("video/x-rwa-rgb", NULL);
312 gst_structure_set_value (tmps, "width", width);
315 gst_structure_set_value (tmps, "height", height);
318 gst_structure_set_value (tmps, "framerate", framerate);
320 gst_caps_merge_structure (tmpcaps, gst_structure_copy (tmps));
322 gst_structure_set_name (tmps, "video/x-raw-yuv");
323 gst_caps_merge_structure (tmpcaps, gst_structure_copy (tmps));
325 gst_structure_set_name (tmps, "video/x-raw-gray");
326 gst_caps_merge_structure (tmpcaps, tmps);
328 gst_caps_unref (intersect);
330 intersect = gst_caps_intersect (caps, tmpcaps);
331 gst_caps_unref (tmpcaps);
337 gst_emulenc_getcaps (GstPad *pad)
339 GstEmulEnc *emulenc = (GstEmulEnc *) GST_PAD_PARENT (pad);
340 GstEmulEncClass *oclass =
341 (GstEmulEncClass *) G_OBJECT_GET_CLASS (emulenc);
342 CodecContext *ctx = NULL;
343 enum PixelFormat pixfmt;
344 GstCaps *caps = NULL;
345 GstCaps *finalcaps = NULL;
348 GST_DEBUG_OBJECT (emulenc, "getting caps");
350 if (!oclass->codec) {
351 GST_ERROR_OBJECT (emulenc, "codec element is null.");
355 if (oclass->codec->media_type == AVMEDIA_TYPE_AUDIO) {
356 caps = gst_caps_copy (gst_pad_get_pad_template_caps (pad));
358 GST_DEBUG_OBJECT (emulenc, "audio caps, return template %" GST_PTR_FORMAT,
364 if (oclass->sinkcaps) {
365 caps = gst_emulenc_get_possible_sizes (emulenc, pad, oclass->sinkcaps);
366 GST_DEBUG_OBJECT (emulenc, "return cached caps %" GST_PTR_FORMAT, caps);
370 GST_DEBUG_OBJECT (emulenc, "probing caps");
373 for (pixfmt = 0;; pixfmt++) {
376 if ((pixfmt = oclass->codec->pix_fmts[i++]) == PIX_FMT_NONE) {
377 GST_DEBUG_OBJECT (emulenc,
378 "At the end of official pixfmt for this codec, breaking out");
382 GST_DEBUG_OBJECT (emulenc,
383 "Got an official pixfmt [%d], attempting to get caps", pixfmt);
384 tmpcaps = gst_emul_pixfmt_to_caps (pixfmt, NULL, oclass->codec->name);
386 GST_DEBUG_OBJECT (emulenc, "Got caps, breaking out");
388 caps = gst_caps_new_empty ();
390 gst_caps_append (caps, tmpcaps);
394 GST_DEBUG_OBJECT (emulenc,
395 "Couldn't figure out caps without context, trying again with a context");
397 GST_DEBUG_OBJECT (emulenc, "pixfmt: %d", pixfmt);
398 if (pixfmt >= PIX_FMT_NB) {
399 GST_WARNING ("Invalid pixfmt, breaking out");
403 ctx = g_malloc0 (sizeof(CodecContext));
405 GST_DEBUG_OBJECT (emulenc, "no context");
409 ctx->video.width = DEFAULT_WIDTH;
410 ctx->video.height = DEFAULT_HEIGHT;
411 ctx->video.fps_n = 1;
412 ctx->video.fps_d = 25;
413 ctx->video.ticks_per_frame = 1;
414 ctx->bit_rate = DEFAULT_VIDEO_BITRATE;
416 // ctx->strict_std_compliance = -1;
417 ctx->video.pix_fmt = pixfmt;
419 GST_DEBUG ("Attempting to open codec");
420 if (gst_emul_avcodec_open (ctx, oclass->codec, emulenc->dev) >= 0
421 && ctx->video.pix_fmt == pixfmt) {
422 ctx->video.width = -1;
424 caps = gst_caps_new_empty ();
426 tmpcaps = gst_emul_codectype_to_caps (oclass->codec->media_type, ctx,
427 oclass->codec->name, TRUE);
429 gst_caps_append (caps, tmpcaps);
431 GST_LOG_OBJECT (emulenc,
432 "Couldn't get caps for codec: %s", oclass->codec->name);
434 gst_emul_avcodec_close (ctx, emulenc->dev);
436 GST_DEBUG_OBJECT (emulenc, "Opening codec failed with pixfmt: %d", pixfmt);
439 gst_emul_avcodec_close (ctx, emulenc->dev);
441 if (ctx->priv_data) {
442 gst_emul_avcodec_close (ctx, emulenc->dev);
449 caps = gst_emulenc_get_possible_sizes (emulenc, pad,
450 gst_pad_get_pad_template_caps (pad));
451 GST_DEBUG_OBJECT (emulenc, "probing gave nothing, "
452 "return template %" GST_PTR_FORMAT, caps);
456 GST_DEBUG_OBJECT (emulenc, "probed caps gave %" GST_PTR_FORMAT, caps);
457 oclass->sinkcaps = gst_caps_copy (caps);
459 finalcaps = gst_emulenc_get_possible_sizes (emulenc, pad, caps);
460 gst_caps_unref (caps);
466 gst_emulenc_setcaps (GstPad *pad, GstCaps *caps)
469 GstEmulEncClass *oclass;
471 GstCaps *allowed_caps;
473 enum PixelFormat pix_fmt;
476 emulenc = (GstEmulEnc *) (gst_pad_get_parent (pad));
477 oclass = (GstEmulEncClass *) (G_OBJECT_GET_CLASS (emulenc));
479 if (emulenc->opened) {
480 gst_emul_avcodec_close (emulenc->context, emulenc->dev);
481 emulenc->opened = FALSE;
483 gst_pad_set_caps (emulenc->srcpad, NULL);
486 emulenc->context->bit_rate = emulenc->bitrate;
487 GST_DEBUG_OBJECT (emulenc, "Setting context to bitrate %lu, gop_size %d",
488 emulenc->bitrate, emulenc->gop_size);
492 // user defined properties
493 emulenc->context->gop_size = emulenc->gop_size;
494 emulenc->context->lmin = (emulenc->lmin * FF_QP2LAMBDA + 0.5);
495 emulenc->context->lmax = (emulenc->lmax * FF_QP2LAMBDA + 0.5);
497 // some other defaults
498 emulenc->context->b_frame_strategy = 0;
499 emulenc->context->coder_type = 0;
500 emulenc->context->context_model = 0;
501 emulenc->context->scenechange_threshold = 0;
502 emulenc->context->inter_threshold = 0;
504 if (emulenc->interlaced) {
505 emulenc->context->flags |=
506 CODEC_FLAG_INTERLACED_DCT | CODEC_FLAG_INTERLACED_ME;
507 emulenc->picture->interlaced_frame = TRUE;
509 emulenc->picture->top_field_first = TRUE;
513 gst_emul_caps_with_codectype (oclass->codec->media_type, caps, emulenc->context);
515 if (!emulenc->context->video.fps_d) {
516 emulenc->context->video.fps_d = 25;
517 emulenc->context->video.fps_n = 1;
518 } else if (!strcmp(oclass->codec->name ,"mpeg4")
519 && (emulenc->context->video.fps_d > 65535)) {
520 emulenc->context->video.fps_n =
521 (gint) gst_util_uint64_scale_int (emulenc->context->video.fps_n,
522 65535, emulenc->context->video.fps_d);
523 emulenc->context->video.fps_d = 65535;
524 GST_LOG_OBJECT (emulenc, "MPEG4 : scaled down framerate to %d / %d",
525 emulenc->context->video.fps_d, emulenc->context->video.fps_n);
528 pix_fmt = emulenc->context->video.pix_fmt;
531 switch (oclass->codec->media_type) {
532 case AVMEDIA_TYPE_VIDEO:
536 width = emulenc->context->video.width;
537 height = emulenc->context->video.height;
538 buf_size = width * height * 6 + FF_MIN_BUFFER_SIZE + 100;
541 case AVMEDIA_TYPE_AUDIO:
542 buf_size = FF_MAX_AUDIO_FRAME_SIZE + 100;
550 emulenc->dev->buf_size = gst_emul_align_size(buf_size);
553 if (gst_emul_avcodec_open (emulenc->context,
554 oclass->codec, emulenc->dev) < 0) {
555 GST_DEBUG_OBJECT (emulenc, "maru_%senc: Failed to open codec",
556 oclass->codec->name);
560 if (pix_fmt != emulenc->context->video.pix_fmt) {
561 gst_emul_avcodec_close (emulenc->context, emulenc->dev);
562 GST_DEBUG_OBJECT (emulenc,
563 "maru_%senc: AV wants different colorspace (%d given, %d wanted)",
564 oclass->codec->name, pix_fmt, emulenc->context->video.pix_fmt);
568 if (oclass->codec->media_type == AVMEDIA_TYPE_VIDEO
569 && pix_fmt == PIX_FMT_NONE) {
570 GST_DEBUG_OBJECT (emulenc, "maru_%senc: Failed to determine input format",
571 oclass->codec->name);
575 GST_DEBUG_OBJECT (emulenc, "picking an output format.");
576 allowed_caps = gst_pad_get_allowed_caps (emulenc->srcpad);
578 GST_DEBUG_OBJECT (emulenc, "but no peer, using template caps");
580 gst_caps_copy (gst_pad_get_pad_template_caps (emulenc->srcpad));
583 GST_DEBUG_OBJECT (emulenc, "chose caps %" GST_PTR_FORMAT, allowed_caps);
584 gst_emul_caps_with_codecname (oclass->codec->name,
585 oclass->codec->media_type, allowed_caps, emulenc->context);
588 gst_emul_codecname_to_caps (oclass->codec->name, emulenc->context, TRUE);
590 GST_DEBUG("Unsupported codec - no caps found");
591 gst_emul_avcodec_close (emulenc->context, emulenc->dev);
595 icaps = gst_caps_intersect (allowed_caps, other_caps);
596 gst_caps_unref (allowed_caps);
597 gst_caps_unref (other_caps);
598 if (gst_caps_is_empty (icaps)) {
599 gst_caps_unref (icaps);
603 if (gst_caps_get_size (icaps) > 1) {
607 gst_caps_new_full (gst_structure_copy (gst_caps_get_structure (icaps,
609 gst_caps_unref (icaps);
613 if (!gst_pad_set_caps (emulenc->srcpad, icaps)) {
614 gst_emul_avcodec_close (emulenc->context, emulenc->dev);
615 gst_caps_unref (icaps);
618 gst_object_unref (emulenc);
620 emulenc->opened = TRUE;
626 gst_emulenc_setup_working_buf (GstEmulEnc *emulenc)
629 emulenc->context->video.width * emulenc->context->video.height * 6 +
632 if (emulenc->working_buf == NULL ||
633 emulenc->working_buf_size != wanted_size) {
634 if (emulenc->working_buf) {
635 g_free (emulenc->working_buf);
637 emulenc->working_buf_size = wanted_size;
638 emulenc->working_buf = g_malloc0 (emulenc->working_buf_size);
640 emulenc->buffer_size = wanted_size;
644 gst_emulenc_chain_video (GstPad *pad, GstBuffer *buffer)
646 GstEmulEnc *emulenc = (GstEmulEnc *) (GST_PAD_PARENT (pad));
648 gint ret_size = 0, frame_size;
650 GST_DEBUG_OBJECT (emulenc,
651 "Received buffer of time %" GST_TIME_FORMAT,
652 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)));
655 GST_OBJECT_LOCK (emulenc);
656 force_keyframe = emulenc->force_keyframe;
657 emulenc->force_keyframe = FALSE;
658 GST_OBJECT_UNLOCK (emulenc);
660 if (force_keyframe) {
661 emulenc->picture->pict_type = FF_I_TYPE;
665 frame_size = gst_emul_avpicture_size (emulenc->context->video.pix_fmt,
666 emulenc->context->video.width, emulenc->context->video.height);
667 g_return_val_if_fail (frame_size == GST_BUFFER_SIZE (buffer),
671 pts = gst_emul_time_gst_to_ff (GST_BUFFER_TIMESTAMP (buffer) /
672 emulenc->context.video.ticks_per_frame,
673 emulenc->context.video.fps_n, emulen->context.video.fps_d);
676 // TODO: check whether this func needs or not.
677 gst_emulenc_setup_working_buf (emulenc);
680 codec_encode_video (emulenc->context, emulenc->working_buf,
681 emulenc->working_buf_size, GST_BUFFER_DATA (buffer),
682 GST_BUFFER_SIZE (buffer), GST_BUFFER_TIMESTAMP (buffer),
686 GstEmulEncClass *oclass =
687 (GstEmulEncClass *) (G_OBJECT_GET_CLASS (emulenc));
688 GST_ERROR_OBJECT (emulenc,
689 "maru_%senc: failed to encode buffer", oclass->codec->name);
690 gst_buffer_unref (buffer);
694 g_queue_push_tail (emulenc->delay, buffer);
696 buffer = g_queue_pop_head (emulenc->delay);
702 if (emulenc->file && emulenc->context->stats_out) {
703 if (fprintf (emulenc->file, "%s", emulenc->context->stats_out) < 0) {
704 GST_ELEMENT_ERROR (emulenc, RESOURCE, WRITE,
705 (("Could not write to file \"%s\"."), emulenc->filename),
714 uint8_t *working_buf = NULL;
716 mem_offset = emulenc->dev->mem_info.offset;
717 working_buf = emulenc->dev->buf + mem_offset;
721 "encoded video. mem_offset = 0x%x\n", mem_offset);
723 outbuf = gst_buffer_new_and_alloc (ret_size);
724 // memcpy (GST_BUFFER_DATA (outbuf), emulenc->working_buf, ret_size);
725 memcpy (GST_BUFFER_DATA (outbuf), working_buf, ret_size);
726 GST_BUFFER_TIMESTAMP (outbuf) = GST_BUFFER_TIMESTAMP (buffer);
727 GST_BUFFER_DURATION (outbuf) = GST_BUFFER_DURATION (buffer);
730 ret = ioctl(emulenc->dev->fd, CODEC_CMD_RELEASE_MEMORY, &mem_offset);
732 CODEC_LOG (ERR, "failed to release used buffer\n");
738 if (emulenc->context->coded_frame) {
739 if (!emulenc->context->coded_frame->key_frame) {
740 GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DELTA_UNIT);
743 GST_WARNING_OBJECT (emulenc, "codec did not provide keyframe info");
746 gst_buffer_set_caps (outbuf, GST_PAD_CAPS (emulenc->srcpad));
748 gst_buffer_unref (buffer);
752 if (force_keyframe) {
753 gst_pad_push_event (emulenc->srcpad,
754 gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM,
755 gst_structure_new ("GstForceKeyUnit", "timestamp",
756 G_TYPE_UINT64, GST_BUFFER_TIMESTAMP (outbuf), NULL)));
760 return gst_pad_push (emulenc->srcpad, outbuf);
764 gst_emulenc_encode_audio (GstEmulEnc *emulenc, guint8 *audio_in,
765 guint in_size, guint max_size, GstClockTime timestamp,
766 GstClockTime duration, gboolean discont)
773 outbuf = gst_buffer_new_and_alloc (max_size + FF_MIN_BUFFER_SIZE);
774 audio_out = GST_BUFFER_DATA (outbuf);
776 GST_LOG_OBJECT (emulenc, "encoding buffer of max size %d", max_size);
777 if (emulenc->buffer_size != max_size) {
778 emulenc->buffer_size = max_size;
781 res = codec_encode_audio (emulenc->context, audio_out, max_size,
782 audio_in, in_size, emulenc->dev);
785 GST_ERROR_OBJECT (emulenc, "Failed to encode buffer: %d", res);
786 gst_buffer_unref (outbuf);
789 GST_LOG_OBJECT (emulenc, "got output size %d", res);
791 GST_BUFFER_SIZE (outbuf) = res;
792 GST_BUFFER_TIMESTAMP (outbuf) = timestamp;
793 GST_BUFFER_DURATION (outbuf) = duration;
795 GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
797 gst_buffer_set_caps (outbuf, GST_PAD_CAPS (emulenc->srcpad));
799 GST_LOG_OBJECT (emulenc, "pushing size %d, timestamp %",
800 GST_TIME_FORMAT, res, GST_TIME_ARGS (timestamp));
802 ret = gst_pad_push (emulenc->srcpad, outbuf);
808 gst_emulenc_chain_audio (GstPad *pad, GstBuffer *buffer)
811 GstEmulEncClass *oclass;
812 GstClockTime timestamp, duration;
813 guint in_size, frame_size;
821 emulenc = (GstEmulEnc *) (GST_OBJECT_PARENT (pad));
822 oclass = (GstEmulEncClass *) G_OBJECT_GET_CLASS (emulenc);
824 ctx = emulenc->context;
826 in_size = GST_BUFFER_SIZE (buffer);
827 timestamp = GST_BUFFER_TIMESTAMP (buffer);
828 duration = GST_BUFFER_DURATION (buffer);
829 discont = GST_BUFFER_IS_DISCONT (buffer);
831 GST_DEBUG_OBJECT (emulenc,
832 "Received time %" GST_TIME_FORMAT ", duration %" GST_TIME_FORMAT
833 ", size %d", GST_TIME_ARGS (timestamp), GST_TIME_ARGS (duration), in_size);
835 frame_size = ctx->audio.frame_size;
836 osize = ctx->audio.bits_per_sample_fmt;
838 if (frame_size > 1) {
839 guint avail, frame_bytes;
842 GST_LOG_OBJECT (emulenc, "DISCONT, clear adapter");
843 gst_adapter_clear (emulenc->adapter);
844 emulenc->discont = TRUE;
847 if (gst_adapter_available (emulenc->adapter) == 0) {
848 GST_LOG_OBJECT (emulenc, "taking buffer timestamp %" GST_TIME_FORMAT,
849 GST_TIME_ARGS (timestamp));
850 emulenc->adapter_ts = timestamp;
851 emulenc->adapter_consumed = 0;
853 GstClockTime upstream_time;
854 GstClockTime consumed_time;
858 gst_util_uint64_scale (emulenc->adapter_consumed, GST_SECOND,
859 ctx->audio.sample_rate);
860 timestamp = emulenc->adapter_ts + consumed_time;
861 GST_LOG_OBJECT (emulenc, "taking adapter timestamp %" GST_TIME_FORMAT
862 " and adding consumed time %" GST_TIME_FORMAT,
863 GST_TIME_ARGS (emulenc->adapter_ts), GST_TIME_ARGS (consumed_time));
865 upstream_time = gst_adapter_prev_timestamp (emulenc->adapter, &bytes);
866 if (GST_CLOCK_TIME_IS_VALID (upstream_time)) {
867 GstClockTimeDiff diff;
870 gst_util_uint64_scale (bytes, GST_SECOND,
871 ctx->audio.sample_rate * osize * ctx->audio.channels);
872 diff = upstream_time - timestamp;
874 if (diff > GST_SECOND / 10 || diff < -GST_SECOND / 10) {
875 GST_DEBUG_OBJECT (emulenc, "adapter timestamp drifting, "
876 "taking upstream timestamp %" GST_TIME_FORMAT,
877 GST_TIME_ARGS (upstream_time));
878 timestamp = upstream_time;
880 emulenc->adapter_consumed = bytes / (osize * ctx->audio.channels);
881 emulenc->adapter_ts =
882 upstream_time - gst_util_uint64_scale (emulenc->adapter_consumed,
883 GST_SECOND, ctx->audio.sample_rate);
884 emulenc->discont = TRUE;
889 GST_LOG_OBJECT (emulenc, "pushing buffer in adapter");
890 gst_adapter_push (emulenc->adapter, buffer);
892 frame_bytes = frame_size * osize * ctx->audio.channels;
893 avail = gst_adapter_available (emulenc->adapter);
895 GST_LOG_OBJECT (emulenc, "frame_bytes %u, avail %u", frame_bytes, avail);
897 while (avail >= frame_bytes) {
898 GST_LOG_OBJECT (emulenc, "taking %u bytes from the adapter", frame_bytes);
900 in_data = (guint8 *) gst_adapter_peek (emulenc->adapter, frame_bytes);
901 emulenc->adapter_consumed += frame_size;
904 gst_util_uint64_scale (emulenc->adapter_consumed, GST_SECOND,
905 ctx->audio.sample_rate);
906 duration -= (timestamp - emulenc->adapter_ts);
908 out_size = frame_bytes * 4;
911 gst_emulenc_encode_audio (emulenc, in_data, frame_bytes, out_size,
912 timestamp, duration, emulenc->discont);
914 gst_adapter_flush (emulenc->adapter, frame_bytes);
915 if (ret != GST_FLOW_OK) {
916 GST_DEBUG_OBJECT (emulenc, "Failed to push buffer %d (%s)", ret,
917 gst_flow_get_name (ret));
920 timestamp += duration;
922 emulenc->discont = FALSE;
923 avail = gst_adapter_available (emulenc->adapter);
925 GST_LOG_OBJECT (emulenc, "%u bytes left in the adapter", avail);
928 int coded_bps = av_get_bits_per_sample (oclass->codec->name);
930 GST_LOG_OBJECT (emulenc, "coded bps %d, osize %d", coded_bps, osize);
932 out_size = in_size / osize;
934 out_size = (out_size * coded_bps) / 8;
937 in_data = (guint8 *) GST_BUFFER_DATA (buffer);
938 ret = gst_emulenc_encode_audio (emulenc, in_data, in_size, out_size,
939 timestamp, duration, discont);
940 gst_buffer_unref (buffer);
941 if (ret != GST_FLOW_OK) {
942 GST_DEBUG_OBJECT (emulenc, "Failed to push buffer %d (%s)", ret,
943 gst_flow_get_name (ret));
951 gst_emulenc_flush_buffers (GstEmulEnc *emulenc, gboolean send)
953 GstBuffer *outbuf, *inbuf;
956 GST_DEBUG_OBJECT (emulenc, "flushing buffers with sending %d", send);
958 if (!emulenc->opened) {
959 while (!g_queue_is_empty (emulenc->delay)) {
960 gst_buffer_unref (g_queue_pop_head (emulenc->delay));
965 while (!g_queue_is_empty (emulenc->delay)) {
966 emulenc_setup_working_buf (emulenc);
968 ret_size = codec_encode_video (emulenc->context,
969 emulenc->working_buf, emulenc->working_buf_size, NULL, NULL, 0,
973 GstEmulEncClass *oclass =
974 (GstEmulEncClass *) (G_OBJECT_GET_CLASS (emulenc));
975 GST_WARNING_OBJECT (emulenc,
976 "maru_%senc: failed to flush buffer", oclass->codec->name);
980 if (emulenc->file && emulenc->context->stats_out) {
981 if (fprintf (emulenc->file, "%s", emulenc->context->stats_out) < 0) {
982 GST_ELEMENT_ERROR (emeulenc, RESOURCE, WRITE,
983 (("Could not write to file \"%s\"."), emulenc->filename),
988 inbuf = g_queue_pop_head (emulenc->delay);
990 outbuf = gst_buffer_new_and_alloc (ret_size);
991 memcpy (GST_BUFFER_DATA (outbuf), emulenc->working_buf, ret_size);
992 GST_BUFFER_TIMESTAMP (outbuf) = GST_BUFFER_TIMESTAMP (inbuf);
993 GST_BUFFER_DURATION (outbuf) = GST_BUFFER_DURATION (inbuf);
995 if (!emulenc->context->coded_frame->key_frame) {
996 GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DELTA_UNIT);
998 gst_buffer_set_caps (outbuf, GST_PAD_CAPS (emulenc->srcpad));
1000 gst_buffer_unref (inbuf);
1003 gst_pad_push (emulenc->srcpad, outbuf);
1005 gst_buffer_unref (outbuf);
1009 while (!g_queue_is_empty (emulenc->delay)) {
1010 gst_buffer_unref (g_queue_pop_head (emulenc->delay));
1016 gst_emulenc_event_video (GstPad *pad, GstEvent *event)
1018 GstEmulEnc *emulenc;
1019 emulenc = (GstEmulEnc *) gst_pad_get_parent (pad);
1021 switch (GST_EVENT_TYPE (event)) {
1023 gst_emulenc_flush_buffers (emulenc, TRUE);
1025 case GST_EVENT_CUSTOM_DOWNSTREAM:
1027 const GstStructure *s;
1028 s = gst_event_get_structure (event);
1030 if (gst_structure_has_name (s, "GstForceKeyUnit")) {
1032 emulenc->picture->pict_type = FF_I_TYPE;
1041 return gst_pad_push_event (emulenc->srcpad, event);
1045 gst_emulenc_event_src (GstPad *pad, GstEvent *event)
1047 GstEmulEnc *emulenc = (GstEmulEnc *) (GST_PAD_PARENT (pad));
1048 gboolean forward = TRUE;
1050 switch (GST_EVENT_TYPE (event)) {
1051 case GST_EVENT_CUSTOM_UPSTREAM:
1053 const GstStructure *s;
1054 s = gst_event_get_structure (event);
1056 if (gst_structure_has_name (s, "GstForceKeyUnit")) {
1058 GST_OBJECT_LOCK (emulenc);
1059 emulenc->force_keyframe = TRUE;
1060 GST_OBJECT_UNLOCK (emulenc);
1063 gst_event_unref (event);
1072 return gst_pad_push_event (emulenc->sinkpad, event);
1078 GstStateChangeReturn
1079 gst_emulenc_change_state (GstElement *element, GstStateChange transition)
1081 GstEmulEnc *emulenc = (GstEmulEnc*)element;
1082 GstStateChangeReturn ret;
1084 switch (transition) {
1089 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
1091 switch (transition) {
1092 case GST_STATE_CHANGE_PAUSED_TO_READY:
1093 gst_emulenc_flush_buffers (emulenc, FALSE);
1094 if (emulenc->opened) {
1095 gst_emul_avcodec_close (emulenc->context, emulenc->dev);
1096 emulenc->opened = FALSE;
1098 gst_adapter_clear (emulenc->adapter);
1101 if (emulenc->flie) {
1102 fclose (emulenc->file);
1103 emulenc->file = NULL;
1107 if (emulenc->working_buf) {
1108 g_free (emulenc->working_buf);
1109 emulenc->working_buf = NULL;
1120 gst_emulenc_register (GstPlugin *plugin, GList *element)
1122 GTypeInfo typeinfo = {
1123 sizeof (GstEmulEncClass),
1124 (GBaseInitFunc) gst_emulenc_base_init,
1126 (GClassInitFunc) gst_emulenc_class_init,
1129 sizeof (GstEmulEnc),
1131 (GInstanceInitFunc) gst_emulenc_init,
1136 gint rank = GST_RANK_NONE;
1137 GList *elem = element;
1138 CodecElement *codec = NULL;
1144 /* register element */
1146 codec = (CodecElement *)(elem->data);
1151 if (codec->codec_type != CODEC_TYPE_ENCODE) {
1155 type_name = g_strdup_printf ("maru_%senc", codec->name);
1156 type = g_type_from_name (type_name);
1158 type = g_type_register_static (GST_TYPE_ELEMENT, type_name, &typeinfo, 0);
1159 g_type_set_qdata (type, GST_EMULENC_PARAMS_QDATA, (gpointer) codec);
1162 if (!gst_element_register (plugin, type_name, rank, type)) {
1167 } while ((elem = elem->next));