[MPlayer-dev-eng] NSV demuxer retry
Reza Jelveh
reza.jelveh at tu-harburg.de
Sat Apr 3 19:08:53 CEST 2004
hi,
now here is the more or less working and clean version of this nsv demuxer.
audio/video is sync for most streams ive encountered. however some streams like the ones that have fixed fps in their header suddenly speed up for some reason.
theres an issue with vp6 which is that vp6 streams will first show weird colored mosaic and then after a few seconds show correct picture.
www.nullsoft.com/nsv has some examples. for example that adara sings stream clip does work with the ffmpeg vp3 codec but not with the binary vp3 or vp4 codec(they will fail at init_video_codec).
while the nullsoft band samples work fine even with binary codec.
all music video streams from www.winamp.com are vp5 and dolby vlb aac.
dolby vlb doesnt seem to work(yet). and the vp5 decoding seems kinda broken too try it out and see what i mean :).
my guess would be that some info is missing for initializing those codecs... maybe i_bps to calculate the bitrate?
however it does work just fine for many winamp tv streams i tested(not those fixed fps ones tho! they have video speed issues) .
seek is yet to be implemented.
im still looking into that codec problem and the speed issues. otherwise this patch is fine id say.
regards,
Reza Jelveh
diff -uNr MPlayer-20040331/libmpdemux/Makefile MPlayer-20040331-nsv2/libmpdemux/Makefile
--- MPlayer-20040331/libmpdemux/Makefile 2004-03-09 15:46:34.000000000 +0100
+++ MPlayer-20040331-nsv2/libmpdemux/Makefile 2004-04-01 12:15:11.000000000 +0200
@@ -3,7 +3,7 @@
include ../config.mak
-SRCS = mp3_hdr.c video.c mpeg_hdr.c cache2.c asfheader.c aviheader.c aviprint.c muxer.c muxer_avi.c muxer_mpeg.c demux_asf.c demux_avi.c demux_mov.c parse_mp4.c demux_mpg.c demux_ty.c demux_ty_osd.c demux_pva.c demux_viv.c demuxer.c dvdnav_stream.c open.c parse_es.c stream.c stream_file.c stream_netstream.c stream_vcd.c stream_null.c stream_ftp.c tv.c tvi_dummy.c tvi_v4l.c tvi_v4l2.c tvi_bsdbt848.c frequencies.c demux_fli.c demux_real.c demux_y4m.c yuv4mpeg.c yuv4mpeg_ratio.c demux_nuv.c demux_film.c demux_roq.c mf.c demux_mf.c demux_audio.c demux_demuxers.c demux_ogg.c demux_bmp.c cdda.c demux_rawaudio.c demux_rawvideo.c cddb.c cdinfo.c demux_rawdv.c ai_alsa.c ai_alsa1x.c ai_oss.c audio_in.c demux_smjpeg.c demux_lmlm4.c cue_read.c extension.c demux_gif.c demux_ts.c demux_realaud.c url.c muxer_rawvideo.c
+SRCS = mp3_hdr.c video.c mpeg_hdr.c cache2.c asfheader.c aviheader.c aviprint.c muxer.c muxer_avi.c muxer_mpeg.c demux_asf.c demux_avi.c demux_mov.c parse_mp4.c demux_mpg.c demux_ty.c demux_ty_osd.c demux_pva.c demux_viv.c demuxer.c dvdnav_stream.c open.c parse_es.c stream.c stream_file.c stream_netstream.c stream_vcd.c stream_null.c stream_ftp.c tv.c tvi_dummy.c tvi_v4l.c tvi_v4l2.c tvi_bsdbt848.c frequencies.c demux_fli.c demux_real.c demux_y4m.c yuv4mpeg.c yuv4mpeg_ratio.c demux_nsv.c demux_nuv.c demux_film.c demux_roq.c mf.c demux_mf.c demux_audio.c demux_demuxers.c demux_ogg.c demux_bmp.c cdda.c demux_rawaudio.c demux_rawvideo.c cddb.c cdinfo.c demux_rawdv.c ai_alsa.c ai_alsa1x.c ai_oss.c audio_in.c demux_smjpeg.c demux_lmlm4.c cue_read.c extension.c demux_gif.c demux_ts.c demux_realaud.c url.c muxer_rawvideo.c
ifeq ($(XMMS_PLUGINS),yes)
SRCS += demux_xmms.c
endif
diff -uNr MPlayer-20040331/libmpdemux/demux_nsv.c MPlayer-20040331-nsv2/libmpdemux/demux_nsv.c
--- MPlayer-20040331/libmpdemux/demux_nsv.c 1970-01-01 01:00:00.000000000 +0100
+++ MPlayer-20040331-nsv2/libmpdemux/demux_nsv.c 2004-04-03 18:43:46.992141112 +0200
@@ -0,0 +1,286 @@
+
+/*
+ * Nullsoft Streaming Video demuxer
+ * for MPlayer
+ * by Reza Jelveh <reza.jelveh at tuhh.de>
+ * seeking and PCM audio not yet supported
+ * PCM needs extra audio chunk "miniheader" parsing
+ * Based on a'rpis g2 work
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "config.h"
+#include "mp_msg.h"
+#include "help_mp.h"
+#include "stream.h"
+#include "demuxer.h"
+#include "stheader.h"
+
+typedef struct {
+ float v_pts;
+ int video_pack_no;
+
+} nsv_priv_t;
+
+/**
+ * Seeking still to be implemented
+ */
+void demux_seek_nsv ( demuxer_t *demuxer, float rel_seek_secs, int flags )
+{
+// seeking is not yet implemented
+}
+
+
+int demux_nsv_fill_buffer ( demuxer_t *demuxer )
+{
+ unsigned char hdr[17];
+ // for the extra data
+ unsigned char aux[6];
+ int i_aux;
+ // videolen = audio chunk length, audiolen = video chunk length
+ int videolen,audiolen;
+
+ sh_video_t *sh_video = NULL;
+ sh_audio_t *sh_audio = NULL;
+
+ nsv_priv_t * priv = demuxer->priv;
+
+ sh_video = demuxer->video->sh ;
+
+ // if the audio/video chunk has no new header the first 2 bytes will be discarded 0xBEEF
+ // or rather 0xEF 0xBE
+ stream_read(demuxer->stream,hdr,7);
+ if(stream_eof(demuxer->stream)) return 0;
+ // sometimes instead of 0xBEEF as described for the next audio/video chunk we get
+ // a whole new header
+ if(hdr[0]==0x4E && hdr[1]==0x53 && hdr[2]==0x56){
+ // NSV header!
+ if(hdr[3]==0x73){
+ // NSVs
+ // get the header since there is no more metaheader after the first one
+ // there is no more need to skip that
+ stream_read(demuxer->stream,hdr+7,17-7);
+ // read length header
+
+ stream_read(demuxer->stream,hdr,7);
+
+ }
+ }
+ demuxer->filepos=stream_tell(demuxer->stream);
+
+
+ sh_video->pts = priv->v_pts =demuxer->video->pts= priv->video_pack_no *
+ (float)sh_video->frametime;
+
+ mp_dbg(MSGT_DEMUX,MSGL_DBG2,"demux_nsv: %08X: %02X %02X | %02X %02X %02X | %02X %02X \n",
+ (int)demuxer->filepos, hdr[0],hdr[1],hdr[2],hdr[3],hdr[4],hdr[5],hdr[6]);
+ // read video:
+ videolen=(hdr[2]>>4)|(hdr[3]<<4)|(hdr[4]<<0xC);
+ //check if we got extra data like subtitles here
+ if( (hdr[2]&0x0f) != 0x0 )
+ {
+ if( stream_read( demuxer->stream, aux, 6 ) < 6 )
+ return 0;
+
+ i_aux = aux[1]|aux[0]<<8;
+ /* We skip this extra data */
+ stream_skip( demuxer->stream, i_aux );
+ videolen -= 6 + i_aux;
+
+ }
+ if(videolen){
+ if(demuxer->video->sh){
+ ds_read_packet(demuxer->video,demuxer->stream,videolen,priv->v_pts,demuxer->filepos,0);
+ ++priv->video_pack_no;
+ }
+ else
+ stream_skip(demuxer->stream,videolen);
+ }
+ // read audio:
+ audiolen=(hdr[5])|(hdr[6]<<8);
+ if(audiolen){
+ if(demuxer->audio->sh){
+ ds_read_packet(demuxer->audio,demuxer->stream,audiolen,priv->v_pts,demuxer->filepos+videolen,0);
+ }
+ else
+ stream_skip(demuxer->stream,audiolen);
+ }
+
+ return 1;
+
+}
+
+
+demuxer_t* demux_open_nsv ( demuxer_t* demuxer )
+{
+ // last 2 bytes 17 and 18 are unknown but right after that comes the length
+ unsigned char hdr[17];
+ int videolen,audiolen;
+ sh_video_t *sh_video = NULL;
+ sh_audio_t *sh_audio = NULL;
+
+
+ nsv_priv_t * priv = malloc(sizeof(nsv_priv_t));
+ demuxer->priv=priv;
+ priv->video_pack_no=0;
+ /* Create a new video stream header */
+ sh_video = new_sh_video ( demuxer, 0 );
+
+ /* Make sure the demuxer knows about the new video stream header
+ * (even though new_sh_video() ought to take care of it)
+ */
+ demuxer->video->sh = sh_video;
+
+ /* Make sure that the video demuxer stream header knows about its
+ * parent video demuxer stream (this is getting wacky), or else
+ * video_read_properties() will choke
+ */
+ sh_video->ds = demuxer->video;
+
+ /* disable seeking yet to be fixed*/
+ demuxer->seekable = 0;
+
+ stream_read(demuxer->stream,hdr,4);
+ if(stream_eof(demuxer->stream)) return 0;
+
+ /*** if we detected the file to be nsv and there was neither eof nor a header
+ **** that means that its most likely a shoutcast stream so we will need to seek
+ **** to the first occurance of the NSVs header ****/
+ if(!(hdr[0]==0x4E && hdr[1]==0x53 && hdr[2]==0x56)){
+ // todo: replace this with a decent string search algo
+ while(1){
+ stream_read(demuxer->stream,hdr,1);
+ if(stream_eof(demuxer->stream))
+ return 0;
+ if(hdr[0]!=0x4E)
+ continue;
+
+ stream_read(demuxer->stream,hdr+1,1);
+
+ if(stream_eof(demuxer->stream))
+ return 0;
+ if(hdr[1]!=0x53)
+ continue;
+
+ stream_read(demuxer->stream,hdr+2,1);
+
+ if(stream_eof(demuxer->stream))
+ return 0;
+ if(hdr[2]!=0x56)
+ continue;
+
+ stream_read(demuxer->stream,hdr+3,1);
+
+ if(stream_eof(demuxer->stream))
+ return 0;
+ if(hdr[3]!=0x73)
+ continue;
+
+ break;
+ }
+ }
+ if(hdr[0]==0x4E && hdr[1]==0x53 && hdr[2]==0x56){
+ // NSV header!
+ if(hdr[3]==0x73){
+ // NSVs
+ stream_read(demuxer->stream,hdr+4,17-4);
+
+ }
+
+ if(hdr[3]==0x66){
+ // NSVf
+ int len=stream_read_dword_le(demuxer->stream);
+ // TODO: parse out metadata!!!!
+ stream_skip(demuxer->stream,len-8);
+
+ // NSVs
+ stream_read(demuxer->stream,hdr,17);
+
+ }
+ // bytes 4-7 video codec fourcc
+ sh_video->format=mmioFOURCC(hdr[4],hdr[5],hdr[6],hdr[7]);
+
+ // bytes 8-11 audio codec fourcc
+ // PCM fourcc needs extra parsing for every audio chunk, yet to implement
+ if( strncmp(hdr+8,"NONE", 4)&&strncmp(hdr+8,"VLB ",4)){
+ sh_audio = new_sh_audio ( demuxer, 0 );
+ demuxer->audio->sh = sh_audio;
+ sh_audio->format=mmioFOURCC(hdr[8],hdr[9],hdr[10],hdr[11]);
+ sh_audio->ds = demuxer->audio;
+ }
+
+
+ // dummy debug message
+ mp_msg(MSGT_DEMUX,MSGL_V,"demux_nsv: Header: %s\n",hdr);
+
+ // new video stream! parse header
+ sh_video->disp_w=hdr[12]|(hdr[13]<<8);
+ sh_video->disp_h=hdr[14]|(hdr[15]<<8);
+ sh_video->bih=(BITMAPINFOHEADER*)calloc(1,sizeof(BITMAPINFOHEADER));
+ sh_video->bih->biSize=sizeof(BITMAPINFOHEADER);
+ sh_video->bih->biPlanes=1;
+ sh_video->bih->biBitCount=24;
+ sh_video->bih->biWidth=hdr[12]|(hdr[13]<<8);
+ sh_video->bih->biHeight=hdr[14]|(hdr[15]<<8);
+ memcpy(&sh_video->bih->biCompression,hdr+4,4);
+ sh_video->bih->biSizeImage=sh_video->bih->biWidth*sh_video->bih->biHeight*3;
+
+ switch(hdr[16]){
+ case 0x80:
+ sh_video->fps=30;
+ break;
+ case 0x81:
+ sh_video->fps=(float)30000.0/1001.0;
+ break;
+ case 0x82:
+ sh_video->fps=25;
+ break;
+ case 0x83:
+ sh_video->fps=(float)24000.0/1001.0;
+ break;
+ case 0x85:
+ sh_video->fps=(float)15000.0/1001.0;
+ break;
+ default:
+ sh_video->fps = (float)hdr[16];
+ }
+ sh_video->frametime = (float)1.0 / (float)sh_video->fps;
+
+ }
+
+
+
+ return demuxer;
+}
+
+int nsv_check_file ( demuxer_t* demuxer )
+{
+ unsigned int id;
+
+ /* Store original position */
+ off_t orig_pos = stream_tell(demuxer->stream);
+
+ mp_msg ( MSGT_DEMUX, MSGL_V, "Checking for Nullsoft Streaming Video\n" );
+
+ //---- check NSVx header:
+ id=stream_read_dword_le(demuxer->stream);
+ if(id!=mmioFOURCC('N','S','V','f') &&
+ id!=mmioFOURCC('N','S','V','s')) return 0; // not an NSV file
+
+ stream_reset(demuxer->stream); // clear EOF
+ stream_seek(demuxer->stream,demuxer->stream->start_pos);
+
+
+ return 1;
+}
+
+void demux_close_nsv(demuxer_t* demuxer) {
+ nsv_priv_t* priv = demuxer->priv;
+ if(!priv)
+ return;
+ free(priv);
+
+}
diff -uNr MPlayer-20040331/libmpdemux/demuxer.c MPlayer-20040331-nsv2/libmpdemux/demuxer.c
--- MPlayer-20040331/libmpdemux/demuxer.c 2004-02-22 07:20:48.000000000 +0100
+++ MPlayer-20040331-nsv2/libmpdemux/demuxer.c 2004-04-01 12:15:11.000000000 +0200
@@ -123,6 +123,7 @@
extern void demux_close_film(demuxer_t* demuxer);
extern void demux_close_bmp(demuxer_t* demuxer);
extern void demux_close_fli(demuxer_t* demuxer);
+extern void demux_close_nsv(demuxer_t* demuxer);
extern void demux_close_nuv(demuxer_t* demuxer);
extern void demux_close_audio(demuxer_t* demuxer);
extern void demux_close_ogg(demuxer_t* demuxer);
@@ -174,6 +175,8 @@
demux_close_bmp(demuxer); break;
case DEMUXER_TYPE_FLI:
demux_close_fli(demuxer); break;
+ case DEMUXER_TYPE_NSV:
+ demux_close_nsv(demuxer); break;
case DEMUXER_TYPE_NUV:
demux_close_nuv(demuxer); break;
case DEMUXER_TYPE_MPEG_TY:
@@ -295,6 +298,7 @@
int demux_mov_fill_buffer(demuxer_t *demux,demux_stream_t* ds);
int demux_vivo_fill_buffer(demuxer_t *demux);
int demux_real_fill_buffer(demuxer_t *demuxer);
+int demux_nsv_fill_buffer(demuxer_t *demux);
int demux_nuv_fill_buffer(demuxer_t *demux);
int demux_rtp_fill_buffer(demuxer_t *demux, demux_stream_t* ds);
int demux_rawdv_fill_buffer(demuxer_t *demuxer);
@@ -339,6 +343,7 @@
case DEMUXER_TYPE_RAWDV: return demux_rawdv_fill_buffer(demux);
#endif
case DEMUXER_TYPE_REAL: return demux_real_fill_buffer(demux);
+ case DEMUXER_TYPE_NSV: return demux_nsv_fill_buffer(demux);
case DEMUXER_TYPE_NUV: return demux_nuv_fill_buffer(demux);
#ifdef USE_TV
case DEMUXER_TYPE_TV: return demux_tv_fill_buffer(demux, ds);
@@ -590,7 +595,9 @@
extern demuxer_t * demux_open_pva(demuxer_t * demuxer);
extern int real_check_file(demuxer_t *demuxer);
extern void demux_open_real(demuxer_t *demuxer);
+extern int nsv_check_file(demuxer_t *demuxer);
extern int nuv_check_file(demuxer_t *demuxer);
+extern void demux_open_nsv(demuxer_t *demuxer);
extern void demux_open_nuv(demuxer_t *demuxer);
extern int demux_audio_open(demuxer_t* demuxer);
extern int demux_ogg_open(demuxer_t* demuxer);
@@ -705,6 +712,17 @@
demuxer = NULL;
}
}
+//=============== Try to open as NSV file: =================
+if(file_format==DEMUXER_TYPE_UNKNOWN || file_format==DEMUXER_TYPE_NSV){
+ demuxer=new_demuxer(stream,DEMUXER_TYPE_NSV,audio_id,video_id,dvdsub_id);
+ if(file_format==DEMUXER_TYPE_NSV||nsv_check_file(demuxer)){
+ mp_msg(MSGT_DEMUXER,MSGL_INFO,MSGTR_Detected_XXX_FileFormat,"Nullsoft Streaming Video");
+ file_format=DEMUXER_TYPE_NSV;
+ } else {
+ free_demuxer(demuxer);
+ demuxer = NULL;
+ }
+}
//=============== Try to open as NUV file: =================
if(file_format==DEMUXER_TYPE_UNKNOWN || file_format==DEMUXER_TYPE_NUV){
demuxer=new_demuxer(stream,DEMUXER_TYPE_NUV,audio_id,video_id,dvdsub_id);
@@ -1169,6 +1187,10 @@
return demuxer;
// break;
}
+ case DEMUXER_TYPE_NSV: {
+ demux_open_nsv(demuxer);
+ break;
+ }
case DEMUXER_TYPE_NUV: {
demux_open_nuv(demuxer);
break;
diff -uNr MPlayer-20040331/libmpdemux/demuxer.h MPlayer-20040331-nsv2/libmpdemux/demuxer.h
--- MPlayer-20040331/libmpdemux/demuxer.h 2003-12-08 20:33:38.000000000 +0100
+++ MPlayer-20040331-nsv2/libmpdemux/demuxer.h 2004-04-01 12:15:11.000000000 +0200
@@ -43,11 +43,12 @@
#define DEMUXER_TYPE_REALAUDIO 32
#define DEMUXER_TYPE_MPEG_TY 33
#define DEMUXER_TYPE_LMLM4 34
+#define DEMUXER_TYPE_NSV 35
// This should always match the higest demuxer type number.
// Unless you want to disallow users to force the demuxer to some types
#define DEMUXER_TYPE_MIN 0
-#define DEMUXER_TYPE_MAX 34
+#define DEMUXER_TYPE_MAX 35
#define DEMUXER_TYPE_DEMUXERS (1<<16)
// A virtual demuxer type for the network code
diff -uNr MPlayer-20040331/libmpdemux/extension.c MPlayer-20040331-nsv2/libmpdemux/extension.c
--- MPlayer-20040331/libmpdemux/extension.c 2003-10-05 00:00:25.000000000 +0200
+++ MPlayer-20040331-nsv2/libmpdemux/extension.c 2004-04-03 18:43:58.926326840 +0200
@@ -48,7 +48,8 @@
{ "it", DEMUXER_TYPE_XMMS },
{ "mid", DEMUXER_TYPE_XMMS },
{ "midi", DEMUXER_TYPE_XMMS },
- { "vqf", DEMUXER_TYPE_XMMS }
+ { "vqf", DEMUXER_TYPE_XMMS },
+ { "nsv", DEMUXER_TYPE_NSV }
};
int demuxer_type_by_filename(char* filename){
diff -uNr MPlayer-20040331/libmpdemux/network.c MPlayer-20040331-nsv2/libmpdemux/network.c
--- MPlayer-20040331/libmpdemux/network.c 2004-03-13 17:10:02.000000000 +0100
+++ MPlayer-20040331-nsv2/libmpdemux/network.c 2004-04-01 12:15:11.000000000 +0200
@@ -92,7 +92,9 @@
// Real Media
{ "audio/x-pn-realaudio", DEMUXER_TYPE_REAL },
// OGG Streaming
- { "application/x-ogg", DEMUXER_TYPE_OGG }
+ { "application/x-ogg", DEMUXER_TYPE_OGG },
+ // NullSoft Streaming Video
+ { "video/nsv", DEMUXER_TYPE_NSV}
};
@@ -778,8 +780,14 @@
mp_msg(MSGT_NETWORK,MSGL_INFO,"Public : %s\n", atoi(field_data)?"yes":"no"); field_data = NULL;
if( (field_data = http_get_field(http_hdr, "icy-br")) != NULL )
mp_msg(MSGT_NETWORK,MSGL_INFO,"Bitrate: %skbit/s\n", field_data); field_data = NULL;
- // Ok, we have detected an mp3 stream
- *file_format = DEMUXER_TYPE_AUDIO;
+
+ // If content-type == video/nsv we most likely have a winamp video stream
+ // otherwise it should be mp3. if there are more types consider adding mime type
+ // handling like later
+ if( !strcmp((field_data = http_get_field(http_hdr, "content-type")),"video/nsv"))
+ *file_format = DEMUXER_TYPE_NSV;
+ else
+ *file_format = DEMUXER_TYPE_AUDIO;
return 0;
}
case 400: // Server Full
@@ -1248,6 +1256,7 @@
case DEMUXER_TYPE_OGG:
case DEMUXER_TYPE_PLAYLIST:
case DEMUXER_TYPE_UNKNOWN:
+ case DEMUXER_TYPE_NSV:
// Generic start, doesn't need to filter
// the network stream, it's a raw stream
ret = nop_streaming_start( stream );
More information about the MPlayer-dev-eng
mailing list