Mercurial > mplayer.hg
changeset 14402:53a70339c70c
Real multirate files support
author | rtognimp |
---|---|
date | Thu, 06 Jan 2005 16:29:46 +0000 |
parents | ddf3ac9a7539 |
children | 5dac1eeb8d6b |
files | libmpdemux/demux_real.c |
diffstat | 1 files changed, 232 insertions(+), 28 deletions(-) [+] |
line wrap: on
line diff
--- a/libmpdemux/demux_real.c Thu Jan 06 16:24:58 2005 +0000 +++ b/libmpdemux/demux_real.c Thu Jan 06 16:29:46 2005 +0000 @@ -77,6 +77,21 @@ // int a_streams[MAX_STREAMS]; // int last_v_stream; // int v_streams[MAX_STREAMS]; + + /** + * Used to demux multirate files + */ + int is_multirate; ///< != 0 for multirate files + int str_data_offset[MAX_STREAMS]; ///< Data chunk offset for every audio/video stream + int audio_curpos; ///< Current file position for audio demuxing + int video_curpos; ///< Current file position for video demuxing + int a_num_of_packets; ///< Number of audio packets + int v_num_of_packets; ///< Number of video packets + int a_idx_ptr; ///< Audio index position pointer + int v_idx_ptr; ///< Video index position pointer + int a_bitrate; ///< Audio bitrate + int v_bitrate; ///< Video bitrate + int stream_switch; ///< Flag used to switch audio/video demuxing } real_priv_t; /* originally from FFmpeg */ @@ -514,11 +529,33 @@ while(1){ + /* Handle audio/video demxing switch for multirate files (non-interleaved) */ + if (priv->is_multirate && priv->stream_switch) { + if (priv->a_idx_ptr >= priv->index_table_size[demuxer->audio->id]) + demuxer->audio->eof = 1; + if (priv->v_idx_ptr >= priv->index_table_size[demuxer->video->id]) + demuxer->video->eof = 1; + if (demuxer->audio->eof && demuxer->video->eof) + return 0; + else if (!demuxer->audio->eof && demuxer->video->eof) + stream_seek(demuxer->stream, priv->audio_curpos); // Get audio + else if (demuxer->audio->eof && !demuxer->video->eof) + stream_seek(demuxer->stream, priv->video_curpos); // Get video + else if (priv->index_table[demuxer->audio->id][priv->a_idx_ptr].timestamp < + priv->index_table[demuxer->video->id][priv->v_idx_ptr].timestamp) + stream_seek(demuxer->stream, priv->audio_curpos); // Get audio + else + stream_seek(demuxer->stream, priv->video_curpos); // Get video + priv->stream_switch = 0; + } + demuxer->filepos = stream_tell(demuxer->stream); version = stream_read_word(demuxer->stream); /* version */ len = stream_read_word(demuxer->stream); if ((version==0x4441) && (len==0x5441)) { // new data chunk mp_msg(MSGT_DEMUX,MSGL_INFO,"demux_real: New data chunk is coming!!!\n"); + if (priv->is_multirate) + return 0; // EOF stream_skip(demuxer->stream,14); demuxer->filepos = stream_tell(demuxer->stream); version = stream_read_word(demuxer->stream); /* version */ @@ -548,6 +585,13 @@ /* 0x1 - reliable */ /* 0x2 - keyframe */ + if (version == 1) { + int tmp; + tmp = stream_read_char(demuxer->stream); + mp_msg(MSGT_DEMUX, MSGL_DBG2,"Version: %d, skipped byte is %d\n", version, tmp); + len--; + } + if (flags & 2) add_index_item(demuxer, stream_id, timestamp, demuxer->filepos); @@ -649,6 +693,14 @@ timestamp > priv->index_table[demuxer->audio->id][priv->current_apacket].timestamp) priv->current_apacket += 1; + if(priv->is_multirate) + while (priv->a_idx_ptr + 1 < priv->index_table_size[demuxer->audio->id] && + timestamp > priv->index_table[demuxer->audio->id][priv->a_idx_ptr + 1].timestamp) { + priv->a_idx_ptr++; + priv->audio_curpos = stream_tell(demuxer->stream); + priv->stream_switch = 1; + } + return 1; } @@ -858,6 +910,14 @@ timestamp > priv->index_table[demuxer->video->id][priv->current_vpacket + 1].timestamp) priv->current_vpacket += 1; + if(priv->is_multirate) + while (priv->v_idx_ptr + 1 < priv->index_table_size[demuxer->video->id] && + timestamp > priv->index_table[demuxer->video->id][priv->v_idx_ptr + 1].timestamp) { + priv->v_idx_ptr++; + priv->video_curpos = stream_tell(demuxer->stream); + priv->stream_switch = 1; + } + return 1; } @@ -1025,6 +1085,8 @@ int codec_data_size; int codec_pos; int tmp; + int len; + char *descr, *mimet; stream_id = stream_read_word(demuxer->stream); mp_msg(MSGT_DEMUX,MSGL_V,"Found new stream (id: %d)\n", stream_id); @@ -1037,40 +1099,45 @@ stream_skip(demuxer->stream, 4); /* preroll */ stream_skip(demuxer->stream, 4); /* duration */ - skip_str(1, demuxer); /* stream description (name) */ - skip_str(1, demuxer); /* mimetype */ +// skip_str(1, demuxer); /* stream description (name) */ + if ((len = stream_read_char(demuxer->stream)) > 0) { + descr = malloc(len+1); + stream_read(demuxer->stream, descr, len); + descr[len] = 0; + printf("Stream description: %s\n", descr); + free(descr); + } +// skip_str(1, demuxer); /* mimetype */ + if ((len = stream_read_char(demuxer->stream)) > 0) { + mimet = malloc(len+1); + stream_read(demuxer->stream, mimet, len); + mimet[len] = 0; + printf("Stream mimetype: %s\n", mimet); + } /* Type specific header */ codec_data_size = stream_read_dword(demuxer->stream); codec_pos = stream_tell(demuxer->stream); - if (!codec_data_size) { - mp_msg(MSGT_DEMUX,MSGL_DBG2,"demux_real: no codec data in MDPR chunk at fpos=0x%X\n", codec_pos); - break; - } - - tmp = stream_read_dword(demuxer->stream); - - mp_msg(MSGT_DEMUX,MSGL_DBG2,"demux_real: type_spec: len=%d fpos=0x%X first_dword=0x%X (%.4s) \n", - (int)codec_data_size,(int)codec_pos,tmp,&tmp); - -#if 1 - // skip unknown shit - FIXME: find a better/cleaner way! - { int len=codec_data_size; - while(--len>=8){ - if(tmp==MKTAG(0xfd, 'a', 'r', '.')) break; // audio - if(tmp==MKTAG('O', 'D', 'I', 'V')) break; // video - tmp=(tmp<<8)|stream_read_char(demuxer->stream); - } - } -#endif - #ifdef MP_DEBUG #define stream_skip(st,siz) { int i; for(i=0;i<siz;i++) mp_msg(MSGT_DEMUX,MSGL_V," %02X",stream_read_char(st)); mp_msg(MSGT_DEMUX,MSGL_V,"\n");} #endif - if (tmp == MKTAG(0xfd, 'a', 'r', '.')) + if (!strncmp(mimet,"audio/",6)) { + if (strstr(mimet,"x-pn-realaudio") || strstr(mimet,"x-pn-multirate-realaudio")) { + // skip unknown shit - FIXME: find a better/cleaner way! + len=codec_data_size; + tmp = stream_read_dword(demuxer->stream); +// mp_msg(MSGT_DEMUX,MSGL_DBG2,"demux_real: type_spec: len=%d fpos=0x%X first_dword=0x%X (%.4s) \n", +// (int)codec_data_size,(int)codec_pos,tmp,&tmp); + while(--len>=8){ + if(tmp==MKTAG(0xfd, 'a', 'r', '.')) break; // audio + tmp=(tmp<<8)|stream_read_char(demuxer->stream); + } + if (tmp != MKTAG(0xfd, 'a', 'r', '.')) { + mp_msg(MSGT_DEMUX,MSGL_V,"Audio: can't find .ra in codec data\n"); + } else { /* audio header */ sh_audio_t *sh = new_sh_audio(demuxer, stream_id); char buf[128]; /* for codec name */ @@ -1313,6 +1380,14 @@ if (verbose > 0) print_wave_header(sh->wf); + /* Select audio stream with highest bitrate if multirate file*/ + if (priv->is_multirate && ((demuxer->audio->id == -1) || + ((demuxer->audio->id >= 0) && priv->a_bitrate && (bitrate > priv->a_bitrate)))) { + demuxer->audio->id = stream_id; + priv->a_bitrate = bitrate; + mp_msg(MSGT_DEMUX,MSGL_DBG2,"Multirate autoselected audio id %d with bitrate %d\n", stream_id, bitrate); + } + if(demuxer->audio->id==stream_id){ demuxer->audio->id=stream_id; sh->ds=demuxer->audio; @@ -1325,10 +1400,48 @@ #undef stream_skip #endif } - else -// case MKTAG('V', 'I', 'D', 'O'): - if(tmp == MKTAG('O', 'D', 'I', 'V')) +#if 0 + } else if (strstr(mimet,"X-MP3")) { + sh_audio_t *sh = new_sh_audio(demuxer, stream_id); + + /* Emulate WAVEFORMATEX struct: */ + sh->wf = malloc(sizeof(WAVEFORMATEX)); + memset(sh->wf, 0, sizeof(WAVEFORMATEX)); + sh->wf->nChannels = 0;//sh->channels; + sh->wf->wBitsPerSample = 16; + sh->wf->nSamplesPerSec = 0;//sh->samplerate; + sh->wf->nAvgBytesPerSec = 0;//bitrate; + sh->wf->nBlockAlign = 0;//frame_size; + sh->wf->cbSize = 0; + sh->wf->wFormatTag = sh->format = 0x55; + + if(demuxer->audio->id==stream_id){ + sh->ds=demuxer->audio; + demuxer->audio->sh=sh; + } + + ++a_streams; +#endif + } else if (strstr(mimet,"x-ralf-mpeg4")) { + mp_msg(MSGT_DEMUX,MSGL_ERR,"Real lossless audio not supported yet\n"); + } else { + mp_msg(MSGT_DEMUX,MSGL_V,"Unknown audio stream format\n"); + } + } else if (!strncmp(mimet,"video/",6)) { + if (strstr(mimet,"x-pn-realvideo") || strstr(mimet,"x-pn-multirate-realvideo")) { + tmp = stream_read_dword(demuxer->stream); +// mp_msg(MSGT_DEMUX,MSGL_DBG2,"demux_real: type_spec: len=%d fpos=0x%X first_dword=0x%X (%.4s) \n", +// (int)codec_data_size,(int)codec_pos,tmp,&tmp); + // skip unknown shit - FIXME: find a better/cleaner way! + len=codec_data_size; + while(--len>=8){ + if(tmp==MKTAG('O', 'D', 'I', 'V')) break; // video + tmp=(tmp<<8)|stream_read_char(demuxer->stream); + } + if(tmp != MKTAG('O', 'D', 'I', 'V')) { + mp_msg(MSGT_DEMUX,MSGL_V,"Video: can't find VIDO in codec data\n"); + } else { /* video header */ sh_video_t *sh = new_sh_video(demuxer, stream_id); @@ -1411,6 +1524,14 @@ ((unsigned short*)(sh->bih+1))[5]=4*(unsigned short)stream_read_char(demuxer->stream); //height } + /* Select video stream with highest bitrate if multirate file*/ + if (priv->is_multirate && ((demuxer->video->id == -1) || + ((demuxer->video->id >= 0) && priv->v_bitrate && (bitrate > priv->v_bitrate)))) { + demuxer->video->id = stream_id; + priv->v_bitrate = bitrate; + mp_msg(MSGT_DEMUX,MSGL_DBG2,"Multirate autoselected video id %d with bitrate %d\n", stream_id, bitrate); + } + if(demuxer->video->id==stream_id){ demuxer->video->id=stream_id; sh->ds=demuxer->video; @@ -1420,12 +1541,43 @@ ++v_streams; } + } else { + mp_msg(MSGT_DEMUX,MSGL_V,"Unknown video stream format\n"); + } + } else if (strstr(mimet,"logical-")) { + if (strstr(mimet,"fileinfo")) { + mp_msg(MSGT_DEMUX,MSGL_V,"Got a logical-fileinfo chunk\n"); + } else if (strstr(mimet,"-audio") || strstr(mimet,"-video")) { + int i, stream_cnt; + int stream_list[MAX_STREAMS]; + + priv->is_multirate = 1; + stream_skip(demuxer->stream, 4); // Length of codec data (repeated) + stream_cnt = stream_read_dword(demuxer->stream); // Get number of audio or video streams + if (stream_cnt >= MAX_STREAMS) { + mp_msg(MSGT_DEMUX,MSGL_ERR,"Too many streams in %s. Big troubles ahead.\n", mimet); + goto skip_this_chunk; + } + for (i = 0; i < stream_cnt; i++) + stream_list[i] = stream_read_word(demuxer->stream); + for (i = 0; i < stream_cnt; i++) + if (stream_list[i] >= MAX_STREAMS) { + mp_msg(MSGT_DEMUX,MSGL_ERR,"Stream id out of range: %d. Ignored.\n", stream_list[i]); + stream_skip(demuxer->stream, 4); // Skip DATA offset for broken stream + } else { + priv->str_data_offset[stream_list[i]] = stream_read_dword(demuxer->stream); + mp_msg(MSGT_DEMUX,MSGL_V,"Stream %d with DATA offset 0x%08x\n", stream_list[i], priv->str_data_offset[stream_list[i]]); + } + // Skip the rest of this chunk + } else + mp_msg(MSGT_DEMUX,MSGL_V,"Unknown logical stream\n"); + } else { mp_msg(MSGT_DEMUX, MSGL_ERR, "Not audio/video stream or unsupported!\n"); } // break; // default: -//skip_this_chunk: +skip_this_chunk: /* skip codec info */ tmp = stream_tell(demuxer->stream) - codec_pos; mp_msg(MSGT_DEMUX,MSGL_V,"### skipping %d bytes of codec info\n", codec_data_size - tmp); @@ -1438,6 +1590,8 @@ #else stream_skip(demuxer->stream, codec_data_size - tmp); #endif + if (mimet) + free (mimet); break; // } } @@ -1452,6 +1606,40 @@ } header_end: + if(priv->is_multirate) { + mp_msg(MSGT_DEMUX,MSGL_V,"Selected video id %d audio id %d\n", demuxer->video->id, demuxer->audio->id); + /* Perform some sanity checks to avoid checking streams id all over the code*/ + if (demuxer->audio->id >= MAX_STREAMS) { + mp_msg(MSGT_DEMUX,MSGL_ERR,"Invalid audio stream %d. No sound will be played.\n", demuxer->audio->id); + demuxer->audio->id = -2; + } else if ((demuxer->audio->id >= 0) && (priv->str_data_offset[demuxer->audio->id] == 0)) { + mp_msg(MSGT_DEMUX,MSGL_ERR,"Audio stream %d not found. No sound will be played.\n", demuxer->audio->id); + demuxer->audio->id = -2; + } + if (demuxer->video->id >= MAX_STREAMS) { + mp_msg(MSGT_DEMUX,MSGL_ERR,"Invalid video stream %d. No video will be played.\n", demuxer->video->id); + demuxer->video->id = -2; + } else if ((demuxer->video->id >= 0) && (priv->str_data_offset[demuxer->video->id] == 0)) { + mp_msg(MSGT_DEMUX,MSGL_ERR,"Video stream %d not found. No video will be played.\n", demuxer->video->id); + demuxer->video->id = -2; + } + } + + if(priv->is_multirate && ((demuxer->video->id >= 0) || (demuxer->audio->id >=0))) { + /* If audio or video only, seek to right place and behave like standard file */ + if (demuxer->video->id < 0) { + // Stream is audio only, or -novideo + stream_seek(demuxer->stream, priv->data_chunk_offset = priv->str_data_offset[demuxer->audio->id]+10); + priv->is_multirate = 0; + } + if (demuxer->audio->id < 0) { + // Stream is video only, or -nosound + stream_seek(demuxer->stream, priv->data_chunk_offset = priv->str_data_offset[demuxer->video->id]+10); + priv->is_multirate = 0; + } + } + + if(!priv->is_multirate) { // printf("i=%d num_of_headers=%d \n",i,num_of_headers); priv->num_of_packets = stream_read_dword(demuxer->stream); // stream_skip(demuxer->stream, 4); /* number of packets */ @@ -1461,6 +1649,19 @@ if (priv->num_of_packets == 0) priv->num_of_packets = -10; + } else { + priv->audio_curpos = priv->str_data_offset[demuxer->audio->id] + 18; + stream_seek(demuxer->stream, priv->str_data_offset[demuxer->audio->id]+10); + priv->a_num_of_packets=priv->a_num_of_packets = stream_read_dword(demuxer->stream); + priv->video_curpos = priv->str_data_offset[demuxer->video->id] + 18; + stream_seek(demuxer->stream, priv->str_data_offset[demuxer->video->id]+10); + priv->v_num_of_packets = stream_read_dword(demuxer->stream); + priv->stream_switch = 1; + /* Index required for multirate playback, force building if it's not there */ + /* but respect user request to force index regeneration */ + if (index_mode == -1) + index_mode = 1; + } priv->audio_need_keyframe = 0; @@ -1492,6 +1693,9 @@ break; } + if(priv->is_multirate) + demuxer->seekable = 0; // No seeking yet for multirate streams + // detect streams: if(demuxer->video->id==-1 && v_streams>0){ // find the valid video stream: