Ignore:
Timestamp:
May 5, 2011, 5:36:53 AM (14 years ago)
Author:
Dmitry A. Kuminov
Message:

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

Location:
trunk
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk

  • trunk/src/3rdparty/phonon/gstreamer/mediaobject.cpp

    r561 r846  
    1717#include <cmath>
    1818#include <gst/interfaces/propertyprobe.h>
     19#include <gst/pbutils/install-plugins.h>
    1920#include "common.h"
    2021#include "mediaobject.h"
     
    5455        , m_prefinishMark(0)
    5556        , m_transitionTime(0)
     57        , m_isStream(false)
    5658        , m_posAtSeek(-1)
    5759        , m_prefinishMarkReachedNotEmitted(true)
     
    8082        , m_availableTitles(0)
    8183        , m_currentTitle(1)
     84        , m_pendingTitle(1)
    8285{
    8386    qRegisterMetaType<GstCaps*>("GstCaps*");
     
    9699        connect(m_tickTimer, SIGNAL(timeout()), SLOT(emitTick()));
    97100    }
    98     connect(this, SIGNAL(stateChanged(Phonon::State,Phonon::State)),
    99             this, SLOT(notifyStateChange(Phonon::State,Phonon::State)));
     101    connect(this, SIGNAL(stateChanged(Phonon::State, Phonon::State)),
     102            this, SLOT(notifyStateChange(Phonon::State, Phonon::State)));
    100103
    101104}
     
    137140}
    138141
     142void
     143pluginInstallationDone( GstInstallPluginsReturn res, gpointer userData )
     144{
     145    // Nothing inside yet
     146    Q_UNUSED(res);
     147    Q_UNUSED(userData);
     148}
     149
    139150void MediaObject::saveState()
    140151{
     
    196207        bool canPlay = (m_hasAudio || m_videoStreamFound);
    197208        Phonon::ErrorType error = canPlay ? Phonon::NormalError : Phonon::FatalError;
     209#ifdef PLUGIN_INSTALL_API
     210        GstInstallPluginsContext *ctx = gst_install_plugins_context_new ();
     211        gchar *details[2];
     212        details[0] = m_missingCodecs[0].toLocal8Bit().data();
     213        details[1] = NULL;
     214        GstInstallPluginsReturn status;
     215
     216        status = gst_install_plugins_async( details, ctx, pluginInstallationDone, NULL );
     217        gst_install_plugins_context_free ( ctx );
     218
     219        if ( status != GST_INSTALL_PLUGINS_STARTED_OK )
     220        {
     221            if( status == GST_INSTALL_PLUGINS_HELPER_MISSING )
     222                setError(tr("Missing codec helper script assistant."), Phonon::FatalError );
     223            else
     224                setError(tr("Plugin codec installation failed for codec: %0")
     225                        .arg(m_missingCodecs[0].split("|")[3]), error);
     226        }
     227        m_missingCodecs.clear();
     228#else
     229        QString codecs = m_missingCodecs.join(", ");
     230
    198231        if (error == Phonon::NormalError && m_hasVideo && !m_videoStreamFound) {
    199232            m_hasVideo = false;
    200233            emit hasVideoChanged(false);
    201234        }
    202         QString codecs = m_missingCodecs.join(", ");
    203         setError(QString(tr("A required codec is missing. You need to install the following codec(s) to play this content: %0")).arg(codecs), error);
     235        setError(tr("A required codec is missing. You need to install the following codec(s) to play this content: %0").arg(codecs), error);
    204236        m_missingCodecs.clear();
     237#endif
    205238    }
    206239}
     
    249282
    250283    }
    251     media->addMissingCodecName(value);
     284
     285#ifdef PLUGIN_INSTALL_API
     286    QString plugins = QString("gstreamer|0.10|%0|%1|decoder-%2")
     287        .arg( qApp->applicationName() )
     288        .arg( value )
     289        .arg( QString::fromUtf8(gst_caps_to_string (caps) ) );
     290    media->addMissingCodecName( plugins );
     291#else
     292    media->addMissingCodecName( value );
     293#endif
    252294}
    253295
     
    310352            // Note that the notify::caps _must_ be installed after linking to work with Dapper
    311353            m_capsHandler = g_signal_connect(pad, "notify::caps", G_CALLBACK(notifyVideoCaps), this);
    312  
     354
    313355            if (!m_loading && !m_hasVideo) {
    314356                m_hasVideo = m_videoStreamFound;
     
    369411
    370412    // Create a new datasource based on the input URL
    371     QByteArray encoded_cstr_url = url.toEncoded();
     413    // add the 'file' scheme if it's missing; the double '/' is needed!
     414    QByteArray encoded_cstr_url = (url.scheme() == QLatin1String("") ?
     415                    "file://" + url.toEncoded() :
     416                    url.toEncoded());
    372417    m_datasource = gst_element_make_from_uri(GST_URI_SRC, encoded_cstr_url.constData(), (const char*)NULL);
    373418    if (!m_datasource)
     
    389434            m_backend->logMessage(QString("new device speed : 2X"), Backend::Info, this);
    390435        }
     436  }
     437
     438    /* make HTTP sources send extra headers so we get icecast
     439     * metadata in case the stream is an icecast stream */
     440    if (encoded_cstr_url.startsWith("http://")
     441        && g_object_class_find_property (G_OBJECT_GET_CLASS (m_datasource), "iradio-mode")) {
     442        g_object_set (m_datasource, "iradio-mode", TRUE, NULL);
     443        m_isStream = true;
    391444    }
    392445
     
    443496    gst_object_sink (GST_OBJECT (m_pipeline));
    444497
    445     m_decodebin = gst_element_factory_make ("decodebin", NULL);
     498    m_decodebin = gst_element_factory_make ("decodebin2", NULL);
    446499    g_signal_connect (m_decodebin, "new-decoded-pad", G_CALLBACK (&cb_newpad), this);
    447500    g_signal_connect (m_decodebin, "unknown-type", G_CALLBACK (&cb_unknown_type), this);
     
    647700        } else if (currentState == GST_STATE_PLAYING) {
    648701            changeState(Phonon::PlayingState);
    649         } else if (!m_atEndOfStream && gst_element_set_state(m_pipeline, GST_STATE_PLAYING) != GST_STATE_CHANGE_FAILURE) {
     702        } else if (gst_element_set_state(m_pipeline, GST_STATE_PLAYING) != GST_STATE_CHANGE_FAILURE) {
    650703            m_pendingState = Phonon::PlayingState;
    651704        } else {
     
    677730
    678731    Phonon::State oldState = m_state;
    679     m_state = newstate; // m_state must be set before emitting, since 
     732    m_state = newstate; // m_state must be set before emitting, since
    680733                        // Error state requires that state() will return the new value
    681734    m_pendingState = newstate;
     
    697750    case Phonon::StoppedState:
    698751        m_backend->logMessage("phonon state changed: Stopped", Backend::Info, this);
     752        // We must reset the pipeline when playing again
     753        m_resetNeeded = true;
    699754        m_tickTimer->stop();
    700755        break;
     
    862917    GstState state;
    863918    gst_element_set_state(m_pipeline, GST_STATE_NULL);
    864     gst_element_get_state (m_pipeline, &state, NULL, 2000);
     919    gst_element_get_state(m_pipeline, &state, NULL, 2000);
    865920
    866921    m_source = source;
     
    872927    changeState(Phonon::LoadingState);
    873928    m_loading = true;
    874     m_resetNeeded = false;
     929    // IMPORTANT: Honor the m_resetNeeded flag as it currently stands.
     930    // See https://qa.mandriva.com/show_bug.cgi?id=56807
     931    //m_resetNeeded = false;
    875932    m_resumeState = false;
    876933    m_pendingState = Phonon::StoppedState;
     
    885942    m_aboutToFinishEmitted = false;
    886943    m_error = NoError;
    887     m_errorString = QString();
    888    
     944    m_errorString.clear();
     945
    889946    m_bufferPercent = 0;
    890947    m_prefinishMarkReachedNotEmitted = true;
     
    895952    m_atEndOfStream = false;
    896953
    897     // Clear exising meta tags
     954    m_availableTitles = 0;
     955    m_pendingTitle = 1;
     956    m_currentTitle = 1;
     957
     958    // Clear existing meta tags
    898959    m_metaData.clear();
     960    m_isStream = false;
    899961
    900962    switch (source.type()) {
    901     case MediaSource::Url: {           
    902             if (createPipefromURL(source.url()))
    903                 m_loading = true;
    904             else
     963    case MediaSource::Url: {
     964            if (!createPipefromURL(source.url()))
    905965                setError(tr("Could not open media source."));
    906966        }
     
    908968
    909969    case MediaSource::LocalFile: {
    910             if (createPipefromURL(QUrl::fromLocalFile(source.fileName())))
    911                 m_loading = true;
    912             else
     970            if (!createPipefromURL(QUrl::fromLocalFile(source.fileName())))
    913971                setError(tr("Could not open media source."));
    914972        }
     
    923981
    924982    case MediaSource::Stream:
    925         if (createPipefromStream(source))
    926             m_loading = true;
    927         else
     983        if (!createPipefromStream(source))
    928984            setError(tr("Could not open media source."));
    929985        break;
     
    931987    case MediaSource::Disc:
    932988        {
    933             QString mediaUrl;
    934             switch (source.discType()) {
    935             case Phonon::NoDisc:
     989       QString mediaUrl;
     990       switch (source.discType()) {
     991       case Phonon::NoDisc:
    936992                qWarning() << "I should never get to see a MediaSource that is a disc but doesn't specify which one";
    937993                return;
     
    9491005                return;
    9501006            }
    951             if (!mediaUrl.isEmpty() && createPipefromURL(QUrl(mediaUrl)))
    952                 m_loading = true;
    953             else
     1007            if (mediaUrl.isEmpty() || !createPipefromURL(QUrl(mediaUrl)))
    9541008                setError(tr("Could not open media source."));
    9551009        }
     
    9671021    // We need to link this node to ensure that fake sinks are connected
    9681022    // before loading, otherwise the stream will be blocked
    969     if (m_loading)
    970         link();
     1023    link();
    9711024    beginLoad();
    9721025}
     
    10051058    }
    10061059
    1007     m_availableTitles = 1;
    1008     gint64 titleCount;
    1009     GstFormat format = gst_format_get_by_nick("track");
    1010     if (gst_element_query_duration (m_pipeline, &format, &titleCount)) {
     1060    if (m_source.discType() == Phonon::Cd) {
     1061        gint64 titleCount;
     1062        GstFormat format = gst_format_get_by_nick("track");
     1063        if (gst_element_query_duration (m_pipeline, &format, &titleCount)) {
    10111064        //check if returned format is still "track",
    10121065        //gstreamer sometimes returns the total time, if tracks information is not available.
    1013         if (qstrcmp(gst_format_get_name(format), "track") == 0)  {
    1014             int oldAvailableTitles = m_availableTitles;
    1015             m_availableTitles = (int)titleCount;
    1016             if (m_availableTitles != oldAvailableTitles) {
    1017                 emit availableTitlesChanged(m_availableTitles);
    1018                 m_backend->logMessage(QString("Available titles changed: %0").arg(m_availableTitles), Backend::Info, this);
     1066            if (qstrcmp(gst_format_get_name(format), "track") == 0)  {
     1067                int oldAvailableTitles = m_availableTitles;
     1068                m_availableTitles = (int)titleCount;
     1069                if (m_availableTitles != oldAvailableTitles) {
     1070                    emit availableTitlesChanged(m_availableTitles);
     1071                    m_backend->logMessage(QString("Available titles changed: %0").arg(m_availableTitles), Backend::Info, this);
     1072                }
    10191073            }
    10201074        }
    10211075    }
    1022 
    10231076}
    10241077
     
    10781131
    10791132        quint64 current = currentTime();
    1080         quint64 total = totalTime(); 
     1133        quint64 total = totalTime();
    10811134
    10821135        if (current < total - m_prefinishMark)
     
    10991152    if (m_tickInterval > 0 && currentTime != m_previousTickTime) {
    11001153        emit tick(currentTime);
    1101         m_previousTickTime = currentTime;       
     1154        m_previousTickTime = currentTime;
    11021155    }
    11031156    if (m_state == Phonon::PlayingState) {
     
    11101163        // Prepare load of next source
    11111164        if (currentTime >= totalTime - ABOUT_TO_FINNISH_TIME) {
    1112             if (!m_aboutToFinishEmitted) {
     1165            if (m_source.type() == MediaSource::Disc &&
     1166                m_autoplayTitles &&
     1167                m_availableTitles > 1 &&
     1168                m_currentTitle < m_availableTitles) {
     1169                m_aboutToFinishEmitted = false;
     1170            } else if (!m_aboutToFinishEmitted) {
    11131171                m_aboutToFinishEmitted = true; // track is about to finish
    11141172                emit aboutToFinish();
     
    12141272    switch (GST_MESSAGE_TYPE (gstMessage)) {
    12151273
    1216     case GST_MESSAGE_EOS: 
    1217         m_backend->logMessage("EOS recieved", Backend::Info, this);
     1274    case GST_MESSAGE_EOS:
     1275        m_backend->logMessage("EOS received", Backend::Info, this);
    12181276        handleEndOfStream();
    12191277        break;
     
    12231281            gst_message_parse_tag(gstMessage, &tag_list);
    12241282            if (tag_list) {
     1283                TagMap newTags;
     1284                gst_tag_list_foreach (tag_list, &foreach_tag_function, &newTags);
     1285                gst_tag_list_free(tag_list);
     1286
     1287                // Determine if we should no fake the album/artist tags.
     1288                // This is a little confusing as we want to fake it on initial
     1289                // connection where title, album and artist are all missing.
     1290                // There are however times when we get just other information,
     1291                // e.g. codec, and so we want to only do clever stuff if we
     1292                // have a commonly available tag (ORGANIZATION) or we have a
     1293                // change in title
     1294                bool fake_it =
     1295                   (m_isStream
     1296                    && ((!newTags.contains("TITLE")
     1297                         && newTags.contains("ORGANIZATION"))
     1298                        || (newTags.contains("TITLE")
     1299                            && m_metaData.value("TITLE") != newTags.value("TITLE")))
     1300                    && !newTags.contains("ALBUM")
     1301                    && !newTags.contains("ARTIST"));
     1302
    12251303                TagMap oldMap = m_metaData; // Keep a copy of the old one for reference
    1226                 // Append any new meta tags to the existing tag list
    1227                 gst_tag_list_foreach (tag_list, &foreach_tag_function, &m_metaData);
     1304
     1305                // Now we've checked the new data, append any new meta tags to the existing tag list
     1306                // We cannot use TagMap::iterator as this is a multimap and when streaming data
     1307                // could in theory be lost.
     1308                QList<QString> keys = newTags.keys();
     1309                for (QList<QString>::iterator i = keys.begin(); i != keys.end(); ++i) {
     1310                    QString key = *i;
     1311                    if (m_isStream) {
     1312                        // If we're streaming, we need to remove data in m_metaData
     1313                        // in order to stop it filling up indefinitely (as it's a multimap)
     1314                        m_metaData.remove(key);
     1315                    }
     1316                    QList<QString> values = newTags.values(key);
     1317                    for (QList<QString>::iterator j = values.begin(); j != values.end(); ++j) {
     1318                        QString value = *j;
     1319                        QString currVal = m_metaData.value(key);
     1320                        if (!m_metaData.contains(key) || currVal != value) {
     1321                            m_metaData.insert(key, value);
     1322                        }
     1323                    }
     1324                }
     1325
    12281326                m_backend->logMessage("Meta tags found", Backend::Info, this);
    1229                 if (oldMap != m_metaData && !m_loading)
    1230                     emit metaDataChanged(m_metaData);
    1231                 gst_tag_list_free(tag_list);
    1232             }
     1327                if (oldMap != m_metaData) {
     1328                    // This is a bit of a hack to ensure that stream metadata is
     1329                    // returned. We get as much as we can from the Shoutcast server's
     1330                    // StreamTitle= header. If further info is decoded from the stream
     1331                    // itself later, then it will overwrite this info.
     1332                    if (m_isStream && fake_it) {
     1333                        m_metaData.remove("ALBUM");
     1334                        m_metaData.remove("ARTIST");
     1335
     1336                        // Detect whether we want to "fill in the blanks"
     1337                        QString str;
     1338                        if (m_metaData.contains("TITLE"))
     1339                        {
     1340                            str = m_metaData.value("TITLE");
     1341                            int splitpoint;
     1342                            // Check to see if our title matches "%s - %s"
     1343                            // Where neither %s are empty...
     1344                            if ((splitpoint = str.indexOf(" - ")) > 0
     1345                                && str.size() > (splitpoint+3)) {
     1346                                m_metaData.insert("ARTIST", str.left(splitpoint));
     1347                                m_metaData.replace("TITLE", str.mid(splitpoint+3));
     1348                            }
     1349                        } else {
     1350                            str = m_metaData.value("GENRE");
     1351                            if (!str.isEmpty())
     1352                                m_metaData.insert("TITLE", str);
     1353                            else
     1354                                m_metaData.insert("TITLE", "Streaming Data");
     1355                        }
     1356                        if (!m_metaData.contains("ARTIST")) {
     1357                            str = m_metaData.value("LOCATION");
     1358                            if (!str.isEmpty())
     1359                                m_metaData.insert("ARTIST", str);
     1360                            else
     1361                                m_metaData.insert("ARTIST", "Streaming Data");
     1362                        }
     1363                        str = m_metaData.value("ORGANIZATION");
     1364                        if (!str.isEmpty())
     1365                            m_metaData.insert("ALBUM", str);
     1366                        else
     1367                            m_metaData.insert("ALBUM", "Streaming Data");
     1368                    }
     1369                    // As we manipulate the title, we need to recompare
     1370                    // oldMap and m_metaData here...
     1371                    if (oldMap != m_metaData && !m_loading)
     1372                        emit metaDataChanged(m_metaData);
     1373                }
     1374                        }
    12331375        }
    12341376        break;
     
    12561398                m_tickTimer->start();
    12571399                changeState(Phonon::PlayingState);
     1400                if ((m_source.type() == MediaSource::Disc) && (m_currentTitle != m_pendingTitle)) {
     1401                    setTrack(m_pendingTitle);
     1402                }
    12581403                if (m_resumeState && m_oldState == Phonon::PlayingState) {
    12591404                    seek(m_oldPos);
     
    12911436                m_backend->logMessage("gstreamer: pipeline state set to ready", Backend::Debug, this);
    12921437                m_tickTimer->stop();
     1438                if ((m_source.type() == MediaSource::Disc) && (m_currentTitle != m_pendingTitle)) {
     1439                    setTrack(m_pendingTitle);
     1440                }
    12931441                break;
    12941442
     
    13291477                        gst_caps_unref (caps);
    13301478                        gst_object_unref (sinkPad);
    1331                    } 
     1479                   }
    13321480               } else {
    13331481                    setError(QString(err->message), Phonon::FatalError);
     
    14011549        //case GST_MESSAGE_LATENCY: only from 0.10.12
    14021550        //case GST_MESSAGE_ASYNC_DONE: only from 0.10.13
    1403     default: 
    1404         break; 
     1551    default:
     1552        break;
    14051553    }
    14061554}
     
    14181566        m_atEndOfStream = true;
    14191567
    1420     if (m_autoplayTitles &&
     1568    if (m_source.type() == MediaSource::Disc &&
     1569        m_autoplayTitles &&
    14211570        m_availableTitles > 1 &&
    14221571        m_currentTitle < m_availableTitles) {
     
    14421591                setState(m_pendingState);
    14431592        }
     1593    }
     1594}
     1595
     1596void MediaObject::invalidateGraph()
     1597{
     1598    m_resetNeeded = true;
     1599    if (m_state == Phonon::PlayingState || m_state == Phonon::PausedState) {
     1600        changeState(Phonon::StoppedState);
    14441601    }
    14451602}
     
    15031660void MediaObject::_iface_setCurrentTitle(int title)
    15041661{
     1662    m_backend->logMessage(QString("setCurrentTitle %0").arg(title), Backend::Info, this);
     1663    if ((title == m_currentTitle) || (title == m_pendingTitle))
     1664        return;
     1665
     1666    m_pendingTitle = title;
     1667
     1668    if (m_state == Phonon::PlayingState || m_state == Phonon::StoppedState) {
     1669        setTrack(m_pendingTitle);
     1670    } else {
     1671        setState(Phonon::StoppedState);
     1672    }
     1673}
     1674
     1675void MediaObject::setTrack(int title)
     1676{
     1677    if (((m_state != Phonon::PlayingState) && (m_state != Phonon::StoppedState)) || (title < 1) || (title > m_availableTitles))
     1678        return;
     1679
     1680
     1681    //let's seek to the beginning of the song
    15051682    GstFormat trackFormat = gst_format_get_by_nick("track");
    1506     m_backend->logMessage(QString("setCurrentTitle %0").arg(title), Backend::Info, this);
    1507     if ((title == m_currentTitle) || (title < 1) || (title > m_availableTitles))
    1508         return;
    1509 
    1510     m_currentTitle = title;
    1511 
    1512     //let's seek to the beginning of the song
    1513     if (gst_element_seek_simple(m_pipeline, trackFormat, GST_SEEK_FLAG_FLUSH, m_currentTitle - 1)) {
     1683    m_backend->logMessage(QString("setTrack %0").arg(title), Backend::Info, this);
     1684    if (gst_element_seek_simple(m_pipeline, trackFormat, GST_SEEK_FLAG_FLUSH, title - 1)) {
     1685        m_currentTitle = title;
    15141686        updateTotalTime();
    15151687        m_atEndOfStream = false;
Note: See TracChangeset for help on using the changeset viewer.