fixed prevent issues.
[platform/adaptation/emulator/gst-plugins-emulator.git] / src / gstemulenc.c
1 /*
2  * GStreamer codec plugin for Tizen Emulator.
3  *
4  * Copyright (C) 2013 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact:
7  * KiTae Kim <kt920.kim@samsung.com>
8  * SeokYeon Hwang <syeon.hwang@samsung.com>
9  * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
10  *
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.
15  *
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.
20  *
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.
25  *
26  * Contributors:
27  * - S-Core Co., Ltd
28  *
29  */
30
31 #include "gstemulutils.h"
32 #include "gstemulapi.h"
33 #include "gstemuldev.h"
34 #include <gst/base/gstadapter.h>
35
36 #define GST_EMULENC_PARAMS_QDATA g_quark_from_static_string("maruenc-params")
37
38 typedef struct _GstEmulEnc
39 {
40   GstElement element;
41
42   GstPad *srcpad;
43   GstPad *sinkpad;
44
45   CodecContext *context;
46   CodecDevice *dev;
47   gboolean opened;
48   GstClockTime adapter_ts;
49   guint64 adapter_consumed;
50   GstAdapter *adapter;
51   gboolean discont;
52
53   // cache
54   gulong bitrate;
55   gint gop_size;
56   gulong buffer_size;
57
58   guint8 *working_buf;
59   gulong working_buf_size;
60
61   GQueue *delay;
62
63 } GstEmulEnc;
64
65 typedef struct _GstEmulEncClass
66 {
67   GstElementClass parent_class;
68
69   CodecElement *codec;
70   GstPadTemplate *sinktempl;
71   GstPadTemplate *srctempl;
72   GstCaps *sinkcaps;
73 } GstEmulEncClass;
74
75 static GstElementClass *parent_class = NULL;
76
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);
81
82 static gboolean gst_emulenc_setcaps (GstPad *pad, GstCaps *caps);
83 static GstCaps *gst_emulenc_getcaps (GstPad *pad);
84
85 static GstCaps *gst_emulenc_get_possible_sizes (GstEmulEnc *emulenc,
86   GstPad *pad, const GstCaps *caps);
87
88 static GstFlowReturn gst_emulenc_chain_video (GstPad *pad, GstBuffer *buffer);
89 static GstFlowReturn gst_emulenc_chain_audio (GstPad *pad, GstBuffer *buffer);
90
91 static gboolean gst_emulenc_event_video (GstPad *pad, GstEvent *event);
92 static gboolean gst_emulenc_event_src (GstPad *pad, GstEvent *event);
93
94 GstStateChangeReturn gst_emulenc_change_state (GstElement *element, GstStateChange transition);
95
96 #define DEFAULT_VIDEO_BITRATE   300000
97 #define DEFAULT_VIDEO_GOP_SIZE  15
98 #define DEFAULT_AUDIO_BITRATE   128000
99
100 #define DEFAULT_WIDTH 352
101 #define DEFAULT_HEIGHT 288
102
103 /*
104  * Implementation
105  */
106 static void
107 gst_emulenc_base_init (GstEmulEncClass *klass)
108 {
109     GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
110     GstPadTemplate *sinktempl = NULL, *srctempl = NULL;
111     GstCaps *sinkcaps = NULL, *srccaps = NULL;
112     CodecElement *codec;
113     gchar *longname, *classification, *description;
114
115     codec =
116         (CodecElement *)g_type_get_qdata (G_OBJECT_CLASS_TYPE (klass),
117          GST_EMULENC_PARAMS_QDATA);
118
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);
123
124     gst_element_class_set_details_simple (element_class,
125             longname,
126             classification,
127             description,
128 //            "accelerated codec for Tizen Emulator",
129             "Kitae Kim <kt920.kim@samsung.com>");
130
131     g_free (longname);
132     g_free (classification);
133
134
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);
138   }
139
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");
143     break;
144   case AVMEDIA_TYPE_AUDIO:
145     sinkcaps = gst_emul_codectype_to_audio_caps (NULL, codec->name, TRUE, codec);
146     break;
147   default:
148     GST_LOG("unknown media type.\n");
149     break;
150   }
151
152   if (!sinkcaps) {
153       GST_DEBUG ("Couldn't get sink caps for encoder '%s'", codec->name);
154       sinkcaps = gst_caps_new_simple ("unknown/unknown", NULL);
155   }
156
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);
161
162   gst_element_class_add_pad_template (element_class, srctempl);
163   gst_element_class_add_pad_template (element_class, sinktempl);
164
165   klass->codec = codec;
166   klass->sinktempl = sinktempl;
167   klass->srctempl = srctempl;
168   klass->sinkcaps = NULL;
169 }
170
171 static void
172 gst_emulenc_class_init (GstEmulEncClass *klass)
173 {
174   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
175   GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
176
177   parent_class = g_type_class_peek_parent (klass);
178
179 #if 0
180   gobject_class->set_property = gst_emulenc_set_property
181   gobject_class->get_property = gst_emulenc_get_property
182 #endif
183
184   gstelement_class->change_state = gst_emulenc_change_state;
185
186   gobject_class->finalize = gst_emulenc_finalize;
187 }
188
189 static void
190 gst_emulenc_init (GstEmulEnc *emulenc)
191 {
192   GstEmulEncClass *oclass;
193   oclass = (GstEmulEncClass*) (G_OBJECT_GET_CLASS(emulenc));
194
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));
200
201   emulenc->srcpad = gst_pad_new_from_template (oclass->srctempl, "src");
202   gst_pad_use_fixed_caps (emulenc->srcpad);
203
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);
208
209     emulenc->bitrate = DEFAULT_VIDEO_BITRATE;
210     emulenc->buffer_size = 512 * 1024;
211     emulenc->gop_size = DEFAULT_VIDEO_GOP_SIZE;
212 #if 0
213     emulenc->lmin = 2;
214     emulenc->lmax = 31;
215 #endif
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;
219   }
220
221   gst_element_add_pad (GST_ELEMENT (emulenc), emulenc->sinkpad);
222   gst_element_add_pad (GST_ELEMENT (emulenc), emulenc->srcpad);
223
224   // init
225   emulenc->context = g_malloc0 (sizeof(CodecContext));
226   if (!emulenc->context) {
227     printf("failed to allocate memory.\n");
228   }
229   emulenc->context->video.pix_fmt = PIX_FMT_NONE;
230   emulenc->context->audio.sample_fmt = SAMPLE_FMT_NONE;
231
232   emulenc->opened = FALSE;
233
234 #if 0
235   emulenc->file = NULL;
236 #endif
237   emulenc->delay = g_queue_new ();
238
239   emulenc->dev = g_malloc0 (sizeof(CodecDevice));
240   if (!emulenc->dev) {
241     printf("failed to allocate memory.\n");
242   }
243
244   // need to know what adapter does.
245   emulenc->adapter = gst_adapter_new ();
246 }
247
248 static void
249 gst_emulenc_finalize (GObject *object)
250 {
251   // Deinit Decoder
252   GstEmulEnc *emulenc = (GstEmulEnc *) object;
253
254   if (emulenc->opened) {
255     gst_emul_avcodec_close (emulenc->context, emulenc->dev);
256     emulenc->opened = FALSE;
257   }
258
259   if (emulenc->context) {
260     g_free (emulenc->context);
261     emulenc->context = NULL;
262   }
263
264   g_queue_free (emulenc->delay);
265 #if 0
266   g_free (emulenc->filename);
267 #endif
268
269   g_object_unref (emulenc->adapter);
270
271   G_OBJECT_CLASS (parent_class)->finalize (object);
272 }
273
274 static GstCaps *
275 gst_emulenc_get_possible_sizes (GstEmulEnc *emulenc, GstPad *pad,
276   const GstCaps *caps)
277 {
278   GstCaps *othercaps = NULL;
279   GstCaps *tmpcaps = NULL;
280   GstCaps *intersect = NULL;
281   guint i;
282
283   othercaps = gst_pad_peer_get_caps (emulenc->srcpad);
284
285   if (!othercaps) {
286     return gst_caps_copy (caps);
287   }
288
289   intersect = gst_caps_intersect (othercaps,
290     gst_pad_get_pad_template_caps (emulenc->srcpad));
291   gst_caps_unref (othercaps);
292
293   if (gst_caps_is_empty (intersect)) {
294     return intersect;
295   }
296
297   if (gst_caps_is_any (intersect)) {
298     return gst_caps_copy (caps);
299   }
300
301   tmpcaps = gst_caps_new_empty ();
302
303   for (i = 0; i <gst_caps_get_size (intersect); i++) {
304     GstStructure *s = gst_caps_get_structure (intersect, i);
305     const GValue *height = NULL;
306     const GValue *width = NULL;
307     const GValue *framerate = NULL;
308     GstStructure *tmps;
309
310     height = gst_structure_get_value (s, "height");
311     width = gst_structure_get_value (s, "width");
312     framerate = gst_structure_get_value (s, "framerate");
313
314     tmps = gst_structure_new ("video/x-rwa-rgb", NULL);
315     if (width) {
316       gst_structure_set_value (tmps, "width", width);
317     }
318     if (height) {
319       gst_structure_set_value (tmps, "height", height);
320     }
321     if (framerate) {
322       gst_structure_set_value (tmps, "framerate", framerate);
323     }
324     gst_caps_merge_structure (tmpcaps, gst_structure_copy (tmps));
325
326     gst_structure_set_name (tmps, "video/x-raw-yuv");
327     gst_caps_merge_structure (tmpcaps, gst_structure_copy (tmps));
328
329     gst_structure_set_name (tmps, "video/x-raw-gray");
330     gst_caps_merge_structure (tmpcaps, tmps);
331   }
332   gst_caps_unref (intersect);
333
334   intersect = gst_caps_intersect (caps, tmpcaps);
335   gst_caps_unref (tmpcaps);
336
337   return intersect;
338 }
339
340 static GstCaps *
341 gst_emulenc_getcaps (GstPad *pad)
342 {
343   GstEmulEnc *emulenc = (GstEmulEnc *) GST_PAD_PARENT (pad);
344   GstEmulEncClass *oclass =
345     (GstEmulEncClass *) G_OBJECT_GET_CLASS (emulenc);
346   CodecContext *ctx = NULL;
347   enum PixelFormat pixfmt;
348   GstCaps *caps = NULL;
349   GstCaps *finalcaps = NULL;
350   gint i;
351
352   GST_DEBUG_OBJECT (emulenc, "getting caps");
353
354   if (oclass->codec && oclass->codec->media_type == AVMEDIA_TYPE_AUDIO) {
355     caps = gst_caps_copy (gst_pad_get_pad_template_caps (pad));
356
357     GST_DEBUG_OBJECT (emulenc, "audio caps, return template %" GST_PTR_FORMAT,
358       caps);
359     return caps;
360   }
361
362   // cached
363   if (oclass->sinkcaps) {
364     caps = gst_emulenc_get_possible_sizes (emulenc, pad, oclass->sinkcaps);
365     GST_DEBUG_OBJECT (emulenc, "return cached caps %" GST_PTR_FORMAT, caps);
366     return caps;
367   }
368
369   GST_DEBUG_OBJECT (emulenc, "probing caps");
370   i = pixfmt = 0;
371
372 #if 1
373   for (pixfmt = 0;; pixfmt++) {
374     GstCaps *tmpcaps;
375
376 //    if (oclass->codec->pix_fmts) {
377         if ((pixfmt = oclass->codec->pix_fmts[i++]) == PIX_FMT_NONE) {
378                 GST_DEBUG_OBJECT (emulenc,
379                                 "At the end of official pixfmt for this codec, breaking out");
380                 break;
381         }
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);
385         if (tmpcaps) {
386                 GST_DEBUG_OBJECT (emulenc, "Got caps, breaking out");
387                 if (!caps) {
388                         caps = gst_caps_new_empty ();
389                 }
390                 gst_caps_append (caps, tmpcaps);
391                 continue;
392         }
393         GST_DEBUG_OBJECT (emulenc,
394                         "Couldn't figure out caps without context, trying again with a context");
395 //    }
396
397     GST_DEBUG_OBJECT (emulenc, "pixfmt: %d", pixfmt);
398     if (pixfmt >= PIX_FMT_NB) {
399       GST_WARNING ("Invalid pixfmt, breaking out");
400       break;
401     }
402
403     ctx = g_malloc0 (sizeof(CodecContext));
404     if (!ctx) {
405       GST_DEBUG_OBJECT (emulenc, "no context");
406       break;
407     }
408
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;
415
416 //    ctx->strict_std_compliance = -1;
417     ctx->video.pix_fmt = pixfmt;
418
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;
423       if (!caps) {
424         caps = gst_caps_new_empty ();
425       }
426       tmpcaps = gst_emul_codectype_to_caps (oclass->codec->media_type, ctx,
427         oclass->codec->name, TRUE);
428       if (tmpcaps) {
429         gst_caps_append (caps, tmpcaps);
430       } else {
431         GST_LOG_OBJECT (emulenc,
432           "Couldn't get caps for codec: %s", oclass->codec->name);
433       }
434       gst_emul_avcodec_close (ctx, emulenc->dev);
435     } else {
436       GST_DEBUG_OBJECT (emulenc, "Opening codec failed with pixfmt: %d", pixfmt);
437     }
438
439     gst_emul_avcodec_close (ctx, emulenc->dev);
440 #if 0
441     if (ctx->priv_data) {
442       gst_emul_avcodec_close (ctx, emulenc->dev);
443     }
444 #endif
445     g_free (ctx);
446   }
447 #endif
448
449   if (!caps) {
450     caps = gst_emulenc_get_possible_sizes (emulenc, pad,
451       gst_pad_get_pad_template_caps (pad));
452     GST_DEBUG_OBJECT (emulenc, "probing gave nothing, "
453       "return template %" GST_PTR_FORMAT, caps);
454     return caps;
455   }
456
457   GST_DEBUG_OBJECT (emulenc, "probed caps gave %" GST_PTR_FORMAT, caps);
458   oclass->sinkcaps = gst_caps_copy (caps);
459
460   finalcaps = gst_emulenc_get_possible_sizes (emulenc, pad, caps);
461   gst_caps_unref (caps);
462
463   return finalcaps;
464 }
465
466 static gboolean
467 gst_emulenc_setcaps (GstPad *pad, GstCaps *caps)
468 {
469   GstEmulEnc *emulenc;
470   GstEmulEncClass *oclass;
471   GstCaps *other_caps;
472   GstCaps *allowed_caps;
473   GstCaps *icaps;
474   enum PixelFormat pix_fmt;
475   int32_t buf_size;
476
477   emulenc = (GstEmulEnc *) (gst_pad_get_parent (pad));
478   oclass = (GstEmulEncClass *) (G_OBJECT_GET_CLASS (emulenc));
479
480   if (emulenc->opened) {
481     gst_emul_avcodec_close (emulenc->context, emulenc->dev);
482     emulenc->opened = FALSE;
483
484     gst_pad_set_caps (emulenc->srcpad, NULL);
485   }
486
487   emulenc->context->bit_rate = emulenc->bitrate;
488   GST_DEBUG_OBJECT (emulenc, "Setting context to bitrate %lu, gop_size %d",
489       emulenc->bitrate, emulenc->gop_size);
490
491 #if 0
492
493   // user defined properties
494   emulenc->context->gop_size = emulenc->gop_size;
495   emulenc->context->lmin = (emulenc->lmin * FF_QP2LAMBDA + 0.5);
496   emulenc->context->lmax = (emulenc->lmax * FF_QP2LAMBDA + 0.5);
497
498   // some other defaults
499   emulenc->context->b_frame_strategy = 0;
500   emulenc->context->coder_type = 0;
501   emulenc->context->context_model = 0;
502   emulenc->context->scenechange_threshold = 0;
503   emulenc->context->inter_threshold = 0;
504
505   if (emulenc->interlaced) {
506     emulenc->context->flags |=
507       CODEC_FLAG_INTERLACED_DCT | CODEC_FLAG_INTERLACED_ME;
508     emulenc->picture->interlaced_frame = TRUE;
509
510     emulenc->picture->top_field_first = TRUE;
511   }
512 #endif
513
514   gst_emul_caps_with_codectype (oclass->codec->media_type, caps, emulenc->context);
515
516   if (!emulenc->context->video.fps_d) {
517     emulenc->context->video.fps_d = 25;
518     emulenc->context->video.fps_n = 1;
519   } else if (!strcmp(oclass->codec->name ,"mpeg4")
520       && (emulenc->context->video.fps_d > 65535)) {
521       emulenc->context->video.fps_n =
522         (gint) gst_util_uint64_scale_int (emulenc->context->video.fps_n,
523             65535, emulenc->context->video.fps_d);
524       emulenc->context->video.fps_d = 65535;
525       GST_LOG_OBJECT (emulenc, "MPEG4 : scaled down framerate to %d / %d",
526           emulenc->context->video.fps_d, emulenc->context->video.fps_n);
527   }
528
529   pix_fmt = emulenc->context->video.pix_fmt;
530
531   {
532     switch (oclass->codec->media_type) {
533     case AVMEDIA_TYPE_VIDEO:
534     {
535       int width, height;
536
537       width = emulenc->context->video.width;
538       height = emulenc->context->video.height;
539       buf_size = width * height * 6 + FF_MIN_BUFFER_SIZE + 100;
540       break;
541     }
542     case AVMEDIA_TYPE_AUDIO:
543         buf_size = FF_MAX_AUDIO_FRAME_SIZE + 100;
544         break;
545     default:
546         buf_size = -1;
547         break;
548     }
549   }
550
551   emulenc->dev->buf_size = gst_emul_align_size(buf_size);
552
553   // open codec
554   if (gst_emul_avcodec_open (emulenc->context,
555       oclass->codec, emulenc->dev) < 0) {
556     GST_DEBUG_OBJECT (emulenc, "maru_%senc: Failed to open codec",
557         oclass->codec->name);
558     return FALSE;
559   }
560
561   if (pix_fmt != emulenc->context->video.pix_fmt) {
562     gst_emul_avcodec_close (emulenc->context, emulenc->dev);
563     GST_DEBUG_OBJECT (emulenc,
564       "maru_%senc: AV wants different colorspace (%d given, %d wanted)",
565       oclass->codec->name, pix_fmt, emulenc->context->video.pix_fmt);
566     return FALSE;
567   }
568
569   if (oclass->codec->media_type == AVMEDIA_TYPE_VIDEO
570     && pix_fmt == PIX_FMT_NONE) {
571     GST_DEBUG_OBJECT (emulenc, "maru_%senc: Failed to determine input format",
572       oclass->codec->name);
573     return FALSE;
574   }
575
576   GST_DEBUG_OBJECT (emulenc, "picking an output format.");
577   allowed_caps = gst_pad_get_allowed_caps (emulenc->srcpad);
578   if (!allowed_caps) {
579     GST_DEBUG_OBJECT (emulenc, "but no peer, using template caps");
580     allowed_caps =
581       gst_caps_copy (gst_pad_get_pad_template_caps (emulenc->srcpad));
582   }
583
584   GST_DEBUG_OBJECT (emulenc, "chose caps %" GST_PTR_FORMAT, allowed_caps);
585   gst_emul_caps_with_codecname (oclass->codec->name,
586     oclass->codec->media_type, allowed_caps, emulenc->context);
587
588   other_caps =
589   gst_emul_codecname_to_caps (oclass->codec->name, emulenc->context, TRUE);
590   if (!other_caps) {
591   GST_DEBUG("Unsupported codec - no caps found");
592     gst_emul_avcodec_close (emulenc->context, emulenc->dev);
593     return FALSE;
594   }
595
596   icaps = gst_caps_intersect (allowed_caps, other_caps);
597   gst_caps_unref (allowed_caps);
598   gst_caps_unref (other_caps);
599   if (gst_caps_is_empty (icaps)) {
600     gst_caps_unref (icaps);
601     return FALSE;
602   }
603
604   if (gst_caps_get_size (icaps) > 1) {
605     GstCaps *newcaps;
606
607     newcaps =
608       gst_caps_new_full (gst_structure_copy (gst_caps_get_structure (icaps,
609               0)), NULL);
610     gst_caps_unref (icaps);
611     icaps = newcaps;
612   }
613
614   if (!gst_pad_set_caps (emulenc->srcpad, icaps)) {
615     gst_emul_avcodec_close (emulenc->context, emulenc->dev);
616     gst_caps_unref (icaps);
617     return FALSE;
618   }
619   gst_object_unref (emulenc);
620
621   emulenc->opened = TRUE;
622
623   return TRUE;
624 }
625
626 static void
627 gst_emulenc_setup_working_buf (GstEmulEnc *emulenc)
628 {
629   guint wanted_size =
630       emulenc->context->video.width * emulenc->context->video.height * 6 +
631       FF_MIN_BUFFER_SIZE;
632
633   if (emulenc->working_buf == NULL ||
634     emulenc->working_buf_size != wanted_size) {
635     if (emulenc->working_buf) {
636       g_free (emulenc->working_buf);
637     }
638     emulenc->working_buf_size = wanted_size;
639     emulenc->working_buf = g_malloc0 (emulenc->working_buf_size);
640   }
641   emulenc->buffer_size = wanted_size;
642 }
643
644 GstFlowReturn
645 gst_emulenc_chain_video (GstPad *pad, GstBuffer *buffer)
646 {
647   GstEmulEnc *emulenc = (GstEmulEnc *) (GST_PAD_PARENT (pad));
648   GstBuffer *outbuf;
649   gint ret_size = 0, frame_size;
650
651   GST_DEBUG_OBJECT (emulenc,
652       "Received buffer of time %" GST_TIME_FORMAT,
653       GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)));
654
655 #if 0
656   GST_OBJECT_LOCK (emulenc);
657   force_keyframe = emulenc->force_keyframe;
658   emulenc->force_keyframe = FALSE;
659   GST_OBJECT_UNLOCK (emulenc);
660
661   if (force_keyframe) {
662     emulenc->picture->pict_type = FF_I_TYPE;
663   }
664 #endif
665
666   frame_size = gst_emul_avpicture_size (emulenc->context->video.pix_fmt,
667       emulenc->context->video.width, emulenc->context->video.height);
668   g_return_val_if_fail (frame_size == GST_BUFFER_SIZE (buffer),
669       GST_FLOW_ERROR);
670
671 #if 0
672   pts = gst_emul_time_gst_to_ff (GST_BUFFER_TIMESTAMP (buffer) /
673     emulenc->context.video.ticks_per_frame,
674     emulenc->context.video.fps_n, emulen->context.video.fps_d);
675 #endif
676
677   gst_emulenc_setup_working_buf (emulenc);
678
679   ret_size =
680     emul_avcodec_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),
683                 emulenc->dev);
684
685   if (ret_size < 0) {
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);
691     return GST_FLOW_OK;
692   }
693
694   g_queue_push_tail (emulenc->delay, buffer);
695   if (ret_size) {
696     buffer = g_queue_pop_head (emulenc->delay);
697   } else {
698     return GST_FLOW_OK;
699   }
700
701 #if 0
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),
706         GST_ERROR_SYSTEM);
707     }
708   }
709 #endif
710
711   outbuf = gst_buffer_new_and_alloc (ret_size);
712   memcpy (GST_BUFFER_DATA (outbuf), emulenc->working_buf, ret_size);
713   GST_BUFFER_TIMESTAMP (outbuf) = GST_BUFFER_TIMESTAMP (buffer);
714   GST_BUFFER_DURATION (outbuf) = GST_BUFFER_DURATION (buffer);
715 #if 0
716   if (emulenc->context->coded_frame) {
717     if (!emulenc->context->coded_frame->key_frame) {
718       GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DELTA_UNIT);
719     }
720   } else {
721     GST_WARNING_OBJECT (emulenc, "codec did not provide keyframe info");
722   }
723 #endif
724   gst_buffer_set_caps (outbuf, GST_PAD_CAPS (emulenc->srcpad));
725
726   gst_buffer_unref (buffer);
727
728 #if 0
729
730   if (force_keyframe) {
731     gst_pad_push_event (emulenc->srcpad,
732       gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM,
733       gst_structure_new ("GstForceKeyUnit", "timestamp",
734                          G_TYPE_UINT64, GST_BUFFER_TIMESTAMP (outbuf), NULL)));
735   }
736 #endif
737
738   return gst_pad_push (emulenc->srcpad, outbuf);
739 }
740
741 GstFlowReturn
742 gst_emulenc_encode_audio (GstEmulEnc *emulenc, guint8 *audio_in,
743   guint in_size, guint max_size, GstClockTime timestamp,
744   GstClockTime duration, gboolean discont)
745 {
746   GstBuffer *outbuf;
747   guint8 *audio_out;
748   gint res;
749   GstFlowReturn ret;
750
751   outbuf = gst_buffer_new_and_alloc (max_size + FF_MIN_BUFFER_SIZE);
752   audio_out = GST_BUFFER_DATA (outbuf);
753
754   GST_LOG_OBJECT (emulenc, "encoding buffer of max size %d", max_size);
755   if (emulenc->buffer_size != max_size) {
756     emulenc->buffer_size = max_size;
757   }
758
759   res = emul_avcodec_encode_audio (emulenc->context, audio_out, max_size,
760                                   audio_in, in_size, emulenc->dev);
761
762   if (res < 0) {
763     GST_ERROR_OBJECT (emulenc, "Failed to encode buffer: %d", res);
764     gst_buffer_unref (outbuf);
765     return GST_FLOW_OK;
766   }
767   GST_LOG_OBJECT (emulenc, "got output size %d", res);
768
769   GST_BUFFER_SIZE (outbuf) = res;
770   GST_BUFFER_TIMESTAMP (outbuf) = timestamp;
771   GST_BUFFER_DURATION (outbuf) = duration;
772   if (discont) {
773     GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
774   }
775   gst_buffer_set_caps (outbuf, GST_PAD_CAPS (emulenc->srcpad));
776
777   GST_LOG_OBJECT (emulenc, "pushing size %d, timestamp %",
778       GST_TIME_FORMAT, res, GST_TIME_ARGS (timestamp));
779
780   ret = gst_pad_push (emulenc->srcpad, outbuf);
781
782   return ret;
783 }
784
785 static GstFlowReturn
786 gst_emulenc_chain_audio (GstPad *pad, GstBuffer *buffer)
787 {
788   GstEmulEnc *emulenc;
789   GstEmulEncClass *oclass;
790   GstClockTime timestamp, duration;
791   guint in_size, frame_size;
792   gint osize;
793   GstFlowReturn ret;
794   gint out_size = 0;
795   gboolean discont;
796   guint8 *in_data;
797   CodecContext *ctx;
798
799   emulenc = (GstEmulEnc *) (GST_OBJECT_PARENT (pad));
800   oclass = (GstEmulEncClass *) G_OBJECT_GET_CLASS (emulenc);
801
802   ctx = emulenc->context;
803
804   in_size = GST_BUFFER_SIZE (buffer);
805   timestamp = GST_BUFFER_TIMESTAMP (buffer);
806   duration = GST_BUFFER_DURATION (buffer);
807   discont = GST_BUFFER_IS_DISCONT (buffer);
808
809   GST_DEBUG_OBJECT (emulenc,
810     "Received time %" GST_TIME_FORMAT ", duration %" GST_TIME_FORMAT
811     ", size %d", GST_TIME_ARGS (timestamp), GST_TIME_ARGS (duration), in_size);
812
813   frame_size = ctx->audio.frame_size;
814   osize = ctx->audio.bits_per_smp_fmt;
815
816   if (frame_size > 1) {
817     guint avail, frame_bytes;
818
819     if (discont) {
820       GST_LOG_OBJECT (emulenc, "DISCONT, clear adapter");
821       gst_adapter_clear (emulenc->adapter);
822       emulenc->discont = TRUE;
823     }
824
825     if (gst_adapter_available (emulenc->adapter) == 0) {
826       GST_LOG_OBJECT (emulenc, "taking buffer timestamp %" GST_TIME_FORMAT,
827         GST_TIME_ARGS (timestamp));
828       emulenc->adapter_ts = timestamp;
829       emulenc->adapter_consumed = 0;
830     } else {
831       GstClockTime upstream_time;
832       GstClockTime consumed_time;
833       guint64 bytes;
834
835       consumed_time =
836         gst_util_uint64_scale (emulenc->adapter_consumed, GST_SECOND,
837             ctx->audio.sample_rate);
838       timestamp = emulenc->adapter_ts + consumed_time;
839       GST_LOG_OBJECT (emulenc, "taking adapter timestamp %" GST_TIME_FORMAT
840         " and adding consumed time %" GST_TIME_FORMAT,
841         GST_TIME_ARGS (emulenc->adapter_ts), GST_TIME_ARGS (consumed_time));
842
843       upstream_time = gst_adapter_prev_timestamp (emulenc->adapter, &bytes);
844       if (GST_CLOCK_TIME_IS_VALID (upstream_time)) {
845         GstClockTimeDiff diff;
846
847         upstream_time +=
848           gst_util_uint64_scale (bytes, GST_SECOND,
849             ctx->audio.sample_rate * osize * ctx->audio.channels);
850         diff = upstream_time - timestamp;
851
852         if (diff > GST_SECOND / 10 || diff < -GST_SECOND / 10) {
853           GST_DEBUG_OBJECT (emulenc, "adapter timestamp drifting, "
854             "taking upstream timestamp %" GST_TIME_FORMAT,
855             GST_TIME_ARGS (upstream_time));
856           timestamp = upstream_time;
857
858           emulenc->adapter_consumed = bytes / (osize * ctx->audio.channels);
859           emulenc->adapter_ts =
860             upstream_time - gst_util_uint64_scale (emulenc->adapter_consumed,
861                 GST_SECOND, ctx->audio.sample_rate);
862           emulenc->discont = TRUE;
863         }
864       }
865     }
866
867     GST_LOG_OBJECT (emulenc, "pushing buffer in adapter");
868     gst_adapter_push (emulenc->adapter, buffer);
869
870     frame_bytes = frame_size * osize * ctx->audio.channels;
871     avail = gst_adapter_available (emulenc->adapter);
872
873     GST_LOG_OBJECT (emulenc, "frame_bytes %u, avail %u", frame_bytes, avail);
874
875     while (avail >= frame_bytes) {
876       GST_LOG_OBJECT (emulenc, "taking %u bytes from the adapter", frame_bytes);
877
878       in_data = (guint8 *) gst_adapter_peek (emulenc->adapter, frame_bytes);
879       emulenc->adapter_consumed += frame_size;
880
881       duration =
882         gst_util_uint64_scale (emulenc->adapter_consumed, GST_SECOND,
883           ctx->audio.sample_rate);
884       duration -= (timestamp - emulenc->adapter_ts);
885
886       out_size = frame_bytes * 4;
887
888       ret =
889         gst_emulenc_encode_audio (emulenc, in_data, frame_bytes, out_size,
890           timestamp, duration, emulenc->discont);
891
892       gst_adapter_flush (emulenc->adapter, frame_bytes);
893       if (ret != GST_FLOW_OK) {
894         GST_DEBUG_OBJECT (emulenc, "Failed to push buffer %d (%s)", ret,
895           gst_flow_get_name (ret));
896       }
897
898       timestamp += duration;
899
900       emulenc->discont = FALSE;
901       avail = gst_adapter_available (emulenc->adapter);
902     }
903     GST_LOG_OBJECT (emulenc, "%u bytes left in the adapter", avail);
904   } else {
905 #if 0
906     int coded_bps = av_get_bits_per_sample (oclass->codec->name);
907
908     GST_LOG_OBJECT (emulenc, "coded bps %d, osize %d", coded_bps, osize);
909
910     out_size = in_size / osize;
911     if (coded_bps) {
912       out_size = (out_size * coded_bps) / 8;
913     }
914 #endif
915     in_data = (guint8 *) GST_BUFFER_DATA (buffer);
916     ret = gst_emulenc_encode_audio (emulenc, in_data, in_size, out_size,
917       timestamp, duration, discont);
918     gst_buffer_unref (buffer);
919     if (ret != GST_FLOW_OK) {
920       GST_DEBUG_OBJECT (emulenc, "Failed to push buffer %d (%s)", ret,
921         gst_flow_get_name (ret));
922     }
923   }
924
925   return GST_FLOW_OK;
926 }
927
928 static void
929 gst_emulenc_flush_buffers (GstEmulEnc *emulenc, gboolean send)
930 {
931   GstBuffer *outbuf, *inbuf;
932   gint ret_size;
933
934   GST_DEBUG_OBJECT (emulenc, "flushing buffers with sending %d", send);
935
936
937   if (!emulenc->opened) {
938     while (!g_queue_is_empty (emulenc->delay)) {
939       gst_buffer_unref (g_queue_pop_head (emulenc->delay));
940     }
941   }
942
943 #if 0
944
945   while (!g_queue_is_empty (emulenc->delay)) {
946     emulenc_setup_working_buf (emulenc);
947
948     ret_size = emul_avcodec_encode_video (emulenc->context,
949       emulenc->working_buf, emulenc->working_buf_size, NULL, NULL, 0,
950       emulenc->dev);
951
952     if (ret_size < 0) {
953       GstEmulEncClass *oclass =
954         (GstEmulEncClass *) (G_OBJECT_GET_CLASS (emulenc));
955       GST_WARNING_OBJECT (emulenc,
956         "maru_%senc: failed to flush buffer", oclass->codec->name);
957       break;
958     }
959
960     if (emulenc->file && emulenc->context->stats_out) {
961       if (fprintf (emulenc->file, "%s", emulenc->context->stats_out) < 0) {
962         GST_ELEMENT_ERROR (emeulenc, RESOURCE, WRITE,
963           (("Could not write to file \"%s\"."), emulenc->filename),
964           GST_ERROR_SYSTEM);
965       }
966     }
967
968     inbuf = g_queue_pop_head (emulenc->delay);
969
970     outbuf = gst_buffer_new_and_alloc (ret_size);
971     memcpy (GST_BUFFER_DATA (outbuf), emulenc->working_buf, ret_size);
972     GST_BUFFER_TIMESTAMP (outbuf) = GST_BUFFER_TIMESTAMP (inbuf);
973     GST_BUFFER_DURATION (outbuf) = GST_BUFFER_DURATION (inbuf);
974
975     if (!emulenc->context->coded_frame->key_frame) {
976       GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DELTA_UNIT);
977     }
978     gst_buffer_set_caps (outbuf, GST_PAD_CAPS (emulenc->srcpad));
979
980     gst_buffer_unref (inbuf);
981
982     if (send) {
983       gst_pad_push (emulenc->srcpad, outbuf);
984     } else {
985       gst_buffer_unref (outbuf);
986     }
987   }
988
989   while (!g_queue_is_empty (emulenc->delay)) {
990     gst_buffer_unref (g_queue_pop_head (emulenc->delay));
991   }
992 #endif
993 }
994
995 static gboolean
996 gst_emulenc_event_video (GstPad *pad, GstEvent *event)
997 {
998   GstEmulEnc *emulenc;
999   emulenc = (GstEmulEnc *) gst_pad_get_parent (pad);
1000
1001   switch (GST_EVENT_TYPE (event)) {
1002   case GST_EVENT_EOS:
1003     gst_emulenc_flush_buffers (emulenc, TRUE);
1004     break;
1005   case GST_EVENT_CUSTOM_DOWNSTREAM:
1006   {
1007     const GstStructure *s;
1008     s = gst_event_get_structure (event);
1009
1010     if (gst_structure_has_name (s, "GstForceKeyUnit")) {
1011 #if 0
1012       emulenc->picture->pict_type = FF_I_TYPE;
1013 #endif
1014     }
1015   }
1016     break;
1017   default:
1018     break;
1019   }
1020
1021   return gst_pad_push_event (emulenc->srcpad, event);
1022 }
1023
1024 static gboolean
1025 gst_emulenc_event_src (GstPad *pad, GstEvent *event)
1026 {
1027   GstEmulEnc *emulenc = (GstEmulEnc *) (GST_PAD_PARENT (pad));
1028   gboolean forward = TRUE;
1029
1030   switch (GST_EVENT_TYPE (event)) {
1031   case GST_EVENT_CUSTOM_UPSTREAM:
1032   {
1033     const GstStructure *s;
1034     s = gst_event_get_structure (event);
1035
1036     if (gst_structure_has_name (s, "GstForceKeyUnit")) {
1037 #if 0
1038       GST_OBJECT_LOCK (emulenc);
1039       emulenc->force_keyframe = TRUE;
1040       GST_OBJECT_UNLOCK (emulenc);
1041 #endif
1042       forward = FALSE;
1043       gst_event_unref (event);
1044     }
1045   }
1046     break;
1047   default:
1048     break;
1049   }
1050
1051   if (forward) {
1052     return gst_pad_push_event (emulenc->sinkpad, event);
1053   }
1054
1055   return TRUE;
1056 }
1057
1058 GstStateChangeReturn
1059 gst_emulenc_change_state (GstElement *element, GstStateChange transition)
1060 {
1061   GstEmulEnc *emulenc = (GstEmulEnc*)element;
1062   GstStateChangeReturn ret;
1063
1064   switch (transition) {
1065   default:
1066     break;
1067   }
1068
1069   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
1070
1071   switch (transition) {
1072   case GST_STATE_CHANGE_PAUSED_TO_READY:
1073     gst_emulenc_flush_buffers (emulenc, FALSE);
1074     if (emulenc->opened) {
1075       gst_emul_avcodec_close (emulenc->context, emulenc->dev);
1076       emulenc->opened = FALSE;
1077     }
1078     gst_adapter_clear (emulenc->adapter);
1079
1080 #if 0
1081     if (emulenc->flie) {
1082       fclose (emulenc->file);
1083       emulenc->file = NULL;
1084     }
1085 #endif
1086
1087     if (emulenc->working_buf) {
1088       g_free (emulenc->working_buf);
1089       emulenc->working_buf = NULL;
1090     }
1091     break;
1092   default:
1093     break;
1094   }
1095
1096   return ret;
1097 }
1098
1099 gboolean
1100 gst_emulenc_register (GstPlugin *plugin, GList *element)
1101 {
1102   GTypeInfo typeinfo = {
1103       sizeof (GstEmulEncClass),
1104       (GBaseInitFunc) gst_emulenc_base_init,
1105       NULL,
1106       (GClassInitFunc) gst_emulenc_class_init,
1107       NULL,
1108       NULL,
1109       sizeof (GstEmulEnc),
1110       0,
1111       (GInstanceInitFunc) gst_emulenc_init,
1112   };
1113
1114   GType type;
1115   gchar *type_name;
1116   gint rank = GST_RANK_NONE;
1117   GList *elem = element;
1118   CodecElement *codec = NULL;
1119
1120   if (!elem) {
1121           return FALSE;
1122   }
1123
1124   /* register element */
1125   do {
1126     codec = (CodecElement *)(elem->data);
1127     if (!codec) {
1128       return FALSE;
1129       break;
1130     }
1131
1132     if (codec->codec_type != CODEC_TYPE_ENCODE) {
1133       continue;
1134     }
1135
1136     type_name = g_strdup_printf ("maru_%senc", codec->name);
1137     type = g_type_from_name (type_name);
1138     if (!type) {
1139       type = g_type_register_static (GST_TYPE_ELEMENT, type_name, &typeinfo, 0);
1140       g_type_set_qdata (type, GST_EMULENC_PARAMS_QDATA, (gpointer) codec);
1141     }
1142
1143     if (!gst_element_register (plugin, type_name, rank, type)) {
1144       g_free (type_name);
1145       return FALSE;
1146     }
1147     g_free (type_name);
1148   } while ((elem = g_list_next (elem)));
1149
1150   return TRUE;
1151 }