diff options
Diffstat (limited to 'src/demuxers/demux_mpeg_block.c')
-rw-r--r-- | src/demuxers/demux_mpeg_block.c | 379 |
1 files changed, 277 insertions, 102 deletions
diff --git a/src/demuxers/demux_mpeg_block.c b/src/demuxers/demux_mpeg_block.c index ee6ebdf40..a7c602262 100644 --- a/src/demuxers/demux_mpeg_block.c +++ b/src/demuxers/demux_mpeg_block.c @@ -17,7 +17,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * - * $Id: demux_mpeg_block.c,v 1.34 2001/08/31 17:57:54 jkeil Exp $ + * $Id: demux_mpeg_block.c,v 1.35 2001/09/01 14:33:00 guenter Exp $ * * demultiplexer for mpeg 1/2 program streams * @@ -56,6 +56,7 @@ typedef struct demux_mpeg_block_s { int status; int blocksize; + int rate; int send_end_buffers; @@ -72,12 +73,10 @@ static void demux_mpeg_block_parse_pack (demux_mpeg_block_t *this, int preview_m buf_element_t *buf = NULL; unsigned char *p; int bMpeg1=0; - uint32_t nHeaderLen; - uint32_t nPTS; - uint32_t nDTS; - uint32_t nPacketLen; - uint32_t nStreamID; - + uint32_t header_len; + uint32_t PTS; + uint32_t packet_len; + uint32_t stream_id; buf = this->input->read_block (this->input, this->video_fifo, this->blocksize); @@ -127,9 +126,13 @@ static void demux_mpeg_block_parse_pack (demux_mpeg_block_t *this, int preview_m else buf->decoder_info[0] = 1; + buf->input_pos = this->input->get_current_pos (this->input); + + if (this->rate) + buf->input_time = buf->input_pos / (this->rate * 50); + if (p[3] == 0xBA) { /* program stream pack header */ - int nStuffingBytes; xprintf (VERBOSE|DEMUX, "program stream pack header\n"); @@ -137,28 +140,59 @@ static void demux_mpeg_block_parse_pack (demux_mpeg_block_t *this, int preview_m if (bMpeg1) { + if (!this->rate) { + this->rate = (p[9] & 0x7F) << 15; + this->rate |= (p[10] << 7); + this->rate |= (p[11] >> 1); + } + + buf->input_time = buf->input_pos / (this->rate * 50); + p += 12; } else { /* mpeg2 */ - nStuffingBytes = p[0xD] & 0x07; + int num_stuffing_bytes; + + /* SCR decoding code works but is not used by xine + int scr; + + scr = (p[4] & 0x38) << 27 ; + scr |= (p[4] & 0x03) << 28 ; + scr |= p[5] << 20; + scr |= (p[6] & 0xF8) << 12 ; + scr |= (p[6] & 0x03) << 13 ; + scr |= p[7] << 5; + scr |= (p[8] & 0xF8) >> 3; + + optional - decode extension: + + scr *=300; + scr += ( (p[8] & 0x03 << 7) | (p[9] & 0xFE >> 1) ); + */ - xprintf (VERBOSE|DEMUX, "%d stuffing bytes\n",nStuffingBytes); + if (!this->rate) { + this->rate = (p[0xA] << 14); + this->rate |= (p[0xB] << 6); + this->rate |= (p[0xB] >> 2); + } + + num_stuffing_bytes = p[0xD] & 0x07; - p += 14 + nStuffingBytes; + p += 14 + num_stuffing_bytes; } } if (p[3] == 0xbb) { /* program stream system header */ - int nHeaderLen; + int header_len; xprintf (VERBOSE|DEMUX, "program stream system header\n"); - nHeaderLen = (p[4] << 8) | p[5]; + header_len = (p[4] << 8) | p[5]; - p += 6 + nHeaderLen; + p += 6 + header_len; } /* we should now have a PES packet here */ @@ -169,109 +203,109 @@ static void demux_mpeg_block_parse_pack (demux_mpeg_block_t *this, int preview_m return ; } - nPacketLen = p[4] << 8 | p[5]; - nStreamID = p[3]; + packet_len = p[4] << 8 | p[5]; + stream_id = p[3]; - xprintf (VERBOSE|DEMUX, "packet id = %02x len = %d\n",nStreamID, nPacketLen); + xprintf (VERBOSE|DEMUX, "packet id = %02x len = %d\n",stream_id, packet_len); if (bMpeg1) { - if (nStreamID == 0xBF) { + if (stream_id == 0xBF) { buf->free_buffer (buf); return ; } - p += 6; /* nPacketLen -= 6; */ + p += 6; /* packet_len -= 6; */ while ((p[0] & 0x80) == 0x80) { p++; - nPacketLen--; + packet_len--; /* printf ("stuffing\n");*/ } if ((p[0] & 0xc0) == 0x40) { /* STD_buffer_scale, STD_buffer_size */ p += 2; - nPacketLen -=2; + packet_len -=2; } - nPTS = 0; - nDTS = 0; + PTS = 0; if ((p[0] & 0xf0) == 0x20) { - nPTS = (p[ 0] & 0x0E) << 29 ; - nPTS |= p[ 1] << 22 ; - nPTS |= (p[ 2] & 0xFE) << 14 ; - nPTS |= p[ 3] << 7 ; - nPTS |= (p[ 4] & 0xFE) >> 1 ; + PTS = (p[ 0] & 0x0E) << 29 ; + PTS |= p[ 1] << 22 ; + PTS |= (p[ 2] & 0xFE) << 14 ; + PTS |= p[ 3] << 7 ; + PTS |= (p[ 4] & 0xFE) >> 1 ; p += 5; - nPacketLen -=5; + packet_len -=5; } else if ((p[0] & 0xf0) == 0x30) { - nPTS = (p[ 0] & 0x0E) << 29 ; - nPTS |= p[ 1] << 22 ; - nPTS |= (p[ 2] & 0xFE) << 14 ; - nPTS |= p[ 3] << 7 ; - nPTS |= (p[ 4] & 0xFE) >> 1 ; - nDTS = (p[ 5] & 0x0E) << 29 ; - nDTS |= p[ 6] << 22 ; - nDTS |= (p[ 7] & 0xFE) << 14 ; - nDTS |= p[ 8] << 7 ; - nDTS |= (p[ 9] & 0xFE) >> 1 ; + PTS = (p[ 0] & 0x0E) << 29 ; + PTS |= p[ 1] << 22 ; + PTS |= (p[ 2] & 0xFE) << 14 ; + PTS |= p[ 3] << 7 ; + PTS |= (p[ 4] & 0xFE) >> 1 ; + /* DTS decoding code is working, but not used in xine + DTS = (p[ 5] & 0x0E) << 29 ; + DTS |= p[ 6] << 22 ; + DTS |= (p[ 7] & 0xFE) << 14 ; + DTS |= p[ 8] << 7 ; + DTS |= (p[ 9] & 0xFE) >> 1 ; + */ p += 10; - nPacketLen -= 10; + packet_len -= 10; } else { p++; - nPacketLen --; + packet_len --; } } else { /* mpeg 2 */ if (p[7] & 0x80) { /* PTS avail */ - nPTS = (p[ 9] & 0x0E) << 29 ; - nPTS |= p[10] << 22 ; - nPTS |= (p[11] & 0xFE) << 14 ; - nPTS |= p[12] << 7 ; - nPTS |= (p[13] & 0xFE) >> 1 ; + PTS = (p[ 9] & 0x0E) << 29 ; + PTS |= p[10] << 22 ; + PTS |= (p[11] & 0xFE) << 14 ; + PTS |= p[12] << 7 ; + PTS |= (p[13] & 0xFE) >> 1 ; } else - nPTS = 0; - - if (p[7] & 0x40) { /* PTS avail */ + PTS = 0; + + /* code is working but not used in xine + if (p[7] & 0x40) { - nDTS = (p[14] & 0x0E) << 29 ; - nDTS |= p[15] << 22 ; - nDTS |= (p[16] & 0xFE) << 14 ; - nDTS |= p[17] << 7 ; - nDTS |= (p[18] & 0xFE) >> 1 ; + DTS = (p[14] & 0x0E) << 29 ; + DTS |= p[15] << 22 ; + DTS |= (p[16] & 0xFE) << 14 ; + DTS |= p[17] << 7 ; + DTS |= (p[18] & 0xFE) >> 1 ; } else - nDTS = 0; + DTS = 0; + */ - nHeaderLen = p[8]; + header_len = p[8]; - p += nHeaderLen + 9; - nPacketLen -= nHeaderLen + 3; + p += header_len + 9; + packet_len -= header_len + 3; } - xprintf (VERBOSE|DEMUX, "stream_id=%x len=%d pts=%d dts=%d\n", nStreamID, nPacketLen, nPTS, nDTS); - - if (nStreamID == 0xbd) { + if (stream_id == 0xbd) { - int nTrack, nSPUID; + int track, spu_id; - nTrack = p[0] & 0x0F; /* hack : ac3 track */ + track = p[0] & 0x0F; /* hack : ac3 track */ if((p[0] & 0xE0) == 0x20) { - nSPUID = (p[0] & 0x1f); + spu_id = (p[0] & 0x1f); xprintf(VERBOSE|DEMUX, "SPU PES packet, id 0x%03x\n",p[0] & 0x1f); buf->content = p+1; - buf->size = nPacketLen-1; - buf->type = BUF_SPU_PACKAGE + nSPUID; - buf->PTS = nPTS; - buf->DTS = nDTS ; + buf->size = packet_len-1; + buf->type = BUF_SPU_PACKAGE + spu_id; + buf->PTS = PTS; buf->input_pos = this->input->get_current_pos(this->input); this->video_fifo->put (this->video_fifo, buf); @@ -281,14 +315,14 @@ static void demux_mpeg_block_parse_pack (demux_mpeg_block_t *this, int preview_m if ((p[0]&0xF0) == 0x80) { - xprintf (VERBOSE|DEMUX|AC3, "ac3 PES packet, track %02x\n",nTrack); - /* printf ( "ac3 PES packet, track %02x\n",nTrack); */ + xprintf (VERBOSE|DEMUX|AC3, "ac3 PES packet, track %02x\n",track); + /* printf ( "ac3 PES packet, track %02x\n",track); */ buf->content = p+4; - buf->size = nPacketLen-4; - buf->type = BUF_AUDIO_A52 + nTrack; - buf->PTS = nPTS; - buf->DTS = nDTS ; + buf->size = packet_len-4; + buf->type = BUF_AUDIO_A52 + track; + buf->PTS = PTS; + buf->input_pos = this->input->get_current_pos(this->input); if(this->audio_fifo) @@ -301,9 +335,9 @@ static void demux_mpeg_block_parse_pack (demux_mpeg_block_t *this, int preview_m int pcm_offset; - xprintf (VERBOSE|DEMUX,"LPCMacket, len : %d %02x\n",nPacketLen-4, p[0]); + xprintf (VERBOSE|DEMUX,"LPCMacket, len : %d %02x\n",packet_len-4, p[0]); - for( pcm_offset=0; ++pcm_offset < nPacketLen-1 ; ){ + for( pcm_offset=0; ++pcm_offset < packet_len-1 ; ){ if ( p[pcm_offset] == 0x01 && p[pcm_offset+1] == 0x80 ) { /* START */ pcm_offset += 2; break; @@ -311,10 +345,10 @@ static void demux_mpeg_block_parse_pack (demux_mpeg_block_t *this, int preview_m } buf->content = p+pcm_offset; - buf->size = nPacketLen-pcm_offset; - buf->type = BUF_AUDIO_LPCM_BE + nTrack; - buf->PTS = nPTS; - buf->DTS = nDTS ; + buf->size = packet_len-pcm_offset; + buf->type = BUF_AUDIO_LPCM_BE + track; + buf->PTS = PTS; + buf->input_pos = this->input->get_current_pos(this->input); if(this->audio_fifo) @@ -325,33 +359,33 @@ static void demux_mpeg_block_parse_pack (demux_mpeg_block_t *this, int preview_m return ; } - } else if ((nStreamID >= 0xbc) && ((nStreamID & 0xf0) == 0xe0)) { + } else if ((stream_id >= 0xbc) && ((stream_id & 0xf0) == 0xe0)) { - xprintf (VERBOSE|DEMUX, "video %d\n", nStreamID); + xprintf (VERBOSE|DEMUX, "video %d\n", stream_id); buf->content = p; - buf->size = nPacketLen; + buf->size = packet_len; buf->type = BUF_VIDEO_MPEG; - buf->PTS = nPTS; - buf->DTS = nDTS; + buf->PTS = PTS; + buf->input_pos = this->input->get_current_pos(this->input); this->video_fifo->put (this->video_fifo, buf); return ; - } else if ((nStreamID & 0xe0) == 0xc0) { - int nTrack; + } else if ((stream_id & 0xe0) == 0xc0) { + int track; - nTrack = nStreamID & 0x1f; + track = stream_id & 0x1f; - xprintf (VERBOSE|DEMUX|MPEG, "mpg audio #%d", nTrack); + xprintf (VERBOSE|DEMUX|MPEG, "mpg audio #%d", track); buf->content = p; - buf->size = nPacketLen; - buf->type = BUF_AUDIO_MPEG + nTrack; - buf->PTS = nPTS; - buf->DTS = nDTS; + buf->size = packet_len; + buf->type = BUF_AUDIO_MPEG + track; + buf->PTS = PTS; + buf->input_pos = this->input->get_current_pos(this->input); if(this->audio_fifo) @@ -362,7 +396,7 @@ static void demux_mpeg_block_parse_pack (demux_mpeg_block_t *this, int preview_m return ; } else { - xprintf (VERBOSE | DEMUX, "unknown packet, id = %x\n",nStreamID); + xprintf (VERBOSE | DEMUX, "unknown packet, id = %x\n",stream_id); } buf->free_buffer (buf); @@ -413,6 +447,126 @@ static void *demux_mpeg_block_loop (void *this_gen) { return NULL; } +/* estimate bitrate */ + +static int demux_mpeg_block_estimate_rate (demux_mpeg_block_t *this) { + + buf_element_t *buf = NULL; + unsigned char *p; + int is_mpeg1=0; + off_t pos, last_pos; + off_t step; + uint32_t PTS, last_PTS; + int rate; + int count; + + if (!(this->input->get_capabilities(this->input) & INPUT_CAP_SEEKABLE)) + return 0; + + pos = 0; + last_pos = 0; + last_PTS = 0; + rate = 0; + step = this->input->get_length (this->input) / 10; + step = (step / this->blocksize) * this->blocksize; + count = 0; + + this->input->seek (this->input, 0, SEEK_SET); + + while ((buf = this->input->read_block (this->input, this->video_fifo, this->blocksize)) ) { + + p = buf->content; /* len = this->mnBlocksize; */ + + if (p[3] == 0xBA) { /* program stream pack header */ + + is_mpeg1 = (p[4] & 0x40) == 0; + + if (is_mpeg1) + p += 12; + else + p += 14 + (p[0xD] & 0x07); + } + + if (p[3] == 0xbb) /* program stream system header */ + p += 6 + ((p[4] << 8) | p[5]); + + /* we should now have a PES packet here */ + + if (p[0] || p[1] || (p[2] != 1)) { + printf ("demux_mpeg_block: error %02x %02x %02x (should be 0x000001) \n",p[0],p[1],p[2]); + buf->free_buffer (buf); + return rate; + } + + PTS = 0; + + if (is_mpeg1) { + + if (p[3] != 0xBF) { /* stream_id */ + + p += 6; /* packet_len -= 6; */ + + while ((p[0] & 0x80) == 0x80) { + p++; /* stuffing */ + } + + if ((p[0] & 0xc0) == 0x40) { + /* STD_buffer_scale, STD_buffer_size */ + p += 2; + } + + if ( ((p[0] & 0xf0) == 0x20) || ((p[0] & 0xf0) == 0x30) ) { + PTS = (p[ 0] & 0x0E) << 29 ; + PTS |= p[ 1] << 22 ; + PTS |= (p[ 2] & 0xFE) << 14 ; + PTS |= p[ 3] << 7 ; + PTS |= (p[ 4] & 0xFE) >> 1 ; + } + } + } else { /* mpeg 2 */ + + if (p[7] & 0x80) { /* PTS avail */ + + PTS = (p[ 9] & 0x0E) << 29 ; + PTS |= p[10] << 22 ; + PTS |= (p[11] & 0xFE) << 14 ; + PTS |= p[12] << 7 ; + PTS |= (p[13] & 0xFE) >> 1 ; + + } else + PTS = 0; + } + + if (PTS) { + + if ( (pos>last_pos) && (PTS>last_PTS) ) { + int cur_rate; + + cur_rate = ((pos - last_pos)*90000) / ((PTS - last_PTS) * 50); + + rate = (count * rate + cur_rate) / (count+1); + + count ++; + + /* printf ("demux_mpeg_block: cur_rate = %d, overall rate : %d\n", cur_rate, rate); */ + } + + last_pos = pos; + last_PTS = PTS; + pos += step; + } else + pos += (off_t) this->blocksize; + + buf->free_buffer (buf); + + if (this->input->seek (this->input, pos, SEEK_SET) == (off_t)-1) + break; + } + + return rate; + +} + static void demux_mpeg_block_close (demux_plugin_t *this_gen) { demux_mpeg_block_t *this = (demux_mpeg_block_t *) this_gen; @@ -462,7 +616,7 @@ static int demux_mpeg_block_get_status (demux_plugin_t *this_gen) { static void demux_mpeg_block_start (demux_plugin_t *this_gen, fifo_buffer_t *video_fifo, fifo_buffer_t *audio_fifo, - off_t pos, + off_t start_pos, int start_time, gui_get_next_mrl_cb_t next_mrl_cb, gui_branched_cb_t branched_cb) { @@ -475,9 +629,6 @@ static void demux_mpeg_block_start (demux_plugin_t *this_gen, this->next_mrl_cb = next_mrl_cb; this->branched_cb = branched_cb; - pos /= (off_t) this->blocksize; - pos *= (off_t) this->blocksize; - /* * send start buffer */ @@ -492,6 +643,8 @@ static void demux_mpeg_block_start (demux_plugin_t *this_gen, this->audio_fifo->put (this->audio_fifo, buf); } + this->rate = demux_mpeg_block_estimate_rate (this); + if((this->input->get_capabilities(this->input) & INPUT_CAP_SEEKABLE) != 0) { int num_buffers = NUM_PREVIEW_BUFFERS; @@ -505,8 +658,18 @@ static void demux_mpeg_block_start (demux_plugin_t *this_gen, num_buffers --; } - xprintf (VERBOSE|DEMUX, "=>seek to %Ld\n",pos); - this->input->seek (this->input, pos, SEEK_SET); + if (start_pos) { + start_pos /= (off_t) this->blocksize; + start_pos *= (off_t) this->blocksize; + + this->input->seek (this->input, start_pos, SEEK_SET); + } else if (start_time) { + start_pos = start_time * this->rate * 50; + start_pos /= (off_t) this->blocksize; + start_pos *= (off_t) this->blocksize; + + this->input->seek (this->input, start_pos, SEEK_SET); + } } /* @@ -645,14 +808,25 @@ static char *demux_mpeg_block_get_id(void) { return "MPEG_BLOCK"; } +static int demux_mpeg_block_get_stream_length (demux_plugin_t *this_gen) { + + demux_mpeg_block_t *this = (demux_mpeg_block_t *) this_gen; + + if (this->rate) + return this->input->get_length (this->input) / (this->rate * 50); + else + return 0; + +} + demux_plugin_t *init_demuxer_plugin(int iface, config_values_t *config) { demux_mpeg_block_t *this; - if (iface != 2) { + if (iface != 3) { printf( "demux_mpeg: plugin doesn't support plugin API version %d.\n" "demux_mpeg: this means there's a version mismatch between xine and this " - "demux_mpeg: demuxer plugin.\nInstalling current input plugins should help.\n", + "demux_mpeg: demuxer plugin.\nInstalling current demux plugins should help.\n", iface); return NULL; } @@ -667,6 +841,7 @@ demux_plugin_t *init_demuxer_plugin(int iface, config_values_t *config) { this->demux_plugin.close = demux_mpeg_block_close; this->demux_plugin.get_status = demux_mpeg_block_get_status; this->demux_plugin.get_identifier = demux_mpeg_block_get_id; + this->demux_plugin.get_stream_length = demux_mpeg_block_get_stream_length; this->scratch = xmalloc_aligned (512, 4096); |