// misc
#define OFFSET_PICTURE_BUFFER (0x100)
+// for profile
+#include <glib.h>
+
+static GTimer* profile_decode_timer = NULL;
+static GTimer* profile_copy_timer = NULL;
+static gdouble elapsed_decode_time = 0;
+static gdouble elapsed_copying_time = 0;
+static int decoded_frame_cnt = 0;
+static int last_frame_cnt = 0;
+static QemuMutex profile_mutex;
+static int profile_init = 0;
+
+static gboolean
+maru_profile_cb (gpointer user_data)
+{
+ int decoding_fps = 0;
+ gdouble decoding_time = 0;
+ gdouble copying_time = 0;
+ gdouble total_latency_time = 0;
+
+ qemu_mutex_lock(&profile_mutex);
+ if (decoded_frame_cnt < 0) {
+ decoded_frame_cnt = 0;
+ last_frame_cnt = 0;
+ elapsed_decode_time = 0;
+ elapsed_copying_time = 0;
+ qemu_mutex_unlock(&profile_mutex);
+ return FALSE;
+ }
+
+ decoding_fps = decoded_frame_cnt - last_frame_cnt;
+ last_frame_cnt = decoded_frame_cnt;
+
+ decoding_time = elapsed_decode_time;
+ copying_time = elapsed_copying_time;
+ elapsed_decode_time = 0;
+ elapsed_copying_time = 0;
+ qemu_mutex_unlock(&profile_mutex);
+
+ total_latency_time = decoding_time + copying_time;
+ INFO("decoding fps=%d, latency=%f(decode=%f + get_picture=%f)\n",
+ decoding_fps, total_latency_time/decoding_fps,
+ decoding_time/decoding_fps, copying_time/decoding_fps);
+
+ return TRUE;
+}
+
+static void init_codec_profile(void)
+{
+ if (!profile_init) {
+ profile_init = 1;
+ qemu_mutex_init(&profile_mutex);
+ profile_decode_timer = g_timer_new();
+ profile_copy_timer = g_timer_new();
+ }
+}
+
+static void reset_codec_profile(void)
+{
+ qemu_mutex_lock(&profile_mutex);
+ decoded_frame_cnt = -1;
+ qemu_mutex_unlock(&profile_mutex);
+}
+
+static void begin_video_decode_profile(void)
+{
+ g_timer_start(profile_decode_timer);
+}
+
+static void begin_video_copy_profile(void)
+{
+ g_timer_start(profile_copy_timer);
+}
+
+static void end_video_decode_profile(void)
+{
+ g_timer_stop(profile_decode_timer);
+
+ qemu_mutex_lock(&profile_mutex);
+ if (decoded_frame_cnt == 0) {
+ g_timeout_add_seconds(1, maru_profile_cb, NULL);
+ }
+
+ elapsed_decode_time += g_timer_elapsed(profile_decode_timer, NULL);
+ decoded_frame_cnt++;
+ qemu_mutex_unlock(&profile_mutex);
+}
+
+static void end_video_copy_profile(void)
+{
+ g_timer_stop(profile_copy_timer);
+
+ qemu_mutex_lock(&profile_mutex);
+ elapsed_copying_time += g_timer_elapsed(profile_copy_timer, NULL);
+ qemu_mutex_unlock(&profile_mutex);
+}
+
+#define INIT_CODEC_PROFILE(s) \
+ if ((s)->profile) { \
+ init_codec_profile(); \
+ }
+#define RESET_CODEC_PROFILE() \
+ if (profile_init) { \
+ reset_codec_profile(); \
+ }
+#define BEGIN_VIDEO_DECODE_PROFILE() \
+ if (profile_init) { \
+ begin_video_decode_profile(); \
+ }
+#define END_VIDEO_DECODE_PROFILE() \
+ if (profile_init) { \
+ end_video_decode_profile(); \
+ }
+#define BEGIN_VIDEO_COPY_PROFILE() \
+ if (profile_init) { \
+ begin_video_copy_profile(); \
+ }
+#define END_VIDEO_COPY_PROFILE() \
+ if (profile_init) { \
+ end_video_copy_profile(); \
+ }
+
+
//
// COMMON
//
}
if (dc->frame) {
+ // begin video copy profile
+ BEGIN_VIDEO_COPY_PROFILE();
+
// if picture is exist...
if (context->is_hwaccel) {
plugin->get_picture(dst + dc->picture_buffer_offset, dc->frame);
} else {
default_get_picture(dst + dc->picture_buffer_offset, dc->frame, dc->avctx->pix_fmt);
}
+
+ // end video copy profile
+ END_VIDEO_COPY_PROFILE();
}
g_free(dc);
TRACE("not using parser %s\n", avctx->codec->name);
}
+ // begin video decode profile
+ BEGIN_VIDEO_DECODE_PROFILE();
+
len = avcodec_decode_video2(avctx, picture, (int *)got_picture, packet);
TRACE("decode_video. len %d, got_picture %d\n", len, *got_picture);
+ // end video decode profile
+ END_VIDEO_DECODE_PROFILE();
+
if (!pctx) {
if (len == 0 && (*got_picture) == 0) {
ERR("decoding video didn't return any data! ctx_id %d len %d\n", ctx_id, len);
elem = (DeviceMemEntry *)data_buf;
+ // initialize profile resource
+ INIT_CODEC_PROFILE(s);
+
// allocate AVCodecContext
avctx = maru_brill_codec_alloc_context(s, ctx_id);
if (!avctx) {
brillcodec_push_writequeue(s, NULL, 0, ctx_id, NULL);
+ // reset profile resource
+ RESET_CODEC_PROFILE();
+
TRACE("leave: %s\n", __func__);
return true;
DEVICE_CMD_GET_ELEMENT,
DEVICE_CMD_GET_CONTEXT_INDEX,
DEVICE_CMD_GET_DEVICE_INFO,
+ DEVICE_CMD_GET_PROFILE_STATUS,
};
enum thread_state {
TRACE("get context index: %d\n", ret);
break;
+ case DEVICE_CMD_GET_PROFILE_STATUS:
+ ret = s->profile;
+ TRACE("profile status: %d\n", s->profile);
+ break;
+
default:
ERR("no avaiable command for read. %d\n", addr);
}
# endif
#endif
+ if (s->profile) {
+ INFO("Profile the brillcodec.(%d)\n", s->profile);
+ }
+
return 0;
}
memset(&s->ioparam, 0, sizeof(CodecParam));
}
+static Property brillcodec_props[] = {
+ DEFINE_PROP_UINT8("profile", MaruBrillCodecState, profile, 0),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
static void brillcodec_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
k->device_id = PCI_DEVICE_ID_VIRTUAL_BRILL_CODEC;
k->class_id = PCI_CLASS_OTHERS;
dc->reset = brillcodec_reset;
+ dc->props = brillcodec_props;
dc->desc = "Virtual new codec device for Tizen emulator";
}