summaryrefslogtreecommitdiff
path: root/libavformat/mmsh.c
diff options
context:
space:
mode:
Diffstat (limited to 'libavformat/mmsh.c')
-rw-r--r--libavformat/mmsh.c77
1 files changed, 61 insertions, 16 deletions
diff --git a/libavformat/mmsh.c b/libavformat/mmsh.c
index 5e9d0bc134..dac5d9f653 100644
--- a/libavformat/mmsh.c
+++ b/libavformat/mmsh.c
@@ -2,20 +2,20 @@
* MMS protocol over HTTP
* Copyright (c) 2010 Zhentan Feng <spyfeng at gmail dot com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -56,6 +56,7 @@ typedef enum {
typedef struct {
MMSContext mms;
+ uint8_t location[1024];
int request_seq; ///< request packet sequence
int chunk_seq; ///< data packet sequence
} MMSHContext;
@@ -65,9 +66,9 @@ static int mmsh_close(URLContext *h)
MMSHContext *mmsh = (MMSHContext *)h->priv_data;
MMSContext *mms = &mmsh->mms;
if (mms->mms_hd)
- ffurl_close(mms->mms_hd);
- av_free(mms->streams);
- av_free(mms->asf_header);
+ ffurl_closep(&mms->mms_hd);
+ av_freep(&mms->streams);
+ av_freep(&mms->asf_header);
return 0;
}
@@ -118,7 +119,7 @@ static int read_data_packet(MMSHContext *mmsh, const int len)
int res;
if (len > sizeof(mms->in_buffer)) {
av_log(NULL, AV_LOG_ERROR,
- "Data packet length %d exceeds the in_buffer size %zu\n",
+ "Data packet length %d exceeds the in_buffer size %"SIZE_SPECIFIER"\n",
len, sizeof(mms->in_buffer));
return AVERROR(EIO);
}
@@ -193,7 +194,7 @@ static int get_http_header_data(MMSHContext *mmsh)
if (len) {
if (len > sizeof(mms->in_buffer)) {
av_log(NULL, AV_LOG_ERROR,
- "Other packet len = %d exceed the in_buffer size %zu\n",
+ "Other packet len = %d exceed the in_buffer size %"SIZE_SPECIFIER"\n",
len, sizeof(mms->in_buffer));
return AVERROR(EIO);
}
@@ -210,10 +211,10 @@ static int get_http_header_data(MMSHContext *mmsh)
}
}
-static int mmsh_open(URLContext *h, const char *uri, int flags)
+static int mmsh_open_internal(URLContext *h, const char *uri, int flags, int timestamp, int64_t pos)
{
int i, port, err;
- char httpname[256], path[256], host[128], location[1024];
+ char httpname[256], path[256], host[128];
char *stream_selection = NULL;
char headers[1024];
MMSHContext *mmsh = h->priv_data;
@@ -221,10 +222,10 @@ static int mmsh_open(URLContext *h, const char *uri, int flags)
mmsh->request_seq = h->is_streamed = 1;
mms = &mmsh->mms;
- av_strlcpy(location, uri, sizeof(location));
+ av_strlcpy(mmsh->location, uri, sizeof(mmsh->location));
av_url_split(NULL, 0, NULL, 0,
- host, sizeof(host), &port, path, sizeof(path), location);
+ host, sizeof(host), &port, path, sizeof(path), mmsh->location);
if (port<0)
port = 80; // default mmsh protocol port
ff_url_join(httpname, sizeof(httpname), "http", NULL, host, port, "%s", path);
@@ -241,7 +242,7 @@ static int mmsh_open(URLContext *h, const char *uri, int flags)
"Pragma: no-cache,rate=1.000000,stream-time=0,"
"stream-offset=0:0,request-context=%u,max-duration=0\r\n"
CLIENTGUID
- "Connection: Close\r\n\r\n",
+ "Connection: Close\r\n",
host, port, mmsh->request_seq++);
av_opt_set(mms->mms_hd->priv_data, "headers", headers, 0);
@@ -282,8 +283,9 @@ static int mmsh_open(URLContext *h, const char *uri, int flags)
CLIENTGUID
"Pragma: stream-switch-count=%d\r\n"
"Pragma: stream-switch-entry=%s\r\n"
- "Connection: Close\r\n\r\n",
- host, port, mmsh->request_seq++, mms->stream_num, stream_selection);
+ "Pragma: no-cache,rate=1.000000,stream-time=%u"
+ "Connection: Close\r\n",
+ host, port, mmsh->request_seq++, mms->stream_num, stream_selection, timestamp);
av_freep(&stream_selection);
if (err < 0) {
av_log(NULL, AV_LOG_ERROR, "Build play request failed!\n");
@@ -312,6 +314,11 @@ fail:
return err;
}
+static int mmsh_open(URLContext *h, const char *uri, int flags)
+{
+ return mmsh_open_internal(h, uri, flags, 0, 0);
+}
+
static int handle_chunk_type(MMSHContext *mmsh)
{
MMSContext *mms = &mmsh->mms;
@@ -358,11 +365,49 @@ static int mmsh_read(URLContext *h, uint8_t *buf, int size)
return res;
}
+static int64_t mmsh_read_seek(URLContext *h, int stream_index,
+ int64_t timestamp, int flags)
+{
+ MMSHContext *mmsh_old = h->priv_data;
+ MMSHContext *mmsh = av_mallocz(sizeof(*mmsh));
+ int ret;
+
+ if (!mmsh)
+ return AVERROR(ENOMEM);
+
+ h->priv_data = mmsh;
+ ret= mmsh_open_internal(h, mmsh_old->location, 0, FFMAX(timestamp, 0), 0);
+ if(ret>=0){
+ h->priv_data = mmsh_old;
+ mmsh_close(h);
+ h->priv_data = mmsh;
+ av_free(mmsh_old);
+ mmsh->mms.asf_header_read_size = mmsh->mms.asf_header_size;
+ }else {
+ h->priv_data = mmsh_old;
+ av_free(mmsh);
+ }
+
+ return ret;
+}
+
+static int64_t mmsh_seek(URLContext *h, int64_t pos, int whence)
+{
+ MMSHContext *mmsh = h->priv_data;
+ MMSContext *mms = &mmsh->mms;
+
+ if(pos == 0 && whence == SEEK_CUR)
+ return mms->asf_header_read_size + mms->remaining_in_len + mmsh->chunk_seq * (int64_t)mms->asf_packet_len;
+ return AVERROR(ENOSYS);
+}
+
URLProtocol ff_mmsh_protocol = {
.name = "mmsh",
.url_open = mmsh_open,
.url_read = mmsh_read,
+ .url_seek = mmsh_seek,
.url_close = mmsh_close,
+ .url_read_seek = mmsh_read_seek,
.priv_data_size = sizeof(MMSHContext),
.flags = URL_PROTOCOL_FLAG_NETWORK,
};