Hulu Plugin Development Thread - Developers only!

  Thread Rating:
  • 0 Votes - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Post Reply
highlandsun Offline
Senior Member
Posts: 152
Joined: Mar 2009
Reputation: 0
Post: #106
motd2k: this is generic to RTMP, not specific to RTMPE. And the official RTMP spec from Adobe is now public info. http://www.adobe.com/devnet/rtmp/pdf/rtm...on_1.0.pdf

The same bug exists in flvstreamer, last time I checked.
find quote
motd2k Offline
Team-XBMC Developer
Posts: 666
Joined: Dec 2008
Reputation: 0
Location: England
Post: #107
Yea its cool. RTMP is fine, i know its public - i've looked over librtmp alot recently.

If there's a bug (specific to rtmp) then thats fine. To what field are you refering by 'Channel ID' though? If you post a packet dump i'll get it fixed on SVN



motd
find quote
highlandsun Offline
Senior Member
Posts: 152
Joined: Mar 2009
Reputation: 0
Post: #108
In section 6.1.1 of the spec, the Chunk Stream ID can be 1 to 3 bytes long. The current code only handles a 1 byte ID (values 0-63).

Probably easier for me to just give you the patch...
Code:
diff -wur old/rtmp.cpp new/rtmp.cpp
--- old/rtmp.cpp    2009-05-14 10:13:54.000000000 -0700
+++ new/rtmp.cpp    2009-07-26 19:14:03.000000000 -0700
@@ -1026,6 +1129,28 @@

   packet.m_headerType = (type & 0xc0) >> 6;
   packet.m_nChannel = (type & 0x3f);
+  if ( packet.m_nChannel == 0 )
+  {
+    if (ReadN(&type,1) != 1)
+    {
+      Log(LOGERROR, "%s, failed to read RTMP packet header 2nd byte", __FUNCTION__);
+      return false;
+    }
+    packet.m_nChannel = (unsigned)type;
+    packet.m_nChannel += 64;
+  } else if ( packet.m_nChannel == 1 )
+  {
+    char t[2];
+    int tmp;
+    if (ReadN(t,2) != 2)
+    {
+      Log(LOGERROR, "%s, failed to read RTMP packet header 3rd byte", __FUNCTION__);
+      return false;
+    }
+    tmp = (((unsigned)t[0])<<8) + (unsigned)t[1];
+    packet.m_nChannel = tmp + 64;
+    Log(LOGDEBUG, "%s, m_nChannel: %0x", __FUNCTION__, packet.m_nChannel);
+  }

   int nSize = packetSize[packet.m_headerType];
  
diff -wur old/rtmp.h new/rtmp.h
--- old/rtmp.h    2009-05-12 17:15:20.000000000 -0700
+++ new/rtmp.h    2009-07-26 19:56:43.000000000 -0700
@@ -205,14 +211,12 @@
       char *m_pBuffer;      // data read from socket
       char *m_pBufferStart; // pointer into m_pBuffer of next byte to process
       int  m_nBufferSize;   // number of unprocessed bytes in buffer
-      RTMPPacket m_vecChannelsIn[64];
-      RTMPPacket m_vecChannelsOut[64];
-      int  m_channelTimestamp[64]; // abs timestamp of last packet
+      RTMPPacket m_vecChannelsIn[65600];
+      RTMPPacket m_vecChannelsOut[65600];
+      int  m_channelTimestamp[65600]; // abs timestamp of last packet

       double m_fDuration; // duration of stream in seconds
   };
};

#endif
-
-
diff -wur old/rtmppacket.h new/rtmppacket.h
--- old/rtmppacket.h    2009-05-14 09:45:32.000000000 -0700
+++ new/rtmppacket.h    2009-07-13 22:33:23.000000000 -0700
@@ -56,7 +56,7 @@

       BYTE    m_headerType;
       BYTE    m_packetType;
-      BYTE    m_nChannel;
+      int    m_nChannel;
       int32_t    m_nInfoField1; // 3 first bytes
       int32_t    m_nInfoField2; // last 4 bytes in a long header, absolute timestamp for long headers, relative timestamp for short headers
       bool      m_hasAbsTimestamp; // timestamp absolute or relative?

