27 #include "config_components.h"
60 #include <SDL_thread.h>
68 #define MAX_QUEUE_SIZE (15 * 1024 * 1024)
70 #define EXTERNAL_CLOCK_MIN_FRAMES 2
71 #define EXTERNAL_CLOCK_MAX_FRAMES 10
74 #define SDL_AUDIO_MIN_BUFFER_SIZE 512
76 #define SDL_AUDIO_MAX_CALLBACKS_PER_SEC 30
79 #define SDL_VOLUME_STEP (0.75)
82 #define AV_SYNC_THRESHOLD_MIN 0.04
84 #define AV_SYNC_THRESHOLD_MAX 0.1
86 #define AV_SYNC_FRAMEDUP_THRESHOLD 0.1
88 #define AV_NOSYNC_THRESHOLD 10.0
91 #define SAMPLE_CORRECTION_PERCENT_MAX 10
94 #define EXTERNAL_CLOCK_SPEED_MIN 0.900
95 #define EXTERNAL_CLOCK_SPEED_MAX 1.010
96 #define EXTERNAL_CLOCK_SPEED_STEP 0.001
99 #define AUDIO_DIFF_AVG_NB 20
102 #define REFRESH_RATE 0.01
106 #define SAMPLE_ARRAY_SIZE (8 * 65536)
108 #define CURSOR_HIDE_DELAY 1000000
110 #define USE_ONEPASS_SUBTITLE_RENDER 1
130 #define VIDEO_PICTURE_QUEUE_SIZE 3
131 #define SUBPICTURE_QUEUE_SIZE 16
132 #define SAMPLE_QUEUE_SIZE 9
133 #define FRAME_QUEUE_SIZE FFMAX(SAMPLE_QUEUE_SIZE, FFMAX(VIDEO_PICTURE_QUEUE_SIZE, SUBPICTURE_QUEUE_SIZE))
351 static const char **vfilters_list =
NULL;
352 static int nb_vfilters = 0;
353 static char *afilters =
NULL;
363 #define FF_QUIT_EVENT (SDL_USEREVENT + 2)
397 static int opt_add_vfilter(
void *optctx,
const char *opt,
const char *
arg)
400 vfilters_list[nb_vfilters - 1] =
arg;
410 if (channel_count1 == 1 && channel_count2 == 1)
413 return channel_count1 != channel_count2 || fmt1 != fmt2;
435 SDL_CondSignal(q->
cond);
451 SDL_LockMutex(q->
mutex);
453 SDL_UnlockMutex(q->
mutex);
474 q->
mutex = SDL_CreateMutex();
479 q->
cond = SDL_CreateCond();
492 SDL_LockMutex(q->
mutex);
499 SDL_UnlockMutex(q->
mutex);
506 SDL_DestroyMutex(q->
mutex);
507 SDL_DestroyCond(q->
cond);
512 SDL_LockMutex(q->
mutex);
516 SDL_CondSignal(q->
cond);
518 SDL_UnlockMutex(q->
mutex);
523 SDL_LockMutex(q->
mutex);
526 SDL_UnlockMutex(q->
mutex);
535 SDL_LockMutex(q->
mutex);
560 SDL_UnlockMutex(q->
mutex);
571 d->empty_queue_cond = empty_queue_cond;
581 if (
d->queue->serial ==
d->pkt_serial) {
583 if (
d->queue->abort_request)
586 switch (
d->avctx->codec_type) {
613 d->finished =
d->pkt_serial;
623 if (
d->queue->nb_packets == 0)
624 SDL_CondSignal(
d->empty_queue_cond);
625 if (
d->packet_pending) {
626 d->packet_pending = 0;
628 int old_serial =
d->pkt_serial;
631 if (old_serial !=
d->pkt_serial) {
634 d->next_pts =
d->start_pts;
635 d->next_pts_tb =
d->start_pts_tb;
638 if (
d->queue->serial ==
d->pkt_serial)
649 if (got_frame && !
d->pkt->data) {
650 d->packet_pending = 1;
657 av_log(
d->avctx,
AV_LOG_ERROR,
"Receive_frame and send_packet both returned EAGAIN, which is an API violation.\n");
658 d->packet_pending = 1;
681 if (!(
f->mutex = SDL_CreateMutex())) {
685 if (!(
f->cond = SDL_CreateCond())) {
691 f->keep_last = !!keep_last;
692 for (
i = 0;
i <
f->max_size;
i++)
701 for (
i = 0;
i <
f->max_size;
i++) {
706 SDL_DestroyMutex(
f->mutex);
707 SDL_DestroyCond(
f->cond);
712 SDL_LockMutex(
f->mutex);
713 SDL_CondSignal(
f->cond);
714 SDL_UnlockMutex(
f->mutex);
719 return &
f->queue[(
f->rindex +
f->rindex_shown) %
f->max_size];
724 return &
f->queue[(
f->rindex +
f->rindex_shown + 1) %
f->max_size];
729 return &
f->queue[
f->rindex];
735 SDL_LockMutex(
f->mutex);
736 while (
f->size >=
f->max_size &&
737 !
f->pktq->abort_request) {
738 SDL_CondWait(
f->cond,
f->mutex);
740 SDL_UnlockMutex(
f->mutex);
742 if (
f->pktq->abort_request)
745 return &
f->queue[
f->windex];
751 SDL_LockMutex(
f->mutex);
752 while (
f->size -
f->rindex_shown <= 0 &&
753 !
f->pktq->abort_request) {
754 SDL_CondWait(
f->cond,
f->mutex);
756 SDL_UnlockMutex(
f->mutex);
758 if (
f->pktq->abort_request)
761 return &
f->queue[(
f->rindex +
f->rindex_shown) %
f->max_size];
766 if (++
f->windex ==
f->max_size)
768 SDL_LockMutex(
f->mutex);
770 SDL_CondSignal(
f->cond);
771 SDL_UnlockMutex(
f->mutex);
776 if (
f->keep_last && !
f->rindex_shown) {
781 if (++
f->rindex ==
f->max_size)
783 SDL_LockMutex(
f->mutex);
785 SDL_CondSignal(
f->cond);
786 SDL_UnlockMutex(
f->mutex);
792 return f->size -
f->rindex_shown;
799 if (
f->rindex_shown &&
fp->serial ==
f->pktq->serial)
809 SDL_WaitThread(
d->decoder_tid,
NULL);
810 d->decoder_tid =
NULL;
825 static int realloc_texture(SDL_Texture **texture, Uint32 new_format,
int new_width,
int new_height, SDL_BlendMode blendmode,
int init_texture)
829 if (!*texture || SDL_QueryTexture(*texture, &
format, &access, &
w, &
h) < 0 || new_width !=
w || new_height !=
h || new_format !=
format) {
833 SDL_DestroyTexture(*texture);
834 if (!(*texture = SDL_CreateTexture(
renderer, new_format, SDL_TEXTUREACCESS_STREAMING, new_width, new_height)))
836 if (SDL_SetTextureBlendMode(*texture, blendmode) < 0)
839 if (SDL_LockTexture(*texture,
NULL, &pixels, &pitch) < 0)
841 memset(pixels, 0, pitch * new_height);
842 SDL_UnlockTexture(*texture);
844 av_log(
NULL,
AV_LOG_VERBOSE,
"Created %dx%d texture with %s.\n", new_width, new_height, SDL_GetPixelFormatName(new_format));
850 int scr_xleft,
int scr_ytop,
int scr_width,
int scr_height,
851 int pic_width,
int pic_height,
AVRational pic_sar)
864 if (
width > scr_width) {
868 x = (scr_width -
width) / 2;
869 y = (scr_height -
height) / 2;
870 rect->
x = scr_xleft + x;
871 rect->
y = scr_ytop + y;
879 *sdl_blendmode = SDL_BLENDMODE_NONE;
880 *sdl_pix_fmt = SDL_PIXELFORMAT_UNKNOWN;
885 *sdl_blendmode = SDL_BLENDMODE_BLEND;
897 SDL_BlendMode sdl_blendmode;
899 if (
realloc_texture(tex, sdl_pix_fmt == SDL_PIXELFORMAT_UNKNOWN ? SDL_PIXELFORMAT_ARGB8888 : sdl_pix_fmt,
frame->width,
frame->height, sdl_blendmode, 0) < 0)
901 switch (sdl_pix_fmt) {
902 case SDL_PIXELFORMAT_UNKNOWN:
907 if (*img_convert_ctx !=
NULL) {
910 if (!SDL_LockTexture(*tex,
NULL, (
void **)pixels, pitch)) {
912 0,
frame->height, pixels, pitch);
913 SDL_UnlockTexture(*tex);
920 case SDL_PIXELFORMAT_IYUV:
921 if (
frame->linesize[0] > 0 &&
frame->linesize[1] > 0 &&
frame->linesize[2] > 0) {
925 }
else if (
frame->linesize[0] < 0 &&
frame->linesize[1] < 0 &&
frame->linesize[2] < 0) {
935 if (
frame->linesize[0] < 0) {
947 #if SDL_VERSION_ATLEAST(2,0,8)
948 SDL_YUV_CONVERSION_MODE
mode = SDL_YUV_CONVERSION_AUTOMATIC;
951 mode = SDL_YUV_CONVERSION_JPEG;
953 mode = SDL_YUV_CONVERSION_BT709;
955 mode = SDL_YUV_CONVERSION_BT601;
957 SDL_SetYUVConversionMode(
mode);
968 if (
is->subtitle_st) {
972 if (vp->
pts >=
sp->pts + ((
float)
sp->sub.start_display_time / 1000)) {
977 if (!
sp->width || !
sp->height) {
981 if (
realloc_texture(&
is->sub_texture, SDL_PIXELFORMAT_ARGB8888,
sp->width,
sp->height, SDL_BLENDMODE_BLEND, 1) < 0)
984 for (
i = 0;
i <
sp->sub.num_rects;
i++) {
989 sub_rect->
w =
av_clip(sub_rect->
w, 0,
sp->width - sub_rect->
x);
990 sub_rect->
h =
av_clip(sub_rect->
h, 0,
sp->height - sub_rect->
y);
996 if (!
is->sub_convert_ctx) {
1000 if (!SDL_LockTexture(
is->sub_texture, (SDL_Rect *)sub_rect, (
void **)pixels, pitch)) {
1001 sws_scale(
is->sub_convert_ctx, (
const uint8_t *
const *)sub_rect->data, sub_rect->linesize,
1002 0, sub_rect->h, pixels, pitch);
1003 SDL_UnlockTexture(
is->sub_texture);
1028 #if USE_ONEPASS_SUBTITLE_RENDER
1034 for (
i = 0;
i <
sp->sub.num_rects;
i++) {
1035 SDL_Rect *sub_rect = (SDL_Rect*)
sp->sub.rects[
i];
1036 SDL_Rect target = {.x =
rect.
x + sub_rect->x * xratio,
1037 .y =
rect.
y + sub_rect->y * yratio,
1038 .w = sub_rect->w * xratio,
1039 .h = sub_rect->h * yratio};
1040 SDL_RenderCopy(
renderer,
is->sub_texture, sub_rect, &target);
1048 return a < 0 ?
a%
b +
b :
a%
b;
1053 int i, i_start, x, y1, y, ys, delay, n, nb_display_channels;
1056 int rdft_bits, nb_freq;
1058 for (rdft_bits = 1; (1 << rdft_bits) < 2 *
s->height; rdft_bits++)
1060 nb_freq = 1 << (rdft_bits - 1);
1063 channels =
s->audio_tgt.ch_layout.nb_channels;
1066 int data_used=
s->show_mode == SHOW_MODE_WAVES ?
s->width : (2*nb_freq);
1068 delay =
s->audio_write_buf_size;
1075 delay -= (time_diff *
s->audio_tgt.freq) / 1000000;
1078 delay += 2 * data_used;
1079 if (delay < data_used)
1083 if (
s->show_mode == SHOW_MODE_WAVES) {
1087 int a =
s->sample_array[idx];
1092 if (
h < score && (
b ^
c) < 0) {
1099 s->last_i_start = i_start;
1101 i_start =
s->last_i_start;
1104 if (
s->show_mode == SHOW_MODE_WAVES) {
1105 SDL_SetRenderDrawColor(
renderer, 255, 255, 255, 255);
1108 h =
s->height / nb_display_channels;
1111 for (ch = 0; ch < nb_display_channels; ch++) {
1113 y1 =
s->ytop + ch *
h + (
h / 2);
1114 for (x = 0; x <
s->width; x++) {
1115 y = (
s->sample_array[
i] * h2) >> 15;
1129 SDL_SetRenderDrawColor(
renderer, 0, 0, 255, 255);
1131 for (ch = 1; ch < nb_display_channels; ch++) {
1132 y =
s->ytop + ch *
h;
1136 if (
realloc_texture(&
s->vis_texture, SDL_PIXELFORMAT_ARGB8888,
s->width,
s->height, SDL_BLENDMODE_NONE, 1) < 0)
1139 if (
s->xpos >=
s->width)
1141 nb_display_channels=
FFMIN(nb_display_channels, 2);
1142 if (rdft_bits !=
s->rdft_bits) {
1146 s->rdft_bits = rdft_bits;
1149 if (!
s->rdft || !
s->rdft_data){
1151 s->show_mode = SHOW_MODE_WAVES;
1154 SDL_Rect
rect = {.
x =
s->xpos, .y = 0, .w = 1, .h =
s->height};
1157 for (ch = 0; ch < nb_display_channels; ch++) {
1158 data[ch] =
s->rdft_data + 2 * nb_freq * ch;
1160 for (x = 0; x < 2 * nb_freq; x++) {
1161 double w = (x-nb_freq) * (1.0 / nb_freq);
1162 data[ch][x] =
s->sample_array[
i] * (1.0 -
w *
w);
1171 if (!SDL_LockTexture(
s->vis_texture, &
rect, (
void **)&pixels, &pitch)) {
1173 pixels += pitch *
s->height;
1174 for (y = 0; y <
s->height; y++) {
1175 double w = 1 / sqrt(nb_freq);
1176 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]));
1177 int b = (nb_display_channels == 2 ) ? sqrt(
w *
hypot(
data[1][2 * y + 0],
data[1][2 * y + 1]))
1182 *pixels = (
a << 16) + (
b << 8) + ((
a+
b) >> 1);
1184 SDL_UnlockTexture(
s->vis_texture);
1198 if (stream_index < 0 || stream_index >= ic->
nb_streams)
1209 is->audio_buf1_size = 0;
1235 is->audio_stream = -1;
1239 is->video_stream = -1;
1243 is->subtitle_stream = -1;
1253 is->abort_request = 1;
1254 SDL_WaitThread(
is->read_tid,
NULL);
1257 if (
is->audio_stream >= 0)
1259 if (
is->video_stream >= 0)
1261 if (
is->subtitle_stream >= 0)
1274 SDL_DestroyCond(
is->continue_read_thread);
1278 if (
is->vis_texture)
1279 SDL_DestroyTexture(
is->vis_texture);
1280 if (
is->vid_texture)
1281 SDL_DestroyTexture(
is->vid_texture);
1282 if (
is->sub_texture)
1283 SDL_DestroyTexture(
is->sub_texture);
1295 SDL_DestroyWindow(
window);
1318 if (max_width == INT_MAX && max_height == INT_MAX)
1339 SDL_SetWindowFullscreen(
window, SDL_WINDOW_FULLSCREEN_DESKTOP);
1354 SDL_SetRenderDrawColor(
renderer, 0, 0, 0, 255);
1356 if (
is->audio_st &&
is->show_mode != SHOW_MODE_VIDEO)
1358 else if (
is->video_st)
1365 if (*
c->queue_serial !=
c->serial)
1371 return c->pts_drift + time - (time -
c->last_updated) * (1.0 -
c->speed);
1378 c->last_updated = time;
1379 c->pts_drift =
c->pts - time;
1399 c->queue_serial = queue_serial;
1454 double speed =
is->extclk.speed;
1463 if (!
is->seek_req) {
1470 SDL_CondSignal(
is->continue_read_thread);
1479 if (
is->read_pause_return !=
AVERROR(ENOSYS)) {
1480 is->vidclk.paused = 0;
1485 is->paused =
is->audclk.paused =
is->vidclk.paused =
is->extclk.paused = !
is->paused;
1496 is->muted = !
is->muted;
1501 double volume_level =
is->audio_volume ? (20 * log(
is->audio_volume / (
double)SDL_MIX_MAXVOLUME) / log(10)) : -1000.0;
1502 int new_volume =
lrint(SDL_MIX_MAXVOLUME * pow(10.0, (volume_level + sign *
step) / 20.0));
1503 is->audio_volume =
av_clip(
is->audio_volume == new_volume ? (
is->audio_volume + sign) : new_volume, 0, SDL_MIX_MAXVOLUME);
1516 double sync_threshold,
diff = 0;
1529 if (
diff <= -sync_threshold)
1532 delay = delay +
diff;
1533 else if (
diff >= sync_threshold)
1547 if (
isnan(
duration) || duration <= 0 || duration >
is->max_frame_duration)
1575 if (
is->force_refresh ||
is->last_vis_time +
rdftspeed < time) {
1577 is->last_vis_time = time;
1579 *remaining_time =
FFMIN(*remaining_time,
is->last_vis_time +
rdftspeed - time);
1587 double last_duration,
duration, delay;
1594 if (vp->
serial !=
is->videoq.serial) {
1610 if (time < is->frame_timer + delay) {
1611 *remaining_time =
FFMIN(
is->frame_timer + delay - time, *remaining_time);
1615 is->frame_timer += delay;
1617 is->frame_timer = time;
1619 SDL_LockMutex(
is->pictq.mutex);
1622 SDL_UnlockMutex(
is->pictq.mutex);
1628 is->frame_drops_late++;
1634 if (
is->subtitle_st) {
1643 if (
sp->serial !=
is->subtitleq.serial
1644 || (
is->vidclk.pts > (
sp->pts + ((
float)
sp->sub.end_display_time / 1000)))
1649 for (
i = 0;
i <
sp->sub.num_rects;
i++) {
1654 if (!SDL_LockTexture(
is->sub_texture, (SDL_Rect *)sub_rect, (
void **)&pixels, &pitch)) {
1655 for (j = 0; j < sub_rect->h; j++, pixels += pitch)
1656 memset(pixels, 0, sub_rect->w << 2);
1657 SDL_UnlockTexture(
is->sub_texture);
1669 is->force_refresh = 1;
1671 if (
is->step && !
is->paused)
1676 if (!
display_disable &&
is->force_refresh &&
is->show_mode == SHOW_MODE_VIDEO &&
is->pictq.rindex_shown)
1679 is->force_refresh = 0;
1682 static int64_t last_time;
1684 int aqsize, vqsize, sqsize;
1688 if (!last_time || (cur_time - last_time) >= 30000) {
1693 aqsize =
is->audioq.size;
1695 vqsize =
is->videoq.size;
1696 if (
is->subtitle_st)
1697 sqsize =
is->subtitleq.size;
1699 if (
is->audio_st &&
is->video_st)
1701 else if (
is->video_st)
1703 else if (
is->audio_st)
1708 "%7.2f %s:%7.3f fd=%4d aq=%5dKB vq=%5dKB sq=%5dB f=%"PRId64
"/%"PRId64
" \r",
1710 (
is->audio_st &&
is->video_st) ?
"A-V" : (
is->video_st ?
"M-V" : (
is->audio_st ?
"M-A" :
" ")),
1712 is->frame_drops_early +
is->frame_drops_late,
1716 is->video_st ?
is->viddec.avctx->pts_correction_num_faulty_dts : 0,
1717 is->video_st ?
is->viddec.avctx->pts_correction_num_faulty_pts : 0);
1720 fprintf(stderr,
"%s", buf.str);
1727 last_time = cur_time;
1736 #if defined(DEBUG_SYNC)
1737 printf(
"frame_type=%c pts=%0.3f\n",
1782 diff -
is->frame_last_filter_delay < 0 &&
1783 is->viddec.pkt_serial ==
is->vidclk.serial &&
1784 is->videoq.nb_packets) {
1785 is->frame_drops_early++;
1813 outputs->filter_ctx = source_ctx;
1818 inputs->filter_ctx = sink_ctx;
1843 char sws_flags_str[512] =
"";
1844 char buffersrc_args[256];
1850 int nb_pix_fmts = 0;
1864 if (!strcmp(e->
key,
"sws_flags")) {
1865 av_strlcatf(sws_flags_str,
sizeof(sws_flags_str),
"%s=%s:",
"flags", e->
value);
1869 if (strlen(sws_flags_str))
1870 sws_flags_str[strlen(sws_flags_str)-1] =
'\0';
1874 snprintf(buffersrc_args,
sizeof(buffersrc_args),
1875 "video_size=%dx%d:pix_fmt=%d:time_base=%d/%d:pixel_aspect=%d/%d",
1877 is->video_st->time_base.num,
is->video_st->time_base.den,
1880 av_strlcatf(buffersrc_args,
sizeof(buffersrc_args),
":frame_rate=%d/%d", fr.
num, fr.
den);
1884 "ffplay_buffer", buffersrc_args,
NULL,
1890 "ffplay_buffersink",
NULL,
NULL, graph);
1897 last_filter = filt_out;
1901 #define INSERT_FILT(name, arg) do { \
1902 AVFilterContext *filt_ctx; \
1904 ret = avfilter_graph_create_filter(&filt_ctx, \
1905 avfilter_get_by_name(name), \
1906 "ffplay_" name, arg, NULL, graph); \
1910 ret = avfilter_link(filt_ctx, 0, last_filter, 0); \
1914 last_filter = filt_ctx; \
1921 if (
fabs(theta - 90) < 1.0) {
1922 INSERT_FILT(
"transpose",
"clock");
1923 }
else if (
fabs(theta - 180) < 1.0) {
1924 INSERT_FILT(
"hflip",
NULL);
1925 INSERT_FILT(
"vflip",
NULL);
1926 }
else if (
fabs(theta - 270) < 1.0) {
1927 INSERT_FILT(
"transpose",
"cclock");
1928 }
else if (
fabs(theta) > 1.0) {
1929 char rotate_buf[64];
1930 snprintf(rotate_buf,
sizeof(rotate_buf),
"%f*PI/180", theta);
1931 INSERT_FILT(
"rotate", rotate_buf);
1938 is->in_video_filter = filt_src;
1939 is->out_video_filter = filt_out;
1945 static int configure_audio_filters(
VideoState *
is,
const char *afilters,
int force_output_format)
1950 char aresample_swr_opts[512] =
"";
1953 char asrc_args[256];
1965 if (strlen(aresample_swr_opts))
1966 aresample_swr_opts[strlen(aresample_swr_opts)-1] =
'\0';
1967 av_opt_set(
is->agraph,
"aresample_swr_opts", aresample_swr_opts, 0);
1972 "sample_rate=%d:sample_fmt=%s:time_base=%d/%d:channel_layout=%s",
1974 1,
is->audio_filter_src.freq, bp.str);
1978 asrc_args,
NULL,
is->agraph);
1994 if (force_output_format) {
2008 is->in_audio_filter = filt_asrc;
2009 is->out_audio_filter = filt_asink;
2026 int last_serial = -1;
2046 frame->format,
frame->ch_layout.nb_channels) ||
2048 is->audio_filter_src.freq !=
frame->sample_rate ||
2049 is->auddec.pkt_serial != last_serial;
2052 char buf1[1024], buf2[1024];
2056 "Audio frame changed from rate:%d ch:%d fmt:%s layout:%s serial:%d to rate:%d ch:%d fmt:%s layout:%s serial:%d\n",
2057 is->audio_filter_src.freq,
is->audio_filter_src.ch_layout.nb_channels,
av_get_sample_fmt_name(
is->audio_filter_src.fmt), buf1, last_serial,
2060 is->audio_filter_src.fmt =
frame->format;
2064 is->audio_filter_src.freq =
frame->sample_rate;
2065 last_serial =
is->auddec.pkt_serial;
2067 if ((
ret = configure_audio_filters(
is, afilters, 1)) < 0)
2082 af->
serial =
is->auddec.pkt_serial;
2089 if (
is->audioq.serial !=
is->auddec.pkt_serial)
2093 is->auddec.finished =
is->auddec.pkt_serial;
2108 d->decoder_tid = SDL_CreateThread(
fn, thread_name,
arg);
2109 if (!
d->decoder_tid) {
2132 int last_serial = -1;
2133 int last_vfilter_idx = 0;
2147 if ( last_w !=
frame->width
2148 || last_h !=
frame->height
2149 || last_format !=
frame->format
2150 || last_serial !=
is->viddec.pkt_serial
2151 || last_vfilter_idx !=
is->vfilter_idx) {
2153 "Video frame changed from size:%dx%d format:%s serial:%d to size:%dx%d format:%s serial:%d\n",
2165 if ((
ret = configure_video_filters(graph,
is, vfilters_list ? vfilters_list[
is->vfilter_idx] :
NULL,
frame)) < 0) {
2168 event.user.data1 =
is;
2169 SDL_PushEvent(&event);
2172 filt_in =
is->in_video_filter;
2173 filt_out =
is->out_video_filter;
2174 last_w =
frame->width;
2175 last_h =
frame->height;
2176 last_format =
frame->format;
2177 last_serial =
is->viddec.pkt_serial;
2178 last_vfilter_idx =
is->vfilter_idx;
2192 is->viddec.finished =
is->viddec.pkt_serial;
2199 is->frame_last_filter_delay = 0;
2207 if (
is->videoq.serial !=
is->viddec.pkt_serial)
2239 if (got_subtitle &&
sp->sub.format == 0) {
2243 sp->serial =
is->subdec.pkt_serial;
2244 sp->width =
is->subdec.avctx->width;
2245 sp->height =
is->subdec.avctx->height;
2250 }
else if (got_subtitle) {
2267 memcpy(
is->sample_array +
is->sample_array_index,
samples,
len *
sizeof(
short));
2269 is->sample_array_index +=
len;
2271 is->sample_array_index = 0;
2280 int wanted_nb_samples = nb_samples;
2284 double diff, avg_diff;
2285 int min_nb_samples, max_nb_samples;
2290 is->audio_diff_cum =
diff +
is->audio_diff_avg_coef *
is->audio_diff_cum;
2293 is->audio_diff_avg_count++;
2296 avg_diff =
is->audio_diff_cum * (1.0 -
is->audio_diff_avg_coef);
2298 if (
fabs(avg_diff) >=
is->audio_diff_threshold) {
2299 wanted_nb_samples = nb_samples + (
int)(
diff *
is->audio_src.freq);
2302 wanted_nb_samples =
av_clip(wanted_nb_samples, min_nb_samples, max_nb_samples);
2305 diff, avg_diff, wanted_nb_samples - nb_samples,
2306 is->audio_clock,
is->audio_diff_threshold);
2311 is->audio_diff_avg_count = 0;
2312 is->audio_diff_cum = 0;
2316 return wanted_nb_samples;
2328 int data_size, resampled_data_size;
2330 int wanted_nb_samples;
2347 }
while (af->
serial !=
is->audioq.serial);
2361 &
is->audio_tgt.ch_layout,
is->audio_tgt.fmt,
is->audio_tgt.freq,
2366 "Cannot create sample rate converter for conversion of %d Hz %s %d channels to %d Hz %s %d channels!\n",
2380 uint8_t **
out = &
is->audio_buf1;
2381 int out_count = (int64_t)wanted_nb_samples *
is->audio_tgt.freq / af->
frame->
sample_rate + 256;
2396 if (!
is->audio_buf1)
2403 if (len2 == out_count) {
2408 is->audio_buf =
is->audio_buf1;
2412 resampled_data_size = data_size;
2415 audio_clock0 =
is->audio_clock;
2420 is->audio_clock =
NAN;
2421 is->audio_clock_serial = af->
serial;
2424 static double last_clock;
2425 printf(
"audio: delay=%0.3f clock=%0.3f clock0=%0.3f\n",
2426 is->audio_clock - last_clock,
2427 is->audio_clock, audio_clock0);
2428 last_clock =
is->audio_clock;
2431 return resampled_data_size;
2438 int audio_size, len1;
2443 if (
is->audio_buf_index >=
is->audio_buf_size) {
2445 if (audio_size < 0) {
2450 if (
is->show_mode != SHOW_MODE_VIDEO)
2452 is->audio_buf_size = audio_size;
2454 is->audio_buf_index = 0;
2456 len1 =
is->audio_buf_size -
is->audio_buf_index;
2459 if (!
is->muted &&
is->audio_buf &&
is->audio_volume == SDL_MIX_MAXVOLUME)
2460 memcpy(stream, (uint8_t *)
is->audio_buf +
is->audio_buf_index, len1);
2462 memset(stream, 0, len1);
2463 if (!
is->muted &&
is->audio_buf)
2464 SDL_MixAudioFormat(stream, (uint8_t *)
is->audio_buf +
is->audio_buf_index, AUDIO_S16SYS, len1,
is->audio_volume);
2468 is->audio_buf_index += len1;
2470 is->audio_write_buf_size =
is->audio_buf_size -
is->audio_buf_index;
2472 if (!
isnan(
is->audio_clock)) {
2480 SDL_AudioSpec wanted_spec, spec;
2482 static const int next_nb_channels[] = {0, 0, 1, 6, 2, 6, 4, 6};
2483 static const int next_sample_rates[] = {0, 44100, 48000, 96000, 192000};
2484 int next_sample_rate_idx =
FF_ARRAY_ELEMS(next_sample_rates) - 1;
2485 int wanted_nb_channels = wanted_channel_layout->
nb_channels;
2487 env = SDL_getenv(
"SDL_AUDIO_CHANNELS");
2489 wanted_nb_channels = atoi(env);
2497 wanted_nb_channels = wanted_channel_layout->
nb_channels;
2498 wanted_spec.channels = wanted_nb_channels;
2499 wanted_spec.freq = wanted_sample_rate;
2500 if (wanted_spec.freq <= 0 || wanted_spec.channels <= 0) {
2504 while (next_sample_rate_idx && next_sample_rates[next_sample_rate_idx] >= wanted_spec.freq)
2505 next_sample_rate_idx--;
2506 wanted_spec.format = AUDIO_S16SYS;
2507 wanted_spec.silence = 0;
2510 wanted_spec.userdata = opaque;
2511 while (!(
audio_dev = SDL_OpenAudioDevice(
NULL, 0, &wanted_spec, &spec, SDL_AUDIO_ALLOW_FREQUENCY_CHANGE | SDL_AUDIO_ALLOW_CHANNELS_CHANGE))) {
2513 wanted_spec.channels, wanted_spec.freq, SDL_GetError());
2514 wanted_spec.channels = next_nb_channels[
FFMIN(7, wanted_spec.channels)];
2515 if (!wanted_spec.channels) {
2516 wanted_spec.freq = next_sample_rates[next_sample_rate_idx--];
2517 wanted_spec.channels = wanted_nb_channels;
2518 if (!wanted_spec.freq) {
2520 "No more combinations to try, audio open failed\n");
2526 if (spec.format != AUDIO_S16SYS) {
2528 "SDL advised audio format %d is not supported!\n", spec.format);
2531 if (spec.channels != wanted_spec.channels) {
2536 "SDL advised channel count %d is not supported!\n", spec.channels);
2542 audio_hw_params->
freq = spec.freq;
2560 const char *forced_codec_name =
NULL;
2566 int stream_lowres =
lowres;
2568 if (stream_index < 0 || stream_index >= ic->
nb_streams)
2587 if (forced_codec_name)
2591 "No codec could be found with name '%s'\n", forced_codec_name);
2604 avctx->
lowres = stream_lowres;
2636 if ((
ret = configure_audio_filters(
is, afilters, 0)) < 0)
2638 sink =
is->out_audio_filter;
2654 is->audio_hw_buf_size =
ret;
2655 is->audio_src =
is->audio_tgt;
2656 is->audio_buf_size = 0;
2657 is->audio_buf_index = 0;
2661 is->audio_diff_avg_count = 0;
2664 is->audio_diff_threshold = (
double)(
is->audio_hw_buf_size) /
is->audio_tgt.bytes_per_sec;
2666 is->audio_stream = stream_index;
2667 is->audio_st = ic->
streams[stream_index];
2672 is->auddec.start_pts =
is->audio_st->start_time;
2673 is->auddec.start_pts_tb =
is->audio_st->time_base;
2680 is->video_stream = stream_index;
2681 is->video_st = ic->
streams[stream_index];
2687 is->queue_attachments_req = 1;
2690 is->subtitle_stream = stream_index;
2691 is->subtitle_st = ic->
streams[stream_index];
2715 return is->abort_request;
2719 return stream_id < 0 ||
2727 if( !strcmp(
s->iformat->name,
"rtp")
2728 || !strcmp(
s->iformat->name,
"rtsp")
2729 || !strcmp(
s->iformat->name,
"sdp")
2733 if(
s->pb && ( !strncmp(
s->url,
"rtp:", 4)
2734 || !strncmp(
s->url,
"udp:", 4)
2749 int64_t stream_start_time;
2750 int pkt_in_play_range = 0;
2752 SDL_mutex *wait_mutex = SDL_CreateMutex();
2753 int scan_all_pmts_set = 0;
2762 memset(st_index, -1,
sizeof(st_index));
2781 scan_all_pmts_set = 1;
2789 if (scan_all_pmts_set)
2810 for (
i = 0;
i < orig_nb_streams;
i++)
2816 "%s: could not find codec parameters\n",
is->filename);
2866 st_index[
i] = INT_MAX;
2894 if (codecpar->
width)
2907 if (
is->show_mode == SHOW_MODE_NONE)
2908 is->show_mode =
ret >= 0 ? SHOW_MODE_VIDEO : SHOW_MODE_RDFT;
2914 if (
is->video_stream < 0 &&
is->audio_stream < 0) {
2921 if (infinite_buffer < 0 && is->realtime)
2925 if (
is->abort_request)
2927 if (
is->paused !=
is->last_paused) {
2928 is->last_paused =
is->paused;
2934 #if CONFIG_RTSP_DEMUXER || CONFIG_MMSH_PROTOCOL
2945 int64_t seek_target =
is->seek_pos;
2946 int64_t seek_min =
is->seek_rel > 0 ? seek_target -
is->seek_rel + 2: INT64_MIN;
2947 int64_t seek_max =
is->seek_rel < 0 ? seek_target -
is->seek_rel - 2: INT64_MAX;
2954 "%s: error while seeking\n",
is->ic->url);
2956 if (
is->audio_stream >= 0)
2958 if (
is->subtitle_stream >= 0)
2960 if (
is->video_stream >= 0)
2969 is->queue_attachments_req = 1;
2974 if (
is->queue_attachments_req) {
2981 is->queue_attachments_req = 0;
2991 SDL_LockMutex(wait_mutex);
2992 SDL_CondWaitTimeout(
is->continue_read_thread, wait_mutex, 10);
2993 SDL_UnlockMutex(wait_mutex);
3009 if (
is->video_stream >= 0)
3011 if (
is->audio_stream >= 0)
3013 if (
is->subtitle_stream >= 0)
3023 SDL_LockMutex(wait_mutex);
3024 SDL_CondWaitTimeout(
is->continue_read_thread, wait_mutex, 10);
3025 SDL_UnlockMutex(wait_mutex);
3034 (pkt_ts - (stream_start_time !=
AV_NOPTS_VALUE ? stream_start_time : 0)) *
3060 event.user.data1 =
is;
3061 SDL_PushEvent(&event);
3063 SDL_DestroyMutex(wait_mutex);
3075 is->last_video_stream =
is->video_stream = -1;
3076 is->last_audio_stream =
is->audio_stream = -1;
3077 is->last_subtitle_stream =
is->subtitle_stream = -1;
3098 if (!(
is->continue_read_thread = SDL_CreateCond())) {
3106 is->audio_clock_serial = -1;
3117 if (!
is->read_tid) {
3129 int start_index, stream_index;
3136 start_index =
is->last_video_stream;
3137 old_index =
is->video_stream;
3139 start_index =
is->last_audio_stream;
3140 old_index =
is->audio_stream;
3142 start_index =
is->last_subtitle_stream;
3143 old_index =
is->subtitle_stream;
3145 stream_index = start_index;
3151 for (start_index = 0; start_index <
nb_streams; start_index++)
3156 stream_index = start_index;
3166 is->last_subtitle_stream = -1;
3169 if (start_index == -1)
3173 if (stream_index == start_index)
3175 st =
is->ic->streams[p ? p->
stream_index[stream_index] : stream_index];
3193 if (p && stream_index != -1)
3213 int next =
is->show_mode;
3215 next = (next + 1) % SHOW_MODE_NB;
3216 }
while (next !=
is->show_mode && (next == SHOW_MODE_VIDEO && !
is->video_st || next != SHOW_MODE_VIDEO && !
is->audio_st));
3217 if (
is->show_mode != next) {
3218 is->force_refresh = 1;
3219 is->show_mode = next;
3224 double remaining_time = 0.0;
3226 while (!SDL_PeepEvents(event, 1, SDL_GETEVENT, SDL_FIRSTEVENT, SDL_LASTEVENT)) {
3231 if (remaining_time > 0.0)
3232 av_usleep((int64_t)(remaining_time * 1000000.0));
3234 if (
is->show_mode != SHOW_MODE_NONE && (!
is->paused ||
is->force_refresh))
3245 if (!
is->ic->nb_chapters)
3249 for (
i = 0;
i <
is->ic->nb_chapters;
i++) {
3259 if (
i >=
is->ic->nb_chapters)
3271 double incr,
pos, frac;
3276 switch (event.type) {
3278 if (
exit_on_keydown || event.key.keysym.sym == SDLK_ESCAPE || event.key.keysym.sym == SDLK_q) {
3283 if (!cur_stream->
width)
3285 switch (event.key.keysym.sym) {
3297 case SDLK_KP_MULTIPLY:
3301 case SDLK_KP_DIVIDE:
3324 if (cur_stream->
show_mode == SHOW_MODE_VIDEO && cur_stream->vfilter_idx < nb_vfilters - 1) {
3325 if (++cur_stream->vfilter_idx >= nb_vfilters)
3326 cur_stream->vfilter_idx = 0;
3328 cur_stream->vfilter_idx = 0;
3389 case SDL_MOUSEBUTTONDOWN:
3394 if (event.button.button == SDL_BUTTON_LEFT) {
3395 static int64_t last_mouse_left_click = 0;
3399 last_mouse_left_click = 0;
3404 case SDL_MOUSEMOTION:
3410 if (event.type == SDL_MOUSEBUTTONDOWN) {
3411 if (event.button.button != SDL_BUTTON_RIGHT)
3415 if (!(event.motion.state & SDL_BUTTON_RMASK))
3425 int tns, thh, tmm, tss;
3428 tmm = (tns % 3600) / 60;
3430 frac = x / cur_stream->
width;
3433 mm = (
ns % 3600) / 60;
3436 "Seek to %2.0f%% (%2d:%02d:%02d) of total duration (%2d:%02d:%02d) \n", frac*100,
3437 hh, mm,
ss, thh, tmm, tss);
3444 case SDL_WINDOWEVENT:
3445 switch (event.window.event) {
3446 case SDL_WINDOWEVENT_SIZE_CHANGED:
3453 case SDL_WINDOWEVENT_EXPOSED:
3491 if (!strcmp(
arg,
"audio"))
3493 else if (!strcmp(
arg,
"video"))
3495 else if (!strcmp(
arg,
"ext"))
3519 !strcmp(
arg,
"waves") ? SHOW_MODE_WAVES :
3520 !strcmp(
arg,
"rdft" ) ? SHOW_MODE_RDFT :
3529 "Argument '%s' provided as input filename, but '%s' was already specified.\n",
3533 if (!strcmp(filename,
"-"))
3540 const char *spec = strchr(opt,
':');
3543 "No media specifier was specified in '%s' in option '%s'\n",
3554 "Invalid media specifier '%s' in option '%s'\n", spec, opt);
3564 {
"x",
HAS_ARG, { .func_arg =
opt_width },
"force displayed width",
"width" },
3565 {
"y",
HAS_ARG, { .func_arg =
opt_height },
"force displayed height",
"height" },
3573 {
"ss",
HAS_ARG, { .func_arg =
opt_seek },
"seek to a given position in seconds",
"pos" },
3574 {
"t",
HAS_ARG, { .func_arg =
opt_duration },
"play \"duration\" seconds of audio/video",
"duration" },
3587 {
"sync",
HAS_ARG |
OPT_EXPERT, { .func_arg =
opt_sync },
"set audio-video sync. type (type=audio/video/ext)",
"type" },
3598 {
"vf",
OPT_EXPERT |
HAS_ARG, { .func_arg = opt_add_vfilter },
"set video filters",
"filter_graph" },
3599 {
"af",
OPT_STRING |
HAS_ARG, { &afilters },
"set audio filters",
"filter_graph" },
3602 {
"showmode",
HAS_ARG, { .func_arg =
opt_show_mode},
"select show mode (0 = video, 1 = waves, 2 = RDFT)",
"mode" },
3603 {
"i",
OPT_BOOL, { &
dummy},
"read specified file",
"input_file"},
3604 {
"codec",
HAS_ARG, { .func_arg =
opt_codec},
"force decoder",
"decoder_name" },
3610 "read and decode the streams to fill missing information with heuristics" },
3631 #if !CONFIG_AVFILTER
3636 printf(
"\nWhile playing:\n"
3638 "f toggle full screen\n"
3641 "9, 0 decrease and increase volume respectively\n"
3642 "/, * decrease and increase volume respectively\n"
3643 "a cycle audio channel in the current program\n"
3644 "v cycle video channel\n"
3645 "t cycle subtitle channel in the current program\n"
3647 "w cycle video filters or show modes\n"
3648 "s activate frame-step mode\n"
3649 "left/right seek backward/forward 10 seconds or to custom interval if -seek_interval is set\n"
3650 "down/up seek backward/forward 1 minute\n"
3651 "page down/page up seek backward/forward 10 minutes\n"
3652 "right mouse click seek to percentage in file corresponding to fraction of width\n"
3653 "left double-click toggle full screen\n"
3685 "Use -h to get full help or, even better, run 'man %s'\n",
program_name);
3692 flags = SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER;
3694 flags &= ~SDL_INIT_AUDIO;
3698 if (!SDL_getenv(
"SDL_AUDIO_ALSA_SET_BUFFER_SIZE"))
3699 SDL_setenv(
"SDL_AUDIO_ALSA_SET_BUFFER_SIZE",
"1", 1);
3702 flags &= ~SDL_INIT_VIDEO;
3703 if (SDL_Init (
flags)) {
3709 SDL_EventState(SDL_SYSWMEVENT, SDL_IGNORE);
3710 SDL_EventState(SDL_USEREVENT, SDL_IGNORE);
3713 int flags = SDL_WINDOW_HIDDEN;
3715 #if SDL_VERSION_ATLEAST(2,0,5)
3716 flags |= SDL_WINDOW_ALWAYS_ON_TOP;
3718 av_log(
NULL,
AV_LOG_WARNING,
"Your SDL version doesn't support SDL_WINDOW_ALWAYS_ON_TOP. Feature will be inactive.\n");
3721 flags |= SDL_WINDOW_BORDERLESS;
3723 flags |= SDL_WINDOW_RESIZABLE;
3725 #ifdef SDL_HINT_VIDEO_X11_NET_WM_BYPASS_COMPOSITOR
3726 SDL_SetHint(SDL_HINT_VIDEO_X11_NET_WM_BYPASS_COMPOSITOR,
"0");
3729 SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY,
"linear");
3731 renderer = SDL_CreateRenderer(
window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);