summaryrefslogtreecommitdiff
path: root/apps
diff options
context:
space:
mode:
Diffstat (limited to 'apps')
-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 }