I should point out, it's possible I have the 3 byte decode wrong; the text says the 3rd byte is most significant, but the Figure implies that it's the 2nd byte. So maybe it should be t[0] + t[1] << 8 instead. I suspect though that the actual value doesn't matter to us...
(This post was last modified: 2009-07-31 10:05 by highlandsun.)
find quote
highlandsun Offline
Senior Member
Posts: 152
Joined: Mar 2009
Reputation: 0
Post: #109
Cool, I see my patch has been added to flvstreamer's svn now.
find quote
motd2k Offline
Team-XBMC Developer
Posts: 666
Joined: Dec 2008
Reputation: 0
Location: England
Post: #110
The massive allocations were a problem, needed to convert to std vector but have had alot on the plate.
find quote
zoltar12 Offline
Junior Member
Posts: 13
Joined: Dec 2008
Reputation: 0
Post: #111
Is your C++ patch to fix an issue in XBMC that was causing the HULU plugin to no longer work? Or was the patch for flvstreamer?
Quote:Cool, I see my patch has been added to flvstreamer's svn now.
find quote
highlandsun Offline
Senior Member
Posts: 152
Joined: Mar 2009
Reputation: 0
Post: #112
The patch was for a bug in flvstreamer. I haven't looked at the XBMC hulu plugin lately.
find quote
highlandsun Offline
Senior Member
Posts: 152
Joined: Mar 2009
Reputation: 0
Post: #113
Locutus73 Wrote:Hi, I just wrote a set of scripts useful to retrive Hulu’s pid and auth parameters.
These tools can be used as helpers for applications like get_iplayer http://linuxcentre.net/getiplayer/
List of contents:
hulu-get-keys.c : Based on decswf.c by hyc@highlandsun.com, this program must be compiled against
swfdec-0.9.2 and is useful to retrive pid encryption keys from enc.swf file
downloaded from Hulu.

I've just patched this code to also retrieve the keys for decrypting the SMIL file. Finally got tired of extracting them by hand...

Code:
--- hulu-get-keys.c    2009-03-12 23:11:30.000000000 -0700
+++ hulu-get-keys.c.N    2009-10-14 01:35:09.000000000 -0700
@@ -1,6 +1,7 @@
/* Invoke a function from a given swf and print the result.
  * 2009-03-11 Locutus73
  * based on decswf.c 2009-02-22 hyc@highlandsun.com
+ * updated again on 2009-10-14 hyc@highlandsun.com
  *
  * Tested with swfdec-0.9.2. Uses library-internal APIs, use
  * at your own risk...
@@ -23,15 +24,28 @@
struct _SwfdecSandbox *swfdec_sandbox_get_for_url(SwfdecPlayer *,
    SwfdecURL *,guint,gboolean);

+/* I just use this inside gdb when examining objects. e.g.
+ * call g_hash_table_foreach(keypair->properties, ghfunc, 0)
+ * which will tell you that the keypair object has some child objects
+ * a2, a3, and a couple others I didn't bother to look at...
+ * -- hyc
+ */
+static void ghfunc(gpointer key, gpointer value, gpointer user_data)
+{
+    printf("%s: %p\n", key, value);
+}
+
int main (int argc, char **argv)
{
    SwfdecPlayer* player;
    SwfdecAsContext *ctx;
    SwfdecAsValue out;
    SwfdecAsObject *obj;
+    SwfdecAsObject *xmlkeys, *keypair;
    struct _SwfdecSandbox *sbox;
-    const char *txt;
+    const char *txt, *a2, *a3;
    gboolean res;
+    gint32 i, nkeys;

    if (argc < 2)
    {
@@ -51,7 +65,7 @@
    }
    swfdec_player_set_url(player,url);

-    // We wait till the initialization is completed
+    /* We wait till the initialization is completed */
    while (!swfdec_player_is_initialized (player))
    {
            long next = swfdec_player_get_next_event (player);
@@ -88,10 +102,38 @@
        fprintf(stderr, "class copyrighted_strings not found\n");
        return 1;
    }
-    obj = SWFDEC_AS_VALUE_GET_OBJECT(out);
    txt = swfdec_as_value_to_string(ctx,out);
    puts(txt);

-    return !res;
+    a2 = swfdec_as_context_get_string(ctx, "a2");    
+    a3 = swfdec_as_context_get_string(ctx, "a3");    
+    txt = swfdec_as_context_get_string(ctx, "xmldecskeys");    
+    res = swfdec_as_object_get_variable(obj, txt, &out);
+    if (!res) {
+        fprintf(stderr, "class xmldecskeys not found\n");
+        return 1;
+    }
+    xmlkeys = SWFDEC_AS_VALUE_GET_OBJECT(out);
+    nkeys = swfdec_as_array_get_length(xmlkeys);
+    for (i=0; i<nkeys; i++) {
+        swfdec_as_array_get_value(xmlkeys, i, &out);
+        keypair = SWFDEC_AS_VALUE_GET_OBJECT(out);
+        res = swfdec_as_object_get_variable(keypair, a2, &out);
+        if (!res) {
+            fprintf(stderr, "class xmldecskeys[%d].a2 not found\n", i);
+            return 1;
+        }
+        txt = swfdec_as_value_to_string(ctx,out);
+        puts(txt);

+        res = swfdec_as_object_get_variable(keypair, a3, &out);
+        if (!res) {
+            fprintf(stderr, "class xmldecskeys[%d].a3 not found\n", i);
+            return 1;
+        }
+        txt = swfdec_as_value_to_string(ctx,out);
+        puts(txt);
+    }
+
+    return !res;
}
find quote
highlandsun Offline
Senior Member
Posts: 152
Joined: Mar 2009
Reputation: 0
Post: #114
And one more patch to retrieve the v= parameter. (This must be applied on top of the previous patch.) Also I've formatted the output as perl source:

