Exemplo n.º 1
0
int stream_read_internal(stream_t *s, void *buf, int len)
{
  int orig_len = len;
  // we will retry even if we already reached EOF previously.
  switch(s->type){
  case STREAMTYPE_STREAM:
#ifdef CONFIG_NETWORKING
    if( s->streaming_ctrl!=NULL && s->streaming_ctrl->streaming_read ) {
      len=s->streaming_ctrl->streaming_read(s->fd, buf, len, s->streaming_ctrl);
      if (s->streaming_ctrl->status == streaming_stopped_e)
        s->eof = 1;
    } else
#endif
    if (s->fill_buffer)
      len = s->fill_buffer(s, buf, len);
    else
      len = read(s->fd, buf, len);
    break;
  case STREAMTYPE_DS:
    len = demux_read_data((demux_stream_t*)s->priv, buf, len);
    break;


  default:
    len= s->fill_buffer ? s->fill_buffer(s, buf, len) : 0;
  }
  if(len<=0){
    off_t pos = s->pos;
    // do not retry if this looks like proper eof
    if (s->eof || (s->end_pos && pos == s->end_pos))
      goto eof_out;
    // dvdnav has some horrible hacks to "suspend" reads,
    // we need to skip this code or seeks will hang.
    if (s->type == STREAMTYPE_DVDNAV)
      goto eof_out;

    // just in case this is an error e.g. due to network
    // timeout reset and retry
    // Seeking is used as a hack to make network streams
    // reopen the connection, ideally they would implement
    // e.g. a STREAM_CTRL_RECONNECT to do this
    s->eof=1;
    stream_reset(s);
    if (stream_seek_internal(s, pos) >= 0 || s->pos != pos) // seek failed
      goto eof_out;
    // make sure EOF is set to ensure no endless loops
    s->eof=1;
    return stream_read_internal(s, buf, orig_len);

eof_out:
    s->eof=1;
    return 0;
  }
  // When reading succeeded we are obviously not at eof.
  // This e.g. avoids issues with eof getting stuck when lavf seeks in MPEG-TS
  s->eof=0;
  s->pos+=len;
  return len;
}
Exemplo n.º 2
0
int stream_seek_long(stream_t *s,off_t pos){
  int res;
off_t newpos=0;

//  if( mp_msg_test(MSGT_STREAM,MSGL_DBG3) ) printf("seek_long to 0x%X\n",(unsigned int)pos);

  s->buf_pos=s->buf_len=0;

  if(s->mode == STREAM_WRITE) {
    if(!s->seek || !s->seek(s,pos))
      return 0;
    return 1;
  }

  if(s->sector_size)
      newpos = (pos/s->sector_size)*s->sector_size;
  else
      newpos = pos&(~((off_t)STREAM_BUFFER_SIZE-1));

if( mp_msg_test(MSGT_STREAM,MSGL_DBG3) ){
  mp_msg(MSGT_STREAM,MSGL_DBG3, "s->pos=%"PRIX64"  newpos=%"PRIX64"  new_bufpos=%"PRIX64"  buflen=%X  \n",
    (int64_t)s->pos,(int64_t)newpos,(int64_t)pos,s->buf_len);
}
  pos-=newpos;

  res = stream_seek_internal(s, newpos);
  if (res >= 0)
    return res;

  while(s->pos<newpos){
    if(stream_fill_buffer(s)<=0) break; // EOF
  }

s->eof = 0; // EOF reset when seek succeeds.
while (stream_fill_buffer(s) > 0) {
  if(pos<=s->buf_len){
    s->buf_pos=pos; // byte position in sector
    return 1;
  }
  pos -= s->buf_len;
}
// Fill failed, but seek still is a success.
s->pos += pos;
s->buf_pos = 0;
s->buf_len = 0;

mp_msg(MSGT_STREAM,MSGL_V,
       "stream_seek: Seek to/past EOF: no buffer preloaded.\n");
return 1;
}
Exemplo n.º 3
0
int stream_seek_long(stream_t *s, int64_t pos){
  int res;
  int64_t newpos=0;

//  if( mp_msg_test(MSGT_STREAM,MSGL_DBG3) ) printf("seek_long to 0x%X\n",(unsigned int)pos);

  s->buf_pos=s->buf_len=0;

  if(s->mode == STREAM_WRITE) {
    if(!s->seek || !s->seek(s,pos))
      return 0;
    return 1;
  }

  if(s->sector_size)
      newpos = (pos/s->sector_size)*s->sector_size;
  else
      newpos = pos&(~((int64_t)STREAM_BUFFER_SIZE-1));

if( mp_msg_test(MSGT_STREAM,MSGL_DBG3) ){
  mp_msg(MSGT_STREAM,MSGL_DBG3, "s->pos=%"PRIX64"  newpos=%"PRIX64"  new_bufpos=%"PRIX64"  buflen=%X  \n",
    (int64_t)s->pos,(int64_t)newpos,(int64_t)pos,s->buf_len);
}
  pos-=newpos;

  res = stream_seek_internal(s, newpos);
  if (res >= 0)
    return res;

  while(s->pos<newpos){
    if(stream_fill_buffer(s)<=0) break; // EOF
  }

while(stream_fill_buffer(s) > 0 && pos >= 0) {
  if(pos<=s->buf_len){
    s->buf_pos=pos; // byte position in sector
    return 1;
  }
  pos -= s->buf_len;
}

//  if(pos==s->buf_len) printf("XXX Seek to last byte of file -> EOF\n");

  mp_msg(MSGT_STREAM,MSGL_V,"stream_seek: WARNING! Can't seek to 0x%"PRIX64" !\n",(int64_t)(pos+newpos));
  return 0;
}
Exemplo n.º 4
0
static int stream_reconnect(stream_t *s)
{
#define MAX_RECONNECT_RETRIES 5
#define RECONNECT_SLEEP_MS 1000
    int retry = 0;
    int64_t pos = s->pos;
    // Seeking is used as a hack to make network streams
    // reopen the connection, ideally they would implement
    // e.g. a STREAM_CTRL_RECONNECT to do this
    do {
        if (retry >= MAX_RECONNECT_RETRIES)
            return 0;
        if (retry) usec_sleep(RECONNECT_SLEEP_MS * 1000);
        retry++;
        s->eof=1;
        stream_reset(s);
    } while (stream_seek_internal(s, pos) >= 0 || s->pos != pos); // seek failed
    return 1;
}
Exemplo n.º 5
0
static int cache_fill(cache_vars_t *s)
{
  int back,back2,newb,space,len,pos;
  off_t read=s->read_filepos;
  int read_chunk;
  int wraparound_copy = 0;

  if(read<s->min_filepos || read>s->max_filepos){
      // seek...
      mp_msg(MSGT_CACHE,MSGL_DBG2,"Out of boundaries... seeking to 0x%"PRIX64"  \n",(int64_t)read);
      // drop cache contents only if seeking backward or too much fwd.
      // This is also done for on-disk files, since it loses the backseek cache.
      // That in turn can cause major bandwidth increase and performance
      // issues with e.g. mov or badly interleaved files
      if(read<s->min_filepos || read>=s->max_filepos+s->seek_limit)
      {
        s->offset= // FIXME!?
        s->min_filepos=s->max_filepos=read; // drop cache content :(
        if(s->stream->eof) stream_reset(s->stream);
        stream_seek_internal(s->stream,read);
        mp_msg(MSGT_CACHE,MSGL_DBG2,"Seek done. new pos: 0x%"PRIX64"  \n",(int64_t)stream_tell(s->stream));
      }
  }

  // calc number of back-bytes:
  back=read - s->min_filepos;
  if(back<0) back=0; // strange...
  if(back>s->back_size) back=s->back_size;

  // calc number of new bytes:
  newb=s->max_filepos - read;
  if(newb<0) newb=0; // strange...

  // calc free buffer space:
  space=s->buffer_size - (newb+back);

  // calc bufferpos:
  pos=s->max_filepos - s->offset;
  if(pos>=s->buffer_size) pos-=s->buffer_size; // wrap-around

  if(space<s->fill_limit){
//    printf("Buffer is full (%d bytes free, limit: %d)\n",space,s->fill_limit);
    return 0; // no fill...
  }

//  printf("### read=0x%X  back=%d  newb=%d  space=%d  pos=%d\n",read,back,newb,space,pos);

  // try to avoid wrap-around. If not possible due to sector size
  // do an extra copy.
  if(space>s->buffer_size-pos) {
    if (s->buffer_size-pos >= s->sector_size) {
      space=s->buffer_size-pos;
    } else {
      space = s->sector_size;
      wraparound_copy = 1;
    }
  }

  // limit one-time block size
  read_chunk = s->stream->read_chunk;
  if (!read_chunk) read_chunk = 4*s->sector_size;
  space = FFMIN(space, read_chunk);

#if 1
  // back+newb+space <= buffer_size
  back2=s->buffer_size-(space+newb); // max back size
  if(s->min_filepos<(read-back2)) s->min_filepos=read-back2;
#else
  s->min_filepos=read-back; // avoid seeking-back to temp area...
#endif

  if (wraparound_copy) {
    int to_copy;
    len = stream_read_internal(s->stream, s->stream->buffer, space);
    to_copy = FFMIN(len, s->buffer_size-pos);
    memcpy(s->buffer + pos, s->stream->buffer, to_copy);
    memcpy(s->buffer, s->stream->buffer + to_copy, len - to_copy);
  } else
  len = stream_read_internal(s->stream, &s->buffer[pos], space);
  s->eof= !len;

  s->max_filepos+=len;
  if(pos+len>=s->buffer_size){
      // wrap...
      s->offset+=s->buffer_size;
  }

  return len;

}