changeset 3985:701d18898835

updated/extended some parts, based on RMFF (also initial ATRAC3 hackings and notes)
author alex
date Fri, 04 Jan 2002 19:32:58 +0000
parents 435835bd8dfd
children da96a04ec11e
files libmpdemux/demux_real.c
diffstat 1 files changed, 126 insertions(+), 85 deletions(-) [+]
line wrap: on
line diff
--- a/libmpdemux/demux_real.c	Fri Jan 04 18:10:14 2002 +0000
+++ b/libmpdemux/demux_real.c	Fri Jan 04 19:32:58 2002 +0000
@@ -4,29 +4,22 @@
     (C) Alex Beregszaszi <alex@naxine.org>
     
     Based on FFmpeg's libav/rm.c.
-*/
-
-/*
-Some codecs for Real (from Mike Melanson):
+    
+    $Log$
+    Revision 1.6  2002/01/04 19:32:58  alex
+    updated/extended some parts, based on RMFF (also initial ATRAC3 hackings and notes)
 
-RV10: As has been mentioned, H.263-based; not an unreasonable guess
-RV20: RealVideo 2.0, nothing known
-RV30: RealVideo 3.0,nothing known, but I don't believe I've ever seen any
-media encoded with it
-DNET: apparently one of their original audio codecs, to be used with music
-SIPR: SiprNet, based on ACELP, and is great for compressing voice
-COKR(?): Cooker, the fabled G2 audio codec
-
-New infos:
 
 Audio codecs: (supported by RealPlayer8 for Linux)
-    ATRC - RealAudio 8 (ATRAC3)
-    COOK - RealAudio G2
+    ATRC - RealAudio 8 (ATRAC3) - www.minidisc.org/atrac3_article.pdf,
+           ACM decoder uploaded, needs some fine-tuning to work
+    COOK/COKR - RealAudio G2
     DNET - RealAudio 3.0
-    SIPR - SiproLab's audio codec
+    SIPR - SiproLab's audio codec, ACELP decoder working with MPlayer,
+	   needs fine-tuning too :)
 
 Video codecs: (supported by RealPlayer8 for Linux)
-    RV10
+    RV10 - H.263 based, working with libavcodec's decoder
     RV20
     RV30
 */
@@ -49,9 +42,16 @@
 #define MAX_STREAMS 10
 
 typedef struct {
+    int		timestamp;
+    int		offset;
+    int		packetno;
+} real_index_table_t;
+
+typedef struct {
     /* for seeking */
     int		index_chunk_offset;
-    int		*index_table[MAX_STREAMS];
+    real_index_table_t *index_table[MAX_STREAMS];
+//    int		*index_table[MAX_STREAMS];
     int		index_table_size[MAX_STREAMS];
     int		data_chunk_offset;
     int		num_of_packets;
@@ -64,10 +64,10 @@
     int 	v_streams[MAX_STREAMS];
 } real_priv_t;
 
