mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-01-09 05:14:24 +00:00
Bug 981869 - Blacklist crashy flump3dec gstreamer plugin - r=kinetik
This commit is contained in:
parent
e29d8e1845
commit
3aeced5479
@ -8,6 +8,7 @@
|
||||
#include "nsCharSeparatedTokenizer.h"
|
||||
#include "nsString.h"
|
||||
#include "GStreamerLoader.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
|
||||
#define ENTRY_FORMAT(entry) entry[0]
|
||||
#define ENTRY_CAPS(entry) entry[1]
|
||||
@ -64,6 +65,10 @@ static char const * const sDefaultCodecCaps[][2] = {
|
||||
{"audio/mpeg", "audio/mpeg, layer=(int)3"}
|
||||
};
|
||||
|
||||
static char const * const sPluginBlacklist[] = {
|
||||
"flump3dec",
|
||||
};
|
||||
|
||||
GStreamerFormatHelper::GStreamerFormatHelper()
|
||||
: mFactories(nullptr),
|
||||
mCookie(static_cast<uint32_t>(-1))
|
||||
@ -203,21 +208,58 @@ GstCaps* GStreamerFormatHelper::ConvertFormatsToCaps(const char* aMIMEType,
|
||||
return caps;
|
||||
}
|
||||
|
||||
/* static */ bool
|
||||
GStreamerFormatHelper::IsBlacklistEnabled()
|
||||
{
|
||||
static bool sBlacklistEnabled;
|
||||
static bool sBlacklistEnabledCached = false;
|
||||
|
||||
if (!sBlacklistEnabledCached) {
|
||||
Preferences::AddBoolVarCache(&sBlacklistEnabled,
|
||||
"media.gstreamer.enable-blacklist", true);
|
||||
sBlacklistEnabledCached = true;
|
||||
}
|
||||
|
||||
return sBlacklistEnabled;
|
||||
}
|
||||
|
||||
/* static */ bool
|
||||
GStreamerFormatHelper::IsPluginFeatureBlacklisted(GstPluginFeature *aFeature,
|
||||
FactoryType aTypes)
|
||||
{
|
||||
if (!IsBlacklistEnabled()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const gchar *className =
|
||||
gst_element_factory_get_klass(GST_ELEMENT_FACTORY_CAST(aFeature));
|
||||
|
||||
const gchar *factoryName =
|
||||
gst_plugin_feature_get_name(aFeature);
|
||||
|
||||
if ((!(aTypes & FactoryTypeDecoder) && strstr(className, "Decoder")) ||
|
||||
(!(aTypes & FactoryTypeDemuxer) && strstr(className, "Demuxer")) ||
|
||||
(!(aTypes & FactoryTypeParser) && strstr(className, "Parser"))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < G_N_ELEMENTS(sPluginBlacklist); i++) {
|
||||
if (!strcmp(factoryName, sPluginBlacklist[i])) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static gboolean FactoryFilter(GstPluginFeature *aFeature, gpointer)
|
||||
{
|
||||
if (!GST_IS_ELEMENT_FACTORY(aFeature)) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// TODO _get_klass doesn't exist in 1.0
|
||||
const gchar *className =
|
||||
gst_element_factory_get_klass(GST_ELEMENT_FACTORY_CAST(aFeature));
|
||||
|
||||
if (!strstr(className, "Decoder") && !strstr(className, "Demux")) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return gst_plugin_feature_get_rank(aFeature) >= GST_RANK_MARGINAL;
|
||||
return !GStreamerFormatHelper::IsPluginFeatureBlacklisted(aFeature,
|
||||
(FactoryType)(FactoryTypeDecoder|FactoryTypeDemuxer));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -13,6 +13,13 @@
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
enum FactoryType {
|
||||
FactoryTypeDecoder = 1 << 0,
|
||||
FactoryTypeDemuxer = 1 << 1,
|
||||
FactoryTypeParser = 1 << 2,
|
||||
FactoryTypeAll = FactoryTypeDecoder|FactoryTypeDemuxer|FactoryTypeParser
|
||||
};
|
||||
|
||||
class GStreamerFormatHelper {
|
||||
/* This class can be used to query the GStreamer registry for the required
|
||||
* demuxers/decoders from nsHTMLMediaElement::CanPlayType.
|
||||
@ -29,6 +36,10 @@ class GStreamerFormatHelper {
|
||||
bool CanHandleContainerCaps(GstCaps* aCaps);
|
||||
bool CanHandleCodecCaps(GstCaps* aCaps);
|
||||
|
||||
static bool IsBlacklistEnabled();
|
||||
static bool IsPluginFeatureBlacklisted(GstPluginFeature *aFeature,
|
||||
FactoryType aTypes = FactoryTypeAll);
|
||||
|
||||
static GstCaps* ConvertFormatsToCaps(const char* aMIMEType,
|
||||
const nsAString* aCodecs);
|
||||
|
||||
|
@ -62,6 +62,7 @@ GST_FUNC(LIBGSTREAMER, gst_parse_bin_from_description)
|
||||
GST_FUNC(LIBGSTREAMER, gst_pipeline_get_bus)
|
||||
GST_FUNC(LIBGSTREAMER, gst_pipeline_get_type)
|
||||
GST_FUNC(LIBGSTREAMER, gst_plugin_feature_get_rank)
|
||||
GST_FUNC(LIBGSTREAMER, gst_plugin_feature_get_type)
|
||||
GST_FUNC(LIBGSTREAMER, gst_registry_feature_filter)
|
||||
GST_FUNC(LIBGSTREAMER, gst_registry_get_feature_list_cookie)
|
||||
GST_FUNC(LIBGSTREAMER, gst_segment_init)
|
||||
@ -88,6 +89,7 @@ GST_FUNC(LIBGSTREAMER, gst_pad_add_event_probe)
|
||||
GST_FUNC(LIBGSTREAMER, gst_pad_alloc_buffer)
|
||||
GST_FUNC(LIBGSTREAMER, gst_pad_get_negotiated_caps)
|
||||
GST_FUNC(LIBGSTREAMER, gst_pad_set_bufferalloc_function)
|
||||
GST_FUNC(LIBGSTREAMER, gst_plugin_feature_get_name)
|
||||
GST_FUNC(LIBGSTREAMER, gst_registry_get_default)
|
||||
GST_FUNC(LIBGSTREAMER, gst_segment_set_newsegment)
|
||||
GST_FUNC(LIBGSTVIDEO, gst_video_format_get_component_height)
|
||||
|
@ -195,6 +195,9 @@ nsresult GStreamerReader::Init(MediaDecoderReader* aCloneDonor)
|
||||
g_signal_connect(G_OBJECT(mPlayBin), "element-added",
|
||||
G_CALLBACK(GStreamerReader::PlayElementAddedCb), this);
|
||||
|
||||
g_signal_connect(G_OBJECT(mPlayBin), "element-added",
|
||||
G_CALLBACK(GStreamerReader::ElementAddedCb), this);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -214,6 +217,47 @@ GStreamerReader::Error(GstBus *aBus, GstMessage *aMessage)
|
||||
return GST_BUS_PASS;
|
||||
}
|
||||
|
||||
void GStreamerReader::ElementAddedCb(GstBin *aPlayBin,
|
||||
GstElement *aElement,
|
||||
gpointer aUserData)
|
||||
{
|
||||
const gchar *name =
|
||||
gst_plugin_feature_get_name(GST_PLUGIN_FEATURE(gst_element_get_factory(aElement)));
|
||||
|
||||
if (!strcmp(name, "uridecodebin")) {
|
||||
g_signal_connect(G_OBJECT(aElement), "autoplug-sort",
|
||||
G_CALLBACK(GStreamerReader::ElementFilterCb), aUserData);
|
||||
}
|
||||
}
|
||||
|
||||
GValueArray *GStreamerReader::ElementFilterCb(GstURIDecodeBin *aBin,
|
||||
GstPad *aPad,
|
||||
GstCaps *aCaps,
|
||||
GValueArray *aFactories,
|
||||
gpointer aUserData)
|
||||
{
|
||||
return ((GStreamerReader*)aUserData)->ElementFilter(aBin, aPad, aCaps, aFactories);
|
||||
}
|
||||
|
||||
GValueArray *GStreamerReader::ElementFilter(GstURIDecodeBin *aBin,
|
||||
GstPad *aPad,
|
||||
GstCaps *aCaps,
|
||||
GValueArray *aFactories)
|
||||
{
|
||||
GValueArray *filtered = g_value_array_new(aFactories->n_values);
|
||||
|
||||
for (unsigned int i = 0; i < aFactories->n_values; i++) {
|
||||
GValue *value = &aFactories->values[i];
|
||||
GstPluginFeature *factory = GST_PLUGIN_FEATURE(g_value_peek_pointer(value));
|
||||
|
||||
if (!GStreamerFormatHelper::IsPluginFeatureBlacklisted(factory)) {
|
||||
g_value_array_append(filtered, value);
|
||||
}
|
||||
}
|
||||
|
||||
return filtered;
|
||||
}
|
||||
|
||||
void GStreamerReader::PlayBinSourceSetupCb(GstElement* aPlayBin,
|
||||
GParamSpec* pspec,
|
||||
gpointer aUserData)
|
||||
@ -1148,7 +1192,7 @@ void GStreamerReader::Eos(GstAppSink* aSink)
|
||||
* This callback is called while the pipeline is automatically built, after a
|
||||
* new element has been added to the pipeline. We use it to find the
|
||||
* uridecodebin instance used by playbin and connect to it to apply our
|
||||
* whitelist.
|
||||
* blacklist.
|
||||
*/
|
||||
void
|
||||
GStreamerReader::PlayElementAddedCb(GstBin *aBin, GstElement *aElement,
|
||||
@ -1185,9 +1229,8 @@ GStreamerReader::ShouldAutoplugFactory(GstElementFactory* aFactory, GstCaps* aCa
|
||||
|
||||
/**
|
||||
* This is called by uridecodebin (running inside playbin), after it has found
|
||||
* candidate factories to continue decoding the stream. We apply the whitelist
|
||||
* here, allowing only demuxers and decoders that output the formats we want to
|
||||
* support.
|
||||
* candidate factories to continue decoding the stream. We apply the blacklist
|
||||
* here, disallowing known-crashy plugins.
|
||||
*/
|
||||
GValueArray*
|
||||
GStreamerReader::AutoplugSortCb(GstElement* aElement, GstPad* aPad,
|
||||
|
@ -25,6 +25,8 @@
|
||||
#include "ImageContainer.h"
|
||||
#include "nsRect.h"
|
||||
|
||||
struct GstURIDecodeBin;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
namespace dom {
|
||||
@ -90,6 +92,30 @@ private:
|
||||
static GstBusSyncReply ErrorCb(GstBus *aBus, GstMessage *aMessage, gpointer aUserData);
|
||||
GstBusSyncReply Error(GstBus *aBus, GstMessage *aMessage);
|
||||
|
||||
/*
|
||||
* We attach this callback to playbin so that when uridecodebin is
|
||||
* constructed, we can then list for its autoplug-sort signal to blacklist
|
||||
* the elements it can construct.
|
||||
*/
|
||||
static void ElementAddedCb(GstBin *aPlayBin,
|
||||
GstElement *aElement,
|
||||
gpointer aUserData);
|
||||
|
||||
/*
|
||||
* Called on the autoplug-sort signal emitted by uridecodebin for filtering
|
||||
* the elements it uses.
|
||||
*/
|
||||
static GValueArray *ElementFilterCb(GstURIDecodeBin *aBin,
|
||||
GstPad *aPad,
|
||||
GstCaps *aCaps,
|
||||
GValueArray *aFactories,
|
||||
gpointer aUserData);
|
||||
|
||||
GValueArray *ElementFilter(GstURIDecodeBin *aBin,
|
||||
GstPad *aPad,
|
||||
GstCaps *aCaps,
|
||||
GValueArray *aFactories);
|
||||
|
||||
/* Called on the source-setup signal emitted by playbin. Used to
|
||||
* configure appsrc .
|
||||
*/
|
||||
@ -169,7 +195,7 @@ private:
|
||||
static bool ShouldAutoplugFactory(GstElementFactory* aFactory, GstCaps* aCaps);
|
||||
|
||||
/* Called by decodebin during autoplugging. We use it to apply our
|
||||
* container/codec whitelist.
|
||||
* container/codec blacklist.
|
||||
*/
|
||||
static GValueArray* AutoplugSortCb(GstElement* aElement,
|
||||
GstPad* aPad, GstCaps* aCaps,
|
||||
|
@ -307,6 +307,7 @@ pref("media.webm.intel_decoder.enabled", false);
|
||||
#endif
|
||||
#ifdef MOZ_GSTREAMER
|
||||
pref("media.gstreamer.enabled", true);
|
||||
pref("media.gstreamer.enable-blacklist", true);
|
||||
#endif
|
||||
#ifdef MOZ_APPLEMEDIA
|
||||
pref("media.apple.mp3.enabled", true);
|
||||
|
Loading…
Reference in New Issue
Block a user