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); } }
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 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; }
/* 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; }
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 ) {