content/media/gstreamer/GStreamerFormatHelper.cpp

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

     1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     2 /* vim:set ts=2 sw=2 sts=2 et cindent: */
     3 /* This Source Code Form is subject to the terms of the Mozilla Public
     4  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
     5  * You can obtain one at http://mozilla.org/MPL/2.0/. */
     7 #include "GStreamerFormatHelper.h"
     8 #include "nsCharSeparatedTokenizer.h"
     9 #include "nsString.h"
    10 #include "GStreamerLoader.h"
    12 #define ENTRY_FORMAT(entry) entry[0]
    13 #define ENTRY_CAPS(entry) entry[1]
    15 namespace mozilla {
    17 GStreamerFormatHelper* GStreamerFormatHelper::gInstance = nullptr;
    18 bool GStreamerFormatHelper::sLoadOK = false;
    20 GStreamerFormatHelper* GStreamerFormatHelper::Instance() {
    21   if (!gInstance) {
    22     if ((sLoadOK = load_gstreamer())) {
    23       gst_init(nullptr, nullptr);
    24     }
    26     gInstance = new GStreamerFormatHelper();
    27   }
    29   return gInstance;
    30 }
    32 void GStreamerFormatHelper::Shutdown() {
    33   delete gInstance;
    34   gInstance = nullptr;
    35 }
    37 static char const *const sContainers[6][2] = {
    38   {"video/mp4", "video/quicktime"},
    39   {"video/quicktime", "video/quicktime"},
    40   {"audio/mp4", "audio/x-m4a"},
    41   {"audio/x-m4a", "audio/x-m4a"},
    42   {"audio/mpeg", "audio/mpeg, mpegversion=(int)1"},
    43   {"audio/mp3", "audio/mpeg, mpegversion=(int)1"},
    44 };
    46 static char const *const sCodecs[9][2] = {
    47   {"avc1.42E01E", "video/x-h264"},
    48   {"avc1.42001E", "video/x-h264"},
    49   {"avc1.58A01E", "video/x-h264"},
    50   {"avc1.4D401E", "video/x-h264"},
    51   {"avc1.64001E", "video/x-h264"},
    52   {"avc1.64001F", "video/x-h264"},
    53   {"mp4v.20.3", "video/3gpp"},
    54   {"mp4a.40.2", "audio/mpeg, mpegversion=(int)4"},
    55   {"mp3", "audio/mpeg, mpegversion=(int)1"},
    56 };
    58 static char const * const sDefaultCodecCaps[][2] = {
    59   {"video/mp4", "video/x-h264"},
    60   {"video/quicktime", "video/x-h264"},
    61   {"audio/mp4", "audio/mpeg, mpegversion=(int)4"},
    62   {"audio/x-m4a", "audio/mpeg, mpegversion=(int)4"},
    63   {"audio/mp3", "audio/mpeg, layer=(int)3"},
    64   {"audio/mpeg", "audio/mpeg, layer=(int)3"}
    65 };
    67 GStreamerFormatHelper::GStreamerFormatHelper()
    68   : mFactories(nullptr),
    69     mCookie(static_cast<uint32_t>(-1))
    70 {
    71   if (!sLoadOK) {
    72     return;
    73   }
    75   mSupportedContainerCaps = gst_caps_new_empty();
    76   for (unsigned int i = 0; i < G_N_ELEMENTS(sContainers); i++) {
    77     const char* capsString = sContainers[i][1];
    78     GstCaps* caps = gst_caps_from_string(capsString);
    79     gst_caps_append(mSupportedContainerCaps, caps);
    80   }
    82   mSupportedCodecCaps = gst_caps_new_empty();
    83   for (unsigned int i = 0; i < G_N_ELEMENTS(sCodecs); i++) {
    84     const char* capsString = sCodecs[i][1];
    85     GstCaps* caps = gst_caps_from_string(capsString);
    86     gst_caps_append(mSupportedCodecCaps, caps);
    87   }
    88 }
    90 GStreamerFormatHelper::~GStreamerFormatHelper() {
    91   if (!sLoadOK) {
    92     return;
    93   }
    95   gst_caps_unref(mSupportedContainerCaps);
    96   gst_caps_unref(mSupportedCodecCaps);
    98   if (mFactories)
    99     g_list_free(mFactories);
   100 }
   102 static GstCaps *
   103 GetContainerCapsFromMIMEType(const char *aType) {
   104   /* convert aMIMEType to gst container caps */
   105   const char* capsString = nullptr;
   106   for (uint32_t i = 0; i < G_N_ELEMENTS(sContainers); i++) {
   107     if (!strcmp(ENTRY_FORMAT(sContainers[i]), aType)) {
   108       capsString = ENTRY_CAPS(sContainers[i]);
   109       break;
   110     }
   111   }
   113   if (!capsString) {
   114     /* we couldn't find any matching caps */
   115     return nullptr;
   116   }
   118   return gst_caps_from_string(capsString);
   119 }
   121 static GstCaps *
   122 GetDefaultCapsFromMIMEType(const char *aType) {
   123   GstCaps *caps = GetContainerCapsFromMIMEType(aType);
   125   for (uint32_t i = 0; i < G_N_ELEMENTS(sDefaultCodecCaps); i++) {
   126     if (!strcmp(sDefaultCodecCaps[i][0], aType)) {
   127       GstCaps *tmp = gst_caps_from_string(sDefaultCodecCaps[i][1]);
   129       gst_caps_append(caps, tmp);
   130       return caps;
   131     }
   132   }
   134   return nullptr;
   135 }
   137 bool GStreamerFormatHelper::CanHandleMediaType(const nsACString& aMIMEType,
   138                                                const nsAString* aCodecs) {
   139   if (!sLoadOK) {
   140     return false;
   141   }
   143   const char *type;
   144   NS_CStringGetData(aMIMEType, &type, nullptr);
   146   GstCaps *caps;
   147   if (aCodecs && !aCodecs->IsEmpty()) {
   148     caps = ConvertFormatsToCaps(type, aCodecs);
   149   } else {
   150     // Get a minimal set of codec caps for this MIME type we should support so
   151     // that we don't overreport MIME types we are able to play.
   152     caps = GetDefaultCapsFromMIMEType(type);
   153   }
   155   if (!caps) {
   156     return false;
   157   }
   159   bool ret = HaveElementsToProcessCaps(caps);
   160   gst_caps_unref(caps);
   162   return ret;
   163 }
   165 GstCaps* GStreamerFormatHelper::ConvertFormatsToCaps(const char* aMIMEType,
   166                                                      const nsAString* aCodecs) {
   167   NS_ASSERTION(sLoadOK, "GStreamer library not linked");
   169   unsigned int i;
   171   GstCaps *caps = GetContainerCapsFromMIMEType(aMIMEType);
   172   if (!caps) {
   173     return nullptr;
   174   }
   176   /* container only */
   177   if (!aCodecs) {
   178     return caps;
   179   }
   181   nsCharSeparatedTokenizer tokenizer(*aCodecs, ',');
   182   while (tokenizer.hasMoreTokens()) {
   183     const nsSubstring& codec = tokenizer.nextToken();
   184     const char *capsString = nullptr;
   186     for (i = 0; i < G_N_ELEMENTS(sCodecs); i++) {
   187       if (codec.EqualsASCII(ENTRY_FORMAT(sCodecs[i]))) {
   188         capsString = ENTRY_CAPS(sCodecs[i]);
   189         break;
   190       }
   191     }
   193     if (!capsString) {
   194       gst_caps_unref(caps);
   195       return nullptr;
   196     }
   198     GstCaps* tmp = gst_caps_from_string(capsString);
   199     /* appends and frees tmp */
   200     gst_caps_append(caps, tmp);
   201   }
   203   return caps;
   204 }
   206 static gboolean FactoryFilter(GstPluginFeature *aFeature, gpointer)
   207 {
   208   if (!GST_IS_ELEMENT_FACTORY(aFeature)) {
   209     return FALSE;
   210   }
   212   // TODO _get_klass doesn't exist in 1.0
   213   const gchar *className =
   214     gst_element_factory_get_klass(GST_ELEMENT_FACTORY_CAST(aFeature));
   216   if (!strstr(className, "Decoder") && !strstr(className, "Demux")) {
   217     return FALSE;
   218   }
   220   return gst_plugin_feature_get_rank(aFeature) >= GST_RANK_MARGINAL;
   221 }
   223 /**
   224  * Returns true if any |aFactory| caps intersect with |aCaps|
   225  */
   226 static bool SupportsCaps(GstElementFactory *aFactory, GstCaps *aCaps)
   227 {
   228   for (const GList *iter = gst_element_factory_get_static_pad_templates(aFactory); iter; iter = iter->next) {
   229     GstStaticPadTemplate *templ = static_cast<GstStaticPadTemplate *>(iter->data);
   231     if (templ->direction == GST_PAD_SRC) {
   232       continue;
   233     }
   235     GstCaps *caps = gst_static_caps_get(&templ->static_caps);
   236     if (!caps) {
   237       continue;
   238     }
   240     if (gst_caps_can_intersect(gst_static_caps_get(&templ->static_caps), aCaps)) {
   241       return true;
   242     }
   243   }
   245   return false;
   246 }
   248 bool GStreamerFormatHelper::HaveElementsToProcessCaps(GstCaps* aCaps) {
   249   NS_ASSERTION(sLoadOK, "GStreamer library not linked");
   251   GList* factories = GetFactories();
   253   /* here aCaps contains [containerCaps, [codecCaps1, [codecCaps2, ...]]] so process
   254    * caps structures individually as we want one element for _each_
   255    * structure */
   256   for (unsigned int i = 0; i < gst_caps_get_size(aCaps); i++) {
   257     GstStructure* s = gst_caps_get_structure(aCaps, i);
   258     GstCaps* caps = gst_caps_new_full(gst_structure_copy(s), nullptr);
   260     bool found = false;
   261     for (GList *elem = factories; elem; elem = elem->next) {
   262       if (SupportsCaps(GST_ELEMENT_FACTORY_CAST(elem->data), caps)) {
   263         found = true;
   264         break;
   265       }
   266     }
   268     if (!found) {
   269       return false;
   270     }
   272     gst_caps_unref(caps);
   273   }
   275   return true;
   276 }
   278 bool GStreamerFormatHelper::CanHandleContainerCaps(GstCaps* aCaps)
   279 {
   280   NS_ASSERTION(sLoadOK, "GStreamer library not linked");
   282   return gst_caps_can_intersect(aCaps, mSupportedContainerCaps);
   283 }
   285 bool GStreamerFormatHelper::CanHandleCodecCaps(GstCaps* aCaps)
   286 {
   287   NS_ASSERTION(sLoadOK, "GStreamer library not linked");
   289   return gst_caps_can_intersect(aCaps, mSupportedCodecCaps);
   290 }
   292 GList* GStreamerFormatHelper::GetFactories() {
   293   NS_ASSERTION(sLoadOK, "GStreamer library not linked");
   295 #if GST_VERSION_MAJOR >= 1
   296   uint32_t cookie = gst_registry_get_feature_list_cookie(gst_registry_get());
   297 #else
   298   uint32_t cookie = gst_default_registry_get_feature_list_cookie();
   299 #endif
   300   if (cookie != mCookie) {
   301     g_list_free(mFactories);
   302 #if GST_VERSION_MAJOR >= 1
   303     mFactories =
   304       gst_registry_feature_filter(gst_registry_get(),
   305                                   (GstPluginFeatureFilter)FactoryFilter,
   306                                   false, nullptr);
   307 #else
   308     mFactories =
   309       gst_default_registry_feature_filter((GstPluginFeatureFilter)FactoryFilter,
   310                                           false, nullptr);
   311 #endif
   312     mCookie = cookie;
   313   }
   315   return mFactories;
   316 }
   318 } // namespace mozilla

mercurial