summaryrefslogtreecommitdiff
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
parentf8fde296a63dd06efef5cf71c9fdb2c26c5a3fd6 (diff)
downloadrockbox-b664f62e36b5f0ac296567e423816dab3811075d.tar.gz
rockbox-b664f62e36b5f0ac296567e423816dab3811075d.zip
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
-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 f84a30ddfe..1b1ac8e2f0 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)
601 601
602static bool display_thumb_image(const struct vo_rect *rc) 602static bool display_thumb_image(const struct vo_rect *rc)
603{ 603{
604 bool retval = true;
605 unsigned ltgray = MYLCD_LIGHTGRAY;
606 unsigned dkgray = MYLCD_DARKGRAY;
607
608 int oldcolor = mylcd_get_foreground();
609
604 if (!stream_display_thumb(rc)) 610 if (!stream_display_thumb(rc))
605 { 611 {
606 mylcd_splash(0, "Frame not available"); 612 /* Display "No Frame" and erase any border */
607 return false; 613 const char * const str = "No Frame";
614 int x, y, w, h;
615
616 mylcd_getstringsize(str, &w, &h);
617 x = (rc->r + rc->l - w) / 2;
618 y = (rc->b + rc->t - h) / 2;
619 mylcd_putsxy(x, y, str);
620
621 mylcd_update_rect(x, y, w, h);
622
623 ltgray = dkgray = mylcd_get_background();
624 retval = false;
608 } 625 }
609 626
610 /* Draw a raised border around the frame */ 627 /* Draw a raised border around the frame (or erase if no frame) */
611 int oldcolor = mylcd_get_foreground(); 628
612 mylcd_set_foreground(MYLCD_LIGHTGRAY); 629 mylcd_set_foreground(ltgray);
613 630
614 mylcd_hline(rc->l-1, rc->r-1, rc->t-1); 631 mylcd_hline(rc->l-1, rc->r-1, rc->t-1);
615 mylcd_vline(rc->l-1, rc->t, rc->b-1); 632 mylcd_vline(rc->l-1, rc->t, rc->b-1);
616 633
617 mylcd_set_foreground(MYLCD_DARKGRAY); 634 mylcd_set_foreground(dkgray);
618 635
619 mylcd_hline(rc->l-1, rc->r, rc->b); 636 mylcd_hline(rc->l-1, rc->r, rc->b);
620 mylcd_vline(rc->r, rc->t-1, rc->b); 637 mylcd_vline(rc->r, rc->t-1, rc->b);
@@ -626,7 +643,7 @@ static bool display_thumb_image(const struct vo_rect *rc)
626 mylcd_update_rect(rc->l-1, rc->b, rc->r - rc->l + 2, 1); 643 mylcd_update_rect(rc->l-1, rc->b, rc->r - rc->l + 2, 1);
627 mylcd_update_rect(rc->r, rc->t, 1, rc->b - rc->t); 644 mylcd_update_rect(rc->r, rc->t, 1, rc->b - rc->t);
628 645
629 return true; 646 return retval;
630} 647}
631 648
632/* Add an amount to the specified time - with saturation */ 649/* Add an amount to the specified time - with saturation */
diff --git a/apps/plugins/mpegplayer/mpegplayer.c b/apps/plugins/mpegplayer/mpegplayer.c
index d21907f607..5ea17f9a3e 100644
--- a/apps/plugins/mpegplayer/mpegplayer.c
+++ b/apps/plugins/mpegplayer/mpegplayer.c
@@ -380,6 +380,7 @@ CONFIG_KEYPAD == SANSA_M200_PAD
380 /* 3% of 30min file == 54s step size */ 380 /* 3% of 30min file == 54s step size */
381#define MIN_FF_REWIND_STEP (TS_SECOND/2) 381#define MIN_FF_REWIND_STEP (TS_SECOND/2)
382#define OSD_MIN_UPDATE_INTERVAL (HZ/2) 382#define OSD_MIN_UPDATE_INTERVAL (HZ/2)
383#define FPS_UPDATE_INTERVAL (HZ) /* Get new FPS reading each second */
383 384
384enum video_action 385enum video_action
385{ 386{
@@ -457,9 +458,25 @@ struct osd
457 uint32_t curr_time; 458 uint32_t curr_time;
458 unsigned auto_refresh; 459 unsigned auto_refresh;
459 unsigned flags; 460 unsigned flags;
461 int font;
462};
463
464struct fps
465{
466 /* FPS Display */
467 struct vo_rect rect; /* OSD coordinates */
468 int pf_x; /* Screen coordinates */
469 int pf_y;
470 int pf_width;
471 int pf_height;
472 long update_tick; /* When to next update FPS reading */
473 #define FPS_FORMAT "%d.%02d"
474 #define FPS_DIMSTR "999.99" /* For establishing rect size */
475 #define FPS_BUFSIZE sizeof("999.99")
460}; 476};
461 477
462static struct osd osd; 478static struct osd osd;
479static struct fps fps NOCACHEBSS_ATTR; /* Accessed on other processor */
463 480
464static void osd_show(unsigned show); 481static void osd_show(unsigned show);
465 482
@@ -573,6 +590,12 @@ static void draw_scrollbar_draw_rect(const struct vo_rect *rc, int min,
573 min, max, val); 590 min, max, val);
574} 591}
575 592
593static void draw_setfont(int font)
594{
595 osd.font = font;
596 mylcd_setfont(font);
597}
598
576#ifdef LCD_PORTRAIT 599#ifdef LCD_PORTRAIT
577/* Portrait displays need rotated text rendering */ 600/* Portrait displays need rotated text rendering */
578 601
@@ -646,7 +669,7 @@ static void draw_putsxy_oriented(int x, int y, const char *str)
646 unsigned short ch; 669 unsigned short ch;
647 unsigned short *ucs; 670 unsigned short *ucs;
648 int ofs = MIN(x, 0); 671 int ofs = MIN(x, 0);
649 struct font* pf = rb->font_get(FONT_UI); 672 struct font* pf = rb->font_get(osd.font);
650 673
651 ucs = rb->bidi_l2v(str, 1); 674 ucs = rb->bidi_l2v(str, 1);
652 675
@@ -696,6 +719,96 @@ static void draw_putsxy_oriented(int x, int y, const char *str)
696} 719}
697#endif /* LCD_PORTRAIT */ 720#endif /* LCD_PORTRAIT */
698 721
722/** FPS Display **/
723
724/* Post-frame callback (on video thread) - update the FPS rectangle from the
725 * framebuffer */
726static void fps_post_frame_callback(void)
727{
728 vo_lock();
729 mylcd_update_rect(fps.pf_x, fps.pf_y,
730 fps.pf_width, fps.pf_height);
731 vo_unlock();
732}
733
734/* Set up to have the callback only update the intersection of the video
735 * rectangle and the FPS text rectangle - if they don't intersect, then
736 * the callback is set to NULL */
737static void fps_update_post_frame_callback(void)
738{
739 void (*cb)(void) = NULL;
740
741 if (settings.showfps) {
742 struct vo_rect cliprect;
743
744 if (stream_vo_get_clip(&cliprect)) {
745 /* Oriented screen coordinates -> OSD coordinates */
746 vo_rect_offset(&cliprect, -osd.x, -osd.y);
747
748 if (vo_rect_intersect(&cliprect, &cliprect, &fps.rect)) {
749 int x = cliprect.l;
750 int y = cliprect.t;
751 int width = cliprect.r - cliprect.l;
752 int height = cliprect.b - cliprect.t;
753
754 /* OSD coordinates -> framebuffer coordinates */
755 fps.pf_x = _X;
756 fps.pf_y = _Y;
757 fps.pf_width = _W;
758 fps.pf_height = _H;
759
760 cb = fps_post_frame_callback;
761 }
762 }
763 }
764
765 stream_set_callback(VIDEO_SET_POST_FRAME_CALLBACK, cb);
766}
767
768/* Refresh the FPS display */
769static void fps_refresh(void)
770{
771 char str[FPS_BUFSIZE];
772 struct video_output_stats stats;
773 int w, h, sw;
774 long tick;
775
776 tick = *rb->current_tick;
777
778 if (TIME_BEFORE(tick, fps.update_tick))
779 return;
780
781 fps.update_tick = tick + FPS_UPDATE_INTERVAL;
782
783 stream_video_stats(&stats);
784
785 rb->snprintf(str, FPS_BUFSIZE, FPS_FORMAT,
786 stats.fps / 100, stats.fps % 100);
787
788 w = fps.rect.r - fps.rect.l;
789 h = fps.rect.b - fps.rect.t;
790
791 draw_clear_area(fps.rect.l, fps.rect.t, w, h);
792 mylcd_getstringsize(str, &sw, NULL);
793 draw_putsxy_oriented(fps.rect.r - sw, fps.rect.t, str);
794
795 vo_lock();
796 draw_update_rect(fps.rect.l, fps.rect.t, w, h);
797 vo_unlock();
798}
799
800/* Initialize the FPS display */
801static void fps_init(void)
802{
803 fps.update_tick = *rb->current_tick;
804 fps.rect.l = fps.rect.t = 0;
805 mylcd_getstringsize(FPS_DIMSTR, &fps.rect.r, &fps.rect.b);
806 vo_rect_offset(&fps.rect, -osd.x, -osd.y);
807 fps_update_post_frame_callback();
808}
809
810/** OSD **/
811
699#if defined(HAVE_LCD_ENABLE) || defined(HAVE_LCD_SLEEP) 812#if defined(HAVE_LCD_ENABLE) || defined(HAVE_LCD_SLEEP)
700/* So we can refresh the overlay */ 813/* So we can refresh the overlay */
701static void osd_lcd_enable_hook(void* param) 814static void osd_lcd_enable_hook(void* param)
@@ -743,7 +856,7 @@ static void osd_text_init(void)
743 int phys; 856 int phys;
744 int spc_width; 857 int spc_width;
745 858
746 mylcd_setfont(FONT_UI); 859 draw_setfont(FONT_UI);
747 860
748 osd.x = 0; 861 osd.x = 0;
749 osd.width = SCREEN_WIDTH; 862 osd.width = SCREEN_WIDTH;
@@ -812,7 +925,7 @@ static void osd_text_init(void)
812#endif 925#endif
813 osd.y = SCREEN_HEIGHT - osd.height; 926 osd.y = SCREEN_HEIGHT - osd.height;
814 927
815 mylcd_setfont(FONT_SYSFIXED); 928 draw_setfont(FONT_SYSFIXED);
816} 929}
817 930
818static void osd_init(void) 931static void osd_init(void)
@@ -835,6 +948,7 @@ static void osd_init(void)
835 osd.auto_refresh = OSD_REFRESH_TIME; 948 osd.auto_refresh = OSD_REFRESH_TIME;
836 osd.next_auto_refresh = *rb->current_tick; 949 osd.next_auto_refresh = *rb->current_tick;
837 osd_text_init(); 950 osd_text_init();
951 fps_init();
838} 952}
839 953
840#ifdef HAVE_HEADPHONE_DETECTION 954#ifdef HAVE_HEADPHONE_DETECTION
@@ -1047,6 +1161,9 @@ static void osd_refresh(int hint)
1047 1161
1048 tick = *rb->current_tick; 1162 tick = *rb->current_tick;
1049 1163
1164 if (settings.showfps)
1165 fps_refresh();
1166
1050 if (hint == OSD_REFRESH_DEFAULT) { 1167 if (hint == OSD_REFRESH_DEFAULT) {
1051 /* The default which forces no updates */ 1168 /* The default which forces no updates */
1052 1169
@@ -1116,7 +1233,7 @@ static void osd_refresh(int hint)
1116 oldfg = mylcd_get_foreground(); 1233 oldfg = mylcd_get_foreground();
1117 oldbg = mylcd_get_background(); 1234 oldbg = mylcd_get_background();
1118 1235
1119 mylcd_setfont(FONT_UI); 1236 draw_setfont(FONT_UI);
1120 mylcd_set_foreground(osd.fgcolor); 1237 mylcd_set_foreground(osd.fgcolor);
1121 mylcd_set_background(osd.bgcolor); 1238 mylcd_set_background(osd.bgcolor);
1122 1239
@@ -1140,7 +1257,7 @@ static void osd_refresh(int hint)
1140 } 1257 }
1141 1258
1142 /* Go back to defaults */ 1259 /* Go back to defaults */
1143 mylcd_setfont(FONT_SYSFIXED); 1260 draw_setfont(FONT_SYSFIXED);
1144 mylcd_set_foreground(oldfg); 1261 mylcd_set_foreground(oldfg);
1145 mylcd_set_background(oldbg); 1262 mylcd_set_background(oldbg);
1146 1263
@@ -1391,6 +1508,7 @@ static int osd_play(uint32_t time)
1391 osd_backlight_on_video_mode(true); 1508 osd_backlight_on_video_mode(true);
1392 osd_backlight_brightness_video_mode(true); 1509 osd_backlight_brightness_video_mode(true);
1393 stream_show_vo(true); 1510 stream_show_vo(true);
1511
1394 retval = stream_play(); 1512 retval = stream_play();
1395 1513
1396 if (retval >= STREAM_OK) 1514 if (retval >= STREAM_OK)
@@ -1747,6 +1865,8 @@ static int button_loop(void)
1747 1865
1748 next_action = (settings.play_mode == 0) ? VIDEO_STOP : VIDEO_NEXT; 1866 next_action = (settings.play_mode == 0) ? VIDEO_STOP : VIDEO_NEXT;
1749 1867
1868 fps_update_post_frame_callback();
1869
1750 /* The menu can change the font, so restore */ 1870 /* The menu can change the font, so restore */
1751 rb->lcd_setfont(FONT_SYSFIXED); 1871 rb->lcd_setfont(FONT_SYSFIXED);
1752#ifdef HAVE_LCD_COLOR 1872#ifdef HAVE_LCD_COLOR
diff --git a/apps/plugins/mpegplayer/stream_mgr.c b/apps/plugins/mpegplayer/stream_mgr.c
index cee384fb75..6607402d5a 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)
695 if (disk_buf_status() != STREAM_STOPPED) 695 if (disk_buf_status() != STREAM_STOPPED)
696 break; /* Prepare image if not playing */ 696 break; /* Prepare image if not playing */
697 697
698 if (!parser_prepare_image(str_parser.last_seek_time)) 698 /* Ignore return and try video thread anyway */
699 return false; /* Preparation failed */ 699 parser_prepare_image(str_parser.last_seek_time);
700 700
701 /* Image ready - pass message to video thread */ 701 /* Image ready - pass message to video thread */
702 break; 702 break;
@@ -766,6 +766,25 @@ void stream_vo_set_clip(const struct vo_rect *rc)
766 stream_mgr_unlock(); 766 stream_mgr_unlock();
767} 767}
768 768
769bool stream_vo_get_clip(struct vo_rect *rc)
770{
771 bool retval;
772
773 if (!rc)
774 return false;
775
776 stream_mgr_lock();
777
778 retval = send_video_msg(VIDEO_GET_CLIP_RECT,
779 (intptr_t)&stream_mgr.parms.rc);
780
781 *rc = stream_mgr.parms.rc;
782
783 stream_mgr_unlock();
784
785 return retval;
786}
787
769#ifndef HAVE_LCD_COLOR 788#ifndef HAVE_LCD_COLOR
770/* Show/hide the gray video overlay (independently of vo visibility). */ 789/* Show/hide the gray video overlay (independently of vo visibility). */
771void stream_gray_show(bool show) 790void stream_gray_show(bool show)
@@ -810,6 +829,23 @@ bool stream_draw_frame(bool no_prepare)
810 return retval; 829 return retval;
811} 830}
812 831
832bool stream_set_callback(long id, void *fn)
833{
834 bool retval = false;
835
836 stream_mgr_lock();
837
838 switch (id)
839 {
840 case VIDEO_SET_POST_FRAME_CALLBACK:
841 retval = send_video_msg(id, (intptr_t)fn);
842 }
843
844 stream_mgr_unlock();
845
846 return retval;
847}
848
813/* Return the time playback should resume if interrupted */ 849/* Return the time playback should resume if interrupted */
814uint32_t stream_get_resume_time(void) 850uint32_t stream_get_resume_time(void)
815{ 851{
diff --git a/apps/plugins/mpegplayer/stream_mgr.h b/apps/plugins/mpegplayer/stream_mgr.h
index a07305a847..7dba9acc09 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);
106/* Set the visible section of video */ 106/* Set the visible section of video */
107void stream_vo_set_clip(const struct vo_rect *rc); 107void stream_vo_set_clip(const struct vo_rect *rc);
108 108
109/* Return current visible section of video */
110bool stream_vo_get_clip(struct vo_rect *rc);
111
109#ifndef HAVE_LCD_COLOR 112#ifndef HAVE_LCD_COLOR
110void stream_gray_show(bool show); 113void stream_gray_show(bool show);
111#endif 114#endif
@@ -149,6 +152,11 @@ static inline uint32_t stream_get_duration(void)
149static inline bool stream_can_seek(void) 152static inline bool stream_can_seek(void)
150 { return parser_can_seek(); } 153 { return parser_can_seek(); }
151 154
155static inline void stream_video_stats(struct video_output_stats *s)
156 { video_thread_get_stats(s); }
157
158bool stream_set_callback(long id, void * fn);
159
152/* Keep the disk spinning (for seeking and browsing) */ 160/* Keep the disk spinning (for seeking and browsing) */
153static inline void stream_keep_disk_active(void) 161static inline void stream_keep_disk_active(void)
154{ 162{
diff --git a/apps/plugins/mpegplayer/stream_thread.h b/apps/plugins/mpegplayer/stream_thread.h
index 1d3a445735..5791a49e7f 100644
--- a/apps/plugins/mpegplayer/stream_thread.h
+++ b/apps/plugins/mpegplayer/stream_thread.h
@@ -108,6 +108,8 @@ enum stream_message
108 VIDEO_PRINT_FRAME, /* Print the frame at the current position */ 108 VIDEO_PRINT_FRAME, /* Print the frame at the current position */
109 VIDEO_PRINT_THUMBNAIL, /* Print a thumbnail of the current position */ 109 VIDEO_PRINT_THUMBNAIL, /* Print a thumbnail of the current position */
110 VIDEO_SET_CLIP_RECT, /* Set the visible video area */ 110 VIDEO_SET_CLIP_RECT, /* Set the visible video area */
111 VIDEO_GET_CLIP_RECT, /* Return the visible video area */
112 VIDEO_SET_POST_FRAME_CALLBACK, /* Set a callback after frame is drawn */
111 STREAM_MESSAGE_LAST, 113 STREAM_MESSAGE_LAST,
112}; 114};
113 115
@@ -160,9 +162,20 @@ extern struct stream audio_str IBSS_ATTR;
160 162
161bool video_thread_init(void); 163bool video_thread_init(void);
162void video_thread_exit(void); 164void video_thread_exit(void);
165
166struct video_output_stats
167{
168 int num_drawn; /* Number of frames drawn since reset */
169 int num_skipped; /* Number of frames skipped since reset */
170 int fps; /* fps rate in 100ths of a frame per second */
171};
172
173void video_thread_get_stats(struct video_output_stats *s);
174
163bool audio_thread_init(void); 175bool audio_thread_init(void);
164void audio_thread_exit(void); 176void audio_thread_exit(void);
165 177
178
166/* Some queue function wrappers to keep things clean-ish */ 179/* Some queue function wrappers to keep things clean-ish */
167 180
168/* For stream use only */ 181/* For stream use only */
diff --git a/apps/plugins/mpegplayer/video_out.h b/apps/plugins/mpegplayer/video_out.h
index 808f233ac1..2a3364c382 100644
--- a/apps/plugins/mpegplayer/video_out.h
+++ b/apps/plugins/mpegplayer/video_out.h
@@ -58,8 +58,10 @@ bool vo_show (bool show);
58bool vo_is_visible(void); 58bool vo_is_visible(void);
59void vo_setup (const mpeg2_sequence_t * sequence); 59void vo_setup (const mpeg2_sequence_t * sequence);
60void vo_set_clip_rect(const struct vo_rect *rc); 60void vo_set_clip_rect(const struct vo_rect *rc);
61bool vo_get_clip_rect(struct vo_rect *rc);
61void vo_dimensions(struct vo_ext *sz); 62void vo_dimensions(struct vo_ext *sz);
62void vo_cleanup (void); 63void vo_cleanup (void);
64void vo_set_post_draw_callback(void (*cb)(void));
63 65
64#if NUM_CORES > 1 66#if NUM_CORES > 1
65void vo_lock(void); 67void vo_lock(void);
diff --git a/apps/plugins/mpegplayer/video_out_rockbox.c b/apps/plugins/mpegplayer/video_out_rockbox.c
index fe3deafd01..214bdf3b5c 100644
--- a/apps/plugins/mpegplayer/video_out_rockbox.c
+++ b/apps/plugins/mpegplayer/video_out_rockbox.c
@@ -41,6 +41,7 @@ struct vo_data
41 unsigned flags; 41 unsigned flags;
42 struct vo_rect rc_vid; 42 struct vo_rect rc_vid;
43 struct vo_rect rc_clip; 43 struct vo_rect rc_clip;
44 void (*post_draw_callback)(void);
44}; 45};
45 46
46#if NUM_CORES > 1 47#if NUM_CORES > 1
@@ -80,9 +81,10 @@ static inline void video_unlock(void)
80 81
81 82
82/* Draw a black rectangle if no video frame is available */ 83/* Draw a black rectangle if no video frame is available */
83static void vo_draw_black(void) 84static void vo_draw_black(struct vo_rect *rc)
84{ 85{
85 int foreground; 86 int foreground;
87 int x, y, w, h;
86 88
87 video_lock(); 89 video_lock();
88 90
@@ -90,10 +92,30 @@ static void vo_draw_black(void)
90 92
91 mylcd_set_foreground(MYLCD_BLACK); 93 mylcd_set_foreground(MYLCD_BLACK);
92 94
93 mylcd_fillrect(vo.output_x, vo.output_y, vo.output_width, 95 if (rc)
94 vo.output_height); 96 {
95 mylcd_update_rect(vo.output_x, vo.output_y, vo.output_width, 97 x = rc->l;
96 vo.output_height); 98 y = rc->t;
99 w = rc->r - rc->l;
100 h = rc->b - rc->t;
101 }
102 else
103 {
104#if LCD_WIDTH >= LCD_HEIGHT
105 x = vo.output_x;
106 y = vo.output_y;
107 w = vo.output_width;
108 h = vo.output_height;
109#else
110 x = LCD_WIDTH - vo.output_height - vo.output_y;
111 y = vo.output_x;
112 w = vo.output_height;
113 h = vo.output_width;
114#endif
115 }
116
117 mylcd_fillrect(x, y, w, h);
118 mylcd_update_rect(x, y, w, h);
97 119
98 mylcd_set_foreground(foreground); 120 mylcd_set_foreground(foreground);
99 121
@@ -122,19 +144,22 @@ void vo_draw_frame(uint8_t * const * buf)
122 /* Frame is hidden - either by being set invisible or is clipped 144 /* Frame is hidden - either by being set invisible or is clipped
123 * away - copout */ 145 * away - copout */
124 DEBUGF("vo hidden\n"); 146 DEBUGF("vo hidden\n");
125 return;
126 } 147 }
127 else if (buf == NULL) 148 else if (buf == NULL)
128 { 149 {
129 /* No frame exists - draw black */ 150 /* No frame exists - draw black */
130 vo_draw_black(); 151 vo_draw_black(NULL);
131 DEBUGF("vo no frame\n"); 152 DEBUGF("vo no frame\n");
132 return; 153 }
154 else
155 {
156 yuv_blit(buf, 0, 0, vo.image_width,
157 vo.output_x, vo.output_y, vo.output_width,
158 vo.output_height);
133 } 159 }
134 160
135 yuv_blit(buf, 0, 0, vo.image_width, 161 if (vo.post_draw_callback)
136 vo.output_x, vo.output_y, vo.output_width, 162 vo.post_draw_callback();
137 vo.output_height);
138} 163}
139 164
140static inline void vo_rect_clear_inl(struct vo_rect *rc) 165static 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)
348 int thumb_width, thumb_height; 373 int thumb_width, thumb_height;
349 int thumb_uv_width, thumb_uv_height; 374 int thumb_uv_width, thumb_uv_height;
350 375
351 if (buf == NULL)
352 return false;
353
354 /* Obtain rectangle as clipped to the screen */ 376 /* Obtain rectangle as clipped to the screen */
355 vo_rect_set_ext(&thumb_rc, 0, 0, LCD_WIDTH, LCD_HEIGHT); 377 vo_rect_set_ext(&thumb_rc, 0, 0, LCD_WIDTH, LCD_HEIGHT);
356 if (!vo_rect_intersect(&thumb_rc, rc, &thumb_rc)) 378 if (!vo_rect_intersect(&thumb_rc, rc, &thumb_rc))
357 return true; 379 return true;
358 380
381 if (buf == NULL)
382 goto no_thumb_exit;
383
359 DEBUGF("thumb_rc: %d, %d, %d, %d\n", thumb_rc.l, thumb_rc.t, 384 DEBUGF("thumb_rc: %d, %d, %d, %d\n", thumb_rc.l, thumb_rc.t,
360 thumb_rc.r, thumb_rc.b); 385 thumb_rc.r, thumb_rc.b);
361 386
@@ -377,7 +402,7 @@ bool vo_draw_frame_thumb(uint8_t * const * buf, const struct vo_rect *rc)
377 ) 402 )
378 { 403 {
379 DEBUGF("thumb: insufficient buffer\n"); 404 DEBUGF("thumb: insufficient buffer\n");
380 return false; 405 goto no_thumb_exit;
381 } 406 }
382 407
383 yuv[0] = mem; 408 yuv[0] = mem;
@@ -411,6 +436,10 @@ bool vo_draw_frame_thumb(uint8_t * const * buf, const struct vo_rect *rc)
411#endif /* LCD_WIDTH >= LCD_HEIGHT */ 436#endif /* LCD_WIDTH >= LCD_HEIGHT */
412 437
413 return true; 438 return true;
439
440no_thumb_exit:
441 vo_draw_black(&thumb_rc);
442 return false;
414} 443}
415 444
416void vo_setup(const mpeg2_sequence_t * sequence) 445void vo_setup(const mpeg2_sequence_t * sequence)
@@ -512,6 +541,20 @@ void vo_set_clip_rect(const struct vo_rect *rc)
512 vo.output_height = rc_out.b - rc_out.t; 541 vo.output_height = rc_out.b - rc_out.t;
513} 542}
514 543
544bool vo_get_clip_rect(struct vo_rect *rc)
545{
546 rc->l = vo.output_x;
547 rc->t = vo.output_y;
548 rc->r = rc->l + vo.output_width;
549 rc->b = rc->t + vo.output_height;
550 return (vo.flags & VO_NON_NULL_RECT) != 0;
551}
552
553void vo_set_post_draw_callback(void (*cb)(void))
554{
555 vo.post_draw_callback = cb;
556}
557
515#if NUM_CORES > 1 558#if NUM_CORES > 1
516void vo_lock(void) 559void vo_lock(void)
517{ 560{
diff --git a/apps/plugins/mpegplayer/video_thread.c b/apps/plugins/mpegplayer/video_thread.c
index 69d94f8ba0..aa88590b8e 100644
--- a/apps/plugins/mpegplayer/video_thread.c
+++ b/apps/plugins/mpegplayer/video_thread.c
@@ -37,21 +37,23 @@ struct video_thread_data
37 int state; /* Thread state */ 37 int state; /* Thread state */
38 int status; /* Media status */ 38 int status; /* Media status */
39 struct queue_event ev; /* Our event queue to receive commands */ 39 struct queue_event ev; /* Our event queue to receive commands */
40 int num_drawn; /* Number of frames drawn since reset */
41 int num_skipped; /* Number of frames skipped since reset */
42 uint32_t eta_stream; /* Current time of stream */ 40 uint32_t eta_stream; /* Current time of stream */
43 uint32_t eta_video; /* Time that frame has been scheduled for */ 41 uint32_t eta_video; /* Time that frame has been scheduled for */
44 int32_t eta_early; /* How early has the frame been decoded? */ 42 int32_t eta_early; /* How early has the frame been decoded? */
45 int32_t eta_late; /* How late has the frame been decoded? */ 43 int32_t eta_late; /* How late has the frame been decoded? */
46 int frame_drop_level; /* Drop severity */ 44 int frame_drop_level; /* Drop severity */
47 int skip_level; /* Skip severity */ 45 int skip_level; /* Skip severity */
48 long last_showfps; /* Last time the FPS display was updated */
49 long last_render; /* Last time a frame was drawn */ 46 long last_render; /* Last time a frame was drawn */
50 uint32_t curr_time; /* Current due time of frame */ 47 uint32_t curr_time; /* Current due time of frame */
51 uint32_t period; /* Frame period in clock ticks */ 48 uint32_t period; /* Frame period in clock ticks */
52 int syncf_perfect; /* Last sync fit result */ 49 int syncf_perfect; /* Last sync fit result */
53}; 50};
54 51
52/* Number drawn since reset */
53static int video_num_drawn SHAREDBSS_ATTR;
54/* Number skipped since reset */
55static int video_num_skipped SHAREDBSS_ATTR;
56
55/* TODO: Check if 4KB is appropriate - it works for my test streams, 57/* TODO: Check if 4KB is appropriate - it works for my test streams,
56 so maybe we can reduce it. */ 58 so maybe we can reduce it. */
57#define VIDEO_STACKSIZE (4*1024) 59#define VIDEO_STACKSIZE (4*1024)
@@ -60,35 +62,6 @@ static struct event_queue video_str_queue SHAREDBSS_ATTR;
60static struct queue_sender_list video_str_queue_send SHAREDBSS_ATTR; 62static struct queue_sender_list video_str_queue_send SHAREDBSS_ATTR;
61struct stream video_str IBSS_ATTR; 63struct stream video_str IBSS_ATTR;
62 64
63static void draw_fps(struct video_thread_data *td)
64{
65 uint32_t start;
66 uint32_t clock_ticks = stream_get_ticks(&start);
67 int fps = 0;
68 int buf_pct;
69 char str[80];
70
71 clock_ticks -= start;
72 if (clock_ticks != 0)
73 fps = muldiv_uint32(CLOCK_RATE*100, td->num_drawn, clock_ticks);
74
75 buf_pct = muldiv_uint32(100, pcm_output_used(), PCMOUT_BUFSIZE);
76
77 rb->snprintf(str, sizeof(str), "v:%d.%02d %d %d a:%02d%% %d %d ",
78 /* Video information */
79 fps / 100, fps % 100, td->num_skipped,
80 td->info->display_picture->temporal_reference,
81 /* Audio information */
82 buf_pct, pcm_underruns, pcm_skipped);
83 mylcd_putsxy(0, 0, str);
84
85 vo_lock();
86 mylcd_update_rect(0, 0, LCD_WIDTH, 8);
87 vo_unlock();
88
89 td->last_showfps = *rb->current_tick;
90}
91
92#if defined(DEBUG) || defined(SIMULATOR) 65#if defined(DEBUG) || defined(SIMULATOR)
93static unsigned char pic_coding_type_char(unsigned type) 66static unsigned char pic_coding_type_char(unsigned type)
94{ 67{
@@ -452,6 +425,31 @@ sync_finished:
452 return retval; 425 return retval;
453} 426}
454 427
428static bool frame_print_handler(struct video_thread_data *td)
429{
430 bool retval;
431 uint8_t * const * buf = NULL;
432
433 if (td->info != NULL && td->info->display_fbuf != NULL &&
434 td->syncf_perfect > 0)
435 buf = td->info->display_fbuf->buf;
436
437 if (td->ev.id == VIDEO_PRINT_THUMBNAIL)
438 {
439 /* Print a thumbnail of whatever was last decoded - scale and
440 * position to fill the specified rectangle */
441 retval = vo_draw_frame_thumb(buf, (struct vo_rect *)td->ev.data);
442 }
443 else
444 {
445 /* Print the last frame decoded */
446 vo_draw_frame(buf);
447 retval = buf != NULL;
448 }
449
450 return retval;
451}
452
455/* This only returns to play or quit */ 453/* This only returns to play or quit */
456static void video_thread_msg(struct video_thread_data *td) 454static void video_thread_msg(struct video_thread_data *td)
457{ 455{
@@ -520,8 +518,7 @@ static void video_thread_msg(struct video_thread_data *td)
520 518
521 if (td->ev.data) 519 if (td->ev.data)
522 { 520 {
523 if (td->info != NULL && td->info->display_fbuf != NULL) 521 frame_print_handler(td);
524 vo_draw_frame(td->info->display_fbuf->buf);
525 } 522 }
526 else 523 else
527 { 524 {
@@ -547,10 +544,9 @@ static void video_thread_msg(struct video_thread_data *td)
547 td->eta_late = 0; 544 td->eta_late = 0;
548 td->frame_drop_level = 0; 545 td->frame_drop_level = 0;
549 td->skip_level = 0; 546 td->skip_level = 0;
550 td->num_drawn = 0; 547 td->last_render = *rb->current_tick - HZ;
551 td->num_skipped = 0; 548 video_num_drawn = 0;
552 td->last_showfps = *rb->current_tick - HZ; 549 video_num_skipped = 0;
553 td->last_render = td->last_showfps;
554 550
555 reply = true; 551 reply = true;
556 break; 552 break;
@@ -573,28 +569,17 @@ static void video_thread_msg(struct video_thread_data *td)
573 str_data_notify_received(&video_str); 569 str_data_notify_received(&video_str);
574 break; 570 break;
575 571
572 case VIDEO_PRINT_FRAME:
576 case VIDEO_PRINT_THUMBNAIL: 573 case VIDEO_PRINT_THUMBNAIL:
577 /* Print a thumbnail of whatever was last decoded - scale and 574 reply = frame_print_handler(td);
578 * position to fill the specified rectangle */
579 if (td->info != NULL && td->info->display_fbuf != NULL)
580 {
581 vo_draw_frame_thumb(td->info->display_fbuf->buf,
582 (struct vo_rect *)td->ev.data);
583 reply = true;
584 }
585 break; 575 break;
586 576
587 case VIDEO_SET_CLIP_RECT: 577 case VIDEO_SET_CLIP_RECT:
588 vo_set_clip_rect((const struct vo_rect *)td->ev.data); 578 vo_set_clip_rect((const struct vo_rect *)td->ev.data);
589 break; 579 break;
590 580
591 case VIDEO_PRINT_FRAME: 581 case VIDEO_GET_CLIP_RECT:
592 /* Print the last frame decoded */ 582 reply = vo_get_clip_rect((struct vo_rect *)td->ev.data);
593 if (td->info != NULL && td->info->display_fbuf != NULL)
594 {
595 vo_draw_frame(td->info->display_fbuf->buf);
596 reply = true;
597 }
598 break; 583 break;
599 584
600 case VIDEO_GET_SIZE: 585 case VIDEO_GET_SIZE:
@@ -621,6 +606,11 @@ static void video_thread_msg(struct video_thread_data *td)
621 reply = video_str_scan(td, (struct str_sync_data *)td->ev.data); 606 reply = video_str_scan(td, (struct str_sync_data *)td->ev.data);
622 break; 607 break;
623 608
609 case VIDEO_SET_POST_FRAME_CALLBACK:
610 vo_set_post_draw_callback((void (*)(void))td->ev.data);
611 reply = true;
612 break;
613
624 case STREAM_QUIT: 614 case STREAM_QUIT:
625 /* Time to go - make thread exit */ 615 /* Time to go - make thread exit */
626 td->state = TSTATE_EOS; 616 td->state = TSTATE_EOS;
@@ -802,6 +792,8 @@ static void video_thread(void)
802 if (td.info->display_fbuf == NULL) 792 if (td.info->display_fbuf == NULL)
803 break; /* No picture */ 793 break; /* No picture */
804 794
795 td.syncf_perfect = 1; /* yes, a frame exists */
796
805 /* Get presentation times in audio samples - quite accurate 797 /* Get presentation times in audio samples - quite accurate
806 enough - add previous frame duration if not stamped */ 798 enough - add previous frame duration if not stamped */
807 td.curr_time = (td.info->display_picture->flags & PIC_FLAG_TAGS) ? 799 td.curr_time = (td.info->display_picture->flags & PIC_FLAG_TAGS) ?
@@ -902,8 +894,8 @@ static void video_thread(void)
902 { 894 {
903 /* This frame was set to skip so skip it after having updated 895 /* This frame was set to skip so skip it after having updated
904 timing information */ 896 timing information */
905 td.num_skipped++;
906 td.eta_early = INT32_MIN; 897 td.eta_early = INT32_MIN;
898 video_num_skipped++;
907 goto picture_skip; 899 goto picture_skip;
908 } 900 }
909 901
@@ -913,8 +905,8 @@ static void video_thread(void)
913 /* Render drop was set previously but nothing was dropped in the 905 /* Render drop was set previously but nothing was dropped in the
914 decoder or it's been to long since drawing the last frame. */ 906 decoder or it's been to long since drawing the last frame. */
915 td.skip_level = 0; 907 td.skip_level = 0;
916 td.num_skipped++;
917 td.eta_early = INT32_MIN; 908 td.eta_early = INT32_MIN;
909 video_num_skipped++;
918 goto picture_skip; 910 goto picture_skip;
919 } 911 }
920 912
@@ -970,18 +962,11 @@ static void video_thread(void)
970 picture_draw: 962 picture_draw:
971 /* Record last frame time */ 963 /* Record last frame time */
972 td.last_render = *rb->current_tick; 964 td.last_render = *rb->current_tick;
965
973 vo_draw_frame(td.info->display_fbuf->buf); 966 vo_draw_frame(td.info->display_fbuf->buf);
974 td.num_drawn++; 967 video_num_drawn++;
975 968
976 picture_skip: 969 picture_skip:
977 if (!settings.showfps)
978 break;
979
980 if (TIME_BEFORE(*rb->current_tick, td.last_showfps + HZ))
981 break;
982
983 /* Calculate and display fps */
984 draw_fps(&td);
985 break; 970 break;
986 } 971 }
987 972
@@ -1032,3 +1017,19 @@ void video_thread_exit(void)
1032 video_str.thread = 0; 1017 video_str.thread = 0;
1033 } 1018 }
1034} 1019}
1020
1021
1022/** Misc **/
1023void video_thread_get_stats(struct video_output_stats *s)
1024{
1025 uint32_t start;
1026 uint32_t now = stream_get_ticks(&start);
1027 s->num_drawn = video_num_drawn;
1028 s->num_skipped = video_num_skipped;
1029
1030 s->fps = 0;
1031
1032 if (now > start)
1033 s->fps = muldiv_uint32(CLOCK_RATE*100, s->num_drawn, now - start);
1034}
1035