/*
Real parser & demuxer
(C) Alex Beregszaszi
Based on FFmpeg's libav/rm.c.
Audio codecs: (supported by RealPlayer8 for Linux)
DNET - RealAudio 3.0, really it's AC3 in swapped-byteorder
SIPR - SiproLab's audio codec, ACELP decoder working with MPlayer,
needs fine-tuning too :)
ATRC - RealAudio 8 (ATRAC3) - www.minidisc.org/atrac3_article.pdf,
ACM decoder uploaded, needs some fine-tuning to work
-> RealAudio 8
COOK/COKR - Real Cooker -> RealAudio G2
Video codecs: (supported by RealPlayer8 for Linux)
RV10 - H.263 based, working with libavcodec's decoder
RV20-RV40 - using RealPlayer's codec plugins
*/
#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"
#include "bswap.h"
//#define mp_dbg(mod,lev, args... ) mp_msg_c((mod<<8)|lev, ## args )
#define MKTAG(a, b, c, d) (a | (b << 8) | (c << 16) | (d << 24))
#define MAX_STREAMS 32
typedef struct {
int timestamp;
int offset;
// int packetno;
// int len; /* only filled by our index generator */
// int flags; /* only filled by our index generator */
} real_index_table_t;
typedef struct {
/* for seeking */
int index_chunk_offset;
real_index_table_t *index_table[MAX_STREAMS];
// int *index_table[MAX_STREAMS];
int index_table_size[MAX_STREAMS];
int index_malloc_size[MAX_STREAMS];
int data_chunk_offset;
int num_of_packets;
int current_packet;
// need for seek
int audio_need_keyframe;
int video_after_seek;
int current_apacket;
int current_vpacket;
// timestamp correction:
int kf_base;// timestamp of the prev. video keyframe
int kf_pts; // timestamp of next video keyframe
int a_pts; // previous audio timestamp
float v_pts; // previous video timestamp
unsigned long duration;
/* stream id table */
// int last_a_stream;
// int a_streams[MAX_STREAMS];
// int last_v_stream;
// 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;
if (isbyte)
len = stream_read_char(demuxer->stream);
else
len = stream_read_word(demuxer->stream);
stream_read(demuxer->stream, buf, (len > buf_size) ? buf_size : len);
if (len > buf_size)
stream_skip(demuxer->stream, len-buf_size);
printf("read_str: %d bytes read\n", len);
}
static void skip_str(int isbyte, demuxer_t *demuxer)
{
int len;
if (isbyte)
len = stream_read_char(demuxer->stream);
else
len = stream_read_word(demuxer->stream);
stream_skip(demuxer->stream, len);
printf("skip_str: %d bytes skipped\n", len);
}
static void dump_index(demuxer_t *demuxer, int stream_id)
{
real_priv_t *priv = demuxer->priv;
real_index_table_t *index;
int i, entries;
if (verbose<=0)
return;
if (stream_id > MAX_STREAMS)
return;
index = priv->index_table[stream_id];
entries = priv->index_table_size[stream_id];
printf("Index table for stream %d\n", stream_id);
for (i = 0; i < entries; i++)
{
#if 1
printf("i: %d, pos: %d, timestamp: %d\n", i, index[i].offset, index[i].timestamp);
#else
printf("packetno: %x pos: %x len: %x timestamp: %x flags: %x\n",
index[i].packetno, index[i].offset, index[i].len, index[i].timestamp,
index[i].flags);
#endif
}
}
static int parse_index_chunk(demuxer_t *demuxer)
{
real_priv_t *priv = demuxer->priv;
int origpos = stream_tell(demuxer->stream);
int next_header_pos = priv->index_chunk_offset;
int i, entries, stream_id;
read_index:
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);
index_mode = -1;
if (i == -256)
stream_reset(demuxer->stream);
stream_seek(demuxer->stream, origpos);
return 0;
//goto end;
}
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;
}
priv->index_table_size[stream_id] = entries;
priv->index_table[stream_id] = malloc(priv->index_table_size[stream_id] * sizeof(real_index_table_t));
for (i = 0; i < entries; i++)
{
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);
stream_skip(demuxer->stream, 4); /* packetno */
// 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].offset);
}
dump_index(demuxer, stream_id);
if (next_header_pos > 0)
goto read_index;
end:
demuxer->seekable = 1; /* got index, we're able to seek */
if (i == -256)
stream_reset(demuxer->stream);
stream_seek(demuxer->stream, origpos);
if (i == -256)
return 0;
else
return 1;
}
#if 1
static void add_index_item(demuxer_t *demuxer, int stream_id, int timestamp, int offset)
{
if (index_mode > 0 && (unsigned)stream_id < MAX_STREAMS)
{
real_priv_t *priv = demuxer->priv;
real_index_table_t *index;
if (priv->index_table_size[stream_id] >= priv->index_malloc_size[stream_id])
{
if (priv->index_malloc_size[stream_id] == 0)
priv->index_malloc_size[stream_id] = 2048;
else
priv->index_malloc_size[stream_id] += priv->index_malloc_size[stream_id] / 2;
priv->index_table[stream_id] = realloc(priv->index_table[stream_id], priv->index_malloc_size[stream_id]*sizeof(priv->index_table[0][0]));
}
if (priv->index_table_size[stream_id] > 0)
{
index = &priv->index_table[stream_id][priv->index_table_size[stream_id] - 1];
if (index->timestamp >= timestamp || index->offset >= offset)
return;
}
index = &priv->index_table[stream_id][priv->index_table_size[stream_id]++];
index->timestamp = timestamp;
index->offset = offset;
demuxer->seekable = 1;
}
}
static void add_index_segment(demuxer_t *demuxer, int seek_stream_id, int seek_timestamp)
{
int tag, len, stream_id, timestamp, flags;
if (seek_timestamp != -1 && (unsigned)seek_stream_id >= MAX_STREAMS)
return;
while (1)
{
demuxer->filepos = stream_tell(demuxer->stream);
tag = stream_read_dword(demuxer->stream);
if (tag == MKTAG('A', 'T', 'A', 'D'))
{
stream_skip(demuxer->stream, 14);
continue; /* skip to next loop */
}
len = tag & 0xffff;
if (tag == -256 || len < 12)
break;
stream_id = stream_
|