Changeset 151021 in webkit
- Timestamp:
- May 31, 2013 9:17:47 AM (11 years ago)
- Location:
- trunk/Source/WebCore
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/WebCore/ChangeLog
r151016 r151021 1 2013-05-31 Andre Moreira Magalhaes <andre.magalhaes@collabora.co.uk> 2 3 Make sure gstreamer source element is thread-safe 4 https://bugs.webkit.org/show_bug.cgi?id=115352 5 6 Reviewed by Philippe Normand. 7 8 GStreamer source element may be created by any gstreamer element on any thread by calling 9 gst_element_make_from_uri with the URIs handled by the source element. 10 This patch makes sure the gstreamer source element is thread-safe to avoid issues with it 11 being created outside the main thread. 12 13 * platform/graphics/gstreamer/WebKitWebSourceGStreamer.cpp: 14 (_WebKitWebSrcPrivate): 15 (webkit_web_src_init): 16 (webKitWebSrcFinalize): 17 (webKitWebSrcSetProperty): 18 (webKitWebSrcGetProperty): 19 (webKitWebSrcStop): 20 (webKitWebSrcStart): 21 (webKitWebSrcChangeState): 22 (webKitWebSrcQueryWithParent): 23 (webKitWebSrcGetUri): 24 (webKitWebSrcSetUri): 25 (webKitWebSrcNeedDataMainCb): 26 (webKitWebSrcEnoughDataMainCb): 27 (webKitWebSrcSeekMainCb): 28 (webKitWebSrcSeekDataCb): 29 (webKitWebSrcSetMediaPlayer): 30 (StreamingClient::StreamingClient): 31 (StreamingClient::~StreamingClient): 32 (StreamingClient::didReceiveResponse): 33 (StreamingClient::didReceiveData): 34 (StreamingClient::didFinishLoading): 35 (StreamingClient::wasBlocked): 36 (StreamingClient::cannotShowURL): 37 1 38 2013-05-31 Sergio Villar Senin <svillar@igalia.com> 2 39 -
trunk/Source/WebCore/platform/graphics/gstreamer/WebKitWebSourceGStreamer.cpp
r149383 r151021 43 43 #include <wtf/text/CString.h> 44 44 45 /* Premisses: 46 * - webkitsrc may be created from any thread inside gstreamer 47 * - client holds reference to src, so that src is never deleted while client exists 48 * - if the src exists, appsrc also exists 49 * - client is created on start 50 * - client is deleted on stop after cancelling resource handle 51 * - client callbacks are always invoked from main thread 52 * - resource handle methods must always be called from main thread 53 */ 54 45 55 using namespace WebCore; 46 56 … … 85 95 guint64 requestedOffset; 86 96 97 guint startID; 98 guint stopID; 87 99 guint needDataID; 88 100 guint enoughDataID; … … 136 148 static void webKitWebSrcEnoughDataCb(GstAppSrc*, gpointer userData); 137 149 static gboolean webKitWebSrcSeekDataCb(GstAppSrc*, guint64 offset, gpointer userData); 138 139 static void webKitWebSrcStop(WebKitWebSrc*, bool);140 150 141 151 static GstAppSrcCallbacks appsrcCallbacks = { … … 230 240 src->priv = priv; 231 241 232 priv->client = new StreamingClient(src);233 234 242 priv->appsrc = GST_APP_SRC(gst_element_factory_make("appsrc", 0)); 235 243 if (!priv->appsrc) { … … 280 288 g_object_set(priv->appsrc, "min-percent", 20, NULL); 281 289 282 webKitWebSrcStop(src, false); 290 gst_app_src_set_caps(priv->appsrc, 0); 291 gst_app_src_set_size(priv->appsrc, -1); 283 292 } 284 293 … … 303 312 WebKitWebSrcPrivate* priv = src->priv; 304 313 305 delete priv->client;306 307 314 g_free(priv->uri); 308 315 … … 317 324 switch (propID) { 318 325 case PROP_IRADIO_MODE: 326 GST_OBJECT_LOCK(src); 319 327 priv->iradioMode = g_value_get_boolean(value); 328 GST_OBJECT_UNLOCK(src); 320 329 break; 321 330 case PROP_LOCATION: … … 337 346 WebKitWebSrcPrivate* priv = src->priv; 338 347 348 GST_OBJECT_LOCK(src); 339 349 switch (propID) { 340 350 case PROP_IRADIO_MODE: … … 360 370 break; 361 371 } 362 } 363 364 365 static void webKitWebSrcStop(WebKitWebSrc* src, bool seeking) 366 { 367 WebKitWebSrcPrivate* priv = src->priv; 372 GST_OBJECT_UNLOCK(src); 373 } 374 375 // must be called on main thread and with object unlocked 376 static gboolean webKitWebSrcStop(WebKitWebSrc* src) 377 { 378 WebKitWebSrcPrivate* priv = src->priv; 379 gboolean seeking; 380 381 GST_OBJECT_LOCK(src); 382 383 seeking = priv->seekID; 384 385 if (priv->startID) { 386 g_source_remove(priv->startID); 387 priv->startID = 0; 388 } 368 389 369 390 if (priv->resourceHandle) { … … 373 394 priv->resourceHandle = 0; 374 395 396 if (priv->client) { 397 delete priv->client; 398 priv->client = 0; 399 } 400 375 401 if (priv->frame && !seeking) 376 402 priv->frame.clear(); … … 385 411 } 386 412 387 GST_OBJECT_LOCK(src);388 413 if (priv->needDataID) 389 414 g_source_remove(priv->needDataID); … … 399 424 400 425 priv->paused = FALSE; 401 GST_OBJECT_UNLOCK(src);402 426 403 427 g_free(priv->iradioName); … … 412 436 g_free(priv->iradioTitle); 413 437 priv->iradioTitle = 0; 438 439 priv->offset = 0; 440 priv->seekable = FALSE; 441 442 if (!seeking) { 443 priv->size = 0; 444 priv->requestedOffset = 0; 445 } 446 447 priv->stopID = 0; 448 GST_OBJECT_UNLOCK(src); 414 449 415 450 if (priv->appsrc) { … … 419 454 } 420 455 421 priv->offset = 0;422 priv->seekable = FALSE;423 424 if (!seeking) {425 priv->size = 0;426 priv->requestedOffset = 0;427 }428 429 456 GST_DEBUG_OBJECT(src, "Stopped request"); 430 } 431 432 static bool webKitWebSrcStart(WebKitWebSrc* src) 433 { 434 WebKitWebSrcPrivate* priv = src->priv; 435 457 458 return FALSE; 459 } 460 461 // must be called on main thread and with object unlocked 462 static gboolean webKitWebSrcStart(WebKitWebSrc* src) 463 { 464 WebKitWebSrcPrivate* priv = src->priv; 465 466 GST_OBJECT_LOCK(src); 436 467 if (!priv->uri) { 437 468 GST_ERROR_OBJECT(src, "No URI provided"); 438 return false; 439 } 440 469 GST_OBJECT_UNLOCK(src); 470 webKitWebSrcStop(src); 471 return FALSE; 472 } 473 441 474 KURL url = KURL(KURL(), priv->uri); 442 475 … … 473 506 request.setHTTPHeaderField("transferMode.dlna", "Streaming"); 474 507 508 priv->client = new StreamingClient(src); 475 509 priv->resourceHandle = ResourceHandle::create(context, request, priv->client, false, false); 476 510 if (!priv->resourceHandle) { 477 511 GST_ERROR_OBJECT(src, "Failed to create ResourceHandle"); 478 return false; 479 } 480 481 GST_DEBUG_OBJECT(src, "Started request"); 482 483 return true; 512 GST_OBJECT_UNLOCK(src); 513 webKitWebSrcStop(src); 514 } else { 515 GST_OBJECT_UNLOCK(src); 516 GST_DEBUG_OBJECT(src, "Started request"); 517 } 518 return FALSE; 484 519 } 485 520 … … 512 547 case GST_STATE_CHANGE_READY_TO_PAUSED: 513 548 GST_DEBUG_OBJECT(src, "READY->PAUSED"); 514 if (!webKitWebSrcStart(src)) 515 ret = GST_STATE_CHANGE_FAILURE; 549 GST_OBJECT_LOCK(src); 550 priv->startID = g_timeout_add_full(G_PRIORITY_DEFAULT, 0, (GSourceFunc) webKitWebSrcStart, gst_object_ref(src), (GDestroyNotify) gst_object_unref); 551 GST_OBJECT_UNLOCK(src); 516 552 break; 517 553 case GST_STATE_CHANGE_PAUSED_TO_READY: 518 554 GST_DEBUG_OBJECT(src, "PAUSED->READY"); 519 webKitWebSrcStop(src, false); 555 GST_OBJECT_LOCK(src); 556 priv->stopID = g_timeout_add_full(G_PRIORITY_DEFAULT, 0, (GSourceFunc) webKitWebSrcStop, gst_object_ref(src), (GDestroyNotify) gst_object_unref); 557 GST_OBJECT_UNLOCK(src); 520 558 break; 521 559 default: … … 528 566 static gboolean webKitWebSrcQueryWithParent(GstPad* pad, GstObject* parent, GstQuery* query) 529 567 { 530 WebKitWebSrc* webkitSrc = WEBKIT_WEB_SRC(GST_ELEMENT(parent));568 WebKitWebSrc* src = WEBKIT_WEB_SRC(GST_ELEMENT(parent)); 531 569 gboolean result = FALSE; 532 570 … … 537 575 gst_query_parse_duration(query, &format, NULL); 538 576 539 GST_DEBUG_OBJECT(webkitSrc, "duration query in format %s", gst_format_get_name(format)); 540 if ((format == GST_FORMAT_BYTES) && (webkitSrc->priv->size > 0)) { 541 gst_query_set_duration(query, format, webkitSrc->priv->size); 577 GST_DEBUG_OBJECT(src, "duration query in format %s", gst_format_get_name(format)); 578 GST_OBJECT_LOCK(src); 579 if ((format == GST_FORMAT_BYTES) && (src->priv->size > 0)) { 580 gst_query_set_duration(query, format, src->priv->size); 542 581 result = TRUE; 543 582 } 583 GST_OBJECT_UNLOCK(src); 544 584 break; 545 585 } 546 586 case GST_QUERY_URI: { 547 gst_query_set_uri(query, webkitSrc->priv->uri); 587 GST_OBJECT_LOCK(src); 588 gst_query_set_uri(query, src->priv->uri); 589 GST_OBJECT_UNLOCK(src); 548 590 result = TRUE; 549 591 break; … … 586 628 static gchar* webKitWebSrcGetUri(GstURIHandler* handler) 587 629 { 588 return g_strdup(WEBKIT_WEB_SRC(handler)->priv->uri); 630 WebKitWebSrc* src = WEBKIT_WEB_SRC(handler); 631 gchar* ret; 632 633 GST_OBJECT_LOCK(src); 634 ret = g_strdup(src->priv->uri); 635 GST_OBJECT_UNLOCK(src); 636 return ret; 589 637 } 590 638 … … 599 647 } 600 648 649 GST_OBJECT_LOCK(src); 601 650 g_free(priv->uri); 602 651 priv->uri = 0; 603 652 604 if (!uri) 653 if (!uri) { 654 GST_OBJECT_UNLOCK(src); 605 655 return TRUE; 656 } 606 657 607 658 KURL url(KURL(), uri); 608 659 609 660 if (!url.isValid() || !url.protocolIsInHTTPFamily()) { 661 GST_OBJECT_UNLOCK(src); 610 662 g_set_error(error, GST_URI_ERROR, GST_URI_ERROR_BAD_URI, "Invalid URI '%s'", uri); 611 663 return FALSE; … … 613 665 614 666 priv->uri = g_strdup(url.string().utf8().data()); 667 GST_OBJECT_UNLOCK(src); 615 668 return TRUE; 616 669 } … … 630 683 static const gchar* webKitWebSrcGetUri(GstURIHandler* handler) 631 684 { 632 return g_strdup(WEBKIT_WEB_SRC(handler)->priv->uri); 685 WebKitWebSrc* src = WEBKIT_WEB_SRC(handler); 686 gchar* ret; 687 688 GST_OBJECT_LOCK(src); 689 ret = g_strdup(src->priv->uri); 690 GST_OBJECT_UNLOCK(src); 691 return ret; 633 692 } 634 693 … … 643 702 } 644 703 704 GST_OBJECT_LOCK(src); 645 705 g_free(priv->uri); 646 706 priv->uri = 0; 647 707 648 if (!uri) 708 if (!uri) { 709 GST_OBJECT_UNLOCK(src); 649 710 return TRUE; 711 } 650 712 651 713 KURL url(KURL(), uri); 652 714 653 715 if (!url.isValid() || !url.protocolIsInHTTPFamily()) { 716 GST_OBJECT_UNLOCK(src); 654 717 GST_ERROR_OBJECT(src, "Invalid URI '%s'", uri); 655 718 return FALSE; … … 657 720 658 721 priv->uri = g_strdup(url.string().utf8().data()); 722 GST_OBJECT_UNLOCK(src); 659 723 return TRUE; 660 724 } … … 677 741 WebKitWebSrcPrivate* priv = src->priv; 678 742 679 priv->resourceHandle->setDefersLoading(false); 680 681 GST_OBJECT_LOCK(src); 743 GST_OBJECT_LOCK(src); 744 // already stopped 745 if (!priv->needDataID) { 746 GST_OBJECT_UNLOCK(src); 747 return FALSE; 748 } 749 682 750 priv->paused = FALSE; 683 751 priv->needDataID = 0; 684 752 GST_OBJECT_UNLOCK(src); 753 754 if (priv->resourceHandle) 755 priv->resourceHandle->setDefersLoading(false); 685 756 return FALSE; 686 757 } … … 707 778 WebKitWebSrcPrivate* priv = src->priv; 708 779 709 priv->resourceHandle->setDefersLoading(true); 710 711 GST_OBJECT_LOCK(src); 780 GST_OBJECT_LOCK(src); 781 // already stopped 782 if (!priv->enoughDataID) { 783 GST_OBJECT_UNLOCK(src); 784 return FALSE; 785 } 786 712 787 priv->paused = TRUE; 713 788 priv->enoughDataID = 0; 714 789 GST_OBJECT_UNLOCK(src); 715 790 791 if (priv->resourceHandle) 792 priv->resourceHandle->setDefersLoading(true); 716 793 return FALSE; 717 794 } … … 736 813 static gboolean webKitWebSrcSeekMainCb(WebKitWebSrc* src) 737 814 { 738 webKitWebSrcStop(src , true);815 webKitWebSrcStop(src); 739 816 webKitWebSrcStart(src); 740 817 … … 748 825 749 826 GST_DEBUG_OBJECT(src, "Seeking to offset: %" G_GUINT64_FORMAT, offset); 750 if (offset == priv->offset && priv->requestedOffset == priv->offset) 827 GST_OBJECT_LOCK(src); 828 if (offset == priv->offset && priv->requestedOffset == priv->offset) { 829 GST_OBJECT_UNLOCK(src); 751 830 return TRUE; 752 753 if (!priv->seekable) 831 } 832 833 if (!priv->seekable) { 834 GST_OBJECT_UNLOCK(src); 754 835 return FALSE; 755 if (offset > priv->size) 836 } 837 if (offset > priv->size) { 838 GST_OBJECT_UNLOCK(src); 756 839 return FALSE; 840 } 757 841 758 842 GST_DEBUG_OBJECT(src, "Doing range-request seek"); 759 843 priv->requestedOffset = offset; 760 844 761 GST_OBJECT_LOCK(src);762 845 if (priv->seekID) 763 846 g_source_remove(priv->seekID); 764 847 priv->seekID = g_timeout_add_full(G_PRIORITY_DEFAULT, 0, (GSourceFunc) webKitWebSrcSeekMainCb, gst_object_ref(src), (GDestroyNotify) gst_object_unref); 765 848 GST_OBJECT_UNLOCK(src); 766 849 767 850 return TRUE; 768 851 } … … 781 864 } 782 865 783 StreamingClient::StreamingClient(WebKitWebSrc* src) : m_src(src) 866 StreamingClient::StreamingClient(WebKitWebSrc* src) 867 : m_src(static_cast<WebKitWebSrc*>(gst_object_ref(src))) 784 868 { 785 869 … … 788 872 StreamingClient::~StreamingClient() 789 873 { 790 874 gst_object_unref(m_src); 791 875 } 792 876 … … 795 879 } 796 880 797 void StreamingClient::didReceiveResponse(ResourceHandle *, const ResourceResponse& response)881 void StreamingClient::didReceiveResponse(ResourceHandle *handle, const ResourceResponse& response) 798 882 { 799 883 WebKitWebSrcPrivate* priv = m_src->priv; … … 801 885 GST_DEBUG_OBJECT(m_src, "Received response: %d", response.httpStatusCode()); 802 886 887 GST_OBJECT_LOCK(m_src); 888 803 889 // If we seeked we need 206 == PARTIAL_CONTENT 804 if (priv->requestedOffset && response.httpStatusCode() != 206) { 890 if (handle != priv->resourceHandle || (priv->requestedOffset && response.httpStatusCode() != 206)) { 891 GST_OBJECT_UNLOCK(m_src); 805 892 GST_ELEMENT_ERROR(m_src, RESOURCE, READ, (0), (0)); 806 893 gst_app_src_end_of_stream(priv->appsrc); 807 webKitWebSrcStop(m_src , false);894 webKitWebSrcStop(m_src); 808 895 return; 809 896 } 810 897 811 898 long long length = response.expectedContentLength(); 812 if (length > 0) {899 if (length > 0) 813 900 length += priv->requestedOffset; 814 gst_app_src_set_size(priv->appsrc, length);815 816 #ifndef GST_API_VERSION_1817 if (!priv->haveAppSrc27) {818 gst_segment_set_duration(&GST_BASE_SRC(priv->appsrc)->segment, GST_FORMAT_BYTES, length);819 gst_element_post_message(GST_ELEMENT(priv->appsrc),820 gst_message_new_duration(GST_OBJECT(priv->appsrc),821 GST_FORMAT_BYTES, length));822 }823 #endif824 }825 901 826 902 priv->size = length >= 0 ? length : 0; 827 903 priv->seekable = length > 0 && g_ascii_strcasecmp("none", response.httpHeaderField("Accept-Ranges").utf8().data()); 828 829 // icecast stuff830 String value = response.httpHeaderField("icy-metaint");831 if (!value.isEmpty()) {832 gchar* endptr = 0;833 gint64 icyMetaInt = g_ascii_strtoll(value.utf8().data(), &endptr, 10);834 835 if (endptr && *endptr == '\0' && icyMetaInt > 0) {836 GRefPtr<GstCaps> caps = adoptGRef(gst_caps_new_simple("application/x-icy", "metadata-interval", G_TYPE_INT, (gint) icyMetaInt, NULL));837 838 gst_app_src_set_caps(priv->appsrc, caps.get());839 }840 }841 904 842 905 #ifdef GST_API_VERSION_1 … … 845 908 GstTagList* tags = gst_tag_list_new(); 846 909 #endif 847 value = response.httpHeaderField("icy-name");910 String value = response.httpHeaderField("icy-name"); 848 911 if (!value.isEmpty()) { 849 912 g_free(priv->iradioName); … … 874 937 } 875 938 939 GST_OBJECT_UNLOCK(m_src); 940 941 // notify size/duration 942 if (length > 0) { 943 gst_app_src_set_size(priv->appsrc, length); 944 945 #ifndef GST_API_VERSION_1 946 if (!priv->haveAppSrc27) { 947 gst_segment_set_duration(&GST_BASE_SRC(priv->appsrc)->segment, GST_FORMAT_BYTES, length); 948 gst_element_post_message(GST_ELEMENT(priv->appsrc), 949 gst_message_new_duration(GST_OBJECT(priv->appsrc), 950 GST_FORMAT_BYTES, length)); 951 } 952 #endif 953 } else 954 gst_app_src_set_size(priv->appsrc, -1); 955 956 // icecast stuff 957 value = response.httpHeaderField("icy-metaint"); 958 if (!value.isEmpty()) { 959 gchar* endptr = 0; 960 gint64 icyMetaInt = g_ascii_strtoll(value.utf8().data(), &endptr, 10); 961 962 if (endptr && *endptr == '\0' && icyMetaInt > 0) { 963 GRefPtr<GstCaps> caps = adoptGRef(gst_caps_new_simple("application/x-icy", "metadata-interval", G_TYPE_INT, (gint) icyMetaInt, NULL)); 964 965 gst_app_src_set_caps(priv->appsrc, caps.get()); 966 } 967 } else 968 gst_app_src_set_caps(priv->appsrc, 0); 969 970 // notify tags 876 971 if (gst_tag_list_is_empty(tags)) 877 972 #ifdef GST_API_VERSION_1 … … 881 976 #endif 882 977 else 883 notifyGstTagsOnPad(GST_ELEMENT(m_src), m_src->priv->srcpad, tags);978 notifyGstTagsOnPad(GST_ELEMENT(m_src), priv->srcpad, tags); 884 979 } 885 980 … … 887 982 { 888 983 WebKitWebSrcPrivate* priv = m_src->priv; 984 985 GST_OBJECT_LOCK(m_src); 889 986 890 987 GST_LOG_OBJECT(m_src, "Have %d bytes of data", priv->buffer ? getGstBufferSize(priv->buffer.get()) : length); … … 898 995 899 996 if (priv->seekID || handle != priv->resourceHandle) { 997 GST_OBJECT_UNLOCK(m_src); 900 998 GST_DEBUG_OBJECT(m_src, "Seek in progress, ignoring data"); 901 999 priv->buffer.clear(); … … 916 1014 GST_BUFFER_OFFSET_END(priv->buffer.get()) = priv->offset; 917 1015 1016 GST_OBJECT_UNLOCK(m_src); 1017 918 1018 GstFlowReturn ret = gst_app_src_push_buffer(priv->appsrc, priv->buffer.leakRef()); 919 1019 #ifdef GST_API_VERSION_1 … … 949 1049 GST_DEBUG_OBJECT(m_src, "Have EOS"); 950 1050 951 if (!priv->seekID) 1051 GST_OBJECT_LOCK(m_src); 1052 if (!priv->seekID) { 1053 GST_OBJECT_UNLOCK(m_src); 952 1054 gst_app_src_end_of_stream(m_src->priv->appsrc); 1055 } else 1056 GST_OBJECT_UNLOCK(m_src); 953 1057 } 954 1058 … … 962 1066 void StreamingClient::wasBlocked(ResourceHandle*) 963 1067 { 1068 GOwnPtr<gchar> uri; 1069 964 1070 GST_ERROR_OBJECT(m_src, "Request was blocked"); 965 GST_ELEMENT_ERROR(m_src, RESOURCE, OPEN_READ, ("Access to \"%s\" was blocked", m_src->priv->uri), (0)); 1071 1072 GST_OBJECT_LOCK(m_src); 1073 uri.set(g_strdup(m_src->priv->uri)); 1074 GST_OBJECT_UNLOCK(m_src); 1075 1076 GST_ELEMENT_ERROR(m_src, RESOURCE, OPEN_READ, ("Access to \"%s\" was blocked", uri.get()), (0)); 966 1077 } 967 1078 968 1079 void StreamingClient::cannotShowURL(ResourceHandle*) 969 1080 { 1081 GOwnPtr<gchar> uri; 1082 970 1083 GST_ERROR_OBJECT(m_src, "Cannot show URL"); 971 GST_ELEMENT_ERROR(m_src, RESOURCE, OPEN_READ, ("Can't show \"%s\"", m_src->priv->uri), (0)); 1084 1085 GST_OBJECT_LOCK(m_src); 1086 uri.set(g_strdup(m_src->priv->uri)); 1087 GST_OBJECT_UNLOCK(m_src); 1088 1089 GST_ELEMENT_ERROR(m_src, RESOURCE, OPEN_READ, ("Can't show \"%s\"", uri.get()), (0)); 972 1090 } 973 1091
Note: See TracChangeset
for help on using the changeset viewer.