Originally committed as revision 4521 to svn://svn.ffmpeg.org/ffmpeg/trunk
Unified · Split
| @@ -57,6 +57,7 @@ · 56 unmodified lines | |||
| 57 | 57 | ||
| 58 | #define MAX_VIDEOQ_SIZE (5 * 256 * 1024) | 58 | #define MAX_VIDEOQ_SIZE (5 * 256 * 1024) |
| 59 | #define MAX_AUDIOQ_SIZE (5 * 16 * 1024) | 59 | #define MAX_AUDIOQ_SIZE (5 * 16 * 1024) |
| 60 | #define MAX_SUBTITLEQ_SIZE (5 * 16 * 1024) | ||
| 60 | 61 | ||
| 61 | /* SDL audio buffer size, in samples. Should be small to have precise | 62 | /* SDL audio buffer size, in samples. Should be small to have precise |
| 62 | A/V sync as SDL does not have hardware buffer fullness info. */ | 63 | A/V sync as SDL does not have hardware buffer fullness info. */ |
| @@ -86,6 +87,7 @@ typedef struct PacketQueue { · 23 unmodified lines | |||
| 86 | } PacketQueue; | 87 | } PacketQueue; |
| 87 | 88 | ||
| 88 | #define VIDEO_PICTURE_QUEUE_SIZE 1 | 89 | #define VIDEO_PICTURE_QUEUE_SIZE 1 |
| 90 | #define SUBPICTURE_QUEUE_SIZE 4 | ||
| 89 | 91 | ||
| 90 | typedef struct VideoPicture { | 92 | typedef struct VideoPicture { |
| 91 | double pts; /* presentation time stamp for this picture */ | 93 | double pts; /* presentation time stamp for this picture */ |
| @@ -94,6 +96,11 @@ typedef struct VideoPicture { · 2 unmodified lines | |||
| 94 | int allocated; | 96 | int allocated; |
| 95 | } VideoPicture; | 97 | } VideoPicture; |
| 96 | 98 | ||
| 99 | typedef struct SubPicture { | ||
| 100 | double pts; /* presentation time stamp for this picture */ | ||
| 101 | AVSubtitle sub; | ||
| 102 | } SubPicture; | ||
| 103 | |||
| 97 | enum { | 104 | enum { |
| 98 | AV_SYNC_AUDIO_MASTER, /* default choice */ | 105 | AV_SYNC_AUDIO_MASTER, /* default choice */ |
| 99 | AV_SYNC_VIDEO_MASTER, | 106 | AV_SYNC_VIDEO_MASTER, |
| @@ -142,6 +149,16 @@ typedef struct VideoState { · 42 unmodified lines | |||
| 142 | int sample_array_index; | 149 | int sample_array_index; |
| 143 | int last_i_start; | 150 | int last_i_start; |
| 144 | 151 | ||
| 152 | SDL_Thread *subtitle_tid; | ||
| 153 | int subtitle_stream; | ||
| 154 | int subtitle_stream_changed; | ||
| 155 | AVStream *subtitle_st; | ||
| 156 | PacketQueue subtitleq; | ||
| 157 | SubPicture subpq[SUBPICTURE_QUEUE_SIZE]; | ||
| 158 | int subpq_size, subpq_rindex, subpq_windex; | ||
| 159 | SDL_mutex *subpq_mutex; | ||
| 160 | SDL_cond *subpq_cond; | ||
| 161 | |||
| 145 | double frame_timer; | 162 | double frame_timer; |
| 146 | double frame_last_pts; | 163 | double frame_last_pts; |
| 147 | double frame_last_delay; | 164 | double frame_last_delay; |
| @@ -163,6 +180,7 @@ typedef struct VideoState { · 15 unmodified lines | |||
| 163 | 180 | ||
| 164 | SDL_mutex *video_decoder_mutex; | 181 | SDL_mutex *video_decoder_mutex; |
| 165 | SDL_mutex *audio_decoder_mutex; | 182 | SDL_mutex *audio_decoder_mutex; |
| 183 | SDL_mutex *subtitle_decoder_mutex; | ||
| 166 | 184 | ||
| 167 | // QETimer *video_timer; | 185 | // QETimer *video_timer; |
| 168 | char filename[1024]; | 186 | char filename[1024]; |
| @@ -371,12 +389,270 @@ void fill_border(VideoState *s, int x, int y, int w, int h, int color) · 202 unmodified lines | |||
| 371 | } | 389 | } |
| 372 | #endif | 390 | #endif |
| 373 | 391 | ||
| 392 | |||
| 393 | |||
| 394 | #define SCALEBITS 10 | ||
| 395 | #define ONE_HALF (1 << (SCALEBITS - 1)) | ||
| 396 | #define FIX(x) ((int) ((x) * (1<<SCALEBITS) + 0.5)) | ||
| 397 | |||
| 398 | #define RGB_TO_Y_CCIR(r, g, b) \ | ||
| 399 | ((FIX(0.29900*219.0/255.0) * (r) + FIX(0.58700*219.0/255.0) * (g) + \ | ||
| 400 | FIX(0.11400*219.0/255.0) * (b) + (ONE_HALF + (16 << SCALEBITS))) >> SCALEBITS) | ||
| 401 | |||
| 402 | #define RGB_TO_U_CCIR(r1, g1, b1, shift)\ | ||
| 403 | (((- FIX(0.16874*224.0/255.0) * r1 - FIX(0.33126*224.0/255.0) * g1 + \ | ||
| 404 | FIX(0.50000*224.0/255.0) * b1 + (ONE_HALF << shift) - 1) >> (SCALEBITS + shift)) + 128) | ||
| 405 | |||
| 406 | #define RGB_TO_V_CCIR(r1, g1, b1, shift)\ | ||
| 407 | (((FIX(0.50000*224.0/255.0) * r1 - FIX(0.41869*224.0/255.0) * g1 - \ | ||
| 408 | FIX(0.08131*224.0/255.0) * b1 + (ONE_HALF << shift) - 1) >> (SCALEBITS + shift)) + 128) | ||
| 409 | |||
| 410 | #define ALPHA_BLEND(a, oldp, newp, s)\ | ||
| 411 | ((((oldp << s) * (255 - (a))) + (newp * (a))) / (255 << s)) | ||
| 412 | |||
| 413 | #define RGBA_IN(r, g, b, a, s)\ | ||
| 414 | {\ | ||
| 415 | unsigned int v = ((const uint32_t *)(s))[0];\ | ||
| 416 | a = (v >> 24) & 0xff;\ | ||
| 417 | r = (v >> 16) & 0xff;\ | ||
| 418 | g = (v >> 8) & 0xff;\ | ||
| 419 | b = v & 0xff;\ | ||
| 420 | } | ||
| 421 | |||
| 422 | #define YUVA_IN(y, u, v, a, s, pal)\ | ||
| 423 | {\ | ||
| 424 | unsigned int val = ((const uint32_t *)(pal))[*(const uint8_t*)s];\ | ||
| 425 | a = (val >> 24) & 0xff;\ | ||
| 426 | y = (val >> 16) & 0xff;\ | ||
| 427 | u = (val >> 8) & 0xff;\ | ||
| 428 | v = val & 0xff;\ | ||
| 429 | } | ||
| 430 | |||
| 431 | #define YUVA_OUT(d, y, u, v, a)\ | ||
| 432 | {\ | ||
| 433 | ((uint32_t *)(d))[0] = (a << 24) | (y << 16) | (u << 8) | v;\ | ||
| 434 | } | ||
| 435 | |||
| 436 | |||
| 437 | #define BPP 1 | ||
| 438 | |||
| 439 | static void blend_subrect(AVPicture *dst, const AVSubtitleRect *rect) | ||
| 440 | { | ||
| 441 | int wrap, wrap3, width2, skip2; | ||
| 442 | int y, u, v, a, u1, v1, a1, w, h; | ||
| 443 | uint8_t *lum, *cb, *cr; | ||
| 444 | const uint8_t *p; | ||
| 445 | const uint32_t *pal; | ||
| 446 | |||
| 447 | lum = dst->data[0] + rect->y * dst->linesize[0]; | ||
| 448 | cb = dst->data[1] + (rect->y >> 1) * dst->linesize[1]; | ||
| 449 | cr = dst->data[2] + (rect->y >> 1) * dst->linesize[2]; | ||
| 450 | |||
| 451 | width2 = (rect->w + 1) >> 1; | ||
| 452 | skip2 = rect->x >> 1; | ||
| 453 | wrap = dst->linesize[0]; | ||
| 454 | wrap3 = rect->linesize; | ||
| 455 | p = rect->bitmap; | ||
| 456 | pal = rect->rgba_palette; /* Now in YCrCb! */ | ||
| 457 | |||
| 458 | if (rect->y & 1) { | ||
| 459 | lum += rect->x; | ||
| 460 | cb += skip2; | ||
| 461 | cr += skip2; | ||
| 462 | |||
| 463 | if (rect->x & 1) { | ||
| 464 | YUVA_IN(y, u, v, a, p, pal); | ||
| 465 | lum[0] = ALPHA_BLEND(a, lum[0], y, 0); | ||
| 466 | cb[0] = ALPHA_BLEND(a >> 2, cb[0], u, 0); | ||
| 467 | cr[0] = ALPHA_BLEND(a >> 2, cr[0], v, 0); | ||
| 468 | cb++; | ||
| 469 | cr++; | ||
| 470 | lum++; | ||
| 471 | p += BPP; | ||
| 472 | } | ||
| 473 | for(w = rect->w - (rect->x & 1); w >= 2; w -= 2) { | ||
| 474 | YUVA_IN(y, u, v, a, p, pal); | ||
| 475 | u1 = u; | ||
| 476 | v1 = v; | ||
| 477 | a1 = a; | ||
| 478 | lum[0] = ALPHA_BLEND(a, lum[0], y, 0); | ||
| 479 | |||
| 480 | YUVA_IN(y, u, v, a, p + BPP, pal); | ||
| 481 | u1 += u; | ||
| 482 | v1 += v; | ||
| 483 | a1 += a; | ||
| 484 | lum[1] = ALPHA_BLEND(a, lum[1], y, 0); | ||
| 485 | cb[0] = ALPHA_BLEND(a1 >> 2, cb[0], u1, 1); | ||
| 486 | cr[0] = ALPHA_BLEND(a1 >> 2, cr[0], v1, 1); | ||
| 487 | cb++; | ||
| 488 | cr++; | ||
| 489 | p += 2 * BPP; | ||
| 490 | lum += 2; | ||
| 491 | } | ||
| 492 | if (w) { | ||
| 493 | YUVA_IN(y, u, v, a, p, pal); | ||
| 494 | lum[0] = ALPHA_BLEND(a, lum[0], y, 0); | ||
| 495 | cb[0] = ALPHA_BLEND(a >> 2, cb[0], u, 0); | ||
| 496 | cr[0] = ALPHA_BLEND(a >> 2, cr[0], v, 0); | ||
| 497 | } | ||
| 498 | p += wrap3 + (wrap3 - rect->w * BPP); | ||
| 499 | lum += wrap + (wrap - rect->w - rect->x); | ||
| 500 | cb += dst->linesize[1] - width2 - skip2; | ||
| 501 | cr += dst->linesize[2] - width2 - skip2; | ||
| 502 | } | ||
| 503 | for(h = rect->h - (rect->y & 1); h >= 2; h -= 2) { | ||
| 504 | lum += rect->x; | ||
| 505 | cb += skip2; | ||
| 506 | cr += skip2; | ||
| 507 | |||
| 508 | if (rect->x & 1) { | ||
| 509 | YUVA_IN(y, u, v, a, p, pal); | ||
| 510 | u1 = u; | ||
| 511 | v1 = v; | ||
| 512 | a1 = a; | ||
| 513 | lum[0] = ALPHA_BLEND(a, lum[0], y, 0); | ||
| 514 | p += wrap3; | ||
| 515 | lum += wrap; | ||
| 516 | YUVA_IN(y, u, v, a, p, pal); | ||
| 517 | u1 += u; | ||
| 518 | v1 += v; | ||
| 519 | a1 += a; | ||
| 520 | lum[0] = ALPHA_BLEND(a, lum[0], y, 0); | ||
| 521 | cb[0] = ALPHA_BLEND(a1 >> 2, cb[0], u1, 1); | ||
| 522 | cr[0] = ALPHA_BLEND(a1 >> 2, cr[0], v1, 1); | ||
| 523 | cb++; | ||
| 524 | cr++; | ||
| 525 | p += -wrap3 + BPP; | ||
| 526 | lum += -wrap + 1; | ||
| 527 | } | ||
| 528 | for(w = rect->w - (rect->x & 1); w >= 2; w -= 2) { | ||
| 529 | YUVA_IN(y, u, v, a, p, pal); | ||
| 530 | u1 = u; | ||
| 531 | v1 = v; | ||
| 532 | a1 = a; | ||
| 533 | lum[0] = ALPHA_BLEND(a, lum[0], y, 0); | ||
| 534 | |||
| 535 | YUVA_IN(y, u, v, a, p, pal); | ||
| 536 | u1 += u; | ||
| 537 | v1 += v; | ||
| 538 | a1 += a; | ||
| 539 | lum[1] = ALPHA_BLEND(a, lum[1], y, 0); | ||
| 540 | p += wrap3; | ||
| 541 | lum += wrap; | ||
| 542 | |||
| 543 | YUVA_IN(y, u, v, a, p, pal); | ||
| 544 | u1 += u; | ||
| 545 | v1 += v; | ||
| 546 | a1 += a; | ||
| 547 | lum[0] = ALPHA_BLEND(a, lum[0], y, 0); | ||
| 548 | |||
| 549 | YUVA_IN(y, u, v, a, p, pal); | ||
| 550 | u1 += u; | ||
| 551 | v1 += v; | ||
| 552 | a1 += a; | ||
| 553 | lum[1] = ALPHA_BLEND(a, lum[1], y, 0); | ||
| 554 | |||
| 555 | cb[0] = ALPHA_BLEND(a1 >> 2, cb[0], u1, 2); | ||
| 556 | cr[0] = ALPHA_BLEND(a1 >> 2, cr[0], v1, 2); | ||
| 557 | |||
| 558 | cb++; | ||
| 559 | cr++; | ||
| 560 | p += -wrap3 + 2 * BPP; | ||
| 561 | lum += -wrap + 2; | ||
| 562 | } | ||
| 563 | if (w) { | ||
| 564 | YUVA_IN(y, u, v, a, p, pal); | ||
| 565 | u1 = u; | ||
| 566 | v1 = v; | ||
| 567 | a1 = a; | ||
| 568 | lum[0] = ALPHA_BLEND(a, lum[0], y, 0); | ||
| 569 | p += wrap3; | ||
| 570 | lum += wrap; | ||
| 571 | YUVA_IN(y, u, v, a, p, pal); | ||
| 572 | u1 += u; | ||
| 573 | v1 += v; | ||
| 574 | a1 += a; | ||
| 575 | lum[0] = ALPHA_BLEND(a, lum[0], y, 0); | ||
| 576 | cb[0] = ALPHA_BLEND(a1 >> 2, cb[0], u1, 1); | ||
| 577 | cr[0] = ALPHA_BLEND(a1 >> 2, cr[0], v1, 1); | ||
| 578 | cb++; | ||
| 579 | cr++; | ||
| 580 | p += -wrap3 + BPP; | ||
| 581 | lum += -wrap + 1; | ||
| 582 | } | ||
| 583 | p += wrap3 + (wrap3 - rect->w * BPP); | ||
| 584 | lum += wrap + (wrap - rect->w - rect->x); | ||
| 585 | cb += dst->linesize[1] - width2 - skip2; | ||
| 586 | cr += dst->linesize[2] - width2 - skip2; | ||
| 587 | } | ||
| 588 | /* handle odd height */ | ||
| 589 | if (h) { | ||
| 590 | lum += rect->x; | ||
| 591 | cb += skip2; | ||
| 592 | cr += skip2; | ||
| 593 | |||
| 594 | if (rect->x & 1) { | ||
| 595 | YUVA_IN(y, u, v, a, p, pal); | ||
| 596 | lum[0] = ALPHA_BLEND(a, lum[0], y, 0); | ||
| 597 | cb[0] = ALPHA_BLEND(a >> 2, cb[0], u, 0); | ||
| 598 | cr[0] = ALPHA_BLEND(a >> 2, cr[0], v, 0); | ||
| 599 | cb++; | ||
| 600 | cr++; | ||
| 601 | lum++; | ||
| 602 | p += BPP; | ||
| 603 | } | ||
| 604 | for(w = rect->w - (rect->x & 1); w >= 2; w -= 2) { | ||
| 605 | YUVA_IN(y, u, v, a, p, pal); | ||
| 606 | u1 = u; | ||
| 607 | v1 = v; | ||
| 608 | a1 = a; | ||
| 609 | lum[0] = ALPHA_BLEND(a, lum[0], y, 0); | ||
| 610 | |||
| 611 | YUVA_IN(y, u, v, a, p + BPP, pal); | ||
| 612 | u1 += u; | ||
| 613 | v1 += v; | ||
| 614 | a1 += a; | ||
| 615 | lum[1] = ALPHA_BLEND(a, lum[1], y, 0); | ||
| 616 | cb[0] = ALPHA_BLEND(a1 >> 2, cb[0], u, 1); | ||
| 617 | cr[0] = ALPHA_BLEND(a1 >> 2, cr[0], v, 1); | ||
| 618 | cb++; | ||
| 619 | cr++; | ||
| 620 | p += 2 * BPP; | ||
| 621 | lum += 2; | ||
| 622 | } | ||
| 623 | if (w) { | ||
| 624 | YUVA_IN(y, u, v, a, p, pal); | ||
| 625 | lum[0] = ALPHA_BLEND(a, lum[0], y, 0); | ||
| 626 | cb[0] = ALPHA_BLEND(a >> 2, cb[0], u, 0); | ||
| 627 | cr[0] = ALPHA_BLEND(a >> 2, cr[0], v, 0); | ||
| 628 | } | ||
| 629 | } | ||
| 630 | } | ||
| 631 | |||
| 632 | static void free_subpicture(SubPicture *sp) | ||
| 633 | { | ||
| 634 | int i; | ||
| 635 | |||
| 636 | for (i = 0; i < sp->sub.num_rects; i++) | ||
| 637 | { | ||
| 638 | av_free(sp->sub.rects[i].bitmap); | ||
| 639 | av_free(sp->sub.rects[i].rgba_palette); | ||
| 640 | } | ||
| 641 | |||
| 642 | av_free(sp->sub.rects); | ||
| 643 | |||
| 644 | memset(&sp->sub, 0, sizeof(AVSubtitle)); | ||
| 645 | } | ||
| 646 | |||
| 374 | static void video_image_display(VideoState *is) | 647 | static void video_image_display(VideoState *is) |
| 375 | { | 648 | { |
| 376 | VideoPicture *vp; | 649 | VideoPicture *vp; |
| 650 | SubPicture *sp; | ||
| 651 | AVPicture pict; | ||
| 377 | float aspect_ratio; | 652 | float aspect_ratio; |
| 378 | int width, height, x, y; | 653 | int width, height, x, y; |
| 379 | SDL_Rect rect; | 654 | SDL_Rect rect; |
| 655 | int i; | ||
| 380 | 656 | ||
| 381 | vp = &is->pictq[is->pictq_rindex]; | 657 | vp = &is->pictq[is->pictq_rindex]; |
| 382 | if (vp->bmp) { | 658 | if (vp->bmp) { |
| @@ -424,6 +700,33 @@ static void video_image_display(VideoState *is) · 41 unmodified lines | |||
| 424 | } | 700 | } |
| 425 | #endif | 701 | #endif |
| 426 | 702 | ||
| 703 | if (is->subtitle_st) | ||
| 704 | { | ||
| 705 | if (is->subpq_size > 0) | ||
| 706 | { | ||
| 707 | sp = &is->subpq[is->subpq_rindex]; | ||
| 708 | |||
| 709 | if (vp->pts >= sp->pts + ((float) sp->sub.start_display_time / 1000)) | ||
| 710 | { | ||
| 711 | SDL_LockYUVOverlay (vp->bmp); | ||
| 712 | |||
| 713 | pict.data[0] = vp->bmp->pixels[0]; | ||
| 714 | pict.data[1] = vp->bmp->pixels[2]; | ||
| 715 | pict.data[2] = vp->bmp->pixels[1]; | ||
| 716 | |||
| 717 | pict.linesize[0] = vp->bmp->pitches[0]; | ||
| 718 | pict.linesize[1] = vp->bmp->pitches[2]; | ||
| 719 | pict.linesize[2] = vp->bmp->pitches[1]; | ||
| 720 | |||
| 721 | for (i = 0; i < sp->sub.num_rects; i++) | ||
| 722 | blend_subrect(&pict, &sp->sub.rects[i]); | ||
| 723 | |||
| 724 | SDL_UnlockYUVOverlay (vp->bmp); | ||
| 725 | } | ||
| 726 | } | ||
| 727 | } | ||
| 728 | |||
| 729 | |||
| 427 | /* XXX: we suppose the screen has a 1.0 pixel ratio */ | 730 | /* XXX: we suppose the screen has a 1.0 pixel ratio */ |
| 428 | height = is->height; | 731 | height = is->height; |
| 429 | width = ((int)rint(height * aspect_ratio)) & -3; | 732 | width = ((int)rint(height * aspect_ratio)) & -3; |
| @@ -642,6 +945,7 @@ static void video_refresh_timer(void *opaque) · 212 unmodified lines | |||
| 642 | VideoPicture *vp; | 945 | VideoPicture *vp; |
| 643 | double actual_delay, delay, sync_threshold, ref_clock, diff; | 946 | double actual_delay, delay, sync_threshold, ref_clock, diff; |
| 644 | 947 | ||
| 948 | SubPicture *sp, *sp2; | ||
| 645 | 949 | ||
| 646 | if (is->video_st) { | 950 | if (is->video_st) { |
| 647 | if (is->pictq_size == 0) { | 951 | if (is->pictq_size == 0) { |
| @@ -702,6 +1006,50 @@ static void video_refresh_timer(void *opaque) · 54 unmodified lines | |||
| 702 | delay, actual_delay, vp->pts, -diff); | 1006 | delay, actual_delay, vp->pts, -diff); |
| 703 | #endif | 1007 | #endif |
| 704 | 1008 | ||
| 1009 | if(is->subtitle_st) { | ||
| 1010 | if (is->subtitle_stream_changed) { | ||
| 1011 | SDL_LockMutex(is->subpq_mutex); | ||
| 1012 | |||
| 1013 | while (is->subpq_size) { | ||
| 1014 | free_subpicture(&is->subpq[is->subpq_rindex]); | ||
| 1015 | |||
| 1016 | /* update queue size and signal for next picture */ | ||
| 1017 | if (++is->subpq_rindex == SUBPICTURE_QUEUE_SIZE) | ||
| 1018 | is->subpq_rindex = 0; | ||
| 1019 | |||
| 1020 | is->subpq_size--; | ||
| 1021 | } | ||
| 1022 | is->subtitle_stream_changed = 0; | ||
| 1023 | |||
| 1024 | SDL_CondSignal(is->subpq_cond); | ||
| 1025 | SDL_UnlockMutex(is->subpq_mutex); | ||
| 1026 | } else { | ||
| 1027 | if (is->subpq_size > 0) { | ||
| 1028 | sp = &is->subpq[is->subpq_rindex]; | ||
| 1029 | |||
| 1030 | if (is->subpq_size > 1) | ||
| 1031 | sp2 = &is->subpq[(is->subpq_rindex + 1) % SUBPICTURE_QUEUE_SIZE]; | ||
| 1032 | else | ||
| 1033 | sp2 = NULL; | ||
| 1034 | |||
| 1035 | if ((is->video_current_pts > (sp->pts + ((float) sp->sub.end_display_time / 1000))) | ||
| 1036 | || (sp2 && is->video_current_pts > (sp2->pts + ((float) sp2->sub.start_display_time / 1000)))) | ||
| 1037 | { | ||
| 1038 | free_subpicture(sp); | ||
| 1039 | |||
| 1040 | /* update queue size and signal for next picture */ | ||
| 1041 | if (++is->subpq_rindex == SUBPICTURE_QUEUE_SIZE) | ||
| 1042 | is->subpq_rindex = 0; | ||
| 1043 | |||
| 1044 | SDL_LockMutex(is->subpq_mutex); | ||
| 1045 | is->subpq_size--; | ||
| 1046 | SDL_CondSignal(is->subpq_cond); | ||
| 1047 | SDL_UnlockMutex(is->subpq_mutex); | ||
| 1048 | } | ||
| 1049 | } | ||
| 1050 | } | ||
| 1051 | } | ||
| 1052 | |||
| 705 | /* display picture */ | 1053 | /* display picture */ |
| 706 | video_display(is); | 1054 | video_display(is); |
| 707 | 1055 | ||
| @@ -730,22 +1078,25 @@ static void video_refresh_timer(void *opaque) · 22 unmodified lines | |||
| 730 | if (show_status) { | 1078 | if (show_status) { |
| 731 | static int64_t last_time; | 1079 | static int64_t last_time; |
| 732 | int64_t cur_time; | 1080 | int64_t cur_time; |
| 733 | int aqsize, vqsize; | 1081 | int aqsize, vqsize, sqsize; |
| 734 | double av_diff; | 1082 | double av_diff; |
| 735 | 1083 | ||
| 736 | cur_time = av_gettime(); | 1084 | cur_time = av_gettime(); |
| 737 | if (!last_time || (cur_time - last_time) >= 500 * 1000) { | 1085 | if (!last_time || (cur_time - last_time) >= 500 * 1000) { |
| 738 | aqsize = 0; | 1086 | aqsize = 0; |
| 739 | vqsize = 0; | 1087 | vqsize = 0; |
| 1088 | sqsize = 0; | ||
| 740 | if (is->audio_st) | 1089 | if (is->audio_st) |
| 741 | aqsize = is->audioq.size; | 1090 | aqsize = is->audioq.size; |
| 742 | if (is->video_st) | 1091 | if (is->video_st) |
| 743 | vqsize = is->videoq.size; | 1092 | vqsize = is->videoq.size; |
| 1093 | if (is->subtitle_st) | ||
| 1094 | sqsize = is->subtitleq.size; | ||
| 744 | av_diff = 0; | 1095 | av_diff = 0; |
| 745 | if (is->audio_st && is->video_st) | 1096 | if (is->audio_st && is->video_st) |
| 746 | av_diff = get_audio_clock(is) - get_video_clock(is); | 1097 | av_diff = get_audio_clock(is) - get_video_clock(is); |
| 747 | printf("%7.2f A-V:%7.3f aq=%5dKB vq=%5dKB \r", | 1098 | printf("%7.2f A-V:%7.3f aq=%5dKB vq=%5dKB sq=%5dB \r", |
| 748 | get_master_clock(is), av_diff, aqsize / 1024, vqsize / 1024); | 1099 | get_master_clock(is), av_diff, aqsize / 1024, vqsize / 1024, sqsize); |
| 749 | fflush(stdout); | 1100 | fflush(stdout); |
| 750 | last_time = cur_time; | 1101 | last_time = cur_time; |
| 751 | } | 1102 | } |
| @@ -948,6 +1299,79 @@ static int video_thread(void *arg) · 196 unmodified lines | |||
| 948 | return 0; | 1299 | return 0; |
| 949 | } | 1300 | } |
| 950 | 1301 | ||
| 1302 | static int subtitle_thread(void *arg) | ||
| 1303 | { | ||
| 1304 | VideoState *is = arg; | ||
| 1305 | SubPicture *sp; | ||
| 1306 | AVPacket pkt1, *pkt = &pkt1; | ||
| 1307 | int len1, got_subtitle; | ||
| 1308 | double pts; | ||
| 1309 | int i, j; | ||
| 1310 | int r, g, b, y, u, v, a; | ||
| 1311 | |||
| 1312 | for(;;) { | ||
| 1313 | while (is->paused && !is->subtitleq.abort_request) { | ||
| 1314 | SDL_Delay(10); | ||
| 1315 | } | ||
| 1316 | if (packet_queue_get(&is->subtitleq, pkt, 1) < 0) | ||
| 1317 | break; | ||
| 1318 | |||
| 1319 | SDL_LockMutex(is->subpq_mutex); | ||
| 1320 | while (is->subpq_size >= SUBPICTURE_QUEUE_SIZE && | ||
| 1321 | !is->subtitleq.abort_request) { | ||
| 1322 | SDL_CondWait(is->subpq_cond, is->subpq_mutex); | ||
| 1323 | } | ||
| 1324 | SDL_UnlockMutex(is->subpq_mutex); | ||
| 1325 | |||
| 1326 | if (is->subtitleq.abort_request) | ||
| 1327 | goto the_end; | ||
| 1328 | |||
| 1329 | sp = &is->subpq[is->subpq_windex]; | ||
| 1330 | |||
| 1331 | /* NOTE: ipts is the PTS of the _first_ picture beginning in | ||
| 1332 | this packet, if any */ | ||
| 1333 | pts = 0; | ||
| 1334 | if (pkt->pts != AV_NOPTS_VALUE) | ||
| 1335 | pts = av_q2d(is->subtitle_st->time_base)*pkt->pts; | ||
| 1336 | |||
| 1337 | SDL_LockMutex(is->subtitle_decoder_mutex); | ||
| 1338 | len1 = avcodec_decode_subtitle(is->subtitle_st->codec, | ||
| 1339 | &sp->sub, &got_subtitle, | ||
| 1340 | pkt->data, pkt->size); | ||
| 1341 | SDL_UnlockMutex(is->subtitle_decoder_mutex); | ||
| 1342 | // if (len1 < 0) | ||
| 1343 | // break; | ||
| 1344 | if (got_subtitle && sp->sub.format == 0) { | ||
| 1345 | sp->pts = pts; | ||
| 1346 | |||
| 1347 | for (i = 0; i < sp->sub.num_rects; i++) | ||
| 1348 | { | ||
| 1349 | for (j = 0; j < sp->sub.rects[i].nb_colors; j++) | ||
| 1350 | { | ||
| 1351 | RGBA_IN(r, g, b, a, sp->sub.rects[i].rgba_palette + j); | ||
| 1352 | y = RGB_TO_Y_CCIR(r, g, b); | ||
| 1353 | u = RGB_TO_U_CCIR(r, g, b, 0); | ||
| 1354 | v = RGB_TO_V_CCIR(r, g, b, 0); | ||
| 1355 | YUVA_OUT(sp->sub.rects[i].rgba_palette + j, y, u, v, a); | ||
| 1356 | } | ||
| 1357 | } | ||
| 1358 | |||
| 1359 | /* now we can update the picture count */ | ||
| 1360 | if (++is->subpq_windex == SUBPICTURE_QUEUE_SIZE) | ||
| 1361 | is->subpq_windex = 0; | ||
| 1362 | SDL_LockMutex(is->subpq_mutex); | ||
| 1363 | is->subpq_size++; | ||
| 1364 | SDL_UnlockMutex(is->subpq_mutex); | ||
| 1365 | } | ||
| 1366 | av_free_packet(pkt); | ||
| 1367 | // if (step) | ||
| 1368 | // if (cur_stream) | ||
| 1369 | // stream_pause(cur_stream); | ||
| 1370 | } | ||
| 1371 | the_end: | ||
| 1372 | return 0; | ||
| 1373 | } | ||
| 1374 | |||
| 951 | /* copy samples for viewing in editor window */ | 1375 | /* copy samples for viewing in editor window */ |
| 952 | static void update_sample_display(VideoState *is, short *samples, int samples_size) | 1376 | static void update_sample_display(VideoState *is, short *samples, int samples_size) |
| 953 | { | 1377 | { |
| @@ -1237,6 +1661,13 @@ static int stream_component_open(VideoState *is, int stream_index) · 283 unmodified lines | |||
| 1237 | packet_queue_init(&is->videoq); | 1661 | packet_queue_init(&is->videoq); |
| 1238 | is->video_tid = SDL_CreateThread(video_thread, is); | 1662 | is->video_tid = SDL_CreateThread(video_thread, is); |
| 1239 | break; | 1663 | break; |
| 1664 | case CODEC_TYPE_SUBTITLE: | ||
| 1665 | is->subtitle_stream = stream_index; | ||
| 1666 | is->subtitle_st = ic->streams[stream_index]; | ||
| 1667 | packet_queue_init(&is->subtitleq); | ||
| 1668 | |||
| 1669 | is->subtitle_tid = SDL_CreateThread(subtitle_thread, is); | ||
| 1670 | break; | ||
| 1240 | default: | 1671 | default: |
| 1241 | break; | 1672 | break; |
| 1242 | } | 1673 | } |
| @@ -1248,6 +1679,8 @@ static void stream_component_close(VideoState *is, int stream_index) · 5 unmodified lines | |||
| 1248 | AVFormatContext *ic = is->ic; | 1679 | AVFormatContext *ic = is->ic; |
| 1249 | AVCodecContext *enc; | 1680 | AVCodecContext *enc; |
| 1250 | 1681 | ||
| 1682 | if (stream_index < 0 || stream_index >= ic->nb_streams) | ||
| 1683 | return; | ||
| 1251 | enc = ic->streams[stream_index]->codec; | 1684 | enc = ic->streams[stream_index]->codec; |
| 1252 | 1685 | ||
| 1253 | switch(enc->codec_type) { | 1686 | switch(enc->codec_type) { |
| @@ -1271,6 +1704,21 @@ static void stream_component_close(VideoState *is, int stream_index) · 17 unmodified lines | |||
| 1271 | 1704 | ||
| 1272 | packet_queue_end(&is->videoq); | 1705 | packet_queue_end(&is->videoq); |
| 1273 | break; | 1706 | break; |
| 1707 | case CODEC_TYPE_SUBTITLE: | ||
| 1708 | packet_queue_abort(&is->subtitleq); | ||
| 1709 | |||
| 1710 | /* note: we also signal this mutex to make sure we deblock the | ||
| 1711 | video thread in all cases */ | ||
| 1712 | SDL_LockMutex(is->subpq_mutex); | ||
| 1713 | is->subtitle_stream_changed = 1; | ||
| 1714 | |||
| 1715 | SDL_CondSignal(is->subpq_cond); | ||
| 1716 | SDL_UnlockMutex(is->subpq_mutex); | ||
| 1717 | |||
| 1718 | SDL_WaitThread(is->subtitle_tid, NULL); | ||
| 1719 | |||
| 1720 | packet_queue_end(&is->subtitleq); | ||
| 1721 | break; | ||
| 1274 | default: | 1722 | default: |
| 1275 | break; | 1723 | break; |
| 1276 | } | 1724 | } |
| @@ -1285,6 +1733,10 @@ static void stream_component_close(VideoState *is, int stream_index) · 8 unmodified lines | |||
| 1285 | is->video_st = NULL; | 1733 | is->video_st = NULL; |
| 1286 | is->video_stream = -1; | 1734 | is->video_stream = -1; |
| 1287 | break; | 1735 | break; |
| 1736 | case CODEC_TYPE_SUBTITLE: | ||
| 1737 | is->subtitle_st = NULL; | ||
| 1738 | is->subtitle_stream = -1; | ||
| 1739 | break; | ||
| 1288 | default: | 1740 | default: |
| 1289 | break; | 1741 | break; |
| 1290 | } | 1742 | } |
| @@ -1328,6 +1780,7 @@ static int decode_thread(void *arg) · 37 unmodified lines | |||
| 1328 | audio_index = -1; | 1780 | audio_index = -1; |
| 1329 | is->video_stream = -1; | 1781 | is->video_stream = -1; |
| 1330 | is->audio_stream = -1; | 1782 | is->audio_stream = -1; |
| 1783 | is->subtitle_stream = -1; | ||
| 1331 | 1784 | ||
| 1332 | global_video_state = is; | 1785 | global_video_state = is; |
| 1333 | url_set_interrupt_cb(decode_interrupt_cb); | 1786 | url_set_interrupt_cb(decode_interrupt_cb); |
| @@ -1446,6 +1899,7 @@ static int decode_thread(void *arg) · 112 unmodified lines | |||
| 1446 | /* XXX: must lock decoder threads */ | 1899 | /* XXX: must lock decoder threads */ |
| 1447 | SDL_LockMutex(is->video_decoder_mutex); | 1900 | SDL_LockMutex(is->video_decoder_mutex); |
| 1448 | SDL_LockMutex(is->audio_decoder_mutex); | 1901 | SDL_LockMutex(is->audio_decoder_mutex); |
| 1902 | SDL_LockMutex(is->subtitle_decoder_mutex); | ||
| 1449 | ret = av_seek_frame(is->ic, -1, is->seek_pos, is->seek_flags); | 1903 | ret = av_seek_frame(is->ic, -1, is->seek_pos, is->seek_flags); |
| 1450 | if (ret < 0) { | 1904 | if (ret < 0) { |
| 1451 | fprintf(stderr, "%s: error while seeking\n", is->ic->filename); | 1905 | fprintf(stderr, "%s: error while seeking\n", is->ic->filename); |
| @@ -1453,11 +1907,15 @@ static int decode_thread(void *arg) · 1 unmodified line | |||
| 1453 | if (is->audio_stream >= 0) { | 1907 | if (is->audio_stream >= 0) { |
| 1454 | packet_queue_flush(&is->audioq); | 1908 | packet_queue_flush(&is->audioq); |
| 1455 | } | 1909 | } |
| 1910 | if (is->subtitle_stream >= 0) { | ||
| 1911 | packet_queue_flush(&is->subtitleq); | ||
| 1912 | } | ||
| 1456 | if (is->video_stream >= 0) { | 1913 | if (is->video_stream >= 0) { |
| 1457 | packet_queue_flush(&is->videoq); | 1914 | packet_queue_flush(&is->videoq); |
| 1458 | avcodec_flush_buffers(ic->streams[video_index]->codec); | 1915 | avcodec_flush_buffers(ic->streams[video_index]->codec); |
| 1459 | } | 1916 | } |
| 1460 | } | 1917 | } |
| 1918 | SDL_UnlockMutex(is->subtitle_decoder_mutex); | ||
| 1461 | SDL_UnlockMutex(is->audio_decoder_mutex); | 1919 | SDL_UnlockMutex(is->audio_decoder_mutex); |
| 1462 | SDL_UnlockMutex(is->video_decoder_mutex); | 1920 | SDL_UnlockMutex(is->video_decoder_mutex); |
| 1463 | is->seek_req = 0; | 1921 | is->seek_req = 0; |
| @@ -1466,6 +1924,7 @@ static int decode_thread(void *arg) · 2 unmodified lines | |||
| 1466 | /* if the queue are full, no need to read more */ | 1924 | /* if the queue are full, no need to read more */ |
| 1467 | if (is->audioq.size > MAX_AUDIOQ_SIZE || | 1925 | if (is->audioq.size > MAX_AUDIOQ_SIZE || |
| 1468 | is->videoq.size > MAX_VIDEOQ_SIZE || | 1926 | is->videoq.size > MAX_VIDEOQ_SIZE || |
| 1927 | is->subtitleq.size > MAX_SUBTITLEQ_SIZE || | ||
| 1469 | url_feof(&ic->pb)) { | 1928 | url_feof(&ic->pb)) { |
| 1470 | /* wait 10 ms */ | 1929 | /* wait 10 ms */ |
| 1471 | SDL_Delay(10); | 1930 | SDL_Delay(10); |
| @@ -1483,6 +1942,8 @@ static int decode_thread(void *arg) · 11 unmodified lines | |||
| 1483 | packet_queue_put(&is->audioq, pkt); | 1942 | packet_queue_put(&is->audioq, pkt); |
| 1484 | } else if (pkt->stream_index == is->video_stream) { | 1943 | } else if (pkt->stream_index == is->video_stream) { |
| 1485 | packet_queue_put(&is->videoq, pkt); | 1944 | packet_queue_put(&is->videoq, pkt); |
| 1945 | } else if (pkt->stream_index == is->subtitle_stream) { | ||
| 1946 | packet_queue_put(&is->subtitleq, pkt); | ||
| 1486 | } else { | 1947 | } else { |
| 1487 | av_free_packet(pkt); | 1948 | av_free_packet(pkt); |
| 1488 | } | 1949 | } |
| @@ -1502,6 +1963,8 @@ static int decode_thread(void *arg) · 13 unmodified lines | |||
| 1502 | stream_component_close(is, is->audio_stream); | 1963 | stream_component_close(is, is->audio_stream); |
| 1503 | if (is->video_stream >= 0) | 1964 | if (is->video_stream >= 0) |
| 1504 | stream_component_close(is, is->video_stream); | 1965 | stream_component_close(is, is->video_stream); |
| 1966 | if (is->subtitle_stream >= 0) | ||
| 1967 | stream_component_close(is, is->subtitle_stream); | ||
| 1505 | if (is->ic) { | 1968 | if (is->ic) { |
| 1506 | av_close_input_file(is->ic); | 1969 | av_close_input_file(is->ic); |
| 1507 | is->ic = NULL; /* safety */ | 1970 | is->ic = NULL; /* safety */ |
| @@ -1538,6 +2001,10 @@ static VideoState *stream_open(const char *filename, AVInputFormat *iformat) · 30 unmodified lines | |||
| 1538 | is->pictq_mutex = SDL_CreateMutex(); | 2001 | is->pictq_mutex = SDL_CreateMutex(); |
| 1539 | is->pictq_cond = SDL_CreateCond(); | 2002 | is->pictq_cond = SDL_CreateCond(); |
| 1540 | 2003 | ||
| 2004 | is->subpq_mutex = SDL_CreateMutex(); | ||
| 2005 | is->subpq_cond = SDL_CreateCond(); | ||
| 2006 | |||
| 2007 | is->subtitle_decoder_mutex = SDL_CreateMutex(); | ||
| 1541 | is->audio_decoder_mutex = SDL_CreateMutex(); | 2008 | is->audio_decoder_mutex = SDL_CreateMutex(); |
| 1542 | is->video_decoder_mutex = SDL_CreateMutex(); | 2009 | is->video_decoder_mutex = SDL_CreateMutex(); |
| 1543 | 2010 | ||
| @@ -1571,6 +2038,9 @@ static void stream_close(VideoState *is) · 27 unmodified lines | |||
| 1571 | } | 2038 | } |
| 1572 | SDL_DestroyMutex(is->pictq_mutex); | 2039 | SDL_DestroyMutex(is->pictq_mutex); |
| 1573 | SDL_DestroyCond(is->pictq_cond); | 2040 | SDL_DestroyCond(is->pictq_cond); |
| 2041 | SDL_DestroyMutex(is->subpq_mutex); | ||
| 2042 | SDL_DestroyCond(is->subpq_cond); | ||
| 2043 | SDL_DestroyMutex(is->subtitle_decoder_mutex); | ||
| 1574 | SDL_DestroyMutex(is->audio_decoder_mutex); | 2044 | SDL_DestroyMutex(is->audio_decoder_mutex); |
| 1575 | SDL_DestroyMutex(is->video_decoder_mutex); | 2045 | SDL_DestroyMutex(is->video_decoder_mutex); |
| 1576 | } | 2046 | } |
| @@ -1583,14 +2053,23 @@ void stream_cycle_channel(VideoState *is, int codec_type) · 6 unmodified lines | |||
| 1583 | 2053 | ||
| 1584 | if (codec_type == CODEC_TYPE_VIDEO) | 2054 | if (codec_type == CODEC_TYPE_VIDEO) |
| 1585 | start_index = is->video_stream; | 2055 | start_index = is->video_stream; |
| 1586 | else | 2056 | else if (codec_type == CODEC_TYPE_AUDIO) |
| 1587 | start_index = is->audio_stream; | 2057 | start_index = is->audio_stream; |
| 1588 | if (start_index < 0) | 2058 | else |
| 2059 | start_index = is->subtitle_stream; | ||
| 2060 | if (start_index < (codec_type == CODEC_TYPE_SUBTITLE ? -1 : 0)) | ||
| 1589 | return; | 2061 | return; |
| 1590 | stream_index = start_index; | 2062 | stream_index = start_index; |
| 1591 | for(;;) { | 2063 | for(;;) { |
| 1592 | if (++stream_index >= is->ic->nb_streams) | 2064 | if (++stream_index >= is->ic->nb_streams) |
| 1593 | stream_index = 0; | 2065 | { |
| 2066 | if (codec_type == CODEC_TYPE_SUBTITLE) | ||
| 2067 | { | ||
| 2068 | stream_index = -1; | ||
| 2069 | goto the_end; | ||
| 2070 | } else | ||
| 2071 | stream_index = 0; | ||
| 2072 | } | ||
| 1594 | if (stream_index == start_index) | 2073 | if (stream_index == start_index) |
| 1595 | return; | 2074 | return; |
| 1596 | st = ic->streams[stream_index]; | 2075 | st = ic->streams[stream_index]; |
| @@ -1603,6 +2082,7 @@ void stream_cycle_channel(VideoState *is, int codec_type) · 6 unmodified lines | |||
| 1603 | goto the_end; | 2082 | goto the_end; |
| 1604 | break; | 2083 | break; |
| 1605 | case CODEC_TYPE_VIDEO: | 2084 | case CODEC_TYPE_VIDEO: |
| 2085 | case CODEC_TYPE_SUBTITLE: | ||
| 1606 | goto the_end; | 2086 | goto the_end; |
| 1607 | default: | 2087 | default: |
| 1608 | break; | 2088 | break; |
| @@ -1709,6 +2189,10 @@ void event_loop(void) · 100 unmodified lines | |||
| 1709 | if (cur_stream) | 2189 | if (cur_stream) |
| 1710 | stream_cycle_channel(cur_stream, CODEC_TYPE_VIDEO); | 2190 | stream_cycle_channel(cur_stream, CODEC_TYPE_VIDEO); |
| 1711 | break; | 2191 | break; |
| 2192 | case SDLK_t: | ||
| 2193 | if (cur_stream) | ||
| 2194 | stream_cycle_channel(cur_stream, CODEC_TYPE_SUBTITLE); | ||
| 2195 | break; | ||
| 1712 | case SDLK_w: | 2196 | case SDLK_w: |
| 1713 | toggle_audio_display(); | 2197 | toggle_audio_display(); |
| 1714 | break; | 2198 | break; |
| @@ -1903,6 +2387,7 @@ void show_help(void) · 188 unmodified lines | |||
| 1903 | "p, SPC pause\n" | 2387 | "p, SPC pause\n" |
| 1904 | "a cycle audio channel\n" | 2388 | "a cycle audio channel\n" |
| 1905 | "v cycle video channel\n" | 2389 | "v cycle video channel\n" |
| 2390 | "t cycle subtitle channel\n" | ||
| 1906 | "w show audio waves\n" | 2391 | "w show audio waves\n" |
| 1907 | "left/right seek backward/forward 10 seconds\n" | 2392 | "left/right seek backward/forward 10 seconds\n" |
| 1908 | "down/up seek backward/forward 1 minute\n" | 2393 | "down/up seek backward/forward 1 minute\n" |