Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | RSS feed

  1. /*
  2.  * RTMP network protocol
  3.  * Copyright (c) 2010 Howard Chu
  4.  *
  5.  * This file is part of FFmpeg.
  6.  *
  7.  * FFmpeg is free software; you can redistribute it and/or
  8.  * modify it under the terms of the GNU Lesser General Public
  9.  * License as published by the Free Software Foundation; either
  10.  * version 2.1 of the License, or (at your option) any later version.
  11.  *
  12.  * FFmpeg is distributed in the hope that it will be useful,
  13.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  15.  * Lesser General Public License for more details.
  16.  *
  17.  * You should have received a copy of the GNU Lesser General Public
  18.  * License along with FFmpeg; if not, write to the Free Software
  19.  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  20.  */
  21.  
  22. /**
  23.  * @file
  24.  * RTMP protocol based on http://rtmpdump.mplayerhq.hu/ librtmp
  25.  */
  26.  
  27. #include "libavutil/avstring.h"
  28. #include "libavutil/mathematics.h"
  29. #include "libavutil/opt.h"
  30. #include "avformat.h"
  31. #include "url.h"
  32.  
  33. #include <librtmp/rtmp.h>
  34. #include <librtmp/log.h>
  35.  
  36. typedef struct LibRTMPContext {
  37.     const AVClass *class;
  38.     RTMP rtmp;
  39.     char *app;
  40.     char *playpath;
  41. } LibRTMPContext;
  42.  
  43. static void rtmp_log(int level, const char *fmt, va_list args)
  44. {
  45.     switch (level) {
  46.     default:
  47.     case RTMP_LOGCRIT:    level = AV_LOG_FATAL;   break;
  48.     case RTMP_LOGERROR:   level = AV_LOG_ERROR;   break;
  49.     case RTMP_LOGWARNING: level = AV_LOG_WARNING; break;
  50.     case RTMP_LOGINFO:    level = AV_LOG_INFO;    break;
  51.     case RTMP_LOGDEBUG:   level = AV_LOG_VERBOSE; break;
  52.     case RTMP_LOGDEBUG2:  level = AV_LOG_DEBUG;   break;
  53.     }
  54.  
  55.     av_vlog(NULL, level, fmt, args);
  56.     av_log(NULL, level, "\n");
  57. }
  58.  
  59. static int rtmp_close(URLContext *s)
  60. {
  61.     LibRTMPContext *ctx = s->priv_data;
  62.     RTMP *r = &ctx->rtmp;
  63.  
  64.     RTMP_Close(r);
  65.     return 0;
  66. }
  67.  
  68. /**
  69.  * Open RTMP connection and verify that the stream can be played.
  70.  *
  71.  * URL syntax: rtmp://server[:port][/app][/playpath][ keyword=value]...
  72.  *             where 'app' is first one or two directories in the path
  73.  *             (e.g. /ondemand/, /flash/live/, etc.)
  74.  *             and 'playpath' is a file name (the rest of the path,
  75.  *             may be prefixed with "mp4:")
  76.  *
  77.  *             Additional RTMP library options may be appended as
  78.  *             space-separated key-value pairs.
  79.  */
  80. static int rtmp_open(URLContext *s, const char *uri, int flags)
  81. {
  82.     LibRTMPContext *ctx = s->priv_data;
  83.     RTMP *r = &ctx->rtmp;
  84.     int rc = 0, level;
  85.     char *filename = s->filename;
  86.  
  87.     switch (av_log_get_level()) {
  88.     default:
  89.     case AV_LOG_FATAL:   level = RTMP_LOGCRIT;    break;
  90.     case AV_LOG_ERROR:   level = RTMP_LOGERROR;   break;
  91.     case AV_LOG_WARNING: level = RTMP_LOGWARNING; break;
  92.     case AV_LOG_INFO:    level = RTMP_LOGINFO;    break;
  93.     case AV_LOG_VERBOSE: level = RTMP_LOGDEBUG;   break;
  94.     case AV_LOG_DEBUG:   level = RTMP_LOGDEBUG2;  break;
  95.     }
  96.     RTMP_LogSetLevel(level);
  97.     RTMP_LogSetCallback(rtmp_log);
  98.  
  99.     if (ctx->app || ctx->playpath) {
  100.         int len = strlen(s->filename) + 1;
  101.         if (ctx->app)      len += strlen(ctx->app)      + sizeof(" app=");
  102.         if (ctx->playpath) len += strlen(ctx->playpath) + sizeof(" playpath=");
  103.  
  104.         if (!(filename = av_malloc(len)))
  105.             return AVERROR(ENOMEM);
  106.  
  107.         av_strlcpy(filename, s->filename, len);
  108.         if (ctx->app) {
  109.             av_strlcat(filename, " app=", len);
  110.             av_strlcat(filename, ctx->app, len);
  111.         }
  112.         if (ctx->playpath) {
  113.             av_strlcat(filename, " playpath=", len);
  114.             av_strlcat(filename, ctx->playpath, len);
  115.         }
  116.     }
  117.  
  118.     RTMP_Init(r);
  119.     if (!RTMP_SetupURL(r, filename)) {
  120.         rc = AVERROR_UNKNOWN;
  121.         goto fail;
  122.     }
  123.  
  124.     if (flags & AVIO_FLAG_WRITE)
  125.         RTMP_EnableWrite(r);
  126.  
  127.     if (!RTMP_Connect(r, NULL) || !RTMP_ConnectStream(r, 0)) {
  128.         rc = AVERROR_UNKNOWN;
  129.         goto fail;
  130.     }
  131.  
  132.     s->is_streamed = 1;
  133.     rc = 0;
  134. fail:
  135.     if (filename != s->filename)
  136.         av_freep(&filename);
  137.     return rc;
  138. }
  139.  
  140. static int rtmp_write(URLContext *s, const uint8_t *buf, int size)
  141. {
  142.     LibRTMPContext *ctx = s->priv_data;
  143.     RTMP *r = &ctx->rtmp;
  144.  
  145.     return RTMP_Write(r, buf, size);
  146. }
  147.  
  148. static int rtmp_read(URLContext *s, uint8_t *buf, int size)
  149. {
  150.     LibRTMPContext *ctx = s->priv_data;
  151.     RTMP *r = &ctx->rtmp;
  152.  
  153.     return RTMP_Read(r, buf, size);
  154. }
  155.  
  156. static int rtmp_read_pause(URLContext *s, int pause)
  157. {
  158.     LibRTMPContext *ctx = s->priv_data;
  159.     RTMP *r = &ctx->rtmp;
  160.  
  161.     if (!RTMP_Pause(r, pause))
  162.         return AVERROR_UNKNOWN;
  163.     return 0;
  164. }
  165.  
  166. static int64_t rtmp_read_seek(URLContext *s, int stream_index,
  167.                               int64_t timestamp, int flags)
  168. {
  169.     LibRTMPContext *ctx = s->priv_data;
  170.     RTMP *r = &ctx->rtmp;
  171.  
  172.     if (flags & AVSEEK_FLAG_BYTE)
  173.         return AVERROR(ENOSYS);
  174.  
  175.     /* seeks are in milliseconds */
  176.     if (stream_index < 0)
  177.         timestamp = av_rescale_rnd(timestamp, 1000, AV_TIME_BASE,
  178.             flags & AVSEEK_FLAG_BACKWARD ? AV_ROUND_DOWN : AV_ROUND_UP);
  179.  
  180.     if (!RTMP_SendSeek(r, timestamp))
  181.         return AVERROR_UNKNOWN;
  182.     return timestamp;
  183. }
  184.  
  185. static int rtmp_get_file_handle(URLContext *s)
  186. {
  187.     LibRTMPContext *ctx = s->priv_data;
  188.     RTMP *r = &ctx->rtmp;
  189.  
  190.     return RTMP_Socket(r);
  191. }
  192.  
  193. #define OFFSET(x) offsetof(LibRTMPContext, x)
  194. #define DEC AV_OPT_FLAG_DECODING_PARAM
  195. #define ENC AV_OPT_FLAG_ENCODING_PARAM
  196. static const AVOption options[] = {
  197.     {"rtmp_app",      "Name of application to connect to on the RTMP server", OFFSET(app),      AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC|ENC},
  198.     {"rtmp_playpath", "Stream identifier to play or to publish",              OFFSET(playpath), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC|ENC},
  199.     { NULL },
  200. };
  201.  
  202. #define RTMP_CLASS(flavor)\
  203. static const AVClass lib ## flavor ## _class = {\
  204.     .class_name = "lib" #flavor " protocol",\
  205.     .item_name  = av_default_item_name,\
  206.     .option     = options,\
  207.     .version    = LIBAVUTIL_VERSION_INT,\
  208. };
  209.  
  210. RTMP_CLASS(rtmp)
  211. URLProtocol ff_librtmp_protocol = {
  212.     .name                = "rtmp",
  213.     .url_open            = rtmp_open,
  214.     .url_read            = rtmp_read,
  215.     .url_write           = rtmp_write,
  216.     .url_close           = rtmp_close,
  217.     .url_read_pause      = rtmp_read_pause,
  218.     .url_read_seek       = rtmp_read_seek,
  219.     .url_get_file_handle = rtmp_get_file_handle,
  220.     .priv_data_size      = sizeof(LibRTMPContext),
  221.     .priv_data_class     = &librtmp_class,
  222.     .flags               = URL_PROTOCOL_FLAG_NETWORK,
  223. };
  224.  
  225. RTMP_CLASS(rtmpt)
  226. URLProtocol ff_librtmpt_protocol = {
  227.     .name                = "rtmpt",
  228.     .url_open            = rtmp_open,
  229.     .url_read            = rtmp_read,
  230.     .url_write           = rtmp_write,
  231.     .url_close           = rtmp_close,
  232.     .url_read_pause      = rtmp_read_pause,
  233.     .url_read_seek       = rtmp_read_seek,
  234.     .url_get_file_handle = rtmp_get_file_handle,
  235.     .priv_data_size      = sizeof(LibRTMPContext),
  236.     .priv_data_class     = &librtmpt_class,
  237.     .flags               = URL_PROTOCOL_FLAG_NETWORK,
  238. };
  239.  
  240. RTMP_CLASS(rtmpe)
  241. URLProtocol ff_librtmpe_protocol = {
  242.     .name                = "rtmpe",
  243.     .url_open            = rtmp_open,
  244.     .url_read            = rtmp_read,
  245.     .url_write           = rtmp_write,
  246.     .url_close           = rtmp_close,
  247.     .url_read_pause      = rtmp_read_pause,
  248.     .url_read_seek       = rtmp_read_seek,
  249.     .url_get_file_handle = rtmp_get_file_handle,
  250.     .priv_data_size      = sizeof(LibRTMPContext),
  251.     .priv_data_class     = &librtmpe_class,
  252.     .flags               = URL_PROTOCOL_FLAG_NETWORK,
  253. };
  254.  
  255. RTMP_CLASS(rtmpte)
  256. URLProtocol ff_librtmpte_protocol = {
  257.     .name                = "rtmpte",
  258.     .url_open            = rtmp_open,
  259.     .url_read            = rtmp_read,
  260.     .url_write           = rtmp_write,
  261.     .url_close           = rtmp_close,
  262.     .url_read_pause      = rtmp_read_pause,
  263.     .url_read_seek       = rtmp_read_seek,
  264.     .url_get_file_handle = rtmp_get_file_handle,
  265.     .priv_data_size      = sizeof(LibRTMPContext),
  266.     .priv_data_class     = &librtmpte_class,
  267.     .flags               = URL_PROTOCOL_FLAG_NETWORK,
  268. };
  269.  
  270. RTMP_CLASS(rtmps)
  271. URLProtocol ff_librtmps_protocol = {
  272.     .name                = "rtmps",
  273.     .url_open            = rtmp_open,
  274.     .url_read            = rtmp_read,
  275.     .url_write           = rtmp_write,
  276.     .url_close           = rtmp_close,
  277.     .url_read_pause      = rtmp_read_pause,
  278.     .url_read_seek       = rtmp_read_seek,
  279.     .url_get_file_handle = rtmp_get_file_handle,
  280.     .priv_data_size      = sizeof(LibRTMPContext),
  281.     .priv_data_class     = &librtmps_class,
  282.     .flags               = URL_PROTOCOL_FLAG_NETWORK,
  283. };
  284.