+/* originally from FFmpeg */
 static void get_str(int isbyte, demuxer_t *demuxer, char *buf, int buf_size)
 {
-    int len, i;
-    char *q;
+    int len;
     
     if (isbyte)
 	len = stream_read_char(demuxer->stream);
@@ -99,54 +99,67 @@
 {
     real_priv_t *priv = demuxer->priv;
     int origpos = stream_tell(demuxer->stream);
-    int i, entries;
-    int stream_id = 0;
-
-    printf("Building index table from index chunk (%d)\n",
-	priv->index_chunk_offset);
-    
-    stream_seek(demuxer->stream, priv->index_chunk_offset);
-
-    stream_skip(demuxer->stream, 4); /* INDX */
+    int next_header_pos = priv->index_chunk_offset;
+    int i, entries, stream_id;
 
 read_index:
-    if (stream_id > MAX_STREAMS)
+    stream_seek(demuxer->stream, next_header_pos);
+
+    i = stream_read_dword_le(demuxer->stream);
+    if ((i == -256) || (i != MKTAG('I', 'N', 'D', 'X')))
+    {
+	printf("Something went wrong, no index chunk found on given address (%d)\n",
+	    next_header_pos);
 	goto end;
+    }
 
-    stream_skip(demuxer->stream, 8); /* unknown */
-    entries = stream_read_word(demuxer->stream);
+    printf("Reading index table from index chunk (%d)\n",
+	next_header_pos);
+
+    i = stream_read_dword(demuxer->stream);
+    printf("size: %d bytes\n", i);
+
+    i = stream_read_word(demuxer->stream);
+    if (i != 0)
+	printf("Hmm, index table with unknown version (%d), please report it to MPlayer developers!\n", i);
+
+    entries = stream_read_dword(demuxer->stream);
     printf("entries: %d\n", entries);
+    
+    stream_id = stream_read_word(demuxer->stream);
+    printf("stream_id: %d\n", stream_id);
+    
+    next_header_pos = stream_read_dword(demuxer->stream);
+    printf("next_header_pos: %d\n", next_header_pos);
     if (entries <= 0)
+    {
+	if (next_header_pos)
+	    goto read_index;
+	i = entries;
 	goto end;
-    stream_skip(demuxer->stream, 12); /* unknown */
-
-//    stream_skip(demuxer->stream, 22); /* unknown bytes */
+    }
 
     priv->index_table_size[stream_id] = entries;
-    priv->index_table[stream_id] = malloc(priv->index_table_size[stream_id] * sizeof(int));
+    priv->index_table[stream_id] = malloc(priv->index_table_size[stream_id] * sizeof(real_index_table_t));
     
     for (i = 0; i < entries; i++)
     {
-	priv->index_table[stream_id][i] = stream_read_dword(demuxer->stream);
-	stream_skip(demuxer->stream, 10); /* unknown bytes */
-	/* [position(dword)][unk1(word)][unused(dword)][unk2(word)] */
+	stream_skip(demuxer->stream, 2); /* version */
+	priv->index_table[stream_id][i].timestamp = stream_read_dword(demuxer->stream);
+	priv->index_table[stream_id][i].offset = stream_read_dword(demuxer->stream);
+	priv->index_table[stream_id][i].packetno = stream_read_dword(demuxer->stream);
 	printf("Index table: Stream#%d: entry: %d: pos: %d\n",
-	    stream_id, i, priv->index_table[stream_id][i]);
+	    stream_id, i, priv->index_table[stream_id][i].offset);
     }
     demuxer->seekable = 1; /* got index, we're able to seek */
+    
+    if (next_header_pos > 0)
+	goto read_index;
 
-//    stream_seek(demuxer->stream, stream_tell(demuxer->stream)-7);
-    /* search next index table for other stream */
-    i = stream_read_word(demuxer->stream);
-    printf("pos: %d, next tag: %.4s\n", stream_tell(demuxer->stream), &i);
-    if (i == MKTAG('I', 'N', 'D', 'X'))
-    {
-	stream_id++;
-	goto read_index;
-    }
+    printf("End of index tables\n");
 
 end:
-    if (entries == -256)
+    if (i == -256)
 	stream_reset(demuxer->stream);
     stream_seek(demuxer->stream, origpos);
 }
@@ -207,6 +220,7 @@
     stream_skip(demuxer->stream, 1); /* reserved */
     flags = stream_read_char(demuxer->stream);
     /* flags:		*/
+    /*  0x1 - reliable  */
     /* 	0x2 - keyframe	*/
 
 //    printf("packet#%d: pos: %d, len: %d, stream_id: %d, timestamp: %d, flags: %x\n",
@@ -260,8 +274,10 @@
     int i;
 
     stream_skip(demuxer->stream, 4); /* header size */
-    stream_skip(demuxer->stream, 2);
-    stream_skip(demuxer->stream, 4);
+    stream_skip(demuxer->stream, 2); /* version */
+//    stream_skip(demuxer->stream, 4);
+    i = stream_read_dword(demuxer->stream);
+    printf("File version: %d\n", i);
     num_of_headers = stream_read_dword(demuxer->stream);
 //    stream_skip(demuxer->stream, 4); /* number of headers */
 
@@ -273,7 +289,7 @@
 	chunk = stream_read_dword_le(demuxer->stream);
 	chunk_size = stream_read_dword(demuxer->stream);
 
-	stream_skip(demuxer->stream, 2);
+	stream_skip(demuxer->stream, 2); /* version */
 	
 	if (chunk_size < 10)
 	    goto fail;
