diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/demuxers/demux_real.c | 501 |
1 files changed, 245 insertions, 256 deletions
diff --git a/src/demuxers/demux_real.c b/src/demuxers/demux_real.c index b8bdc65a7..789b942c4 100644 --- a/src/demuxers/demux_real.c +++ b/src/demuxers/demux_real.c @@ -28,7 +28,7 @@ * * Based on FFmpeg's libav/rm.c. * - * $Id: demux_real.c,v 1.57 2003/06/16 16:42:51 holstsn Exp $ + * $Id: demux_real.c,v 1.58 2003/06/20 21:22:41 jstembridge Exp $ */ #ifdef HAVE_CONFIG_H @@ -64,6 +64,8 @@ #define CONT_TAG FOURCC_TAG('C', 'O', 'N', 'T') #define DATA_TAG FOURCC_TAG('D', 'A', 'T', 'A') #define INDX_TAG FOURCC_TAG('I', 'N', 'D', 'X') +#define RA_TAG FOURCC_TAG('.', 'r', 'a', 0xfd) +#define VIDO_TAG FOURCC_TAG('V', 'I', 'D', 'O') #define PREAMBLE_SIZE 8 #define REAL_SIGNATURE_SIZE 4 @@ -74,15 +76,27 @@ #define PN_KEYFRAME_FLAG 0x0002 -#define MAX_STREAMS 10 +#define MAX_VIDEO_STREAMS 8 +#define MAX_AUDIO_STREAMS 8 typedef struct { - int stream; - int64_t offset; - unsigned int size; - int64_t pts; - int keyframe; -} real_packet; + uint16_t object_version; + + uint16_t stream_number; + uint32_t max_bit_rate; + uint32_t avg_bit_rate; + uint32_t max_packet_size; + uint32_t avg_packet_size; + uint32_t start_time; + uint32_t preroll; + uint32_t duration; + char stream_name_size; + char *stream_name; + char mime_type_size; + char *mime_type; + uint32_t type_specific_len; + char *type_specific_data; +} mdpr_t; typedef struct { unsigned int timestamp; @@ -91,6 +105,16 @@ typedef struct { } real_index_entry_t; typedef struct { + uint32_t fourcc; + uint32_t buf_type; + + real_index_entry_t *index; + int index_entries; + + mdpr_t *mdpr; +} real_stream_t; + +typedef struct { demux_plugin_t demux_plugin; @@ -111,15 +135,13 @@ typedef struct { unsigned int packet_count; unsigned int current_packet; - int video_stream_num; - uint32_t video_buf_type; - real_index_entry_t *video_index; - int video_index_entries; - - int audio_stream_num; - uint32_t audio_buf_type; - real_index_entry_t *audio_index; - int audio_index_entries; + real_stream_t video_streams[MAX_VIDEO_STREAMS]; + int num_video_streams; + real_stream_t *video_stream; + + real_stream_t audio_streams[MAX_AUDIO_STREAMS]; + int num_audio_streams; + real_stream_t *audio_stream; int audio_need_keyframe; unsigned int current_data_chunk_packet_count; @@ -151,26 +173,6 @@ typedef struct { config_values_t *config; } demux_real_class_t; -typedef struct { - - uint16_t object_version; - - uint16_t stream_number; - uint32_t max_bit_rate; - uint32_t avg_bit_rate; - uint32_t max_packet_size; - uint32_t avg_packet_size; - uint32_t start_time; - uint32_t preroll; - uint32_t duration; - char stream_name_size; - char *stream_name; - char mime_type_size; - char *mime_type; - uint32_t type_specific_len; - char *type_specific_data; - -} pnm_mdpr_t; #ifdef LOG static void hexdump (char *buf, int length) { @@ -245,26 +247,31 @@ static void real_parse_index(demux_real_t *this) { next_index_chunk = BE_32(&index_chunk_header[16]); /* Find which stream this index is for */ - if(stream_num == this->video_stream_num) { - index = &this->video_index; - this->video_index_entries = entries; + index = NULL; + for(i = 0; i < this->num_video_streams; i++) { + if(stream_num == this->video_streams[i].mdpr->stream_number) { + index = &this->video_streams[i].index; + this->video_streams[i].index_entries = entries; #ifdef LOG - printf("demux_real: found index chunk with %d entries for video stream\n", - entries); + printf("demux_real: found index chunk for video stream with num %d\n", + stream_num); #endif - } else if(stream_num == this->audio_stream_num) { - index = &this->audio_index; - this->audio_index_entries = entries; -#ifdef LOG - printf("demux_real: found index chunk with %d entries for audio stream\n", - entries); -#endif - } else { - index = NULL; + break; + } + } + + if(!index) { + for(i = 0; i < this->num_audio_streams; i++) { + if(stream_num == this->audio_streams[i].mdpr->stream_number) { + index = &this->audio_streams[i].index; + this->audio_streams[i].index_entries = entries; #ifdef LOG - printf("demux_real: found index chunk for unused stream number %d\n", - stream_num); + printf("demux_real: found index chunk for audio stream with num %d\n", + stream_num); #endif + break; + } + } } if(index && entries) { @@ -285,6 +292,9 @@ static void real_parse_index(demux_real_t *this) { (*index)[i].offset = BE_32(&index_record[6]); (*index)[i].packetno = BE_32(&index_record[10]); } + } else { + printf("demux_real: unused index chunk with %d entries for stream num %d\n", + entries, stream_num); } } else { printf("demux_real: expected index chunk found chunk type: %.4s\n", @@ -297,9 +307,9 @@ static void real_parse_index(demux_real_t *this) { this->input->seek(this->input, original_pos, SEEK_SET); } -static pnm_mdpr_t *pnm_parse_mdpr(const char *data) { +static mdpr_t *real_parse_mdpr(const char *data) { - pnm_mdpr_t *mdpr=malloc(sizeof(pnm_mdpr_t)); + mdpr_t *mdpr=malloc(sizeof(mdpr_t)); mdpr->object_version=BE_16(&data[0]); @@ -351,12 +361,12 @@ static pnm_mdpr_t *pnm_parse_mdpr(const char *data) { return mdpr; } -typedef struct dp_hdr_s { - uint32_t chunks; /* number of chunks */ - uint32_t timestamp; /* timestamp from packet header */ - uint32_t len; /* length of actual data */ - uint32_t chunktab; /* offset to chunk offset array */ -} dp_hdr_t; +static void real_free_mdpr (mdpr_t *mdpr) { + free (mdpr->stream_name); + free (mdpr->mime_type); + free (mdpr->type_specific_data); + free (mdpr); +} static void real_parse_headers (demux_real_t *this) { @@ -373,6 +383,8 @@ static void real_parse_headers (demux_real_t *this) { this->data_start = 0; this->data_size = 0; this->current_packet = 0; + this->num_video_streams = 0; + this->num_audio_streams = 0; if ((this->input->get_capabilities (this->input) & INPUT_CAP_SEEKABLE) != 0) this->input->seek (this->input, 0, SEEK_SET); @@ -451,201 +463,71 @@ static void real_parse_headers (demux_real_t *this) { } else if (chunk_type == MDPR_TAG) { - pnm_mdpr_t *mdpr; + mdpr_t *mdpr; + uint32_t fourcc; - mdpr = pnm_parse_mdpr (chunk_buffer); + mdpr = real_parse_mdpr (chunk_buffer); #ifdef LOG printf ("demux_real: parsing type specific data...\n"); #endif - if (mdpr->type_specific_len>8) { - - /* skip unknown stuff - FIXME: find a better/cleaner way */ - { - int off; - - off = 0; - - while (off<=(mdpr->type_specific_len-8)) { - -#ifdef LOG - printf ("demux_real: got %.4s\n", mdpr->type_specific_data+off); -#endif - - if (!strncmp (mdpr->type_specific_data+off, ".ra", 3)) { - int version; - char fourcc[5]; - - off += 4; - -#ifdef LOG - printf ("demux_real: audio detected %.3s\n", - mdpr->type_specific_data+off+4); -#endif - this->stream->stream_info[XINE_STREAM_INFO_AUDIO_BITRATE] = mdpr->avg_bit_rate; - - - version = BE_16 (mdpr->type_specific_data+off); - -#ifdef LOG - printf ("demux_real: audio version %d\n", version); -#endif - - if (version==4) { - int str_len; - int sample_rate; - - sample_rate = BE_16(mdpr->type_specific_data+off+44); - -#ifdef LOG - printf ("demux_real: sample_rate %d\n", sample_rate); -#endif - - str_len = *(mdpr->type_specific_data+off+52); - -#ifdef LOG - printf ("demux_real: str_len = %d\n", str_len); -#endif - - memcpy (fourcc, mdpr->type_specific_data+off+54+str_len, 4); - fourcc[4]=0; - -#ifdef LOG - printf ("demux_real: fourcc == %s\n", fourcc); -#endif - - } else if (version == 5) { - - memcpy (fourcc, mdpr->type_specific_data+off+62, 4); - fourcc[4]=0; - -#ifdef LOG - printf ("demux_real: fourcc == %s\n", fourcc); -#endif - - } else { - printf ("demux_real: error, unknown audio data header version %d\n", - version); - - free (mdpr->stream_name); - free (mdpr->mime_type); - free (mdpr->type_specific_data); - free (mdpr); - free (chunk_buffer); - - this->status = DEMUX_FINISHED; - return; - } - - this->stream->stream_info[XINE_STREAM_INFO_AUDIO_FOURCC] = *(uint32_t *)fourcc; - this->audio_buf_type = formattag_to_buf_audio(*(uint32_t *)fourcc); - -#ifdef LOG - printf ("demux_real: audio codec, buf type %08x\n", - this->audio_buf_type); -#endif + if(BE_32(mdpr->type_specific_data) == RA_TAG) { + int version; - this->audio_stream_num = mdpr->stream_number; - - if (this->audio_buf_type && this->audio_fifo) { - buf_element_t *buf; - - /* send header */ - - buf = this->audio_fifo->buffer_pool_alloc (this->audio_fifo); - - buf->content = buf->mem; - - memcpy (buf->content, mdpr->type_specific_data+off, - mdpr->type_specific_len-off); - - buf->size = mdpr->type_specific_len-off; - - buf->extra_info->input_pos = 0 ; - buf->extra_info->input_time = 0 ; - buf->type = this->audio_buf_type; - buf->decoder_flags = BUF_FLAG_HEADER; - - this->audio_fifo->put (this->audio_fifo, buf); - - } - - this->stream->stream_info[XINE_STREAM_INFO_HAS_AUDIO] = 1; - - break; /* audio */ - } - if (!strncmp (mdpr->type_specific_data+off, "VIDO", 4)) { - const char *video_fmt = (mdpr->type_specific_data + off + 4); + version = BE_16(mdpr->type_specific_data + 4); #ifdef LOG - printf ("demux_real: video detected\n"); + printf("demux_real: audio version %d detected\n", version); #endif - this->stream->stream_info[XINE_STREAM_INFO_VIDEO_BITRATE] = mdpr->avg_bit_rate; - - this->stream->stream_info[XINE_STREAM_INFO_VIDEO_FOURCC] = *(uint32_t *)video_fmt; - - this->video_buf_type = fourcc_to_buf_video(*(uint32_t *)video_fmt); - - if( this->video_buf_type ) { - this->video_stream_num = mdpr->stream_number; - this->stream->stream_info[XINE_STREAM_INFO_HAS_VIDEO] = 1; - } else { - printf("demux_real: video codec [%c%c%c%c] not recognized\n", - video_fmt[0],video_fmt[1],video_fmt[2],video_fmt[3]); - } + if(version == 4) { + int str_len; - if ( this->stream->stream_info[XINE_STREAM_INFO_HAS_VIDEO] ) { - buf_element_t *buf; + str_len = *(mdpr->type_specific_data + 56); + fourcc = *(uint32_t *) (mdpr->type_specific_data + 58 + str_len); + } else if(version == 5) { + fourcc = *(uint32_t *) (mdpr->type_specific_data + 66); + } else { + printf("demux_real: unsupported audio header version %d\n", version); - buf = this->video_fifo->buffer_pool_alloc(this->video_fifo); - - buf->content = buf->mem; - - if (this->video_buf_type == BUF_VIDEO_RV10) { - xine_bmiheader bih; + goto unknown; + } - memcpy(&bih.biWidth, mdpr->type_specific_data+off+8, 2); - memcpy(&bih.biHeight, mdpr->type_specific_data+off+10, 2); - memcpy(&bih.biCompression, mdpr->type_specific_data+off+26, 4); - bih.biWidth=bswap_16(bih.biWidth); - bih.biHeight=bswap_16(bih.biHeight); - bih.biCompression=bswap_32(bih.biCompression); - bih.biSize=sizeof(bih); #ifdef LOG - printf("demux_real: setting size to w:%u h:%u for RV10\n", bih.biWidth, bih.biHeight); - printf("demux_real: setting sub-codec to %X for RV10\n", bih.biCompression); + printf("demux_real: fourcc = %.4s\n", (char *) &fourcc); #endif - memcpy(buf->content, &bih, bih.biSize); - - - } else { - memcpy(buf->content, mdpr->type_specific_data, - mdpr->type_specific_len); - buf->size = mdpr->type_specific_len; - } + this->audio_streams[this->num_audio_streams].fourcc = fourcc; + this->audio_streams[this->num_audio_streams].buf_type = formattag_to_buf_audio(fourcc); + this->audio_streams[this->num_audio_streams].index = NULL; + this->audio_streams[this->num_audio_streams].mdpr = mdpr; - buf->type = this->video_buf_type; - buf->decoder_flags = BUF_FLAG_HEADER; - buf->extra_info->input_pos = 0; - buf->extra_info->input_time = 0; + this->num_audio_streams++; - this->video_fifo->put (this->video_fifo, buf); - } + } else if(BE_32(mdpr->type_specific_data + 4) == VIDO_TAG) { +#ifdef LOG + printf ("demux_real: video detected\n"); +#endif + + fourcc = *(uint32_t *) (mdpr->type_specific_data + 8); +#ifdef LOG + printf("demux_real: fourcc = %.4s\n", (char *) &fourcc); +#endif - break; /* video */ - } - off++; - } /* while */ - } + this->video_streams[this->num_video_streams].fourcc = fourcc; + this->video_streams[this->num_video_streams].buf_type = fourcc_to_buf_video(fourcc); + this->video_streams[this->num_video_streams].index = NULL; + this->video_streams[this->num_video_streams].mdpr = mdpr; - } + this->num_video_streams++; - free (mdpr->stream_name); - free (mdpr->mime_type); - free (mdpr->type_specific_data); - free (mdpr); + } else { +#ifdef LOG + printf("demux_real: unrecognised type specific data\n"); +#endif +unknown: + real_free_mdpr(mdpr); + } } else if (chunk_type == CONT_TAG) { @@ -721,8 +603,105 @@ static void real_parse_headers (demux_real_t *this) { } } + /* Read index tables */ if((this->input->get_capabilities (this->input) & INPUT_CAP_SEEKABLE) != 0) real_parse_index(this); + + /* Select audio and video stream to play */ + if(this->num_video_streams == 1) + this->video_stream = &this->video_streams[0]; + else if(this->num_video_streams) { + /* FIXME: Determine which stream to play */ + printf("demux_real: multiple video streams not supported\n"); + this->status = DEMUX_FINISHED; + return; + } else + this->video_stream = NULL; + + if(this->num_audio_streams == 1) + this->audio_stream = &this->audio_streams[0]; + else if(this->num_audio_streams) { + /* FIXME: Determine which stream to play */ + printf("demux_real: multiple audio streams not supported\n"); + this->status = DEMUX_FINISHED; + return; + } else + this->audio_stream = NULL; + + /* Send headers and set meta info */ + if(this->video_stream) { + buf_element_t *buf; + + /* Send header */ + buf = this->video_fifo->buffer_pool_alloc(this->video_fifo); + buf->content = buf->mem; + + if(this->video_stream->buf_type == BUF_VIDEO_RV10) { + xine_bmiheader bih; + + bih.biWidth = BE_16(this->video_stream->mdpr->type_specific_data + 12); + bih.biHeight = BE_16(this->video_stream->mdpr->type_specific_data + 14); + bih.biCompression = BE_32(this->video_stream->mdpr->type_specific_data + 30); + bih.biSize = sizeof(bih); + +#ifdef LOG + printf("demux_real: setting size to w:%u h:%u for RV10\n", + bih.biWidth, bih.biHeight); + printf("demux_real: setting sub-codec to %X for RV10\n", + bih.biCompression); +#endif + memcpy(buf->content, &bih, bih.biSize); + } else { + memcpy(buf->content, this->video_stream->mdpr->type_specific_data, + this->video_stream->mdpr->type_specific_len); + + buf->size = this->video_stream->mdpr->type_specific_len; + } + + buf->type = this->video_stream->buf_type; + buf->decoder_flags = BUF_FLAG_HEADER; + buf->extra_info->input_pos = 0; + buf->extra_info->input_time = 0; + + this->video_fifo->put (this->video_fifo, buf); + + /* Set meta info */ + this->stream->stream_info[XINE_STREAM_INFO_HAS_VIDEO] = 1; + this->stream->stream_info[XINE_STREAM_INFO_VIDEO_FOURCC] = + this->video_stream->fourcc; + this->stream->stream_info[XINE_STREAM_INFO_VIDEO_BITRATE] = + this->video_stream->mdpr->avg_bit_rate; + } + + if(this->audio_stream) { + /* Send headers */ + if(this->audio_fifo) { + buf_element_t *buf; + + buf = this->audio_fifo->buffer_pool_alloc (this->audio_fifo); + buf->content = buf->mem; + + memcpy(buf->content, + this->audio_stream->mdpr->type_specific_data + 4, + this->audio_stream->mdpr->type_specific_len - 4); + + buf->size = this->audio_stream->mdpr->type_specific_len - 4; + + buf->type = this->audio_stream->buf_type; + buf->decoder_flags = BUF_FLAG_HEADER; + buf->extra_info->input_pos = 0; + buf->extra_info->input_time = 0; + + this->audio_fifo->put (this->audio_fifo, buf); + } + + /* Set meta info */ + this->stream->stream_info[XINE_STREAM_INFO_HAS_AUDIO] = 1; + this->stream->stream_info[XINE_STREAM_INFO_AUDIO_FOURCC] = + this->audio_stream->fourcc; + this->stream->stream_info[XINE_STREAM_INFO_AUDIO_BITRATE] = + this->audio_stream->mdpr->avg_bit_rate; + } } @@ -881,7 +860,7 @@ static int demux_real_send_chunk(demux_plugin_t *this_gen) { stream, size, offset, pts, keyframe ? ", keyframe" : ""); #endif - if (stream == this->video_stream_num) { + if (this->video_stream && (stream == this->video_stream->mdpr->stream_number)) { int vpkg_header, vpkg_length, vpkg_offset; int vpkg_seqnum = -1; @@ -986,7 +965,7 @@ static int demux_real_send_chunk(demux_plugin_t *this_gen) { buf->extra_info->input_time = (int)((int64_t)buf->extra_info->input_pos * 8 * 1000 / this->avg_bitrate); - buf->type = this->video_buf_type; + buf->type = this->video_stream->buf_type; check_newpts (this, pts, PTS_VIDEO, 0); @@ -1055,7 +1034,8 @@ static int demux_real_send_chunk(demux_plugin_t *this_gen) { } /* while(size>2) */ - } else if (stream == this->audio_stream_num && this->audio_fifo) { + } else if (this->audio_fifo && this->audio_stream && + (stream == this->audio_stream->mdpr->stream_number)) { buf_element_t *buf; int n; @@ -1076,7 +1056,7 @@ static int demux_real_send_chunk(demux_plugin_t *this_gen) { buf->extra_info->input_pos = this->input->get_current_pos (this->input); buf->extra_info->input_time = (int)((int64_t)buf->extra_info->input_pos * 8 * 1000 / this->avg_bitrate); - buf->type = this->audio_buf_type; + buf->type = this->audio_stream->buf_type; buf->decoder_flags = 0; buf->size = size; @@ -1183,9 +1163,6 @@ static void demux_real_send_headers(demux_plugin_t *this_gen) { this->stream->stream_info[XINE_STREAM_INFO_HAS_VIDEO] = 0; this->stream->stream_info[XINE_STREAM_INFO_HAS_AUDIO] = 0; - this->video_stream_num = -1; - this->audio_stream_num = -1; - if( !this->reference_mode ) { real_parse_headers (this); } else { @@ -1198,25 +1175,28 @@ static int demux_real_seek (demux_plugin_t *this_gen, off_t start_pos, int start_time) { demux_real_t *this = (demux_real_t *) this_gen; - real_index_entry_t *index, *other_index; + real_index_entry_t *index, *other_index = NULL; int i = 0, entries; if((this->input->get_capabilities(this->input) & INPUT_CAP_SEEKABLE) && - (this->audio_index || this->video_index)) { + ((this->audio_stream && this->audio_stream->index) || + (this->video_stream && this->video_stream->index))) { /* video index has priority over audio index */ - if(this->video_index) { - index = this->video_index; - entries = this->video_index_entries; - other_index = this->audio_index; + if(this->video_stream && this->video_stream->index) { + index = this->video_stream->index; + entries = this->video_stream->index_entries; + if(this->audio_stream) + other_index = this->audio_stream->index; /* when seeking by video index the first audio chunk won't necesserily * be a keyframe which would upset the decoder */ this->audio_need_keyframe = 1; } else { - index = this->audio_index; - entries = this->audio_index_entries; - other_index = this->video_index; + index = this->audio_stream->index; + entries = this->audio_stream->index_entries; + if(this->video_stream) + other_index = this->video_stream->index; } if(start_pos) { @@ -1253,13 +1233,22 @@ static int demux_real_seek (demux_plugin_t *this_gen, static void demux_real_dispose (demux_plugin_t *this_gen) { + int i; + demux_real_t *this = (demux_real_t *) this_gen; - if(this->video_index) - free(this->video_index); - if(this->audio_index) - free(this->audio_index); - + for(i = 0; i < this->num_video_streams; i++) { + real_free_mdpr(this->video_streams[i].mdpr); + if(this->video_streams[i].index) + free(this->video_streams[i].index); + } + + for(i = 0; i < this->num_audio_streams; i++) { + real_free_mdpr(this->audio_streams[i].mdpr); + if(this->audio_streams[i].index) + free(this->audio_streams[i].index); + } + free(this); } |