diff options
Diffstat (limited to 'apps/plugins/mpegplayer')
-rw-r--r-- | apps/plugins/mpegplayer/mpegplayer.c | 219 |
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 | ||
1257 | static void video_thread(void) | 1257 | static 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 | } |