@@ -284,7 +300,8 @@
 	switch(chunk)
 	{
 	    case MKTAG('P', 'R', 'O', 'P'):
-//		printf("Properties chunk\n");
+		/* Properties header */
+
 		stream_skip(demuxer->stream, 4); /* max bitrate */
 		stream_skip(demuxer->stream, 4); /* avg bitrate */
 		stream_skip(demuxer->stream, 4); /* max packet size */
@@ -292,12 +309,10 @@
 		stream_skip(demuxer->stream, 4); /* nb packets */
 		stream_skip(demuxer->stream, 4); /* duration */
 		stream_skip(demuxer->stream, 4); /* preroll */
-//		stream_skip(demuxer->stream, 4); /* index offset */
 		priv->index_chunk_offset = stream_read_dword(demuxer->stream);
-		printf("Index chunk offset: 0x%x\n", priv->index_chunk_offset);
-//		stream_skip(demuxer->stream, 4); /* data offset */
+		printf("First index chunk offset: 0x%x\n", priv->index_chunk_offset);
 		priv->data_chunk_offset = stream_read_dword(demuxer->stream)+10;
-		printf("Data chunk offset: 0x%x\n", priv->data_chunk_offset);
+		printf("First data chunk offset: 0x%x\n", priv->data_chunk_offset);
 		stream_skip(demuxer->stream, 2); /* nb streams */
 #if 0
 		stream_skip(demuxer->stream, 2); /* flags */
@@ -308,7 +323,7 @@
 		    if (flags & 0x1)
 			printf("[save allowed] ");
 		    if (flags & 0x2)
-			printf("[perfect play (?)] ");
+			printf("[perfect play (more buffers)] ");
 		    if (flags & 0x4)
 			printf("[live broadcast] ");
 		    printf("\n");
@@ -317,11 +332,10 @@
 		break;
 	    case MKTAG('C', 'O', 'N', 'T'):
 	    {
+		/* Content description header */
 		char *buf;
 		int len;
 
-//		printf("Broadcasting informations (title, author, copyright, comment)\n");
-
 		len = stream_read_word(demuxer->stream);
 		if (len > 0)
 		{
@@ -360,16 +374,11 @@
 		    demux_info_add(demuxer, "comment", buf);
 		    free(buf);
 		}
-
-//		skip_str(0, demuxer);	/* title */
-//		skip_str(0, demuxer);	/* author */
-//		skip_str(0, demuxer);	/* copyright */
-//		skip_str(0, demuxer);	/* comment */
 		break;
 	    }
 	    case MKTAG('M', 'D', 'P', 'R'):
 	    {
-		/* new stream */
+		/* Media properties header */
 		int stream_id;
 		int bitrate;
 		int codec_data_size;
@@ -380,22 +389,25 @@
 		printf("Found new stream (id: %d)\n", stream_id);
 		
 		stream_skip(demuxer->stream, 4); /* max bitrate */
-		bitrate = stream_read_dword(demuxer->stream); /* bitrate */
+		bitrate = stream_read_dword(demuxer->stream); /* avg bitrate */
 		stream_skip(demuxer->stream, 4); /* max packet size */
 		stream_skip(demuxer->stream, 4); /* avg packet size */
 		stream_skip(demuxer->stream, 4); /* start time */
 		stream_skip(demuxer->stream, 4); /* preroll */
 		stream_skip(demuxer->stream, 4); /* duration */
 		
-		skip_str(1, demuxer);	/* stream description */
+		skip_str(1, demuxer);	/* stream description (name) */
 		skip_str(1, demuxer);	/* mimetype */
 		
+		/* Type specific header */
 		codec_data_size = stream_read_dword(demuxer->stream);
 		codec_pos = stream_tell(demuxer->stream);
 
 		tmp = stream_read_dword(demuxer->stream);
-		if (tmp == MKTAG(0xfd, 'a', 'r', '.')) /* audio header */
+
+		if (tmp == MKTAG(0xfd, 'a', 'r', '.'))
 		{
+		    /* audio header */
 		    sh_audio_t *sh = new_sh_audio(demuxer, stream_id);
 		    char buf[128]; /* for codec name */
 		    int frame_size;
@@ -434,6 +446,7 @@
 		    {
 			stream_skip(demuxer->stream, 4);
 			stream_read(demuxer->stream, buf, 4);
+			buf[4] = 0;
 		    }
 		    else
 		    {		
@@ -443,6 +456,16 @@
 			get_str(1, demuxer, buf, sizeof(buf));
 		    }
 
+		    /* Emulate WAVEFORMATEX struct: */
+		    sh->wf = malloc(sizeof(WAVEFORMATEX));
+		    memset(sh->wf, 0, sizeof(WAVEFORMATEX));
+		    sh->wf->nChannels = sh->channels;
+		    sh->wf->wBitsPerSample = 16;
+		    sh->wf->nSamplesPerSec = sh->samplerate;
+		    sh->wf->nAvgBytesPerSec = bitrate;
+		    sh->wf->nBlockAlign = frame_size;
+		    sh->wf->cbSize = 0;
+
 		    tmp = 1; /* supported audio codec */
 		    switch (MKTAG(buf[0], buf[1], buf[2], buf[3]))
 		    {
@@ -453,31 +476,43 @@
 			case MKTAG('s', 'i', 'p', 'r'):
 			    printf("Audio: SiproLab's ACELP.net\n");
 			    sh->format = 0x130;
+			    /* for buggy directshow loader */
+			    sh->wf = realloc(sh->wf, 18+4);
+			    sh->wf->wBitsPerSample = 0;
+			    sh->wf->nAvgBytesPerSec = 1055;
+			    sh->wf->nBlockAlign = 19;
+//			    sh->wf->nBlockAlign = frame_size / 288;
+			    sh->wf->cbSize = 4;
+			    buf[0] = 30;
+			    buf[1] = 1;
+			    buf[2] = 1;
+			    buf[3] = 0;
+			    memcpy((sh->wf+18), (char *)&buf[0], 4);
+//			    sh->wf[sizeof(WAVEFORMATEX)+1] = 30;
+//			    sh->wf[sizeof(WAVEFORMATEX)+2] = 1;
+//			    sh->wf[sizeof(WAVEFORMATEX)+3] = 1;
+//			    sh->wf[sizeof(WAVEFORMATEX)+4] = 0;
 			    break;
 			case MKTAG('c', 'o', 'o', 'k'):
-			    printf("Audio: Real's GeneralCooker (unsupported)\n");
+			    printf("Audio: Real's GeneralCooker (?) (RealAudio G2?) (unsupported)\n");
 			    tmp = 0;
 			    break;
 			case MKTAG('a', 't', 'r', 'c'):
+			    printf("Audio: ATRAC3 (RealAudio 8?) (unsupported)\n");
+			    sh->format = 0x270;
+			    break;
 			default:
 			    printf("Audio: Unknown (%s)\n", buf);
 			    tmp = 0;
 			    sh->format = MKTAG(buf[0], buf[1], buf[2], buf[3]);
 		    }
 
+		    sh->wf->wFormatTag = sh->format;
+		    
+		    print_wave_header(sh->wf);
+
 		    if (tmp)
 		    {
-			/* Emulate WAVEFORMATEX struct: */
-			sh->wf = malloc(sizeof(WAVEFORMATEX));
-			memset(sh->wf, 0, sizeof(WAVEFORMATEX));
-			sh->wf->wFormatTag = sh->format;
-			sh->wf->nChannels = sh->channels;
-			sh->wf->wBitsPerSample = 16;
-			sh->wf->nSamplesPerSec = sh->samplerate;
-			sh->wf->nAvgBytesPerSec = bitrate;
-			sh->wf->nBlockAlign = frame_size; /* 19 for acelp, pff */
-			sh->wf->cbSize = 0;
-		    
 			/* insert as stream */
 			demuxer->audio->sh = sh;
 			sh->ds = demuxer->audio;
@@ -489,8 +524,12 @@
 			    priv->last_a_stream++;
 			}
 		    }
+		    else
+			free(sh->wf);
+//		    break;
 		}
 		else
+//		case MKTAG('V', 'I', 'D', 'O'):
 		{
 		    /* video header */
 		    sh_video_t *sh = new_sh_video(demuxer, stream_id);
@@ -499,7 +538,7 @@
 		    printf("video: %.4s (%x)\n", (char *)&tmp, tmp);
 		    if (tmp != MKTAG('V', 'I', 'D', 'O'))
 		    {
-			mp_msg(MSGT_DEMUX, MSGL_ERR, "Unsupported video codec\n");
+			mp_msg(MSGT_DEMUX, MSGL_ERR, "Not audio/video stream or unsupported!\n");
 			goto skip_this_chunk;
 		    }
 		    
@@ -559,12 +598,14 @@
 			priv->last_v_stream++;
 		    }
 		}
-
+//		break;
+//	    default:
 skip_this_chunk:
 		/* skip codec info */
 		tmp = stream_tell(demuxer->stream) - codec_pos;
 		stream_skip(demuxer->stream, codec_data_size - tmp);
 		break;
+//	    }
 	    }
 	    case MKTAG('D', 'A', 'T', 'A'):
 		goto header_end;
@@ -589,7 +630,7 @@
     /* disable seeking */
     demuxer->seekable = 0;
 
-    if (priv->index_chunk_offset && (index_mode == 1) || (index_mode == 2))
+    if (priv->index_chunk_offset && ((index_mode == 1) || (index_mode == 2)))
 	parse_index_chunk(demuxer);
 
 fail: