summaryrefslogtreecommitdiff
path: root/ffmpeg/ffplay.c
diff options
context:
space:
mode:
authorTim Redfern <tim@eclectronics.org>2013-12-29 12:19:38 +0000
committerTim Redfern <tim@eclectronics.org>2013-12-29 12:19:38 +0000
commitf7813a5324be39d13ab536c245d15dfc602a7849 (patch)
treefad99148b88823d34a5df2f0a25881a002eb291b /ffmpeg/ffplay.c
parentb7a5a477b8ff4d4e3028b9dfb9a9df0a41463f92 (diff)
basic type mechanism working
Diffstat (limited to 'ffmpeg/ffplay.c')
-rw-r--r--ffmpeg/ffplay.c823
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(&copy, &is->video_st->attached_pic)) < 0)
+ goto fail;
+ packet_queue_put(&is->videoq, &copy);
+ 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);
}