[rtmpdump] Proposal: dynamically loadable plugins

Howard Chu hyc at highlandsun.com
Sun Feb 26 09:57:51 CET 2012


Antti Ajanki wrote:
> Hi,
>
> These patches implement the plugin API I proposed in my previous mail.
> There is also a slightly modified version of the callback patch
> included. Thanks for Adam for the comments. The same patches are also
> available here:
>
> git clone http://users.tkk.fi/~aajanki/rtmpdump-yle/rtmpdump.git
>
> This has been tested only on Linux. It also cross-compiles on mingw, but
> I haven't tried running it on Windows.

I see that you don't look for plugins in the HOME dir on Windows. Why not?

> The patches add two new dependencies: libltdl for cross-platform dynamic
> library loading support and pthreads for synchronizing the loading of
> the plugins.

I'm quite uncomfortable with these added dependencies. libltdl I can sort of 
understand, but pthreads? No. That increases the footprint of the library by a 
huge amount, for practically no benefit. It is the calling app's 
responsibility to ensure that only one thread tries to initialize this library.

Also, you seem to have completely missed the philosophy behind this code, and 
the reason why AVals are used everywhere.

It's not enough to write good code or correct code. You should always write 
*optimal* code. Some of the rules for optimal code:

1) Never compute at runtime what is already known at compile time.
E.g., never use strlen("a string constant") when you can simply use sizeof("a 
string constant")-1.

2) Never compute the same data twice at runtime, unless the second occurrence 
is very long after the first one and it's cheaper to recompute it than to 
remember it.

In this case, your struct RTMPPluginOption is the obvious offender:

+typedef struct RTMPPluginOption {
+  const char *name;  /* Name of the option in SetupURL string */
+  const char *type;  /* Type name to be shown in the help screen */
+  const char *usage; /* A short description in the help screen */
+  void (*parseOption)(const AVal *name, const AVal *val, void *ctx);
+    /* Function that will be called if the SetupURL string contains
+     * this option. ctx is the user data pointer returned by the
+     * create hook. */
+} RTMPPluginOption;

It's even more heinous since you *know* that you need to use AVals to talk to 
the rest of the library.

This function
+static RTMP_Plugin *FindPluginByOpt(const AVal *opt,
+                                    const RTMPPluginOption **optinfo)
+{
+  RTMPPluginNode *pl = GetPlugins();
+  while (pl)
+    {
+      const RTMPPluginOption *plopt = pl->plugin->options;
+      while (plopt && plopt->name)
+        {
+          if (opt->av_len == strlen(plopt->name) &&
+              strcasecmp(opt->av_val, plopt->name) == 0)
+            {
+              *optinfo = plopt;
+              return pl->plugin;
+            }
+
+          plopt++;
+        }
+
+      pl = pl->next;
+    }
+
+  return NULL;

The surest sign that a programmer has been careless is repeated use of 
strlen() inside a loop.

This should have used something like:
   if (opt->av_len == plopt->name.av_len && !strcasecmp(opt->av_val, 
plopt->name.av_val))

Also in the callback patch you've got a namespace violation; rtmp.h must not 
define any user-visible symbols that aren't prefixed by RTMP_ or rtmp_. Your 
NUM_CALLBACK_TYPES should be RTMP_NUM_CALLBACK_TYPES.

I'm not in love with the notion of multiple types of callbacks, each with 
differing signatures. I would prefer a single callback definition, passing the 
invocation type down to the callback and letting the callback decide if it 
wants to handle it or not. In practice I suspect most of the 4 type pointers 
will be unused. But I'm willing to listen to reasons justifying why this 
approach is better.

Overall it's a good idea and a good effort. But I won't merge it as-is. If I 
have time I may commit a cleaned up version later. If you would like to clean 
it up yourself and repost it, that would be better than waiting for me to do it.

> Here is a plugin (together with fully patches rtmpdump sources) that
> uses the API: http://users.tkk.fi/~aajanki/rtmpdump-yle/yle-dl-1.99.1.tar.gz
>
> The plugin does custom authentication for
> http://areena-beta.yle.fi/ng/areena site. An example command for testing
> the plugin:
>
> rtmpdump -r "rtmp://flashu.yle.fi/mediakanta//x
> swfUrl=http://areena-beta.yle.fi/static/player/1.1/flowplayer/flowplayer.cluster-3.2.3.swf
> tcUrl=rtmp://flashu.yle.fi/mediakanta/
> pageUrl=http://areena-beta.yle.fi/ng/areena/tv/1370427/#/play
> yle=2f4d1d102a34462696ad23573adfd296" -o video.flv
>
> Antti


More information about the rtmpdump mailing list