[FFmpeg-soc] [soc]: r5833 - mms/mmsh.c
spyfeng
subversion at mplayerhq.hu
Wed Jun 16 12:02:08 CEST 2010
Author: spyfeng
Date: Wed Jun 16 12:02:08 2010
New Revision: 5833
Log:
reconstruct the code for mmsh.c.
begin to run testcase with mmsh links.
Modified:
mms/mmsh.c
Modified: mms/mmsh.c
==============================================================================
--- mms/mmsh.c Wed Jun 16 11:06:08 2010 (r5832)
+++ mms/mmsh.c Wed Jun 16 12:02:08 2010 (r5833)
@@ -23,7 +23,9 @@
#include "libavutil/intreadwrite.h"
#include <string.h>
#include "libavutil/avstring.h"
+#include "asf.h"
+#define DEBUG
#define CHUNK_TYPE_DATA 0x4424
#define CHUNK_TYPE_ASF_HEADER 0x4824
#define CHUNK_TYPE_END 0x4524
@@ -68,27 +70,31 @@ static const char* mmsh_live_request =
"Pragma: stream-switch-entry=%s\r\n"
"Connection: Close\r\n\r\n";
+typedef struct {
+ int id;
+}MMSStream;
+
typedef struct
{
URLContext *mms_hd;
uint8_t out_buffer[1024]; ///< Buffer for outgoing packet.
uint8_t in_buffer[1024]; //TODO, maybe reused by out_buffer.
uint8_t *read_in_ptr;
+ MMSStream streams[MAX_STREAMS];
- uint8_t *asf_header_pos;
- uint8_t *http_header_data;
- int content_length;
- int asf_header_len;
+ uint8_t *asf_header;
+ int asf_header_size;
int asf_header_read_size;
int asf_data_remaining_len;
+ int asf_packet_len;
+
char location[1024];
int seekable;
int stream_num;
int request_seq;
int chunk_seq;
-
- char stream_selection[10 * MAX_STREAMS];
+ int is_header_parsed;
}MMSHContext;
static int mmsh_close(URLContext *h)
@@ -97,7 +103,7 @@ static int mmsh_close(URLContext *h)
if(mms->mms_hd)
url_close(mms->mms_hd);
av_freep(&h->priv_data);
- av_freep(&mms->http_header_data);
+ av_freep(&mms->asf_header);
//TODO free other alloced mem.
return 0;
}
@@ -131,6 +137,8 @@ static int get_and_parse_http_header(MMS
int http_code;
char content_type[128]={'\0'};
char *p, *pos;
+ uint8_t tmp_buf[8192];
+ url_read_complete(mms->mms_hd, tmp_buf, sizeof(tmp_buf));
for(;;) {
if(url_read(mms->mms_hd, &mms->in_buffer[len], 1) != 1) {
dprintf(NULL, "recv http header failed!\n");
@@ -174,8 +182,6 @@ static int get_and_parse_http_header(MMS
&& strcmp(content_type, "application/vnd.ms.wms-hdr.asfv1") != 0) {
return -1;
}
- } else if((p = find_str(mms->in_buffer, "Content-Length:", 15)) != NULL) {
- mms->content_length = atoi(p);
} else if((p = find_str(mms->in_buffer, "Pragma:", 7)) != NULL) {
pos = strstr(p, "features=");
if (pos){
@@ -195,93 +201,165 @@ static int get_and_parse_http_header(MMS
static int asf_header_parser(MMSHContext * mms)
{
- //TODO
- return 0;
-}
+ uint8_t *p = mms->asf_header;
+ uint8_t *end;
+ int flags, stream_id, real_header_size;
+ mms->stream_num = 0;
-static uint16_t http_header_data_parser(MMSHContext *mms)
-{
- uint16_t chunk_type;
- int chunk_len;
- int data_len = mms->content_length;
- char *pos = mms->http_header_data;
+ if (mms->asf_header_size < sizeof(ff_asf_guid) * 2 + 22 ||
+ memcmp(p, ff_asf_header, sizeof(ff_asf_guid)))
+ return -1;
- while(data_len) {
- chunk_type = AV_RL16(pos);
- chunk_len = AV_RL16(pos + 2);
- if(chunk_type == CHUNK_TYPE_ASF_HEADER) {
- mms->asf_header_pos = pos + 12; // start from asf header data
- mms->asf_header_len = chunk_len - 8;
- }
- data_len -= chunk_len + 4;
- pos += chunk_len + 4;
- if (data_len <= 0) {
- dprintf(NULL, "http header data len is %d for type %x\n", chunk_len, chunk_type);
+ real_header_size = AV_RL64(p + sizeof(ff_asf_guid));
+ end = mms->asf_header + real_header_size;
+
+ p += sizeof(ff_asf_guid) + 14;
+ while(end - p >= sizeof(ff_asf_guid) + 8) {
+ uint64_t chunksize = AV_RL64(p + sizeof(ff_asf_guid));
+ if (!chunksize || chunksize > end - p) {
+ dprintf(NULL, "chunksize is exceptional value:%d!\n", chunksize);
return -1;
}
- if (chunk_type == CHUNK_TYPE_ASF_HEADER) {
- asf_header_parser(mms);
+ if (!memcmp(p, ff_asf_file_header, sizeof(ff_asf_guid))) {
+ /* read packet size */
+ if (end - p > sizeof(ff_asf_guid) * 2 + 68) {
+ mms->asf_packet_len = AV_RL32(p + sizeof(ff_asf_guid) * 2 + 64);
+ if (mms->asf_packet_len <= 0 || mms->asf_packet_len > sizeof(mms->in_buffer)) {
+ dprintf(NULL,"Too large packet len:%d"
+ " may overwrite in_buffer when padding", mms->asf_packet_len);
+ return -1;
+ }
+ }
+ } else if (!memcmp(p, ff_asf_stream_header, sizeof(ff_asf_guid))) {
+ flags = AV_RL16(p + sizeof(ff_asf_guid)*3 + 24);
+ stream_id = flags & 0x7F;
+ if (mms->stream_num < MAX_STREAMS ) {
+ mms->streams[mms->stream_num].id = stream_id;
+ mms->stream_num++;
+ } else {
+ dprintf(NULL, "Too many streams.\n");
+ return -1;
+ }
}
+ p += chunksize;
}
return 0;
}
-static int get_http_header_data(MMSHContext *mms, const int flag)
+static int get_chunk_header(MMSHContext *mms, int *len)
{
- int res;
- if(mms->content_length && flag == 1) {
- mms->http_header_data = av_mallocz(mms->content_length);
- if (!mms->http_header_data)
- return AVERROR(ENOMEM);
- // read the http header data, may contain $H, $M, $P packet.
- // In this situation, it should only has $H packet, ie asf header data.
- res = url_read_complete(mms->mms_hd, mms->http_header_data, mms->content_length);
- if (res != mms->content_length) {
- dprintf(NULL, "recv header data len %d != %d", res, mms->content_length);
- return -1;
- }
- } else if(flag == 2){
- // skip asf header
- uint16_t type;
- char *tmp = av_mallocz(mms->asf_header_len);
- if (!tmp)
- return AVERROR(ENOMEM);
- res = url_read_complete(mms->mms_hd, tmp, mms->asf_header_len);
- if (res != mms->asf_header_len) {
- dprintf(NULL, "read skipped asf header failed!\n");
- av_free(tmp);
- return -1;
- }
- type = AV_RL16(tmp);
- if (type != CHUNK_TYPE_ASF_HEADER) {
- dprintf(NULL, "cann't skip asf header because we didn't recv it!\n");
- av_free(tmp);
- return -1;
- }
- av_free(tmp);
- } else if (flag == 3){
- int header_len;
- res = url_read(mms->mms_hd, mms->http_header_data, CHUNK_HEADER_LENGTH);
- if (res != CHUNK_HEADER_LENGTH) {
- dprintf(NULL, "read chunk header failed with flag = 3!\n");
- return AVERROR(EIO);
- }
- // read header
- header_len = AV_RL16(mms->http_header_data + 2);
- res = url_read_complete(mms->mms_hd, mms->http_header_data + 4, header_len);
- if (res != header_len) {
- dprintf(NULL, "read chunk data failed with flag = 3!\n");
+ uint8_t chunk_header[CHUNK_HEADER_LENGTH];
+ uint8_t ext_header[EXT_HEADER_LENGTH];
+ int chunk_type;
+ int chunk_len, res, ext_header_len = 0;
+
+ res = url_read(mms->mms_hd, chunk_header, CHUNK_HEADER_LENGTH);
+ if (res != CHUNK_HEADER_LENGTH) { // TODO extact common log code as macro define
+ dprintf(NULL, "read data packet header failed!\n");
+ return AVERROR(EIO);
+ }
+ chunk_type = AV_RL16(chunk_header);
+ chunk_len = AV_RL16(chunk_header + 2);
+ if (chunk_type == CHUNK_TYPE_END ||chunk_type == CHUNK_TYPE_STREAM_CHANGE) {
+ ext_header_len = 4;
+ } else if (chunk_type == CHUNK_TYPE_ASF_HEADER || chunk_type == CHUNK_TYPE_DATA) {
+ ext_header_len = 8;
+ }
+ if (ext_header_len) {
+ res = url_read(mms->mms_hd, ext_header, ext_header_len);
+ if (res != ext_header_len) {
+ dprintf(NULL, "read ext header failed!\n");
return AVERROR(EIO);
}
- asf_header_parser(mms);
} else {
- dprintf(NULL, "http response has no data!\n");
+ dprintf(NULL, "strange chunk type %d\n", chunk_type);
return -1;
}
+ *len = chunk_len - ext_header_len;
+ if (chunk_type == CHUNK_TYPE_ASF_HEADER || chunk_type == CHUNK_TYPE_DATA)
+ mms->chunk_seq = AV_RL32(ext_header);
+ return chunk_type;
+}
+
+static int read_data_packet(MMSHContext *mms, const int len)
+{
+ int res, pad_size = 0;
+ res = url_read_complete(mms->mms_hd, mms->in_buffer, len);
+ dprintf(NULL, "data packet len = %d\n", len);
+ if (res != len) {
+ dprintf(NULL, "read data packet failed!\n");
+ return AVERROR(EIO);
+ }
+ if (len > mms->asf_packet_len) {
+ dprintf(NULL, "chunk length %d exceed packet length %d\n", len, mms->asf_packet_len);
+ return -1;
+ } else {
+ pad_size = mms->asf_packet_len - len;
+ memset(mms->in_buffer + len, 0, pad_size);
+ }
+ mms->read_in_ptr = mms->in_buffer;
+ mms->asf_data_remaining_len = mms->asf_packet_len;
return 0;
}
-static int get_http_answer(MMSHContext *mms, const int flag)
+static int get_http_header_data(MMSHContext *mms)
+{
+ int res, len;
+ int chunk_type;
+
+ for (;;) {
+ len = 0;
+ chunk_type = get_chunk_header(mms, &len);
+ if (chunk_type < 0) {
+ return chunk_type;
+ } else if (chunk_type == CHUNK_TYPE_ASF_HEADER){
+ // get asf header and stored it
+ if (!mms->is_header_parsed) {
+ if (!mms->asf_header) {
+ if (len != mms->asf_header_size) {
+ mms->asf_header_size = len;
+ dprintf(NULL, "header len changed form %d to %d\n",
+ mms->asf_header_size, len);
+ av_freep(&mms->asf_header);
+ }
+ mms->asf_header = av_mallocz(len);
+ if (!mms->asf_header) {
+ return AVERROR(ENOMEM);
+ }
+ }
+ }
+ res = url_read_complete(mms->mms_hd, mms->asf_header, len);
+ if (res != len) {
+ dprintf(NULL, "recv asf header data len %d != %d", res, len);
+ return -1;
+ }
+ mms->asf_header_size = len;
+ if (!mms->is_header_parsed) {
+ res = asf_header_parser(mms);
+ mms->is_header_parsed = 1;
+ return res;
+ }
+ } else if (chunk_type == CHUNK_TYPE_DATA) {
+ // read data packet and do padding
+ return read_data_packet(mms, len);
+ break;
+ } else {
+ if (len) {
+ res = url_read_complete(mms->mms_hd, mms->in_buffer, len);
+ if (res != len) {
+ dprintf(NULL, "read other chunk type data failed!\n");
+ return AVERROR(EIO);
+ } else {
+ dprintf(NULL, "skip chunk type %d \n", chunk_type);
+ continue;
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+static int get_http_answer(MMSHContext *mms)
{
int result;
result = get_and_parse_http_header(mms);
@@ -290,26 +368,19 @@ static int get_http_answer(MMSHContext *
return result;
}
- result = get_http_header_data(mms, flag);
+ result = get_http_header_data(mms);
if (result) {
dprintf(NULL, "get http header data fialed!\n");
return result;
}
- if (flag == 1) {
- result = http_header_data_parser(mms);
- if (result) {
- dprintf(NULL, "http header data parser failed!\n");
- return result;
- }
- }
return 0;
}
static int mmsh_open_cnx(MMSHContext *mms)
{
- int port, err;
+ int i, port, err, offset = 0;
char tcpname[256], path[256], host[128];
-
+ char stream_selection[10 * MAX_STREAMS];
if (mms->mms_hd) {
url_close(mms->mms_hd);
}
@@ -324,26 +395,38 @@ static int mmsh_open_cnx(MMSHContext *mm
return err;
// send describe request
snprintf (mms->out_buffer, sizeof(mms->out_buffer), mmsh_first_request, path,
- host, port, mms->request_seq++);
+ host, port, mms->request_seq++);
err = send_pack(mms);
if (err)
return err;
- err = get_http_answer(mms, 1); // TODO match with the first request
+ err = get_http_answer(mms); // TODO match with the first request
if(err)
return err;
+ for (i = 0; i < mms->stream_num; i++) {
+ err = snprintf(stream_selection + offset, sizeof(stream_selection) - offset,
+ "ffff:%d:0 ", mms->streams[i].id);
+ if (err < 0)
+ return err;
+ offset += err;
+ }
+
// send paly request
if (mms->seekable) {
- snprintf(mms->out_buffer, sizeof(mms->out_buffer), mmsh_seekable_request, path,
- host, port, 0, 0, 0, mms->request_seq++, 0, mms->stream_num, mms->stream_selection);
+ err = snprintf(mms->out_buffer, sizeof(mms->out_buffer), mmsh_seekable_request, path,
+ host, port, 0, 0, 0, mms->request_seq++, 0, mms->stream_num, stream_selection);
} else {
- snprintf(mms->out_buffer, sizeof(mms->out_buffer), mmsh_live_request, path,
- host, port, mms->request_seq++, mms->stream_num, mms->stream_selection);
+ err = snprintf(mms->out_buffer, sizeof(mms->out_buffer), mmsh_live_request, path,
+ host, port, mms->request_seq++, mms->stream_num, stream_selection);
+ }
+ if (err < 0) {
+ dprintf(NULL, "build play request failed!\n");
+ return err;
}
err = send_pack(mms);
if (err)
return err;
- err = get_http_answer(mms, 2);// TODO mathc with the second request
+ err = get_http_answer(mms);// TODO mathc with the second request
if(err)
return err;
return 0;
@@ -353,10 +436,10 @@ static int mmsh_open(URLContext *h, cons
{
MMSHContext *mms;
int err;
- mms->request_seq = h->is_streamed = 1;
mms = h->priv_data = av_mallocz(sizeof(MMSHContext));
if (!h->priv_data)
return AVERROR(ENOMEM);
+ mms->request_seq = h->is_streamed = 1;
av_strlcpy(mms->location, uri, sizeof(mms->location));
err =mmsh_open_cnx(mms);
@@ -381,32 +464,9 @@ static int read_data(MMSHContext *mms, c
static int handle_chunk_type(MMSHContext *mms)
{
- uint8_t chunk_header[CHUNK_HEADER_LENGTH];
- uint8_t ext_header[EXT_HEADER_LENGTH];
- uint16_t chunk_type;
- int chunk_len, res, ext_header_len = 0;
-
- res = url_read(mms->mms_hd, chunk_header, CHUNK_HEADER_LENGTH);
- if (res != CHUNK_HEADER_LENGTH) { // TODO extact common log code as macro define
- dprintf(NULL, "read data packet header failed!\n");
- return AVERROR(EIO);
- }
- chunk_type = AV_RL16(chunk_header);
- chunk_len = AV_RL16(chunk_header + 2);
- if (chunk_type == CHUNK_TYPE_END ||chunk_type == CHUNK_TYPE_STREAM_CHANGE) {
- ext_header_len = 4;
- } else if (chunk_type == CHUNK_TYPE_ASF_HEADER || chunk_type == CHUNK_TYPE_DATA) {
- ext_header_len = 8;
- }
- if (ext_header_len) {
- res = url_read(mms->mms_hd, ext_header, ext_header_len);
- if (res != ext_header_len) {
- dprintf(NULL, "read ext header failed!\n");
- return AVERROR(EIO);
- }
- }
- if (chunk_type == CHUNK_TYPE_ASF_HEADER || chunk_type == CHUNK_TYPE_DATA)
- mms->chunk_seq = AV_RL32(ext_header);
+ int res, len = 0;
+ int chunk_type;
+ chunk_type = get_chunk_header(mms, &len);
if(chunk_type == CHUNK_TYPE_END) {
if (mms->chunk_seq == 0) {
@@ -416,24 +476,17 @@ static int handle_chunk_type(MMSHContext
// reconnect
mms->request_seq = 1;
if ((res = mmsh_open_cnx(mms)) !=0) {
- dprintf(NULL, Reconnect failed!\n);
+ dprintf(NULL, "Reconnect failed!\n");
return res;
}
} else if (chunk_type == CHUNK_TYPE_STREAM_CHANGE) {
- if ((res = get_http_header_data(mms, 3)) !=0) {
+ mms->is_header_parsed = 0;
+ if ((res = get_http_header_data(mms)) !=0) {
dprintf(NULL,"stream changed! get new header failed!\n");
return res;
}
} else if (chunk_type == CHUNK_TYPE_DATA) {
- int data_len = chunk_len - ext_header_len;
- res = url_read_complete(mms->mms_hd, mms->in_buffer, data_len);
- dprintf(NULL, "data packet len = %d\n", data_len);
- mms->read_in_ptr = mms->in_buffer;
- mms->asf_data_remaining_len = data_len; //TODO paddings
- if (res != data_len) {
- dprintf(NULL, "read data packet failed!\n");
- return AVERROR(EIO);
- }
+ read_data_packet(mms, len);
} else {
dprintf(NULL, "recv other type packet %d\n", chunk_type);
return -1;
@@ -446,17 +499,17 @@ static int mmsh_read(URLContext *h, uint
int res = 0;
MMSHContext *mms = h->priv_data;
- if (mms->asf_header_read_size < mms->asf_header_len) {
+ if (mms->asf_header_read_size < mms->asf_header_size) {
// copy asf header into buffer
char *pos;
int size_to_copy;
- int remaining_size = mms->asf_header_len - mms->asf_header_read_size;
+ int remaining_size = mms->asf_header_size - mms->asf_header_read_size;
size_to_copy = FFMIN(size, remaining_size);
- pos = mms->asf_header_pos + mms->asf_header_read_size;
+ pos = mms->asf_header + mms->asf_header_read_size;
memcpy(buf, pos, size_to_copy);
mms->asf_header_read_size += size_to_copy;
- if (mms->asf_header_read_size == mms->asf_header_len) {
- av_freep(&mms->http_header_data); // which contains asf header
+ if (mms->asf_header_read_size == mms->asf_header_size) {
+ av_freep(&mms->asf_header); // which contains asf header
}
} else if (mms->asf_data_remaining_len){
res =read_data(mms, buf, size);
More information about the FFmpeg-soc
mailing list