[FFmpeg-soc] [soc]: r5666 - mms/mmst.c
spyfeng
subversion at mplayerhq.hu
Sun Mar 14 18:36:16 CET 2010
Author: spyfeng
Date: Sun Mar 14 18:36:15 2010
New Revision: 5666
Log:
rewrite the mmst.c.
simplify the code with removing state machine.
Modified:
mms/mmst.c
Modified: mms/mmst.c
==============================================================================
--- mms/mmst.c Sat Mar 13 14:55:11 2010 (r5665)
+++ mms/mmst.c Sun Mar 14 18:36:15 2010 (r5666)
@@ -26,30 +26,6 @@
#include "network.h"
#include "asf.h"
-#define DEBUG
-#define MMS_MAXIMUM_PACKET_LENGTH 512
-#define DEFAULT_MMS_PORT 1755
-
-/** State machine states. */
-typedef enum {
- AWAITING_SC_PACKET_CLIENT_ACCEPTED= 0,
- AWAITING_SC_PACKET_TIMING_TEST_REPLY_TYPE,
- AWAITING_CS_PACKET_PROTOCOL_ACCEPTANCE,
- AWAITING_PASSWORD_QUERY_OR_MEDIA_FILE,
- AWAITING_PACKET_HEADER_REQUEST_ACCEPTED_TYPE,
- AWAITING_STREAM_ID_ACCEPTANCE,
- AWAITING_STREAM_START_PACKET,
- AWAITING_ASF_HEADER,
- ASF_HEADER_DONE,
- AWAITING_PAUSE_ACKNOWLEDGE,
- AWAITING_HTTP_PAUSE_CONTROL_ACKNOWLEDGE,
- STREAMING,
- STREAM_DONE,
- STATE_ERROR,
- STREAM_PAUSED,
- USER_CANCELLED
-} MMSState;
-
/** Client to server packet types. */
typedef enum {
CS_PACKET_INITIAL_TYPE= 0x01,
@@ -101,7 +77,6 @@ typedef struct {
uint32_t local_ip_address; ///< Not ipv6 compatible, but neither is the protocol (sent, but not correct).
int local_port; ///< My local port (sent but not correct).
int sequence_number; ///< Outgoing packet sequence number.
- MMSState state; ///< Packet state machine current state.
char path[256]; ///< Path of the resource being asked for.
char host[128]; ///< Host of the resources.
int port; ///< Port of the resource.
@@ -111,7 +86,7 @@ typedef struct {
/** Buffer for outgoing packets. */
/*@{*/
ByteIOContext outgoing_packet_data; ///< Outgoing packet stream
- uint8_t outgoing_packet_buffer[MMS_MAXIMUM_PACKET_LENGTH]; ///< Outgoing packet data
+ uint8_t outgoing_packet_buffer[512]; ///< Outgoing packet data
/*@}*/
/** Buffer for incoming control packets. */
@@ -150,28 +125,9 @@ typedef struct {
int stream_num;
} MMSContext;
-/** Perform state transition. */
-static void ff_mms_set_state(MMSContext *mms, int new_state)
-{
- /* Can't exit error state */
- if(mms->state==STATE_ERROR) {
- dprintf(NULL, "Trying to set state to %d from %d!\n", new_state, mms->state);
- return;
- }
-
- dprintf(NULL, "Set state to %d from %d!\n", new_state, mms->state);
- if(mms->state==new_state && new_state==USER_CANCELLED) {
- ff_mms_set_state(mms, STATE_ERROR);
- return;
- }
-
- mms->state= new_state;
-}
-
/** Close the remote connection. */
static void close_connection(MMSContext *mms)
{
-// av_freep(&mms->incoming_io_buffer.buffer);
url_close(mms->mms_hd);
}
@@ -257,29 +213,15 @@ static int send_command_packet(MMSContex
write_result= url_write(mms->mms_hd, context->buffer, exact_length);
if(write_result != exact_length) {
dprintf(NULL, "url_write returned: %d != %d\n", write_result, exact_length);
-
- ff_mms_set_state(mms, STATE_ERROR);
return AVERROR_IO;
}
return 0;
}
-
-/** Log unexpected incoming packet */
-static void log_packet_in_wrong_state(MMSContext *mms, MMSSCPacketType packet_type)
-{
- if(packet_type>=0) {
- dprintf(NULL, "Got a packet 0x%02x in the wrong state: %d!\n", packet_type, mms->state);
- } else {
- dprintf(NULL, "Got a pseudo-packet %d in the wrong state: %d!\n", packet_type, mms->state);
- }
-}
-
static int send_protocol_select(MMSContext *mms)
{
char data_string[256];
- int err= 0;
// send the timing request packet...
start_command_packet(mms, CS_PACKET_PROTOCOL_SELECT_TYPE);
@@ -297,14 +239,11 @@ static int send_protocol_select(MMSConte
put_le_utf16(&mms->outgoing_packet_data, data_string);
put_le16(&mms->outgoing_packet_data, 0x30);
- err = send_command_packet(mms);
- ff_mms_set_state(mms, AWAITING_CS_PACKET_PROTOCOL_ACCEPTANCE);
- return err;
+ return send_command_packet(mms);
}
static int send_media_file_request(MMSContext *mms)
{
- int err= 0;
start_command_packet(mms, CS_PACKET_MEDIA_FILE_REQUEST_TYPE);
insert_command_prefixes(mms, 1, 0xffffffff);
put_le32(&mms->outgoing_packet_data, 0);
@@ -312,9 +251,7 @@ static int send_media_file_request(MMSCo
put_le_utf16(&mms->outgoing_packet_data, mms->path+1); // +1 because we skip the leading /
put_le32(&mms->outgoing_packet_data, 0); /* More zeroes */
- err = send_command_packet(mms);
- ff_mms_set_state(mms, AWAITING_PASSWORD_QUERY_OR_MEDIA_FILE);
- return err;
+ return send_command_packet(mms);
}
static int read_bytes(MMSContext *mms, uint8_t *buffer, int length_to_read)
@@ -334,15 +271,49 @@ static int read_bytes(MMSContext *mms, u
return len;
}
+static void handle_packet_stream_changing_type(MMSContext *mms)
+{
+ ByteIOContext pkt;
+ dprintf(NULL, "Stream changing!\n");
+
+ // read these from the incoming buffer.. (40 is the packet header size, without the prefixes)
+ init_put_byte(&pkt, mms->incoming_buffer+40, mms->incoming_buffer_length-40, 0, NULL, NULL, NULL, NULL);
+ get_le32(&pkt); // prefix 1
+ mms->header_packet_id= (get_le32(&pkt) & 0xff); // prefix 2
+ dprintf(NULL, "Changed header prefix to 0x%x", mms->header_packet_id);
+}
+
+static int send_keepalive_packet(MMSContext *mms)
+{
+ // respond to a keepalive with a keepalive...
+ start_command_packet(mms, CS_PACKET_KEEPALIVE_TYPE);
+ insert_command_prefixes(mms, 1, 0x100FFFF);
+ return send_command_packet(mms);
+}
+
+/** Pad media packets smaller than max_packet_size and/or adjust read position
+ * after a seek. */
+static void pad_media_packet(MMSContext *mms)
+{
+ if(mms->media_packet_buffer_length<mms->asf_packet_len) {
+ int padding_size = mms->asf_packet_len - mms->media_packet_buffer_length;
+ memset(mms->media_packet_incoming_buffer+mms->media_packet_buffer_length, 0, padding_size);
+ mms->media_packet_buffer_length += padding_size;
+ }
+ if(mms->media_packet_seek_offset) {
+ mms->media_packet_buffer_length -= mms->media_packet_seek_offset;
+ mms->media_packet_read_ptr += mms->media_packet_seek_offset;
+ mms->media_packet_seek_offset = 0;
+ }
+}
+
/** Read incoming MMST media, header or command packet. */
static MMSSCPacketType get_tcp_server_response(MMSContext *mms)
{
- // read the 8 byte header...
int read_result;
MMSSCPacketType packet_type= -1;
int done;
- // use url_fdopen & url_fclose...
do {
done= 1; // assume we're going to get a valid packet.
if((read_result= read_bytes(mms, mms->incoming_buffer, 8))==8) {
@@ -399,7 +370,6 @@ static MMSSCPacketType get_tcp_server_re
if(packet_id_type == mms->header_packet_id) {
// asf header
packet_type = SC_PACKET_ASF_HEADER_TYPE;
-
// Store the asf header
if(!mms->header_parsed) {
mms->asf_header = av_realloc(mms->asf_header, mms->asf_header_size + mms->media_packet_buffer_length);
@@ -427,6 +397,16 @@ static MMSSCPacketType get_tcp_server_re
}
} while(!done);
+ if (packet_type == SC_PACKET_KEEPALIVE_TYPE) {
+ send_keepalive_packet(mms);
+ }
+ if (packet_type == SC_PACKET_STREAM_CHANGING_TYPE) {
+ handle_packet_stream_changing_type(mms);
+ //TODO: Handle new header when change the stream type.
+ }
+ if (packet_type == SC_PACKET_ASF_MEDIA_TYPE) {
+ pad_media_packet(mms);
+ }
return packet_type;
}
@@ -449,7 +429,6 @@ static void handle_packet_media_file_det
if(flags==0xffffffff) {
// this is a permission denied event.
dprintf(NULL, "Permission denied!\n");
- ff_mms_set_state(mms, STATE_ERROR);
} else {
get_le32(&pkt);
get_le32(&pkt);
@@ -485,7 +464,6 @@ static void handle_packet_media_file_det
static int send_media_header_request(MMSContext *mms)
{
- int err= 0;
start_command_packet(mms, CS_PACKET_MEDIA_HEADER_REQUEST_TYPE);
insert_command_prefixes(mms, 1, 0);
put_le32(&mms->outgoing_packet_data, 0);
@@ -501,265 +479,12 @@ static int send_media_header_request(MMS
put_le32(&mms->outgoing_packet_data, 2);
put_le32(&mms->outgoing_packet_data, 0);
- err = send_command_packet(mms);
- ff_mms_set_state(mms, AWAITING_PACKET_HEADER_REQUEST_ACCEPTED_TYPE);
- return err;
-}
-
-static void handle_packet_stream_changing_type(MMSContext *mms)
-{
- ByteIOContext pkt;
- dprintf(NULL, "Stream changing!\n");
-
- // read these from the incoming buffer.. (40 is the packet header size, without the prefixes)
- init_put_byte(&pkt, mms->incoming_buffer+40, mms->incoming_buffer_length-40, 0, NULL, NULL, NULL, NULL);
- get_le32(&pkt); // prefix 1
- mms->header_packet_id= (get_le32(&pkt) & 0xff); // prefix 2
-
- dprintf(NULL, "Changed header prefix to 0x%x", mms->header_packet_id);
-
- ff_mms_set_state(mms, AWAITING_ASF_HEADER); // this is going to hork our avstreams.
-}
-
-static int send_keepalive_packet(MMSContext *mms)
-{
- // respond to a keepalive with a keepalive...
- start_command_packet(mms, CS_PACKET_KEEPALIVE_TYPE);
- insert_command_prefixes(mms, 1, 0x100FFFF);
return send_command_packet(mms);
}
-/** Handling pf TCP-specific packets.
- * @param packet_type incoming packet type to process.
- * @return 0 if the packet_type wasn't handled by this function.
- * 1 if it expected and handled.
- * -1 if it the packet was unexpected in the current state.
- */
-static int tcp_packet_state_machine(MMSContext *mms, MMSSCPacketType packet_type)
-{
- switch(packet_type) {
- case SC_PACKET_CLIENT_ACCEPTED:
- if(mms->state==AWAITING_SC_PACKET_CLIENT_ACCEPTED) {
- dprintf(NULL, "Transitioning from AWAITING_SC_PACKET_CLIENT_ACCEPTED to AWAITING_SC_PACKET_TIMING_TEST_REPLY_TYPE\n");
- // send the timing request packet...
- start_command_packet(mms, CS_PACKET_TIMING_DATA_REQUEST_TYPE);
- insert_command_prefixes(mms, 0xf0f0f0f1, 0x0004000b);
- send_command_packet(mms);
-
- ff_mms_set_state(mms, AWAITING_SC_PACKET_TIMING_TEST_REPLY_TYPE);
- } else
- return -1;
- break;
-
- case SC_PACKET_TIMING_TEST_REPLY_TYPE: // we may, or may not have timing tests.
- if(mms->state==AWAITING_SC_PACKET_TIMING_TEST_REPLY_TYPE || mms->state==AWAITING_SC_PACKET_CLIENT_ACCEPTED) {
- send_protocol_select(mms);
- } else
- return -1;
- break;
-
- case SC_PACKET_PROTOCOL_ACCEPTED_TYPE:
- if(mms->state==AWAITING_CS_PACKET_PROTOCOL_ACCEPTANCE) {
- send_media_file_request(mms);
- } else
- return -1;
- break;
-
- case SC_PACKET_PROTOCOL_FAILED_TYPE:
- if(mms->state==AWAITING_CS_PACKET_PROTOCOL_ACCEPTANCE) {
- // abort;
- dprintf(NULL, "Protocol failed\n");
- ff_mms_set_state(mms, STATE_ERROR);
- } else
- return -1;
- break;
-
- case SC_PACKET_PASSWORD_REQUIRED_TYPE:
- if(mms->state==AWAITING_PASSWORD_QUERY_OR_MEDIA_FILE) {
- // we don't support this right now.
- dprintf(NULL, "Password required\n");
- ff_mms_set_state(mms, STATE_ERROR);
- } else
- return -1;
- break;
-
- case SC_PACKET_MEDIA_FILE_DETAILS_TYPE:
- if(mms->state==AWAITING_PASSWORD_QUERY_OR_MEDIA_FILE) {
- handle_packet_media_file_details(mms);
- if(mms->state != STATE_ERROR)
- send_media_header_request(mms);
- } else
- return -1;
- break;
-
- case SC_PACKET_HEADER_REQUEST_ACCEPTED_TYPE:
- if(mms->state==AWAITING_PACKET_HEADER_REQUEST_ACCEPTED_TYPE) {
- ff_mms_set_state(mms, AWAITING_ASF_HEADER);
- } else
- return -1;
- break;
-
- case SC_PACKET_STREAM_CHANGING_TYPE:
- if(mms->state==STREAMING) {
- handle_packet_stream_changing_type(mms);
- } else
- return -1;
- break;
-
- case SC_PACKET_STREAM_ID_ACCEPTED_TYPE:
- if(mms->state==AWAITING_STREAM_ID_ACCEPTANCE) {
- dprintf(NULL, "Stream ID's accepted!\n");
- ff_mms_set_state(mms, STREAM_PAUSED); // only way to get out of this is to play...
- } else
- return -1;
- break;
-
- case SC_PACKET_MEDIA_PACKET_FOLLOWS_TYPE:
- if(mms->state==AWAITING_STREAM_START_PACKET) {
- // get the stream packets...
- ff_mms_set_state(mms, STREAMING);
- } else
- return -1;
- break;
-
- case SC_PACKET_KEEPALIVE_TYPE:
- if(mms->state==STREAMING || mms->state==STREAM_PAUSED) {
- dprintf(NULL, "Got a Keepalive!\n");
- send_keepalive_packet(mms);
- } else
- return -1;
- break;
-
- default:
- return 0; // Not handled here
- }
-
- return 1; // Handled here
-}
-
-/** Pad media packets smaller than max_packet_size and/or adjust read position
- * after a seek. */
-static void pad_media_packet(MMSContext *mms)
-{
- if(mms->media_packet_buffer_length<mms->asf_packet_len) {
- int padding_size = mms->asf_packet_len - mms->media_packet_buffer_length;
- memset(mms->media_packet_incoming_buffer+mms->media_packet_buffer_length, 0, padding_size);
- mms->media_packet_buffer_length += padding_size;
- }
-
- if(mms->media_packet_seek_offset) {
- mms->media_packet_buffer_length -= mms->media_packet_seek_offset;
- mms->media_packet_read_ptr += mms->media_packet_seek_offset;
- mms->media_packet_seek_offset = 0;
- }
-}
-
-/** Single-step the packet-pumping state machine.
- * @return The type of the last packet from the server.
- */
-static MMSSCPacketType ff_mms_packet_state_machine(MMSContext *mms)
-{
- MMSSCPacketType packet_type = get_tcp_server_response(mms);
-
- /* First, try protocol-specific packet handling */
- int ret = tcp_packet_state_machine(mms, packet_type);
- if(ret != 0) {
- if(ret == -1)
- log_packet_in_wrong_state(mms, packet_type);
- return packet_type;
- }
-
- /* Common packet handling */
- switch(packet_type) {
- case SC_PACKET_ASF_HEADER_TYPE:
- if(mms->state==AWAITING_ASF_HEADER) {
- dprintf(NULL, "Got a SC_PACKET_ASF_HEADER: %d\n", mms->media_packet_buffer_length);
- if((mms->incoming_flags == 0X08) || (mms->incoming_flags == 0X0C))
- {
- dprintf(NULL, "Got the full header!\n");
- ff_mms_set_state(mms, ASF_HEADER_DONE);
- }
- } else {
- log_packet_in_wrong_state(mms, packet_type);
- }
- break;
-
- case SC_PACKET_ASF_MEDIA_TYPE:
- if(mms->state==STREAMING || mms->state==AWAITING_PAUSE_ACKNOWLEDGE || mms->state==AWAITING_HTTP_PAUSE_CONTROL_ACKNOWLEDGE) {
- pad_media_packet(mms);
- } else {
- log_packet_in_wrong_state(mms, packet_type);
- }
- break;
-
- case SC_PACKET_STREAM_STOPPED_TYPE:
- if(mms->state==AWAITING_PAUSE_ACKNOWLEDGE) {
- dprintf(NULL, "Server echoed stream pause\n");
- ff_mms_set_state(mms, STREAM_PAUSED);
- } else if(mms->state==STREAMING) {
- /*
- When echoing a start (from me):
- receive command 0x1e, 48 bytes
- start sequence 00000001
- command id b00bface
- length 20
- protocol 20534d4d
- len8 4
- sequence # 00000006
- len8 (II) 2
- dir | comm 0004001e
- prefix1 00000000
- prefix2 ffff0100
-
- When Ending on it's own:
- receive command 0x1e, 48 bytes
- start sequence 09000001
- command id b00bface
- length 20
- protocol 20534d4d
- len8 4
- sequence # 00000006
- len8 (II) 2
- dir | comm 0004001e
- prefix1 00000000
- prefix2 00000004
- */
- dprintf(NULL, "** Server hit end of stream (may be sending new header information)\n");
- // TODO: if this is a live stream, on the resumption of a pause, this happens, then it follows with a SC_PACKET_STREAM_CHANGING_TYPE
- // otherwise it means this stream is done.
- ff_mms_set_state(mms, STREAM_DONE);
- } else {
- log_packet_in_wrong_state(mms, packet_type);
- }
- break;
-
- case SC_PACKET_TYPE_CANCEL:
- dprintf(NULL, "Got a -1 packet type\n");
- // user cancelled; let us out so it gets closed down...
- ff_mms_set_state(mms, USER_CANCELLED);
- break;
-
- case SC_PACKET_TYPE_NO_DATA:
- dprintf(NULL, "Got no data (closed?)\n");
- ff_mms_set_state(mms, STREAM_DONE); //?
- break;
-
- case SC_PACKET_HTTP_CONTROL_ACKNOWLEDGE:
- ff_mms_set_state(mms, AWAITING_PAUSE_ACKNOWLEDGE);
- break;
-
- default:
- dprintf(NULL, "Unhandled packet type %d\n", packet_type);
- break;
- }
-
- return packet_type;
-}
-
/** Send the initial handshake. */
static int send_startup_packet(MMSContext *mms)
{
- int err;
char data_string[256];
snprintf(data_string, sizeof(data_string), "NSPlayer/7.0.0.1956; {%s}; Host: %s",
@@ -771,18 +496,7 @@ static int send_startup_packet(MMSContex
put_le_utf16(&mms->outgoing_packet_data, data_string);
put_le16(&mms->outgoing_packet_data, 0); // double unicode ended string...
- err = send_command_packet(mms);
- ff_mms_set_state(mms, AWAITING_SC_PACKET_CLIENT_ACCEPTED);
- return err;
-}
-
-static void print_guid(const ff_asf_guid *g)
-{
- int i;
- av_log(NULL, AV_LOG_DEBUG, "{");
- for(i=0;i<16;i++)
- av_log(NULL, AV_LOG_DEBUG, " 0x%02x,", (*g)[i]);
- av_log(NULL, AV_LOG_DEBUG, "}\n");
+ return send_command_packet(mms);
}
static int asf_header_parser(MMSContext *mms)
@@ -810,44 +524,13 @@ static int asf_header_parser(MMSContext
p += chunksize;
} while (end - p >= sizeof(ff_asf_guid) + 8);
- return -1;
-}
-
-/** Read the whole mms header into a buffer of our own .*/
-static int read_mms_header(MMSContext *mms)
-{
- if(mms->state != AWAITING_ASF_HEADER) {
- dprintf(NULL, "cannot read header this state\n");
- ff_mms_set_state(mms, STATE_ERROR);
- return -1;
- }
-
- /* TODO: add timeout */
- /* This will run until the header is stored */
- while(mms->state != ASF_HEADER_DONE && mms->state != STATE_ERROR)
- ff_mms_packet_state_machine(mms);
-
- if(mms->state == STATE_ERROR)
- return -1;
-
- asf_header_parser(mms);
- mms->header_parsed = 1;
-
return 0;
}
-/** Clear all buffers of partial and old packets after a seek or other discontinuity */
-static void clear_stream_buffers(MMSContext *mms)
-{
- mms->media_packet_buffer_length = 0;
- mms->media_packet_read_ptr = mms->media_packet_incoming_buffer;
-}
-
/** Send MMST stream selection command based on the AVStream->discard values. */
static int send_stream_selection_request(MMSContext *mms)
{
int ii;
- int err;
// send the streams we want back...
start_command_packet(mms, CS_PACKET_STREAM_ID_REQUEST_TYPE);
@@ -860,62 +543,7 @@ static int send_stream_selection_request
put_le16(&mms->outgoing_packet_data, 0); /* Extra zeroes */
- err = send_command_packet(mms);
- ff_mms_set_state(mms, AWAITING_STREAM_ID_ACCEPTANCE);
- return err;
-}
-
-/** Request a MMST stream from a timestamp or packet offset.
- * @param rate Play rate. (Only 1 supported as for now)
- * @param byte_offset Byte position to seek to. Set to -1 when seeking by timestamp.
- * The position is from the start of the media stream, i.e. not counting header size.
- * @param timestamp Time point in ms. Set to 0 when seeking from packet offsets.
- */
-static int request_streaming_from(MMSContext *mms,
- int rate, int64_t byte_offset, int64_t timestamp)
-{
- int32_t packet = -1;
- int result;
-
- if(byte_offset > 0)
- packet = byte_offset / mms->asf_packet_len;
-
- /* Send a stream selection request if this is the first call to play */
- if(mms->state == ASF_HEADER_DONE) {
- result = send_stream_selection_request(mms);
-
- if(result==0) {
- while(mms->state != STREAM_PAUSED && mms->state != STATE_ERROR && mms->state != STREAM_DONE) {
- ff_mms_packet_state_machine(mms);
- }
- }
- }
-
- if(mms->state==STREAM_PAUSED || mms->state == ASF_HEADER_DONE) {
- timestamp= av_dbl2int((double)timestamp/1000.0); // is this needed?
-
- start_command_packet(mms, CS_PACKET_START_FROM_PACKET_ID_TYPE);
- insert_command_prefixes(mms, 1, mms->packet_id);
- put_le64(&mms->outgoing_packet_data, timestamp); // seek timestamp
- put_le32(&mms->outgoing_packet_data, 0xffffffff); // unknown
- put_le32(&mms->outgoing_packet_data, packet); // packet offset
- put_byte(&mms->outgoing_packet_data, 0xff); // max stream time limit
- put_byte(&mms->outgoing_packet_data, 0xff); // max stream time limit
- put_byte(&mms->outgoing_packet_data, 0xff); // max stream time limit
- put_byte(&mms->outgoing_packet_data, 0x00); // stream time limit flag
-
- mms->packet_id++; // new packet_id so we can separate new data from old data
- put_le32(&mms->outgoing_packet_data, mms->packet_id);
- send_command_packet(mms);
-
- ff_mms_set_state(mms, AWAITING_STREAM_START_PACKET);
- return 0;
- } else {
-#if (MMS_DEBUG_LEVEL>0)
- dprintf(NULL, "Tried a read_play when the state was not stream paused (%s)\n", state_names[mms->state]);
-#endif
- return -1;
- }
+ return send_command_packet(mms);
}
/** Read at most one media packet (or a whole header). */
@@ -925,85 +553,62 @@ static int read_mms_packet(MMSContext *m
MMSSCPacketType packet_type;
int size_to_copy;
- if(mms->state != STREAM_DONE && mms->state != STREAM_PAUSED && mms->state != STATE_ERROR) {
- do {
- if(mms->asf_header_read_pos < mms->asf_header_size) {
- /* Read from ASF header buffer */
- size_to_copy= FFMIN(buf_size, mms->asf_header_size - mms->asf_header_read_pos);
- memcpy(buf, mms->asf_header + mms->asf_header_read_pos, size_to_copy);
- mms->asf_header_read_pos += size_to_copy;
+ do {
+ if(mms->asf_header_read_pos < mms->asf_header_size) {
+ /* Read from ASF header buffer */
+ size_to_copy= FFMIN(buf_size, mms->asf_header_size - mms->asf_header_read_pos);
+ memcpy(buf, mms->asf_header + mms->asf_header_read_pos, size_to_copy);
+ mms->asf_header_read_pos += size_to_copy;
+ result += size_to_copy;
+ dprintf(NULL, "Copied %d bytes from stored header. left: %d\n", size_to_copy, mms->asf_header_size - mms->asf_header_read_pos);
+ } else if(mms->media_packet_buffer_length) {
+ /* Read from media packet buffer */
+ size_to_copy = FFMIN(buf_size, mms->media_packet_buffer_length);
+ memcpy(buf, mms->media_packet_read_ptr, size_to_copy);
+ mms->media_packet_buffer_length -= size_to_copy;
+ mms->media_packet_read_ptr+= size_to_copy;
+ result += size_to_copy;
+ } else {
+ /* Read from network */
+ packet_type= get_tcp_server_response(mms);
+ switch (packet_type) {
+ case SC_PACKET_ASF_MEDIA_TYPE:
+ if(mms->media_packet_buffer_length>mms->asf_packet_len) {
+ dprintf(NULL, "Incoming packet larger than the asf packet size stated (%d>%d)\n", mms->media_packet_buffer_length, mms->asf_packet_len);
+ result= AVERROR_IO;
+ break;
+ }
+
+ // copy the data to the packet buffer...
+ size_to_copy= FFMIN(buf_size, mms->media_packet_buffer_length);
+ memcpy(buf, mms->media_packet_read_ptr, size_to_copy);
+ mms->media_packet_buffer_length -= size_to_copy;
+ mms->media_packet_read_ptr += size_to_copy;
result += size_to_copy;
- dprintf(NULL, "Copied %d bytes from stored header. left: %d\n", size_to_copy, mms->asf_header_size - mms->asf_header_read_pos);
- } else if(mms->media_packet_buffer_length) {
- /* Read from media packet buffer */
- size_to_copy = FFMIN(buf_size, mms->media_packet_buffer_length);
+ break;
+ case SC_PACKET_ASF_HEADER_TYPE:
+ // copy the data to the packet buffer...
+ size_to_copy= FFMIN(buf_size, mms->media_packet_buffer_length);
memcpy(buf, mms->media_packet_read_ptr, size_to_copy);
mms->media_packet_buffer_length -= size_to_copy;
mms->media_packet_read_ptr+= size_to_copy;
- result += size_to_copy;
- } else {
- /* Read from network */
- packet_type= ff_mms_packet_state_machine(mms);
- switch (packet_type) {
- case SC_PACKET_ASF_MEDIA_TYPE:
- if(mms->media_packet_buffer_length>mms->asf_packet_len) {
- dprintf(NULL, "Incoming packet larger than the asf packet size stated (%d>%d)\n", mms->media_packet_buffer_length, mms->asf_packet_len);
- result= AVERROR_IO;
- break;
- }
-
- // copy the data to the packet buffer...
- size_to_copy= FFMIN(buf_size, mms->media_packet_buffer_length);
- memcpy(buf, mms->media_packet_read_ptr, size_to_copy);
- mms->media_packet_buffer_length -= size_to_copy;
- mms->media_packet_read_ptr += size_to_copy;
- result += size_to_copy;
- break;
- case SC_PACKET_ASF_HEADER_TYPE:
- // copy the data to the packet buffer...
- size_to_copy= FFMIN(buf_size, mms->media_packet_buffer_length);
- memcpy(buf, mms->media_packet_read_ptr, size_to_copy);
- mms->media_packet_buffer_length -= size_to_copy;
- mms->media_packet_read_ptr+= size_to_copy;
- result+= size_to_copy;
- break;
- default:
- if(mms->state==STREAM_PAUSED) {
- result= 0;
- } else if(mms->state==STREAM_DONE || mms->state==USER_CANCELLED) {
- result=-1;
- } else if(mms->state==AWAITING_ASF_HEADER) {
- // we have reset the header; spin though the loop..
- while(mms->state != STREAMING && mms->state != STATE_ERROR) {
- ff_mms_packet_state_machine(mms);
- }
- } else {
- dprintf(NULL, "Got a packet in odd state: %d Packet Type: 0x%x\n", mms->state, packet_type);
- }
- break;
- }
+ result+= size_to_copy;
+ break;
+ default:
+ dprintf(NULL, "Got a unkown Packet Type: 0x%x\n", packet_type);
+ break;
}
- } while(result==0 && mms->state!=STREAM_PAUSED); // only return one packet...
- } else {
- if(mms->state==STREAM_PAUSED) {
- result= 0;
- } else {
- result= -1;
}
- }
-
+ } while(!result); // only return one packet...
return result;
}
static int send_close_packet(MMSContext *mms)
{
- int err;
start_command_packet(mms, CS_PACKET_STREAM_CLOSE_TYPE);
insert_command_prefixes(mms, 1, 1);
- err = send_command_packet(mms);
- ff_mms_set_state(mms, AWAITING_PAUSE_ACKNOWLEDGE);
- return err;
+ return send_command_packet(mms);
}
/** Close the MMSH/MMST connection */
@@ -1012,12 +617,7 @@ static int mms_close(URLContext *h)
MMSContext *mms = (MMSContext *)h->priv_data;
if(mms->mms_hd) {
- // send the close packet if we should...
- if(mms->state != STATE_ERROR) {
- send_close_packet(mms);
- }
-
- // need an url_fdclose()
+ send_close_packet(mms);
close_connection(mms);
}
@@ -1040,7 +640,7 @@ static int mms_open_cnx(URLContext *h)
&mms->port, mms->path, sizeof(mms->path), mms->location);
if(mms->port<0)
- mms->port = DEFAULT_MMS_PORT;
+ mms->port = 1755; // defaut mms protocol port
/* the outgoing packet buffer */
init_put_byte(&mms->outgoing_packet_data, mms->outgoing_packet_buffer, sizeof(mms->outgoing_packet_buffer), 1, NULL, NULL, NULL, NULL);
@@ -1055,41 +655,58 @@ static int mms_open_cnx(URLContext *h)
mms->packet_id = 3; // default, initial value. (3 will be incremented to 4 before first use)
mms->header_packet_id = 2; // default, initial value.
- /* okay, now setup stuff. working from unclear specifications is great! */
- //mms->protocol->send_startup_message(mms); //TOBEDONE
send_startup_packet(mms);
+ if (get_tcp_server_response(mms) == SC_PACKET_CLIENT_ACCEPTED) {
+// start_command_packet(mms, CS_PACKET_TIMING_DATA_REQUEST_TYPE);
+// insert_command_prefixes(mms, 0xf0f0f0f1, 0x0004000b);
+// send_command_packet(mms);
+ send_protocol_select(mms);
+ } else
+ goto fail;
- // TODO: add timeout here... (mms_watchdog_reset() ?)
- while(mms->state != AWAITING_ASF_HEADER &&
- mms->state != STATE_ERROR &&
- mms->state != STREAM_DONE) {
- ff_mms_packet_state_machine(mms); // TOBEDONE
- }
+// if (get_tcp_server_response(mms) == SC_PACKET_TIMING_TEST_REPLY_TYPE) {
+// send_protocol_select(mms);
+// } else
+// goto fail;
- /* We store the header internally */
- if(mms->state != STATE_ERROR)
- read_mms_header(mms); // TOBEDONE use asf_read_header?
+ if (get_tcp_server_response(mms) == SC_PACKET_PROTOCOL_ACCEPTED_TYPE) {
+ send_media_file_request(mms);
+ } else
+ goto fail;
- if(mms->state == STATE_ERROR) {
- err = AVERROR(EIO);
+ if (get_tcp_server_response(mms) == SC_PACKET_MEDIA_FILE_DETAILS_TYPE) {
+ handle_packet_media_file_details(mms);
+ send_media_header_request(mms);
+ } else
goto fail;
- }
- dprintf(NULL, "Leaving open (success)\n");
+ if (get_tcp_server_response(mms) == SC_PACKET_HEADER_REQUEST_ACCEPTED_TYPE) {
+ // recv asf header data
+ if (get_tcp_server_response(mms) == SC_PACKET_ASF_HEADER_TYPE) {
+ if((mms->incoming_flags == 0X08) || (mms->incoming_flags == 0X0C)) {
+ asf_header_parser(mms);
+ mms->header_parsed = 1;
+ } else
+ goto fail;
+ } else
+ goto fail;
+ } else
+ goto fail;
+ if (!mms->asf_packet_len || !mms->stream_num)
+ goto fail;
+
+ dprintf(NULL, "Leaving open (success)\n");
return 0;
fail:
mms_close(h);
-
dprintf(NULL, "Leaving open (failure: %d)\n", err);
-
return err;
}
static int mms_open(URLContext *h, const char *uri, int flags)
{
MMSContext *mms;
- int ret;
h->is_streamed = 1;
mms = av_malloc(sizeof(MMSContext));
@@ -1099,29 +716,24 @@ static int mms_open(URLContext *h, const
h->priv_data = mms;
av_strlcpy(mms->location, uri, sizeof(mms->location));
- ret = mms_open_cnx(h);
- return ret;
+ return mms_open_cnx(h);
}
-/** Like AVInputFormat::read_play().
- * @see AVInputFormat::read_play()
- */
-static int ff_mms_play(URLContext *h)
+static int send_media_packet_request(MMSContext *mms)
{
- MMSContext *mms = h->priv_data;
- int64_t stream_offset = 0;
-
- /* Early return if already playing. */
- if(mms->state == STREAMING || mms->state == AWAITING_STREAM_START_PACKET)
- return 0;
-
- /* If resuming from pause */
- if(mms->state==STREAM_PAUSED)
- stream_offset = (mms->pause_resume_seq+1) * mms->asf_packet_len;
-
- clear_stream_buffers(mms);
+ start_command_packet(mms, CS_PACKET_START_FROM_PACKET_ID_TYPE);
+ insert_command_prefixes(mms, 1, 0x0001FFFF);
+ put_le64(&mms->outgoing_packet_data, 0); // seek timestamp
+ put_le32(&mms->outgoing_packet_data, 0xffffffff); // unknown
+ put_le32(&mms->outgoing_packet_data, 0xffffffff); // packet offset
+ put_byte(&mms->outgoing_packet_data, 0xff); // max stream time limit
+ put_byte(&mms->outgoing_packet_data, 0xff); // max stream time limit
+ put_byte(&mms->outgoing_packet_data, 0xff); // max stream time limit
+ put_byte(&mms->outgoing_packet_data, 0x00); // stream time limit flag
- return request_streaming_from(mms, 1, stream_offset, 0);
+ mms->packet_id++; // new packet_id so we can separate new data from old data
+ put_le32(&mms->outgoing_packet_data, mms->packet_id);
+ return send_command_packet(mms);
}
/** Read ASF data through the protocol. */
@@ -1136,26 +748,25 @@ static int mms_read(URLContext *h, uint8
/* Automatically start playing if the app wants to read before it has called play()
* (helps with non-streaming aware apps) */
- if(mms->state == ASF_HEADER_DONE && mms->asf_header_read_pos >= mms->asf_header_size) {
- dprintf(NULL, "mms_read() before play(). Playing automatically.\n");
- result = ff_mms_play(h);// TOBEDONE
- if(result < 0)
- return result;
- }
-
- /* We won't get any packets from the server if paused. Nothing else to do than
- * to return. FIXME: return AVERROR(EAGAIN)? */
- if(mms->state == STREAM_PAUSED) {
- dprintf(NULL, "mms_read in STREAM_PAUSED\n");
- return 0;
- } else if(mms->state==STREAMING || mms->state==AWAITING_STREAM_START_PACKET || mms->state == ASF_HEADER_DONE) {
- result = read_mms_packet(mms, buf, size);//TOBEDONE use asf_read_packet?
+ if(mms->header_parsed) {
+ if (mms->asf_header_read_pos >= mms->asf_header_size) {
+ dprintf(NULL, "mms_read() before play(). Playing automatically.\n");
+ result = send_stream_selection_request(mms);
+ if(result < 0)
+ return result;
+ if (get_tcp_server_response(mms) != SC_PACKET_STREAM_ID_ACCEPTED_TYPE) {
+ dprintf(NULL, "Canot get stream id accepted packet from server.\n");
+ return 0;
+ }
- /* Note which packet we last returned. FIXME: doesn't handle partially read packets */
- mms->pause_resume_seq = mms->incoming_packet_seq;
- } else {
- dprintf(NULL, "mms_read: wrong state %d, returning AVERROR_IO!\n", mms->state);
- result = AVERROR(EIO);
+ // send media packet request
+ send_media_packet_request(mms);
+ if (get_tcp_server_response(mms) != SC_PACKET_MEDIA_PACKET_FOLLOWS_TYPE) {
+ dprintf(NULL, "Canot get media follows packet from server.\n");
+ return 0;
+ }
+ }
+ result = read_mms_packet(mms, buf, size);
}
return result;
More information about the FFmpeg-soc
mailing list