2 * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
3 * Copyright (C) 2013 Samsung Electronics Co., Ltd.
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
15 * You should have received a copy of the GNU Library General Public
16 * License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 * Boston, MA 02111-1307, USA.
21 /* Modifications by Samsung Electronics Co., Ltd.
22 * 1. Provide a hardware buffer in order to avoid additional memcpy operations.
25 #include "gstmarudevice.h"
26 #include "gstmaruutils.h"
27 #include "gstmaruinterface.h"
29 #define GST_MARUDEC_PARAMS_QDATA g_quark_from_static_string("marudec-params")
31 /* indicate dts, pts, offset in the stream */
32 #define GST_TS_INFO_NONE &ts_info_none
33 static const GstTSInfo ts_info_none = { -1, -1, -1, -1 };
35 typedef struct _GstMaruVidDecClass
37 GstVideoDecoderClass parent_class;
42 typedef struct _GstMaruDecClass
44 GstElementClass parent_class;
47 GstPadTemplate *sinktempl;
48 GstPadTemplate *srctempl;
52 static GstElementClass *parent_class = NULL;
54 static void gst_maruviddec_base_init (GstMaruVidDecClass *klass);
55 static void gst_maruviddec_class_init (GstMaruVidDecClass *klass);
56 static void gst_maruviddec_init (GstMaruVidDec *marudec);
57 static void gst_maruviddec_finalize (GObject *object);
59 static gboolean gst_marudec_set_format (GstVideoDecoder * decoder, GstVideoCodecState * state);
60 static GstFlowReturn gst_maruviddec_handle_frame (GstVideoDecoder * decoder, GstVideoCodecFrame * frame);
61 static gboolean gst_marudec_negotiate (GstMaruVidDec *dec, gboolean force);
62 static gint gst_maruviddec_frame (GstMaruVidDec *marudec, guint8 *data, guint size, gint *got_data,
63 const GstTSInfo *dec_info, gint64 in_offset, GstVideoCodecFrame * frame, GstFlowReturn *ret);
65 static gboolean gst_marudec_open (GstMaruVidDec *marudec);
66 static gboolean gst_marudec_close (GstMaruVidDec *marudec);
68 GstFlowReturn alloc_and_copy (GstMaruVidDec *marudec, guint64 offset, guint size,
69 GstCaps *caps, GstBuffer **buf);
72 static GTimer* profile_decode_timer = NULL;
73 static gdouble elapsed_decode_time = 0;
74 static int decoded_frame_cnt = 0;
75 static int last_frame_cnt = 0;
76 static GMutex profile_mutex;
77 static int profile_init = 0;
80 maru_profile_cb (gpointer user_data)
82 GST_DEBUG (" >> ENTER ");
84 gdouble decoding_time = 0;
86 g_mutex_lock (&profile_mutex);
87 if (decoded_frame_cnt < 0) {
88 decoded_frame_cnt = 0;
90 elapsed_decode_time = 0;
91 g_mutex_unlock (&profile_mutex);
95 decoding_fps = decoded_frame_cnt - last_frame_cnt;
96 last_frame_cnt = decoded_frame_cnt;
98 decoding_time = elapsed_decode_time;
99 elapsed_decode_time = 0;
100 g_mutex_unlock (&profile_mutex);
102 GST_DEBUG ("decoding fps=%d, latency=%f\n", decoding_fps, decoding_time/decoding_fps);
106 static void init_codec_profile(void)
108 GST_DEBUG (" >> ENTER ");
111 profile_decode_timer = g_timer_new();
115 static void reset_codec_profile(void)
117 GST_DEBUG (" >> ENTER ");
118 g_mutex_lock (&profile_mutex);
119 decoded_frame_cnt = -1;
120 g_mutex_lock (&profile_mutex);
123 static void begin_video_decode_profile(void)
125 GST_DEBUG (" >> ENTER ");
126 g_timer_start(profile_decode_timer);
129 static void end_video_decode_profile(void)
131 GST_DEBUG (" >> ENTER ");
132 g_timer_stop(profile_decode_timer);
134 g_mutex_lock (&profile_mutex);
135 if (decoded_frame_cnt == 0) {
136 g_timeout_add_seconds(1, maru_profile_cb, NULL);
139 elapsed_decode_time += g_timer_elapsed(profile_decode_timer, NULL);
141 g_mutex_unlock (&profile_mutex);
144 #define INIT_CODEC_PROFILE(fd) \
145 if (interface->get_profile_status(fd)) { \
146 init_codec_profile(); \
148 #define RESET_CODEC_PROFILE(s) \
149 if (profile_init) { \
150 reset_codec_profile(); \
152 #define BEGIN_VIDEO_DECODE_PROFILE() \
153 if (profile_init) { \
154 begin_video_decode_profile(); \
156 #define END_VIDEO_DECODE_PROFILE() \
157 if (profile_init) { \
158 end_video_decode_profile(); \
162 static const GstTSInfo *
163 gst_ts_info_store (GstMaruVidDec *dec, GstClockTime timestamp,
164 GstClockTime duration, gint64 offset)
166 GST_DEBUG (" >> ENTER ");
167 gint idx = dec->ts_idx;
168 dec->ts_info[idx].idx = idx;
169 dec->ts_info[idx].timestamp = timestamp;
170 dec->ts_info[idx].duration = duration;
171 dec->ts_info[idx].offset = offset;
172 dec->ts_idx = (idx + 1) & MAX_TS_MASK;
174 return &dec->ts_info[idx];
177 static const GstTSInfo *
178 gst_ts_info_get (GstMaruVidDec *dec, gint idx)
180 GST_DEBUG (" >> ENTER ");
181 if (G_UNLIKELY (idx < 0 || idx > MAX_TS_MASK)){
182 GST_DEBUG (" >> LEAVE 0");
183 return GST_TS_INFO_NONE;
186 GST_DEBUG (" >> LEAVE ");
187 return &dec->ts_info[idx];
191 gst_marudec_reset_ts (GstMaruVidDec *marudec)
193 GST_DEBUG (" >> ENTER ");
194 marudec->next_out = GST_CLOCK_TIME_NONE;
198 gst_marudec_do_qos (GstMaruVidDec *marudec, GstVideoCodecFrame * frame,
199 GstClockTime timestamp, gboolean *mode_switch)
201 GST_DEBUG (" >> ENTER ");
202 GstClockTimeDiff diff;
204 *mode_switch = FALSE;
206 if (G_UNLIKELY (frame == NULL)) {
207 marudec->processed++;
208 GST_DEBUG (" >> LEAVE ");
212 diff = gst_video_decoder_get_max_decode_time (GST_VIDEO_DECODER (marudec), frame);
213 /* if we don't have timing info, then we don't do QoS */
214 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (diff))) {
215 marudec->processed++;
216 GST_DEBUG (" >> LEAVE ");
221 marudec->processed++;
222 GST_DEBUG (" >> LEAVE ");
223 } else if (diff <= 0) {
224 GST_DEBUG (" >> LEAVE ");
229 gst_marudec_drain (GstMaruVidDec *marudec)
231 GST_DEBUG (" >> ENTER ");
232 GST_DEBUG_OBJECT (marudec, "drain frame");
235 gint have_data, len, try = 0;
241 gst_maruviddec_frame (marudec, NULL, 0, &have_data, &ts_info_none, 0, NULL, &ret);
243 if (len < 0 || have_data == 0) {
246 } while (try++ < 10);
254 gst_maruviddec_base_init (GstMaruVidDecClass *klass)
256 GST_DEBUG (" >> ENTER ");
257 GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
258 GstPadTemplate *sinktempl, *srctempl;
259 GstCaps *sinkcaps, *srccaps;
261 gchar *longname, *description;
264 (CodecElement *)g_type_get_qdata (G_OBJECT_CLASS_TYPE (klass),
265 GST_MARUDEC_PARAMS_QDATA);
266 g_assert (codec != NULL);
268 longname = g_strdup_printf ("%s Decoder long", codec->longname);
269 description = g_strdup_printf("%s Decoder desc", codec->name);
271 gst_element_class_set_metadata (element_class,
273 "Codec/Decoder/Video sims",
275 "Sooyoung Ha <yoosah.ha@samsung.com>");
278 g_free (description);
281 sinkcaps = gst_maru_codecname_to_caps (codec->name, NULL, FALSE);
283 sinkcaps = gst_caps_new_empty_simple ("unknown/unknown");
286 srccaps = gst_maru_codectype_to_video_caps (NULL, codec->name, FALSE, codec);
289 srccaps = gst_caps_from_string ("video/x-raw");
293 sinktempl = gst_pad_template_new ("sink", GST_PAD_SINK,
294 GST_PAD_ALWAYS, sinkcaps);
295 srctempl = gst_pad_template_new ("src", GST_PAD_SRC,
296 GST_PAD_ALWAYS, srccaps);
298 gst_element_class_add_pad_template (element_class, srctempl);
299 gst_element_class_add_pad_template (element_class, sinktempl);
301 klass->codec = codec;
305 gst_maruviddec_class_init (GstMaruVidDecClass *klass)
307 GST_DEBUG (" >> ENTER ");
308 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
309 GstVideoDecoderClass *viddec_class = GST_VIDEO_DECODER_CLASS (klass);
311 parent_class = g_type_class_peek_parent (klass);
313 gobject_class->finalize = gst_maruviddec_finalize;
315 /* use these function when defines new properties.
316 gobject_class->set_property = gst_marudec_set_property
317 gobject_class->get_property = gst_marudec_get_property
320 viddec_class->set_format = gst_marudec_set_format;
321 viddec_class->handle_frame = gst_maruviddec_handle_frame;
325 gst_maruviddec_init (GstMaruVidDec *marudec)
327 GST_DEBUG (" >> ENTER ");
328 marudec->context = g_malloc0 (sizeof(CodecContext));
329 marudec->context->video.pix_fmt = PIX_FMT_NONE;
330 marudec->context->audio.sample_fmt = SAMPLE_FMT_NONE;
332 marudec->opened = FALSE;
336 gst_maruviddec_finalize (GObject *object)
338 GST_DEBUG (" >> ENTER ");
339 GstMaruVidDec *marudec = (GstMaruVidDec *) object;
341 GST_DEBUG_OBJECT (marudec, "finalize object and release context");
342 g_free (marudec->context);
343 marudec->context = NULL;
345 G_OBJECT_CLASS (parent_class)->finalize (object);
349 gst_marudec_set_format (GstVideoDecoder * decoder, GstVideoCodecState * state)
351 GST_DEBUG (" >> ENTER ");
352 GstMaruVidDec *marudec;
353 GstMaruVidDecClass *oclass;
354 gboolean ret = FALSE;
356 marudec = (GstMaruVidDec *) decoder;
357 oclass = (GstMaruVidDecClass *) (G_OBJECT_GET_CLASS (marudec));
359 GST_ERROR ("invalid marudec");
362 if (marudec->last_caps != NULL &&
363 gst_caps_is_equal (marudec->last_caps, state->caps)) {
367 GST_DEBUG_OBJECT (marudec, "setcaps called.");
369 GST_OBJECT_LOCK (marudec);
371 /* stupid check for VC1 */
372 if (!strcmp(oclass->codec->name, "wmv3") ||
373 !strcmp(oclass->codec->name, "vc1")) {
374 gst_maru_caps_to_codecname (state->caps, oclass->codec->name, NULL);
377 /* close old session */
378 if (marudec->opened) {
379 GST_OBJECT_UNLOCK (marudec);
380 gst_marudec_drain (marudec);
381 GST_OBJECT_LOCK (marudec);
382 if (!gst_marudec_close (marudec)) {
383 GST_OBJECT_UNLOCK (marudec);
388 gst_caps_replace (&marudec->last_caps, state->caps);
390 GST_LOG_OBJECT (marudec, "size %dx%d", marudec->context->video.width,
391 marudec->context->video.height);
393 gst_maru_caps_with_codecname (oclass->codec->name, oclass->codec->media_type,
394 state->caps, marudec->context);
396 GST_LOG_OBJECT (marudec, "size after %dx%d", marudec->context->video.width,
397 marudec->context->video.height);
399 if (!marudec->context->video.fps_d || !marudec->context->video.fps_n) {
400 GST_DEBUG_OBJECT (marudec, "forcing 25/1 framerate");
401 marudec->context->video.fps_n = 1;
402 marudec->context->video.fps_d = 25;
408 query = gst_query_new_latency ();
410 /* Check if upstream is live. If it isn't we can enable frame based
411 * threading, which is adding latency */
412 if (gst_pad_peer_query (GST_VIDEO_DECODER_SINK_PAD (marudec), query)) {
413 gst_query_parse_latency (query, &is_live, NULL, NULL);
415 gst_query_unref (query);
417 if (!gst_marudec_open (marudec)) {
418 GST_DEBUG_OBJECT (marudec, "Failed to open");
424 if (marudec->input_state) {
425 gst_video_codec_state_unref (marudec->input_state);
427 marudec->input_state = gst_video_codec_state_ref (state);
429 if (marudec->input_state->info.fps_n) {
430 GstVideoInfo *info = &marudec->input_state->info;
431 gst_util_uint64_scale_ceil (GST_SECOND, info->fps_d, info->fps_n);
433 GST_OBJECT_UNLOCK (marudec);
439 gst_marudec_open (GstMaruVidDec *marudec)
441 GST_DEBUG (" >> ENTER ");
442 GstMaruVidDecClass *oclass;
444 oclass = (GstMaruVidDecClass *) (G_OBJECT_GET_CLASS (marudec));
446 marudec->dev = g_try_malloc0 (sizeof(CodecDevice));
448 GST_ERROR_OBJECT (marudec, "failed to allocate memory for CodecDevice");
452 if (gst_maru_avcodec_open (marudec->context, oclass->codec, marudec->dev) < 0) {
453 g_free(marudec->dev);
455 GST_ERROR_OBJECT (marudec,
456 "maru_%sdec: Failed to open codec", oclass->codec->name);
460 marudec->opened = TRUE;
462 GST_LOG_OBJECT (marudec, "Opened codec %s", oclass->codec->name);
464 gst_marudec_reset_ts (marudec);
466 // initialize profile resource
467 INIT_CODEC_PROFILE(marudec->dev->fd);
473 gst_marudec_close (GstMaruVidDec *marudec)
475 GST_DEBUG (" >> ENTER ");
476 if (!marudec->opened) {
477 GST_DEBUG_OBJECT (marudec, "not opened yet");
481 if (marudec->context) {
482 g_free(marudec->context->codecdata);
483 marudec->context->codecdata = NULL;
490 gst_maru_avcodec_close (marudec->context, marudec->dev);
491 marudec->opened = FALSE;
494 g_free(marudec->dev);
498 // reset profile resource
499 RESET_CODEC_PROFILE();
504 update_video_context (GstMaruVidDec * marudec, CodecContext * context,
507 GST_DEBUG (" >> ENTER ");
508 if (!force && marudec->ctx_width == context->video.width
509 && marudec->ctx_height == context->video.height
510 && marudec->ctx_ticks == context->video.ticks_per_frame
511 && marudec->ctx_time_n == context->video.fps_n
512 && marudec->ctx_time_d == context->video.fps_d
513 && marudec->ctx_pix_fmt == context->video.pix_fmt
514 && marudec->ctx_par_n == context->video.par_n
515 && marudec->ctx_par_d == context->video.par_d) {
518 marudec->ctx_width = context->video.width;
519 marudec->ctx_height = context->video.height;
520 marudec->ctx_ticks = context->video.ticks_per_frame;
521 marudec->ctx_time_n = context->video.fps_n;
522 marudec->ctx_time_d = context->video.fps_d;
523 marudec->ctx_pix_fmt = context->video.pix_fmt;
524 marudec->ctx_par_n = context->video.par_n;
525 marudec->ctx_par_d = context->video.par_d;
531 gst_maruviddec_update_par (GstMaruVidDec * marudec,
532 GstVideoInfo * in_info, GstVideoInfo * out_info)
534 GST_DEBUG (" >> ENTER");
535 gboolean demuxer_par_set = FALSE;
536 gboolean decoder_par_set = FALSE;
537 gint demuxer_num = 1, demuxer_denom = 1;
538 gint decoder_num = 1, decoder_denom = 1;
540 if (in_info->par_n && in_info->par_d) {
541 demuxer_num = in_info->par_n;
542 demuxer_denom = in_info->par_d;
543 demuxer_par_set = TRUE;
544 GST_DEBUG_OBJECT (marudec, "Demuxer PAR: %d:%d", demuxer_num,
548 if (marudec->ctx_par_n && marudec->ctx_par_d) {
549 decoder_num = marudec->ctx_par_n;
550 decoder_denom = marudec->ctx_par_d;
551 decoder_par_set = TRUE;
552 GST_DEBUG_OBJECT (marudec, "Decoder PAR: %d:%d", decoder_num,
556 if (!demuxer_par_set && !decoder_par_set)
559 if (demuxer_par_set && !decoder_par_set)
560 goto use_demuxer_par;
562 if (decoder_par_set && !demuxer_par_set)
563 goto use_decoder_par;
565 /* Both the demuxer and the decoder provide a PAR. If one of
566 * the two PARs is 1:1 and the other one is not, use the one
567 * that is not 1:1. */
568 if (demuxer_num == demuxer_denom && decoder_num != decoder_denom)
569 goto use_decoder_par;
571 if (decoder_num == decoder_denom && demuxer_num != demuxer_denom)
572 goto use_demuxer_par;
574 /* Both PARs are non-1:1, so use the PAR provided by the demuxer */
575 goto use_demuxer_par;
579 GST_DEBUG_OBJECT (marudec,
580 "Setting decoder provided pixel-aspect-ratio of %u:%u", decoder_num,
582 out_info->par_n = decoder_num;
583 out_info->par_d = decoder_denom;
588 GST_DEBUG_OBJECT (marudec,
589 "Setting demuxer provided pixel-aspect-ratio of %u:%u", demuxer_num,
591 out_info->par_n = demuxer_num;
592 out_info->par_d = demuxer_denom;
597 GST_DEBUG_OBJECT (marudec,
598 "Neither demuxer nor codec provide a pixel-aspect-ratio");
607 gst_marudec_negotiate (GstMaruVidDec *marudec, gboolean force)
609 GST_DEBUG (" >> ENTER ");
610 CodecContext *context = marudec->context;
612 GstVideoInfo *in_info, *out_info;
613 GstVideoCodecState *output_state;
616 if (!update_video_context (marudec, context, force))
619 fmt = gst_maru_pixfmt_to_videoformat (marudec->ctx_pix_fmt);
620 if (G_UNLIKELY (fmt == GST_VIDEO_FORMAT_UNKNOWN))
624 gst_video_decoder_set_output_state (GST_VIDEO_DECODER (marudec), fmt,
625 marudec->ctx_width, marudec->ctx_height, marudec->input_state);
626 if (marudec->output_state)
627 gst_video_codec_state_unref (marudec->output_state);
628 marudec->output_state = output_state;
630 in_info = &marudec->input_state->info;
631 out_info = &marudec->output_state->info;
632 out_info->interlace_mode = GST_VIDEO_INTERLACE_MODE_MIXED;
634 /* try to find a good framerate */
635 if ((in_info->fps_d && in_info->fps_n) ||
636 GST_VIDEO_INFO_FLAG_IS_SET (in_info, GST_VIDEO_FLAG_VARIABLE_FPS)) {
637 /* take framerate from input when it was specified (#313970) */
638 fps_n = in_info->fps_n;
639 fps_d = in_info->fps_d;
641 fps_n = marudec->ctx_time_d / marudec->ctx_ticks;
642 fps_d = marudec->ctx_time_n;
645 GST_LOG_OBJECT (marudec, "invalid framerate: %d/0, -> %d/1", fps_n,
649 if (gst_util_fraction_compare (fps_n, fps_d, 1000, 1) > 0) {
650 GST_LOG_OBJECT (marudec, "excessive framerate: %d/%d, -> 0/1", fps_n,
656 GST_LOG_OBJECT (marudec, "setting framerate: %d/%d", fps_n, fps_d);
657 out_info->fps_n = fps_n;
658 out_info->fps_d = fps_d;
660 /* calculate and update par now */
661 gst_maruviddec_update_par (marudec, in_info, out_info);
663 if (!gst_video_decoder_negotiate (GST_VIDEO_DECODER (marudec)))
664 goto negotiate_failed;
671 GST_ERROR_OBJECT (marudec,
672 "decoder requires a video format unsupported by GStreamer");
677 /* Reset so we try again next time even if force==FALSE */
678 marudec->ctx_width = 0;
679 marudec->ctx_height = 0;
680 marudec->ctx_ticks = 0;
681 marudec->ctx_time_n = 0;
682 marudec->ctx_time_d = 0;
683 marudec->ctx_pix_fmt = 0;
684 marudec->ctx_par_n = 0;
685 marudec->ctx_par_d = 0;
687 GST_ERROR_OBJECT (marudec, "negotiation failed");
693 get_output_buffer (GstMaruVidDec *marudec, GstVideoCodecFrame * frame)
695 GST_DEBUG (" >> ENTER ");
697 GstFlowReturn ret = GST_FLOW_OK;
699 if (G_UNLIKELY (!gst_marudec_negotiate (marudec, FALSE))) {
700 GST_DEBUG_OBJECT (marudec, "negotiate failed");
701 return GST_FLOW_NOT_NEGOTIATED;
703 pict_size = gst_maru_avpicture_size (marudec->context->video.pix_fmt,
704 marudec->context->video.width, marudec->context->video.height);
706 GST_DEBUG_OBJECT (marudec, "size of a picture is negative. "
707 "pixel format: %d, width: %d, height: %d",
708 marudec->context->video.pix_fmt, marudec->context->video.width,
709 marudec->context->video.height);
710 return GST_FLOW_ERROR;
713 GST_DEBUG_OBJECT (marudec, "outbuf size of decoded video %d", pict_size);
715 ret = gst_video_decoder_allocate_output_frame (GST_VIDEO_DECODER (marudec), frame);
717 alloc_and_copy(marudec, 0, pict_size, NULL, &(frame->output_buffer));
719 if (G_UNLIKELY (ret != GST_FLOW_OK)) {
720 GST_ERROR ("alloc output buffer failed");
727 gst_maruviddec_video_frame (GstMaruVidDec *marudec, guint8 *data, guint size,
728 const GstTSInfo *dec_info, gint64 in_offset,
729 GstVideoCodecFrame * frame, GstFlowReturn *ret)
731 GST_DEBUG (" >> ENTER ");
733 gboolean mode_switch;
734 GstClockTime out_timestamp, out_duration, out_pts;
736 const GstTSInfo *out_info;
739 /* run QoS code, we don't stop decoding the frame when we are late because
740 * else we might skip a reference frame */
741 gst_marudec_do_qos (marudec, frame, dec_info->timestamp, &mode_switch);
743 GST_DEBUG_OBJECT (marudec, "decode video: input buffer size %d", size);
745 // begin video decode profile
746 BEGIN_VIDEO_DECODE_PROFILE();
748 len = interface->decode_video (marudec, data, size,
749 dec_info->idx, in_offset, NULL, &have_data);
750 if (len < 0 || !have_data) {
751 GST_ERROR ("decode video failed, len = %d", len);
755 // end video decode profile
756 END_VIDEO_DECODE_PROFILE();
758 *ret = get_output_buffer (marudec, frame);
759 if (G_UNLIKELY (*ret != GST_FLOW_OK)) {
760 GST_DEBUG_OBJECT (marudec, "no output buffer");
762 GST_DEBUG_OBJECT (marudec, "return flow %d, out %p, len %d",
763 *ret, (void *) (frame->output_buffer), len);
767 out_info = gst_ts_info_get (marudec, dec_info->idx);
768 out_pts = out_info->timestamp;
769 out_duration = out_info->duration;
770 out_offset = out_info->offset;
775 out_timestamp = (GstClockTime) out_pts;
776 GST_LOG_OBJECT (marudec, "using timestamp %" GST_TIME_FORMAT
777 " returned by ffmpeg", GST_TIME_ARGS (out_timestamp));
780 if (!GST_CLOCK_TIME_IS_VALID (out_timestamp) && marudec->next_out != -1) {
781 out_timestamp = marudec->next_out;
782 GST_LOG_OBJECT (marudec, "using next timestamp %" GST_TIME_FORMAT,
783 GST_TIME_ARGS (out_timestamp));
786 if (!GST_CLOCK_TIME_IS_VALID (out_timestamp)) {
787 out_timestamp = dec_info->timestamp;
788 GST_LOG_OBJECT (marudec, "using in timestamp %" GST_TIME_FORMAT,
789 GST_TIME_ARGS (out_timestamp));
791 GST_BUFFER_TIMESTAMP (frame->output_buffer) = out_timestamp;
794 if (out_offset != GST_BUFFER_OFFSET_NONE) {
795 GST_LOG_OBJECT (marudec, "Using offset returned by ffmpeg");
796 } else if (out_timestamp != GST_CLOCK_TIME_NONE) {
797 /* TODO: check this is needed.
798 GstFormat out_fmt = GST_FORMAT_DEFAULT;
799 GST_LOG_OBJECT (marudec, "Using offset converted from timestamp");
801 gst_pad_query_peer_convert (marudec->sinkpad,
802 GST_FORMAT_TIME, out_timestamp, &out_fmt, &out_offset);
804 } else if (dec_info->offset != GST_BUFFER_OFFSET_NONE) {
805 GST_LOG_OBJECT (marudec, "using in_offset %" G_GINT64_FORMAT,
807 out_offset = dec_info->offset;
809 GST_LOG_OBJECT (marudec, "no valid offset found");
810 out_offset = GST_BUFFER_OFFSET_NONE;
812 GST_BUFFER_OFFSET (frame->output_buffer) = out_offset;
815 if (GST_CLOCK_TIME_IS_VALID (out_duration)) {
816 GST_LOG_OBJECT (marudec, "Using duration returned by ffmpeg");
817 } else if (GST_CLOCK_TIME_IS_VALID (dec_info->duration)) {
818 GST_LOG_OBJECT (marudec, "Using in_duration");
819 out_duration = dec_info->duration;
821 if (marudec->ctx_time_n != -1 &&
822 (marudec->ctx_time_n != 1000 &&
823 marudec->ctx_time_d != 1)) {
824 GST_LOG_OBJECT (marudec, "using input framerate for duration");
825 out_duration = gst_util_uint64_scale_int (GST_SECOND,
826 marudec->ctx_time_d, marudec->ctx_time_n);
828 if (marudec->context->video.fps_n != 0 &&
829 (marudec->context->video.fps_d > 0 &&
830 marudec->context->video.fps_d < 1000)) {
831 GST_LOG_OBJECT (marudec, "using decoder's framerate for duration");
832 out_duration = gst_util_uint64_scale_int (GST_SECOND,
833 marudec->context->video.fps_n * 1,
834 marudec->context->video.fps_d);
836 GST_LOG_OBJECT (marudec, "no valid duration found");
841 GST_DEBUG_OBJECT (marudec, "return flow %d, out %p, len %d",
842 *ret, (void *) (frame->output_buffer), len);
844 *ret = gst_video_decoder_finish_frame (GST_VIDEO_DECODER (marudec), frame);
850 gst_maruviddec_frame (GstMaruVidDec *marudec, guint8 *data, guint size,
851 gint *got_data, const GstTSInfo *dec_info, gint64 in_offset,
852 GstVideoCodecFrame * frame, GstFlowReturn *ret)
854 GST_DEBUG (" >> ENTER ");
855 GstMaruVidDecClass *oclass;
856 gint have_data = 0, len = 0;
858 if (G_UNLIKELY (marudec->context->codec == NULL)) {
859 GST_ERROR_OBJECT (marudec, "no codec context");
862 GST_LOG_OBJECT (marudec, "data:%p, size:%d", data, size);
865 oclass = (GstMaruVidDecClass *) (G_OBJECT_GET_CLASS (marudec));
867 switch (oclass->codec->media_type) {
868 case AVMEDIA_TYPE_VIDEO:
869 len = gst_maruviddec_video_frame (marudec, data, size,
870 dec_info, in_offset, frame, ret);
873 GST_ERROR_OBJECT (marudec, "Asked to decode non-audio/video frame!");
874 g_assert_not_reached ();
878 if (frame && frame->output_buffer) {
882 if (len < 0 || have_data < 0) {
883 GST_WARNING_OBJECT (marudec,
884 "maru_%sdec: decoding error (len: %d, have_data: %d)",
885 oclass->codec->name, len, have_data);
888 } else if (len == 0 && have_data == 0) {
899 gst_maruviddec_handle_frame (GstVideoDecoder * decoder, GstVideoCodecFrame * frame)
901 GST_DEBUG (" >> ENTER ");
902 GstMaruVidDec *marudec = (GstMaruVidDec *) decoder;
905 GstFlowReturn ret = GST_FLOW_OK;
909 GstClockTime in_timestamp;
910 GstClockTime in_duration;
912 const GstTSInfo *in_info;
913 const GstTSInfo *dec_info;
915 if (!gst_buffer_map (frame->input_buffer, &mapinfo, GST_MAP_READ)) {
916 GST_ERROR_OBJECT (marudec, "Failed to map buffer");
917 return GST_FLOW_ERROR;
920 in_timestamp = GST_BUFFER_TIMESTAMP (frame->input_buffer);
921 in_duration = GST_BUFFER_DURATION (frame->input_buffer);
922 in_offset = GST_BUFFER_OFFSET (frame->input_buffer);
924 in_info = gst_ts_info_store (marudec, in_timestamp, in_duration, in_offset);
925 GST_LOG_OBJECT (marudec,
926 "Received new data of size %zu, offset: %" G_GUINT64_FORMAT ", ts:%"
927 GST_TIME_FORMAT ", dur: %" GST_TIME_FORMAT ", info %d",
928 mapinfo.size, GST_BUFFER_OFFSET (frame->input_buffer),
929 GST_TIME_ARGS (in_timestamp), GST_TIME_ARGS (in_duration), in_info->idx);
931 in_size = mapinfo.size;
932 in_buf = (guint8 *) mapinfo.data;
936 gst_buffer_unmap (frame->input_buffer, &mapinfo);
938 gst_maruviddec_frame (marudec, in_buf, in_size, &have_data, dec_info, in_offset, frame, &ret);
944 gst_maruviddec_register (GstPlugin *plugin, GList *element)
946 GTypeInfo typeinfo = {
947 sizeof (GstMaruVidDecClass),
948 (GBaseInitFunc) gst_maruviddec_base_init,
950 (GClassInitFunc) gst_maruviddec_class_init,
953 sizeof (GstMaruVidDec),
955 (GInstanceInitFunc) gst_maruviddec_init,
960 gint rank = GST_RANK_PRIMARY;
961 GList *elem = element;
962 CodecElement *codec = NULL;
968 /* register element */
970 codec = (CodecElement *)(elem->data);
975 if (codec->codec_type != CODEC_TYPE_DECODE || codec->media_type != AVMEDIA_TYPE_VIDEO) {
979 type_name = g_strdup_printf ("maru_%sdec", codec->name);
980 type = g_type_from_name (type_name);
982 type = g_type_register_static (GST_TYPE_VIDEO_DECODER, type_name, &typeinfo, 0);
983 g_type_set_qdata (type, GST_MARUDEC_PARAMS_QDATA, (gpointer) codec);
986 if (!gst_element_register (plugin, type_name, rank, type)) {
991 } while ((elem = elem->next));