summaryrefslogtreecommitdiff
path: root/apps/plugins
diff options
context:
space:
mode:
authorMichael Sevakis <jethead71@rockbox.org>2011-01-03 16:41:19 +0000
committerMichael Sevakis <jethead71@rockbox.org>2011-01-03 16:41:19 +0000
commitb664f62e36b5f0ac296567e423816dab3811075d (patch)
tree7ca49c59d7332d7c1e51139efa12466b6730e511 /apps/plugins
parentf8fde296a63dd06efef5cf71c9fdb2c26c5a3fd6 (diff)
downloadrockbox-b664f62e36b5f0ac296567e423816dab3811075d.zip
rockbox-b664f62e36b5f0ac296567e423816dab3811075d.tar.gz
rockbox-b664f62e36b5f0ac296567e423816dab3811075d.tar.bz2
rockbox-b664f62e36b5f0ac296567e423816dab3811075d.tar.xz
MPEGPlayer graphics mutation: Implement a more visible FPS display and remove the debugging info from it. Tweak thumbnailing and printing of unavailable frames.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@28960 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'apps/plugins')
-rw-r--r--apps/plugins/mpegplayer/mpeg_settings.c31
-rw-r--r--apps/plugins/mpegplayer/mpegplayer.c130
-rw-r--r--apps/plugins/mpegplayer/stream_mgr.c40
-rw-r--r--apps/plugins/mpegplayer/stream_mgr.h8
-rw-r--r--apps/plugins/mpegplayer/stream_thread.h13
-rw-r--r--apps/plugins/mpegplayer/video_out.h2
-rw-r--r--apps/plugins/mpegplayer/video_out_rockbox.c73
-rw-r--r--apps/plugins/mpegplayer/video_thread.c129
8 files changed, 333 insertions, 93 deletions
diff --git a/apps/plugins/mpegplayer/mpeg_settings.c b/apps/plugins/mpegplayer/mpeg_settings.c
index f84a30d..1b1ac8e 100644
--- a/apps/plugins/mpegplayer/mpeg_settings.c
+++ b/apps/plugins/mpegplayer/mpeg_settings.c
@@ -601,20 +601,37 @@ static void draw_slider(uint32_t range, uint32_t pos, struct vo_rect *rc)
static bool display_thumb_image(const struct vo_rect *rc)
{
+ bool retval = true;
+ unsigned ltgray = MYLCD_LIGHTGRAY;
+ unsigned dkgray = MYLCD_DARKGRAY;
+
+ int oldcolor = mylcd_get_foreground();
+
if (!stream_display_thumb(rc))
{
- mylcd_splash(0, "Frame not available");
- return false;
+ /* Display "No Frame" and erase any border */
+ const char * const str = "No Frame";
+ int x, y, w, h;
+
+ mylcd_getstringsize(str, &w, &h);
+ x = (rc->r + rc->l - w) / 2;
+ y = (rc->b + rc->t - h) / 2;
+ mylcd_putsxy(x, y, str);
+
+ mylcd_update_rect(x, y, w, h);
+
+ ltgray = dkgray = mylcd_get_background();
+ retval = false;
}
- /* Draw a raised border around the frame */
- int oldcolor = mylcd_get_foreground();
- mylcd_set_foreground(MYLCD_LIGHTGRAY);
+ /* Draw a raised border around the frame (or erase if no frame) */
+
+ mylcd_set_foreground(ltgray);
mylcd_hline(rc->l-1, rc->r-1, rc->t-1);
mylcd_vline(rc->l-1, rc->t, rc->b-1);
- mylcd_set_foreground(MYLCD_DARKGRAY);
+ mylcd_set_foreground(dkgray);
mylcd_hline(rc->l-1, rc->r, rc->b);
mylcd_vline(rc->r, rc->t-1, rc->b);
@@ -626,7 +643,7 @@ static bool display_thumb_image(const struct vo_rect *rc)
mylcd_update_rect(rc->l-1, rc->b, rc->r - rc->l + 2, 1);
mylcd_update_rect(rc->r, rc->t, 1, rc->b - rc->t);
- return true;
+ return retval;
}
/* Add an amount to the specified time - with saturation */
diff --git a/apps/plugins/mpegplayer/mpegplayer.c b/apps/plugins/mpegplayer/mpegplayer.c
index d21907f..5ea17f9 100644
--- a/apps/plugins/mpegplayer/mpegplayer.c
+++ b/apps/plugins/mpegplayer/mpegplayer.c
@@ -380,6 +380,7 @@ CONFIG_KEYPAD == SANSA_M200_PAD
/* 3% of 30min file == 54s step size */
#define MIN_FF_REWIND_STEP (TS_SECOND/2)
#define OSD_MIN_UPDATE_INTERVAL (HZ/2)
+#define FPS_UPDATE_INTERVAL (HZ) /* Get new FPS reading each second */
enum video_action
{
@@ -457,9 +458,25 @@ struct osd
uint32_t curr_time;
unsigned auto_refresh;
unsigned flags;
+ int font;
+};
+
+struct fps
+{
+ /* FPS Display */
+ struct vo_rect rect; /* OSD coordinates */
+ int pf_x; /* Screen coordinates */
+ int pf_y;
+ int pf_width;
+ int pf_height;
+ long update_tick; /* When to next update FPS reading */
+ #define FPS_FORMAT "%d.%02d"
+ #define FPS_DIMSTR "999.99" /* For establishing rect size */
+ #define FPS_BUFSIZE sizeof("999.99")
};
static struct osd osd;
+static struct fps fps NOCACHEBSS_ATTR; /* Accessed on other processor */
static void osd_show(unsigned show);
@@ -573,6 +590,12 @@ static void draw_scrollbar_draw_rect(const struct vo_rect *rc, int min,
min, max, val);
}
+static void draw_setfont(int font)
+{
+ osd.font = font;
+ mylcd_setfont(font);
+}
+
#ifdef LCD_PORTRAIT
/* Portrait displays need rotated text rendering */
@@ -646,7 +669,7 @@ static void draw_putsxy_oriented(int x, int y, const char *str)
unsigned short ch;
unsigned short *ucs;
int ofs = MIN(x, 0);
- struct font* pf = rb->font_get(FONT_UI);
+ struct font* pf = rb->font_get(osd.font);
ucs = rb->bidi_l2v(str, 1);
@@ -696,6 +719,96 @@ static void draw_putsxy_oriented(int x, int y, const char *str)
}
#endif /* LCD_PORTRAIT */
+/** FPS Display **/
+
+/* Post-frame callback (on video thread) - update the FPS rectangle from the
+ * framebuffer */
+static void fps_post_frame_callback(void)
+{
+ vo_lock();
+ mylcd_update_rect(fps.pf_x, fps.pf_y,
+ fps.pf_width, fps.pf_height);
+ vo_unlock();
+}
+
+/* Set up to have the callback only update the intersection of the video
+ * rectangle and the FPS text rectangle - if they don't intersect, then
+ * the callback is set to NULL */
+static void fps_update_post_frame_callback(void)
+{
+ void (*cb)(void) = NULL;
+
+ if (settings.showfps) {
+ struct vo_rect cliprect;
+
+ if (stream_vo_get_clip(&cliprect)) {
+ /* Oriented screen coordinates -> OSD coordinates */
+ vo_rect_offset(&cliprect, -osd.x, -osd.y);
+
+ if (vo_rect_intersect(&cliprect, &cliprect, &fps.rect)) {
+ int x = cliprect.l;
+ int y = cliprect.t;
+ int width = cliprect.r - cliprect.l;
+ int height = cliprect.b - cliprect.t;
+
+ /* OSD coordinates -> framebuffer coordinates */
+ fps.pf_x = _X;
+ fps.pf_y = _Y;
+ fps.pf_width = _W;
+ fps.pf_height = _H;
+
+ cb = fps_post_frame_callback;
+ }
+ }
+ }
+
+ stream_set_callback(VIDEO_SET_POST_FRAME_CALLBACK, cb);
+}
+
+/* Refresh the FPS display */
+static void fps_refresh(void)
+{
+ char str[FPS_BUFSIZE];
+ struct video_output_stats stats;
+ int w, h, sw;
+ long tick;
+
+ tick = *rb->current_tick;
+
+ if (TIME_BEFORE(tick, fps.update_tick))
+ return;
+
+ fps.update_tick = tick + FPS_UPDATE_INTERVAL;
+
+ stream_video_stats(&stats);
+
+ rb->snprintf(str, FPS_BUFSIZE, FPS_FORMAT,
+ stats.fps / 100, stats.fps % 100);
+
+ w = fps.rect.r - fps.rect.l;
+ h = fps.rect.b - fps.rect.t;
+
+ draw_clear_area(fps.rect.l, fps.rect.t, w, h);
+ mylcd_getstringsize(str, &sw, NULL);
+ draw_putsxy_oriented(fps.rect.r - sw, fps.rect.t, str);
+
+ vo_lock();
+ draw_update_rect(fps.rect.l, fps.rect.t, w, h);
+ vo_unlock();
+}
+
+/* Initialize the FPS display */
+static void fps_init(void)
+{
+ fps.update_tick = *rb->current_tick;
+ fps.rect.l = fps.rect.t = 0;
+ mylcd_getstringsize(FPS_DIMSTR, &fps.rect.r, &fps.rect.b);
+ vo_rect_offset(&fps.rect, -osd.x, -osd.y);
+ fps_update_post_frame_callback();
+}
+
+/** OSD **/
+
#if defined(HAVE_LCD_ENABLE) || defined(HAVE_LCD_SLEEP)
/* So we can refresh the overlay */
static void osd_lcd_enable_hook(void* param)
@@ -743,7 +856,7 @@ static void osd_text_init(void)
int phys;
int spc_width;
- mylcd_setfont(FONT_UI);
+ draw_setfont(FONT_UI);
osd.x = 0;
osd.width = SCREEN_WIDTH;
@@ -812,7 +925,7 @@ static void osd_text_init(void)
#endif
osd.y = SCREEN_HEIGHT - osd.height;
- mylcd_setfont(FONT_SYSFIXED);
+ draw_setfont(FONT_SYSFIXED);
}
static void osd_init(void)
@@ -835,6 +948,7 @@ static void osd_init(void)
osd.auto_refresh = OSD_REFRESH_TIME;
osd.next_auto_refresh = *rb->current_tick;
osd_text_init();
+ fps_init();
}
#ifdef HAVE_HEADPHONE_DETECTION
@@ -1047,6 +1161,9 @@ static void osd_refresh(int hint)
tick = *rb->current_tick;
+ if (settings.showfps)
+ fps_refresh();
+
if (hint == OSD_REFRESH_DEFAULT) {
/* The default which forces no updates */
@@ -1116,7 +1233,7 @@ static void osd_refresh(int hint)
oldfg = mylcd_get_foreground();
oldbg = mylcd_get_background();
- mylcd_setfont(FONT_UI);
+ draw_setfont(FONT_UI);
mylcd_set_foreground(osd.fgcolor);
mylcd_set_background(osd.bgcolor);
@@ -1140,7 +1257,7 @@ static void osd_refresh(int hint)
}
/* Go back to defaults */
- mylcd_setfont(FONT_SYSFIXED);
+ draw_setfont(FONT_SYSFIXED);
mylcd_set_foreground(oldfg);
mylcd_set_background(oldbg);
@@ -1391,6 +1508,7 @@ static int osd_play(uint32_t time)
osd_backlight_on_video_mode(true);
osd_backlight_brightness_video_mode(true);
stream_show_vo(true);
+
retval = stream_play();
if (retval >= STREAM_OK)
@@ -1747,6 +1865,8 @@ static int button_loop(void)
next_action = (settings.play_mode == 0) ? VIDEO_STOP : VIDEO_NEXT;
+ fps_update_post_frame_callback();
+
/* The menu can change the font, so restore */
rb->lcd_setfont(FONT_SYSFIXED);
#ifdef HAVE_LCD_COLOR
diff --git a/apps/plugins/mpegplayer/stream_mgr.c b/apps/plugins/mpegplayer/stream_mgr.c
index cee384f..6607402 100644
--- a/apps/plugins/mpegplayer/stream_mgr.c
+++ b/apps/plugins/mpegplayer/stream_mgr.c
@@ -695,8 +695,8 @@ static intptr_t send_video_msg(long id, intptr_t data)
if (disk_buf_status() != STREAM_STOPPED)
break; /* Prepare image if not playing */
- if (!parser_prepare_image(str_parser.last_seek_time))
- return false; /* Preparation failed */
+ /* Ignore return and try video thread anyway */
+ parser_prepare_image(str_parser.last_seek_time);
/* Image ready - pass message to video thread */
break;
@@ -766,6 +766,25 @@ void stream_vo_set_clip(const struct vo_rect *rc)
stream_mgr_unlock();
}
+bool stream_vo_get_clip(struct vo_rect *rc)
+{
+ bool retval;
+
+ if (!rc)
+ return false;
+
+ stream_mgr_lock();
+
+ retval = send_video_msg(VIDEO_GET_CLIP_RECT,
+ (intptr_t)&stream_mgr.parms.rc);
+
+ *rc = stream_mgr.parms.rc;
+
+ stream_mgr_unlock();
+
+ return retval;
+}
+
#ifndef HAVE_LCD_COLOR
/* Show/hide the gray video overlay (independently of vo visibility). */
void stream_gray_show(bool show)
@@ -810,6 +829,23 @@ bool stream_draw_frame(bool no_prepare)
return retval;
}
+bool stream_set_callback(long id, void *fn)
+{
+ bool retval = false;
+
+ stream_mgr_lock();
+
+ switch (id)
+ {
+ case VIDEO_SET_POST_FRAME_CALLBACK:
+ retval = send_video_msg(id, (intptr_t)fn);
+ }
+
+ stream_mgr_unlock();
+
+ return retval;
+}
+
/* Return the time playback should resume if interrupted */
uint32_t stream_get_resume_time(void)
{
diff --git a/apps/plugins/mpegplayer/stream_mgr.h b/apps/plugins/mpegplayer/stream_mgr.h
index a07305a..7dba9ac 100644
--- a/apps/plugins/mpegplayer/stream_mgr.h
+++ b/apps/plugins/mpegplayer/stream_mgr.h
@@ -106,6 +106,9 @@ bool stream_show_vo(bool show);
/* Set the visible section of video */
void stream_vo_set_clip(const struct vo_rect *rc);
+/* Return current visible section of video */
+bool stream_vo_get_clip(struct vo_rect *rc);
+
#ifndef HAVE_LCD_COLOR
void stream_gray_show(bool show);
#endif
@@ -149,6 +152,11 @@ static inline uint32_t stream_get_duration(void)
static inline bool stream_can_seek(void)
{ return parser_can_seek(); }
+static inline void stream_video_stats(struct video_output_stats *s)
+ { video_thread_get_stats(s); }
+
+bool stream_set_callback(long id, void * fn);
+
/* Keep the disk spinning (for seeking and browsing) */
static inline void stream_keep_disk_active(void)
{
diff --git a/apps/plugins/mpegplayer/stream_thread.h b/apps/plugins/mpegplayer/stream_thread.h
index 1d3a445..5791a49 100644
--- a/apps/plugins/mpegplayer/stream_thread.h
+++ b/apps/plugins/mpegplayer/stream_thread.h
@@ -108,6 +108,8 @@ enum stream_message
VIDEO_PRINT_FRAME, /* Print the frame at the current position */
VIDEO_PRINT_THUMBNAIL, /* Print a thumbnail of the current position */
VIDEO_SET_CLIP_RECT, /* Set the visible video area */
+ VIDEO_GET_CLIP_RECT, /* Return the visible video area */
+ VIDEO_SET_POST_FRAME_CALLBACK, /* Set a callback after frame is drawn */
STREAM_MESSAGE_LAST,
};
@@ -160,9 +162,20 @@ extern struct stream audio_str IBSS_ATTR;
bool video_thread_init(void);
void video_thread_exit(void);
+
+struct video_output_stats
+{
+ int num_drawn; /* Number of frames drawn since reset */
+ int num_skipped; /* Number of frames skipped since reset */
+ int fps; /* fps rate in 100ths of a frame per second */
+};
+
+void video_thread_get_stats(struct video_output_stats *s);
+
bool audio_thread_init(void);
void audio_thread_exit(void);
+
/* Some queue function wrappers to keep things clean-ish */
/* For stream use only */
diff --git a/apps/plugins/mpegplayer/video_out.h b/apps/plugins/mpegplayer/video_out.h
index 808f233..2a3364c 100644
--- a/apps/plugins/mpegplayer/video_out.h
+++ b/apps/plugins/mpegplayer/video_out.h
@@ -58,8 +58,10 @@ bool vo_show (bool show);
bool vo_is_visible(void);
void vo_setup (const mpeg2_sequence_t * sequence);
void vo_set_clip_rect(const struct vo_rect *rc);
+bool vo_get_clip_rect(struct vo_rect *rc);
void vo_dimensions(struct vo_ext *sz);
void vo_cleanup (void);
+void vo_set_post_draw_callback(void (*cb)(void));
#if NUM_CORES > 1
void vo_lock(void);
diff --git a/apps/plugins/mpegplayer/video_out_rockbox.c b/apps/plugins/mpegplayer/video_out_rockbox.c
index fe3deaf..214bdf3 100644
--- a/apps/plugins/mpegplayer/video_out_rockbox.c
+++ b/apps/plugins/mpegplayer/video_out_rockbox.c
@@ -41,6 +41,7 @@ struct vo_data
unsigned flags;
struct vo_rect rc_vid;
struct vo_rect rc_clip;
+ void (*post_draw_callback)(void);
};
#if NUM_CORES > 1
@@ -80,9 +81,10 @@ static inline void video_unlock(void)
/* Draw a black rectangle if no video frame is available */
-static void vo_draw_black(void)
+static void vo_draw_black(struct vo_rect *rc)
{
int foreground;
+ int x, y, w, h;
video_lock();
@@ -90,10 +92,30 @@ static void vo_draw_black(void)
mylcd_set_foreground(MYLCD_BLACK);
- mylcd_fillrect(vo.output_x, vo.output_y, vo.output_width,
- vo.output_height);
- mylcd_update_rect(vo.output_x, vo.output_y, vo.output_width,
- vo.output_height);
+ if (rc)
+ {
+ x = rc->l;
+ y = rc->t;
+ w = rc->r - rc->l;
+ h = rc->b - rc->t;
+ }
+ else
+ {
+#if LCD_WIDTH >= LCD_HEIGHT
+ x = vo.output_x;
+ y = vo.output_y;
+ w = vo.output_width;
+ h = vo.output_height;
+#else
+ x = LCD_WIDTH - vo.output_height - vo.output_y;
+ y = vo.output_x;
+ w = vo.output_height;
+ h = vo.output_width;
+#endif
+ }
+
+ mylcd_fillrect(x, y, w, h);
+ mylcd_update_rect(x, y, w, h);
mylcd_set_foreground(foreground);
@@ -122,19 +144,22 @@ void vo_draw_frame(uint8_t * const * buf)
/* Frame is hidden - either by being set invisible or is clipped
* away - copout */
DEBUGF("vo hidden\n");
- return;
}
else if (buf == NULL)
{
/* No frame exists - draw black */
- vo_draw_black();
+ vo_draw_black(NULL);
DEBUGF("vo no frame\n");
- return;
+ }
+ else
+ {
+ yuv_blit(buf, 0, 0, vo.image_width,
+ vo.output_x, vo.output_y, vo.output_width,
+ vo.output_height);
}
- yuv_blit(buf, 0, 0, vo.image_width,
- vo.output_x, vo.output_y, vo.output_width,
- vo.output_height);
+ if (vo.post_draw_callback)
+ vo.post_draw_callback();
}
static inline void vo_rect_clear_inl(struct vo_rect *rc)
@@ -348,14 +373,14 @@ bool vo_draw_frame_thumb(uint8_t * const * buf, const struct vo_rect *rc)
int thumb_width, thumb_height;
int thumb_uv_width, thumb_uv_height;
- if (buf == NULL)
- return false;
-
/* Obtain rectangle as clipped to the screen */
vo_rect_set_ext(&thumb_rc, 0, 0, LCD_WIDTH, LCD_HEIGHT);
if (!vo_rect_intersect(&thumb_rc, rc, &thumb_rc))
return true;
+ if (buf == NULL)
+ goto no_thumb_exit;
+
DEBUGF("thumb_rc: %d, %d, %d, %d\n", thumb_rc.l, thumb_rc.t,
thumb_rc.r, thumb_rc.b);
@@ -377,7 +402,7 @@ bool vo_draw_frame_thumb(uint8_t * const * buf, const struct vo_rect *rc)
)
{
DEBUGF("thumb: insufficient buffer\n");
- return false;
+ goto no_thumb_exit;
}
yuv[0] = mem;
@@ -411,6 +436,10 @@ bool vo_draw_frame_thumb(uint8_t * const * buf, const struct vo_rect *rc)
#endif /* LCD_WIDTH >= LCD_HEIGHT */
return true;
+
+no_thumb_exit:
+ vo_draw_black(&thumb_rc);
+ return false;
}
void vo_setup(const mpeg2_sequence_t * sequence)
@@ -512,6 +541,20 @@ void vo_set_clip_rect(const struct vo_rect *rc)
vo.output_height = rc_out.b - rc_out.t;
}
+bool vo_get_clip_rect(struct vo_rect *rc)
+{
+ rc->l = vo.output_x;
+ rc->t = vo.output_y;
+ rc->r = rc->l + vo.output_width;
+ rc->b = rc->t + vo.output_height;
+ return (vo.flags & VO_NON_NULL_RECT) != 0;
+}
+
+void vo_set_post_draw_callback(void (*cb)(void))
+{
+ vo.post_draw_callback = cb;
+}
+
#if NUM_CORES > 1
void vo_lock(void)
{
diff --git a/apps/plugins/mpegplayer/video_thread.c b/apps/plugins/mpegplayer/video_thread.c
index 69d94f8..aa88590 100644
--- a/apps/plugins/mpegplayer/video_thread.c
+++ b/apps/plugins/mpegplayer/video_thread.c
@@ -37,21 +37,23 @@ struct video_thread_data
int state; /* Thread state */
int status; /* Media status */
struct queue_event ev; /* Our event queue to receive commands */
- int num_drawn; /* Number of frames drawn since reset */
- int num_skipped; /* Number of frames skipped since reset */
uint32_t eta_stream; /* Current time of stream */
uint32_t eta_video; /* Time that frame has been scheduled for */
int32_t eta_early; /* How early has the frame been decoded? */
int32_t eta_late; /* How late has the frame been decoded? */
int frame_drop_level; /* Drop severity */
int skip_level; /* Skip severity */
- long last_showfps; /* Last time the FPS display was updated */
long last_render; /* Last time a frame was drawn */
uint32_t curr_time; /* Current due time of frame */
uint32_t period; /* Frame period in clock ticks */
int syncf_perfect; /* Last sync fit result */
};
+/* Number drawn since reset */
+static int video_num_drawn SHAREDBSS_ATTR;
+/* Number skipped since reset */
+static int video_num_skipped SHAREDBSS_ATTR;
+
/* TODO: Check if 4KB is appropriate - it works for my test streams,
so maybe we can reduce it. */
#define VIDEO_STACKSIZE (4*1024)
@@ -60,35 +62,6 @@ static struct event_queue video_str_queue SHAREDBSS_ATTR;
static struct queue_sender_list video_str_queue_send SHAREDBSS_ATTR;
struct stream video_str IBSS_ATTR;
-static void draw_fps(struct video_thread_data *td)
-{
- uint32_t start;
- uint32_t clock_ticks = stream_get_ticks(&start);
- int fps = 0;
- int buf_pct;
- char str[80];
-
- clock_ticks -= start;
- if (clock_ticks != 0)
- fps = muldiv_uint32(CLOCK_RATE*100, td->num_drawn, clock_ticks);
-
- buf_pct = muldiv_uint32(100, pcm_output_used(), PCMOUT_BUFSIZE);
-
- rb->snprintf(str, sizeof(str), "v:%d.%02d %d %d a:%02d%% %d %d ",
- /* Video information */
- fps / 100, fps % 100, td->num_skipped,
- td->info->display_picture->temporal_reference,
- /* Audio information */
- buf_pct, pcm_underruns, pcm_skipped);
- mylcd_putsxy(0, 0, str);
-
- vo_lock();
- mylcd_update_rect(0, 0, LCD_WIDTH, 8);
- vo_unlock();
-
- td->last_showfps = *rb->current_tick;
-}
-
#if defined(DEBUG) || defined(SIMULATOR)
static unsigned char pic_coding_type_char(unsigned type)
{
@@ -452,6 +425,31 @@ sync_finished:
return retval;
}
+static bool frame_print_handler(struct video_thread_data *td)
+{
+ bool retval;
+ uint8_t * const * buf = NULL;
+
+ if (td->info != NULL && td->info->display_fbuf != NULL &&
+ td->syncf_perfect > 0)
+ buf = td->info->display_fbuf->buf;
+
+ if (td->ev.id == VIDEO_PRINT_THUMBNAIL)
+ {
+ /* Print a thumbnail of whatever was last decoded - scale and
+ * position to fill the specified rectangle */
+ retval = vo_draw_frame_thumb(buf, (struct vo_rect *)td->ev.data);
+ }
+ else
+ {
+ /* Print the last frame decoded */
+ vo_draw_frame(buf);
+ retval = buf != NULL;
+ }
+
+ return retval;
+}
+
/* This only returns to play or quit */
static void video_thread_msg(struct video_thread_data *td)
{
@@ -520,8 +518,7 @@ static void video_thread_msg(struct video_thread_data *td)
if (td->ev.data)
{
- if (td->info != NULL && td->info->display_fbuf != NULL)
- vo_draw_frame(td->info->display_fbuf->buf);
+ frame_print_handler(td);
}
else
{
@@ -547,10 +544,9 @@ static void video_thread_msg(struct video_thread_data *td)
td->eta_late = 0;
td->frame_drop_level = 0;
td->skip_level = 0;
- td->num_drawn = 0;
- td->num_skipped = 0;
- td->last_showfps = *rb->current_tick - HZ;
- td->last_render = td->last_showfps;
+ td->last_render = *rb->current_tick - HZ;
+ video_num_drawn = 0;
+ video_num_skipped = 0;
reply = true;
break;
@@ -573,28 +569,17 @@ static void video_thread_msg(struct video_thread_data *td)
str_data_notify_received(&video_str);
break;
+ case VIDEO_PRINT_FRAME:
case VIDEO_PRINT_THUMBNAIL:
- /* Print a thumbnail of whatever was last decoded - scale and
- * position to fill the specified rectangle */
- if (td->info != NULL && td->info->display_fbuf != NULL)
- {
- vo_draw_frame_thumb(td->info->display_fbuf->buf,
- (struct vo_rect *)td->ev.data);
- reply = true;
- }
+ reply = frame_print_handler(td);
break;
case VIDEO_SET_CLIP_RECT:
vo_set_clip_rect((const struct vo_rect *)td->ev.data);
break;
- case VIDEO_PRINT_FRAME:
- /* Print the last frame decoded */
- if (td->info != NULL && td->info->display_fbuf != NULL)
- {
- vo_draw_frame(td->info->display_fbuf->buf);
- reply = true;
- }
+ case VIDEO_GET_CLIP_RECT:
+ reply = vo_get_clip_rect((struct vo_rect *)td->ev.data);
break;
case VIDEO_GET_SIZE:
@@ -621,6 +606,11 @@ static void video_thread_msg(struct video_thread_data *td)
reply = video_str_scan(td, (struct str_sync_data *)td->ev.data);
break;
+ case VIDEO_SET_POST_FRAME_CALLBACK:
+ vo_set_post_draw_callback((void (*)(void))td->ev.data);
+ reply = true;
+ break;
+
case STREAM_QUIT:
/* Time to go - make thread exit */
td->state = TSTATE_EOS;
@@ -802,6 +792,8 @@ static void video_thread(void)
if (td.info->display_fbuf == NULL)
break; /* No picture */
+ td.syncf_perfect = 1; /* yes, a frame exists */
+
/* Get presentation times in audio samples - quite accurate
enough - add previous frame duration if not stamped */
td.curr_time = (td.info->display_picture->flags & PIC_FLAG_TAGS) ?
@@ -902,8 +894,8 @@ static void video_thread(void)
{
/* This frame was set to skip so skip it after having updated
timing information */
- td.num_skipped++;
td.eta_early = INT32_MIN;
+ video_num_skipped++;
goto picture_skip;
}
@@ -913,8 +905,8 @@ static void video_thread(void)
/* Render drop was set previously but nothing was dropped in the
decoder or it's been to long since drawing the last frame. */
td.skip_level = 0;
- td.num_skipped++;
td.eta_early = INT32_MIN;
+ video_num_skipped++;
goto picture_skip;
}
@@ -970,18 +962,11 @@ static void video_thread(void)
picture_draw:
/* Record last frame time */
td.last_render = *rb->current_tick;
+
vo_draw_frame(td.info->display_fbuf->buf);
- td.num_drawn++;
+ video_num_drawn++;
picture_skip:
- if (!settings.showfps)
- break;
-
- if (TIME_BEFORE(*rb->current_tick, td.last_showfps + HZ))
- break;
-
- /* Calculate and display fps */
- draw_fps(&td);
break;
}
@@ -1032,3 +1017,19 @@ void video_thread_exit(void)
video_str.thread = 0;
}
}
+
+
+/** Misc **/
+void video_thread_get_stats(struct video_output_stats *s)
+{
+ uint32_t start;
+ uint32_t now = stream_get_ticks(&start);
+ s->num_drawn = video_num_drawn;
+ s->num_skipped = video_num_skipped;
+
+ s->fps = 0;
+
+ if (now > start)
+ s->fps = muldiv_uint32(CLOCK_RATE*100, s->num_drawn, now - start);
+}
+