[MPlayer-dev-eng] [PATCH] Recursively Nested ASX Playlists

Mrc Gran mrc.gran at gmail.com
Wed Mar 7 05:02:05 CET 2007


Hello,

I'm sending a patch to make mplayer capable of playing recursively nested
asx playlists.
A nested asx playlist is one whose refs point to further asx list files
instead of real media files such as wmv.
(This patch is not to be confused with processing of entryrefs which seems
to be already implemented at asxparser.c.)


Both asx playlists and wmv files are of mime type x-ms-asf. This patches
modifies stream/asf_streaming.c
so that it looks for a file ending with '.asx' which, if found, returns a
demux_type_playlist to mplayer.c instead of the
expected demuxer_type_asf. This triggers mplayer.c to synchronously follow
the recursive nested playlists.
A new streaming type ASF_ASXPlaylist_e is added to asf.h to control the new
code branch.
The function play_tree_parser_get_line() also receives a new code branch to
deal with buffered streams
which is necessary in order to parse the playlist, buffered when the asf
stream was opened.

I felt the necessity to develop this patch because there are sites which use
nested asx playlists, such
as video.globo.com (see discussions at
http://sourceforge.net/forum/forum.php?thread_id=1668761&forum_id=242727
and
http://sourceforge.net/mailarchive/forum.php?thread_id=31642270&forum_id=21800),
and nested playlists
are part of the microsoft specification for asx (
http://msdn2.microsoft.com/en-us/library/bb262812.aspx).
I also tested the patch against www.bbc.co.uk, www.cnn.com,
http://wptv.wp.pl/news.html
(mplayer -playlist http://i.wp.pl/a/f/asx/11771/wptvnews.asx) and all worked
fine.
Extra care was taken to modify the minimum amount of code and to minimize
potential regressions.

In case this patch is approved for inclusion in mplayer, I would be grateful
if my name was cited in the
list of contributors. All comments welcome.

Thanks,
Marcus C. Granado
mrc [d-o-t] gran [a-t] gmail [d-o-t] com
--
-------------- next part --------------
Index: stream/asf_streaming.c
===================================================================
--- stream/asf_streaming.c	(revision 22481)
+++ stream/asf_streaming.c	(working copy)
@@ -25,6 +25,9 @@
 #include "network.h"
 #include "tcp.h"
 
+#include "../playtree.h"
+extern int playtree_add_playlist(play_tree_t* entry);
+
 #ifdef ARCH_X86
 #define	ASF_LOAD_GUID_PREFIX(guid)	(*(uint32_t *)(guid))
 #else
@@ -765,11 +768,39 @@
 			mp_msg(MSGT_NETWORK,MSGL_DBG2,"Response [%s]\n", http_hdr->buffer );
 		}
 		ret = asf_http_parse_response(asf_http_ctrl, http_hdr);
+		
+		if (strstr(url->url,".asx")!=NULL) {
+		  mp_msg(MSGT_NETWORK,MSGL_V,"ASXPlaylist detected: url=%s, bodysize=%i\n",url->url,http_hdr->body_size);
+		  ret = 0;
+		  asf_http_ctrl->streaming_type=ASF_ASXPlaylist_e;
+		}
+
 		if( ret<0 ) {
 			mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_ASF_HeaderParseFailed);
 			goto err_out;
 		}
 		switch( asf_http_ctrl->streaming_type ) {
+			case ASF_ASXPlaylist_e:
+
+				if( http_hdr->body_size>0 ) {
+				  if( streaming_bufferize( stream->streaming_ctrl, http_hdr->body, http_hdr->body_size )<0 ) {
+				    goto err_out;
+				  }
+				}
+
+				//TODO: read potentially remaining
+				//asx playlist data into buffer
+				//{ int r;
+				//for( r=?; r < http_hdr->body_size; ) {
+				//i = nop_streaming_read(fd,((char*)stream->streaming_ctrl->buffer)+r,http_hdr->body_size - r,stream->streaming_ctrl);
+				//if(i <= 0) return -1;
+				//r += i;
+				//}
+				//}
+				*demuxer_type = DEMUXER_TYPE_PLAYLIST;
+				done=1;
+			  break;
+	
 			case ASF_Live_e:
 			case ASF_Prerecorded_e:
 			case ASF_PlainText_e:
@@ -817,7 +848,7 @@
 	} while(!done);
 
 	stream->fd = fd;
-	if( asf_http_ctrl->streaming_type==ASF_PlainText_e || asf_http_ctrl->streaming_type==ASF_Redirector_e ) {
+	if( asf_http_ctrl->streaming_type==ASF_PlainText_e || asf_http_ctrl->streaming_type==ASF_Redirector_e || asf_http_ctrl->streaming_type==ASF_ASXPlaylist_e) {
 		stream->streaming_ctrl->streaming_read = nop_streaming_read;
 		stream->streaming_ctrl->streaming_seek = nop_streaming_seek;
 	} else {
@@ -852,20 +883,21 @@
 	url_free(url);
 	
 	mp_msg(MSGT_OPEN, MSGL_INFO, MSGTR_MPDEMUX_ASF_InfoStreamASFURL, stream->url);
-	if((!strncmp(stream->url, "http", 4)) && (*file_format!=DEMUXER_TYPE_ASF && *file_format!=DEMUXER_TYPE_UNKNOWN)) {
+	if((!strncmp(stream->url, "http", 4)) && (*file_format!=DEMUXER_TYPE_ASF && *file_format!=DEMUXER_TYPE_UNKNOWN && *file_format!=DEMUXER_TYPE_PLAYLIST)) {
 		streaming_ctrl_free(stream->streaming_ctrl);
 		stream->streaming_ctrl = NULL;
 		return STREAM_UNSUPORTED;
 	}
 
+	*file_format = DEMUXER_TYPE_ASF;
 	if(asf_streaming_start(stream, file_format) < 0) {
 		mp_msg(MSGT_OPEN, MSGL_ERR, MSGTR_MPDEMUX_ASF_StreamingFailed);
 		streaming_ctrl_free(stream->streaming_ctrl);
 		stream->streaming_ctrl = NULL;
 		return STREAM_UNSUPORTED;
 	}
-	
-	*file_format = DEMUXER_TYPE_ASF;
+	if (*file_format != DEMUXER_TYPE_PLAYLIST)	
+	  *file_format = DEMUXER_TYPE_ASF;
 	stream->type = STREAMTYPE_STREAM;
 	fixup_network_stream_cache(stream);
 	return STREAM_OK;
Index: mplayer.c
===================================================================
--- mplayer.c	(revision 22481)
+++ mplayer.c	(working copy)
@@ -2864,6 +2864,8 @@
     mp_msg(MSGT_CPLAYER,MSGL_V,"Parsing playlist %s...\n",
 	    filename_recode(filename));
     entry = parse_playtree(mpctx->stream,0);
+    //TODO:limit depth of nested playlists
+    //to avoid following infinitely nested playlists.
     mpctx->eof=playtree_add_playlist(entry);
     goto goto_next_file;
   }
Index: playtreeparser.c
===================================================================
--- playtreeparser.c	(revision 22481)
+++ playtreeparser.c	(working copy)
@@ -51,18 +51,46 @@
 play_tree_parser_get_line(play_tree_parser_t* p) {
   char *end,*line_end;
   int r,resize = 0;
+  int buffered_stream=0;
 
+  if (p==NULL) return NULL;
+  if (p->stream !=NULL &&
+      p->stream->streaming_ctrl != NULL &&
+      p->stream->streaming_ctrl->buffer != NULL &&
+      p->stream->streaming_ctrl->buffer_size > 0) {
+    buffered_stream=1;
+  }
+
   if(p->buffer == NULL) {
-    p->buffer = malloc(BUF_STEP);
-    p->buffer_size = BUF_STEP;
+    if (!buffered_stream) {
+      p->buffer = malloc(BUF_STEP);
+      p->buffer_size = BUF_STEP;
+    } else {
+      p->buffer_size = p->stream->streaming_ctrl->buffer_size + 1;
+      p->buffer = malloc(p->buffer_size);
+      memcpy( p->buffer, p->stream->streaming_ctrl->buffer, p->stream->streaming_ctrl->buffer_size );
+      p->buffer[p->buffer_size - 1] = '\0';
+      p->buffer_end = p->buffer_size;
+      p->stream->eof = 1;
+      free(p->stream->streaming_ctrl->buffer);
+      p->stream->streaming_ctrl->buffer=NULL;
+      p->stream->streaming_ctrl->buffer_size=0;
+    }
     p->iter = p->buffer;
   }
 
   if(p->stream->eof && (p->buffer_end == 0 || p->iter[0] == '\0'))
     return NULL;
-    
-  while(1) {
 
+  if (buffered_stream) {
+
+      end = strchr(p->iter,'\n');
+      if (!end) end = p->buffer + p->buffer_end;
+
+  } else {
+
+   while(1) {
+
     if(resize) {
       r = p->iter - p->buffer;
       p->buffer = (char*)realloc(p->buffer,p->buffer_size+BUF_STEP);
@@ -91,16 +119,18 @@
       continue;
     }
     break;
+   }
   }
 
   line_end = ((*(end-1)) == '\r') ? end-1 : end;
   if(line_end - p->iter >= 0)
     p->line = (char*)realloc(p->line,line_end - p->iter+1);
   else
-    return NULL;
+    return NULL;  
   if(line_end - p->iter > 0)
     strncpy(p->line,p->iter,line_end - p->iter);
-  p->line[line_end - p->iter] = '\0';
+  p->line[line_end - p->iter] = '\0';   
+
   if(end[0] != '\0')
     end++;
 
@@ -792,7 +822,6 @@
   assert(p != NULL);
 #endif
 
-
   while(play_tree_parser_get_line(p) != NULL) {
     play_tree_parser_reset(p);
 
Index: libmpdemux/asf.h
===================================================================
--- libmpdemux/asf.h	(revision 22481)
+++ libmpdemux/asf.h	(working copy)
@@ -120,7 +120,8 @@
 	ASF_Prerecorded_e,
 	ASF_Redirector_e,
 	ASF_PlainText_e,
-	ASF_Authenticate_e
+	ASF_Authenticate_e,
+	ASF_ASXPlaylist_e
 } ASF_StreamType_e;
 
 typedef struct {


More information about the MPlayer-dev-eng mailing list