diff options
| author | Tim Redfern <tim@eclectronics.org> | 2013-12-29 12:19:38 +0000 |
|---|---|---|
| committer | Tim Redfern <tim@eclectronics.org> | 2013-12-29 12:19:38 +0000 |
| commit | f7813a5324be39d13ab536c245d15dfc602a7849 (patch) | |
| tree | fad99148b88823d34a5df2f0a25881a002eb291b /ffmpeg/ffplay.c | |
| parent | b7a5a477b8ff4d4e3028b9dfb9a9df0a41463f92 (diff) | |
basic type mechanism working
Diffstat (limited to 'ffmpeg/ffplay.c')
| -rw-r--r-- | ffmpeg/ffplay.c | 823 |
1 files changed, 454 insertions, 369 deletions
diff --git a/ffmpeg/ffplay.c b/ffmpeg/ffplay.c index 535798d..0b5331b 100644 --- a/ffmpeg/ffplay.c +++ b/ffmpeg/ffplay.c @@ -28,6 +28,8 @@ #include <math.h> #include <limits.h> #include <signal.h> +#include <stdint.h> + #include "libavutil/avstring.h" #include "libavutil/colorspace.h" #include "libavutil/mathematics.h" @@ -48,7 +50,6 @@ #if CONFIG_AVFILTER # include "libavfilter/avcodec.h" # include "libavfilter/avfilter.h" -# include "libavfilter/avfiltergraph.h" # include "libavfilter/buffersink.h" # include "libavfilter/buffersrc.h" #endif @@ -70,8 +71,12 @@ const int program_birth_year = 2003; A/V sync as SDL does not have hardware buffer fullness info. */ #define SDL_AUDIO_BUFFER_SIZE 1024 -/* no AV sync correction is done if below the AV sync threshold */ -#define AV_SYNC_THRESHOLD 0.01 +/* no AV sync correction is done if below the minimum AV sync threshold */ +#define AV_SYNC_THRESHOLD_MIN 0.01 +/* AV sync correction is done if above the maximum AV sync threshold */ +#define AV_SYNC_THRESHOLD_MAX 0.1 +/* If a frame duration is longer than this, it will not be duplicated to compensate AV sync */ +#define AV_SYNC_FRAMEDUP_THRESHOLD 0.1 /* no AV correction is done if too big error */ #define AV_NOSYNC_THRESHOLD 10.0 @@ -113,11 +118,12 @@ typedef struct PacketQueue { SDL_cond *cond; } PacketQueue; -#define VIDEO_PICTURE_QUEUE_SIZE 4 +#define VIDEO_PICTURE_QUEUE_SIZE 3 #define SUBPICTURE_QUEUE_SIZE 4 typedef struct VideoPicture { double pts; // presentation timestamp for this picture + double duration; // estimated duration based on frame rate int64_t pos; // byte position in file SDL_Overlay *bmp; int width, height; /* source height & width */ @@ -131,6 +137,7 @@ typedef struct VideoPicture { typedef struct SubPicture { double pts; /* presentation time stamp for this picture */ AVSubtitle sub; + int serial; } SubPicture; typedef struct AudioParams { @@ -140,6 +147,16 @@ typedef struct AudioParams { enum AVSampleFormat fmt; } AudioParams; +typedef struct Clock { + double pts; /* clock base */ + double pts_drift; /* clock base minus time at which we updated the clock */ + double last_updated; + double speed; + int serial; /* clock is based on a packet with this serial */ + int paused; + int *queue_serial; /* pointer to the current packet queue serial, used for obsolete clock detection */ +} Clock; + enum { AV_SYNC_AUDIO_MASTER, /* default choice */ AV_SYNC_VIDEO_MASTER, @@ -163,14 +180,16 @@ typedef struct VideoState { int read_pause_return; AVFormatContext *ic; int realtime; + int audio_finished; + int video_finished; + + Clock audclk; + Clock vidclk; + Clock extclk; int audio_stream; int av_sync_type; - double external_clock; ///< external clock base - double external_clock_drift; ///< external clock base - time (av_gettime) at which we updated external_clock - int64_t external_clock_time; ///< last reference time - double external_clock_speed; ///< speed of the external clock double audio_clock; int audio_clock_serial; @@ -188,6 +207,7 @@ typedef struct VideoState { unsigned int audio_buf1_size; int audio_buf_index; /* in bytes */ int audio_write_buf_size; + int audio_buf_frames_pending; AVPacket audio_pkt_temp; AVPacket audio_pkt; int audio_pkt_temp_serial; @@ -198,11 +218,10 @@ typedef struct VideoState { #endif struct AudioParams audio_tgt; struct SwrContext *swr_ctx; - double audio_current_pts; - double audio_current_pts_drift; int frame_drops_early; int frame_drops_late; AVFrame *frame; + int64_t audio_frame_next_pts; enum ShowMode { SHOW_MODE_NONE = -1, SHOW_MODE_VIDEO = 0, SHOW_MODE_WAVES, SHOW_MODE_RDFT, SHOW_MODE_NB @@ -218,7 +237,6 @@ typedef struct VideoState { SDL_Thread *subtitle_tid; int subtitle_stream; - int subtitle_stream_changed; AVStream *subtitle_st; PacketQueue subtitleq; SubPicture subpq[SUBPICTURE_QUEUE_SIZE]; @@ -227,20 +245,13 @@ typedef struct VideoState { SDL_cond *subpq_cond; double frame_timer; - double frame_last_pts; - double frame_last_duration; - double frame_last_dropped_pts; double frame_last_returned_time; double frame_last_filter_delay; - int64_t frame_last_dropped_pos; int video_stream; AVStream *video_st; PacketQueue videoq; - double video_current_pts; // current displayed pts - 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; @@ -295,7 +306,6 @@ static int workaround_bugs = 1; static int fast = 0; static int genpts = 0; static int lowres = 0; -static int idct = FF_IDCT_AUTO; static int error_concealment = 3; static int decoder_reorder_pts = -1; static int autoexit; @@ -395,6 +405,16 @@ static int packet_queue_put(PacketQueue *q, AVPacket *pkt) return ret; } +static int packet_queue_put_nullpacket(PacketQueue *q, int stream_index) +{ + AVPacket pkt1, *pkt = &pkt1; + av_init_packet(pkt); + pkt->data = NULL; + pkt->size = 0; + pkt->stream_index = stream_index; + return packet_queue_put(q, pkt); +} + /* packet queue handling */ static void packet_queue_init(PacketQueue *q) { @@ -763,6 +783,14 @@ static void blend_subrect(AVPicture *dst, const AVSubtitleRect *rect, int imgw, } } +static void free_picture(VideoPicture *vp) +{ + if (vp->bmp) { + SDL_FreeYUVOverlay(vp->bmp); + vp->bmp = NULL; + } +} + static void free_subpicture(SubPicture *sp) { avsubtitle_free(&sp->sub); @@ -965,7 +993,8 @@ static void video_audio_display(VideoState *s) } av_rdft_calc(s->rdft, data[ch]); } - // least efficient way to do this, we should of course directly access it but its more than fast enough + /* Least efficient way to do this, we should of course + * directly access it but it is more than fast enough. */ for (y = 0; y < s->height; y++) { double w = 1 / sqrt(nb_freq); int a = sqrt(w * sqrt(data[0][2 * y + 0] * data[0][2 * y + 0] + data[0][2 * y + 1] * data[0][2 * y + 1])); @@ -990,7 +1019,6 @@ static void video_audio_display(VideoState *s) static void stream_close(VideoState *is) { - VideoPicture *vp; int i; /* XXX: use a special url_shutdown call to abort parse cleanly */ is->abort_request = 1; @@ -1000,13 +1028,10 @@ static void stream_close(VideoState *is) packet_queue_destroy(&is->subtitleq); /* free all pictures */ - for (i = 0; i < VIDEO_PICTURE_QUEUE_SIZE; i++) { - vp = &is->pictq[i]; - if (vp->bmp) { - SDL_FreeYUVOverlay(vp->bmp); - vp->bmp = NULL; - } - } + for (i = 0; i < VIDEO_PICTURE_QUEUE_SIZE; i++) + free_picture(&is->pictq[i]); + for (i = 0; i < SUBPICTURE_QUEUE_SIZE; i++) + free_subpicture(&is->subpq[i]); SDL_DestroyMutex(is->pictq_mutex); SDL_DestroyCond(is->pictq_cond); SDL_DestroyMutex(is->subpq_mutex); @@ -1026,7 +1051,6 @@ static void do_exit(VideoState *is) av_lockmgr_register(NULL); uninit_opts(); #if CONFIG_AVFILTER - avfilter_uninit(); av_freep(&vfilters); #endif avformat_network_deinit(); @@ -1042,20 +1066,24 @@ static void sigterm_handler(int sig) exit(123); } +static void set_default_window_size(VideoPicture *vp) +{ + SDL_Rect rect; + calculate_display_rect(&rect, 0, 0, INT_MAX, vp->height, vp); + default_width = rect.w; + default_height = rect.h; +} + static int video_open(VideoState *is, int force_set_video_mode, VideoPicture *vp) { int flags = SDL_HWSURFACE | SDL_ASYNCBLIT | SDL_HWACCEL; int w,h; - SDL_Rect rect; if (is_full_screen) flags |= SDL_FULLSCREEN; else flags |= SDL_RESIZABLE; - if (vp && vp->width) { - calculate_display_rect(&rect, 0, 0, INT_MAX, vp->height, vp); - default_width = rect.w; - default_height = rect.h; - } + if (vp && vp->width) + set_default_window_size(vp); if (is_full_screen && fs_screen_width) { w = fs_screen_width; @@ -1067,12 +1095,13 @@ static int video_open(VideoState *is, int force_set_video_mode, VideoPicture *vp w = default_width; h = default_height; } + w = FFMIN(16383, w); if (screen && is->width == screen->w && screen->w == w && is->height== screen->h && screen->h == h && !force_set_video_mode) return 0; screen = SDL_SetVideoMode(w, h, 0, flags); if (!screen) { - fprintf(stderr, "SDL: could not set video mode - exiting\n"); + av_log(NULL, AV_LOG_FATAL, "SDL: could not set video mode - exiting\n"); do_exit(is); } if (!window_title) @@ -1096,39 +1125,52 @@ static void video_display(VideoState *is) video_image_display(is); } -/* get the current audio clock value */ -static double get_audio_clock(VideoState *is) +static double get_clock(Clock *c) { - if (is->audio_clock_serial != is->audioq.serial) + if (*c->queue_serial != c->serial) return NAN; - if (is->paused) { - return is->audio_current_pts; + if (c->paused) { + return c->pts; } else { - return is->audio_current_pts_drift + av_gettime() / 1000000.0; + double time = av_gettime() / 1000000.0; + return c->pts_drift + time - (time - c->last_updated) * (1.0 - c->speed); } } -/* get the current video clock value */ -static double get_video_clock(VideoState *is) +static void set_clock_at(Clock *c, double pts, int serial, double time) { - if (is->video_clock_serial != is->videoq.serial) - return NAN; - if (is->paused) { - return is->video_current_pts; - } else { - return is->video_current_pts_drift + av_gettime() / 1000000.0; - } + c->pts = pts; + c->last_updated = time; + c->pts_drift = c->pts - time; + c->serial = serial; } -/* get the current external clock value */ -static double get_external_clock(VideoState *is) +static void set_clock(Clock *c, double pts, int serial) { - if (is->paused) { - return is->external_clock; - } else { - double time = av_gettime() / 1000000.0; - return is->external_clock_drift + time - (time - is->external_clock_time / 1000000.0) * (1.0 - is->external_clock_speed); - } + double time = av_gettime() / 1000000.0; + set_clock_at(c, pts, serial, time); +} + +static void set_clock_speed(Clock *c, double speed) +{ + set_clock(c, get_clock(c), c->serial); + c->speed = speed; +} + +static void init_clock(Clock *c, int *queue_serial) +{ + c->speed = 1.0; + c->paused = 0; + c->queue_serial = queue_serial; + set_clock(c, NAN, -1); +} + +static void sync_clock_to_slave(Clock *c, Clock *slave) +{ + double clock = get_clock(c); + double slave_clock = get_clock(slave); + if (!isnan(slave_clock) && (isnan(clock) || fabs(clock - slave_clock) > AV_NOSYNC_THRESHOLD)) + set_clock(c, slave_clock, slave->serial); } static int get_master_sync_type(VideoState *is) { @@ -1154,48 +1196,29 @@ static double get_master_clock(VideoState *is) switch (get_master_sync_type(is)) { case AV_SYNC_VIDEO_MASTER: - val = get_video_clock(is); + val = get_clock(&is->vidclk); break; case AV_SYNC_AUDIO_MASTER: - val = get_audio_clock(is); + val = get_clock(&is->audclk); break; default: - val = get_external_clock(is); + val = get_clock(&is->extclk); break; } return val; } -static void update_external_clock_pts(VideoState *is, double pts) -{ - is->external_clock_time = av_gettime(); - is->external_clock = pts; - is->external_clock_drift = pts - is->external_clock_time / 1000000.0; -} - -static void check_external_clock_sync(VideoState *is, double pts) { - double ext_clock = get_external_clock(is); - if (isnan(ext_clock) || fabs(ext_clock - pts) > AV_NOSYNC_THRESHOLD) { - update_external_clock_pts(is, pts); - } -} - -static void update_external_clock_speed(VideoState *is, double speed) { - update_external_clock_pts(is, get_external_clock(is)); - is->external_clock_speed = speed; -} - static void check_external_clock_speed(VideoState *is) { if (is->video_stream >= 0 && is->videoq.nb_packets <= MIN_FRAMES / 2 || is->audio_stream >= 0 && is->audioq.nb_packets <= MIN_FRAMES / 2) { - update_external_clock_speed(is, FFMAX(EXTERNAL_CLOCK_SPEED_MIN, is->external_clock_speed - EXTERNAL_CLOCK_SPEED_STEP)); + set_clock_speed(&is->extclk, FFMAX(EXTERNAL_CLOCK_SPEED_MIN, is->extclk.speed - EXTERNAL_CLOCK_SPEED_STEP)); } else if ((is->video_stream < 0 || is->videoq.nb_packets > MIN_FRAMES * 2) && (is->audio_stream < 0 || is->audioq.nb_packets > MIN_FRAMES * 2)) { - update_external_clock_speed(is, FFMIN(EXTERNAL_CLOCK_SPEED_MAX, is->external_clock_speed + EXTERNAL_CLOCK_SPEED_STEP)); + set_clock_speed(&is->extclk, FFMIN(EXTERNAL_CLOCK_SPEED_MAX, is->extclk.speed + EXTERNAL_CLOCK_SPEED_STEP)); } else { - double speed = is->external_clock_speed; + double speed = is->extclk.speed; if (speed != 1.0) - update_external_clock_speed(is, speed + EXTERNAL_CLOCK_SPEED_STEP * (1.0 - speed) / fabs(1.0 - speed)); + set_clock_speed(&is->extclk, speed + EXTERNAL_CLOCK_SPEED_STEP * (1.0 - speed) / fabs(1.0 - speed)); } } @@ -1217,14 +1240,14 @@ static void stream_seek(VideoState *is, int64_t pos, int64_t rel, int seek_by_by static void stream_toggle_pause(VideoState *is) { if (is->paused) { - is->frame_timer += av_gettime() / 1000000.0 + is->video_current_pts_drift - is->video_current_pts; + is->frame_timer += av_gettime() / 1000000.0 + is->vidclk.pts_drift - is->vidclk.pts; if (is->read_pause_return != AVERROR(ENOSYS)) { - is->video_current_pts = is->video_current_pts_drift + av_gettime() / 1000000.0; + is->vidclk.paused = 0; } - is->video_current_pts_drift = is->video_current_pts - av_gettime() / 1000000.0; + set_clock(&is->vidclk, get_clock(&is->vidclk), is->vidclk.serial); } - update_external_clock_pts(is, get_external_clock(is)); - is->paused = !is->paused; + set_clock(&is->extclk, get_clock(&is->extclk), is->extclk.serial); + is->paused = is->audclk.paused = is->vidclk.paused = is->extclk.paused = !is->paused; } static void toggle_pause(VideoState *is) @@ -1249,15 +1272,17 @@ static double compute_target_delay(double delay, VideoState *is) if (get_master_sync_type(is) != AV_SYNC_VIDEO_MASTER) { /* if video is slave, we try to correct big delays by duplicating or deleting a frame */ - diff = get_video_clock(is) - get_master_clock(is); + diff = get_clock(&is->vidclk) - get_master_clock(is); /* skip or repeat frame. We take into account the delay to compute the threshold. I still don't know if it is the best guess */ - sync_threshold = FFMAX(AV_SYNC_THRESHOLD, delay); - if (!isnan(diff) && fabs(diff) < AV_NOSYNC_THRESHOLD) { + sync_threshold = FFMAX(AV_SYNC_THRESHOLD_MIN, FFMIN(AV_SYNC_THRESHOLD_MAX, delay)); + if (!isnan(diff) && fabs(diff) < is->max_frame_duration) { if (diff <= -sync_threshold) - delay = 0; + delay = FFMAX(0, delay + diff); + else if (diff >= sync_threshold && delay > AV_SYNC_FRAMEDUP_THRESHOLD) + delay = delay + diff; else if (diff >= sync_threshold) delay = 2 * delay; } @@ -1269,6 +1294,18 @@ static double compute_target_delay(double delay, VideoState *is) return delay; } +static double vp_duration(VideoState *is, VideoPicture *vp, VideoPicture *nextvp) { + if (vp->serial == nextvp->serial) { + double duration = nextvp->pts - vp->pts; + if (isnan(duration) || duration <= 0 || duration > is->max_frame_duration) + return vp->duration; + else + return duration; + } else { + return 0.0; + } +} + static void pictq_next_picture(VideoState *is) { /* update queue size and signal for next picture */ if (++is->pictq_rindex == VIDEO_PICTURE_QUEUE_SIZE) @@ -1287,7 +1324,7 @@ static int pictq_prev_picture(VideoState *is) { prevvp = &is->pictq[(is->pictq_rindex + VIDEO_PICTURE_QUEUE_SIZE - 1) % VIDEO_PICTURE_QUEUE_SIZE]; if (prevvp->allocated && prevvp->serial == is->videoq.serial) { SDL_LockMutex(is->pictq_mutex); - if (is->pictq_size < VIDEO_PICTURE_QUEUE_SIZE - 1) { + if (is->pictq_size < VIDEO_PICTURE_QUEUE_SIZE) { if (--is->pictq_rindex == -1) is->pictq_rindex = VIDEO_PICTURE_QUEUE_SIZE - 1; is->pictq_size++; @@ -1300,22 +1337,16 @@ static int pictq_prev_picture(VideoState *is) { } static void update_video_pts(VideoState *is, double pts, int64_t pos, int serial) { - double time = av_gettime() / 1000000.0; /* update current video pts */ - is->video_current_pts = pts; - is->video_current_pts_drift = is->video_current_pts - time; + set_clock(&is->vidclk, pts, serial); + sync_clock_to_slave(&is->extclk, &is->vidclk); 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); } /* called to display each frame */ static void video_refresh(void *opaque, double *remaining_time) { VideoState *is = opaque; - VideoPicture *vp; double time; SubPicture *sp, *sp2; @@ -1338,51 +1369,53 @@ static void video_refresh(void *opaque, double *remaining_time) redisplay = pictq_prev_picture(is); retry: if (is->pictq_size == 0) { - SDL_LockMutex(is->pictq_mutex); - if (is->frame_last_dropped_pts != AV_NOPTS_VALUE && is->frame_last_dropped_pts > is->frame_last_pts) { - update_video_pts(is, is->frame_last_dropped_pts, is->frame_last_dropped_pos, 0); - is->frame_last_dropped_pts = AV_NOPTS_VALUE; - } - SDL_UnlockMutex(is->pictq_mutex); // nothing to do, no picture to display in the queue } else { double last_duration, duration, delay; + VideoPicture *vp, *lastvp; + /* dequeue the picture */ vp = &is->pictq[is->pictq_rindex]; + lastvp = &is->pictq[(is->pictq_rindex + VIDEO_PICTURE_QUEUE_SIZE - 1) % VIDEO_PICTURE_QUEUE_SIZE]; if (vp->serial != is->videoq.serial) { pictq_next_picture(is); + is->video_current_pos = -1; redisplay = 0; goto retry; } + if (lastvp->serial != vp->serial && !redisplay) + is->frame_timer = av_gettime() / 1000000.0; + if (is->paused) goto display; /* compute nominal last_duration */ - last_duration = vp->pts - is->frame_last_pts; - if (last_duration > 0 && last_duration < is->max_frame_duration) { - /* if duration of the last frame was sane, update last_duration in video state */ - is->frame_last_duration = last_duration; - } - delay = compute_target_delay(is->frame_last_duration, is); + last_duration = vp_duration(is, lastvp, vp); + if (redisplay) + delay = 0.0; + else + delay = compute_target_delay(last_duration, is); time= av_gettime()/1000000.0; - if (time < is->frame_timer + delay) { + if (time < is->frame_timer + delay && !redisplay) { *remaining_time = FFMIN(is->frame_timer + delay - time, *remaining_time); return; } - if (delay > 0) - is->frame_timer += delay * FFMAX(1, floor((time-is->frame_timer) / delay)); + is->frame_timer += delay; + if (delay > 0 && time - is->frame_timer > AV_SYNC_THRESHOLD_MAX) + is->frame_timer = time; SDL_LockMutex(is->pictq_mutex); - update_video_pts(is, vp->pts, vp->pos, vp->serial); + if (!redisplay && !isnan(vp->pts)) + update_video_pts(is, vp->pts, vp->pos, vp->serial); SDL_UnlockMutex(is->pictq_mutex); if (is->pictq_size > 1) { VideoPicture *nextvp = &is->pictq[(is->pictq_rindex + 1) % VIDEO_PICTURE_QUEUE_SIZE]; - duration = nextvp->pts - vp->pts; + duration = vp_duration(is, vp, nextvp); 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++; @@ -1393,24 +1426,7 @@ retry: } if (is->subtitle_st) { - if (is->subtitle_stream_changed) { - SDL_LockMutex(is->subpq_mutex); - - while (is->subpq_size) { - free_subpicture(&is->subpq[is->subpq_rindex]); - - /* update queue size and signal for next picture */ - if (++is->subpq_rindex == SUBPICTURE_QUEUE_SIZE) - is->subpq_rindex = 0; - - is->subpq_size--; - } - is->subtitle_stream_changed = 0; - - SDL_CondSignal(is->subpq_cond); - SDL_UnlockMutex(is->subpq_mutex); - } else { - if (is->subpq_size > 0) { + while (is->subpq_size > 0) { sp = &is->subpq[is->subpq_rindex]; if (is->subpq_size > 1) @@ -1418,8 +1434,9 @@ retry: else sp2 = NULL; - if ((is->video_current_pts > (sp->pts + ((float) sp->sub.end_display_time / 1000))) - || (sp2 && is->video_current_pts > (sp2->pts + ((float) sp2->sub.start_display_time / 1000)))) + if (sp->serial != is->subtitleq.serial + || (is->vidclk.pts > (sp->pts + ((float) sp->sub.end_display_time / 1000))) + || (sp2 && is->vidclk.pts > (sp2->pts + ((float) sp2->sub.start_display_time / 1000)))) { free_subpicture(sp); @@ -1431,9 +1448,10 @@ retry: is->subpq_size--; SDL_CondSignal(is->subpq_cond); SDL_UnlockMutex(is->subpq_mutex); + } else { + break; } } - } } display: @@ -1467,9 +1485,15 @@ display: sqsize = is->subtitleq.size; av_diff = 0; if (is->audio_st && is->video_st) - av_diff = get_audio_clock(is) - get_video_clock(is); - printf("%7.2f A-V:%7.3f fd=%4d aq=%5dKB vq=%5dKB sq=%5dB f=%"PRId64"/%"PRId64" \r", + av_diff = get_clock(&is->audclk) - get_clock(&is->vidclk); + else if (is->video_st) + av_diff = get_master_clock(is) - get_clock(&is->vidclk); + else if (is->audio_st) + av_diff = get_master_clock(is) - get_clock(&is->audclk); + av_log(NULL, AV_LOG_INFO, + "%7.2f %s:%7.3f fd=%4d aq=%5dKB vq=%5dKB sq=%5dB f=%"PRId64"/%"PRId64" \r", get_master_clock(is), + (is->audio_st && is->video_st) ? "A-V" : (is->video_st ? "M-V" : (is->audio_st ? "M-A" : " ")), av_diff, is->frame_drops_early + is->frame_drops_late, aqsize / 1024, @@ -1488,21 +1512,23 @@ display: static void alloc_picture(VideoState *is) { VideoPicture *vp; + int64_t bufferdiff; vp = &is->pictq[is->pictq_windex]; - if (vp->bmp) - SDL_FreeYUVOverlay(vp->bmp); + free_picture(vp); video_open(is, 0, vp); vp->bmp = SDL_CreateYUVOverlay(vp->width, vp->height, SDL_YV12_OVERLAY, screen); - if (!vp->bmp || vp->bmp->pitches[0] < vp->width) { + bufferdiff = vp->bmp ? FFMAX(vp->bmp->pixels[0], vp->bmp->pixels[1]) - FFMIN(vp->bmp->pixels[0], vp->bmp->pixels[1]) : 0; + if (!vp->bmp || vp->bmp->pitches[0] < vp->width || bufferdiff < (int64_t)vp->height * vp->bmp->pitches[0]) { /* SDL allocates a buffer smaller than requested if the video * overlay hardware is unable to support the requested size. */ - fprintf(stderr, "Error: the video system does not support an image\n" + av_log(NULL, AV_LOG_FATAL, + "Error: the video system does not support an image\n" "size of %dx%d pixels. Try using -lowres or -vf \"scale=w:h\"\n" "to reduce the image size.\n", vp->width, vp->height ); do_exit(is); @@ -1532,7 +1558,7 @@ static void duplicate_right_border_pixels(SDL_Overlay *bmp) { } } -static int queue_picture(VideoState *is, AVFrame *src_frame, double pts, int64_t pos, int serial) +static int queue_picture(VideoState *is, AVFrame *src_frame, double pts, double duration, int64_t pos, int serial) { VideoPicture *vp; @@ -1545,7 +1571,7 @@ static int queue_picture(VideoState *is, AVFrame *src_frame, double pts, int64_t SDL_LockMutex(is->pictq_mutex); /* keep the last already displayed picture in the queue */ - while (is->pictq_size >= VIDEO_PICTURE_QUEUE_SIZE - 2 && + while (is->pictq_size >= VIDEO_PICTURE_QUEUE_SIZE - 1 && !is->videoq.abort_request) { SDL_CondWait(is->pictq_cond, is->pictq_mutex); } @@ -1556,11 +1582,7 @@ static int queue_picture(VideoState *is, AVFrame *src_frame, double pts, int64_t vp = &is->pictq[is->pictq_windex]; -#if CONFIG_AVFILTER vp->sar = src_frame->sample_aspect_ratio; -#else - vp->sar = av_guess_sample_aspect_ratio(is->ic, is->video_st, src_frame); -#endif /* alloc or resize hardware picture buffer */ if (!vp->bmp || vp->reallocate || !vp->allocated || @@ -1621,7 +1643,7 @@ static int queue_picture(VideoState *is, AVFrame *src_frame, double pts, int64_t vp->width, vp->height, src_frame->format, vp->width, vp->height, AV_PIX_FMT_YUV420P, sws_flags, NULL, NULL, NULL); if (is->img_convert_ctx == NULL) { - fprintf(stderr, "Cannot initialize the conversion context\n"); + av_log(NULL, AV_LOG_FATAL, "Cannot initialize the conversion context\n"); exit(1); } sws_scale(is->img_convert_ctx, src_frame->data, src_frame->linesize, @@ -1633,6 +1655,7 @@ static int queue_picture(VideoState *is, AVFrame *src_frame, double pts, int64_t SDL_UnlockYUVOverlay(vp->bmp); vp->pts = pts; + vp->duration = duration; vp->pos = pos; vp->serial = serial; @@ -1646,7 +1669,7 @@ static int queue_picture(VideoState *is, AVFrame *src_frame, double pts, int64_t return 0; } -static int get_video_frame(VideoState *is, AVFrame *frame, int64_t *pts, AVPacket *pkt, int *serial) +static int get_video_frame(VideoState *is, AVFrame *frame, AVPacket *pkt, int *serial) { int got_picture; @@ -1655,55 +1678,44 @@ static int get_video_frame(VideoState *is, AVFrame *frame, int64_t *pts, AVPacke if (pkt->data == flush_pkt.data) { avcodec_flush_buffers(is->video_st->codec); - - SDL_LockMutex(is->pictq_mutex); - // Make sure there are no long delay timers (ideally we should just flush the queue but that's harder) - while (is->pictq_size && !is->videoq.abort_request) { - SDL_CondWait(is->pictq_cond, is->pictq_mutex); - } - is->video_current_pos = -1; - is->frame_last_pts = AV_NOPTS_VALUE; - is->frame_last_duration = 0; - is->frame_timer = (double)av_gettime() / 1000000.0; - is->frame_last_dropped_pts = AV_NOPTS_VALUE; - SDL_UnlockMutex(is->pictq_mutex); return 0; } if(avcodec_decode_video2(is->video_st->codec, frame, &got_picture, pkt) < 0) return 0; + if (!got_picture && !pkt->data) + is->video_finished = *serial; + if (got_picture) { int ret = 1; + double dpts = NAN; if (decoder_reorder_pts == -1) { - *pts = av_frame_get_best_effort_timestamp(frame); + frame->pts = av_frame_get_best_effort_timestamp(frame); } else if (decoder_reorder_pts) { - *pts = frame->pkt_pts; + frame->pts = frame->pkt_pts; } else { - *pts = frame->pkt_dts; + frame->pts = frame->pkt_dts; } - if (*pts == AV_NOPTS_VALUE) { - *pts = 0; - } + if (frame->pts != AV_NOPTS_VALUE) + dpts = av_q2d(is->video_st->time_base) * frame->pts; + + frame->sample_aspect_ratio = av_guess_sample_aspect_ratio(is->ic, is->video_st, frame); if (framedrop>0 || (framedrop && get_master_sync_type(is) != AV_SYNC_VIDEO_MASTER)) { - SDL_LockMutex(is->pictq_mutex); - if (is->frame_last_pts != AV_NOPTS_VALUE && *pts) { - 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 (!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; - is->frame_last_dropped_pts = dpts; + if (frame->pts != AV_NOPTS_VALUE) { + double diff = dpts - get_master_clock(is); + if (!isnan(diff) && fabs(diff) < AV_NOSYNC_THRESHOLD && + diff - is->frame_last_filter_delay < 0 && + *serial == is->vidclk.serial && + is->videoq.nb_packets) { is->frame_drops_early++; + av_frame_unref(frame); ret = 0; } } - SDL_UnlockMutex(is->pictq_mutex); } return ret; @@ -1736,7 +1748,7 @@ static int configure_filtergraph(AVFilterGraph *graph, const char *filtergraph, inputs->pad_idx = 0; inputs->next = NULL; - if ((ret = avfilter_graph_parse(graph, filtergraph, &inputs, &outputs, NULL)) < 0) + if ((ret = avfilter_graph_parse_ptr(graph, filtergraph, &inputs, &outputs, NULL)) < 0) goto fail; } else { if ((ret = avfilter_link(source_ctx, 0, sink_ctx, 0)) < 0) @@ -1756,12 +1768,9 @@ static int configure_video_filters(AVFilterGraph *graph, VideoState *is, const c char sws_flags_str[128]; char buffersrc_args[256]; int ret; - AVBufferSinkParams *buffersink_params = av_buffersink_params_alloc(); AVFilterContext *filt_src = NULL, *filt_out = NULL, *filt_crop; AVCodecContext *codec = is->video_st->codec; - - if (!buffersink_params) - return AVERROR(ENOMEM); + AVRational fr = av_guess_frame_rate(is->ic, is->video_st, NULL); av_opt_get_int(sws_opts, "sws_flags", 0, &sws_flags); snprintf(sws_flags_str, sizeof(sws_flags_str), "flags=%"PRId64, sws_flags); @@ -1772,6 +1781,8 @@ static int configure_video_filters(AVFilterGraph *graph, VideoState *is, const c frame->width, frame->height, frame->format, is->video_st->time_base.num, is->video_st->time_base.den, codec->sample_aspect_ratio.num, FFMAX(codec->sample_aspect_ratio.den, 1)); + if (fr.num && fr.den) + av_strlcatf(buffersrc_args, sizeof(buffersrc_args), ":frame_rate=%d/%d", fr.num, fr.den); if ((ret = avfilter_graph_create_filter(&filt_src, avfilter_get_by_name("buffer"), @@ -1779,13 +1790,15 @@ static int configure_video_filters(AVFilterGraph *graph, VideoState *is, const c graph)) < 0) goto fail; - buffersink_params->pixel_fmts = pix_fmts; ret = avfilter_graph_create_filter(&filt_out, avfilter_get_by_name("buffersink"), - "ffplay_buffersink", NULL, buffersink_params, graph); + "ffplay_buffersink", NULL, NULL, graph); if (ret < 0) goto fail; + if ((ret = av_opt_set_int_list(filt_out, "pix_fmts", pix_fmts, AV_PIX_FMT_NONE, AV_OPT_SEARCH_CHILDREN)) < 0) + goto fail; + /* SDL YUV code is not handling odd width/height for some driver * combinations, therefore we crop the picture to an even width/height. */ if ((ret = avfilter_graph_create_filter(&filt_crop, @@ -1802,7 +1815,6 @@ static int configure_video_filters(AVFilterGraph *graph, VideoState *is, const c is->out_video_filter = filt_out; fail: - av_freep(&buffersink_params); return ret; } @@ -1813,18 +1825,26 @@ static int configure_audio_filters(VideoState *is, const char *afilters, int for int64_t channel_layouts[2] = { 0, -1 }; int channels[2] = { 0, -1 }; AVFilterContext *filt_asrc = NULL, *filt_asink = NULL; + char aresample_swr_opts[512] = ""; + AVDictionaryEntry *e = NULL; char asrc_args[256]; - AVABufferSinkParams *asink_params = NULL; int ret; avfilter_graph_free(&is->agraph); if (!(is->agraph = avfilter_graph_alloc())) return AVERROR(ENOMEM); + while ((e = av_dict_get(swr_opts, "", e, AV_DICT_IGNORE_SUFFIX))) + av_strlcatf(aresample_swr_opts, sizeof(aresample_swr_opts), "%s=%s:", e->key, e->value); + if (strlen(aresample_swr_opts)) + aresample_swr_opts[strlen(aresample_swr_opts)-1] = '\0'; + av_opt_set(is->agraph, "aresample_swr_opts", aresample_swr_opts, 0); + ret = snprintf(asrc_args, sizeof(asrc_args), - "sample_rate=%d:sample_fmt=%s:channels=%d", + "sample_rate=%d:sample_fmt=%s:channels=%d:time_base=%d/%d", is->audio_filter_src.freq, av_get_sample_fmt_name(is->audio_filter_src.fmt), - is->audio_filter_src.channels); + is->audio_filter_src.channels, + 1, is->audio_filter_src.freq); if (is->audio_filter_src.channel_layout) snprintf(asrc_args + ret, sizeof(asrc_args) - ret, ":channel_layout=0x%"PRIx64, is->audio_filter_src.channel_layout); @@ -1835,29 +1855,32 @@ static int configure_audio_filters(VideoState *is, const char *afilters, int for if (ret < 0) goto end; - if (!(asink_params = av_abuffersink_params_alloc())) { - ret = AVERROR(ENOMEM); + + ret = avfilter_graph_create_filter(&filt_asink, + avfilter_get_by_name("abuffersink"), "ffplay_abuffersink", + NULL, NULL, is->agraph); + if (ret < 0) + goto end; + + if ((ret = av_opt_set_int_list(filt_asink, "sample_fmts", sample_fmts, AV_SAMPLE_FMT_NONE, AV_OPT_SEARCH_CHILDREN)) < 0) + goto end; + if ((ret = av_opt_set_int(filt_asink, "all_channel_counts", 1, AV_OPT_SEARCH_CHILDREN)) < 0) goto end; - } - asink_params->sample_fmts = sample_fmts; - asink_params->all_channel_counts = 1; if (force_output_format) { channel_layouts[0] = is->audio_tgt.channel_layout; - asink_params->channel_layouts = channel_layouts; - asink_params->all_channel_counts = 0; - channels[0] = is->audio_tgt.channels; - asink_params->channel_counts = channels; - asink_params->all_channel_counts = 0; - sample_rates[0] = is->audio_tgt.freq; - asink_params->sample_rates = sample_rates; + channels [0] = is->audio_tgt.channels; + sample_rates [0] = is->audio_tgt.freq; + if ((ret = av_opt_set_int(filt_asink, "all_channel_counts", 0, AV_OPT_SEARCH_CHILDREN)) < 0) + goto end; + if ((ret = av_opt_set_int_list(filt_asink, "channel_layouts", channel_layouts, -1, AV_OPT_SEARCH_CHILDREN)) < 0) + goto end; + if ((ret = av_opt_set_int_list(filt_asink, "channel_counts" , channels , -1, AV_OPT_SEARCH_CHILDREN)) < 0) + goto end; + if ((ret = av_opt_set_int_list(filt_asink, "sample_rates" , sample_rates , -1, AV_OPT_SEARCH_CHILDREN)) < 0) + goto end; } - ret = avfilter_graph_create_filter(&filt_asink, - avfilter_get_by_name("abuffersink"), "ffplay_abuffersink", - NULL, asink_params, is->agraph); - if (ret < 0) - goto end; if ((ret = configure_filtergraph(is->agraph, afilters, filt_asrc, filt_asink)) < 0) goto end; @@ -1866,7 +1889,6 @@ static int configure_audio_filters(VideoState *is, const char *afilters, int for is->out_audio_filter = filt_asink; end: - av_freep(&asink_params); if (ret < 0) avfilter_graph_free(&is->agraph); return ret; @@ -1878,10 +1900,12 @@ static int video_thread(void *arg) AVPacket pkt = { 0 }; VideoState *is = arg; AVFrame *frame = av_frame_alloc(); - int64_t pts_int = AV_NOPTS_VALUE, pos = -1; double pts; + double duration; int ret; int serial = 0; + AVRational tb = is->video_st->time_base; + AVRational frame_rate = av_guess_frame_rate(is->ic, is->video_st, NULL); #if CONFIG_AVFILTER AVFilterGraph *graph = avfilter_graph_alloc(); @@ -1893,19 +1917,15 @@ static int video_thread(void *arg) #endif for (;;) { -#if CONFIG_AVFILTER - AVRational tb; -#endif while (is->paused && !is->videoq.abort_request) SDL_Delay(10); avcodec_get_frame_defaults(frame); av_free_packet(&pkt); - ret = get_video_frame(is, frame, &pts_int, &pkt, &serial); + ret = get_video_frame(is, frame, &pkt, &serial); if (ret < 0) goto the_end; - if (!ret) continue; @@ -1936,10 +1956,9 @@ static int video_thread(void *arg) last_h = frame->height; last_format = frame->format; last_serial = serial; + frame_rate = filt_out->inputs[0]->frame_rate; } - frame->pts = pts_int; - frame->sample_aspect_ratio = av_guess_sample_aspect_ratio(is->ic, is->video_st, frame); ret = av_buffersrc_add_frame(filt_in, frame); if (ret < 0) goto the_end; @@ -1952,6 +1971,8 @@ static int video_thread(void *arg) ret = av_buffersink_get_frame_flags(filt_out, frame, 0); if (ret < 0) { + if (ret == AVERROR_EOF) + is->video_finished = serial; ret = 0; break; } @@ -1959,33 +1980,20 @@ static int video_thread(void *arg) is->frame_last_filter_delay = av_gettime() / 1000000.0 - is->frame_last_returned_time; if (fabs(is->frame_last_filter_delay) > AV_NOSYNC_THRESHOLD / 10.0) is->frame_last_filter_delay = 0; - - pts_int = frame->pts; - tb = filt_out->inputs[0]->time_base; - pos = av_frame_get_pkt_pos(frame); - if (av_cmp_q(tb, is->video_st->time_base)) { - av_unused int64_t pts1 = pts_int; - pts_int = av_rescale_q(pts_int, tb, is->video_st->time_base); - av_dlog(NULL, "video_thread(): " - "tb:%d/%d pts:%"PRId64" -> tb:%d/%d pts:%"PRId64"\n", - tb.num, tb.den, pts1, - is->video_st->time_base.num, is->video_st->time_base.den, pts_int); - } - pts = pts_int * av_q2d(is->video_st->time_base); - ret = queue_picture(is, frame, pts, pos, serial); + tb = filt_out->inputs[0]->time_base; +#endif + duration = (frame_rate.num && frame_rate.den ? av_q2d((AVRational){frame_rate.den, frame_rate.num}) : 0); + pts = (frame->pts == AV_NOPTS_VALUE) ? NAN : frame->pts * av_q2d(tb); + ret = queue_picture(is, frame, pts, duration, av_frame_get_pkt_pos(frame), serial); av_frame_unref(frame); +#if CONFIG_AVFILTER } -#else - pts = pts_int * av_q2d(is->video_st->time_base); - ret = queue_picture(is, frame, pts, pkt.pos, serial); - av_frame_unref(frame); #endif if (ret < 0) goto the_end; } the_end: - avcodec_flush_buffers(is->video_st->codec); #if CONFIG_AVFILTER avfilter_graph_free(&graph); #endif @@ -2000,6 +2008,7 @@ static int subtitle_thread(void *arg) SubPicture *sp; AVPacket pkt1, *pkt = &pkt1; int got_subtitle; + int serial; double pts; int i, j; int r, g, b, y, u, v, a; @@ -2008,7 +2017,7 @@ static int subtitle_thread(void *arg) while (is->paused && !is->subtitleq.abort_request) { SDL_Delay(10); } - if (packet_queue_get(&is->subtitleq, pkt, 1, NULL) < 0) + if (packet_queue_get(&is->subtitleq, pkt, 1, &serial) < 0) break; if (pkt->data == flush_pkt.data) { @@ -2039,6 +2048,7 @@ static int subtitle_thread(void *arg) if (sp->sub.pts != AV_NOPTS_VALUE) pts = sp->sub.pts / (double)AV_TIME_BASE; sp->pts = pts; + sp->serial = serial; for (i = 0; i < sp->sub.num_rects; i++) { @@ -2058,6 +2068,8 @@ static int subtitle_thread(void *arg) SDL_LockMutex(is->subpq_mutex); is->subpq_size++; SDL_UnlockMutex(is->subpq_mutex); + } else if (got_subtitle) { + avsubtitle_free(&sp->sub); } av_free_packet(pkt); } @@ -2094,7 +2106,7 @@ static int synchronize_audio(VideoState *is, int nb_samples) double diff, avg_diff; int min_nb_samples, max_nb_samples; - diff = get_audio_clock(is) - get_master_clock(is); + diff = get_clock(&is->audclk) - get_master_clock(is); if (!isnan(diff) && fabs(diff) < AV_NOSYNC_THRESHOLD) { is->audio_diff_cum = diff + is->audio_diff_avg_coef * is->audio_diff_cum; @@ -2142,20 +2154,19 @@ static int audio_decode_frame(VideoState *is) int64_t dec_channel_layout; int got_frame; av_unused double audio_clock0; - int new_packet = 0; - int flush_complete = 0; int wanted_nb_samples; AVRational tb; + int ret; + int reconfigure; for (;;) { /* NOTE: the audio packet can contain several frames */ - while (pkt_temp->size > 0 || (!pkt_temp->data && new_packet)) { + while (pkt_temp->stream_index != -1 || is->audio_buf_frames_pending) { if (!is->frame) { - if (!(is->frame = avcodec_alloc_frame())) + if (!(is->frame = av_frame_alloc())) return AVERROR(ENOMEM); } else { av_frame_unref(is->frame); - avcodec_get_frame_defaults(is->frame); } if (is->audioq.serial != is->audio_pkt_temp_serial) @@ -2164,37 +2175,42 @@ static int audio_decode_frame(VideoState *is) if (is->paused) return -1; - if (flush_complete) - break; - new_packet = 0; - len1 = avcodec_decode_audio4(dec, is->frame, &got_frame, pkt_temp); - if (len1 < 0) { - /* if error, we skip the frame */ - pkt_temp->size = 0; - break; - } - - pkt_temp->data += len1; - pkt_temp->size -= len1; + if (!is->audio_buf_frames_pending) { + len1 = avcodec_decode_audio4(dec, is->frame, &got_frame, pkt_temp); + if (len1 < 0) { + /* if error, we skip the frame */ + pkt_temp->size = 0; + break; + } - if (!got_frame) { - /* stop sending empty packets if the decoder is finished */ - if (!pkt_temp->data && dec->codec->capabilities & CODEC_CAP_DELAY) - flush_complete = 1; - continue; - } + pkt_temp->dts = + pkt_temp->pts = AV_NOPTS_VALUE; + pkt_temp->data += len1; + pkt_temp->size -= len1; + if (pkt_temp->data && pkt_temp->size <= 0 || !pkt_temp->data && !got_frame) + pkt_temp->stream_index = -1; + if (!pkt_temp->data && !got_frame) + is->audio_finished = is->audio_pkt_temp_serial; + + if (!got_frame) + continue; + + tb = (AVRational){1, is->frame->sample_rate}; + if (is->frame->pts != AV_NOPTS_VALUE) + is->frame->pts = av_rescale_q(is->frame->pts, dec->time_base, tb); + else if (is->frame->pkt_pts != AV_NOPTS_VALUE) + is->frame->pts = av_rescale_q(is->frame->pkt_pts, is->audio_st->time_base, tb); + else if (is->audio_frame_next_pts != AV_NOPTS_VALUE) +#if CONFIG_AVFILTER + is->frame->pts = av_rescale_q(is->audio_frame_next_pts, (AVRational){1, is->audio_filter_src.freq}, tb); +#else + is->frame->pts = av_rescale_q(is->audio_frame_next_pts, (AVRational){1, is->audio_src.freq}, tb); +#endif - if (is->frame->pts == AV_NOPTS_VALUE && pkt_temp->pts != AV_NOPTS_VALUE) - is->frame->pts = av_rescale_q(pkt_temp->pts, is->audio_st->time_base, dec->time_base); - if (pkt_temp->pts != AV_NOPTS_VALUE) - pkt_temp->pts += (double) is->frame->nb_samples / is->frame->sample_rate / av_q2d(is->audio_st->time_base); - tb = dec->time_base; + if (is->frame->pts != AV_NOPTS_VALUE) + is->audio_frame_next_pts = is->frame->pts + is->frame->nb_samples; #if CONFIG_AVFILTER - { - int ret; - int reconfigure; - dec_channel_layout = get_valid_channel_layout(is->frame->channel_layout, av_frame_get_channels(is->frame)); reconfigure = @@ -2226,10 +2242,20 @@ static int audio_decode_frame(VideoState *is) if ((ret = av_buffersrc_add_frame(is->in_audio_filter, is->frame)) < 0) return ret; av_frame_unref(is->frame); - if ((ret = av_buffersink_get_frame_flags(is->out_audio_filter, is->frame, 0)) < 0) - return ret; - tb = is->out_audio_filter->inputs[0]->time_base; +#endif + } +#if CONFIG_AVFILTER + if ((ret = av_buffersink_get_frame_flags(is->out_audio_filter, is->frame, 0)) < 0) { + if (ret == AVERROR(EAGAIN)) { + is->audio_buf_frames_pending = 0; + continue; + } + if (ret == AVERROR_EOF) + is->audio_finished = is->audio_pkt_temp_serial; + return ret; } + is->audio_buf_frames_pending = 1; + tb = is->out_audio_filter->inputs[0]->time_base; #endif data_size = av_samples_get_buffer_size(NULL, av_frame_get_channels(is->frame), @@ -2251,7 +2277,8 @@ static int audio_decode_frame(VideoState *is) dec_channel_layout, is->frame->format, is->frame->sample_rate, 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", + av_log(NULL, AV_LOG_ERROR, + "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), av_frame_get_channels(is->frame), is->audio_tgt.freq, av_get_sample_fmt_name(is->audio_tgt.fmt), is->audio_tgt.channels); break; @@ -2268,10 +2295,14 @@ static int audio_decode_frame(VideoState *is) int out_count = (int64_t)wanted_nb_samples * is->audio_tgt.freq / is->frame->sample_rate + 256; int out_size = av_samples_get_buffer_size(NULL, is->audio_tgt.channels, out_count, is->audio_tgt.fmt, 0); int len2; + if (out_size < 0) { + av_log(NULL, AV_LOG_ERROR, "av_samples_get_buffer_size() failed\n"); + break; + } if (wanted_nb_samples != is->frame->nb_samples) { if (swr_set_compensation(is->swr_ctx, (wanted_nb_samples - is->frame->nb_samples) * is->audio_tgt.freq / is->frame->sample_rate, wanted_nb_samples * is->audio_tgt.freq / is->frame->sample_rate) < 0) { - fprintf(stderr, "swr_set_compensation() failed\n"); + av_log(NULL, AV_LOG_ERROR, "swr_set_compensation() failed\n"); break; } } @@ -2280,11 +2311,11 @@ static int audio_decode_frame(VideoState *is) return AVERROR(ENOMEM); len2 = swr_convert(is->swr_ctx, out, out_count, in, is->frame->nb_samples); if (len2 < 0) { - fprintf(stderr, "swr_convert() failed\n"); + av_log(NULL, AV_LOG_ERROR, "swr_convert() failed\n"); break; } if (len2 == out_count) { - fprintf(stderr, "warning: audio buffer is probably too small\n"); + av_log(NULL, AV_LOG_WARNING, "audio buffer is probably too small\n"); swr_init(is->swr_ctx); } is->audio_buf = is->audio_buf1; @@ -2296,10 +2327,11 @@ static int audio_decode_frame(VideoState *is) audio_clock0 = is->audio_clock; /* update the audio clock with the pts */ - if (is->frame->pts != AV_NOPTS_VALUE) { + if (is->frame->pts != AV_NOPTS_VALUE) is->audio_clock = is->frame->pts * av_q2d(tb) + (double) is->frame->nb_samples / is->frame->sample_rate; - is->audio_clock_serial = is->audio_pkt_temp_serial; - } + else + is->audio_clock = NAN; + is->audio_clock_serial = is->audio_pkt_temp_serial; #ifdef DEBUG { static double last_clock; @@ -2316,6 +2348,7 @@ static int audio_decode_frame(VideoState *is) if (pkt->data) av_free_packet(pkt); memset(pkt_temp, 0, sizeof(*pkt_temp)); + pkt_temp->stream_index = -1; if (is->audioq.abort_request) { return -1; @@ -2325,12 +2358,15 @@ static int audio_decode_frame(VideoState *is) SDL_CondSignal(is->continue_read_thread); /* read next packet */ - if ((new_packet = packet_queue_get(&is->audioq, pkt, 1, &is->audio_pkt_temp_serial)) < 0) + if ((packet_queue_get(&is->audioq, pkt, 1, &is->audio_pkt_temp_serial)) < 0) return -1; if (pkt->data == flush_pkt.data) { avcodec_flush_buffers(dec); - flush_complete = 0; + is->audio_buf_frames_pending = 0; + is->audio_frame_next_pts = AV_NOPTS_VALUE; + if ((is->ic->iformat->flags & (AVFMT_NOBINSEARCH | AVFMT_NOGENSEARCH | AVFMT_NO_BYTE_SEEK)) && !is->ic->iformat->read_seek) + is->audio_frame_next_pts = is->audio_st->start_time; } *pkt_temp = *pkt; @@ -2372,17 +2408,17 @@ static void sdl_audio_callback(void *opaque, Uint8 *stream, int len) bytes_per_sec = is->audio_tgt.freq * is->audio_tgt.channels * av_get_bytes_per_sample(is->audio_tgt.fmt); is->audio_write_buf_size = is->audio_buf_size - is->audio_buf_index; /* 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_clock_serial) - check_external_clock_sync(is, is->audio_current_pts); + if (!isnan(is->audio_clock)) { + set_clock_at(&is->audclk, is->audio_clock - (double)(2 * is->audio_hw_buf_size + is->audio_write_buf_size) / bytes_per_sec, is->audio_clock_serial, audio_callback_time / 1000000.0); + sync_clock_to_slave(&is->extclk, &is->audclk); + } } static int audio_open(void *opaque, int64_t wanted_channel_layout, int wanted_nb_channels, int wanted_sample_rate, struct AudioParams *audio_hw_params) { SDL_AudioSpec wanted_spec, spec; const char *env; - const int next_nb_channels[] = {0, 0, 1, 6, 2, 6, 4, 6}; + static const int next_nb_channels[] = {0, 0, 1, 6, 2, 6, 4, 6}; env = SDL_getenv("SDL_AUDIO_CHANNELS"); if (env) { @@ -2396,7 +2432,7 @@ static int audio_open(void *opaque, int64_t wanted_channel_layout, int wanted_nb wanted_spec.channels = av_get_channel_layout_nb_channels(wanted_channel_layout); wanted_spec.freq = wanted_sample_rate; if (wanted_spec.freq <= 0 || wanted_spec.channels <= 0) { - fprintf(stderr, "Invalid sample rate or channel count!\n"); + av_log(NULL, AV_LOG_ERROR, "Invalid sample rate or channel count!\n"); return -1; } wanted_spec.format = AUDIO_S16SYS; @@ -2405,22 +2441,25 @@ static int audio_open(void *opaque, int64_t wanted_channel_layout, int wanted_nb wanted_spec.callback = sdl_audio_callback; wanted_spec.userdata = opaque; while (SDL_OpenAudio(&wanted_spec, &spec) < 0) { - fprintf(stderr, "SDL_OpenAudio (%d channels): %s\n", wanted_spec.channels, SDL_GetError()); + av_log(NULL, AV_LOG_WARNING, "SDL_OpenAudio (%d channels): %s\n", wanted_spec.channels, SDL_GetError()); wanted_spec.channels = next_nb_channels[FFMIN(7, wanted_spec.channels)]; if (!wanted_spec.channels) { - fprintf(stderr, "No more channel combinations to try, audio open failed\n"); + av_log(NULL, AV_LOG_ERROR, + "No more channel combinations to try, audio open failed\n"); return -1; } wanted_channel_layout = av_get_default_channel_layout(wanted_spec.channels); } if (spec.format != AUDIO_S16SYS) { - fprintf(stderr, "SDL advised audio format %d is not supported!\n", spec.format); + av_log(NULL, AV_LOG_ERROR, + "SDL advised audio format %d is not supported!\n", spec.format); return -1; } if (spec.channels != wanted_spec.channels) { wanted_channel_layout = av_get_default_channel_layout(spec.channels); if (!wanted_channel_layout) { - fprintf(stderr, "SDL advised channel count %d is not supported!\n", spec.channels); + av_log(NULL, AV_LOG_ERROR, + "SDL advised channel count %d is not supported!\n", spec.channels); return -1; } } @@ -2444,6 +2483,7 @@ static int stream_component_open(VideoState *is, int stream_index) int sample_rate, nb_channels; int64_t channel_layout; int ret; + int stream_lowres = lowres; if (stream_index < 0 || stream_index >= ic->nb_streams) return -1; @@ -2459,23 +2499,24 @@ static int stream_component_open(VideoState *is, int stream_index) if (forced_codec_name) codec = avcodec_find_decoder_by_name(forced_codec_name); if (!codec) { - if (forced_codec_name) fprintf(stderr, "No codec could be found with name '%s'\n", forced_codec_name); - else fprintf(stderr, "No codec could be found with id %d\n", avctx->codec_id); + if (forced_codec_name) av_log(NULL, AV_LOG_WARNING, + "No codec could be found with name '%s'\n", forced_codec_name); + else av_log(NULL, AV_LOG_WARNING, + "No codec could be found with id %d\n", avctx->codec_id); return -1; } avctx->codec_id = codec->id; avctx->workaround_bugs = workaround_bugs; - avctx->lowres = lowres; - if(avctx->lowres > codec->max_lowres){ + if(stream_lowres > av_codec_get_max_lowres(codec)){ av_log(avctx, AV_LOG_WARNING, "The maximum value for lowres supported by the decoder is %d\n", - codec->max_lowres); - avctx->lowres= codec->max_lowres; + av_codec_get_max_lowres(codec)); + stream_lowres = av_codec_get_max_lowres(codec); } - avctx->idct_algo = idct; + av_codec_set_lowres(avctx, stream_lowres); avctx->error_concealment = error_concealment; - if(avctx->lowres) avctx->flags |= CODEC_FLAG_EMU_EDGE; + if(stream_lowres) avctx->flags |= CODEC_FLAG_EMU_EDGE; if (fast) avctx->flags2 |= CODEC_FLAG2_FAST; if(codec->capabilities & CODEC_CAP_DR1) avctx->flags |= CODEC_FLAG_EMU_EDGE; @@ -2483,6 +2524,8 @@ static int stream_component_open(VideoState *is, int stream_index) opts = filter_codec_opts(codec_opts, avctx->codec_id, ic, ic->streams[stream_index], codec); if (!av_dict_get(opts, "threads", NULL, 0)) av_dict_set(&opts, "threads", "auto", 0); + if (stream_lowres) + av_dict_set(&opts, "lowres", av_asprintf("%d", stream_lowres), AV_DICT_DONT_STRDUP_VAL); if (avctx->codec_type == AVMEDIA_TYPE_VIDEO || avctx->codec_type == AVMEDIA_TYPE_AUDIO) av_dict_set(&opts, "refcounted_frames", "1", 0); if (avcodec_open2(avctx, codec, &opts) < 0) @@ -2533,6 +2576,7 @@ static int stream_component_open(VideoState *is, int stream_index) memset(&is->audio_pkt, 0, sizeof(is->audio_pkt)); memset(&is->audio_pkt_temp, 0, sizeof(is->audio_pkt_temp)); + is->audio_pkt_temp.stream_index = -1; is->audio_stream = stream_index; is->audio_st = ic->streams[stream_index]; @@ -2546,6 +2590,7 @@ static int stream_component_open(VideoState *is, int stream_index) packet_queue_start(&is->videoq); is->video_tid = SDL_CreateThread(video_thread, is); + is->queue_attachments_req = 1; break; case AVMEDIA_TYPE_SUBTITLE: is->subtitle_stream = stream_index; @@ -2612,8 +2657,6 @@ static void stream_component_close(VideoState *is, int stream_index) /* note: we also signal this mutex to make sure we deblock the video thread in all cases */ SDL_LockMutex(is->subpq_mutex); - is->subtitle_stream_changed = 1; - SDL_CondSignal(is->subpq_cond); SDL_UnlockMutex(is->subpq_mutex); @@ -2676,6 +2719,7 @@ static int read_thread(void *arg) int st_index[AVMEDIA_TYPE_NB]; AVPacket pkt1, *pkt = &pkt1; int eof = 0; + int64_t stream_start_time; int pkt_in_play_range = 0; AVDictionaryEntry *t; AVDictionary **opts; @@ -2711,7 +2755,8 @@ static int read_thread(void *arg) err = avformat_find_stream_info(ic, opts); if (err < 0) { - fprintf(stderr, "%s: could not find codec parameters\n", is->filename); + av_log(NULL, AV_LOG_WARNING, + "%s: could not find codec parameters\n", is->filename); ret = -1; goto fail; } @@ -2723,10 +2768,13 @@ static int read_thread(void *arg) ic->pb->eof_reached = 0; // FIXME hack, ffplay maybe should not use url_feof() to test for the end if (seek_by_bytes < 0) - seek_by_bytes = !!(ic->iformat->flags & AVFMT_TS_DISCONT); + seek_by_bytes = !!(ic->iformat->flags & AVFMT_TS_DISCONT) && strcmp("ogg", ic->iformat->name); is->max_frame_duration = (ic->iformat->flags & AVFMT_TS_DISCONT) ? 10.0 : 3600.0; + if (!window_title && (t = av_dict_get(ic->metadata, "title", NULL, 0))) + window_title = av_asprintf("%s - %s", t->value, input_filename); + /* if seeking requested, we execute it */ if (start_time != AV_NOPTS_VALUE) { int64_t timestamp; @@ -2737,7 +2785,7 @@ static int read_thread(void *arg) timestamp += ic->start_time; ret = avformat_seek_file(ic, -1, INT64_MIN, timestamp, INT64_MAX, 0); if (ret < 0) { - fprintf(stderr, "%s: could not seek to position %0.3f\n", + av_log(NULL, AV_LOG_WARNING, "%s: could not seek to position %0.3f\n", is->filename, (double)timestamp / AV_TIME_BASE); } } @@ -2769,6 +2817,13 @@ static int read_thread(void *arg) } is->show_mode = show_mode; + if (st_index[AVMEDIA_TYPE_VIDEO] >= 0) { + AVStream *st = ic->streams[st_index[AVMEDIA_TYPE_VIDEO]]; + AVCodecContext *avctx = st->codec; + VideoPicture vp = {.width = avctx->width, .height = avctx->height, .sar = av_guess_sample_aspect_ratio(ic, st, NULL)}; + if (vp.width) + set_default_window_size(&vp); + } /* open the streams */ if (st_index[AVMEDIA_TYPE_AUDIO] >= 0) { @@ -2787,7 +2842,8 @@ static int read_thread(void *arg) } if (is->video_stream < 0 && is->audio_stream < 0) { - fprintf(stderr, "%s: could not open codecs\n", is->filename); + av_log(NULL, AV_LOG_FATAL, "Failed to open file '%s' or configure filtergraph\n", + is->filename); ret = -1; goto fail; } @@ -2824,7 +2880,8 @@ static int read_thread(void *arg) ret = avformat_seek_file(is->ic, -1, seek_min, seek_target, seek_max, is->seek_flags); if (ret < 0) { - fprintf(stderr, "%s: error while seeking\n", is->ic->filename); + av_log(NULL, AV_LOG_ERROR, + "%s: error while seeking\n", is->ic->filename); } else { if (is->audio_stream >= 0) { packet_queue_flush(&is->audioq); @@ -2839,18 +2896,25 @@ static int read_thread(void *arg) packet_queue_put(&is->videoq, &flush_pkt); } if (is->seek_flags & AVSEEK_FLAG_BYTE) { - update_external_clock_pts(is, NAN); + set_clock(&is->extclk, NAN, 0); } else { - update_external_clock_pts(is, seek_target / (double)AV_TIME_BASE); + set_clock(&is->extclk, seek_target / (double)AV_TIME_BASE, 0); } } is->seek_req = 0; + is->queue_attachments_req = 1; eof = 0; if (is->paused) step_to_next_frame(is); } if (is->queue_attachments_req) { - avformat_queue_attached_pictures(ic); + if (is->video_st && is->video_st->disposition & AV_DISPOSITION_ATTACHED_PIC) { + AVPacket copy; + if ((ret = av_copy_packet(©, &is->video_st->attached_pic)) < 0) + goto fail; + packet_queue_put(&is->videoq, ©); + packet_queue_put_nullpacket(&is->videoq, is->video_stream); + } is->queue_attachments_req = 0; } @@ -2858,7 +2922,8 @@ static int read_thread(void *arg) if (infinite_buffer<1 && (is->audioq.size + is->videoq.size + is->subtitleq.size > MAX_QUEUE_SIZE || ( (is->audioq .nb_packets > MIN_FRAMES || is->audio_stream < 0 || is->audioq.abort_request) - && (is->videoq .nb_packets > MIN_FRAMES || is->video_stream < 0 || is->videoq.abort_request) + && (is->videoq .nb_packets > MIN_FRAMES || is->video_stream < 0 || is->videoq.abort_request + || (is->video_st->disposition & AV_DISPOSITION_ATTACHED_PIC)) && (is->subtitleq.nb_packets > MIN_FRAMES || is->subtitle_stream < 0 || is->subtitleq.abort_request)))) { /* wait 10 ms */ SDL_LockMutex(wait_mutex); @@ -2866,31 +2931,22 @@ static int read_thread(void *arg) SDL_UnlockMutex(wait_mutex); continue; } - if (eof) { - if (is->video_stream >= 0) { - av_init_packet(pkt); - pkt->data = NULL; - pkt->size = 0; - pkt->stream_index = is->video_stream; - packet_queue_put(&is->videoq, pkt); - } - if (is->audio_stream >= 0 && - is->audio_st->codec->codec->capabilities & CODEC_CAP_DELAY) { - av_init_packet(pkt); - pkt->data = NULL; - pkt->size = 0; - pkt->stream_index = is->audio_stream; - packet_queue_put(&is->audioq, pkt); + if (!is->paused && + (!is->audio_st || is->audio_finished == is->audioq.serial) && + (!is->video_st || (is->video_finished == is->videoq.serial && is->pictq_size == 0))) { + if (loop != 1 && (!loop || --loop)) { + stream_seek(is, start_time != AV_NOPTS_VALUE ? start_time : 0, 0, 0); + } else if (autoexit) { + ret = AVERROR_EOF; + goto fail; } + } + if (eof) { + if (is->video_stream >= 0) + packet_queue_put_nullpacket(&is->videoq, is->video_stream); + if (is->audio_stream >= 0) + packet_queue_put_nullpacket(&is->audioq, is->audio_stream); SDL_Delay(10); - if (is->audioq.size + is->videoq.size + is->subtitleq.size == 0) { - if (loop != 1 && (!loop || --loop)) { - stream_seek(is, start_time != AV_NOPTS_VALUE ? start_time : 0, 0, 0); - } else if (autoexit) { - ret = AVERROR_EOF; - goto fail; - } - } eof=0; continue; } @@ -2906,14 +2962,16 @@ static int read_thread(void *arg) continue; } /* check if packet is in play range specified by user, then queue, otherwise discard */ + stream_start_time = ic->streams[pkt->stream_index]->start_time; pkt_in_play_range = duration == AV_NOPTS_VALUE || - (pkt->pts - ic->streams[pkt->stream_index]->start_time) * + (pkt->pts - (stream_start_time != AV_NOPTS_VALUE ? stream_start_time : 0)) * av_q2d(ic->streams[pkt->stream_index]->time_base) - (double)(start_time != AV_NOPTS_VALUE ? start_time : 0) / 1000000 <= ((double)duration / 1000000); if (pkt->stream_index == is->audio_stream && pkt_in_play_range) { packet_queue_put(&is->audioq, pkt); - } else if (pkt->stream_index == is->video_stream && pkt_in_play_range) { + } else if (pkt->stream_index == is->video_stream && pkt_in_play_range + && !(is->video_st->disposition & AV_DISPOSITION_ATTACHED_PIC)) { packet_queue_put(&is->videoq, pkt); } else if (pkt->stream_index == is->subtitle_stream && pkt_in_play_range) { packet_queue_put(&is->subtitleq, pkt); @@ -2975,12 +3033,10 @@ static VideoState *stream_open(const char *filename, AVInputFormat *iformat) is->continue_read_thread = SDL_CreateCond(); - 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; + init_clock(&is->vidclk, &is->videoq.serial); + init_clock(&is->audclk, &is->audioq.serial); + init_clock(&is->extclk, &is->extclk.serial); is->audio_clock_serial = -1; - is->video_clock_serial = -1; is->audio_last_serial = -1; is->av_sync_type = av_sync_type; is->read_tid = SDL_CreateThread(read_thread, is); @@ -2997,6 +3053,8 @@ static void stream_cycle_channel(VideoState *is, int codec_type) int start_index, stream_index; int old_index; AVStream *st; + AVProgram *p = NULL; + int nb_streams = is->ic->nb_streams; if (codec_type == AVMEDIA_TYPE_VIDEO) { start_index = is->last_video_stream; @@ -3009,8 +3067,22 @@ static void stream_cycle_channel(VideoState *is, int codec_type) old_index = is->subtitle_stream; } stream_index = start_index; + + if (codec_type != AVMEDIA_TYPE_VIDEO && is->video_stream != -1) { + p = av_find_program_from_stream(ic, NULL, is->video_stream); + if (p) { + nb_streams = p->nb_stream_indexes; + for (start_index = 0; start_index < nb_streams; start_index++) + if (p->stream_index[start_index] == stream_index) + break; + if (start_index == nb_streams) + start_index = -1; + stream_index = start_index; + } + } + for (;;) { - if (++stream_index >= is->ic->nb_streams) + if (++stream_index >= nb_streams) { if (codec_type == AVMEDIA_TYPE_SUBTITLE) { @@ -3024,7 +3096,7 @@ static void stream_cycle_channel(VideoState *is, int codec_type) } if (stream_index == start_index) return; - st = ic->streams[stream_index]; + st = is->ic->streams[p ? p->stream_index[stream_index] : stream_index]; if (st->codec->codec_type == codec_type) { /* check that parameters are OK */ switch (codec_type) { @@ -3042,10 +3114,10 @@ static void stream_cycle_channel(VideoState *is, int codec_type) } } the_end: + if (p && stream_index != -1) + stream_index = p->stream_index[stream_index]; stream_component_close(is, old_index); stream_component_open(is, stream_index); - if (codec_type == AVMEDIA_TYPE_VIDEO) - is->queue_attachments_req = 1; } @@ -3131,6 +3203,11 @@ static void event_loop(VideoState *cur_stream) case SDLK_v: stream_cycle_channel(cur_stream, AVMEDIA_TYPE_VIDEO); break; + case SDLK_c: + stream_cycle_channel(cur_stream, AVMEDIA_TYPE_VIDEO); + stream_cycle_channel(cur_stream, AVMEDIA_TYPE_AUDIO); + stream_cycle_channel(cur_stream, AVMEDIA_TYPE_SUBTITLE); + break; case SDLK_t: stream_cycle_channel(cur_stream, AVMEDIA_TYPE_SUBTITLE); break; @@ -3219,7 +3296,8 @@ static void event_loop(VideoState *cur_stream) hh = ns / 3600; mm = (ns % 3600) / 60; ss = (ns % 60); - fprintf(stderr, "Seek to %2.0f%% (%2d:%02d:%02d) of total duration (%2d:%02d:%02d) \n", frac*100, + av_log(NULL, AV_LOG_INFO, + "Seek to %2.0f%% (%2d:%02d:%02d) of total duration (%2d:%02d:%02d) \n", frac*100, hh, mm, ss, thh, tmm, tss); ts = frac * cur_stream->ic->duration; if (cur_stream->ic->start_time != AV_NOPTS_VALUE) @@ -3228,10 +3306,14 @@ static void event_loop(VideoState *cur_stream) } break; case SDL_VIDEORESIZE: - screen = SDL_SetVideoMode(event.resize.w, event.resize.h, 0, + screen = SDL_SetVideoMode(FFMIN(16383, event.resize.w), event.resize.h, 0, SDL_HWSURFACE|SDL_RESIZABLE|SDL_ASYNCBLIT|SDL_HWACCEL); - screen_width = cur_stream->width = event.resize.w; - screen_height = cur_stream->height = event.resize.h; + if (!screen) { + av_log(NULL, AV_LOG_FATAL, "Failed to set video mode\n"); + do_exit(cur_stream); + } + screen_width = cur_stream->width = screen->w; + screen_height = cur_stream->height = screen->h; cur_stream->force_refresh = 1; break; case SDL_QUIT: @@ -3269,7 +3351,7 @@ static int opt_format(void *optctx, const char *opt, const char *arg) { file_iformat = av_find_input_format(arg); if (!file_iformat) { - fprintf(stderr, "Unknown input format: %s\n", arg); + av_log(NULL, AV_LOG_FATAL, "Unknown input format: %s\n", arg); return AVERROR(EINVAL); } return 0; @@ -3290,7 +3372,7 @@ static int opt_sync(void *optctx, const char *opt, const char *arg) else if (!strcmp(arg, "ext")) av_sync_type = AV_SYNC_EXTERNAL_CLOCK; else { - fprintf(stderr, "Unknown value for %s: %s\n", opt, arg); + av_log(NULL, AV_LOG_ERROR, "Unknown value for %s: %s\n", opt, arg); exit(1); } return 0; @@ -3320,7 +3402,8 @@ static int opt_show_mode(void *optctx, const char *opt, const char *arg) static void opt_input_file(void *optctx, const char *filename) { if (input_filename) { - fprintf(stderr, "Argument '%s' provided as input filename, but '%s' was already specified.\n", + av_log(NULL, AV_LOG_FATAL, + "Argument '%s' provided as input filename, but '%s' was already specified.\n", filename, input_filename); exit(1); } @@ -3333,7 +3416,8 @@ static int opt_codec(void *optctx, const char *opt, const char *arg) { const char *spec = strchr(opt, ':'); if (!spec) { - fprintf(stderr, "No media specifier was specified in '%s' in option '%s'\n", + av_log(NULL, AV_LOG_ERROR, + "No media specifier was specified in '%s' in option '%s'\n", arg, opt); return AVERROR(EINVAL); } @@ -3343,7 +3427,8 @@ static int opt_codec(void *optctx, const char *opt, const char *arg) case 's' : subtitle_codec_name = arg; break; case 'v' : video_codec_name = arg; break; default: - fprintf(stderr, "Invalid media specifier '%s' in option '%s'\n", spec, opt); + av_log(NULL, AV_LOG_ERROR, + "Invalid media specifier '%s' in option '%s'\n", spec, opt); return AVERROR(EINVAL); } return 0; @@ -3375,7 +3460,6 @@ static const OptionDef options[] = { { "genpts", OPT_BOOL | OPT_EXPERT, { &genpts }, "generate pts", "" }, { "drp", OPT_INT | HAS_ARG | OPT_EXPERT, { &decoder_reorder_pts }, "let decoder reorder pts 0=off 1=on -1=auto", ""}, { "lowres", OPT_INT | HAS_ARG | OPT_EXPERT, { &lowres }, "", "" }, - { "idct", OPT_INT | HAS_ARG | OPT_EXPERT, { &idct }, "set idct algo", "algo" }, { "ec", OPT_INT | HAS_ARG | OPT_EXPERT, { &error_concealment }, "set error concealment options", "bit_mask" }, { "sync", HAS_ARG | OPT_EXPERT, { .func_arg = opt_sync }, "set audio-video sync. type (type=audio/video/ext)", "type" }, { "autoexit", OPT_BOOL | OPT_EXPERT, { &autoexit }, "exit at the end", "" }, @@ -3425,9 +3509,10 @@ void show_help_default(const char *opt, const char *arg) "q, ESC quit\n" "f toggle full screen\n" "p, SPC pause\n" - "a cycle audio channel\n" + "a cycle audio channel in the current program\n" "v cycle video channel\n" - "t cycle subtitle channel\n" + "t cycle subtitle channel in the current program\n" + "c cycle program\n" "w show audio waves\n" "s activate frame-step mode\n" "left/right seek backward/forward 10 seconds\n" @@ -3467,7 +3552,6 @@ int main(int argc, char **argv) parse_loglevel(argc, argv, options); /* register all codecs, demux and protocols */ - avcodec_register_all(); #if CONFIG_AVDEVICE avdevice_register_all(); #endif @@ -3488,8 +3572,9 @@ int main(int argc, char **argv) if (!input_filename) { show_usage(); - fprintf(stderr, "An input file must be specified\n"); - fprintf(stderr, "Use -h to get full help or, even better, run 'man %s'\n", program_name); + av_log(NULL, AV_LOG_FATAL, "An input file must be specified\n"); + av_log(NULL, AV_LOG_FATAL, + "Use -h to get full help or, even better, run 'man %s'\n", program_name); exit(1); } @@ -3505,8 +3590,8 @@ int main(int argc, char **argv) flags |= SDL_INIT_EVENTTHREAD; /* Not supported on Windows or Mac OS X */ #endif if (SDL_Init (flags)) { - fprintf(stderr, "Could not initialize SDL - %s\n", SDL_GetError()); - fprintf(stderr, "(Did you set the DISPLAY variable?)\n"); + av_log(NULL, AV_LOG_FATAL, "Could not initialize SDL - %s\n", SDL_GetError()); + av_log(NULL, AV_LOG_FATAL, "(Did you set the DISPLAY variable?)\n"); exit(1); } @@ -3521,16 +3606,16 @@ int main(int argc, char **argv) SDL_EventState(SDL_USEREVENT, SDL_IGNORE); if (av_lockmgr_register(lockmgr)) { - fprintf(stderr, "Could not initialize lock manager!\n"); + av_log(NULL, AV_LOG_FATAL, "Could not initialize lock manager!\n"); do_exit(NULL); } av_init_packet(&flush_pkt); - flush_pkt.data = (char *)(intptr_t)"FLUSH"; + flush_pkt.data = (uint8_t *)&flush_pkt; is = stream_open(input_filename, file_iformat); if (!is) { - fprintf(stderr, "Failed to initialize VideoState!\n"); + av_log(NULL, AV_LOG_FATAL, "Failed to initialize VideoState!\n"); do_exit(NULL); } |
