Originally committed as revision 4521 to svn://svn.ffmpeg.org/ffmpeg/trunk
Unified · Split
| @@ -57,6 +57,7 @@ · 56 unmodified lines | ||
| 57 | 57 | |
| 58 | 58 | #define MAX_VIDEOQ_SIZE (5 * 256 * 1024) |
| 59 | 59 | #define MAX_AUDIOQ_SIZE (5 * 16 * 1024) |
| 60 | +#define MAX_SUBTITLEQ_SIZE (5 * 16 * 1024) | |
| 60 | 61 | |
| 61 | 62 | /* SDL audio buffer size, in samples. Should be small to have precise |
| 62 | 63 | A/V sync as SDL does not have hardware buffer fullness info. */ |
| @@ -86,6 +87,7 @@ typedef struct PacketQueue { · 23 unmodified lines | ||
| 86 | 87 | } PacketQueue; |
| 87 | 88 | |
| 88 | 89 | #define VIDEO_PICTURE_QUEUE_SIZE 1 |
| 90 | +#define SUBPICTURE_QUEUE_SIZE 4 | |
| 89 | 91 | |
| 90 | 92 | typedef struct VideoPicture { |
| 91 | 93 | double pts; /* presentation time stamp for this picture */ |
| @@ -94,6 +96,11 @@ typedef struct VideoPicture { · 2 unmodified lines | ||
| 94 | 96 | int allocated; |
| 95 | 97 | } VideoPicture; |
| 96 | 98 | |
| 99 | +typedef struct SubPicture { | |
| 100 | + double pts; /* presentation time stamp for this picture */ | |
| 101 | + AVSubtitle sub; | |
| 102 | +} SubPicture; | |
| 103 | + | |
| 97 | 104 | enum { |
| 98 | 105 | AV_SYNC_AUDIO_MASTER, /* default choice */ |
| 99 | 106 | AV_SYNC_VIDEO_MASTER, |
| @@ -142,6 +149,16 @@ typedef struct VideoState { · 42 unmodified lines | ||
| 142 | 149 | int sample_array_index; |
| 143 | 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 | 162 | double frame_timer; |
| 146 | 163 | double frame_last_pts; |
| 147 | 164 | double frame_last_delay; |
| @@ -163,6 +180,7 @@ typedef struct VideoState { · 15 unmodified lines | ||
| 163 | 180 | |
| 164 | 181 | SDL_mutex *video_decoder_mutex; |
| 165 | 182 | SDL_mutex *audio_decoder_mutex; |
| 183 | + SDL_mutex *subtitle_decoder_mutex; | |
| 166 | 184 | |
| 167 | 185 | // QETimer *video_timer; |
| 168 | 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 | 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 | 647 | static void video_image_display(VideoState *is) |
| 375 | 648 | { |
| 376 | 649 | VideoPicture *vp; |
| 650 | + SubPicture *sp; | |
| 651 | + AVPicture pict; | |
| 377 | 652 | float aspect_ratio; |
| 378 | 653 | int width, height, x, y; |
| 379 | 654 | SDL_Rect rect; |
| 655 | + int i; | |
| 380 | 656 | |
| 381 | 657 | vp = &is->pictq[is->pictq_rindex]; |
| 382 | 658 | if (vp->bmp) { |
| @@ -424,6 +700,33 @@ static void video_image_display(VideoState *is) · 41 unmodified lines | ||
| 424 | 700 | } |
| 425 | 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 | 730 | /* XXX: we suppose the screen has a 1.0 pixel ratio */ |
| 428 | 731 | height = is->height; |
| 429 | 732 | width = ((int)rint(height * aspect_ratio)) & -3; |
| @@ -642,6 +945,7 @@ static void video_refresh_timer(void *opaque) · 212 unmodified lines | ||
| 642 | 945 | VideoPicture *vp; |
| 643 | 946 | double actual_delay, delay, sync_threshold, ref_clock, diff; |
| 644 | 947 | |
| 948 | + SubPicture *sp, *sp2; | |
| 645 | 949 | |
| 646 | 950 | if (is->video_st) { |
| 647 | 951 | if (is->pictq_size == 0) { |
| @@ -702,6 +1006,50 @@ static void video_refresh_timer(void *opaque) · 54 unmodified lines | ||
| 702 | 1006 | delay, actual_delay, vp->pts, -diff); |
| 703 | 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 | 1053 | /* display picture */ |
| 706 | 1054 | video_display(is); |
| 707 | 1055 | |
| @@ -730,22 +1078,25 @@ static void video_refresh_timer(void *opaque) · 22 unmodified lines | ||
| 730 | 1078 | if (show_status) { |
| 731 | 1079 | static int64_t last_time; |
| 732 | 1080 | int64_t cur_time; |
| 733 | − int aqsize, vqsize; | |
| 1081 | + int aqsize, vqsize, sqsize; | |
| 734 | 1082 | double av_diff; |
| 735 | 1083 | |
| 736 | 1084 | cur_time = av_gettime(); |
| 737 | 1085 | if (!last_time || (cur_time - last_time) >= 500 * 1000) { |
| 738 | 1086 | aqsize = 0; |
| 739 | 1087 | vqsize = 0; |
| 1088 | + sqsize = 0; | |
| 740 | 1089 | if (is->audio_st) |
| 741 | 1090 | aqsize = is->audioq.size; |
| 742 | 1091 | if (is->video_st) |
| 743 | 1092 | vqsize = is->videoq.size; |
| 1093 | + if (is->subtitle_st) | |
| 1094 | + sqsize = is->subtitleq.size; | |
| 744 | 1095 | av_diff = 0; |
| 745 | 1096 | if (is->audio_st && is->video_st) |
| 746 | 1097 | av_diff = get_audio_clock(is) - get_video_clock(is); |
| 747 | − printf("%7.2f A-V:%7.3f aq=%5dKB vq=%5dKB \r", | |
| 748 | − get_master_clock(is), av_diff, aqsize / 1024, vqsize / 1024); | |
| 1098 | + printf("%7.2f A-V:%7.3f aq=%5dKB vq=%5dKB sq=%5dB \r", | |
| 1099 | + get_master_clock(is), av_diff, aqsize / 1024, vqsize / 1024, sqsize); | |
| 749 | 1100 | fflush(stdout); |
| 750 | 1101 | last_time = cur_time; |
| 751 | 1102 | } |
| @@ -948,6 +1299,79 @@ static int video_thread(void *arg) · 196 unmodified lines | ||
| 948 | 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 | 1375 | /* copy samples for viewing in editor window */ |
| 952 | 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 | 1661 | packet_queue_init(&is->videoq); |
| 1238 | 1662 | is->video_tid = SDL_CreateThread(video_thread, is); |
| 1239 | 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 | 1671 | default: |
| 1241 | 1672 | break; |
| 1242 | 1673 | } |
| @@ -1248,6 +1679,8 @@ static void stream_component_close(VideoState *is, int stream_index) · 5 unmodified lines | ||
| 1248 | 1679 | AVFormatContext *ic = is->ic; |
| 1249 | 1680 | AVCodecContext *enc; |
| 1250 | 1681 | |
| 1682 | + if (stream_index < 0 || stream_index >= ic->nb_streams) | |
| 1683 | + return; | |
| 1251 | 1684 | enc = ic->streams[stream_index]->codec; |
| 1252 | 1685 | |
| 1253 | 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 | 1705 | packet_queue_end(&is->videoq); |
| 1273 | 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 | 1722 | default: |
| 1275 | 1723 | break; |
| 1276 | 1724 | } |
| @@ -1285,6 +1733,10 @@ static void stream_component_close(VideoState *is, int stream_index) · 8 unmodified lines | ||
| 1285 | 1733 | is->video_st = NULL; |
| 1286 | 1734 | is->video_stream = -1; |
| 1287 | 1735 | break; |
| 1736 | + case CODEC_TYPE_SUBTITLE: | |
| 1737 | + is->subtitle_st = NULL; | |
| 1738 | + is->subtitle_stream = -1; | |
| 1739 | + break; | |
| 1288 | 1740 | default: |
| 1289 | 1741 | break; |
| 1290 | 1742 | } |
| @@ -1328,6 +1780,7 @@ static int decode_thread(void *arg) · 37 unmodified lines | ||
| 1328 | 1780 | audio_index = -1; |
| 1329 | 1781 | is->video_stream = -1; |
| 1330 | 1782 | is->audio_stream = -1; |
| 1783 | + is->subtitle_stream = -1; | |
| 1331 | 1784 | |
| 1332 | 1785 | global_video_state = is; |
| 1333 | 1786 | url_set_interrupt_cb(decode_interrupt_cb); |
| @@ -1446,6 +1899,7 @@ static int decode_thread(void *arg) · 112 unmodified lines | ||
| 1446 | 1899 | /* XXX: must lock decoder threads */ |
| 1447 | 1900 | SDL_LockMutex(is->video_decoder_mutex); |
| 1448 | 1901 | SDL_LockMutex(is->audio_decoder_mutex); |
| 1902 | + SDL_LockMutex(is->subtitle_decoder_mutex); | |
| 1449 | 1903 | ret = av_seek_frame(is->ic, -1, is->seek_pos, is->seek_flags); |
| 1450 | 1904 | if (ret < 0) { |
| 1451 | 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 | 1907 | if (is->audio_stream >= 0) { |
| 1454 | 1908 | packet_queue_flush(&is->audioq); |
| 1455 | 1909 | } |
| 1910 | + if (is->subtitle_stream >= 0) { | |
| 1911 | + packet_queue_flush(&is->subtitleq); | |
| 1912 | + } | |
| 1456 | 1913 | if (is->video_stream >= 0) { |
| 1457 | 1914 | packet_queue_flush(&is->videoq); |
| 1458 | 1915 | avcodec_flush_buffers(ic->streams[video_index]->codec); |
| 1459 | 1916 | } |
| 1460 | 1917 | } |
| 1918 | + SDL_UnlockMutex(is->subtitle_decoder_mutex); | |
| 1461 | 1919 | SDL_UnlockMutex(is->audio_decoder_mutex); |
| 1462 | 1920 | SDL_UnlockMutex(is->video_decoder_mutex); |
| 1463 | 1921 | is->seek_req = 0; |
| @@ -1466,6 +1924,7 @@ static int decode_thread(void *arg) · 2 unmodified lines | ||
| 1466 | 1924 | /* if the queue are full, no need to read more */ |
| 1467 | 1925 | if (is->audioq.size > MAX_AUDIOQ_SIZE || |
| 1468 | 1926 | is->videoq.size > MAX_VIDEOQ_SIZE || |
| 1927 | + is->subtitleq.size > MAX_SUBTITLEQ_SIZE || | |
| 1469 | 1928 | url_feof(&ic->pb)) { |
| 1470 | 1929 | /* wait 10 ms */ |
| 1471 | 1930 | SDL_Delay(10); |
| @@ -1483,6 +1942,8 @@ static int decode_thread(void *arg) · 11 unmodified lines | ||
| 1483 | 1942 | packet_queue_put(&is->audioq, pkt); |
| 1484 | 1943 | } else if (pkt->stream_index == is->video_stream) { |
| 1485 | 1944 | packet_queue_put(&is->videoq, pkt); |
| 1945 | + } else if (pkt->stream_index == is->subtitle_stream) { | |
| 1946 | + packet_queue_put(&is->subtitleq, pkt); | |
| 1486 | 1947 | } else { |
| 1487 | 1948 | av_free_packet(pkt); |
| 1488 | 1949 | } |
| @@ -1502,6 +1963,8 @@ static int decode_thread(void *arg) · 13 unmodified lines | ||
| 1502 | 1963 | stream_component_close(is, is->audio_stream); |
| 1503 | 1964 | if (is->video_stream >= 0) |
| 1504 | 1965 | stream_component_close(is, is->video_stream); |
| 1966 | + if (is->subtitle_stream >= 0) | |
| 1967 | + stream_component_close(is, is->subtitle_stream); | |
| 1505 | 1968 | if (is->ic) { |
| 1506 | 1969 | av_close_input_file(is->ic); |
| 1507 | 1970 | is->ic = NULL; /* safety */ |
| @@ -1538,6 +2001,10 @@ static VideoState *stream_open(const char *filename, AVInputFormat *iformat) · 30 unmodified lines | ||
| 1538 | 2001 | is->pictq_mutex = SDL_CreateMutex(); |
| 1539 | 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 | 2008 | is->audio_decoder_mutex = SDL_CreateMutex(); |
| 1542 | 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 | 2039 | SDL_DestroyMutex(is->pictq_mutex); |
| 1573 | 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 | 2044 | SDL_DestroyMutex(is->audio_decoder_mutex); |
| 1575 | 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 | 2054 | if (codec_type == CODEC_TYPE_VIDEO) |
| 1585 | 2055 | start_index = is->video_stream; |
| 1586 | − else | |
| 2056 | + else if (codec_type == CODEC_TYPE_AUDIO) | |
| 1587 | 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 | 2061 | return; |
| 1590 | 2062 | stream_index = start_index; |
| 1591 | 2063 | for(;;) { |
| 1592 | 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 | 2073 | if (stream_index == start_index) |
| 1595 | 2074 | return; |
| 1596 | 2075 | st = ic->streams[stream_index]; |
| @@ -1603,6 +2082,7 @@ void stream_cycle_channel(VideoState *is, int codec_type) · 6 unmodified lines | ||
| 1603 | 2082 | goto the_end; |
| 1604 | 2083 | break; |
| 1605 | 2084 | case CODEC_TYPE_VIDEO: |
| 2085 | + case CODEC_TYPE_SUBTITLE: | |
| 1606 | 2086 | goto the_end; |
| 1607 | 2087 | default: |
| 1608 | 2088 | break; |
| @@ -1709,6 +2189,10 @@ void event_loop(void) · 100 unmodified lines | ||
| 1709 | 2189 | if (cur_stream) |
| 1710 | 2190 | stream_cycle_channel(cur_stream, CODEC_TYPE_VIDEO); |
| 1711 | 2191 | break; |
| 2192 | + case SDLK_t: | |
| 2193 | + if (cur_stream) | |
| 2194 | + stream_cycle_channel(cur_stream, CODEC_TYPE_SUBTITLE); | |
| 2195 | + break; | |
| 1712 | 2196 | case SDLK_w: |
| 1713 | 2197 | toggle_audio_display(); |
| 1714 | 2198 | break; |
| @@ -1903,6 +2387,7 @@ void show_help(void) · 188 unmodified lines | ||
| 1903 | 2387 | "p, SPC pause\n" |
| 1904 | 2388 | "a cycle audio channel\n" |
| 1905 | 2389 | "v cycle video channel\n" |
| 2390 | + "t cycle subtitle channel\n" | |
| 1906 | 2391 | "w show audio waves\n" |
| 1907 | 2392 | "left/right seek backward/forward 10 seconds\n" |
| 1908 | 2393 | "down/up seek backward/forward 1 minute\n" |