Code:
diff -u -r1.2 ./hulu-get-keys.c
--- ./hulu-get-keys.c    2009/10/28 03:05:45    1.2
+++ ./hulu-get-keys.c    2009/11/02 08:14:10
@@ -41,7 +41,7 @@
    SwfdecAsContext *ctx;
    SwfdecAsValue out;
    SwfdecAsObject *obj;
-    SwfdecAsObject *xmlkeys, *keypair;
+    SwfdecAsObject *keys, *keypair;
    struct _SwfdecSandbox *sbox;
    const char *txt, *a2, *a3;
    gboolean res;
@@ -96,14 +96,27 @@
    }
    obj = SWFDEC_AS_VALUE_GET_OBJECT(out);

+    txt = swfdec_as_context_get_string(ctx, "v");    
+    res = swfdec_as_object_call(obj, txt, 0, NULL, &out);
+    txt = swfdec_as_value_to_string(ctx,out);
+    printf("my $v='%s';\n", txt);
+
    txt = swfdec_as_context_get_string(ctx, "copyrighted_strings");    
    res = swfdec_as_object_get_variable(obj, txt, &out);
    if (!res) {
        fprintf(stderr, "class copyrighted_strings not found\n");
        return 1;
    }
-    txt = swfdec_as_value_to_string(ctx,out);
-    puts(txt);
+    keys = SWFDEC_AS_VALUE_GET_OBJECT(out);
+    nkeys = swfdec_as_array_get_length(keys);
+    printf("my @pid=(");
+    for (i=0; i<nkeys; i++) {
+        swfdec_as_array_get_value(keys, i, &out);
+        txt = swfdec_as_value_to_string(ctx,out);
+        if (i) printf(",");
+        printf("\n\t'%s'", txt);
+    }
+    printf(");\n");

    a2 = swfdec_as_context_get_string(ctx, "a2");    
    a3 = swfdec_as_context_get_string(ctx, "a3");    
@@ -113,10 +126,11 @@
        fprintf(stderr, "class xmldecskeys not found\n");
        return 1;
    }
