void MediaPlayerPrivateGStreamerBase::setVolume(float volume) { if (!m_volumeElement) return; LOG_MEDIA_MESSAGE("Setting volume: %f", volume); gst_stream_volume_set_volume(m_volumeElement.get(), GST_STREAM_VOLUME_FORMAT_CUBIC, static_cast<double>(volume)); }
void MediaPlayerPrivateGStreamerBase::setStreamVolumeElement(GstStreamVolume* volume) { ASSERT(!m_volumeElement); m_volumeElement = volume; // We don't set the initial volume because we trust the sink to keep it for us. See // https://bugs.webkit.org/show_bug.cgi?id=118974 for more information. if (!m_player->platformVolumeConfigurationRequired()) { LOG_MEDIA_MESSAGE("Setting stream volume to %f", m_player->volume()); g_object_set(m_volumeElement.get(), "volume", m_player->volume(), NULL); } else LOG_MEDIA_MESSAGE("Not setting stream volume, trusting system one"); LOG_MEDIA_MESSAGE("Setting stream muted %d", m_player->muted()); g_object_set(m_volumeElement.get(), "mute", m_player->muted(), NULL); m_volumeSignalHandler = g_signal_connect(m_volumeElement.get(), "notify::volume", G_CALLBACK(mediaPlayerPrivateVolumeChangedCallback), this); m_muteSignalHandler = g_signal_connect(m_volumeElement.get(), "notify::mute", G_CALLBACK(mediaPlayerPrivateMuteChangedCallback), this); }
// Returns the size of the video IntSize MediaPlayerPrivateGStreamerBase::naturalSize() const { if (!hasVideo()) return IntSize(); if (!m_videoSize.isEmpty()) return m_videoSize; GRefPtr<GstCaps> caps = currentVideoSinkCaps(); if (!caps) return IntSize(); // TODO: handle possible clean aperture data. See // https://bugzilla.gnome.org/show_bug.cgi?id=596571 // TODO: handle possible transformation matrix. See // https://bugzilla.gnome.org/show_bug.cgi?id=596326 // Get the video PAR and original size, if this fails the // video-sink has likely not yet negotiated its caps. int pixelAspectRatioNumerator, pixelAspectRatioDenominator, stride; IntSize originalSize; GstVideoFormat format; if (!getVideoSizeAndFormatFromCaps(caps.get(), originalSize, format, pixelAspectRatioNumerator, pixelAspectRatioDenominator, stride)) return IntSize(); LOG_MEDIA_MESSAGE("Original video size: %dx%d", originalSize.width(), originalSize.height()); LOG_MEDIA_MESSAGE("Pixel aspect ratio: %d/%d", pixelAspectRatioNumerator, pixelAspectRatioDenominator); // Calculate DAR based on PAR and video size. int displayWidth = originalSize.width() * pixelAspectRatioNumerator; int displayHeight = originalSize.height() * pixelAspectRatioDenominator; // Divide display width and height by their GCD to avoid possible overflows. int displayAspectRatioGCD = greatestCommonDivisor(displayWidth, displayHeight); displayWidth /= displayAspectRatioGCD; displayHeight /= displayAspectRatioGCD; // Apply DAR to original video size. This is the same behavior as in xvimagesink's setcaps function. guint64 width = 0, height = 0; if (!(originalSize.height() % displayHeight)) { LOG_MEDIA_MESSAGE("Keeping video original height"); width = gst_util_uint64_scale_int(originalSize.height(), displayWidth, displayHeight); height = static_cast<guint64>(originalSize.height()); } else if (!(originalSize.width() % displayWidth)) { LOG_MEDIA_MESSAGE("Keeping video original width"); height = gst_util_uint64_scale_int(originalSize.width(), displayHeight, displayWidth); width = static_cast<guint64>(originalSize.width()); } else { LOG_MEDIA_MESSAGE("Approximating while keeping original video height"); width = gst_util_uint64_scale_int(originalSize.height(), displayWidth, displayHeight); height = static_cast<guint64>(originalSize.height()); } LOG_MEDIA_MESSAGE("Natural size: %" G_GUINT64_FORMAT "x%" G_GUINT64_FORMAT, width, height); m_videoSize = IntSize(static_cast<int>(width), static_cast<int>(height)); return m_videoSize; }
void PlaybackPipeline::flushAndEnqueueNonDisplayingSamples(Vector<RefPtr<MediaSample> > samples) { ASSERT(WTF::isMainThread()); if (samples.size() == 0) { LOG_MEDIA_MESSAGE("No samples, trackId unknown"); return; } AtomicString trackId = samples[0]->trackID(); LOG_MEDIA_MESSAGE("flushAndEnqueueNonDisplayingSamples: trackId=%s PTS[0]=%f ... PTS[n]=%f", trackId.string().utf8().data(), samples[0]->presentationTime().toFloat(), samples[samples.size()-1]->presentationTime().toFloat()); GST_DEBUG_OBJECT(m_webKitMediaSrc.get(), "Flushing and re-enqueing %d samples for stream %s", samples.size(), trackId.string().utf8().data()); GST_OBJECT_LOCK(m_webKitMediaSrc.get()); Stream* stream = getStreamByTrackId(m_webKitMediaSrc.get(), trackId); if (!stream) { GST_OBJECT_UNLOCK(m_webKitMediaSrc.get()); return; } GstElement* appsrc = stream->appsrc; GST_OBJECT_UNLOCK(m_webKitMediaSrc.get()); // Actually no need to flush. The seek preparations have done it for us. for (Vector<RefPtr<MediaSample> >::iterator it = samples.begin(); it != samples.end(); ++it) { GStreamerMediaSample* sample = static_cast<GStreamerMediaSample*>(it->get()); if (sample->sample() && gst_sample_get_buffer(sample->sample())) { GstSample* gstsample = gst_sample_ref(sample->sample()); GST_BUFFER_FLAG_SET(gst_sample_get_buffer(gstsample), GST_BUFFER_FLAG_DECODE_ONLY); push_sample(GST_APP_SRC(appsrc), gstsample); // gst_app_src_push_sample() uses transfer-none for gstsample gst_sample_unref(gstsample); } } }
static void mediaPlayerPrivateVolumeChangedCallback(GObject*, GParamSpec*, MediaPlayerPrivateGStreamerBase* player) { // This is called when m_volumeElement receives the notify::volume signal. LOG_MEDIA_MESSAGE("Volume changed to: %f", player->volume()); player->volumeChanged(); }
void PlaybackPipeline::setWebKitMediaSrc(WebKitMediaSrc* webKitMediaSrc) { LOG_MEDIA_MESSAGE("webKitMediaSrc=%p", webKitMediaSrc); m_webKitMediaSrc = adoptGRef(static_cast<WebKitMediaSrc*>(gst_object_ref(webKitMediaSrc))); }
void PlaybackPipeline::reattachTrack(RefPtr<SourceBufferPrivateGStreamer> sourceBufferPrivate, RefPtr<TrackPrivateBase> trackPrivate, GstCaps* caps) { LOG_MEDIA_MESSAGE("Re-attaching track"); UNUSED_PARAM(caps); // TODO: Maybe remove this method. // Now the caps change is managed by gst_appsrc_push_sample() // in enqueueSample() and flushAndEnqueueNonDisplayingSamples(). WebKitMediaSrc* webKitMediaSrc = m_webKitMediaSrc.get(); GST_OBJECT_LOCK(webKitMediaSrc); Stream* stream = getStreamBySourceBufferPrivate(webKitMediaSrc, sourceBufferPrivate.get()); GST_OBJECT_UNLOCK(webKitMediaSrc); ASSERT(stream != 0); ASSERT(stream->type != Invalid); GstCaps* oldAppsrccaps = gst_app_src_get_caps(GST_APP_SRC(stream->appsrc)); // Now the caps change is managed by gst_appsrc_push_sample() // in enqueueSample() and flushAndEnqueueNonDisplayingSamples(). // gst_app_src_set_caps(GST_APP_SRC(stream->appsrc), caps); GstCaps* appsrccaps = gst_app_src_get_caps(GST_APP_SRC(stream->appsrc)); const gchar* mediaType = gst_structure_get_name(gst_caps_get_structure(appsrccaps, 0)); if (!gst_caps_is_equal(oldAppsrccaps, appsrccaps)) { LOG_MEDIA_MESSAGE("Caps have changed, but reconstructing the sequence of elements is not supported yet"); gchar* stroldcaps = gst_caps_to_string(oldAppsrccaps); gchar* strnewcaps = gst_caps_to_string(appsrccaps); LOG_MEDIA_MESSAGE("oldcaps: %s", stroldcaps); LOG_MEDIA_MESSAGE("newcaps: %s", strnewcaps); g_free(stroldcaps); g_free(strnewcaps); } int signal = -1; GST_OBJECT_LOCK(webKitMediaSrc); if (g_str_has_prefix(mediaType, "audio")) { ASSERT(stream->type == Audio); signal = SIGNAL_AUDIO_CHANGED; stream->audioTrack = RefPtr<WebCore::AudioTrackPrivateGStreamer>(static_cast<WebCore::AudioTrackPrivateGStreamer*>(trackPrivate.get())); } else if (g_str_has_prefix(mediaType, "video")) { ASSERT(stream->type == Video); signal = SIGNAL_VIDEO_CHANGED; stream->videoTrack = RefPtr<WebCore::VideoTrackPrivateGStreamer>(static_cast<WebCore::VideoTrackPrivateGStreamer*>(trackPrivate.get())); } else if (g_str_has_prefix(mediaType, "text")) { ASSERT(stream->type == Text); signal = SIGNAL_TEXT_CHANGED; // TODO: Support text tracks and mediaTypes related to EME } GST_OBJECT_UNLOCK(webKitMediaSrc); gst_caps_unref(appsrccaps); gst_caps_unref(oldAppsrccaps); if (signal != -1) g_signal_emit(G_OBJECT(stream->parent), webkit_media_src_signals[signal], 0, NULL); }