示例#1
0
文件: stream_dvd.c 项目: wagic520/mpv
static int dvd_read_sector(stream_t *stream, dvd_priv_t *d, unsigned char *data)
{
  int len;

  if(d->packs_left==0) {
    /**
     * If we're not at the end of this cell, we can determine the next
     * VOBU to display using the VOBU_SRI information section of the
     * DSI.  Using this value correctly follows the current angle,
     * avoiding the doubled scenes in The Matrix, and makes our life
     * really happy.
     *
     * Otherwise, we set our next address past the end of this cell to
     * force the code above to go to the next cell in the program.
     */
    if(d->dsi_pack.vobu_sri.next_vobu != SRI_END_OF_CELL) {
       d->cur_pack= d->dsi_pack.dsi_gi.nv_pck_lbn + ( d->dsi_pack.vobu_sri.next_vobu & 0x7fffffff );
       MP_DBG(stream, "Navi  new pos=0x%X  \n",d->cur_pack);
    } else {
      // end of cell! find next cell!
      MP_VERBOSE(stream, "--- END OF CELL !!! ---\n");
      d->cur_pack=d->cell_last_pack+1;
    }
  }

read_next:
  if(d->cur_pack>d->cell_last_pack) {
    // end of cell!
    int next=dvd_next_cell(stream, d);
    if(next>=0) {
      d->cur_cell=next;
      // if( d->cur_pgc->cell_playback[d->cur_cell].block_type
      // == BLOCK_TYPE_ANGLE_BLOCK ) d->cur_cell+=dvd_angle-1;
      d->cur_pack = d->cur_pgc->cell_playback[ d->cur_cell ].first_sector;
      d->cell_last_pack=d->cur_pgc->cell_playback[ d->cur_cell ].last_sector;
      MP_VERBOSE(stream, "DVD next cell: %d  pack: 0x%X-0x%X  \n",d->cur_cell,d->cur_pack,d->cell_last_pack);
    } else
        return -1; // EOF
  }

  len = DVDReadBlocks(d->title, d->cur_pack, 1, data);
  // only == 0 should indicate an error, but some dvdread version are buggy when used with dvdcss
  if(len <= 0) return -1; //error

  if(data[38]==0 && data[39]==0 && data[40]==1 && data[41]==0xBF &&
    data[1024]==0 && data[1025]==0 && data[1026]==1 && data[1027]==0xBF) {
       // found a Navi packet!!!
#if DVDREAD_VERSION >= LIBDVDREAD_VERSION(0,9,0)
    navRead_DSI(&d->dsi_pack, &(data[ DSI_START_BYTE ]));
#else
    navRead_DSI(&d->dsi_pack, &(data[ DSI_START_BYTE ]), sizeof(dsi_t));
#endif
    if(d->cur_pack != d->dsi_pack.dsi_gi.nv_pck_lbn ) {
      MP_VERBOSE(stream, "Invalid NAVI packet! lba=0x%X  navi=0x%X  \n",
        d->cur_pack,d->dsi_pack.dsi_gi.nv_pck_lbn);
    } else {
      // process!
      d->packs_left = d->dsi_pack.dsi_gi.vobu_ea;
      MP_DBG(stream, "Found NAVI packet! lba=0x%X  len=%d  \n",d->cur_pack,d->packs_left);
      //navPrint_DSI(&d->dsi_pack);
      MP_TRACE(stream, "\r### CELL %d: Navi: %d/%d  IFO: %d/%d   \n",d->cur_cell,
        d->dsi_pack.dsi_gi.vobu_c_idn,d->dsi_pack.dsi_gi.vobu_vob_idn,
        d->cur_pgc->cell_position[d->cur_cell].cell_nr,
        d->cur_pgc->cell_position[d->cur_cell].vob_id_nr);

      if(d->angle_seek) {
        int i,skip=0;
        for(i=0;i<9;i++)        // check if all values zero:
          if((skip=d->dsi_pack.sml_agli.data[i].address)!=0) break;
        if(skip && skip!=0x7fffffff) {
          // sml_agli table has valid data (at least one non-zero):
         d->cur_pack=d->dsi_pack.dsi_gi.nv_pck_lbn+
         d->dsi_pack.sml_agli.data[d->dvd_angle-1].address;
         d->angle_seek=0;
         d->cur_pack--;
         MP_VERBOSE(stream, "Angle-seek synced using sml_agli map!  new_lba=0x%X  \n",d->cur_pack);
        } else {
          // check if we're in the right cell, jump otherwise:
          if( (d->dsi_pack.dsi_gi.vobu_c_idn==d->cur_pgc->cell_position[d->cur_cell].cell_nr) &&
            (d->dsi_pack.dsi_gi.vobu_vob_idn==d->cur_pgc->cell_position[d->cur_cell].vob_id_nr) ){
            d->angle_seek=0;
            MP_VERBOSE(stream, "Angle-seek synced by cell/vob IDN search!  \n");
          } else {
            // wrong angle, skip this vobu:
            d->cur_pack=d->dsi_pack.dsi_gi.nv_pck_lbn+
            d->dsi_pack.dsi_gi.vobu_ea;
            d->angle_seek=2; // DEBUG
          }
        }
      }
    }
    ++d->cur_pack;
    goto read_next;
  }

  ++d->cur_pack;
  if(d->packs_left>=0) --d->packs_left;

  if(d->angle_seek) {
    if(d->angle_seek==2) MP_VERBOSE(stream, "!!! warning! reading packet while angle_seek !!!\n");
    goto read_next; // searching for Navi packet
  }

  return d->cur_pack-1;
}
示例#2
0
off_t copy_descriptors(int in_fd, int out_fd, off_t content_length, JOINT_FILE_INFO_T *joint_file_info_p)
{
	int i;
	struct _buff {
		int inuse;
		int pos;
		int len;
		unsigned char *p;
	} *buff;
	unsigned char *p;
	int read_idx = 0;
	int write_idx = 0;
	int idx_count = 0;
	off_t read_cnt = 0;

	off_t			total_read_size = 0;
	size_t			target_read_size;
	int				len;

	int flag_finish = 0;
	int flag_first_time = 0;
	int flag_verbose = 0;
	time_t first_timeout = 0;
	off_t written = 0;
	
	struct timeb marker1,marker2; //,marker3;
	int marker_count;

	if(global_param.buffer_size < 1) global_param.buffer_size = 1;
	if(global_param.stream_chunk_size < 512) global_param.stream_chunk_size = 512;

	ssize_t blocks_read = 0;
	int offset = 0;
	if (joint_file_info_p) offset = joint_file_info_p->iso_seek;
	
	// ======================
	// 送信バッファを確保
	// ======================

	debug_log_output("Allocating %d buffers of %d bytes each\n", global_param.buffer_size, global_param.stream_chunk_size);

	buff = malloc(global_param.buffer_size * sizeof(struct _buff));
	if ( buff == NULL )
	{
		debug_log_output("malloc() error.\n");
		return (-1 );
	}
	p = malloc(global_param.buffer_size * global_param.stream_chunk_size);
	if ( p == NULL )
	{
		debug_log_output("malloc() error.\n");
		return ( 0 );
	}
	for (i=0; i<global_param.buffer_size; i++) {
		buff[i].pos = 0;
		buff[i].inuse = 0;
		buff[i].len = 0;
		buff[i].p = p + i*global_param.stream_chunk_size;
	}

	// ブロックモードの設定
	//set_blocking_mode(in_fd, 0);	/* blocking */
	set_blocking_mode(out_fd, (global_param.buffer_size>1));	/* non-blocking if multiple buffers */
	//debug_log_output("set non-blocking mode");

	// Do the calculation this way so global_param.buffer_size<4 always gets flag_first_time
	//No, don't force this!!!  :  if (content_length < global_param.stream_chunk_size * (global_param.buffer_size>>2)) flag_first_time = 1;
	if (global_param.buffer_size < 4) flag_first_time = 1;
	// If only one buffer, then we work the same as the http_simple_file_send()
	if (global_param.buffer_size == 1) global_param.flag_buffer_send_asap = 1;

	ftime(&marker1);
	marker_count = 0;

	first_timeout = time(NULL);
	// ================
	// 実体転送開始
	// ================
	while ( flag_finish < 2 )
	{
		struct timeval tv;
		fd_set writefds;

		if (flag_first_time == 0 && first_timeout + 13 <= time(NULL)) {
				debug_log_output( 
				   "****************************************************\n"
				   "**  Low bandwidth? send it anyway...              **\n"
				   "****************************************************");
				flag_first_time = 1;
		}
		if (flag_finish || flag_first_time || (idx_count >= (global_param.buffer_size-2))) 
		{
			if (flag_first_time == 0) {
				debug_log_output( 
				   "*********************************************************\n"
				   "**                    CACHE FILLED!                    **\n"
				   "*********************************************************");
				flag_first_time = 1;
			}
			while(buff[write_idx].inuse) {
				// If there is nothing more to read, concentrate on writing
				FD_ZERO(&writefds);
				FD_SET(out_fd, &writefds);
				tv.tv_sec = 0;
				if (flag_finish == 0 && !buff[read_idx].inuse) {
					// Don't wait for the select because we have room to read
					tv.tv_usec = 0;
				} else {
					tv.tv_usec = 100000; // 100msec maximum wait = 10Hz polling rate
				}
//ftime(&marker2);
				i = select(FD_SETSIZE, NULL, &writefds, NULL, &tv);
//ftime(&marker3);
//len = (marker3.time-marker2.time)*1000 + (marker3.millitm-marker2.millitm);
//if(len>9) fputc('0'+len/10, stderr);
				if (i < 0) {
					// Select returned an error - socket must be closed
					debug_log_output("select failed. err = %s", strerror(errno));
					flag_finish = 2;
					break;
				} else if(i > 0) {
//ftime(&marker2);
					len = write(out_fd, buff[write_idx].p + buff[write_idx].pos,
						(buff[write_idx].len < global_param.socket_chunk_size) ? buff[write_idx].len : global_param.socket_chunk_size );
//ftime(&marker3);
//i = (marker3.time-marker2.time)*1000 + (marker3.millitm-marker2.millitm);
//if(i>9) fputc('a'+i/10, stderr);
					if(len > 0) {
//fputc('.', stderr);
						written += len;
						buff[write_idx].len -= len;

						marker_count += len;
						if(!global_param.flag_daemon && (marker_count > 2000000)) {
							// Display the network transfer rate
							double rate;
							ftime(&marker2);
							rate = (marker2.time-marker1.time) + 0.001*(marker2.millitm-marker1.millitm);
							if(rate > 0) {
								rate = 8e-6 * marker_count / rate;
								/* fprintf(stderr, "%g Mbps\n", rate); */
							}
							marker1 = marker2;
							marker_count = 0;
						}

						if (flag_verbose) {
							debug_log_output("sent: len =%6d, idx = %4d, idxcount = %4d", len, write_idx, idx_count);
						} else if(0 && !global_param.flag_daemon) {
							show_progress(idx_count * 100 / global_param.buffer_size, idx_count);
						}
						if (buff[write_idx].len <= 0) {
							buff[write_idx].inuse = 0;
							buff[write_idx].len = 0;
							buff[write_idx].pos = 0;
							write_idx = (write_idx + 1) % global_param.buffer_size;
							idx_count --;
						} else {
							buff[write_idx].pos += len;
						}
					} else {
//fputc('-', stderr);
						// Failed to write - end the stream
						if (len < 0) {
							if(errno == EAGAIN) {
								debug_log_output("write would block");
								break;
							}
							debug_log_output("write failed after %d bytes. err = %s (%d)", written, strerror(errno), (int)errno);
						} else {
							debug_log_output("socket closed by player");
						}
						flag_finish = 2;
						break;
					}
				} else {
					// Not ready to write, exit from the loop to do a read
//if (flag_finish == 0 && !buff[read_idx].inuse) {
//	fputc(',', stderr);
//} else {
//	fputc('o', stderr);
//}
					break;
				}
			}
			if((flag_finish==1) && !buff[write_idx].inuse) {
				flag_finish = 2;
				debug_log_output(
				   "*********************************************************\n"
				   "**                    SEND FINISHED!                   **\n"
				   "*********************************************************");
			}
		}
		// Always attempt a read if we have a buffer available
		//if (FD_ISSET(in_fd, &readfds)) {
		if(flag_finish == 0 && !buff[read_idx].inuse) {
			// target_read_size = (content_length - total_read_size) > 1024 ? 1024 : (content_length - total_read_size);
			target_read_size = global_param.stream_chunk_size - buff[read_idx].len;
/*
			if (buff[read_idx].p == NULL) {
				debug_log_output("error! idx: %d", read_idx);
			}
*/
ftime(&marker2);
			if ((joint_file_info_p!=NULL) && (joint_file_info_p->dvd_file != NULL)) {
				blocks_read = DVDReadBlocks(joint_file_info_p->dvd_file, offset, target_read_size/2048, buff[read_idx].p + buff[read_idx].len); 
				len = (off_t)blocks_read*2048;
				offset += blocks_read;
			} else if (joint_file_info_p && read_cnt >= joint_file_info_p->file[joint_file_info_p->current_file_num].size) {
				len = 0;
				read_cnt = 0;
				debug_log_output("finished file chunk %d\n", joint_file_info_p->current_file_num);
				//printf("finished file chunk %d\n", joint_file_info_p->current_file_num);
			} else {
				if (joint_file_info_p && target_read_size + read_cnt > joint_file_info_p->file[joint_file_info_p->current_file_num].size) {
					target_read_size = joint_file_info_p->file[joint_file_info_p->current_file_num].size - read_cnt;
					debug_log_output("finishing last block of %d\n", joint_file_info_p->current_file_num);
					//printf("finishing last block of %d\n", joint_file_info_p->current_file_num);
				}

				len = read(in_fd, buff[read_idx].p + buff[read_idx].len, target_read_size);
				read_cnt += len;
			}
//ftime(&marker3);
//i = (marker3.time-marker2.time)*1000 + (marker3.millitm-marker2.millitm);
//if(i>9) fputc('A'+i/10, stderr);
			if(len == 0) {
				if(    (joint_file_info_p==NULL)
					|| (joint_file_info_p->dvd_file != NULL)
					|| next_file(&in_fd, joint_file_info_p)) {
					// 読み込み終わり
					flag_finish = 1;
					if (flag_verbose) {
						debug_log_output("recv: len = %d, idx = %d finish!", len, read_idx);
					} else {
						debug_log_output(
					   "*********************************************************\n"
					   "**                    RECV FINISHED!                   **\n"
					   "*********************************************************");
					}
					if (buff[read_idx].len > 0) {
						buff[read_idx].inuse = 1;
						buff[read_idx].pos = 0;
					}
				} else {
					// 次のファイルに続く(ここでは何もしない)
				}
			} else if (len > 0) {
//fputc(':', stderr);
				if (flag_verbose) {
					debug_log_output("recv: len =%6d, idx = %4d, idxcount = %4d", len, read_idx, idx_count);
				} else if(0 && !global_param.flag_daemon) {
					show_progress(idx_count * 100 / global_param.buffer_size, idx_count);
				}
				buff[read_idx].len += len;
				total_read_size += len;

				if (global_param.flag_buffer_send_asap == TRUE
				|| buff[read_idx].len >= global_param.stream_chunk_size) {
					buff[read_idx].inuse = 1;
					buff[read_idx].pos = 0;
					idx_count ++;
					read_idx = (read_idx + 1) % global_param.buffer_size;
				}
/*
				if (content_length - total_read_size <= 0) {
					flag_finish = 1;
				}
*/
			} else {
				flag_finish = 1;
				if (flag_verbose) {
					debug_log_output("read err?: len = %d, idx = %d, err: %s", len, read_idx, strerror(errno));
				} else {
					debug_log_output(
				   "*********************************************************\n"
				   "**                    RECV FINISHED!(ret = %d)          **\n"
				   "*********************************************************", len);
				}
			}
		}
	}

	free(p);
	free(buff);	// Memory Free.
	debug_log_output("copy descriptors end.");

	// 正常終了
	return written;
}
示例#3
0
static int dvd_read_sector(dvd_priv_t *d, unsigned char *data)
{
  int len;

  if(d->packs_left==0) {
    /**
     * If we're not at the end of this cell, we can determine the next
     * VOBU to display using the VOBU_SRI information section of the
     * DSI.  Using this value correctly follows the current angle,
     * avoiding the doubled scenes in The Matrix, and makes our life
     * really happy.
     *
     * Otherwise, we set our next address past the end of this cell to
     * force the code above to go to the next cell in the program.
     */
    if(d->dsi_pack.vobu_sri.next_vobu != SRI_END_OF_CELL) {
       d->cur_pack= d->dsi_pack.dsi_gi.nv_pck_lbn + ( d->dsi_pack.vobu_sri.next_vobu & 0x7fffffff );
       mp_msg(MSGT_DVD,MSGL_DBG2, "Navi  new pos=0x%X  \n",d->cur_pack);
    } else {
      // end of cell! find next cell!
      mp_msg(MSGT_DVD,MSGL_V, "--- END OF CELL !!! ---\n");
      d->cur_pack=d->cell_last_pack+1;
    }
  }

read_next:
  if(d->cur_pack>d->cell_last_pack) {
    // end of cell!
    int next=dvd_next_cell(d);
    if(next>=0) {
      d->cur_cell=next;
      // if( d->cur_pgc->cell_playback[d->cur_cell].block_type
      // == BLOCK_TYPE_ANGLE_BLOCK ) d->cur_cell+=dvd_angle;
      d->cur_pack = d->cur_pgc->cell_playback[ d->cur_cell ].first_sector;
      d->cell_last_pack=d->cur_pgc->cell_playback[ d->cur_cell ].last_sector;
      mp_msg(MSGT_DVD,MSGL_V, "DVD next cell: %d  pack: 0x%X-0x%X  \n",d->cur_cell,d->cur_pack,d->cell_last_pack);
    } else
        return -1; // EOF
  }

  len = DVDReadBlocks(d->title, d->cur_pack, 1, data);
  // only == 0 should indicate an error, but some dvdread version are buggy when used with dvdcss
  if(len <= 0) return -1; //error

  if(data[38]==0 && data[39]==0 && data[40]==1 && data[41]==0xBF &&
    data[1024]==0 && data[1025]==0 && data[1026]==1 && data[1027]==0xBF) {
       // found a Navi packet!!!
#if DVDREAD_VERSION >= LIBDVDREAD_VERSION(0,9,0)
    navRead_DSI(&d->dsi_pack, &(data[ DSI_START_BYTE ]));
#else
    navRead_DSI(&d->dsi_pack, &(data[ DSI_START_BYTE ]), sizeof(dsi_t));
#endif
    if(d->cur_pack != d->dsi_pack.dsi_gi.nv_pck_lbn ) {
      mp_msg(MSGT_DVD,MSGL_V, "Invalid NAVI packet! lba=0x%X  navi=0x%X  \n",
        d->cur_pack,d->dsi_pack.dsi_gi.nv_pck_lbn);
    } else {
      // process!
      d->packs_left = d->dsi_pack.dsi_gi.vobu_ea;
      mp_msg(MSGT_DVD,MSGL_DBG2, "Found NAVI packet! lba=0x%X  len=%d  \n",d->cur_pack,d->packs_left);
      //navPrint_DSI(&d->dsi_pack);
      mp_msg(MSGT_DVD,MSGL_DBG3,"\r### CELL %d: Navi: %d/%d  IFO: %d/%d   \n",d->cur_cell,
        d->dsi_pack.dsi_gi.vobu_c_idn,d->dsi_pack.dsi_gi.vobu_vob_idn,
        d->cur_pgc->cell_position[d->cur_cell].cell_nr,
        d->cur_pgc->cell_position[d->cur_cell].vob_id_nr);

      if(d->angle_seek) {
        int i,skip=0;
#if defined(__GNUC__) && ( defined(__sparc__) || defined(hpux) )
        // workaround for a bug in the sparc/hpux version of gcc 2.95.X ... 3.2,
        // it generates incorrect code for unaligned access to a packed
        // structure member, resulting in an mplayer crash with a SIGBUS
        // signal.
        //
        // See also gcc problem report PR c/7847:
        // http://gcc.gnu.org/cgi-bin/gnatsweb.pl?database=gcc&cmd=view+audit-trail&pr=7847
        for(i=0;i<9;i++) {	// check if all values zero:
          __typeof__(d->dsi_pack.sml_agli.data[i].address) tmp_addr;
          memcpy(&tmp_addr,&d->dsi_pack.sml_agli.data[i].address,sizeof(tmp_addr));
          if((skip=tmp_addr)!=0) break;
        }
#else
        for(i=0;i<9;i++)	// check if all values zero:
          if((skip=d->dsi_pack.sml_agli.data[i].address)!=0) break;
#endif
        if(skip && skip!=0x7fffffff) {
          // sml_agli table has valid data (at least one non-zero):
         d->cur_pack=d->dsi_pack.dsi_gi.nv_pck_lbn+
         d->dsi_pack.sml_agli.data[dvd_angle].address;
         d->angle_seek=0;
         d->cur_pack--;
         mp_msg(MSGT_DVD,MSGL_V, "Angle-seek synced using sml_agli map!  new_lba=0x%X  \n",d->cur_pack);
        } else {
          // check if we're in the right cell, jump otherwise:
          if( (d->dsi_pack.dsi_gi.vobu_c_idn==d->cur_pgc->cell_position[d->cur_cell].cell_nr) &&
            (d->dsi_pack.dsi_gi.vobu_vob_idn==d->cur_pgc->cell_position[d->cur_cell].vob_id_nr) ){
            d->angle_seek=0;
            mp_msg(MSGT_DVD,MSGL_V, "Angle-seek synced by cell/vob IDN search!  \n");
          } else {
            // wrong angle, skip this vobu:
            d->cur_pack=d->dsi_pack.dsi_gi.nv_pck_lbn+
            d->dsi_pack.dsi_gi.vobu_ea;
            d->angle_seek=2; // DEBUG
          }
        }
      }
    }
    ++d->cur_pack;
    goto read_next;
  }

  ++d->cur_pack;
  if(d->packs_left>=0) --d->packs_left;

  if(d->angle_seek) {
    if(d->angle_seek==2) mp_msg(MSGT_DVD,MSGL_V, "!!! warning! reading packet while angle_seek !!!\n");
    goto read_next; // searching for Navi packet
  }

  return d->cur_pack-1;
}
示例#4
0
off_t copy_descriptors(int in_fd, int out_fd, off_t content_length, JOINT_FILE_INFO_T *joint_file_info_p)
{
	int i;

	pthread_t id;
	pthread_attr_t attr;
	thread_param_type param;

	int index = 0;
	int next_index;
	int oneback,twoback,shortcount;

	off_t	total_read_size = 0;
	int	len;

	off_t read_cnt = 0;

	int flag_verbose = 0; // Set to 1 for debugging sessions, set to 0 for release
	int flag_send_asap = global_param.flag_buffer_send_asap;

	ssize_t blocks_read = 0;
	int offset = 0;
	
	if(global_param.buffer_size < 1) global_param.buffer_size = 1;
	if(global_param.stream_chunk_size < 512) global_param.stream_chunk_size = 512;

	if (joint_file_info_p) offset = joint_file_info_p->iso_seek;
	
	if(flag_verbose && global_param.flag_debug_log_output) {
		// Redirect streaming debug log to stderr
		debug_log_initialize(NULL);
	}
	// ======================
	// 送信バッファを確保
	// ======================

	param.count = global_param.buffer_size;

	// Need at least 4 buffers for this to be reasonable
	if(param.count < 4)
		param.count = 4;

	param.length = global_param.stream_chunk_size;

	debug_log_output("Allocating %d buffers of %d bytes each\n", param.count, param.length);

	param.bytes = (int *)malloc(param.count * sizeof(int));
	param.total = (off_t *)malloc(param.count * sizeof(off_t));
	param.buffer = (char **)malloc(param.count * sizeof(char *));
	param.mutex = (pthread_mutex_t *)malloc(param.count * sizeof(pthread_mutex_t));

	if ( ( param.bytes == NULL ) || ( param.buffer == NULL ) || ( param.mutex == NULL ) )
	{
		debug_log_output("malloc() error.\n");
		return (-1 );
	}

	for(i=0; i<param.count; i++) {
		param.bytes[i] = 0;
		param.buffer[i] = (char *)malloc(param.length);
		if(param.buffer[i] == NULL) {
			debug_log_output("malloc() error.\n");
			return ( 0 );
		}
		pthread_mutex_init(&param.mutex[i], NULL);
	}

	// Launch a separate thread to send the data out
	param.fd = out_fd;
	param.flags = 0;
	param.written = 0;

	// Lock the next block in advance
	pthread_mutex_lock(&param.mutex[index]);

	pthread_attr_init(&attr);

// This doesn't seek to work well under Cygwin
//#define USE_PTHREAD_PRIORITY
#ifdef USE_PTHREAD_PRIORITY
	{
		int policy,retcode,curr,mn,mx;
		struct sched_param schp;

		memset(&schp, 0, sizeof(schp));
		// Get the current settings
		pthread_getschedparam(pthread_self(), &policy, &schp);
		curr=schp.sched_priority;
		mn=sched_get_priority_min(policy);
		mx=sched_get_priority_max(policy);
		schp.sched_priority = (curr+mx)/2;
		debug_log_output("Setting policy %d, priority %d (was=%d, min=%d, max=%d)\n", policy, schp.sched_priority, curr, mn, mx);
		retcode = pthread_attr_setschedpolicy(&attr,policy);
		if(retcode != 0) {
			debug_log_output("pthread_attr_setschedpolicy returned %d\n",retcode);
		}
		retcode = pthread_attr_setschedparam(&attr,&schp);
		if(retcode != 0) {
			debug_log_output("pthread_attr_setschedparam returned %d\n",retcode);
		}
	}
#endif
	if((i = pthread_create(&id, &attr, send_buffers, &param)) != 0) {
		debug_log_output("pthread_create returned %d\n",i);
		return ( 0 );
	}

	// Watch the two bins behind, and shorten the buffer if the write thread is catching up
	twoback = param.count - 2;
	oneback = param.count - 1;
	shortcount = param.length/4;
	if(shortcount < 4096)
		shortcount = 4096;

	while ( param.flags == 0 )
	{
		// Wait for a buffer to free up
		next_index = index+1;
		if(next_index >= param.count)
			next_index = 0;

		if(pthread_mutex_lock(&param.mutex[next_index]) == 0) {
			for(i=0 ; i < param.length; ) {
				len = param.length - i;
				if(len > global_param.file_chunk_size)
					len = global_param.file_chunk_size;
				if ((joint_file_info_p!=NULL) && (joint_file_info_p->dvd_file != NULL)) {
					blocks_read = DVDReadBlocks(joint_file_info_p->dvd_file, offset, len/2048, param.buffer[index] + i); 
					len = (off_t)blocks_read*2048;
					offset += blocks_read;
				} else if (joint_file_info_p && read_cnt >= joint_file_info_p->file[joint_file_info_p->current_file_num].size) {
					len = 0;
					read_cnt = 0;
					debug_log_output("finished file chunk %d\n", joint_file_info_p->current_file_num);
					//printf("finished file chunk %d\n", joint_file_info_p->current_file_num);
				} else {
					if (joint_file_info_p && len + read_cnt > joint_file_info_p->file[joint_file_info_p->current_file_num].size) {
						len = joint_file_info_p->file[joint_file_info_p->current_file_num].size - read_cnt;
						debug_log_output("finishing last block of %d\n", joint_file_info_p->current_file_num);
						//printf("finishing last block of %d\n", joint_file_info_p->current_file_num);
					}

					len = read(in_fd, param.buffer[index] + i, len);
					read_cnt += len;
				}
				if(len == 0) {
					// End of file
					if(    (joint_file_info_p==NULL)
						|| (joint_file_info_p->dvd_file != NULL)
						|| next_file(&in_fd, joint_file_info_p)) {
						// No more files
						if (flag_verbose) {
							debug_log_output("recv: len = %d, idx = %d finish!", len, index);
						} else {
							debug_log_output(
							   "*********************************************************\n"
							   "**                    RECV FINISHED!                   **\n"
							   "*********************************************************");
						}
						param.flags |= FLAG_READ_COMPLETE;
						break;
					} else {
						// We opened up a new file, so continue the loop
					}
				} else if (len > 0) {
					i += len;
					total_read_size += len;
					if((content_length > 0) && (total_read_size >= content_length)) {
						// Only send as much as is requested
						if(total_read_size > content_length) {
							debug_log_output("Restricting content length, read=%lld, allowed=%lld", total_read_size, content_length);
							total_read_size -= content_length;
							i -= (int)total_read_size;;
							total_read_size = content_length;
						}
						param.flags |= FLAG_READ_COMPLETE;
						break;
					}
				} else {
					// Read error
					if (flag_verbose) {
						debug_log_output("read err?: len = %d, idx = %d, err: %s", len, index, strerror(errno));
					} else {
						debug_log_output(
					   "*********************************************************\n"
					   "**                    RECV FINISHED!(ret = %d)          **\n"
					   "*********************************************************", len);
					}
					param.flags |= FLAG_READ_COMPLETE;
					break;
				}
				// Check the trailing bins to see if the write thread is catching us
				// with the exception that if we already fell behind, 
				// then we allow it to rebuffer completely for one block
				if((i >= shortcount) && (param.bytes[twoback] == 0) && (total_read_size > param.length)) {
					if(param.bytes[oneback] == 0) {
						//fputc('.',stderr); // Only one buffer full - reloading
					} else {
						//fputc(':',stderr); // Only two buffers full, cut this buffer short
						break;
					}
				}
			}
			// Flag this block as ready-to-write
			param.bytes[index] = i;
			param.total[index] = total_read_size;
			if(flag_send_asap) {
				pthread_mutex_unlock(&param.mutex[index]);
			} else if(next_index == (param.count-2)) {
				// Buffers are filled, so release the sending thread
				flag_send_asap = TRUE;
				for(i=0; i<next_index; i++)
					pthread_mutex_unlock(&param.mutex[i]);
			}

			twoback = oneback;
			oneback = index;
			index = next_index;
		}
	}

	// Count the number of bytes in the queue
	for(i=0,len=0; i<param.count; i++) {
		len += param.bytes[i];
	}
	debug_log_output("Read complete, read %lld bytes, %d bytes to transmit", total_read_size, len);

	// If we haven't released the sending thread yet, do so now
	if(!flag_send_asap) {
		for(i=0; i<index; i++)
			pthread_mutex_unlock(&param.mutex[i]);
	}

	// Release the last block, unused
	pthread_mutex_unlock(&param.mutex[index]);

	// Wait for the created thread to complete
	pthread_join(id,NULL);

	// Free up the allocated memory
	if(param.bytes != NULL)
		free(param.bytes);
	for(i=0; i<param.count; i++) {
		if(param.buffer[i] != NULL)
			free(param.buffer[i]);
		pthread_mutex_destroy(&param.mutex[i]);
	}
	debug_log_output("copy descriptors end.");

	return param.written;
}
int dvdnav_read_cache_block(read_cache_t *self, int sector, size_t block_count, uint8_t **buf) {
  int i, use;
  int start;
  int size;
  int incr;
  uint8_t *read_ahead_buf;
  int32_t res;

  if(!self)
    return 0;

  use = -1;

  if(self->dvd_self->use_read_ahead) {
    /* first check, if sector is in current chunk */
    read_cache_chunk_t cur = self->chunk[self->current];
    if (cur.cache_valid && sector >= cur.cache_start_sector &&
        sector <= (cur.cache_start_sector + cur.cache_read_count) &&
        sector + block_count <= cur.cache_start_sector + cur.cache_block_count)
      use = self->current;
    else
      for (i = 0; i < READ_CACHE_CHUNKS; i++)
        if (self->chunk[i].cache_valid &&
            sector >= self->chunk[i].cache_start_sector &&
            sector <= (self->chunk[i].cache_start_sector + self->chunk[i].cache_read_count) &&
            sector + block_count <= self->chunk[i].cache_start_sector + self->chunk[i].cache_block_count)
            use = i;
  }

  if (use >= 0) {
    read_cache_chunk_t *chunk;

    /* Increment read-ahead size if sector follows the last sector */
    if (sector == (self->last_sector + 1)) {
      if (self->read_ahead_incr < READ_AHEAD_SIZE_MAX)
        self->read_ahead_incr++;
    } else {
      self->read_ahead_size = READ_AHEAD_SIZE_MIN;
      self->read_ahead_incr = 0;
    }
    self->last_sector = sector;

    /* The following resources need to be protected by a mutex :
     *   self->chunk[*].cache_buffer
     *   self->chunk[*].cache_malloc_size
     *   self->chunk[*].usage_count
     */
    pthread_mutex_lock(&self->lock);
    chunk = &self->chunk[use];
    read_ahead_buf = chunk->cache_buffer + chunk->cache_read_count * DVD_VIDEO_LB_LEN;
    *buf = chunk->cache_buffer + (sector - chunk->cache_start_sector) * DVD_VIDEO_LB_LEN;
    chunk->usage_count++;
    pthread_mutex_unlock(&self->lock);

    dprintf("libdvdnav: sector=%d, start_sector=%d, last_sector=%d\n", sector, chunk->cache_start_sector, chunk->cache_start_sector + chunk->cache_block_count);

    /* read_ahead_size */
    incr = self->read_ahead_incr >> 1;
    if ((self->read_ahead_size + incr) > READ_AHEAD_SIZE_MAX) {
      self->read_ahead_size = READ_AHEAD_SIZE_MAX;
    } else {
      self->read_ahead_size += incr;
    }

    /* real read size */
    start = chunk->cache_start_sector + chunk->cache_read_count;
    if (chunk->cache_read_count + self->read_ahead_size > chunk->cache_block_count) {
      size = chunk->cache_block_count - chunk->cache_read_count;
    } else {
      size = self->read_ahead_size;
      /* ensure that the sector we want will be read */
      if (sector >= chunk->cache_start_sector + chunk->cache_read_count + size)
        size = sector - chunk->cache_start_sector - chunk->cache_read_count;
    }
    dprintf("libdvdnav: read_ahead_size=%d, size=%d\n", self->read_ahead_size, size);

    if (size)
      chunk->cache_read_count += DVDReadBlocks(self->dvd_self->file,
                                               start,
                                               size,
                                               read_ahead_buf);

    res = DVD_VIDEO_LB_LEN * block_count;

  } else {
示例#6
0
static int fs_read(const char *path, char *buf, size_t count, off_t offset,
                      struct fuse_file_info *fi)
{
    int res;
    struct ext_file_info *xfi = fi->fh;

    if (!xfi || !xfi->fi->fd)
	return -ENOENT;

    /* fprintf(stderr, "read %s, xfi %d, offset %Ld, count %ld\n", path, xfi, offset, count); */

    if (IS_VOB(xfi->domain)) {
	off_t bk_off;
	size_t bk_cnt;

	if (xfi->domain == DVD_READ_TITLE_VOBS)
	    offset += PART_TO_OFFSET(xfi->partnum, part_size);

	if (offset % DVD_VIDEO_LB_LEN) {
	    return -EIO;
	}

	if (count % DVD_VIDEO_LB_LEN) {
	    return -EIO;
	}
	bk_off = offset / DVD_VIDEO_LB_LEN;
	bk_cnt = count / DVD_VIDEO_LB_LEN;
	
   res = DVDReadBlocks(xfi->fi->fd, bk_off, bk_cnt, (unsigned char*)buf);
   if (res > 0)
       res *= DVD_VIDEO_LB_LEN;

   //Caching can cause problems with slow drive if READ_AHEAD too high
   //have also not seen an improvement in performance from using it
   //Therefore disable and just do read as requested
#if 0
	/* Is this offset/count contained wholly in the cache? */
	if (xfi->cache_off <= offset && offset+count <= xfi->cache_off+xfi->cache_len) {
	    /* Yes, wholly in cache, so use cache only */
	    memcpy(buf, xfi->cache + (offset - xfi->cache_off), count);
	    res = count;
	}
	else {
	    /* No. Read the requested data and then do some read-ahead */
	    res = DVDReadBlocks(xfi->fi->fd, bk_off, bk_cnt, (unsigned char*)buf);
	    if (res > 0) {
		res *= DVD_VIDEO_LB_LEN;

		if (!xfi->cache)
		    xfi->cache = malloc(READ_AHEAD);
		if (xfi->cache && READ_AHEAD >= DVD_VIDEO_LB_LEN) {
		    int res2;

		    xfi->cache_off = offset + res;
		    res2 = DVDReadBlocks(xfi->fi->fd, xfi->cache_off/DVD_VIDEO_LB_LEN, READ_AHEAD/DVD_VIDEO_LB_LEN, xfi->cache);
		    if (res2 < 0)
			res2 = 0;
		    xfi->cache_len = res2 * DVD_VIDEO_LB_LEN;
		}
	    }
	}
#endif
    } else {
	if (xfi->cache) {
	    if (offset >= xfi->fi->len || offset < 0) {
		res = 0;
	    } else {
		res = min(count, xfi->fi->len - offset);
		memcpy(buf, xfi->cache + offset, res);
	    }
	} else {
	    res = -EIO;
	}
    }


    /* fprintf(stderr, "read: %d\n", res); */

    return res;
}
示例#7
0
/* This function will do the cache read */
int dvdnav_read_cache_block( read_cache_t *self, int sector, size_t block_count, uint8_t **buf) {
  int result, diff;

  if(!self)
   return 0;

  pthread_mutex_lock(&self->cache_lock);
  dprintf("Read from %i -> +%i (buffer pos=%i, read_point=%i, size=%i)... ", sector, block_count,
	 self->pos, self->read_point, self->size);
  if((self->size > 0) && (sector >= self->read_point) &&
     (sector + block_count <= self->pos + self->size)) {
    /* Hit */

    /* Drop any skipped blocks */
    diff = sector - self->read_point;
    if(diff > 0)
     self->read_point += diff;

    diff = self->read_point - self->pos;

    if(((self->start + diff) % CACHE_BUFFER_SIZE) + block_count <= CACHE_BUFFER_SIZE) {
      dprintf("************** Single read\n");
      memcpy(*buf, self->buffer + (((self->start + diff) % CACHE_BUFFER_SIZE) * DVD_VIDEO_LB_LEN),
	     block_count * DVD_VIDEO_LB_LEN);
      self->read_point += block_count;
      pthread_mutex_unlock(&self->cache_lock);

      return (int)block_count;
    } else {
      int32_t boundary = CACHE_BUFFER_SIZE - self->start;

      dprintf("************** Multiple read\n");
      memcpy(*buf, self->buffer + (((self->start + diff) % CACHE_BUFFER_SIZE) * DVD_VIDEO_LB_LEN),
	     boundary * DVD_VIDEO_LB_LEN);
      memcpy(*buf + (boundary  * DVD_VIDEO_LB_LEN), self->buffer,
	     (block_count-boundary) * DVD_VIDEO_LB_LEN);
      self->read_point += block_count;
      pthread_mutex_unlock(&self->cache_lock);

      return (int)block_count;
    }
  } else {
    /* Miss */

    fprintf(MSG_OUT, "libdvdnav: DVD read cache miss! (not bad but a performance hit) sector=%d\n", sector);
    result = DVDReadBlocks( self->dvd_self->file, sector, block_count, *buf);
    self->read_point = sector+block_count;
    if(self->read_point > self->pos + self->size) {
      /* Flush the cache as its not much use */
      dprintf("Contents irrelevent... flushing\n");
      self->size = 0;
      self->start = 0;
      self->pos = sector+block_count;
    }
    pthread_mutex_unlock(&self->cache_lock);
    usleep(300);
    return result;
  }

  /* Should never get here */
  return 0;
}
示例#8
0
void * read_cache_read_thread (void * this_gen) {
  int cont = 1;
  int32_t diff, start;
  uint32_t pos, size, startp, endp;
  uint32_t s,c;
  uint8_t *at;
  read_cache_t *self = (read_cache_t*)this_gen;

  while(cont) {

    pthread_mutex_lock(&self->cache_lock);

    if(self->size >= 0) {
      diff = self->read_point - self->pos;
      if(diff >= self->size/2) {
	dprintf("(II) Read thread -- ");

	startp = (self->start) % CACHE_BUFFER_SIZE;
	endp = abs((self->start + diff - 1) % CACHE_BUFFER_SIZE);
	dprintf("startp = %i, endp = %i -- ",startp, endp);

	pos = self->pos + diff;
	size = self->size - diff;
	start = (self->start + diff) % CACHE_BUFFER_SIZE;

	/* Fill remainder of buffer */

	if(startp > endp) {
	  s = pos + size; c = CACHE_BUFFER_SIZE - startp;
	  at = self->buffer + (startp * DVD_VIDEO_LB_LEN);
	  if(c > 0) {
	    dprintf("(1) Reading from %i to %i to %i ", s, s+c-1, startp);
	    pthread_mutex_unlock(&self->cache_lock);
	    DVDReadBlocks(self->dvd_self->file, s,c, at);
	    pthread_mutex_lock(&self->cache_lock);
	  }

	  s = pos + size + c; c = CACHE_BUFFER_SIZE - size - c;
	  at = self->buffer;
	  if(c > 0) {
	    dprintf("(2) Reading from %i to %i to %i ", s, s+c-1, 0);
	    pthread_mutex_unlock(&self->cache_lock);
	    DVDReadBlocks(self->dvd_self->file, s,c, at);
	    pthread_mutex_lock(&self->cache_lock);
	  }
	} else {
	  s = pos + size; c = CACHE_BUFFER_SIZE - size;
	  at = self->buffer + (startp * DVD_VIDEO_LB_LEN);
	  if(c > 0) {
	    dprintf("(3) Reading from %i to %i to %i ", s, s+c-1, startp);
	    pthread_mutex_unlock(&self->cache_lock);
	    DVDReadBlocks(self->dvd_self->file, s,c, at);
	    pthread_mutex_lock(&self->cache_lock);
	  }
	}

	dprintf("\n");

	self->pos = pos;
	self->start = start; self->size = CACHE_BUFFER_SIZE;
      }
    }

    pthread_mutex_unlock(&self->cache_lock);
    cont = (self->buffer != NULL);
    usleep(100);
  }

  return NULL;
}