summaryrefslogtreecommitdiffstats
path: root/libmpdemux/demux_real.c
diff options
context:
space:
mode:
Diffstat (limited to 'libmpdemux/demux_real.c')
-rw-r--r--libmpdemux/demux_real.c200
1 files changed, 126 insertions, 74 deletions
diff --git a/libmpdemux/demux_real.c b/libmpdemux/demux_real.c
index 4ac8b6074a..1e07e8bd75 100644
--- a/libmpdemux/demux_real.c
+++ b/libmpdemux/demux_real.c
@@ -38,6 +38,13 @@ Video codecs: (supported by RealPlayer8 for Linux)
#define MAX_STREAMS 32
+static unsigned char sipr_swaps[38][2]={
+ {0,63},{1,22},{2,44},{3,90},{5,81},{7,31},{8,86},{9,58},{10,36},{12,68},
+ {13,39},{14,73},{15,53},{16,69},{17,57},{19,88},{20,34},{21,71},{24,46},
+ {25,94},{26,54},{28,75},{29,50},{32,70},{33,92},{35,74},{38,85},{40,56},
+ {42,87},{43,65},{45,59},{48,79},{49,93},{51,89},{55,95},{61,76},{67,83},
+ {77,80} };
+
typedef struct {
int timestamp;
int offset;
@@ -92,6 +99,18 @@ typedef struct {
int a_bitrate; ///< Audio bitrate
int v_bitrate; ///< Video bitrate
int stream_switch; ///< Flag used to switch audio/video demuxing
+
+ /**
+ * Used to reorder audio data
+ */
+ int sub_packet_size[MAX_STREAMS]; ///< sub packet size, per stream
+ int sub_packet_h[MAX_STREAMS]; ///< number of coded frames per block
+ int coded_framesize[MAX_STREAMS]; ///< coded frame size, per stream
+ int audiopk_size[MAX_STREAMS]; ///< audio packet size
+ unsigned char *audio_buf; ///< place to store reordered audio data
+ int audio_timestamp; ///< timestamp for all audio packets in a block
+ int sub_packet_cnt; ///< number of subpacket already received
+ int audio_filepos; ///< file position of first audio packet in block
} real_priv_t;
/* originally from FFmpeg */
@@ -531,6 +550,8 @@ static int demux_real_fill_buffer(demuxer_t *demuxer, demux_stream_t *dsds)
int version;
int reserved;
demux_packet_t *dp;
+ int x, sps, cfs, sph, spc, w;
+ int audioreorder_getnextpk = 0;
while(1){
@@ -622,6 +643,11 @@ got_audio:
ds=demuxer->audio;
mp_dbg(MSGT_DEMUX,MSGL_DBG2, "packet is audio (id: %d)\n", stream_id);
+ if (flags & 2) {
+ priv->sub_packet_cnt = 0;
+ audioreorder_getnextpk = 0;
+ }
+
// parse audio chunk:
{
#ifdef CRACK_MATRIX
@@ -649,8 +675,79 @@ got_audio:
free(sub_packet_lengths);
return 1;
}
+ if ((((sh_audio_t*)ds->sh)->format == mmioFOURCC('2', '8', '_', '8')) ||
+ (((sh_audio_t*)ds->sh)->format == mmioFOURCC('c', 'o', 'o', 'k')) ||
+ (((sh_audio_t*)ds->sh)->format == mmioFOURCC('a', 't', 'r', 'c')) ||
+ (((sh_audio_t*)ds->sh)->format == mmioFOURCC('s', 'i', 'p', 'r'))) {
+ sps = priv->sub_packet_size[stream_id];
+ sph = priv->sub_packet_h[stream_id];
+ cfs = priv->coded_framesize[stream_id];
+ w = priv->audiopk_size[stream_id];
+ spc = priv->sub_packet_cnt;
+ switch (((sh_audio_t*)ds->sh)->format) {
+ case mmioFOURCC('2', '8', '_', '8'):
+ for (x = 0; x < sph / 2; x++)
+ stream_read(demuxer->stream, priv->audio_buf + x * 2 * w + spc * cfs, cfs);
+ break;
+ case mmioFOURCC('c', 'o', 'o', 'k'):
+ case mmioFOURCC('a', 't', 'r', 'c'):
+ for (x = 0; x < w / sps; x++)
+ stream_read(demuxer->stream, priv->audio_buf + sps * (sph * x + ((sph + 1) / 2) * (spc & 1) +
+ (spc >> 1)), sps);
+ break;
+ case mmioFOURCC('s', 'i', 'p', 'r'):
+ stream_read(demuxer->stream, priv->audio_buf + spc * w, w);
+ if (spc == sph - 1) {
+ int n;
+ int bs = sph * w * 2 / 96; // nibbles per subpacket
+ // Perform reordering
+ for(n=0; n < 38; n++) {
+ int j;
+ int i = bs * sipr_swaps[n][0];
+ int o = bs * sipr_swaps[n][1];
+ // swap nibbles of block 'i' with 'o' TODO: optimize
+ for(j = 0;j < bs; j++) {
+ int x = (i & 1) ? (priv->audio_buf[i >> 1] >> 4) : (priv->audio_buf[i >> 1] & 0x0F);
+ int y = (o & 1) ? (priv->audio_buf[o >> 1] >> 4) : (priv->audio_buf[o >> 1] & 0x0F);
+ if(o & 1)
+ priv->audio_buf[o >> 1] = (priv->audio_buf[o >> 1] & 0x0F) | (x << 4);
+ else
+ priv->audio_buf[o >> 1] = (priv->audio_buf[o >> 1] & 0xF0) | x;
+ if(i & 1)
+ priv->audio_buf[i >> 1] = (priv->audio_buf[i >> 1] & 0x0F) | (y << 4);
+ else
+ priv->audio_buf[i >> 1] = (priv->audio_buf[i >> 1] & 0xF0) | y;
+ ++i; ++o;
+ }
+ }
+ }
+ break;
+ }
+ priv->audio_need_keyframe = 0;
+ priv->audio_timestamp = timestamp / 1000.0f;
+ priv->a_pts = timestamp; // All packets in a block have the same timestamp
+ if (priv->sub_packet_cnt == 0)
+ priv->audio_filepos = demuxer->filepos;
+ if (++(priv->sub_packet_cnt) < sph)
+ audioreorder_getnextpk = 1;
+ else {
+ int apk_usize = ((WAVEFORMATEX*)((sh_audio_t*)ds->sh)->wf)->nBlockAlign;
+ audioreorder_getnextpk = 0;
+ priv->sub_packet_cnt = 0;
+ // Release all the audio packets
+ for (x = 0; x < sph*w/apk_usize; x++) {
+ dp = new_demux_packet(apk_usize);
+ memcpy(dp->buffer, priv->audio_buf + x * apk_usize, apk_usize);
+ dp->pts = x ? 0 : priv->audio_timestamp;
+ dp->pos = priv->audio_filepos; // all equal
+ dp->flags = x ? 0 : 0x10; // Mark first packet as keyframe
+ ds_add_packet(ds, dp);
+ }
+ }
+ } else { // Not a codec that require reordering
dp = new_demux_packet(len);
- stream_read(demuxer->stream, dp->buffer, len);
+ stream_read(demuxer->stream, dp->buffer, len);
+
#ifdef CRACK_MATRIX
mp_msg(MSGT_DEMUX, MSGL_V,"*** audio block len=%d\n",len);
{ // HACK - used for reverse engineering the descrambling matrix
@@ -691,6 +788,8 @@ got_audio:
dp->pos = demuxer->filepos;
dp->flags = (flags & 0x2) ? 0x10 : 0;
ds_add_packet(ds, dp);
+
+ } // codec_id check, codec default case
}
// we will not use audio index if we use -idx and have a video
if(!demuxer->video->sh && index_mode == 2 && (unsigned)demuxer->audio->id < MAX_STREAMS)
@@ -706,6 +805,10 @@ got_audio:
priv->stream_switch = 1;
}
+ // If we're reordering audio packets and we need more data get it
+ if (audioreorder_getnextpk)
+ continue;
+
return 1;
}
@@ -933,6 +1036,7 @@ if(stream_id<256){
demuxer->audio->id=stream_id;
sh->ds=demuxer->audio;
demuxer->audio->sh=sh;
+ priv->audio_buf = malloc(priv->sub_packet_h[demuxer->audio->id] * priv->audiopk_size[demuxer->audio->id]);
mp_msg(MSGT_DEMUX,MSGL_V,"Auto-selected RM audio ID = %d\n",stream_id);
goto got_audio;
}
@@ -1260,30 +1364,11 @@ static demuxer_t* demux_open_real(demuxer_t* demuxer)
sh->wf->nChannels = sh->channels;
sh->wf->wBitsPerSample = sh->samplesize*8;
sh->wf->nSamplesPerSec = sh->samplerate;
- sh->wf->nAvgBytesPerSec = bitrate;
+ sh->wf->nAvgBytesPerSec = bitrate/8;
sh->wf->nBlockAlign = frame_size;
sh->wf->cbSize = 0;
sh->format = MKTAG(buf[0], buf[1], buf[2], buf[3]);
-#if 0
- switch (sh->format){
- case MKTAG('d', 'n', 'e', 't'):
- mp_msg(MSGT_DEMUX,MSGL_V,"Audio: DNET (AC3 with low-bitrate extension)\n");
- break;
- case MKTAG('s', 'i', 'p', 'r'):
- mp_msg(MSGT_DEMUX,MSGL_V,"Audio: SiproLab's ACELP.net\n");
- break;
- case MKTAG('c', 'o', 'o', 'k'):
- mp_msg(MSGT_DEMUX,MSGL_V,"Audio: Real's GeneralCooker (?) (RealAudio G2?) (unsupported)\n");
- break;
- case MKTAG('a', 't', 'r', 'c'):
- mp_msg(MSGT_DEMUX,MSGL_V,"Audio: Sony ATRAC3 (RealAudio 8) (unsupported)\n");
- break;
- default:
- mp_msg(MSGT_DEMUX,MSGL_V,"Audio: Unknown (%s)\n", buf);
- }
-#endif
-
switch (sh->format)
{
case MKTAG('d', 'n', 'e', 't'):
@@ -1291,74 +1376,40 @@ static demuxer_t* demux_open_real(demuxer_t* demuxer)
// sh->format = 0x2000;
break;
case MKTAG('1', '4', '_', '4'):
- sh->wf->cbSize = 10;
- sh->wf = realloc(sh->wf, sizeof(WAVEFORMATEX)+sh->wf->cbSize);
- ((short*)(sh->wf+1))[0]=0;
- ((short*)(sh->wf+1))[1]=240;
- ((short*)(sh->wf+1))[2]=0;
- ((short*)(sh->wf+1))[3]=0x14;
- ((short*)(sh->wf+1))[4]=0;
+ sh->wf->nBlockAlign = 0x14;
break;
case MKTAG('2', '8', '_', '8'):
- sh->wf->cbSize = 10;
- sh->wf = realloc(sh->wf, sizeof(WAVEFORMATEX)+sh->wf->cbSize);
- ((short*)(sh->wf+1))[0]=sub_packet_size;
- ((short*)(sh->wf+1))[1]=sub_packet_h;
- ((short*)(sh->wf+1))[2]=flavor;
- ((short*)(sh->wf+1))[3]=coded_frame_size;
- ((short*)(sh->wf+1))[4]=0;
+ sh->wf->nBlockAlign = coded_frame_size;
+ priv->sub_packet_size[stream_id] = sub_packet_size;
+ priv->sub_packet_h[stream_id] = sub_packet_h;
+ priv->coded_framesize[stream_id] = coded_frame_size;
+ priv->audiopk_size[stream_id] = frame_size;
break;
case MKTAG('s', 'i', 'p', 'r'):
-#if 0
- sh->format = 0x130;
- /* for buggy directshow loader */
- sh->wf->cbSize = 4;
- sh->wf = realloc(sh->wf, sizeof(WAVEFORMATEX)+sh->wf->cbSize);
- sh->wf->wBitsPerSample = 0;
- sh->wf->nAvgBytesPerSec = 1055;
- sh->wf->nBlockAlign = 19;
-// sh->wf->nBlockAlign = frame_size / 288;
- 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;
-#endif
case MKTAG('a', 't', 'r', 'c'):
-#if 0
- sh->format = 0x270;
- /* 14 bytes extra header needed ! */
- sh->wf->cbSize = 14;
- sh->wf = realloc(sh->wf, sizeof(WAVEFORMATEX)+sh->wf->cbSize);
- sh->wf->nAvgBytesPerSec = 16537; // 8268
- sh->wf->nBlockAlign = 384; // 192
- sh->wf->wBitsPerSample = 0; /* from AVI created by VirtualDub */
- break;
-#endif
case MKTAG('c', 'o', 'o', 'k'):
// realaudio codec plugins - common:
-// sh->wf->cbSize = 4+2+24;
stream_skip(demuxer->stream,3); // Skip 3 unknown bytes
if (version==5)
stream_skip(demuxer->stream,1); // Skip 1 additional unknown byte
codecdata_length=stream_read_dword(demuxer->stream);
- sh->wf->cbSize = 10+codecdata_length;
+ sh->wf->cbSize = codecdata_length;
sh->wf = realloc(sh->wf, sizeof(WAVEFORMATEX)+sh->wf->cbSize);
- ((short*)(sh->wf+1))[0]=sub_packet_size;
- ((short*)(sh->wf+1))[1]=sub_packet_h;
- ((short*)(sh->wf+1))[2]=flavor;
- ((short*)(sh->wf+1))[3]=coded_frame_size;
- ((short*)(sh->wf+1))[4]=codecdata_length;
-// stream_read(demuxer->stream, ((char*)(sh->wf+1))+6, 24); // extras
- stream_read(demuxer->stream, ((char*)(sh->wf+1))+10, codecdata_length); // extras
+ stream_read(demuxer->stream, ((char*)(sh->wf+1)), codecdata_length); // extras
+ if ((sh->format == MKTAG('a', 't', 'r', 'c')) ||
+ (sh->format == MKTAG('c', 'o', 'o', 'k')))
+ sh->wf->nBlockAlign = sub_packet_size;
+ else
+ sh->wf->nBlockAlign = coded_frame_size;
+
+ priv->sub_packet_size[stream_id] = sub_packet_size;
+ priv->sub_packet_h[stream_id] = sub_packet_h;
+ priv->coded_framesize[stream_id] = coded_frame_size;
+ priv->audiopk_size[stream_id] = frame_size;
break;
+
case MKTAG('r', 'a', 'a', 'c'):
case MKTAG('r', 'a', 'c', 'p'):
/* This is just AAC. The two or five bytes of */
@@ -1397,6 +1448,7 @@ static demuxer_t* demux_open_real(demuxer_t* demuxer)
demuxer->audio->id=stream_id;
sh->ds=demuxer->audio;
demuxer->audio->sh=sh;
+ priv->audio_buf = malloc(priv->sub_packet_h[demuxer->audio->id] * priv->audiopk_size[demuxer->audio->id]);
}
++a_streams;