void xine_cue_point_event(xine_stream_t *stream, int64_t in_cur_time) { xine_event_t event; int next_time; int cur_time; int next_freq; xine_cue_point_data_t *cue_point; event.type=XINE_EVENT_CUE_POINT; event.data_length=sizeof(xine_cue_point_data_t); cur_time=(in_cur_time-stream->metronom->vpts_offset)/90; next_time=stream->org_next_cue_time; if (cur_time<next_time) return; pthread_mutex_lock (&stream->cue_points_lock); cue_point = (xine_cue_point_data_t *) xine_list_first_content(stream->cue_points); while (cue_point) { if (cue_point->cuetime<=cur_time && cue_point->cuetime>=next_time) { event.data=cue_point; cue_point->currtime=cur_time; xine_event_send(stream,&event); } else { next_freq=cue_point->frequency-((next_time-cue_point->cuetime) % cue_point->frequency); if (next_freq==cue_point->frequency) next_freq=0; /* printf("%d, %d, %d\n",next_time,next_freq,(cur_time-next_time));*/ if (cue_point->frequency!=0 && cue_point->cuetime<cur_time && (next_freq<=(cur_time-next_time))) { event.data=cue_point; cue_point->currtime=cur_time; xine_event_send(stream,&event); } } cue_point = (xine_cue_point_data_t *) xine_list_next_content(stream->cue_points); } pthread_mutex_unlock (&stream->cue_points_lock); xine_recalculate_next_cue_point(stream,in_cur_time); }
static void report_progress (xine_stream_t *stream, int p) { xine_event_t event; xine_progress_data_t prg; prg.description = _("Buffering..."); prg.percent = (p>100)?100:p; event.type = XINE_EVENT_PROGRESS; event.data = &prg; event.data_length = sizeof (xine_progress_data_t); xine_event_send (stream, &event); }
/** * @brief Callback function called when the information on the * context's sink is retrieved. * @param ctx Context which operation has succeeded * @param info Structure containing the sink's information * @param this_gen pulse_driver_t pointer for the PulseAudio output * instance. * * This function saves the volume field of the passed structure to the * @c cvolume variable of the output instance and send an update volume * event to the frontend. */ static void __xine_pa_sink_info_callback(pa_context *c, const pa_sink_input_info *info, int is_last, void *userdata) { pulse_driver_t *const this = (pulse_driver_t *) userdata; if (is_last < 0) { xprintf (this->xine, XINE_VERBOSITY_DEBUG, "audio_pulse_out: Failed to get sink input info: %s\n", pa_strerror(pa_context_errno(this->context))); return; } if (!info) return; this->cvolume = info->volume; this->swvolume = pa_cvolume_avg(&info->volume); #if PA_PROTOCOL_VERSION >= 11 /* PulseAudio 0.9.7 and newer */ this->muted = info->mute; #else this->muted = pa_cvolume_is_muted (&this->cvolume); #endif /* send update volume event to frontend */ xine_event_t event; xine_audio_level_data_t data; xine_stream_t *stream; xine_list_iterator_t ite; data.right = data.left = (int) (pa_sw_volume_to_linear(this->swvolume)*100); data.mute = this->muted; event.type = XINE_EVENT_AUDIO_LEVEL; event.data = &data; event.data_length = sizeof(data); pthread_mutex_lock(&this->xine->streams_lock); for(ite = xine_list_front(this->xine->streams); ite; ite = xine_list_next(this->xine->streams, ite)) { stream = xine_list_get_value(this->xine->streams, ite); event.stream = stream; xine_event_send(stream, &event); } pthread_mutex_unlock(&this->xine->streams_lock); }
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; }
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 ) {
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 ) {