示例#1
0
文件: utils.c 项目: Caught/openpliPC
void xine_xprintf(xine_t *xine, int verbose, const char *fmt, ...) {
  char message[256];
  va_list ap;

  if (xine && xine->verbosity >= verbose) {
    va_start(ap, fmt);
    vsnprintf(message, sizeof(message), fmt, ap);
    va_end(ap);
    xine_log(xine, XINE_LOG_TRACE, "%s", message);
  }
}
示例#2
0
static int vo_frame_draw (vo_frame_t *img, xine_stream_t *stream) {

  vos_t         *this = (vos_t *) img->port;
  int64_t        diff;
  int64_t        cur_vpts;
  int64_t        pic_vpts ;
  int            frames_to_skip;

  img->stream = stream;
  extra_info_merge( img->extra_info, stream->video_decoder_extra_info );
  this->current_width = img->width;
  this->current_height = img->height;
  
  stream->metronom->got_video_frame (stream->metronom, img);
  this->current_duration = img->duration;

  if (!this->grab_only) {

    pic_vpts = img->vpts;
    img->extra_info->vpts = img->vpts;

    cur_vpts = this->clock->get_current_time(this->clock);
    this->last_delivery_pts = cur_vpts;

#ifdef LOG
    printf ("video_out: got image at master vpts %lld. vpts for picture is %lld (pts was %lld)\n",
	    cur_vpts, pic_vpts, img->pts);
#endif

    this->num_frames_delivered++;

    diff = pic_vpts - cur_vpts;
    /* avoid division by zero */
    if( img->duration <= 0 )
      img->duration = 3000;
    
    /* Frame dropping slow start:
     *   The engine starts to drop frames if there is less than frame_drop_limit
     *   frames in advance. There might be a problem just after a seek because
     *   there is no frame in advance yet.
     *   The following code increases progressively the frame_drop_limit (-2 -> 3)
     *   after a seek to give a chance to the engine to display the first frames
     *   smootly before starting to drop frames if the decoder is really too
     *   slow.
     */
    if (stream->first_frame_flag == 2)
      this->frame_drop_cpt = 10;

    if (this->frame_drop_cpt) {
      this->frame_drop_limit = 3 - (this->frame_drop_cpt / 2);
      this->frame_drop_cpt--;
    }
    frames_to_skip = ((-1 * diff) / img->duration + this->frame_drop_limit) * 2;

    if (frames_to_skip<0)
      frames_to_skip = 0;
  } else {
    frames_to_skip = 0;

    if (this->discard_frames) {
#ifdef LOG
      printf ("video_out: i'm in flush mode, not appending this frame to queue\n");
#endif
      return 0;
    }
  }


#ifdef LOG
  printf ("video_out: delivery diff : %lld, current vpts is %lld, %d frames to skip\n",
	  diff, cur_vpts, frames_to_skip);
#endif

  if (!img->bad_frame) {

    /* do not call proc_*() for frames that will be dropped */
    if( !frames_to_skip && !img->proc_called )
      vo_frame_driver_proc(img);
    
    /*
     * put frame into FIFO-Buffer
     */

#ifdef LOG
    printf ("video_out: frame is ok => appending to display buffer\n");
#endif

    /*
     * check for first frame after seek and mark it
     */
    img->is_first = 0;
    pthread_mutex_lock(&this->streams_lock);
    for (stream = xine_list_first_content(this->streams); stream;
         stream = xine_list_next_content(this->streams)) {
      pthread_mutex_lock (&stream->first_frame_lock);
      if (stream->first_frame_flag == 2) {
        stream->first_frame_flag = (this->grab_only)?0:1;
        img->is_first = 1;
#ifdef LOG
        printf ("video_out: get_next_video_frame first_frame_reached\n");
#endif
      }
      pthread_mutex_unlock (&stream->first_frame_lock);
    }
    pthread_mutex_unlock(&this->streams_lock);

    vo_frame_inc_lock( img );
    vo_append_to_img_buf_queue (this->display_img_buf_queue, img);

  } else {
#ifdef LOG
    printf ("video_out: bad_frame\n");
#endif
    pthread_mutex_lock( &stream->current_extra_info_lock );
    extra_info_merge( stream->current_extra_info, img->extra_info );
    pthread_mutex_unlock( &stream->current_extra_info_lock );

    this->num_frames_skipped++;
  }

  /*
   * performance measurement
   */

  if ((this->num_frames_delivered % 200) == 0 && this->num_frames_delivered) {
    int send_event;

    if( (100 * this->num_frames_skipped / this->num_frames_delivered) >
         this->warn_skipped_threshold ||
        (100 * this->num_frames_discarded / this->num_frames_delivered) >
         this->warn_discarded_threshold )
      this->warn_threshold_exceeded++;
    else
      this->warn_threshold_exceeded = 0;

    /* make sure threshold has being consistently exceeded - 5 times in a row
     * (that is, this is not just a small burst of dropped frames).
     */
    send_event = (this->warn_threshold_exceeded == 5 && 
                  !this->warn_threshold_event_sent);
    this->warn_threshold_event_sent += send_event;

    pthread_mutex_lock(&this->streams_lock);
    for (stream = xine_list_first_content(this->streams); stream;
         stream = xine_list_next_content(this->streams)) {
      stream->stream_info[XINE_STREAM_INFO_SKIPPED_FRAMES] =
        1000 * this->num_frames_skipped / this->num_frames_delivered;
      stream->stream_info[XINE_STREAM_INFO_DISCARDED_FRAMES] =
        1000 * this->num_frames_discarded / this->num_frames_delivered;

      /* we send XINE_EVENT_DROPPED_FRAMES to frontend to warn that
       * number of skipped or discarded frames is too high.
       */
      if( send_event ) {
         xine_event_t          event;
         xine_dropped_frames_t data;

         event.type        = XINE_EVENT_DROPPED_FRAMES;
         event.stream      = stream;
         event.data        = &data;
         event.data_length = sizeof(data);
         data.skipped_frames = stream->stream_info[XINE_STREAM_INFO_SKIPPED_FRAMES];
         data.skipped_threshold = this->warn_skipped_threshold * 10;
         data.discarded_frames = stream->stream_info[XINE_STREAM_INFO_DISCARDED_FRAMES];
         data.discarded_threshold = this->warn_discarded_threshold * 10;
         xine_event_send(stream, &event);
      }
    }
    pthread_mutex_unlock(&this->streams_lock);


    if( this->num_frames_skipped || this->num_frames_discarded ) {
      xine_log(this->xine, XINE_LOG_MSG,
	       _("%d frames delivered, %d frames skipped, %d frames discarded\n"), 
	       this->num_frames_delivered, 
	       this->num_frames_skipped, this->num_frames_discarded);
    }

    this->num_frames_delivered = 0;
    this->num_frames_discarded = 0;
    this->num_frames_skipped   = 0;
  }
  
  return frames_to_skip;
}
示例#3
0
static int demux_mve_send_chunk(demux_plugin_t *this_gen) {
  demux_mve_t *this = (demux_mve_t *) this_gen;

  buf_element_t *buf = NULL;
  int64_t text_pts = 0;
  int64_t audio_pts = 0;
  unsigned char preamble[PREAMBLE_SIZE];
  unsigned int chunk_tag;
  unsigned int chunk_size;
  off_t current_file_pos;
  unsigned int palette_number;

  /* compensate for the initial data in the file */
  current_file_pos = this->input->get_current_pos(this->input) -
    this->data_start;

  if (this->input->read(this->input, preamble, PREAMBLE_SIZE) !=
    PREAMBLE_SIZE)
    this->status = DEMUX_FINISHED;
  else {
    chunk_tag = _X_BE_32(&preamble[0]);
    /* round up to the nearest even size */
    chunk_size = (_X_BE_32(&preamble[4]) + 1) & (~1);

    if (chunk_tag == BRCH_TAG) {
      /* empty chunk; do nothing */
    } else if (chunk_tag == SHOT_TAG) {
      if (this->seek_flag) {
        /* reset pts */
        this->video_pts = 0;
        _x_demux_control_newpts(this->stream, 0, BUF_FLAG_SEEK);
        this->seek_flag = 0;
      } else {
        /* record the offset of the SHOT chunk */
        if (this->current_shot < this->number_of_shots) {
	  this->shot_offsets[this->current_shot] =
            this->input->get_current_pos(this->input) - PREAMBLE_SIZE;
        }
      }
      this->current_shot++;

      /* this is the start of a new shot; send a new palette */
      if (this->input->read(this->input, preamble, 4) != 4) {
        this->status = DEMUX_FINISHED;
        return this->status;
      }
      palette_number = _X_LE_32(&preamble[0]);

      if (palette_number >= this->number_of_shots) {
        xine_log(this->stream->xine, XINE_LOG_MSG,
		 _("demux_wc3movie: SHOT chunk referenced invalid palette (%d >= %d)\n"),
          palette_number, this->number_of_shots);
        this->status = DEMUX_FINISHED;
        return this->status;
      }

      buf = this->video_fifo->buffer_pool_alloc (this->video_fifo);
      buf->decoder_flags = BUF_FLAG_SPECIAL|BUF_FLAG_HEADER;
      buf->decoder_info[1] = BUF_SPECIAL_PALETTE;
      buf->decoder_info[2] = PALETTE_SIZE;
      buf->decoder_info_ptr[2] = &this->palettes[PALETTE_SIZE * palette_number];
      buf->size = 0;
      buf->type = BUF_VIDEO_WC3;
      this->video_fifo->put (this->video_fifo, buf);

    } else if (chunk_tag == AUDI_TAG) {
      if( this->audio_fifo ) {
        audio_pts = this->video_pts - WC3_PTS_INC;

        while (chunk_size) {
          buf = this->audio_fifo->buffer_pool_alloc (this->audio_fifo);
          buf->type = BUF_AUDIO_LPCM_LE;
          if( this->data_size )
            buf->extra_info->input_normpos = (int)( (double) current_file_pos * 65535 / this->data_size);
          buf->extra_info->input_time = audio_pts / 90;
          buf->pts = audio_pts;

          if (chunk_size > buf->max_size)
            buf->size = buf->max_size;
          else
            buf->size = chunk_size;
          chunk_size -= buf->size;

          if (this->input->read(this->input, buf->content, buf->size) !=
            buf->size) {
            buf->free_buffer(buf);
            this->status = DEMUX_FINISHED;
            break;
          }

          if (!chunk_size)
            buf->decoder_flags |= BUF_FLAG_FRAME_END;

          this->audio_fifo->put (this->audio_fifo, buf);
        }
      }else{
        this->input->seek(this->input, chunk_size, SEEK_CUR);
      }
    } else if (chunk_tag == VGA_TAG) {
      while (chunk_size) {
        buf = this->video_fifo->buffer_pool_alloc (this->video_fifo);
        buf->type = BUF_VIDEO_WC3;
        if( this->data_size )
          buf->extra_info->input_normpos = (int)( (double) current_file_pos * 65535 / this->data_size);
        buf->extra_info->input_time = this->video_pts / 90;
        buf->pts = this->video_pts;

        if (chunk_size > buf->max_size)
          buf->size = buf->max_size;
        else
          buf->size = chunk_size;
        chunk_size -= buf->size;

        if (this->input->read(this->input, buf->content, buf->size) !=
          buf->size) {
          buf->free_buffer(buf);
          this->status = DEMUX_FINISHED;
          break;
        }

        if (!chunk_size)
          buf->decoder_flags |= BUF_FLAG_FRAME_END;

        this->video_fifo->put (this->video_fifo, buf);
      }
      this->video_pts += WC3_PTS_INC;
    } else if (chunk_tag == TEXT_TAG) {
      text_pts = this->video_pts - WC3_PTS_INC;

      /* unhandled thus far */
      this->input->seek(this->input, chunk_size, SEEK_CUR);
    } else {
      /* report an unknown chunk and skip it */
      lprintf("encountered unknown chunk: %c%c%c%c\n",
        (chunk_tag >> 24) & 0xFF,
        (chunk_tag >> 16) & 0xFF,
        (chunk_tag >>  8) & 0xFF,
        (chunk_tag >>  0) & 0xFF);
      this->input->seek(this->input, chunk_size, SEEK_CUR);
    }
  }

  return this->status;
}
示例#4
0
/* Open a FILM file
 * This function is called from the _open() function of this demuxer.
 * It returns 1 if FILM file was opened successfully. */
