[FFmpeg-soc] [soc]: r4506 - in rtmp: rtmp.patch rtmpdec.c rtmpproto.c

kostya subversion at mplayerhq.hu
Tue Jun 23 20:18:18 CEST 2009


Author: kostya
Date: Tue Jun 23 20:18:17 2009
New Revision: 4506

Log:
Convert RTMP demuxer into protocol handler

Replaced:
   rtmp/rtmpproto.c   (contents, props changed)
      - copied, changed from r4505, rtmp/rtmpdec.c
Deleted:
   rtmp/rtmpdec.c
Modified:
   rtmp/rtmp.patch

Modified: rtmp/rtmp.patch
==============================================================================
--- rtmp/rtmp.patch	Tue Jun 23 20:01:44 2009	(r4505)
+++ rtmp/rtmp.patch	Tue Jun 23 20:18:17 2009	(r4506)
@@ -1,192 +1,20 @@
-Index: libavformat/flvdec.c
-===================================================================
---- libavformat/flvdec.c	(revision 19214)
-+++ libavformat/flvdec.c	(working copy)
-@@ -304,39 +304,38 @@
-     return 0;
- }
- 
--static int flv_read_packet(AVFormatContext *s, AVPacket *pkt)
-+int ff_flv_read_packet(AVFormatContext *s, ByteIOContext *pb, AVPacket *pkt, int *wrong_dts)
- {
--    FLVContext *flv = s->priv_data;
-     int ret, i, type, size, flags, is_audio;
-     int64_t next, pos;
-     int64_t dts, pts = AV_NOPTS_VALUE;
-     AVStream *st = NULL;
- 
-  for(;;){
--    pos = url_ftell(s->pb);
--    url_fskip(s->pb, 4); /* size of previous packet */
--    type = get_byte(s->pb);
--    size = get_be24(s->pb);
--    dts = get_be24(s->pb);
--    dts |= get_byte(s->pb) << 24;
-+    pos = url_ftell(pb);
-+    url_fskip(pb, 4); /* size of previous packet */
-+    type = get_byte(pb);
-+    size = get_be24(pb);
-+    dts = get_be24(pb);
-+    dts |= get_byte(pb) << 24;
- //    av_log(s, AV_LOG_DEBUG, "type:%d, size:%d, dts:%d\n", type, size, dts);
--    if (url_feof(s->pb))
-+    if (url_feof(pb))
-         return AVERROR_EOF;
--    url_fskip(s->pb, 3); /* stream id, always 0 */
-+    url_fskip(pb, 3); /* stream id, always 0 */
-     flags = 0;
- 
-     if(size == 0)
-         continue;
- 
--    next= size + url_ftell(s->pb);
-+    next= size + url_ftell(pb);
- 
-     if (type == FLV_TAG_TYPE_AUDIO) {
-         is_audio=1;
--        flags = get_byte(s->pb);
-+        flags = get_byte(pb);
-         size--;
-     } else if (type == FLV_TAG_TYPE_VIDEO) {
-         is_audio=0;
--        flags = get_byte(s->pb);
-+        flags = get_byte(pb);
-         size--;
-         if ((flags & 0xf0) == 0x50) /* video info / command frame */
-             goto skip;
-@@ -346,7 +345,7 @@
-         else /* skip packet */
-             av_log(s, AV_LOG_DEBUG, "skipping flv packet: type %d, size %d, flags %d\n", type, size, flags);
-     skip:
--        url_fseek(s->pb, next, SEEK_SET);
-+        url_fseek(pb, next, SEEK_SET);
-         continue;
-     }
- 
-@@ -370,7 +369,7 @@
-        ||(st->discard >= AVDISCARD_BIDIR  &&  ((flags & FLV_VIDEO_FRAMETYPE_MASK) == FLV_FRAME_DISP_INTER && !is_audio))
-        || st->discard >= AVDISCARD_ALL
-        ){
--        url_fseek(s->pb, next, SEEK_SET);
-+        url_fseek(pb, next, SEEK_SET);
-         continue;
-     }
-     if ((flags & FLV_VIDEO_FRAMETYPE_MASK) == FLV_FRAME_KEY)
-@@ -379,17 +378,17 @@
-  }
- 
-     // if not streamed and no duration from metadata then seek to end to find the duration from the timestamps
--    if(!url_is_streamed(s->pb) && s->duration==AV_NOPTS_VALUE){
-+    if(!url_is_streamed(pb) && s->duration==AV_NOPTS_VALUE){
-         int size;
--        const int64_t pos= url_ftell(s->pb);
--        const int64_t fsize= url_fsize(s->pb);
--        url_fseek(s->pb, fsize-4, SEEK_SET);
--        size= get_be32(s->pb);
--        url_fseek(s->pb, fsize-3-size, SEEK_SET);
--        if(size == get_be24(s->pb) + 11){
--            s->duration= get_be24(s->pb) * (int64_t)AV_TIME_BASE / 1000;
-+        const int64_t pos= url_ftell(pb);
-+        const int64_t fsize= url_fsize(pb);
-+        url_fseek(pb, fsize-4, SEEK_SET);
-+        size= get_be32(pb);
-+        url_fseek(pb, fsize-3-size, SEEK_SET);
-+        if(size == get_be24(pb) + 11){
-+            s->duration= get_be24(pb) * (int64_t)AV_TIME_BASE / 1000;
-         }
--        url_fseek(s->pb, pos, SEEK_SET);
-+        url_fseek(pb, pos, SEEK_SET);
-     }
- 
-     if(is_audio){
-@@ -407,16 +406,16 @@
- 
-     if (st->codec->codec_id == CODEC_ID_AAC ||
-         st->codec->codec_id == CODEC_ID_H264) {
--        int type = get_byte(s->pb);
-+        int type = get_byte(pb);
-         size--;
-         if (st->codec->codec_id == CODEC_ID_H264) {
--            int32_t cts = (get_be24(s->pb)+0xff800000)^0xff800000; // sign extension
-+            int32_t cts = (get_be24(pb)+0xff800000)^0xff800000; // sign extension
-             pts = dts + cts;
-             if (cts < 0) { // dts are wrong
--                flv->wrong_dts = 1;
-+                *wrong_dts = 1;
-                 av_log(s, AV_LOG_WARNING, "negative cts, previous timestamps might be wrong\n");
-             }
--            if (flv->wrong_dts)
-+            if (*wrong_dts)
-                 dts = AV_NOPTS_VALUE;
-         }
-         if (type == 0) {
-@@ -442,7 +441,7 @@
-     if (!size)
-         return AVERROR(EAGAIN);
- 
--    ret= av_get_packet(s->pb, pkt, size);
-+    ret= av_get_packet(pb, pkt, size);
-     if (ret < 0) {
-         return AVERROR(EIO);
-     }
-@@ -459,6 +458,13 @@
-     return ret;
- }
- 
-+static int flv_read_packet(AVFormatContext *s, AVPacket *pkt)
-+{
-+    FLVContext *flv = s->priv_data;
-+
-+    return ff_flv_read_packet(s, &s->pb, pkt, &flv->wrong_dts);
-+}
-+
- AVInputFormat flv_demuxer = {
-     "flv",
-     NULL_IF_CONFIG_SMALL("FLV format"),
 Index: libavformat/Makefile
 ===================================================================
---- libavformat/Makefile	(revision 19214)
+--- libavformat/Makefile	(revision 19256)
 +++ libavformat/Makefile	(working copy)
-@@ -188,6 +188,7 @@
- OBJS-$(CONFIG_ROQ_DEMUXER)               += idroq.o
- OBJS-$(CONFIG_ROQ_MUXER)                 += raw.o
- OBJS-$(CONFIG_RPL_DEMUXER)               += rpl.o
-+OBJS-$(CONFIG_RTMP_DEMUXER)              += rtmpdec.o rtmppkt.o
- OBJS-$(CONFIG_RTP_MUXER)                 += rtp.o         \
-                                             rtp_aac.o     \
-                                             rtp_amr.o     \
-@@ -246,6 +247,7 @@
+@@ -246,6 +246,7 @@
  OBJS-$(CONFIG_GOPHER_PROTOCOL)           += gopher.o
  OBJS-$(CONFIG_HTTP_PROTOCOL)             += http.o
  OBJS-$(CONFIG_PIPE_PROTOCOL)             += file.o
-+OBJS-$(CONFIG_RTMP_PROTOCOL)             += rtmpproto.o
++OBJS-$(CONFIG_RTMP_PROTOCOL)             += rtmpproto.o rtmppkt.o
  OBJS-$(CONFIG_RTP_PROTOCOL)              += rtpproto.o
  OBJS-$(CONFIG_TCP_PROTOCOL)              += tcp.o
  OBJS-$(CONFIG_UDP_PROTOCOL)              += udp.o
-Index: libavformat/flv.h
-===================================================================
---- libavformat/flv.h	(revision 19214)
-+++ libavformat/flv.h	(working copy)
-@@ -110,4 +110,6 @@
-     AMF_DATA_TYPE_UNSUPPORTED = 0x0d,
- } AMFDataType;
- 
-+extern int ff_flv_read_packet(AVFormatContext *s, ByteIOContext *pb, AVPacket *pkt, int *wrong_dts);
-+
- #endif /* AVFORMAT_FLV_H */
 Index: libavformat/allformats.c
 ===================================================================
---- libavformat/allformats.c	(revision 19214)
+--- libavformat/allformats.c	(revision 19256)
 +++ libavformat/allformats.c	(working copy)
-@@ -165,6 +165,7 @@
-     REGISTER_MUXDEMUX (RM, rm);
-     REGISTER_MUXDEMUX (ROQ, roq);
-     REGISTER_DEMUXER  (RPL, rpl);
-+    REGISTER_DEMUXER  (RTMP, rtmp);
-     REGISTER_MUXER    (RTP, rtp);
-     REGISTER_DEMUXER  (RTSP, rtsp);
-     REGISTER_DEMUXER  (SDP, sdp);
-@@ -209,6 +210,7 @@
+@@ -209,6 +209,7 @@
      REGISTER_PROTOCOL (GOPHER, gopher);
      REGISTER_PROTOCOL (HTTP, http);
      REGISTER_PROTOCOL (PIPE, pipe);

Copied and modified: rtmp/rtmpproto.c (from r4505, rtmp/rtmpdec.c)
==============================================================================
--- rtmp/rtmpdec.c	Tue Jun 23 20:01:44 2009	(r4505, copy source)
+++ rtmp/rtmpproto.c	Tue Jun 23 20:18:17 2009	(r4506)
@@ -1,5 +1,5 @@
 /*
- * RTMP input format
+ * RTMP network protocol
  * Copyright (c) 2009 Kostya Shishkov
  *
  * This file is part of FFmpeg.
@@ -19,6 +19,10 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  */
 
+/**
+ * @file libavformat/rtmpproto.c
+ * RTMP protocol
+ */
 /* needed for gethostname() */
 #define _XOPEN_SOURCE 600
 
@@ -29,6 +33,7 @@
 #include "avformat.h"
 
 #include <unistd.h>
+#include <stdarg.h>
 #include <sys/time.h>
 #include "network.h"
 
@@ -52,7 +57,7 @@ typedef struct RTMPContext {
     int           main_stream_id;
     uint8_t*      flv_data;
     int           flv_size;
-    ByteIOContext pb;
+    int           flv_off;
     int           wrong_dts;
     uint32_t      video_ts, audio_ts;
 } RTMPContext;
@@ -79,7 +84,7 @@ static const uint8_t rtmp_server_key[] =
     0xE6, 0x36, 0xCF, 0xEB, 0x31, 0xAE
 };
 
-static void gen_connect(AVFormatContext *s, RTMPContext *rt, const char *proto,
+static void gen_connect(URLContext *s, RTMPContext *rt, const char *proto,
                         const char *host, int port, const char *app)
 {
     RTMPPacket pkt;
@@ -126,13 +131,13 @@ static void gen_connect(AVFormatContext 
     rtmp_packet_write(rt->rtmp_hd, &pkt, rt->chunk_size, rt->prev_pkt[1]);
 }
 
-static void gen_create_stream(AVFormatContext *s, RTMPContext *rt)
+static void gen_create_stream(URLContext *s, RTMPContext *rt)
 {
     RTMPPacket pkt;
     uint8_t *p;
     double num;
 
-    av_log(s, AV_LOG_DEBUG, "Creating stream...\n");
+    //av_log(s, AV_LOG_DEBUG, "Creating stream...\n");
     rtmp_packet_create(&pkt, RTMP_VIDEO_CHANNEL, RTMP_PT_INVOKE, 0, 25);
 
     num = 3.0;
@@ -145,13 +150,13 @@ static void gen_create_stream(AVFormatCo
     rtmp_packet_destroy(&pkt);
 }
 
-static void gen_play(AVFormatContext *s, RTMPContext *rt)
+static void gen_play(URLContext *s, RTMPContext *rt)
 {
     RTMPPacket pkt;
     uint8_t *p;
     double num;
 
-    av_log(s, AV_LOG_DEBUG, "Sending play command for '%s'\n", rt->playpath);
+    //av_log(s, AV_LOG_DEBUG, "Sending play command for '%s'\n", rt->playpath);
     rtmp_packet_create(&pkt, RTMP_VIDEO_CHANNEL, RTMP_PT_INVOKE, 0,
                        29 + strlen(rt->playpath));
     pkt.extra = rt->main_stream_id;
@@ -180,7 +185,7 @@ static void gen_play(AVFormatContext *s,
     rtmp_packet_destroy(&pkt);
 }
 
-static void gen_pong(AVFormatContext *s, RTMPContext *rt, RTMPPacket *ppkt)
+static void gen_pong(URLContext *s, RTMPContext *rt, RTMPPacket *ppkt)
 {
     RTMPPacket pkt;
     uint8_t *p;
@@ -267,7 +272,7 @@ static int rtmp_validate_digest(uint8_t 
     return 0;
 }
 
-static int rtmp_handshake(AVFormatContext *s, RTMPContext *rt)
+static int rtmp_handshake(URLContext *s, RTMPContext *rt)
 {
     AVLFG rnd;
     uint8_t tosend    [RTMP_HANDSHAKE_PACKET_SIZE+1];
@@ -277,7 +282,7 @@ static int rtmp_handshake(AVFormatContex
     int server_pos, client_pos;
     uint8_t digest[32];
 
-    av_log(s, AV_LOG_DEBUG, "Handshaking...\n");
+    //av_log(s, AV_LOG_DEBUG, "Handshaking...\n");
 
     av_lfg_init(&rnd, 0xDEADC0DE);
     // generate handshake packet - 1536 bytes of pseudorandom data
@@ -295,23 +300,23 @@ static int rtmp_handshake(AVFormatContex
     url_write(rt->rtmp_hd, tosend, RTMP_HANDSHAKE_PACKET_SIZE + 1);
     i = url_read_complete(rt->rtmp_hd, serverdata, RTMP_HANDSHAKE_PACKET_SIZE + 1);
     if (i != RTMP_HANDSHAKE_PACKET_SIZE + 1) {
-        av_log(s, AV_LOG_ERROR, "Cannot read RTMP handshake response\n");
+        //av_log(s, AV_LOG_ERROR, "Cannot read RTMP handshake response\n");
         return -1;
     }
     i = url_read_complete(rt->rtmp_hd, clientdata, RTMP_HANDSHAKE_PACKET_SIZE);
     if (i != RTMP_HANDSHAKE_PACKET_SIZE) {
-        av_log(s, AV_LOG_ERROR, "Cannot read RTMP handshake response\n");
+        //av_log(s, AV_LOG_ERROR, "Cannot read RTMP handshake response\n");
         return -1;
     }
 
-    av_log(s, AV_LOG_DEBUG, "Server version %d.%d.%d.%d\n",
-           serverdata[5], serverdata[6], serverdata[7], serverdata[8]);
+    //av_log(s, AV_LOG_DEBUG, "Server version %d.%d.%d.%d\n",
+    //       serverdata[5], serverdata[6], serverdata[7], serverdata[8]);
 
     server_pos = rtmp_validate_digest(serverdata + 1, 772);
     if (!server_pos) {
         server_pos = rtmp_validate_digest(serverdata + 1, 8);
         if (!server_pos) {
-            av_log(s, AV_LOG_ERROR, "Server response validating failed\n");
+            //av_log(s, AV_LOG_ERROR, "Server response validating failed\n");
             return -1;
         }
     }
@@ -323,7 +328,7 @@ static int rtmp_handshake(AVFormatContex
                      digest, 32,
                      digest);
     if (memcmp(digest, clientdata + RTMP_HANDSHAKE_PACKET_SIZE - 32, 32)) {
-        av_log(s, AV_LOG_ERROR, "Signature mismatch\n");
+        //av_log(s, AV_LOG_ERROR, "Signature mismatch\n");
         return -1;
     }
 
@@ -341,99 +346,19 @@ static int rtmp_handshake(AVFormatContex
     return 0;
 }
 
-static int rtmp_probe(AVProbeData *p)
-{
-    if (av_strstart(p->filename, "rtmp:", NULL))
-        return AVPROBE_SCORE_MAX;
-    return 0;
-}
-
-static int rtmp_read_header(AVFormatContext *s,
-                            AVFormatParameters *ap)
-{
-    RTMPContext *rt = s->priv_data;
-    char proto[8], hostname[256], path[512], app[128], *fname;
-    int port;
-    uint8_t buf[2048];
-    AVStream *st;
-
-    url_split(proto, sizeof(proto), NULL, 0, hostname, sizeof(hostname), &port,
-              path, sizeof(path), s->filename);
-
-    if(port == -1)
-        port = RTMP_DEFAULT_PORT;
-    snprintf(buf, sizeof(buf), "tcp://%s:%d", hostname, port);
-    url_open(&rt->rtmp_hd, buf, URL_RDWR);
-    rt->state = STATE_START;
-    if (rtmp_handshake(s, rt))
-        return -1;
-
-    rt->chunk_size = 128;
-    rt->state = STATE_HANDSHAKED;
-    //extract "app" part from path
-    if (!strncmp(path, "/ondemand/", 10)) {
-        fname = path + 10;
-        memcpy(app, "ondemand", 9);
-    } else {
-        char *p = strchr(path + 1, '/');
-        if (!p) {
-            fname = path + 1;
-            app[0] = '\0';
-        } else {
-            fname = strchr(p + 1, '/');
-            if (!fname) {
-                fname = p + 1;
-                memcpy(app, path + 1, p - path - 1);
-                app[p - path - 1] = 0;
-            } else {
-                fname++;
-                memcpy(app, path + 1, fname - path - 2);
-                app[fname - path - 2] = 0;
-            }
-        }
-    }
-    if (!strcmp(fname + strlen(fname) - 4, ".f4v") ||
-        !strcmp(fname + strlen(fname) - 4, ".mp4")) {
-        memcpy(rt->playpath, "mp4:", 5);
-    } else {
-        rt->playpath[0] = ':';
-        rt->playpath[0] = 0;
-    }
-    strncat(rt->playpath, fname, sizeof(rt->playpath) - 5);
-
-    av_log(s, AV_LOG_DEBUG, "Proto = %s, path = %s, app = %s, fname = %s\n",
-           proto, path, app, rt->playpath);
-    gen_connect(s, rt, proto, hostname, port, app);
-
-    st = av_new_stream(s, 0);
-    if (!st)
-        return -1;
-    st->codec->codec_type = CODEC_TYPE_VIDEO;
-    av_set_pts_info(st, 32, 1, 1000); /* 32 bit pts in ms */
-
-    st = av_new_stream(s, 1);
-    if (!st)
-        return -1;
-    st->codec->codec_type = CODEC_TYPE_AUDIO;
-    av_set_pts_info(st, 32, 1, 1000); /* 32 bit pts in ms */
-
-    init_put_byte(&rt->pb, NULL, 0, 0, NULL, NULL, NULL, NULL);
-    return 0;
-}
-
-static int rtmp_parse_result(AVFormatContext *s, RTMPContext *rt, RTMPPacket *pkt)
+static int rtmp_parse_result(URLContext *s, RTMPContext *rt, RTMPPacket *pkt)
 {
     int i, t;
 
     switch (pkt->type) {
     case RTMP_PT_CHUNK_SIZE:
         if (pkt->data_size != 4) {
-            av_log(s, AV_LOG_ERROR, "Chunk size change packet is not 4 (%d)\n",
-                   pkt->data_size);
+            //av_log(s, AV_LOG_ERROR, "Chunk size change packet is not 4 (%d)\n",
+            //       pkt->data_size);
             return -1;
         }
         rt->chunk_size = AV_RB32(pkt->data);
-        av_log(s, AV_LOG_DEBUG, "New chunk size = %d\n", rt->chunk_size);
+        //av_log(s, AV_LOG_DEBUG, "New chunk size = %d\n", rt->chunk_size);
         break;
     case RTMP_PT_PING:
         t = AV_RB16(pkt->data);
@@ -453,7 +378,7 @@ static int rtmp_parse_result(AVFormatCon
             case STATE_CONNECTING:
                 //extract a number from result
                 if (pkt->data[10] || pkt->data[19] != 5 || pkt->data[20])
-                    av_log(s, AV_LOG_WARNING, "Unexpected reply on connect()\n");
+                    av_log(NULL, AV_LOG_WARNING, "Unexpected reply on connect()\n");
                 else
                     rt->main_stream_id = (int) av_int2dbl(AV_RB64(pkt->data + 21));
                 gen_play(s, rt);
@@ -469,7 +394,7 @@ static int rtmp_parse_result(AVFormatCon
     return 0;
 }
 
-static int rtmp_read_packet(AVFormatContext *s, AVPacket *pkt)
+static int get_packet(URLContext *s)
 {
     RTMPContext *rt = s->priv_data;
     struct timespec ts;
@@ -478,7 +403,7 @@ static int rtmp_read_packet(AVFormatCont
     ts.tv_sec = 0;
     ts.tv_nsec = 500000000;
 
-    while (url_ftell(&rt->pb) == rt->flv_size) {
+    for(;;) {
         RTMPPacket rpkt;
         int has_data = 0;
         if ((ret = rtmp_packet_read(rt->rtmp_hd, &rpkt,
@@ -512,50 +437,168 @@ static int rtmp_read_packet(AVFormatCont
                 rt->audio_ts += rpkt.timestamp;
                 ts = rt->audio_ts;
             }
+            rt->flv_off  = 0;
             rt->flv_size = rpkt.data_size + 15;
             rt->flv_data = p = av_realloc(rt->flv_data, rt->flv_size);
-            bytestream_put_be32(&p, 0);
             bytestream_put_byte(&p, rpkt.type);
             bytestream_put_be24(&p, rpkt.data_size);
             bytestream_put_be24(&p, ts);
             bytestream_put_byte(&p, ts >> 24);
             bytestream_put_be24(&p, 0);
             bytestream_put_buffer(&p, rpkt.data, rpkt.data_size);
+            bytestream_put_be32(&p, 0);
             has_data = 1;
         } else if (rpkt.type == RTMP_PT_METADATA) {
-            rt->flv_size = rpkt.data_size + 4;
+            rt->flv_off  = 0;
+            rt->flv_size = rpkt.data_size;
             rt->flv_data = av_realloc(rt->flv_data, rt->flv_size);
-            memset(rt->flv_data, 0, 4); //previous packet size
-            memcpy(rt->flv_data + 4, rpkt.data, rpkt.data_size);
+            memcpy(rt->flv_data, rpkt.data, rpkt.data_size);
             has_data = 1;
         }
         rtmp_packet_destroy(&rpkt);
-        if (has_data) {
-            init_put_byte(&rt->pb, rt->flv_data, rt->flv_size, 0, NULL, NULL, NULL, NULL);
+        if (has_data)
             break;
+    }
+    return 0;
+}
+
+/**
+ * url syntax: rtp://host:port[?option=val...]
+ * option: 'ttl=n'       : set the ttl value (for multicast only)
+ *         'localport=n' : set the local port to n
+ */
+static int rtmp_open(URLContext *s, const char *uri, int flags)
+{
+    RTMPContext *rt;
+    char proto[8], hostname[256], path[1024], app[128], *fname;
+    uint8_t buf[2048];
+    int port, is_input;
+
+    is_input = !(flags & URL_WRONLY);
+
+    rt = av_mallocz(sizeof(RTMPContext));
+    if (!rt)
+        return AVERROR(ENOMEM);
+    s->priv_data = rt;
+
+    url_split(proto, sizeof(proto), NULL, 0, hostname, sizeof(hostname), &port,
+              path, sizeof(path), s->filename);
+
+    if (port == -1)
+        port = RTMP_DEFAULT_PORT;
+    snprintf(buf, sizeof(buf), "tcp://%s:%d", hostname, port);
+
+    if (url_open(&rt->rtmp_hd, buf, URL_RDWR) < 0)
+        goto fail;
+
+    if (!is_input) {
+        //av_log(s, AV_LOG_ERROR, "RTMP output is not supported yet\n");
+        goto fail;
+    } else {
+    rt->state = STATE_START;
+    if (rtmp_handshake(s, rt))
+        return -1;
+
+    rt->chunk_size = 128;
+    rt->state = STATE_HANDSHAKED;
+    //extract "app" part from path
+    if (!strncmp(path, "/ondemand/", 10)) {
+        fname = path + 10;
+        memcpy(app, "ondemand", 9);
+    } else {
+        char *p = strchr(path + 1, '/');
+        if (!p) {
+            fname = path + 1;
+            app[0] = '\0';
+        } else {
+            fname = strchr(p + 1, '/');
+            if (!fname) {
+                fname = p + 1;
+                strncpy(app, path + 1, p - path - 1);
+                app[p - path - 1] = '\0';
+            } else {
+                fname++;
+                strncpy(app, path + 1, fname - path - 2);
+                app[fname - path - 2] = '\0';
+            }
         }
     }
-    ret = ff_flv_read_packet(s, &rt->pb, pkt, &rt->wrong_dts);
-    if (ret == AVERROR_EOF)
-        return AVERROR(EAGAIN);
-    return ret;
+    if (!strcmp(fname + strlen(fname) - 4, ".f4v") ||
+        !strcmp(fname + strlen(fname) - 4, ".mp4")) {
+        memcpy(rt->playpath, "mp4:", 5);
+    } else {
+        rt->playpath[0] = ':';
+        rt->playpath[0] = 0;
+    }
+    strncat(rt->playpath, fname, sizeof(rt->playpath) - 5);
+
+    //av_log(s, AV_LOG_DEBUG, "Proto = %s, path = %s, app = %s, fname = %s\n",
+    //       proto, path, app, rt->playpath);
+    gen_connect(s, rt, proto, hostname, port, app);
+    }
+
+    rt->flv_data = av_malloc(13);
+    rt->flv_size = 13;
+    rt->flv_off  = 0;
+    memcpy(rt->flv_data, "FLV\1\5\0\0\0\011\0\0\0\0", 13);
+
+    s->max_packet_size = url_get_max_packet_size(rt->rtmp_hd);
+    s->is_streamed = 1;
+    return 0;
+
+fail:
+    if (rt->rtmp_hd)
+        url_close(rt->rtmp_hd);
+    av_free(rt);
+    return AVERROR(EIO);
 }
 
-static int rtmp_read_close(AVFormatContext *s)
+static int rtmp_read(URLContext *s, uint8_t *buf, int size)
 {
     RTMPContext *rt = s->priv_data;
+    int orig_size = size;
+    int ret;
+
+    while (size > 0) {
+        int data_left = rt->flv_size - rt->flv_off;
+
+        if (data_left >= size) {
+            memcpy(buf, rt->flv_data + rt->flv_off, size);
+            rt->flv_off += size;
+            return orig_size;
+        }
+        if (data_left > 0) {
+            memcpy(buf, rt->flv_data + rt->flv_off, data_left);
+            buf  += data_left;
+            size -= data_left;
+            rt->flv_off = rt->flv_size;
+        }
+        if ((ret = get_packet(s)) < 0)
+           return ret;
+    }
+    return orig_size;
+}
+
+static int rtmp_write(URLContext *h, uint8_t *buf, int size)
+{
+    return 0;
+}
+
+static int rtmp_close(URLContext *h)
+{
+    RTMPContext *rt = h->priv_data;
 
     av_freep(&rt->flv_data);
     url_close(rt->rtmp_hd);
+    av_free(rt);
     return 0;
 }
 
-AVInputFormat rtmp_demuxer = {
+URLProtocol rtmp_protocol = {
     "rtmp",
-    NULL_IF_CONFIG_SMALL("RTMP"),
-    sizeof(RTMPContext),
-    rtmp_probe,
-    rtmp_read_header,
-    rtmp_read_packet,
-    rtmp_read_close,
+    rtmp_open,
+    rtmp_read,
+    rtmp_write,
+    NULL, /* seek */
+    rtmp_close,
 };


More information about the FFmpeg-soc mailing list