summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Sevakis <jethead71@rockbox.org>2007-04-18 23:23:18 +0000
committerMichael Sevakis <jethead71@rockbox.org>2007-04-18 23:23:18 +0000
commit01c0fb492fba2aaa2f57b1d80a279b4655ec96cb (patch)
tree3e89454edfd336d09e2de61c4cb28a18bd17ab42
parent0b11d983e7da48f762b51234bc6d65f7a7428465 (diff)
downloadrockbox-01c0fb492fba2aaa2f57b1d80a279b4655ec96cb.tar.gz
rockbox-01c0fb492fba2aaa2f57b1d80a279b4655ec96cb.zip
mpegplayer: Better frame dropping code adapted to the using correct timestamps change. Even smoother frames. Higher FPS and smoother when having to drop than before (Around 15fps regulated for Elephants Dream on x5 which is a dismal situation, up from around 12 or so).
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@13205 a1c6a512-1295-4272-9138-f99709370657
-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 52d33673f4..6bd5abfa45 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;
1256 1256
1257static void video_thread(void) 1257static void video_thread(void)
1258{ 1258{
1259 /* Time dither to maximally spread frame drops in time to best
1260 approximate the appearance of a lower frame rate */
1261 static const uint32_t time_dither[8] =
1262 { 1, 4, 7, 2, 5, 8, 3, 6 };
1263 const mpeg2_info_t * info; 1259 const mpeg2_info_t * info;
1264 mpeg2_state_t state; 1260 mpeg2_state_t state;
1265 char str[80]; 1261 char str[80];
1266 int dither_index = 0;
1267 uint32_t curr_time = 0; 1262 uint32_t curr_time = 0;
1268 uint32_t period = 0; /* Frame period in clock ticks */ 1263 uint32_t period = 0; /* Frame period in clock ticks */
1269 uint32_t eta_audio = UINT_MAX, eta_video = 0; 1264 uint32_t eta_audio = UINT_MAX, eta_video = 0;
1270 int32_t eta_early = 0, eta_late = 0; 1265 int32_t eta_early = 0, eta_late = 0;
1271 int frame_drop_level = 0; 1266 int frame_drop_level = 0;
1272 int drop_frame = 0; 1267 int skip_level = 0;
1273 int num_skipped = 0; 1268 int num_skipped = 0;
1274 int num_drawn = 0; 1269 int num_drawn = 0;
1275 /* Used to decide when to display FPS */ 1270 /* Used to decide when to display FPS */
@@ -1293,6 +1288,10 @@ static void video_thread(void)
1293 1288
1294 /* Request the first packet data */ 1289 /* Request the first packet data */
1295 get_next_data( &video_str ); 1290 get_next_data( &video_str );
1291
1292 if (video_str.curr_packet == NULL)
1293 goto done;
1294
1296 mpeg2_buffer (mpeg2dec, video_str.curr_packet, video_str.curr_packet_end); 1295 mpeg2_buffer (mpeg2dec, video_str.curr_packet, video_str.curr_packet_end);
1297 total_offset += video_str.curr_packet_end - video_str.curr_packet; 1296 total_offset += video_str.curr_packet_end - video_str.curr_packet;
1298 1297
@@ -1346,13 +1345,67 @@ static void video_thread(void)
1346 1345
1347 case STATE_PICTURE: 1346 case STATE_PICTURE:
1348 { 1347 {
1349 /* A new picture is available - see if we should draw it */ 1348 int skip = 0; /* Assume no skip */
1349
1350 if (frame_drop_level >= 1 || skip_level > 0)
1351 {
1352 /* A frame will be dropped in the decoder */
1353
1354 /* Frame type: I/P/B/D */
1355 int type = info->current_picture->flags & PIC_MASK_CODING_TYPE;
1356
1357 switch (type)
1358 {
1359 case PIC_FLAG_CODING_TYPE_I:
1360 case PIC_FLAG_CODING_TYPE_D:
1361 /* Level 5: Things are extremely late and all frames will be
1362 dropped until the next key frame */
1363 if (frame_drop_level >= 1)
1364 frame_drop_level = 0; /* Key frame - reset drop level */
1365 if (skip_level >= 5)
1366 {
1367 frame_drop_level = 1;
1368 skip_level = 0; /* reset */
1369 }
1370 break;
1371 case PIC_FLAG_CODING_TYPE_P:
1372 /* Level 4: Things are very late and all frames will be
1373 dropped until the next key frame */
1374 if (skip_level >= 4)
1375 {
1376 frame_drop_level = 1;
1377 skip_level = 0; /* reset */
1378 }
1379 break;
1380 case PIC_FLAG_CODING_TYPE_B:
1381 /* We want to drop something, so this B frame won't even
1382 be decoded. Drawing can happen on the next frame if so
1383 desired. Bring the level down as skips are done. */
1384 skip = 1;
1385 if (skip_level > 0)
1386 skip_level--;
1387 }
1388
1389 skip |= frame_drop_level;
1390 }
1391
1392 mpeg2_skip(mpeg2dec, skip);
1393 break;
1394 }
1395
1396 case STATE_SLICE:
1397 case STATE_END:
1398 case STATE_INVALID_END:
1399 {
1350 int32_t offset; /* Tick adjustment to keep sync */ 1400 int32_t offset; /* Tick adjustment to keep sync */
1351 1401
1352 /* No limiting => no dropping so simply make sure skipping is off 1402 /* draw current picture */
1353 in the decoder and the frame will be drawn */ 1403 if (!info->display_fbuf)
1404 break;
1405
1406 /* No limiting => no dropping - draw this frame */
1354 if (!settings.limitfps) 1407 if (!settings.limitfps)
1355 goto picture_done; 1408 goto picture_draw;
1356 1409
1357 /* Get presentation times in audio samples - quite accurate 1410 /* Get presentation times in audio samples - quite accurate
1358 enough - add previous frame duration if not stamped */ 1411 enough - add previous frame duration if not stamped */
@@ -1383,7 +1436,7 @@ static void video_thread(void)
1383 offset = eta_video; 1436 offset = eta_video;
1384 1437
1385 eta_video -= offset; 1438 eta_video -= offset;
1386 goto picture_done; 1439 goto picture_draw;
1387 } 1440 }
1388 1441
1389 /** Possibly skip this frame **/ 1442 /** Possibly skip this frame **/
@@ -1444,115 +1497,67 @@ static void video_thread(void)
1444 } 1497 }
1445 } 1498 }
1446 1499
1447 /* If we are more than 167ms behind schedule and it's 1500 if (info->display_picture->flags & PIC_FLAG_SKIP)
1448 been less than 1/2 second since the last frame, skip frame. */
1449 dither_index = (dither_index + 1) & 7;
1450 offset += time_dither[dither_index]*period >> 3;
1451
1452 if (frame_drop_level > 1 || offset > CLOCK_RATE*167/1000)
1453 { 1501 {
1454 /* Frame type: I/P/B/D */ 1502 /* This frame was set to skip so skip it after having updated
1455 int type = info->current_picture->flags & PIC_MASK_CODING_TYPE; 1503 timing information */
1456 1504 num_skipped++;
1457 /* Things are running a bit late or all frames are being 1505 eta_early = INT32_MIN;
1458 dropped until a key frame */ 1506 goto picture_skip;
1459 if (frame_drop_level > 1)
1460 {
1461 switch (type)
1462 {
1463 case PIC_FLAG_CODING_TYPE_I:
1464 case PIC_FLAG_CODING_TYPE_D:
1465 frame_drop_level = 0; /* This frame can be drawn */
1466 }
1467 }
1468
1469 if (frame_drop_level <= 1 && offset > CLOCK_RATE*250/1000)
1470 {
1471 /* Things are very, very late. Resort to stronger measures
1472 to keep sync by dropping a I/D/P frame. Drawing cannot
1473 take place again until the next key frame. */
1474 switch (type)
1475 {
1476 case PIC_FLAG_CODING_TYPE_I:
1477 case PIC_FLAG_CODING_TYPE_P:
1478 case PIC_FLAG_CODING_TYPE_D:
1479 frame_drop_level = 2;
1480 }
1481 }
1482
1483 drop_frame = 1 << frame_drop_level;
1484
1485 if (*rb->current_tick - last_render >= HZ/2)
1486 {
1487 /* Timeout has expired and this frame will be drawn if it
1488 is available. This may reverse the decision to drop a
1489 key frame above. */
1490 switch (type)
1491 {
1492 default:
1493 if (frame_drop_level <= 1)
1494 {
1495 case PIC_FLAG_CODING_TYPE_I:
1496 case PIC_FLAG_CODING_TYPE_D:
1497 drop_frame = 0;
1498 }
1499 }
1500 }
1501 else if (type == PIC_FLAG_CODING_TYPE_B)
1502 {
1503 /* We want to drop something, so this B frame won't even be
1504 decoded. Drawing can happen on the next frame if so
1505 desired. Drop level is not affected. */
1506 drop_frame |= 1 << 1;
1507 }
1508
1509 if (drop_frame != 0)
1510 {
1511 num_skipped++;
1512 eta_early = INT32_MIN; /* Indicate a dropped frame */
1513 }
1514 } 1507 }
1515 1508
1516 picture_done: 1509 if (skip_level == 3 && TIME_BEFORE(*rb->current_tick, last_render + HZ/2))
1517 mpeg2_skip(mpeg2dec, drop_frame >> 1); 1510 {
1518 break; 1511 /* Render drop was set previously but nothing was dropped in the
1512 decoder or it's been to long since drawing the last frame. */
1513 skip_level = 0;
1514 num_skipped++;
1515 eta_early = INT32_MIN;
1516 goto picture_skip;
1519 } 1517 }
1520 case STATE_SLICE:
1521 case STATE_END:
1522 case STATE_INVALID_END:
1523 /* draw current picture */
1524 if (!info->display_fbuf)
1525 break;
1526 1518
1527 if (settings.limitfps) 1519 /* At this point a frame _will_ be drawn - a skip may happen on
1528 { 1520 the next however */
1529 /* Framerate regulation is turned on - drop it if STATE_PICTURE said 1521 skip_level = 0;
1530 or wait for it if it's too early to draw it. */
1531 if (drop_frame != 0)
1532 {
1533 drop_frame = 0;
1534 break;
1535 }
1536 1522
1537 /* Wait until audio catches up */ 1523 if (offset > CLOCK_RATE*110/1000)
1538 while (eta_video > eta_audio) 1524 {
1539 { 1525 /* Decide which skip level is needed in order to catch up */
1540 rb->priority_yield(); 1526
1527 /* TODO: Calculate this rather than if...else - this is rather
1528 exponential though */
1529 if (offset > CLOCK_RATE*367/1000)
1530 skip_level = 5; /* Decoder skip: I/D */
1531 if (offset > CLOCK_RATE*233/1000)
1532 skip_level = 4; /* Decoder skip: P */
1533 else if (offset > CLOCK_RATE*167/1000)
1534 skip_level = 3; /* Render skip */
1535 else if (offset > CLOCK_RATE*133/1000)
1536 skip_level = 2; /* Decoder skip: B */
1537 else
1538 skip_level = 1; /* Decoder skip: B */
1539 }
1541 1540
1542 /* Make sure not to get stuck waiting here forever */ 1541 /* Wait until audio catches up */
1543 if (videostatus != STREAM_PLAYING) 1542 while (eta_video > eta_audio)
1544 goto rendering_finished; 1543 {
1544 rb->priority_yield();
1545 1545
1546 eta_audio = get_stream_time(); 1546 /* Make sure not to get stuck waiting here forever */
1547 } 1547 if (videostatus != STREAM_PLAYING)
1548 goto rendering_finished;
1548 1549
1549 /* Record last frame time */ 1550 eta_audio = get_stream_time();
1550 last_render = *rb->current_tick;
1551 } 1551 }
1552 1552
1553 picture_draw:
1554 /* Record last frame time */
1555 last_render = *rb->current_tick;
1556
1553 vo_draw_frame(info->display_fbuf->buf); 1557 vo_draw_frame(info->display_fbuf->buf);
1554 num_drawn++; 1558 num_drawn++;
1555 1559
1560 picture_skip:
1556 if (!settings.showfps) 1561 if (!settings.showfps)
1557 break; 1562 break;
1558 1563
@@ -1574,6 +1579,8 @@ static void video_thread(void)
1574 last_showfps = *rb->current_tick; 1579 last_showfps = *rb->current_tick;
1575 } 1580 }
1576 break; 1581 break;
1582 }
1583
1577 default: 1584 default:
1578 break; 1585 break;
1579 } 1586 }