static int open_film_file(demux_film_t *film) {

  unsigned char *film_header;
  unsigned int film_header_size;
  unsigned char scratch[16];
  unsigned int chunk_type;
  unsigned int chunk_size;
  unsigned int i, j;
  unsigned int audio_byte_count = 0;
  int64_t largest_pts = 0;
  unsigned int pts;

  /* initialize structure fields */
  film->bih.biWidth = 0;
  film->bih.biHeight = 0;
  film->video_codec = 0;
  film->sample_rate = 0;
  film->audio_bits = 0;
  film->audio_channels = 0;

  /* get the signature, header length and file version */
  if (_x_demux_read_header(film->input, scratch, 16) != 16)
    return 0;

  /* FILM signature correct? */
  if (!_x_is_fourcc(scratch, "FILM"))
    return 0;

  llprintf(DEBUG_FILM_LOAD, "found 'FILM' signature\n");

  /* file is qualified; skip over the header bytes in the stream */
  film->input->seek(film->input, 16, SEEK_SET);

  /* header size = header size - 16-byte FILM signature */
  film_header_size = _X_BE_32(&scratch[4]) - 16;
  film_header = malloc(film_header_size);
  if (!film_header)
    return 0;
  memcpy(film->version, &scratch[8], 4);
  llprintf(DEBUG_FILM_LOAD, "0x%X header bytes, version %c%c%c%c\n",
    film_header_size,
    film->version[0],
    film->version[1],
    film->version[2],
    film->version[3]);

  /* load the rest of the FILM header */
  if (film->input->read(film->input, film_header, film_header_size) !=
    film_header_size) {
    free (film->interleave_buffer);
    free (film->sample_table);
    free (film_header);
    return 0;
  }

  /* get the starting offset */
  film->data_start = film->input->get_current_pos(film->input);
  film->data_size = film->input->get_length(film->input) - film->data_start;

  /* traverse the FILM header */
  i = 0;
  while (i < film_header_size) {
    chunk_type = _X_BE_32(&film_header[i]);
    chunk_size = _X_BE_32(&film_header[i + 4]);

    /* sanity check the chunk size */
    if (i + chunk_size > film_header_size) {
      xine_log(film->stream->xine, XINE_LOG_MSG, _("invalid FILM chunk size\n"));
      free (film->interleave_buffer);
      free (film->sample_table);
      free (film_header);
      return 0;
    }

    switch(chunk_type) {
    case FDSC_TAG:
      llprintf(DEBUG_FILM_LOAD, "parsing FDSC chunk\n");

      /* always fetch the video information */
      film->bih.biWidth = _X_BE_32(&film_header[i + 16]);
      film->bih.biHeight = _X_BE_32(&film_header[i + 12]);
      film->video_codec = *(uint32_t *)&film_header[i + 8];
      film->video_type = _x_fourcc_to_buf_video(*(uint32_t *)&film_header[i + 8]);

      if( !film->video_type )
      {
        film->video_type = BUF_VIDEO_UNKNOWN;
        _x_report_video_fourcc (film->stream->xine, LOG_MODULE,
				*(uint32_t *)&film_header[i + 8]);
      }

      /* fetch the audio information if the chunk size checks out */
      if (chunk_size == 32) {
        film->audio_channels = film_header[21];
        film->audio_bits = film_header[22];
        film->sample_rate = _X_BE_16(&film_header[24]);
      } else {
        /* If the FDSC chunk is not 32 bytes long, this is an early FILM
         * file. Make a few assumptions about the audio parms based on the
         * video codec used in the file. */
        if (film->video_type == BUF_VIDEO_CINEPAK) {
          film->audio_channels = 1;
          film->audio_bits = 8;
          film->sample_rate = 22050;
        } else if (film->video_type == BUF_VIDEO_SEGA) {
          film->audio_channels = 1;
          film->audio_bits = 8;
          film->sample_rate = 16000;
        }
      }
      if (film->sample_rate)
        film->audio_type = BUF_AUDIO_LPCM_BE;
      else
        film->audio_type = 0;

      if (film->video_type)
        llprintf(DEBUG_FILM_LOAD, "video: %dx%d %c%c%c%c\n",
          film->bih.biWidth, film->bih.biHeight,
          film_header[i + 8],
          film_header[i + 9],
          film_header[i + 10],
          film_header[i + 11]);
      else
        llprintf(DEBUG_FILM_LOAD, "no video\n");

      if (film->audio_type)
        llprintf(DEBUG_FILM_LOAD, "audio: %d Hz, %d channels, %d bits PCM\n",
          film->sample_rate,
          film->audio_channels,
          film->audio_bits);
      else
        llprintf(DEBUG_FILM_LOAD, "no audio\n");

      break;

    case STAB_TAG:
      llprintf(DEBUG_FILM_LOAD, "parsing STAB chunk\n");

      /* load the sample table */
      free(film->sample_table);
      film->frequency = _X_BE_32(&film_header[i + 8]);
      film->sample_count = _X_BE_32(&film_header[i + 12]);
      film->sample_table =
        xine_xcalloc(film->sample_count, sizeof(film_sample_t));
      if (!film->sample_table)
        goto film_abort;
      for (j = 0; j < film->sample_count; j++) {

        film->sample_table[j].sample_offset =
          _X_BE_32(&film_header[(i + 16) + j * 16 + 0])
          + film_header_size + 16;
        film->sample_table[j].sample_size =
          _X_BE_32(&film_header[(i + 16) + j * 16 + 4]);
        pts =
          _X_BE_32(&film_header[(i + 16) + j * 16 + 8]);
        film->sample_table[j].duration =
          _X_BE_32(&film_header[(i + 16) + j * 16 + 12]);

        if (pts == 0xFFFFFFFF) {

          film->sample_table[j].audio = 1;
          film->sample_table[j].keyframe = 0;

          /* figure out audio pts */
          film->sample_table[j].pts = audio_byte_count;
          film->sample_table[j].pts *= 90000;
          film->sample_table[j].pts /=
            (film->sample_rate * film->audio_channels * (film->audio_bits / 8));
          audio_byte_count += film->sample_table[j].sample_size;

        } else {

          /* figure out video pts, duration, and keyframe */
          film->sample_table[j].audio = 0;

          /* keyframe if top bit of this field is 0 */
          if (pts & 0x80000000)
            film->sample_table[j].keyframe = 0;
          else
            film->sample_table[j].keyframe = 1;

          /* remove the keyframe bit */
          film->sample_table[j].pts = pts & 0x7FFFFFFF;

          /* compute the pts */
          film->sample_table[j].pts *= 90000;
          film->sample_table[j].pts /= film->frequency;

          /* compute the frame duration */
          film->sample_table[j].duration *= 90000;
          film->sample_table[j].duration /= film->frequency;

        }

        /* use this to calculate the total running time of the file */
        if (film->sample_table[j].pts > largest_pts)
          largest_pts = film->sample_table[j].pts;

        llprintf(DEBUG_FILM_LOAD, "sample %4d @ %8" PRIxMAX ", %8X bytes, %s, pts %" PRId64 ", duration %" PRId64 "%s\n",
          j,
          (intmax_t)film->sample_table[j].sample_offset,
          film->sample_table[j].sample_size,
          (film->sample_table[j].audio) ? "audio" : "video",
          film->sample_table[j].pts,
          film->sample_table[j].duration,
          (film->sample_table[j].keyframe) ? " (keyframe)" : "");
      }

      /*
       * in some files, this chunk length does not account for the 16-byte
       * chunk preamble; watch for it
       */
      if (chunk_size == film->sample_count * 16)
        i += 16;

      /* allocate enough space in the interleave preload buffer for the
       * first chunk (which will be more than enough for successive chunks) */
      if (film->audio_type) {
	free(film->interleave_buffer);
        film->interleave_buffer = calloc(1, film->sample_table[0].sample_size);
        if (!film->interleave_buffer)
          goto film_abort;
      }
      break;

    default:
      xine_log(film->stream->xine, XINE_LOG_MSG, _("unrecognized FILM chunk\n"));
    film_abort:
      free (film->interleave_buffer);
      free (film->sample_table);
      free (film_header);
      return 0;
    }

    i += chunk_size;
  }

  film->total_time = largest_pts / 90;

  free (film_header);

  return 1;
}
示例#5
0
static void *audio_decoder_loop (void *stream_gen) {

  buf_element_t   *buf = NULL;
  buf_element_t   *first_header = NULL;
  buf_element_t   *last_header = NULL;
  int              replaying_headers = 0;
  xine_stream_t   *stream = (xine_stream_t *) stream_gen;
  xine_ticket_t   *running_ticket = stream->xine->port_ticket;
  int              running = 1;
  int              prof_audio_decode = -1;
  uint32_t         buftype_unknown = 0;
  int              audio_channel_user = stream->audio_channel_user;

  if (prof_audio_decode == -1)
    prof_audio_decode = xine_profiler_allocate_slot ("audio decoder/output");

  while (running) {

    lprintf ("audio_loop: waiting for package...\n");

    if( !replaying_headers )
      buf = stream->audio_fifo->get (stream->audio_fifo);

    lprintf ("audio_loop: got package pts = %"PRId64", type = %08x\n", buf->pts, buf->type);

    _x_extra_info_merge( stream->audio_decoder_extra_info, buf->extra_info );
    stream->audio_decoder_extra_info->seek_count = stream->video_seek_count;

    switch (buf->type) {

    case BUF_CONTROL_HEADERS_DONE:
      pthread_mutex_lock (&stream->counter_lock);
      stream->header_count_audio++;
      pthread_cond_broadcast (&stream->counter_changed);
      pthread_mutex_unlock (&stream->counter_lock);
      break;

    case BUF_CONTROL_START:

      lprintf ("start\n");

      /* decoder dispose might call port functions */
      running_ticket->acquire(running_ticket, 0);

      if (stream->audio_decoder_plugin) {

	lprintf ("close old decoder\n");

	stream->keep_ao_driver_open = !!(buf->decoder_flags & BUF_FLAG_GAPLESS_SW);
	_x_free_audio_decoder (stream, stream->audio_decoder_plugin);
	stream->audio_decoder_plugin = NULL;
	stream->audio_track_map_entries = 0;
	stream->audio_type = 0;
	stream->keep_ao_driver_open = 0;
      }

      running_ticket->release(running_ticket, 0);

      if( !(buf->decoder_flags & BUF_FLAG_GAPLESS_SW) )
        stream->metronom->handle_audio_discontinuity (stream->metronom, DISC_STREAMSTART, 0);

      buftype_unknown = 0;
      break;

    case BUF_CONTROL_END:

      /* free all held header buffers, see comments below */
      if( first_header ) {
        buf_element_t  *cur, *next;

        cur = first_header;
        while( cur ) {
          next = cur->next;
          cur->free_buffer (cur);
          cur = next;
        }
        first_header = last_header = NULL;
      }

      /*
       * wait the output fifos to run dry before sending the notification event
       * to the frontend. this test is only valid if there is only a single
       * stream attached to the current output port.
       */
      while(1) {
        int num_bufs, num_streams;

        running_ticket->acquire(running_ticket, 0);
        num_bufs = stream->audio_out->get_property(stream->audio_out, AO_PROP_BUFS_IN_FIFO);
        num_streams = stream->audio_out->get_property(stream->audio_out, AO_PROP_NUM_STREAMS);
        running_ticket->release(running_ticket, 0);

        if( num_bufs > 0 && num_streams == 1 && !stream->early_finish_event)
          xine_usec_sleep (10000);
        else
          break;
      }

      /* wait for video to reach this marker, if necessary */
      pthread_mutex_lock (&stream->counter_lock);

      stream->finished_count_audio++;

      lprintf ("reached end marker # %d\n", stream->finished_count_audio);

      pthread_cond_broadcast (&stream->counter_changed);

      if (stream->video_thread_created) {
        while (stream->finished_count_video < stream->finished_count_audio) {
          struct timeval tv;
          struct timespec ts;
          gettimeofday(&tv, NULL);
          ts.tv_sec  = tv.tv_sec + 1;
          ts.tv_nsec = tv.tv_usec * 1000;
          /* use timedwait to workaround buggy pthread broadcast implementations */
          pthread_cond_timedwait (&stream->counter_changed, &stream->counter_lock, &ts);
        }
      }
      pthread_mutex_unlock (&stream->counter_lock);
      stream->audio_channel_auto = -1;

      break;

    case BUF_CONTROL_QUIT:
      /* decoder dispose might call port functions */
      running_ticket->acquire(running_ticket, 0);

      if (stream->audio_decoder_plugin) {
	_x_free_audio_decoder (stream, stream->audio_decoder_plugin);
	stream->audio_decoder_plugin = NULL;
	stream->audio_track_map_entries = 0;
	stream->audio_type = 0;
      }

      running_ticket->release(running_ticket, 0);
      running = 0;
      break;

    case BUF_CONTROL_NOP:
      break;

    case BUF_CONTROL_RESET_DECODER:
      lprintf ("reset\n");

      _x_extra_info_reset( stream->audio_decoder_extra_info );
      if (stream->audio_decoder_plugin) {
	running_ticket->acquire(running_ticket, 0);
	stream->audio_decoder_plugin->reset (stream->audio_decoder_plugin);
	running_ticket->release(running_ticket, 0);
      }
      break;

    case BUF_CONTROL_DISCONTINUITY:
      if (stream->audio_decoder_plugin) {
	running_ticket->acquire(running_ticket, 0);
	stream->audio_decoder_plugin->discontinuity (stream->audio_decoder_plugin);
	running_ticket->release(running_ticket, 0);
      }

      stream->metronom->handle_audio_discontinuity (stream->metronom, DISC_RELATIVE, buf->disc_off);
      break;

    case BUF_CONTROL_NEWPTS:
      if (stream->audio_decoder_plugin) {
	running_ticket->acquire(running_ticket, 0);
	stream->audio_decoder_plugin->discontinuity (stream->audio_decoder_plugin);
	running_ticket->release(running_ticket, 0);
      }

      if (buf->decoder_flags & BUF_FLAG_SEEK) {
        stream->metronom->handle_audio_discontinuity (stream->metronom, DISC_STREAMSEEK, buf->disc_off);
      } else {
        stream->metronom->handle_audio_discontinuity (stream->metronom, DISC_ABSOLUTE, buf->disc_off);
      }
      break;

    case BUF_CONTROL_AUDIO_CHANNEL:
      {
	xprintf(stream->xine, XINE_VERBOSITY_DEBUG,
		"audio_decoder: suggested switching to stream_id %02x\n", buf->decoder_info[0]);
	stream->audio_channel_auto = buf->decoder_info[0] & 0xff;
      }
      break;

    case BUF_CONTROL_RESET_TRACK_MAP:
      if (stream->audio_track_map_entries)
      {
        xine_event_t ui_event;

        stream->audio_track_map_entries = 0;

        ui_event.type        = XINE_EVENT_UI_CHANNELS_CHANGED;
        ui_event.data_length = 0;
        xine_event_send(stream, &ui_event);
      }
      break;


    default:

      if (_x_stream_info_get(stream, XINE_STREAM_INFO_IGNORE_AUDIO))
        break;

      xine_profiler_start_count (prof_audio_decode);

      running_ticket->acquire(running_ticket, 0);

      if ( (buf->type & 0xFF000000) == BUF_AUDIO_BASE ) {

	uint32_t audio_type = 0;
	int      i,j;
	uint32_t chan=buf->type&0x0000FFFF;

	/*
        printf("audio_decoder: buf_type=%08x auto=%08x user=%08x\n",
	       buf->type,
	       stream->audio_channel_auto,
	       audio_channel_user);
	       */

        /* update track map */

        i = 0;
        while ( (i<stream->audio_track_map_entries) && ((stream->audio_track_map[i]&0x0000FFFF)<chan) )
          i++;

        if ( (i==stream->audio_track_map_entries)
	     || ((stream->audio_track_map[i]&0x0000FFFF)!=chan) ) {
          xine_event_t  ui_event;

          j = stream->audio_track_map_entries;

          if (j >= 50)
            break;

          while (j>i) {
            stream->audio_track_map[j] = stream->audio_track_map[j-1];
            j--;
          }
          stream->audio_track_map[i] = buf->type;
          stream->audio_track_map_entries++;
          /* implicit channel change - reopen decoder below */
          if ((i == 0) && (audio_channel_user == -1) && (stream->audio_channel_auto < 0))
            stream->audio_decoder_streamtype = -1;

	  ui_event.type        = XINE_EVENT_UI_CHANNELS_CHANGED;
	  ui_event.data_length = 0;
	  xine_event_send (stream, &ui_event);
        }

	/* find out which audio type to decode */

	lprintf ("audio_channel_user = %d, map[0]=%08x\n",
		 audio_channel_user,
		 stream->audio_track_map[0]);

	if (audio_channel_user > -2) {

	  if (audio_channel_user == -1) {

	    /* auto */

	    lprintf ("audio_channel_auto = %d\n", stream->audio_channel_auto);

	    if (stream->audio_channel_auto>=0) {

	      if ((buf->type & 0xFF) == stream->audio_channel_auto) {
		audio_type = buf->type;
	      } else
		audio_type = -1;

	    } else
	      audio_type = stream->audio_track_map[0];

	  } else {
	    if (audio_channel_user <= stream->audio_track_map_entries)
	      audio_type = stream->audio_track_map[audio_channel_user];
	    else
	      audio_type = -1;
	  }

	  /* now, decode stream buffer if it's the right audio type */

	  if (buf->type == audio_type) {

	    int streamtype = (buf->type>>16) & 0xFF;

	    /* close old decoder of audio type has changed */

            if( buf->type != buftype_unknown &&
                (stream->audio_decoder_streamtype != streamtype ||
                !stream->audio_decoder_plugin) ) {

              if (stream->audio_decoder_plugin) {
                _x_free_audio_decoder (stream, stream->audio_decoder_plugin);
              }

              stream->audio_decoder_streamtype = streamtype;
              stream->audio_decoder_plugin = _x_get_audio_decoder (stream, streamtype);

              _x_stream_info_set(stream, XINE_STREAM_INFO_AUDIO_HANDLED,
				 (stream->audio_decoder_plugin != NULL));
            }

	    if (audio_type != stream->audio_type) {

	      if (stream->audio_decoder_plugin) {
		xine_event_t event;

		stream->audio_type = audio_type;

		event.type         = XINE_EVENT_UI_CHANNELS_CHANGED;
		event.data_length  = 0;
		xine_event_send(stream, &event);
	      }
	    }

	    /* finally - decode data */

	    if (stream->audio_decoder_plugin)
	      stream->audio_decoder_plugin->decode_data (stream->audio_decoder_plugin, buf);

	    if (buf->type != buftype_unknown &&
	        !_x_stream_info_get(stream, XINE_STREAM_INFO_AUDIO_HANDLED)) {
	      xine_log (stream->xine, XINE_LOG_MSG,
			_("audio_decoder: no plugin available to handle '%s'\n"), _x_buf_audio_name( buf->type ) );

              if( !_x_meta_info_get(stream, XINE_META_INFO_AUDIOCODEC) )
                _x_meta_info_set_utf8(stream, XINE_META_INFO_AUDIOCODEC, _x_buf_audio_name( buf->type ));

	      buftype_unknown = buf->type;

	      /* fatal error - dispose plugin */
	      if (stream->audio_decoder_plugin) {
	        _x_free_audio_decoder (stream, stream->audio_decoder_plugin);
	        stream->audio_decoder_plugin = NULL;
	      }
	    }
	  }
	}
      } else if( buf->type != buftype_unknown ) {
示例#6
0
static void *audio_decoder_loop (void *stream_gen) {

  buf_element_t   *buf;
  xine_stream_t   *stream = (xine_stream_t *) stream_gen;
  int              running = 1;
  int              prof_audio_decode = -1;
  uint32_t         buftype_unknown = 0;

  if (prof_audio_decode == -1)
    prof_audio_decode = xine_profiler_allocate_slot ("audio decoder/output");

  while (running) {

#ifdef LOG
    printf ("audio_loop: waiting for package...\n");  
#endif

    buf = stream->audio_fifo->get (stream->audio_fifo);

    
#ifdef LOG
    printf ("audio_loop: got package pts = %lld, type = %08x\n", 
	    buf->pts, buf->type); 
#endif    

    extra_info_merge( stream->audio_decoder_extra_info, buf->extra_info );
    stream->audio_decoder_extra_info->seek_count = stream->video_seek_count;
      
    /* check for a new port to use */
    if (stream->next_audio_port) {
      uint32_t bits, rate;
      int mode;
      
      /* noone is allowed to modify the next port from now on */
      pthread_mutex_lock(&stream->next_audio_port_lock);
      if (stream->audio_out->status(stream->audio_out, stream, &bits, &rate, &mode)) {
        /* register our stream at the new output port */
        stream->next_audio_port->open(stream->next_audio_port, stream, bits, rate, mode);
        stream->audio_out->close(stream->audio_out, stream);
      }
      stream->audio_out = stream->next_audio_port;
      stream->next_audio_port = NULL;
      pthread_mutex_unlock(&stream->next_audio_port_lock);
      pthread_cond_broadcast(&stream->next_audio_port_wired);
    }

    switch (buf->type) {
      
    case BUF_CONTROL_HEADERS_DONE:
      pthread_mutex_lock (&stream->counter_lock);
      stream->header_count_audio++;
      pthread_cond_broadcast (&stream->counter_changed);
      pthread_mutex_unlock (&stream->counter_lock);
      break;

    case BUF_CONTROL_START:

#ifdef LOG
      printf ("audio_decoder: start\n");
#endif

      if (stream->audio_decoder_plugin) {

#ifdef LOG
	printf ("audio_decoder: close old decoder\n");
#endif	

	free_audio_decoder (stream, stream->audio_decoder_plugin);
	stream->audio_decoder_plugin = NULL;
	stream->audio_track_map_entries = 0;
	stream->audio_type = 0;
      }
      
      stream->metronom->handle_audio_discontinuity (stream->metronom, DISC_STREAMSTART, 0);
      
      buftype_unknown = 0;
      break;
      
    case BUF_CONTROL_END:

      /* wait for video to reach this marker, if necessary */
      
      pthread_mutex_lock (&stream->counter_lock);

      stream->finished_count_audio++;

#ifdef LOG
      printf ("audio_decoder: reached end marker # %d\n", 
	      stream->finished_count_audio);
#endif

      pthread_cond_broadcast (&stream->counter_changed);

      while (stream->finished_count_video < stream->finished_count_audio) {
        struct timeval tv;
        struct timespec ts;
        gettimeofday(&tv, NULL);
        ts.tv_sec  = tv.tv_sec + 1;
        ts.tv_nsec = tv.tv_usec * 1000;
        /* use timedwait to workaround buggy pthread broadcast implementations */
        pthread_cond_timedwait (&stream->counter_changed, &stream->counter_lock, &ts);
      }
          
      pthread_mutex_unlock (&stream->counter_lock);

      stream->audio_channel_auto = -1;

      break;
      
    case BUF_CONTROL_QUIT:
      if (stream->audio_decoder_plugin) {
	free_audio_decoder (stream, stream->audio_decoder_plugin);
	stream->audio_decoder_plugin = NULL;
	stream->audio_track_map_entries = 0;
	stream->audio_type = 0;
      }
      running = 0;
      break;

    case BUF_CONTROL_NOP:
      break;

    case BUF_CONTROL_RESET_DECODER:
#ifdef LOG
      printf ("audio_decoder: reset\n");
#endif
      extra_info_reset( stream->audio_decoder_extra_info );
      if (stream->audio_decoder_plugin)
        stream->audio_decoder_plugin->reset (stream->audio_decoder_plugin);
      break;
          
    case BUF_CONTROL_DISCONTINUITY:
      if (stream->audio_decoder_plugin)
        stream->audio_decoder_plugin->discontinuity (stream->audio_decoder_plugin);
      stream->metronom->handle_audio_discontinuity (stream->metronom, DISC_RELATIVE, buf->disc_off);
      break;

    case BUF_CONTROL_NEWPTS:
      if (stream->audio_decoder_plugin)
        stream->audio_decoder_plugin->discontinuity (stream->audio_decoder_plugin);
      if (buf->decoder_flags && BUF_FLAG_SEEK) {
        stream->metronom->handle_audio_discontinuity (stream->metronom, DISC_STREAMSEEK, buf->disc_off);
      } else {
        stream->metronom->handle_audio_discontinuity (stream->metronom, DISC_ABSOLUTE, buf->disc_off);
      }
      break;

    case BUF_CONTROL_AUDIO_CHANNEL:
      {
	if (stream->xine->verbosity >= XINE_VERBOSITY_DEBUG)
	  printf ("audio_decoder: suggested switching to stream_id %02x\n",
		  buf->decoder_info[0]);
	stream->audio_channel_auto = buf->decoder_info[0] & 0xff;
      }
      break;

    default:

      if (stream->stream_info[XINE_STREAM_INFO_IGNORE_AUDIO])
        break;

      xine_profiler_start_count (prof_audio_decode);

      if ( (buf->type & 0xFF000000) == BUF_AUDIO_BASE ) {
	
	uint32_t audio_type = 0;
	int      i,j;

	/*
        printf("audio_decoder: buf_type=%08x auto=%08x user=%08x\n",
	       buf->type, 
	       stream->audio_channel_auto,
	       stream->audio_channel_user);
	       */

        /* update track map */
        
        i = 0;
        while ( (i<stream->audio_track_map_entries) && (stream->audio_track_map[i]<buf->type) ) 
          i++;
        
        if ( (i==stream->audio_track_map_entries) 
	     || (stream->audio_track_map[i] != buf->type) ) {
          
          j = stream->audio_track_map_entries;

          if (j >= 50)
            break;

          while (j>i) {
            stream->audio_track_map[j] = stream->audio_track_map[j-1];
            j--;
          }
          stream->audio_track_map[i] = buf->type;
          stream->audio_track_map_entries++;
        }

	/* find out which audio type to decode */

#ifdef LOG
	printf ("audio_decoder: audio_channel_user = %d, map[0]=%08x\n",
		stream->audio_channel_user,
		stream->audio_track_map[0]);
#endif

	if (stream->audio_channel_user > -2) {

	  if (stream->audio_channel_user == -1) {

	    /* auto */

#ifdef LOG
	    printf ("audio_decoder: audio_channel_auto = %d\n",
		    stream->audio_channel_auto);
#endif

	    if (stream->audio_channel_auto>=0) {
 
	      if ((buf->type & 0xFF) == stream->audio_channel_auto) {
		audio_type = buf->type;
	      } else
		audio_type = -1;

	    } else
	      audio_type = stream->audio_track_map[0];

	  } else {
	    if (stream->audio_channel_user <= stream->audio_track_map_entries)
	      audio_type = stream->audio_track_map[stream->audio_channel_user];
	    else
	      audio_type = -1;
	  }

	  /* now, decode stream buffer if it's the right audio type */
	  
	  if (buf->type == audio_type) {
	    
	    int streamtype = (buf->type>>16) & 0xFF;

	    /* close old decoder of audio type has changed */
        
            if( buf->type != buftype_unknown && 
                (stream->audio_decoder_streamtype != streamtype ||
                !stream->audio_decoder_plugin) ) {
              
              if (stream->audio_decoder_plugin) {
                free_audio_decoder (stream, stream->audio_decoder_plugin);
              }
              
              stream->audio_decoder_streamtype = streamtype;
              stream->audio_decoder_plugin = get_audio_decoder (stream, streamtype);
              
              stream->stream_info[XINE_STREAM_INFO_AUDIO_HANDLED] = 
                (stream->audio_decoder_plugin != NULL);
            }
	    
	    if (audio_type != stream->audio_type) {
	      
	      if (stream->audio_decoder_plugin) {
		xine_event_t event;

		stream->audio_type = audio_type;

		event.type         = XINE_EVENT_UI_CHANNELS_CHANGED;
		event.data_length  = 0;
		xine_event_send(stream, &event);
	      }
	    }
	    
	    /* finally - decode data */
	    
	    if (stream->audio_decoder_plugin) 
	      stream->audio_decoder_plugin->decode_data (stream->audio_decoder_plugin, buf);
       
	    if (buf->type != buftype_unknown && 
	        !stream->stream_info[XINE_STREAM_INFO_AUDIO_HANDLED]) {
	      xine_log (stream->xine, XINE_LOG_MSG, 
			"audio_decoder: no plugin available to handle '%s'\n",
		        buf_audio_name( buf->type ) );
              
              if( !stream->meta_info[XINE_META_INFO_AUDIOCODEC] )
                stream->meta_info[XINE_META_INFO_AUDIOCODEC] 
                  = strdup (buf_audio_name( buf->type ));
                
	      buftype_unknown = buf->type;

	      /* fatal error - dispose plugin */       
	      if (stream->audio_decoder_plugin) {
	        free_audio_decoder (stream, stream->audio_decoder_plugin);
	        stream->audio_decoder_plugin = NULL;
	      }
	    }
	  }
	} 
      } else if( buf->type != buftype_unknown ) {