static int fill_queue(struct af_instance *af, struct mp_audio *data, int offset) { af_scaletempo_t *s = af->priv; int bytes_in = mp_audio_psize(data) - offset; int offset_unchanged = offset; if (s->bytes_to_slide > 0) { if (s->bytes_to_slide < s->bytes_queued) { int bytes_move = s->bytes_queued - s->bytes_to_slide; memmove(s->buf_queue, s->buf_queue + s->bytes_to_slide, bytes_move); s->bytes_to_slide = 0; s->bytes_queued = bytes_move; } else { int bytes_skip; s->bytes_to_slide -= s->bytes_queued; bytes_skip = MPMIN(s->bytes_to_slide, bytes_in); s->bytes_queued = 0; s->bytes_to_slide -= bytes_skip; offset += bytes_skip; bytes_in -= bytes_skip; } } if (bytes_in > 0) { int bytes_copy = MPMIN(s->bytes_queue - s->bytes_queued, bytes_in); assert(bytes_copy >= 0); memcpy(s->buf_queue + s->bytes_queued, (int8_t *)data->planes[0] + offset, bytes_copy); s->bytes_queued += bytes_copy; offset += bytes_copy; } return offset - offset_unchanged; }
// Initialization and runtime control static int control(struct af_instance* af, int cmd, void* arg) { af_pan_t* s = af->priv; switch(cmd) { case AF_CONTROL_REINIT: // Sanity check if(!arg) return AF_ERROR; af->data->rate = ((struct mp_audio*)arg)->rate; mp_audio_set_format(af->data, AF_FORMAT_FLOAT); set_channels(af->data, s->nch ? s->nch: ((struct mp_audio*)arg)->nch); if((af->data->format != ((struct mp_audio*)arg)->format) || (af->data->bps != ((struct mp_audio*)arg)->bps)) { mp_audio_set_format((struct mp_audio*)arg, af->data->format); return AF_FALSE; } return AF_OK; case AF_CONTROL_SET_PAN_LEVEL: { int i; int ch = ((af_control_ext_t*)arg)->ch; float* level = ((af_control_ext_t*)arg)->arg; if (ch >= AF_NCH) return AF_FALSE; for(i=0; i<AF_NCH; i++) s->level[ch][i] = level[i]; return AF_OK; } case AF_CONTROL_SET_PAN_NOUT: // Reinit must be called after this function has been called // Sanity check if(((int*)arg)[0] <= 0 || ((int*)arg)[0] > AF_NCH) { MP_ERR(af, "The number of output channels must be" " between 1 and %i. Current value is %i\n",AF_NCH,((int*)arg)[0]); return AF_ERROR; } s->nch=((int*)arg)[0]; return AF_OK; case AF_CONTROL_SET_PAN_BALANCE: { float val = *(float*)arg; if (s->nch) return AF_ERROR; if (af->data->nch >= 2) { s->level[0][0] = MPMIN(1.f, 1.f - val); s->level[0][1] = MPMAX(0.f, val); s->level[1][0] = MPMAX(0.f, -val); s->level[1][1] = MPMIN(1.f, 1.f + val); } return AF_OK; } case AF_CONTROL_GET_PAN_BALANCE: if (s->nch) return AF_ERROR; *(float*)arg = s->level[0][1] - s->level[1][0]; return AF_OK; } return AF_UNKNOWN; }
// This is called both during init and at runtime. static int resize_cache(struct priv *s, int64_t size) { int64_t min_size = FILL_LIMIT * 4; int64_t max_size = ((size_t)-1) / 4; int64_t buffer_size = MPMIN(MPMAX(size, min_size), max_size); unsigned char *buffer = malloc(buffer_size); struct byte_meta *bm = calloc(buffer_size / BYTE_META_CHUNK_SIZE + 2, sizeof(struct byte_meta)); if (!buffer || !bm) { free(buffer); free(bm); return STREAM_ERROR; } if (s->buffer) { // Copy & free the old ringbuffer data. // If the buffer is too small, prefer to copy these regions: // 1. Data starting from read_filepos, until cache end size_t read_1 = read_buffer(s, buffer, buffer_size, s->read_filepos); // 2. then data from before read_filepos until cache start // (this one needs to be copied to the end of the ringbuffer) size_t read_2 = 0; if (s->min_filepos < s->read_filepos) { size_t copy_len = buffer_size - read_1; copy_len = MPMIN(copy_len, s->read_filepos - s->min_filepos); assert(copy_len + read_1 <= buffer_size); read_2 = read_buffer(s, buffer + buffer_size - copy_len, copy_len, s->read_filepos - copy_len); // This shouldn't happen, unless copy_len was computed incorrectly. assert(read_2 == copy_len); } // Set it up such that read_1 is at buffer pos 0, and read_2 wraps // around below it, so that it is located at the end of the buffer. s->min_filepos = s->read_filepos - read_2; s->max_filepos = s->read_filepos + read_1; s->offset = s->max_filepos - read_1; } else { cache_drop_contents(s); } free(s->buffer); free(s->bm); s->buffer_size = buffer_size; s->back_size = buffer_size / 2; s->buffer = buffer; s->bm = bm; s->idle = false; s->eof = false; //make sure that we won't wait from cache_fill //more data than it is allowed to fill if (s->seek_limit > s->buffer_size - FILL_LIMIT) s->seek_limit = s->buffer_size - FILL_LIMIT; return STREAM_OK; }
static void fill_rect(struct vo *vo, GC gc, int x0, int y0, int x1, int y1) { struct vo_x11_state *x11 = vo->x11; x0 = MPMAX(x0, 0); y0 = MPMAX(y0, 0); x1 = MPMIN(x1, vo->dwidth); y1 = MPMIN(y1, vo->dheight); if (x11->window && gc && x1 > x0 && y1 > y0) XFillRectangle(x11->display, x11->window, gc, x0, y0, x1 - x0, y1 - y0); }
// Copy at most dst_size from the cache at the given absolute file position pos. // Return number of bytes that could actually be read. // Does not advance the file position, or change anything else. // Can be called from anywhere, as long as the mutex is held. static size_t read_buffer(struct priv *s, unsigned char *dst, size_t dst_size, int64_t pos) { size_t read = 0; while (read < dst_size) { if (pos >= s->max_filepos || pos < s->min_filepos) break; int64_t newb = s->max_filepos - pos; // new bytes in the buffer int64_t bpos = pos - s->offset; // file pos to buffer memory pos if (bpos < 0) { bpos += s->buffer_size; } else if (bpos >= s->buffer_size) { bpos -= s->buffer_size; } if (newb > s->buffer_size - bpos) newb = s->buffer_size - bpos; // handle wrap... newb = MPMIN(newb, dst_size - read); assert(newb >= 0 && read + newb <= dst_size); assert(bpos >= 0 && bpos + newb <= s->buffer_size); memcpy(&dst[read], &s->buffer[bpos], newb); read += newb; pos += newb; } return read; }
void ca_get_active_chmap(struct ao *ao, AudioDeviceID device, int channel_count, struct mp_chmap *out_map) { // Apparently, we have to guess by looking back at the supported layouts, // and I haven't found a property that retrieves the actual currently // active channel layout. struct mp_chmap_sel chmap_sel = {0}; ca_retrieve_layouts(ao, &chmap_sel, device); // Use any exact match. for (int n = 0; n < chmap_sel.num_chmaps; n++) { if (chmap_sel.chmaps[n].num == channel_count) { MP_VERBOSE(ao, "mismatching channels - fallback #%d\n", n); *out_map = chmap_sel.chmaps[n]; return; } } // Fall back to stereo or mono, and fill the rest with silence. (We don't // know what the device expects. We could use a larger default layout here, // but let's not.) mp_chmap_from_channels(out_map, MPMIN(2, channel_count)); out_map->num = channel_count; for (int n = 2; n < out_map->num; n++) out_map->speaker[n] = MP_SPEAKER_ID_NA; MP_WARN(ao, "mismatching channels - falling back to %s\n", mp_chmap_to_str(out_map)); }
static int archive_entry_seek(stream_t *s, int64_t newpos) { struct priv *p = s->priv; if (!p->mpa) return -1; if (archive_seek_data(p->mpa->arch, newpos, SEEK_SET) >= 0) return 1; // libarchive can't seek in most formats. if (newpos < s->pos) { // Hack seeking backwards into working by reopening the archive and // starting over. MP_VERBOSE(s, "trying to reopen archive for performing seek\n"); if (reopen_archive(s) < STREAM_OK) return -1; s->pos = 0; } if (newpos > s->pos) { // For seeking forwards, just keep reading data (there's no libarchive // skip function either). char buffer[4096]; while (newpos > s->pos) { if (mp_cancel_test(s->cancel)) return -1; int size = MPMIN(newpos - s->pos, sizeof(buffer)); int r = archive_read_data(p->mpa->arch, buffer, size); if (r < 0) { MP_ERR(s, "%s\n", archive_error_string(p->mpa->arch)); return -1; } s->pos += r; } } return 1; }
static void mp_msg_av_log_callback(void *ptr, int level, const char *fmt, va_list vl) { AVClass *avc = ptr ? *(AVClass **)ptr : NULL; int mp_level = av_log_level_to_mp_level(level); // Note: mp_log is thread-safe, but destruction of the log instances is not. pthread_mutex_lock(&log_lock); if (!log_mpv_instance) { pthread_mutex_unlock(&log_lock); // Fallback to stderr vfprintf(stderr, fmt, vl); return; } struct mp_log *log = get_av_log(ptr); if (mp_msg_test(log, mp_level)) { char buffer[4096] = ""; int pos = 0; const char *prefix = avc ? avc->item_name(ptr) : NULL; if (log_print_prefix && prefix) pos = snprintf(buffer, sizeof(buffer), "%s: ", prefix); log_print_prefix = fmt[strlen(fmt) - 1] == '\n'; pos = MPMIN(MPMAX(pos, 0), sizeof(buffer)); vsnprintf(buffer + pos, sizeof(buffer) - pos, fmt, vl); mp_msg(log, mp_level, "%s", buffer); } pthread_mutex_unlock(&log_lock); }
static int filter_out(struct af_instance *af) { struct priv *p = af->priv; while (rubberband_available(p->rubber) <= 0) { const float *dummy[MP_NUM_CHANNELS] = {0}; const float **in_data = dummy; size_t in_samples = 0; if (p->pending) { if (!p->pending->samples) break; // recover from previous EOF if (p->needs_reset) { rubberband_reset(p->rubber); p->rubber_delay = 0; } p->needs_reset = false; size_t needs = rubberband_get_samples_required(p->rubber); in_data = (void *)&p->pending->planes; in_samples = MPMIN(p->pending->samples, needs); } if (p->needs_reset) break; // previous EOF p->needs_reset = !p->pending; // EOF rubberband_process(p->rubber, in_data, in_samples, p->needs_reset); p->rubber_delay += in_samples; if (!p->pending) break; mp_audio_skip_samples(p->pending, in_samples); } int out_samples = rubberband_available(p->rubber); if (out_samples > 0) { struct mp_audio *out = mp_audio_pool_get(af->out_pool, af->data, out_samples); if (!out) return -1; if (p->pending) mp_audio_copy_config(out, p->pending); float **out_data = (void *)&out->planes; out->samples = rubberband_retrieve(p->rubber, out_data, out->samples); p->rubber_delay -= out->samples * p->speed; af_add_output_frame(af, out); } int delay_samples = p->rubber_delay; if (p->pending) delay_samples += p->pending->samples; af->delay = delay_samples / (af->data->rate * p->speed); return 0; }
// Filter len bytes of input, put result into outbuf. static int filter_n_bytes(struct dec_audio *da, struct mp_audio_buffer *outbuf, int len) { int error = 0; struct mp_audio config; mp_audio_buffer_get_format(da->decode_buffer, &config); while (mp_audio_buffer_samples(da->decode_buffer) < len) { int maxlen = mp_audio_buffer_get_write_available(da->decode_buffer); if (maxlen < DECODE_MAX_UNIT) break; struct mp_audio buffer; mp_audio_buffer_get_write_buffer(da->decode_buffer, maxlen, &buffer); buffer.samples = 0; error = da->ad_driver->decode_audio(da, &buffer, maxlen); if (error < 0) break; // Commit the data just read as valid data mp_audio_buffer_finish_write(da->decode_buffer, buffer.samples); // Format change if (!mp_audio_config_equals(&da->decoded, &config)) { // If there are still samples left in the buffer, let them drain // first, and don't signal a format change to the caller yet. if (mp_audio_buffer_samples(da->decode_buffer) > 0) break; error = -2; break; } } // Filter struct mp_audio filter_data; mp_audio_buffer_peek(da->decode_buffer, &filter_data); filter_data.rate = da->afilter->input.rate; // due to playback speed change len = MPMIN(filter_data.samples, len); filter_data.samples = len; bool eof = filter_data.samples == 0 && error < 0; if (af_filter(da->afilter, &filter_data, eof ? AF_FILTER_FLAG_EOF : 0) < 0) return -1; mp_audio_buffer_append(outbuf, &filter_data); if (eof && filter_data.samples > 0) error = 0; // don't end playback yet // remove processed data from decoder buffer: mp_audio_buffer_skip(da->decode_buffer, len); // Assume the filter chain is drained from old data at this point. // (If not, the remaining old data is discarded.) if (error == -2) { if (!reinit_audio_buffer(da)) error = -1; // switch to invalid format } return error; }
static int fill_buffer(stream_t *s, char *buffer, int max_len) { struct priv *p = s->priv; if (s->pos < 0) return -1; if (s->pos >= p->max_size) { if (stream_seek(p->original, s->pos) < 1) return -1; return stream_read(p->original, buffer, max_len); } // Size of file changes -> invalidate last block if (s->pos >= p->size - BLOCK_SIZE) { int64_t new_size = -1; stream_control(s, STREAM_CTRL_GET_SIZE, &new_size); if (new_size != p->size) set_bit(p, BLOCK_ALIGN(p->size), 0); p->size = MPMIN(p->max_size, new_size); } int64_t aligned = BLOCK_ALIGN(s->pos); if (!test_bit(p, aligned)) { char tmp[BLOCK_SIZE]; stream_seek(p->original, aligned); int r = stream_read(p->original, tmp, BLOCK_SIZE); if (r < BLOCK_SIZE) { if (p->size < 0) { MP_WARN(s, "suspected EOF\n"); } else if (aligned + r < p->size) { MP_ERR(s, "unexpected EOF\n"); return -1; } } if (fseeko(p->cache_file, aligned, SEEK_SET)) return -1; if (fwrite(tmp, r, 1, p->cache_file) != 1) return -1; set_bit(p, aligned, 1); } if (fseeko(p->cache_file, s->pos, SEEK_SET)) return -1; // align/limit to blocks max_len = MPMIN(max_len, BLOCK_SIZE - (s->pos % BLOCK_SIZE)); // Limit to max. known file size max_len = MPMIN(max_len, p->size - s->pos); return fread(buffer, 1, max_len, p->cache_file); }
// Clamp [start, end) to range [0, size) with various fallbacks. static void clamp_size(int size, int *start, int *end) { *start = MPMAX(0, *start); *end = MPMIN(size, *end); if (*start >= *end) { *start = 0; *end = 1; } }
static int archive_entry_seek(stream_t *s, int64_t newpos) { struct priv *p = s->priv; if (p->mpa && !p->broken_seek) { locale_t oldlocale = uselocale(p->mpa->locale); int r = archive_seek_data(p->mpa->arch, newpos, SEEK_SET); uselocale(oldlocale); if (r >= 0) return 1; MP_WARN(s, "possibly unsupported seeking - switching to reopening\n"); p->broken_seek = true; if (reopen_archive(s) < STREAM_OK) return -1; } // libarchive can't seek in most formats. if (newpos < s->pos) { // Hack seeking backwards into working by reopening the archive and // starting over. MP_VERBOSE(s, "trying to reopen archive for performing seek\n"); if (reopen_archive(s) < STREAM_OK) return -1; s->pos = 0; } if (newpos > s->pos) { // For seeking forwards, just keep reading data (there's no libarchive // skip function either). char buffer[4096]; while (newpos > s->pos) { if (mp_cancel_test(s->cancel)) return -1; int size = MPMIN(newpos - s->pos, sizeof(buffer)); locale_t oldlocale = uselocale(p->mpa->locale); int r = archive_read_data(p->mpa->arch, buffer, size); if (r <= 0) { if (r == 0 && newpos > p->entry_size) { MP_ERR(s, "demuxer trying to seek beyond end of archive " "entry\n"); } else if (r == 0) { MP_ERR(s, "end of archive entry reached while seeking\n"); } else { MP_ERR(s, "%s\n", archive_error_string(p->mpa->arch)); } uselocale(oldlocale); if (mp_archive_check_fatal(p->mpa, r)) { mp_archive_free(p->mpa); p->mpa = NULL; } return -1; } uselocale(oldlocale); s->pos += r; } } return 1; }
static void reselect_streams(demuxer_t *demuxer) { struct priv *p = demuxer->priv; for (int n = 0; n < MPMIN(p->slave->num_streams, p->num_streams); n++) { if (p->streams[n]) { demuxer_select_track(p->slave, p->slave->streams[n], demux_stream_is_selected(p->streams[n])); } } }
// Initialization and runtime control static int control(struct af_instance* af, int cmd, void* arg) { af_channels_t* s = af->priv; switch(cmd){ case AF_CONTROL_REINIT: ; struct mp_chmap chmap; mp_chmap_set_unknown(&chmap, s->nch); mp_audio_set_channels(af->data, &chmap); // Set default channel assignment if(!s->router){ int i; // Make sure this filter isn't redundant if(af->data->nch == ((struct mp_audio*)arg)->nch) return AF_DETACH; // If mono: fake stereo if(((struct mp_audio*)arg)->nch == 1){ s->nr = MPMIN(af->data->nch,2); for(i=0;i<s->nr;i++){ s->route[i][FR] = 0; s->route[i][TO] = i; } } else{ s->nr = MPMIN(af->data->nch, ((struct mp_audio*)arg)->nch); for(i=0;i<s->nr;i++){ s->route[i][FR] = i; s->route[i][TO] = i; } } } af->data->rate = ((struct mp_audio*)arg)->rate; mp_audio_force_interleaved_format((struct mp_audio*)arg); mp_audio_set_format(af->data, ((struct mp_audio*)arg)->format); return check_routes(af,((struct mp_audio*)arg)->nch,af->data->nch); } return AF_UNKNOWN; }
static void update_speed(struct af_instance *af, float speed) { af_scaletempo_t *s = af->priv; s->speed = speed; double factor = (s->speed_opt & SCALE_PITCH) ? 1.0 / s->speed : s->speed; s->scale = factor * s->scale_nominal; s->frames_stride_scaled = s->scale * s->frames_stride; s->frames_stride_error = MPMIN(s->frames_stride_error, s->frames_stride_scaled); }
static int SkipBlock(struct stream *s, const rar_block_t *hdr) { uint64_t size = (uint64_t)hdr->size + hdr->add_size; while (size > 0) { int skip = MPMIN(size, INT_MAX); if (!stream_skip(s, skip)) return -1; size -= skip; } return 0; }
ssize_t RarRead(rar_file_t *file, void *data, size_t size) { size_t total = 0; while (total < size) { const uint64_t chunk_end = file->current_chunk->cummulated_size + file->current_chunk->size; int max = MPMIN(MPMIN((int64_t)(size - total), (int64_t)(chunk_end - file->i_pos)), INT_MAX); if (max <= 0) break; int r = stream_read(file->s, data, max); if (r <= 0) break; total += r; data = (char *)data + r; file->i_pos += r; if (file->i_pos >= chunk_end && RarSeek(file, file->i_pos)) break; } return total; }
static int keys_count_matches(char *buf, int buflen) { int count = 0; if (buflen < 0) buflen = strlen(buf); for (int i = 0; i < getch2_keys.len; i++) { keycode_st *st = &getch2_keys.map[i]; int len = MPMIN(buflen, st->len); if (memcmp(buf, st->chars, len) == 0) count++; } return count; }
// Copy data from input frame to encode frame (because libavcodec wants a full // AC3 frame for encoding, while filter input frames can be smaller or larger). // Return true if the frame is complete. static bool fill_buffer(struct af_instance *af) { af_ac3enc_t *s = af->priv; af->delay = 0; if (s->pending) { int copy = MPMIN(s->in_samples - s->input->samples, s->pending->samples); s->input->samples += copy; mp_audio_copy(s->input, s->input->samples - copy, s->pending, 0, copy); mp_audio_skip_samples(s->pending, copy); } update_delay(af); return s->input->samples >= s->in_samples; }
static bool is_compatible(int fmt1, int fmt2) { struct mp_imgfmt_desc d1 = mp_imgfmt_get_desc(fmt1); struct mp_imgfmt_desc d2 = mp_imgfmt_get_desc(fmt2); if (d1.num_planes < d2.num_planes) return false; if (!(d1.flags & MP_IMGFLAG_BYTE_ALIGNED) || !(d2.flags & MP_IMGFLAG_BYTE_ALIGNED)) return false; for (int n = 0; n < MPMIN(d1.num_planes, d2.num_planes); n++) { if (d1.bytes[n] != d2.bytes[n]) return false; if (d1.xs[n] != d2.xs[n] || d1.ys[n] != d2.ys[n]) return false; } return true; }
// Copy data from input frame to encode frame (because libavcodec wants a full // AC3 frame for encoding, while filter input frames can be smaller or larger). // Return true if the frame is complete. static bool fill_buffer(struct af_instance *af) { af_ac3enc_t *s = af->priv; af->delay = 0; if (s->pending) { if (!mp_audio_is_writeable(s->input)) assert(s->input->samples == 0); // we can't have sent a partial frame mp_audio_realloc_min(s->input, s->in_samples); int copy = MPMIN(s->in_samples - s->input->samples, s->pending->samples); s->input->samples += copy; mp_audio_copy(s->input, s->input->samples - copy, s->pending, 0, copy); mp_audio_skip_samples(s->pending, copy); } update_delay(af); return s->input->samples >= s->in_samples; }
void mp_set_avcodec_threads(struct mp_log *l, AVCodecContext *avctx, int threads) { if (threads == 0) { threads = av_cpu_count(); if (threads < 1) { mp_warn(l, "Could not determine thread count to use, defaulting to 1.\n"); threads = 1; } else { mp_verbose(l, "Detected %d logical cores.\n", threads); if (threads > 1) threads += 1; // extra thread for better load balancing } // Apparently some libavcodec versions have or had trouble with more // than 16 threads, and/or print a warning when using > 16. threads = MPMIN(threads, 16); } mp_verbose(l, "Requesting %d threads for decoding.\n", threads); avctx->thread_count = threads; }
static float compute_replaygain(struct MPContext *mpctx) { struct MPOpts *opts = mpctx->opts; float rgain = 1.0; struct replaygain_data *rg = NULL; struct track *track = mpctx->current_track[0][STREAM_AUDIO]; if (track) rg = track->stream->codec->replaygain_data; if (opts->rgain_mode && rg) { MP_VERBOSE(mpctx, "Replaygain: Track=%f/%f Album=%f/%f\n", rg->track_gain, rg->track_peak, rg->album_gain, rg->album_peak); float gain, peak; if (opts->rgain_mode == 1) { gain = rg->track_gain; peak = rg->track_peak; } else { gain = rg->album_gain; peak = rg->album_peak; } gain += opts->rgain_preamp; rgain = db_gain(gain); MP_VERBOSE(mpctx, "Applying replay-gain: %f\n", rgain); if (!opts->rgain_clip) { // clipping prevention rgain = MPMIN(rgain, 1.0 / peak); MP_VERBOSE(mpctx, "...with clipping prevention: %f\n", rgain); } } else if (opts->rgain_fallback) { rgain = db_gain(opts->rgain_fallback); MP_VERBOSE(mpctx, "Applying fallback gain: %f\n", rgain); } return rgain; }
static int play(struct ao *ao, void **data, int samples, int flags) { struct priv *priv = ao->priv; int accepted; resume(ao); if (priv->buffered <= 0) priv->buffered = priv->latency; // emulate fixed latency priv->playing_final = flags & AOPLAY_FINAL_CHUNK; if (priv->playing_final) { // Last audio chunk - don't round to outburst. accepted = MPMIN(priv->buffersize - priv->buffered, samples); } else { int maxbursts = (priv->buffersize - priv->buffered) / priv->outburst; int playbursts = samples / priv->outburst; int bursts = playbursts > maxbursts ? maxbursts : playbursts; accepted = bursts * priv->outburst; } priv->buffered += accepted; return accepted; }
struct timespec mp_time_us_to_timespec(int64_t time_us) { struct timespec ts; get_realtime(&ts); // We don't know what time source mp_time_us() uses, but usually it's not // CLOCK_REALTIME - so we have to remap the times. int64_t unow = mp_time_us(); int64_t diff_us = time_us - unow; int64_t diff_secs = diff_us / (1000L * 1000L); long diff_nsecs = (diff_us - diff_secs * (1000L * 1000L)) * 1000L; if (diff_nsecs < 0) { diff_secs -= 1; diff_nsecs += 1000000000L; } if (diff_nsecs + ts.tv_nsec >= 1000000000UL) { diff_secs += 1; diff_nsecs -= 1000000000UL; } // OSX can't deal with large timeouts. Also handles tv_sec/time_t overflows. diff_secs = MPMIN(diff_secs, 10000000); ts.tv_sec += diff_secs; ts.tv_nsec += diff_nsecs; return ts; }
// Filter data through filter static int filter(struct af_instance* af, struct mp_audio* audio, int flags) { struct mp_audio *out = af->data; af_ac3enc_t *s = af->priv; int num_frames = (audio->samples + mp_audio_buffer_samples(s->pending)) / s->in_samples; int max_out_samples = s->out_samples * num_frames; mp_audio_realloc_min(out, max_out_samples); out->samples = 0; while (audio->samples > 0) { int ret; int consumed_pending = 0; struct mp_audio in_frame; int pending = mp_audio_buffer_samples(s->pending); if (pending == 0 && audio->samples >= s->in_samples) { in_frame = *audio; mp_audio_skip_samples(audio, s->in_samples); } else { if (pending > 0 && pending < s->in_samples) { struct mp_audio tmp = *audio; tmp.samples = MPMIN(tmp.samples, s->in_samples); mp_audio_buffer_append(s->pending, &tmp); mp_audio_skip_samples(audio, tmp.samples); } mp_audio_buffer_peek(s->pending, &in_frame); if (in_frame.samples < s->in_samples) break; consumed_pending = s->in_samples; } in_frame.samples = s->in_samples; AVFrame *frame = av_frame_alloc(); if (!frame) { MP_FATAL(af, "Could not allocate memory \n"); return -1; } frame->nb_samples = s->in_samples; frame->format = s->lavc_actx->sample_fmt; frame->channel_layout = s->lavc_actx->channel_layout; assert(in_frame.num_planes <= AV_NUM_DATA_POINTERS); frame->extended_data = frame->data; for (int n = 0; n < in_frame.num_planes; n++) frame->data[n] = in_frame.planes[n]; frame->linesize[0] = s->in_samples * audio->sstride; int ok; ret = avcodec_encode_audio2(s->lavc_actx, &s->pkt, frame, &ok); av_frame_free(&frame); if (ret < 0 || !ok) { MP_FATAL(af, "Encode failed.\n"); return -1; } mp_audio_buffer_skip(s->pending, consumed_pending); MP_DBG(af, "avcodec_encode_audio got %d, pending %d.\n", s->pkt.size, mp_audio_buffer_samples(s->pending)); int frame_size = s->pkt.size; int header_len = 0; char hdr[8]; if (s->cfg_add_iec61937_header && s->pkt.size > 5) { int bsmod = s->pkt.data[5] & 0x7; int len = frame_size; frame_size = AC3_FRAME_SIZE * 2 * 2; header_len = 8; AV_WB16(hdr, 0xF872); // iec 61937 syncword 1 AV_WB16(hdr + 2, 0x4E1F); // iec 61937 syncword 2 hdr[4] = bsmod; // bsmod hdr[5] = 0x01; // data-type ac3 AV_WB16(hdr + 6, len << 3); // number of bits in payload } size_t max_size = (max_out_samples - out->samples) * out->sstride; if (frame_size > max_size) abort(); char *buf = (char *)out->planes[0] + out->samples * out->sstride; memcpy(buf, hdr, header_len); memcpy(buf + header_len, s->pkt.data, s->pkt.size); memset(buf + header_len + s->pkt.size, 0, frame_size - (header_len + s->pkt.size)); out->samples += frame_size / out->sstride; } mp_audio_buffer_append(s->pending, audio); *audio = *out; return 0; }
// Filter len bytes of input, put result into outbuf. static int filter_n_bytes(struct dec_audio *da, struct mp_audio_buffer *outbuf, int len) { bool format_change = false; int error = 0; assert(len > 0); // would break EOF logic below while (mp_audio_buffer_samples(da->decode_buffer) < len) { // Check for a format change struct mp_audio config; mp_audio_buffer_get_format(da->decode_buffer, &config); format_change = !mp_audio_config_equals(&da->decoded, &config); if (format_change) { error = AD_EOF; // drain remaining data left in the current buffer break; } if (da->decoded.samples > 0) { int copy = MPMIN(da->decoded.samples, len); struct mp_audio append = da->decoded; append.samples = copy; mp_audio_buffer_append(da->decode_buffer, &append); mp_audio_skip_samples(&da->decoded, copy); da->pts_offset += copy; continue; } error = da->ad_driver->decode_packet(da); if (error < 0) break; } if (error == AD_WAIT) return error; // Filter struct mp_audio filter_data; mp_audio_buffer_peek(da->decode_buffer, &filter_data); filter_data.rate = da->afilter->input.rate; // due to playback speed change len = MPMIN(filter_data.samples, len); filter_data.samples = len; bool eof = error == AD_EOF && filter_data.samples == 0; if (af_filter(da->afilter, &filter_data, eof ? AF_FILTER_FLAG_EOF : 0) < 0) return AD_ERR; mp_audio_buffer_append(outbuf, &filter_data); if (error == AD_EOF && filter_data.samples > 0) error = 0; // don't end playback yet // remove processed data from decoder buffer: mp_audio_buffer_skip(da->decode_buffer, len); // if format was changed, and all data was drained, execute the format change if (format_change && eof) { error = AD_NEW_FMT; if (!reinit_audio_buffer(da)) error = AD_ERR; // switch to invalid format } return error; }
static int init(struct ao *ao) { if (SDL_WasInit(SDL_INIT_AUDIO)) { MP_ERR(ao, "already initialized\n"); return -1; } struct priv *priv = ao->priv; if (SDL_InitSubSystem(SDL_INIT_AUDIO)) { if (!ao->probing) MP_ERR(ao, "SDL_Init failed\n"); uninit(ao); return -1; } struct mp_chmap_sel sel = {0}; mp_chmap_sel_add_waveext_def(&sel); if (!ao_chmap_sel_adjust(ao, &sel, &ao->channels)) { uninit(ao); return -1; } ao->format = af_fmt_from_planar(ao->format); SDL_AudioSpec desired, obtained; desired.format = AUDIO_S16SYS; for (int n = 0; fmtmap[n][0]; n++) { if (ao->format == fmtmap[n][0]) { desired.format = fmtmap[n][1]; break; } } desired.freq = ao->samplerate; desired.channels = ao->channels.num; desired.samples = MPMIN(32768, ceil_power_of_two(ao->samplerate * priv->buflen)); desired.callback = audio_callback; desired.userdata = ao; MP_VERBOSE(ao, "requested format: %d Hz, %d channels, %x, " "buffer size: %d samples\n", (int) desired.freq, (int) desired.channels, (int) desired.format, (int) desired.samples); obtained = desired; if (SDL_OpenAudio(&desired, &obtained)) { if (!ao->probing) MP_ERR(ao, "could not open audio: %s\n", SDL_GetError()); uninit(ao); return -1; } MP_VERBOSE(ao, "obtained format: %d Hz, %d channels, %x, " "buffer size: %d samples\n", (int) obtained.freq, (int) obtained.channels, (int) obtained.format, (int) obtained.samples); // The sample count is usually the number of samples the callback requests, // which we assume is the period size. Normally, ao.c will allocate a large // enough buffer. But in case the period size should be pathologically // large, this will help. ao->device_buffer = 3 * obtained.samples; ao->format = 0; for (int n = 0; fmtmap[n][0]; n++) { if (obtained.format == fmtmap[n][1]) { ao->format = fmtmap[n][0]; break; } } if (!ao->format) { if (!ao->probing) MP_ERR(ao, "could not find matching format\n"); uninit(ao); return -1; } if (!ao_chmap_sel_get_def(ao, &sel, &ao->channels, obtained.channels)) { uninit(ao); return -1; } ao->samplerate = obtained.freq; priv->paused = 1; return 1; }
static int audio_start_sync(struct MPContext *mpctx, int playsize) { struct ao *ao = mpctx->ao; struct MPOpts *opts = mpctx->opts; sh_audio_t * const sh_audio = mpctx->sh_audio; int res; // Timing info may not be set without res = decode_audio(sh_audio, &ao->buffer, 1); if (res < 0) return res; int bytes; bool did_retry = false; double written_pts; double bps = ao->bps / opts->playback_speed; bool hrseek = mpctx->hrseek_active; // audio only hrseek mpctx->hrseek_active = false; while (1) { written_pts = written_audio_pts(mpctx); double ptsdiff; if (hrseek) ptsdiff = written_pts - mpctx->hrseek_pts; else ptsdiff = written_pts - mpctx->sh_video->pts - mpctx->delay - mpctx->audio_delay; bytes = ptsdiff * bps; bytes -= bytes % (ao->channels.num * af_fmt2bits(ao->format) / 8); // ogg demuxers give packets without timing if (written_pts <= 1 && sh_audio->pts == MP_NOPTS_VALUE) { if (!did_retry) { // Try to read more data to see packets that have pts res = decode_audio(sh_audio, &ao->buffer, ao->bps); if (res < 0) return res; did_retry = true; continue; } bytes = 0; } if (fabs(ptsdiff) > 300 || isnan(ptsdiff)) // pts reset or just broken? bytes = 0; if (bytes > 0) break; mpctx->syncing_audio = false; int a = MPMIN(-bytes, MPMAX(playsize, 20000)); res = decode_audio(sh_audio, &ao->buffer, a); bytes += ao->buffer.len; if (bytes >= 0) { memmove(ao->buffer.start, ao->buffer.start + ao->buffer.len - bytes, bytes); ao->buffer.len = bytes; if (res < 0) return res; return decode_audio(sh_audio, &ao->buffer, playsize); } ao->buffer.len = 0; if (res < 0) return res; } if (hrseek) // Don't add silence in audio-only case even if position is too late return 0; int fillbyte = 0; if ((ao->format & AF_FORMAT_SIGN_MASK) == AF_FORMAT_US) fillbyte = 0x80; if (bytes >= playsize) { /* This case could fall back to the one below with * bytes = playsize, but then silence would keep accumulating * in a_out_buffer if the AO accepts less data than it asks for * in playsize. */ char *p = malloc(playsize); memset(p, fillbyte, playsize); write_to_ao(mpctx, p, playsize, 0, written_pts - bytes / bps); free(p); return ASYNC_PLAY_DONE; } mpctx->syncing_audio = false; decode_audio_prepend_bytes(&ao->buffer, bytes, fillbyte); return decode_audio(sh_audio, &ao->buffer, playsize); }