diff options
author | Jinghua Luo <sunmoon1997@gmail.com> | 2008-04-07 17:27:49 +0100 |
---|---|---|
committer | Jinghua Luo <sunmoon1997@gmail.com> | 2008-04-07 17:27:49 +0100 |
commit | d3bb60048b4ff30adc379f5e1eab62db8354db8b (patch) | |
tree | 527a2eb2c04e7662e992ce9bf97f450a0ad62a4f /src/demuxers | |
parent | aae81ebc2ba5f815d8cc153b1edabb70fda440ca (diff) | |
download | xine-lib-d3bb60048b4ff30adc379f5e1eab62db8354db8b.tar.gz xine-lib-d3bb60048b4ff30adc379f5e1eab62db8354db8b.tar.bz2 |
Use ffmpeg's cook decoder and fix Real decoder bugs
This patch drops support for RV20.
Diffstat (limited to 'src/demuxers')
-rw-r--r-- | src/demuxers/demux_real.c | 170 | ||||
-rw-r--r-- | src/demuxers/demux_realaudio.c | 114 |
2 files changed, 274 insertions, 10 deletions
diff --git a/src/demuxers/demux_real.c b/src/demuxers/demux_real.c index 60075d750..f0724a992 100644 --- a/src/demuxers/demux_real.c +++ b/src/demuxers/demux_real.c @@ -113,6 +113,12 @@ typedef struct { int index_entries; mdpr_t *mdpr; + int sps, cfs, w, h; + int block_align; + int frame_size; + uint8_t *frame_buffer; + uint32_t frame_num_bytes; + uint32_t sub_packet_cnt; } real_stream_t; typedef struct { @@ -168,6 +174,12 @@ typedef struct { demux_class_t demux_class; } demux_real_class_t; +static const 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}}; static void real_parse_index(demux_real_t *this) { @@ -316,6 +328,64 @@ static void real_free_mdpr (mdpr_t *mdpr) { free (mdpr); } +static void real_parse_audio_specific_data (demux_real_t *this, + real_stream_t * stream, + uint8_t * data, int len) +{ + int coded_frame_size; + int codec_data_length; + int coded_frame_size2; + int subpacket_size; + + coded_frame_size = _X_BE_32 (data+24); + codec_data_length = _X_BE_16 (data+40); + coded_frame_size2 = _X_BE_16 (data+42); + subpacket_size = _X_BE_16 (data+44); + + stream->sps = subpacket_size; + stream->w = coded_frame_size2; + stream->h = codec_data_length; + stream->block_align = coded_frame_size2; + stream->cfs = coded_frame_size; + + switch (stream->buf_type) { + case BUF_AUDIO_COOK: + case BUF_AUDIO_ATRK: + stream->block_align = subpacket_size; + break; + + case BUF_AUDIO_14_4: + break; + + case BUF_AUDIO_28_8: + stream->block_align = stream->cfs; + break; + + case BUF_AUDIO_SIPRO: + /* this->block_align = 19; */ + break; + + default: + xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, + "demux_real: error, i don't handle buf type 0x%08x\n", stream->buf_type); + } + + if (stream->sps) { + stream->frame_size = stream->w / stream->sps * stream->h * stream->sps; + stream->frame_buffer = xine_xmalloc (stream->frame_size); + stream->frame_num_bytes = 0; + } else { + stream->frame_size = stream->w * stream->h; + stream->frame_buffer = xine_xmalloc (stream->frame_size); + stream->frame_num_bytes = 0; + } + stream->sub_packet_cnt = 0; + + xprintf (this->stream->xine, XINE_VERBOSITY_LOG, + "demux_real: buf type 0x%08x frame size %dblock align %d\n", stream->buf_type, + stream->frame_size, stream->block_align); + +} static void real_parse_headers (demux_real_t *this) { @@ -426,8 +496,16 @@ static void real_parse_headers (demux_real_t *this) { mdpr = real_parse_mdpr (chunk_buffer); lprintf ("parsing type specific data...\n"); + if(!strcmp(mdpr->mime_type, "audio/X-MP3-draft-00")) { + lprintf ("mpeg layer 3 audio detected...\n"); - if(_X_BE_32(mdpr->type_specific_data) == RA_TAG) { + fourcc = ME_FOURCC('a', 'd', 'u', 0x55); + this->audio_streams[this->num_audio_streams].fourcc = fourcc; + this->audio_streams[this->num_audio_streams].buf_type = _x_formattag_to_buf_audio(fourcc); + this->audio_streams[this->num_audio_streams].index = NULL; + this->audio_streams[this->num_audio_streams].mdpr = mdpr; + this->num_audio_streams++; + } else if(_X_BE_32(mdpr->type_specific_data) == RA_TAG) { int version, len; if(this->num_audio_streams == MAX_AUDIO_STREAMS) { @@ -465,6 +543,10 @@ static void real_parse_headers (demux_real_t *this) { this->audio_streams[this->num_audio_streams].index = NULL; this->audio_streams[this->num_audio_streams].mdpr = mdpr; + real_parse_audio_specific_data (this, + &this->audio_streams[this->num_audio_streams], + mdpr->type_specific_data, + mdpr->type_specific_len); this->num_audio_streams++; } else if(_X_BE_32(mdpr->type_specific_data + 4) == VIDO_TAG) { @@ -985,6 +1067,7 @@ static int demux_real_send_chunk(demux_plugin_t *this_gen) { off_t offset, input_length = 0; int normpos = 0; + read_next_packet: if(this->reference_mode) return demux_real_parse_references(this); @@ -1322,6 +1405,86 @@ static int demux_real_send_chunk(demux_plugin_t *this_gen) { } free(sizes); + } else if (this->audio_stream->buf_type == BUF_AUDIO_COOK || + this->audio_stream->buf_type == BUF_AUDIO_ATRK || + this->audio_stream->buf_type == BUF_AUDIO_28_8 || + this->audio_stream->buf_type == BUF_AUDIO_SIPRO) { + /* reorder */ + uint8_t * buffer = this->audio_stream->frame_buffer; + int sps = this->audio_stream->sps; + int sph = this->audio_stream->h; + int cfs = this->audio_stream->cfs; + int w = this->audio_stream->w; + int spc = this->audio_stream->sub_packet_cnt; + int x, pos; + + switch (this->audio_stream->buf_type) { + case BUF_AUDIO_28_8: + for (x = 0; x < sph / 2; x++) { + pos = x * 2 * w + spc * cfs; + if(this->input->read(this->input, buffer + pos, cfs) < cfs) { + xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, + "demux_real: failed to read audio chunk\n"); + + this->status = DEMUX_FINISHED; + return this->status; + } + } + break; + case BUF_AUDIO_COOK: + case BUF_AUDIO_ATRK: + for (x = 0; x < w / sps; x++) { + pos = sps * (sph * x + ((sph + 1) / 2) * (spc & 1) + (spc >> 1)); + if(this->input->read(this->input, buffer + pos, sps) < sps) { + xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, + "demux_real: failed to read audio chunk\n"); + + this->status = DEMUX_FINISHED; + return this->status; + } + } + break; + case BUF_AUDIO_SIPRO: + pos = spc * w; + if(this->input->read(this->input, buffer + pos, w) < w) { + xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, + "demux_real: failed to read audio chunk\n"); + + this->status = DEMUX_FINISHED; + return this->status; + } + 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) ? (buffer[i >> 1] >> 4) : (buffer[i >> 1] & 0x0F); + int y = (o & 1) ? (buffer[o >> 1] >> 4) : (buffer[o >> 1] & 0x0F); + if(o & 1) + buffer[o >> 1] = (buffer[o >> 1] & 0x0F) | (x << 4); + else + buffer[o >> 1] = (buffer[o >> 1] & 0xF0) | x; + if(i & 1) + buffer[i >> 1] = (buffer[i >> 1] & 0x0F) | (y << 4); + else + buffer[i >> 1] = (buffer[i >> 1] & 0xF0) | y; + ++i; ++o; + } + } + } + break; + } + if(++this->audio_stream->sub_packet_cnt == sph) { + this->audio_stream->sub_packet_cnt = 0; + _x_demux_send_data(this->audio_fifo, buffer, this->audio_stream->frame_size, + pts, this->audio_stream->buf_type, 0, normpos, input_time, + this->duration, 0); + } } else { if(_x_demux_read_send_data(this->audio_fifo, this->input, size, pts, this->audio_stream->buf_type, 0, normpos, @@ -1471,6 +1634,9 @@ static int demux_real_seek (demux_plugin_t *this_gen, this->input->seek(this->input, index[i].offset, SEEK_SET); if(playing) { + if(this->audio_stream) + this->audio_stream->sub_packet_cnt = 0; + this->buf_flag_seek = 1; _x_demux_flush_engine(this->stream); } @@ -1509,6 +1675,8 @@ static void demux_real_dispose (demux_plugin_t *this_gen) { real_free_mdpr(this->audio_streams[i].mdpr); if(this->audio_streams[i].index) free(this->audio_streams[i].index); + if(this->audio_streams[i].frame_buffer) + free(this->audio_streams[i].frame_buffer); } if(this->fragment_tab) diff --git a/src/demuxers/demux_realaudio.c b/src/demuxers/demux_realaudio.c index b663912b8..2075f1b6f 100644 --- a/src/demuxers/demux_realaudio.c +++ b/src/demuxers/demux_realaudio.c @@ -62,6 +62,10 @@ typedef struct { off_t data_start; off_t data_size; + int sps, cfs, w, h; + int frame_size; + uint8_t *frame_buffer; + unsigned char *header; unsigned int header_size; } demux_ra_t; @@ -70,6 +74,16 @@ typedef struct { demux_class_t demux_class; } demux_ra_class_t; +static const 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}}; + +/* Map flavour to bytes per second */ +static int sipr_fl2bps[4] = {813, 1062, 625, 2000}; // 6.5, 8.5, 5, 16 kbit per second + /* returns 1 if the RealAudio file was opened successfully, 0 otherwise */ static int open_ra_file(demux_ra_t *this) { unsigned char file_header[RA_FILE_HEADER_PREV_SIZE], len; @@ -165,20 +179,41 @@ static int open_ra_file(demux_ra_t *this) { offset++; /* Fourcc for version 3 comes after meta info */ - if((version == 3) && ((offset+7) <= this->header_size)) { - if(this->header[offset+2] == 4) - this->fourcc = _X_ME_32(&this->header[offset+3]); - else { - xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, - "demux_realaudio: invalid fourcc size %d\n", this->header[offset+2]); - free(this->header); - return 0; + if(version == 3) { + if (((offset+7) <= this->header_size)) { + if(this->header[offset+2] == 4) + this->fourcc = _X_ME_32(&this->header[offset+3]); + else { + xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, + "demux_realaudio: invalid fourcc size %d\n", this->header[offset+2]); + free(this->header); + return 0; + } + } else { + this->fourcc = ME_FOURCC('l', 'p', 'c', 'J'); } } _x_stream_info_set(this->stream, XINE_STREAM_INFO_AUDIO_FOURCC, this->fourcc); this->audio_type = _x_formattag_to_buf_audio(this->fourcc); + if (version == 4) { + this->sps = _X_BE_16 (this->header+44); + this->w = _X_BE_16 (this->header+42); + this->h = _X_BE_16 (this->header+40); + this->cfs = _X_BE_32 (this->header+24); + if (this->sps) { + this->frame_size = this->sps * this->h * this->sps; + this->frame_buffer = xine_xmalloc (this->frame_size); + } else { + this->frame_size = this->w * this->h; + this->frame_buffer = xine_xmalloc (this->frame_size); + } + + if (this->audio_type == BUF_AUDIO_28_8 || this->audio_type == BUF_AUDIO_SIPRO) + this->block_align = this->cfs; + } + /* seek to start of data */ this->data_start = this->header_size; if (this->input->seek(this->input, this->data_start, SEEK_SET) != @@ -212,7 +247,65 @@ static int demux_ra_send_chunk(demux_plugin_t *this_gen) { this->seek_flag = 0; } - if(_x_demux_read_send_data(this->audio_fifo, this->input, this->block_align, + if (this->audio_type == BUF_AUDIO_28_8 || this->audio_type == BUF_AUDIO_SIPRO) { + int x; + uint8_t * buffer; + + buffer = this->frame_buffer; + if (this->audio_type == BUF_AUDIO_SIPRO) { + int n; + int len = this->h * this->w; + int bs = len * 2 / 96; /* nibbles per subpacket */ + if(this->input->read(this->input, this->frame_buffer, len) < len) { + xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, + "demux_realaudio: failed to read audio chunk\n"); + + this->status = DEMUX_FINISHED; + return this->status; + } + /* 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) ? (this->frame_buffer[i >> 1] >> 4) : (this->frame_buffer[i >> 1] & 0x0F); + int y = (o & 1) ? (this->frame_buffer[o >> 1] >> 4) : (this->frame_buffer[o >> 1] & 0x0F); + if(o & 1) + this->frame_buffer[o >> 1] = (this->frame_buffer[o >> 1] & 0x0F) | (x << 4); + else + this->frame_buffer[o >> 1] = (this->frame_buffer[o >> 1] & 0xF0) | x; + if(i & 1) + this->frame_buffer[i >> 1] = (this->frame_buffer[i >> 1] & 0x0F) | (y << 4); + else + this->frame_buffer[i >> 1] = (this->frame_buffer[i >> 1] & 0xF0) | y; + ++i; ++o; + } + } + } else { + int x, y; + int pos; + + for (y = 0; y < this->h; y++) + for (x = 0; x < this->h / 2; x++) { + pos = x * 2 * this->w + y * this->cfs; + if(this->input->read(this->input, this->frame_buffer + pos, + this->cfs) < this->cfs) { + xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, + "demux_realaudio: failed to read audio chunk\n"); + + this->status = DEMUX_FINISHED; + return this->status; + } + } + } + + _x_demux_send_data(this->audio_fifo, + buffer, this->frame_size, + current_pts, this->audio_type, 0, + current_normpos, current_pts / 90, 0, 0); + } else if(_x_demux_read_send_data(this->audio_fifo, this->input, this->block_align, current_pts, this->audio_type, 0, current_normpos, current_pts / 90, 0, 0) < 0) { this->status = DEMUX_FINISHED; @@ -299,6 +392,8 @@ static void demux_ra_dispose (demux_plugin_t *this_gen) { if(this->header) free(this->header); + if (this->frame_buffer) + free(this->frame_buffer); free(this); } @@ -333,6 +428,7 @@ static demux_plugin_t *open_plugin (demux_class_t *class_gen, xine_stream_t *str this = xine_xmalloc (sizeof (demux_ra_t)); this->stream = stream; this->input = input; + this->frame_buffer = NULL; this->demux_plugin.send_headers = demux_ra_send_headers; this->demux_plugin.send_chunk = demux_ra_send_chunk; |