summaryrefslogtreecommitdiff
path: root/apps/plugins/mpegplayer/mpegplayer.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/plugins/mpegplayer/mpegplayer.c')
-rw-r--r--apps/plugins/mpegplayer/mpegplayer.c219
1 files changed, 113 insertions, 106 deletions
diff --git a/apps/plugins/mpegplayer/mpegplayer.c b/apps/plugins/mpegplayer/mpegplayer.c
index 52d3367..6bd5abf 100644
--- a/apps/plugins/mpegplayer/mpegplayer.c
+++ b/apps/plugins/mpegplayer/mpegplayer.c
@@ -1256,20 +1256,15 @@ static uint32_t video_stack[VIDEO_STACKSIZE / sizeof(uint32_t)] IBSS_ATTR;
static void video_thread(void)
{
- /* Time dither to maximally spread frame drops in time to best
- approximate the appearance of a lower frame rate */
- static const uint32_t time_dither[8] =
- { 1, 4, 7, 2, 5, 8, 3, 6 };
const mpeg2_info_t * info;
mpeg2_state_t state;
char str[80];
- int dither_index = 0;
uint32_t curr_time = 0;
uint32_t period = 0; /* Frame period in clock ticks */
uint32_t eta_audio = UINT_MAX, eta_video = 0;
int32_t eta_early = 0, eta_late = 0;
int frame_drop_level = 0;
- int drop_frame = 0;
+ int skip_level = 0;
int num_skipped = 0;
int num_drawn = 0;
/* Used to decide when to display FPS */
@@ -1293,6 +1288,10 @@ static void video_thread(void)
/* Request the first packet data */
get_next_data( &video_str );
+
+ if (video_str.curr_packet == NULL)
+ goto done;
+
mpeg2_buffer (mpeg2dec, video_str.curr_packet, video_str.curr_packet_end);
total_offset += video_str.curr_packet_end - video_str.curr_packet;
@@ -1346,13 +1345,67 @@ static void video_thread(void)
case STATE_PICTURE:
{
- /* A new picture is available - see if we should draw it */
+ int skip = 0; /* Assume no skip */
+
+ if (frame_drop_level >= 1 || skip_level > 0)
+ {
+ /* A frame will be dropped in the decoder */
+
+ /* Frame type: I/P/B/D */
+ int type = info->current_picture->flags & PIC_MASK_CODING_TYPE;
+
+ switch (type)
+ {
+ case PIC_FLAG_CODING_TYPE_I:
+ case PIC_FLAG_CODING_TYPE_D:
+ /* Level 5: Things are extremely late and all frames will be
+ dropped until the next key frame */
+ if (frame_drop_level >= 1)
+ frame_drop_level = 0; /* Key frame - reset drop level */
+ if (skip_level >= 5)
+ {
+ frame_drop_level = 1;
+ skip_level = 0; /* reset */
+ }
+ break;
+ case PIC_FLAG_CODING_TYPE_P:
+ /* Level 4: Things are very late and all frames will be
+ dropped until the next key frame */
+ if (skip_level >= 4)
+ {
+ frame_drop_level = 1;
+ skip_level = 0; /* reset */
+ }
+ break;
+ case PIC_FLAG_CODING_TYPE_B:
+ /* We want to drop something, so this B frame won't even
+ be decoded. Drawing can happen on the next frame if so
+ desired. Bring the level down as skips are done. */
+ skip = 1;
+ if (skip_level > 0)
+ skip_level--;
+ }
+
+ skip |= frame_drop_level;
+ }
+
+ mpeg2_skip(mpeg2dec, skip);
+ break;
+ }
+
+ case STATE_SLICE:
+ case STATE_END:
+ case STATE_INVALID_END:
+ {
int32_t offset; /* Tick adjustment to keep sync */
- /* No limiting => no dropping so simply make sure skipping is off
- in the decoder and the frame will be drawn */
+ /* draw current picture */
+ if (!info->display_fbuf)
+ break;
+
+ /* No limiting => no dropping - draw this frame */
if (!settings.limitfps)
- goto picture_done;
+ goto picture_draw;
/* Get presentation times in audio samples - quite accurate
enough - add previous frame duration if not stamped */
@@ -1383,7 +1436,7 @@ static void video_thread(void)
offset = eta_video;
eta_video -= offset;
- goto picture_done;
+ goto picture_draw;
}
/** Possibly skip this frame **/
@@ -1444,115 +1497,67 @@ static void video_thread(void)
}
}
- /* If we are more than 167ms behind schedule and it's
- been less than 1/2 second since the last frame, skip frame. */
- dither_index = (dither_index + 1) & 7;
- offset += time_dither[dither_index]*period >> 3;
-
- if (frame_drop_level > 1 || offset > CLOCK_RATE*167/1000)
+ if (info->display_picture->flags & PIC_FLAG_SKIP)
{
- /* Frame type: I/P/B/D */
- int type = info->current_picture->flags & PIC_MASK_CODING_TYPE;
-
- /* Things are running a bit late or all frames are being
- dropped until a key frame */
- if (frame_drop_level > 1)
- {
- switch (type)
- {
- case PIC_FLAG_CODING_TYPE_I:
- case PIC_FLAG_CODING_TYPE_D:
- frame_drop_level = 0; /* This frame can be drawn */
- }
- }
-
- if (frame_drop_level <= 1 && offset > CLOCK_RATE*250/1000)
- {
- /* Things are very, very late. Resort to stronger measures
- to keep sync by dropping a I/D/P frame. Drawing cannot
- take place again until the next key frame. */
- switch (type)
- {
- case PIC_FLAG_CODING_TYPE_I:
- case PIC_FLAG_CODING_TYPE_P:
- case PIC_FLAG_CODING_TYPE_D:
- frame_drop_level = 2;
- }
- }
-
- drop_frame = 1 << frame_drop_level;
-
- if (*rb->current_tick - last_render >= HZ/2)
- {
- /* Timeout has expired and this frame will be drawn if it
- is available. This may reverse the decision to drop a
- key frame above. */
- switch (type)
- {
- default:
- if (frame_drop_level <= 1)
- {
- case PIC_FLAG_CODING_TYPE_I:
- case PIC_FLAG_CODING_TYPE_D:
- drop_frame = 0;
- }
- }
- }
- else if (type == PIC_FLAG_CODING_TYPE_B)
- {
- /* We want to drop something, so this B frame won't even be
- decoded. Drawing can happen on the next frame if so
- desired. Drop level is not affected. */
- drop_frame |= 1 << 1;
- }
-
- if (drop_frame != 0)
- {
- num_skipped++;
- eta_early = INT32_MIN; /* Indicate a dropped frame */
- }
+ /* This frame was set to skip so skip it after having updated
+ timing information */
+ num_skipped++;
+ eta_early = INT32_MIN;
+ goto picture_skip;
}
- picture_done:
- mpeg2_skip(mpeg2dec, drop_frame >> 1);
- break;
+ if (skip_level == 3 && TIME_BEFORE(*rb->current_tick, last_render + HZ/2))
+ {
+ /* Render drop was set previously but nothing was dropped in the
+ decoder or it's been to long since drawing the last frame. */
+ skip_level = 0;
+ num_skipped++;
+ eta_early = INT32_MIN;
+ goto picture_skip;
}
- case STATE_SLICE:
- case STATE_END:
- case STATE_INVALID_END:
- /* draw current picture */
- if (!info->display_fbuf)
- break;
- if (settings.limitfps)
- {
- /* Framerate regulation is turned on - drop it if STATE_PICTURE said
- or wait for it if it's too early to draw it. */
- if (drop_frame != 0)
- {
- drop_frame = 0;
- break;
- }
+ /* At this point a frame _will_ be drawn - a skip may happen on
+ the next however */
+ skip_level = 0;
- /* Wait until audio catches up */
- while (eta_video > eta_audio)
- {
- rb->priority_yield();
+ if (offset > CLOCK_RATE*110/1000)
+ {
+ /* Decide which skip level is needed in order to catch up */
+
+ /* TODO: Calculate this rather than if...else - this is rather
+ exponential though */
+ if (offset > CLOCK_RATE*367/1000)
+ skip_level = 5; /* Decoder skip: I/D */
+ if (offset > CLOCK_RATE*233/1000)
+ skip_level = 4; /* Decoder skip: P */
+ else if (offset > CLOCK_RATE*167/1000)
+ skip_level = 3; /* Render skip */
+ else if (offset > CLOCK_RATE*133/1000)
+ skip_level = 2; /* Decoder skip: B */
+ else
+ skip_level = 1; /* Decoder skip: B */
+ }
- /* Make sure not to get stuck waiting here forever */
- if (videostatus != STREAM_PLAYING)
- goto rendering_finished;
+ /* Wait until audio catches up */
+ while (eta_video > eta_audio)
+ {
+ rb->priority_yield();
- eta_audio = get_stream_time();
- }
+ /* Make sure not to get stuck waiting here forever */
+ if (videostatus != STREAM_PLAYING)
+ goto rendering_finished;
- /* Record last frame time */
- last_render = *rb->current_tick;
+ eta_audio = get_stream_time();
}
+ picture_draw:
+ /* Record last frame time */
+ last_render = *rb->current_tick;
+
vo_draw_frame(info->display_fbuf->buf);
num_drawn++;
+ picture_skip:
if (!settings.showfps)
break;
@@ -1574,6 +1579,8 @@ static void video_thread(void)
last_showfps = *rb->current_tick;
}
break;
+ }
+
default:
break;
}