-    xmlkeys = SWFDEC_AS_VALUE_GET_OBJECT(out);
-    nkeys = swfdec_as_array_get_length(xmlkeys);
+    keys = SWFDEC_AS_VALUE_GET_OBJECT(out);
+    nkeys = swfdec_as_array_get_length(keys);
+    printf("my @smil=(");
    for (i=0; i<nkeys; i++) {
-        swfdec_as_array_get_value(xmlkeys, i, &out);
+        swfdec_as_array_get_value(keys, i, &out);
        keypair = SWFDEC_AS_VALUE_GET_OBJECT(out);
        res = swfdec_as_object_get_variable(keypair, a2, &out);
        if (!res) {
@@ -124,7 +138,8 @@
            return 1;
        }
        txt = swfdec_as_value_to_string(ctx,out);
-        puts(txt);
+        if (i) printf(",");
+        printf("\n['%s', ", txt);

        res = swfdec_as_object_get_variable(keypair, a3, &out);
        if (!res) {
@@ -132,8 +147,9 @@
            return 1;
        }
        txt = swfdec_as_value_to_string(ctx,out);
-        puts(txt);
+        printf("'%s']", txt);
    }
+    printf(");\n");

    return !res;
}
find quote
highlandsun Offline
Senior Member
Posts: 152
Joined: Mar 2009
Reputation: 0
Post: #115
http://code.google.com/p/xbmc-addons/iss...tail?id=49

Need some help figuring out why the buffering is broken. Perhaps it will work better in a newer SVN rev?

Yes, it works fine using r28276.
(This post was last modified: 2010-03-20 00:48 by highlandsun.)
find quote
highlandsun Offline
Senior Member
Posts: 152
Joined: Mar 2009
Reputation: 0
Post: #116
They are in the midst of migrating to a new CDN, and some of the parsing needs to be fixed again.

Is anyone using this plugin now, or am I just talking to myself? If no one's using it I'm not going to bother updating the patch.
find quote
maruchan Offline
Senior Member
Posts: 277
Joined: Feb 2009
Reputation: 0
Post: #117
highlandsun Wrote:Is anyone using this plugin now, or am I just talking to myself? If no one's using it I'm not going to bother updating the patch.

The plugin is working again? I've been following this thread as Hulu support in XBMC again has been my dream since it broke... I'm currently switching between XBMC and Boxee simply for the Hulu support. I'm not familiar with using a diff patch nor do I have the original Hulu plugin to patch it with, but I'll try to get this up and running today. Thanks!
find quote
cbrunhaver Offline
Member
Posts: 84
Joined: Sep 2009
Reputation: 0
Post: #118
ditto. It would be fantastic to get hulu support going again.

-Chris
find quote
highlandsun Offline
Senior Member
Posts: 152
Joined: Mar 2009
Reputation: 0
Post: #119
You're going to need several customizations to get this working; the plugin uses some python crypto modules that aren't part of the default XBMC build. I guess you should be able to just install the modules in your ~/.xbmc directory but I don't know the details. (And since it does the crypto in python, you no longer need gnash or any other external programs.)

You also need to recompile XBMC anyway, incorporating the patch here http://trac.xbmc.org/ticket/8971 (which I also discussed in this thread http://forum.xbmc.org/showthread.php?tid=70512 )

Since I already have python 2.6 installed on my machine, I configured my XBMC build to use the system python instead of its internal one.

When applying the patch, I just replace xbmc/xbmc/lib/libRTMP with a symlink to rtmpdump/librtmp. That way I don't have to change any other link or compile paths.

I've uploaded my plugin to http://highlandsun.com/hyc/Hulu.zip, you should be able to just extract it in your plugins folder. (It's the actual source tree, so it contains a lot of extra junk you don't need. It also contains the SVN history so you can type "svn diff" to see what I fixed.)
(This post was last modified: 2010-04-03 02:05 by highlandsun.)
find quote
highlandsun Offline
Senior Member
Posts: 152
Joined: Mar 2009
Reputation: 0
Post: #120
I just noticed, this plugin is using the RSS feeds to populate the list of episodes. But the RSS feeds only show "new" material, stuff that was recently added. So e.g. if a show has 2 seasons, the RSS feed will likely only list the latest episodes in season 2. That whole part needs to be reworked...
find quote
Post Reply