typedef struct AudioParams {
int freq;
int channels;
- int channel_layout;
+ int64_t channel_layout;
enum AVSampleFormat fmt;
} AudioParams;
double external_clock_speed; ///< speed of the external clock
double audio_clock;
+ int audio_clock_serial;
double audio_diff_cum; /* used for AV difference average computation */
double audio_diff_avg_coef;
double audio_diff_threshold;
double video_current_pts_drift; // video_current_pts - time (av_gettime) at which we updated video_current_pts - used to have running video pts
int64_t video_current_pos; // current displayed file pos
double max_frame_duration; // maximum duration of a frame - above this, we consider the jump a timestamp discontinuity
+ int video_clock_serial;
VideoPicture pictq[VIDEO_PICTURE_QUEUE_SIZE];
int pictq_size, pictq_rindex, pictq_windex;
SDL_mutex *pictq_mutex;
static int screen_height = 0;
static int audio_disable;
static int video_disable;
+static int subtitle_disable;
static int wanted_stream[AVMEDIA_TYPE_NB] = {
[AVMEDIA_TYPE_AUDIO] = -1,
[AVMEDIA_TYPE_VIDEO] = -1,
/* get the current audio clock value */
static double get_audio_clock(VideoState *is)
{
+ if (is->audio_clock_serial != is->audioq.serial)
+ return NAN;
if (is->paused) {
return is->audio_current_pts;
} else {
/* get the current video clock value */
static double get_video_clock(VideoState *is)
{
+ if (is->video_clock_serial != is->videoq.serial)
+ return NAN;
if (is->paused) {
return is->video_current_pts;
} else {
}
static void check_external_clock_sync(VideoState *is, double pts) {
- if (fabs(get_external_clock(is) - pts) > AV_NOSYNC_THRESHOLD) {
+ double ext_clock = get_external_clock(is);
+ if (isnan(ext_clock) || fabs(ext_clock - pts) > AV_NOSYNC_THRESHOLD) {
update_external_clock_pts(is, pts);
}
}
if (seek_by_bytes)
is->seek_flags |= AVSEEK_FLAG_BYTE;
is->seek_req = 1;
+ SDL_CondSignal(is->continue_read_thread);
}
}
delay to compute the threshold. I still don't know
if it is the best guess */
sync_threshold = FFMAX(AV_SYNC_THRESHOLD, delay);
- if (fabs(diff) < AV_NOSYNC_THRESHOLD) {
+ if (!isnan(diff) && fabs(diff) < AV_NOSYNC_THRESHOLD) {
if (diff <= -sync_threshold)
delay = 0;
else if (diff >= sync_threshold)
SDL_UnlockMutex(is->pictq_mutex);
}
-static void pictq_prev_picture(VideoState *is) {
+static int pictq_prev_picture(VideoState *is) {
VideoPicture *prevvp;
+ int ret = 0;
/* update queue size and signal for the previous picture */
prevvp = &is->pictq[(is->pictq_rindex + VIDEO_PICTURE_QUEUE_SIZE - 1) % VIDEO_PICTURE_QUEUE_SIZE];
if (prevvp->allocated && prevvp->serial == is->videoq.serial) {
if (--is->pictq_rindex == -1)
is->pictq_rindex = VIDEO_PICTURE_QUEUE_SIZE - 1;
is->pictq_size++;
+ ret = 1;
}
SDL_CondSignal(is->pictq_cond);
SDL_UnlockMutex(is->pictq_mutex);
}
+ return ret;
}
static void update_video_pts(VideoState *is, double pts, int64_t pos, int serial) {
is->video_current_pts_drift = is->video_current_pts - time;
is->video_current_pos = pos;
is->frame_last_pts = pts;
+ is->video_clock_serial = serial;
if (is->videoq.serial == serial)
check_external_clock_sync(is, is->video_current_pts);
}
}
if (is->video_st) {
+ int redisplay = 0;
if (is->force_refresh)
- pictq_prev_picture(is);
+ redisplay = pictq_prev_picture(is);
retry:
if (is->pictq_size == 0) {
SDL_LockMutex(is->pictq_mutex);
if (vp->serial != is->videoq.serial) {
pictq_next_picture(is);
+ redisplay = 0;
goto retry;
}
if (is->pictq_size > 1) {
VideoPicture *nextvp = &is->pictq[(is->pictq_rindex + 1) % VIDEO_PICTURE_QUEUE_SIZE];
duration = nextvp->pts - vp->pts;
- if(!is->step && (framedrop>0 || (framedrop && get_master_sync_type(is) != AV_SYNC_VIDEO_MASTER)) && time > is->frame_timer + duration){
- is->frame_drops_late++;
+ if(!is->step && (redisplay || framedrop>0 || (framedrop && get_master_sync_type(is) != AV_SYNC_VIDEO_MASTER)) && time > is->frame_timer + duration){
+ if (!redisplay)
+ is->frame_drops_late++;
pictq_next_picture(is);
+ redisplay = 0;
goto retry;
}
}
double clockdiff = get_video_clock(is) - get_master_clock(is);
double dpts = av_q2d(is->video_st->time_base) * *pts;
double ptsdiff = dpts - is->frame_last_pts;
- if (fabs(clockdiff) < AV_NOSYNC_THRESHOLD &&
+ if (!isnan(clockdiff) && fabs(clockdiff) < AV_NOSYNC_THRESHOLD &&
ptsdiff > 0 && ptsdiff < AV_NOSYNC_THRESHOLD &&
clockdiff + ptsdiff - is->frame_last_filter_delay < 0) {
is->frame_last_dropped_pos = pkt->pos;
diff = get_audio_clock(is) - get_master_clock(is);
- if (fabs(diff) < AV_NOSYNC_THRESHOLD) {
+ if (!isnan(diff) && fabs(diff) < AV_NOSYNC_THRESHOLD) {
is->audio_diff_cum = diff + is->audio_diff_avg_coef * is->audio_diff_cum;
if (is->audio_diff_avg_count < AUDIO_DIFF_AVG_NB) {
/* not enough measures to have a correct estimate */
} else
avcodec_get_frame_defaults(is->frame);
+ if (is->audioq.serial != is->audio_pkt_temp_serial)
+ break;
+
if (is->paused)
return -1;
flush_complete = 1;
continue;
}
- data_size = av_samples_get_buffer_size(NULL, is->frame->channels,
+ data_size = av_samples_get_buffer_size(NULL, av_frame_get_channels(is->frame),
is->frame->nb_samples,
is->frame->format, 1);
dec_channel_layout =
- (is->frame->channel_layout && is->frame->channels == av_get_channel_layout_nb_channels(is->frame->channel_layout)) ?
- is->frame->channel_layout : av_get_default_channel_layout(is->frame->channels);
+ (is->frame->channel_layout && av_frame_get_channels(is->frame) == av_get_channel_layout_nb_channels(is->frame->channel_layout)) ?
+ is->frame->channel_layout : av_get_default_channel_layout(av_frame_get_channels(is->frame));
wanted_nb_samples = synchronize_audio(is, is->frame->nb_samples);
if (is->frame->format != is->audio_src.fmt ||
0, NULL);
if (!is->swr_ctx || swr_init(is->swr_ctx) < 0) {
fprintf(stderr, "Cannot create sample rate converter for conversion of %d Hz %s %d channels to %d Hz %s %d channels!\n",
- is->frame->sample_rate, av_get_sample_fmt_name(is->frame->format), (int)is->frame->channels,
- is->audio_tgt.freq, av_get_sample_fmt_name(is->audio_tgt.fmt), is->audio_tgt.channels);
+ is->frame->sample_rate, av_get_sample_fmt_name(is->frame->format), av_frame_get_channels(is->frame),
+ is->audio_tgt.freq, av_get_sample_fmt_name(is->audio_tgt.fmt), is->audio_tgt.channels);
break;
}
is->audio_src.channel_layout = dec_channel_layout;
- is->audio_src.channels = is->frame->channels;
+ is->audio_src.channels = av_frame_get_channels(is->frame);
is->audio_src.freq = is->frame->sample_rate;
is->audio_src.fmt = is->frame->format;
}
audio_clock0 = is->audio_clock;
is->audio_clock += (double)data_size /
- (is->frame->channels * is->frame->sample_rate * av_get_bytes_per_sample(is->frame->format));
+ (av_frame_get_channels(is->frame) * is->frame->sample_rate * av_get_bytes_per_sample(is->frame->format));
#ifdef DEBUG
{
static double last_clock;
av_free_packet(pkt);
memset(pkt_temp, 0, sizeof(*pkt_temp));
- if (is->paused || is->audioq.abort_request) {
+ if (is->audioq.abort_request) {
return -1;
}
/* if update the audio clock with the pts */
if (pkt->pts != AV_NOPTS_VALUE) {
is->audio_clock = av_q2d(is->audio_st->time_base)*pkt->pts;
+ is->audio_clock_serial = is->audio_pkt_temp_serial;
}
}
}
/* Let's assume the audio driver that is used by SDL has two periods. */
is->audio_current_pts = is->audio_clock - (double)(2 * is->audio_hw_buf_size + is->audio_write_buf_size) / bytes_per_sec;
is->audio_current_pts_drift = is->audio_current_pts - audio_callback_time / 1000000.0;
- if (is->audioq.serial == is->audio_pkt_temp_serial)
+ if (is->audioq.serial == is->audio_clock_serial)
check_external_clock_sync(is, is->audio_current_pts);
}
wanted_stream[AVMEDIA_TYPE_AUDIO],
st_index[AVMEDIA_TYPE_VIDEO],
NULL, 0);
- if (!video_disable)
+ if (!video_disable && !subtitle_disable)
st_index[AVMEDIA_TYPE_SUBTITLE] =
av_find_best_stream(ic, AVMEDIA_TYPE_SUBTITLE,
wanted_stream[AVMEDIA_TYPE_SUBTITLE],
packet_queue_put(&is->videoq, &flush_pkt);
}
if (is->seek_flags & AVSEEK_FLAG_BYTE) {
- //FIXME: use a cleaner way to signal obsolete external clock...
- update_external_clock_pts(is, (double)AV_NOPTS_VALUE);
+ update_external_clock_pts(is, NAN);
} else {
update_external_clock_pts(is, seek_target / (double)AV_TIME_BASE);
}
is->continue_read_thread = SDL_CreateCond();
- //FIXME: use a cleaner way to signal obsolete external clock...
- update_external_clock_pts(is, (double)AV_NOPTS_VALUE);
+ update_external_clock_pts(is, NAN);
update_external_clock_speed(is, 1.0);
is->audio_current_pts_drift = -av_gettime() / 1000000.0;
is->video_current_pts_drift = is->audio_current_pts_drift;
+ is->audio_clock_serial = -1;
+ is->video_clock_serial = -1;
is->av_sync_type = av_sync_type;
is->read_tid = SDL_CreateThread(read_thread, is);
if (!is->read_tid) {
static void toggle_audio_display(VideoState *is)
{
int bgcolor = SDL_MapRGB(screen->format, 0x00, 0x00, 0x00);
- is->show_mode = (is->show_mode + 1) % SHOW_MODE_NB;
- fill_rectangle(screen,
- is->xleft, is->ytop, is->width, is->height,
- bgcolor, 1);
+ int next = is->show_mode;
+ do {
+ next = (next + 1) % SHOW_MODE_NB;
+ } while (next != is->show_mode && (next == SHOW_MODE_VIDEO && !is->video_st || next != SHOW_MODE_VIDEO && !is->audio_st));
+ if (is->show_mode != next) {
+ fill_rectangle(screen,
+ is->xleft, is->ytop, is->width, is->height,
+ bgcolor, 1);
+ is->force_refresh = 1;
+ is->show_mode = next;
+ }
}
static void refresh_loop_wait_event(VideoState *is, SDL_Event *event) {
break;
case SDLK_w:
toggle_audio_display(cur_stream);
- cur_stream->force_refresh = 1;
break;
case SDLK_PAGEUP:
incr = 600.0;
stream_seek(cur_stream, pos, incr, 1);
} else {
pos = get_master_clock(cur_stream);
+ if (isnan(pos))
+ pos = (double)cur_stream->seek_pos / AV_TIME_BASE;
pos += incr;
if (cur_stream->ic->start_time != AV_NOPTS_VALUE && pos < cur_stream->ic->start_time / (double)AV_TIME_BASE)
pos = cur_stream->ic->start_time / (double)AV_TIME_BASE;
{ "fs", OPT_BOOL, { &is_full_screen }, "force full screen" },
{ "an", OPT_BOOL, { &audio_disable }, "disable audio" },
{ "vn", OPT_BOOL, { &video_disable }, "disable video" },
+ { "sn", OPT_BOOL, { &subtitle_disable }, "disable subtitling" },
{ "ast", OPT_INT | HAS_ARG | OPT_EXPERT, { &wanted_stream[AVMEDIA_TYPE_AUDIO] }, "select desired audio stream", "stream_number" },
{ "vst", OPT_INT | HAS_ARG | OPT_EXPERT, { &wanted_stream[AVMEDIA_TYPE_VIDEO] }, "select desired video stream", "stream_number" },
{ "sst", OPT_INT | HAS_ARG | OPT_EXPERT, { &wanted_stream[AVMEDIA_TYPE_SUBTITLE] }, "select desired subtitle stream", "stream_number" },