58 #include <SDL_thread.h>
67 #define MAX_QUEUE_SIZE (15 * 1024 * 1024)
69 #define EXTERNAL_CLOCK_MIN_FRAMES 2
70 #define EXTERNAL_CLOCK_MAX_FRAMES 10
73 #define SDL_AUDIO_MIN_BUFFER_SIZE 512
75 #define SDL_AUDIO_MAX_CALLBACKS_PER_SEC 30
78 #define SDL_VOLUME_STEP (0.75)
81 #define AV_SYNC_THRESHOLD_MIN 0.04
83 #define AV_SYNC_THRESHOLD_MAX 0.1
85 #define AV_SYNC_FRAMEDUP_THRESHOLD 0.1
87 #define AV_NOSYNC_THRESHOLD 10.0
90 #define SAMPLE_CORRECTION_PERCENT_MAX 10
93 #define EXTERNAL_CLOCK_SPEED_MIN 0.900
94 #define EXTERNAL_CLOCK_SPEED_MAX 1.010
95 #define EXTERNAL_CLOCK_SPEED_STEP 0.001
98 #define AUDIO_DIFF_AVG_NB 20
101 #define REFRESH_RATE 0.01
105 #define SAMPLE_ARRAY_SIZE (8 * 65536)
107 #define CURSOR_HIDE_DELAY 1000000
109 #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))
352 static const char **vfilters_list =
NULL;
353 static int nb_vfilters = 0;
354 static char *afilters =
NULL;
366 #define FF_QUIT_EVENT (SDL_USEREVENT + 2)
400 static int opt_add_vfilter(
void *optctx,
const char *opt,
const char *
arg)
403 vfilters_list[nb_vfilters - 1] =
arg;
413 if (channel_count1 == 1 && channel_count2 == 1)
416 return channel_count1 != channel_count2 || fmt1 != fmt2;
423 return channel_layout;
453 SDL_CondSignal(q->
cond);
461 SDL_LockMutex(q->
mutex);
463 SDL_UnlockMutex(q->
mutex);
485 q->
mutex = SDL_CreateMutex();
490 q->
cond = SDL_CreateCond();
503 SDL_LockMutex(q->
mutex);
514 SDL_UnlockMutex(q->
mutex);
520 SDL_DestroyMutex(q->
mutex);
521 SDL_DestroyCond(q->
cond);
526 SDL_LockMutex(q->
mutex);
530 SDL_CondSignal(q->
cond);
532 SDL_UnlockMutex(q->
mutex);
537 SDL_LockMutex(q->
mutex);
540 SDL_UnlockMutex(q->
mutex);
549 SDL_LockMutex(q->
mutex);
578 SDL_UnlockMutex(q->
mutex);
673 av_log(d->
avctx,
AV_LOG_ERROR,
"Receive_frame and send_packet both returned EAGAIN, which is an API violation.\n");
698 if (!(
f->mutex = SDL_CreateMutex())) {
702 if (!(
f->cond = SDL_CreateCond())) {
708 f->keep_last = !!keep_last;
709 for (
i = 0;
i <
f->max_size;
i++)
718 for (
i = 0;
i <
f->max_size;
i++) {
723 SDL_DestroyMutex(
f->mutex);
724 SDL_DestroyCond(
f->cond);
729 SDL_LockMutex(
f->mutex);
730 SDL_CondSignal(
f->cond);
731 SDL_UnlockMutex(
f->mutex);
736 return &
f->queue[(
f->rindex +
f->rindex_shown) %
f->max_size];
741 return &
f->queue[(
f->rindex +
f->rindex_shown + 1) %
f->max_size];
746 return &
f->queue[
f->rindex];
752 SDL_LockMutex(
f->mutex);
753 while (
f->size >=
f->max_size &&
754 !
f->pktq->abort_request) {
755 SDL_CondWait(
f->cond,
f->mutex);
757 SDL_UnlockMutex(
f->mutex);
759 if (
f->pktq->abort_request)
762 return &
f->queue[
f->windex];
768 SDL_LockMutex(
f->mutex);
769 while (
f->size -
f->rindex_shown <= 0 &&
770 !
f->pktq->abort_request) {
771 SDL_CondWait(
f->cond,
f->mutex);
773 SDL_UnlockMutex(
f->mutex);
775 if (
f->pktq->abort_request)
778 return &
f->queue[(
f->rindex +
f->rindex_shown) %
f->max_size];
783 if (++
f->windex ==
f->max_size)
785 SDL_LockMutex(
f->mutex);
787 SDL_CondSignal(
f->cond);
788 SDL_UnlockMutex(
f->mutex);
793 if (
f->keep_last && !
f->rindex_shown) {
798 if (++
f->rindex ==
f->max_size)
800 SDL_LockMutex(
f->mutex);
802 SDL_CondSignal(
f->cond);
803 SDL_UnlockMutex(
f->mutex);
809 return f->size -
f->rindex_shown;
816 if (
f->rindex_shown &&
fp->serial ==
f->pktq->serial)
842 static int realloc_texture(SDL_Texture **texture, Uint32 new_format,
int new_width,
int new_height, SDL_BlendMode blendmode,
int init_texture)
846 if (!*texture || SDL_QueryTexture(*texture, &
format, &access, &
w, &
h) < 0 || new_width !=
w || new_height !=
h || new_format !=
format) {
850 SDL_DestroyTexture(*texture);
851 if (!(*texture = SDL_CreateTexture(
renderer, new_format, SDL_TEXTUREACCESS_STREAMING, new_width, new_height)))
853 if (SDL_SetTextureBlendMode(*texture, blendmode) < 0)
856 if (SDL_LockTexture(*texture,
NULL, &pixels, &pitch) < 0)
858 memset(pixels, 0, pitch * new_height);
859 SDL_UnlockTexture(*texture);
861 av_log(
NULL,
AV_LOG_VERBOSE,
"Created %dx%d texture with %s.\n", new_width, new_height, SDL_GetPixelFormatName(new_format));
867 int scr_xleft,
int scr_ytop,
int scr_width,
int scr_height,
868 int pic_width,
int pic_height,
AVRational pic_sar)
881 if (
width > scr_width) {
885 x = (scr_width -
width) / 2;
886 y = (scr_height -
height) / 2;
887 rect->
x = scr_xleft + x;
888 rect->
y = scr_ytop + y;
896 *sdl_blendmode = SDL_BLENDMODE_NONE;
897 *sdl_pix_fmt = SDL_PIXELFORMAT_UNKNOWN;
902 *sdl_blendmode = SDL_BLENDMODE_BLEND;
914 SDL_BlendMode sdl_blendmode;
916 if (
realloc_texture(tex, sdl_pix_fmt == SDL_PIXELFORMAT_UNKNOWN ? SDL_PIXELFORMAT_ARGB8888 : sdl_pix_fmt,
frame->width,
frame->height, sdl_blendmode, 0) < 0)
918 switch (sdl_pix_fmt) {
919 case SDL_PIXELFORMAT_UNKNOWN:
924 if (*img_convert_ctx !=
NULL) {
927 if (!SDL_LockTexture(*tex,
NULL, (
void **)pixels, pitch)) {
929 0,
frame->height, pixels, pitch);
930 SDL_UnlockTexture(*tex);
937 case SDL_PIXELFORMAT_IYUV:
938 if (
frame->linesize[0] > 0 &&
frame->linesize[1] > 0 &&
frame->linesize[2] > 0) {
942 }
else if (
frame->linesize[0] < 0 &&
frame->linesize[1] < 0 &&
frame->linesize[2] < 0) {
952 if (
frame->linesize[0] < 0) {
964 #if SDL_VERSION_ATLEAST(2,0,8)
965 SDL_YUV_CONVERSION_MODE
mode = SDL_YUV_CONVERSION_AUTOMATIC;
968 mode = SDL_YUV_CONVERSION_JPEG;
970 mode = SDL_YUV_CONVERSION_BT709;
972 mode = SDL_YUV_CONVERSION_BT601;
974 SDL_SetYUVConversionMode(
mode);
985 if (
is->subtitle_st) {
989 if (vp->
pts >=
sp->pts + ((
float)
sp->sub.start_display_time / 1000)) {
994 if (!
sp->width || !
sp->height) {
998 if (
realloc_texture(&
is->sub_texture, SDL_PIXELFORMAT_ARGB8888,
sp->width,
sp->height, SDL_BLENDMODE_BLEND, 1) < 0)
1001 for (
i = 0;
i <
sp->sub.num_rects;
i++) {
1004 sub_rect->
x = av_clip(sub_rect->
x, 0,
sp->width );
1005 sub_rect->
y = av_clip(sub_rect->
y, 0,
sp->height);
1006 sub_rect->
w = av_clip(sub_rect->
w, 0,
sp->width - sub_rect->
x);
1007 sub_rect->
h = av_clip(sub_rect->
h, 0,
sp->height - sub_rect->
y);
1013 if (!
is->sub_convert_ctx) {
1017 if (!SDL_LockTexture(
is->sub_texture, (SDL_Rect *)sub_rect, (
void **)pixels, pitch)) {
1018 sws_scale(
is->sub_convert_ctx, (
const uint8_t *
const *)sub_rect->data, sub_rect->linesize,
1019 0, sub_rect->h, pixels, pitch);
1020 SDL_UnlockTexture(
is->sub_texture);
1043 #if USE_ONEPASS_SUBTITLE_RENDER
1047 double xratio = (double)
rect.
w / (
double)
sp->width;
1048 double yratio = (double)
rect.
h / (
double)
sp->height;
1049 for (
i = 0;
i <
sp->sub.num_rects;
i++) {
1050 SDL_Rect *sub_rect = (SDL_Rect*)
sp->sub.rects[
i];
1051 SDL_Rect target = {.x =
rect.
x + sub_rect->x * xratio,
1052 .y =
rect.
y + sub_rect->y * yratio,
1053 .w = sub_rect->w * xratio,
1054 .h = sub_rect->h * yratio};
1055 SDL_RenderCopy(
renderer,
is->sub_texture, sub_rect, &target);
1063 return a < 0 ?
a%
b +
b :
a%
b;
1068 int i, i_start, x, y1, y, ys, delay, n, nb_display_channels;
1071 int rdft_bits, nb_freq;
1073 for (rdft_bits = 1; (1 << rdft_bits) < 2 *
s->height; rdft_bits++)
1075 nb_freq = 1 << (rdft_bits - 1);
1081 int data_used=
s->show_mode == SHOW_MODE_WAVES ?
s->width : (2*nb_freq);
1083 delay =
s->audio_write_buf_size;
1090 delay -= (time_diff *
s->audio_tgt.freq) / 1000000;
1093 delay += 2 * data_used;
1094 if (delay < data_used)
1098 if (
s->show_mode == SHOW_MODE_WAVES) {
1102 int a =
s->sample_array[idx];
1107 if (
h < score && (
b ^
c) < 0) {
1114 s->last_i_start = i_start;
1116 i_start =
s->last_i_start;
1119 if (
s->show_mode == SHOW_MODE_WAVES) {
1120 SDL_SetRenderDrawColor(
renderer, 255, 255, 255, 255);
1123 h =
s->height / nb_display_channels;
1126 for (ch = 0; ch < nb_display_channels; ch++) {
1128 y1 =
s->ytop + ch *
h + (
h / 2);
1129 for (x = 0; x <
s->width; x++) {
1130 y = (
s->sample_array[
i] * h2) >> 15;
1144 SDL_SetRenderDrawColor(
renderer, 0, 0, 255, 255);
1146 for (ch = 1; ch < nb_display_channels; ch++) {
1147 y =
s->ytop + ch *
h;
1151 if (
realloc_texture(&
s->vis_texture, SDL_PIXELFORMAT_ARGB8888,
s->width,
s->height, SDL_BLENDMODE_NONE, 1) < 0)
1154 if (
s->xpos >=
s->width)
1156 nb_display_channels=
FFMIN(nb_display_channels, 2);
1157 if (rdft_bits !=
s->rdft_bits) {
1161 s->rdft_bits = rdft_bits;
1164 if (!
s->rdft || !
s->rdft_data){
1166 s->show_mode = SHOW_MODE_WAVES;
1169 SDL_Rect
rect = {.
x =
s->xpos, .y = 0, .w = 1, .h =
s->height};
1172 for (ch = 0; ch < nb_display_channels; ch++) {
1173 data[ch] =
s->rdft_data + 2 * nb_freq * ch;
1175 for (x = 0; x < 2 * nb_freq; x++) {
1176 double w = (x-nb_freq) * (1.0 / nb_freq);
1177 data[ch][x] =
s->sample_array[
i] * (1.0 -
w *
w);
1186 if (!SDL_LockTexture(
s->vis_texture, &
rect, (
void **)&pixels, &pitch)) {
1188 pixels += pitch *
s->height;
1189 for (y = 0; y <
s->height; y++) {
1190 double w = 1 / sqrt(nb_freq);
1191 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]));
1192 int b = (nb_display_channels == 2 ) ? sqrt(
w *
hypot(
data[1][2 * y + 0],
data[1][2 * y + 1]))
1197 *pixels = (
a << 16) + (
b << 8) + ((
a+
b) >> 1);
1199 SDL_UnlockTexture(
s->vis_texture);
1213 if (stream_index < 0 || stream_index >= ic->
nb_streams)
1224 is->audio_buf1_size = 0;
1250 is->audio_stream = -1;
1254 is->video_stream = -1;
1258 is->subtitle_stream = -1;
1268 is->abort_request = 1;
1269 SDL_WaitThread(
is->read_tid,
NULL);
1272 if (
is->audio_stream >= 0)
1274 if (
is->video_stream >= 0)
1276 if (
is->subtitle_stream >= 0)
1289 SDL_DestroyCond(
is->continue_read_thread);
1293 if (
is->vis_texture)
1294 SDL_DestroyTexture(
is->vis_texture);
1295 if (
is->vid_texture)
1296 SDL_DestroyTexture(
is->vid_texture);
1297 if (
is->sub_texture)
1298 SDL_DestroyTexture(
is->sub_texture);
1310 SDL_DestroyWindow(
window);
1333 if (max_width == INT_MAX && max_height == INT_MAX)
1354 SDL_SetWindowFullscreen(
window, SDL_WINDOW_FULLSCREEN_DESKTOP);
1369 SDL_SetRenderDrawColor(
renderer, 0, 0, 0, 255);
1371 if (
is->audio_st &&
is->show_mode != SHOW_MODE_VIDEO)
1373 else if (
is->video_st)
1380 if (*
c->queue_serial !=
c->serial)
1386 return c->pts_drift + time - (time -
c->last_updated) * (1.0 -
c->speed);
1393 c->last_updated = time;
1394 c->pts_drift =
c->pts - time;
1414 c->queue_serial = queue_serial;
1469 double speed =
is->extclk.speed;
1478 if (!
is->seek_req) {
1485 SDL_CondSignal(
is->continue_read_thread);
1494 if (
is->read_pause_return !=
AVERROR(ENOSYS)) {
1495 is->vidclk.paused = 0;
1500 is->paused =
is->audclk.paused =
is->vidclk.paused =
is->extclk.paused = !
is->paused;
1511 is->muted = !
is->muted;
1516 double volume_level =
is->audio_volume ? (20 * log(
is->audio_volume / (
double)SDL_MIX_MAXVOLUME) / log(10)) : -1000.0;
1517 int new_volume =
lrint(SDL_MIX_MAXVOLUME * pow(10.0, (volume_level + sign *
step) / 20.0));
1518 is->audio_volume = av_clip(
is->audio_volume == new_volume ? (
is->audio_volume + sign) : new_volume, 0, SDL_MIX_MAXVOLUME);
1531 double sync_threshold,
diff = 0;
1544 if (
diff <= -sync_threshold)
1547 delay = delay +
diff;
1548 else if (
diff >= sync_threshold)
1562 if (
isnan(
duration) || duration <= 0 || duration >
is->max_frame_duration)
1590 if (
is->force_refresh ||
is->last_vis_time +
rdftspeed < time) {
1592 is->last_vis_time = time;
1594 *remaining_time =
FFMIN(*remaining_time,
is->last_vis_time +
rdftspeed - time);
1602 double last_duration,
duration, delay;
1609 if (vp->
serial !=
is->videoq.serial) {
1625 if (time < is->frame_timer + delay) {
1626 *remaining_time =
FFMIN(
is->frame_timer + delay - time, *remaining_time);
1630 is->frame_timer += delay;
1632 is->frame_timer = time;
1634 SDL_LockMutex(
is->pictq.mutex);
1637 SDL_UnlockMutex(
is->pictq.mutex);
1643 is->frame_drops_late++;
1649 if (
is->subtitle_st) {
1658 if (
sp->serial !=
is->subtitleq.serial
1659 || (
is->vidclk.pts > (
sp->pts + ((
float)
sp->sub.end_display_time / 1000)))
1664 for (
i = 0;
i <
sp->sub.num_rects;
i++) {
1669 if (!SDL_LockTexture(
is->sub_texture, (SDL_Rect *)sub_rect, (
void **)&pixels, &pitch)) {
1670 for (j = 0; j < sub_rect->h; j++, pixels += pitch)
1671 memset(pixels, 0, sub_rect->w << 2);
1672 SDL_UnlockTexture(
is->sub_texture);
1684 is->force_refresh = 1;
1686 if (
is->step && !
is->paused)
1691 if (!
display_disable &&
is->force_refresh &&
is->show_mode == SHOW_MODE_VIDEO &&
is->pictq.rindex_shown)
1694 is->force_refresh = 0;
1697 static int64_t last_time;
1699 int aqsize, vqsize, sqsize;
1703 if (!last_time || (cur_time - last_time) >= 30000) {
1708 aqsize =
is->audioq.size;
1710 vqsize =
is->videoq.size;
1711 if (
is->subtitle_st)
1712 sqsize =
is->subtitleq.size;
1714 if (
is->audio_st &&
is->video_st)
1716 else if (
is->video_st)
1718 else if (
is->audio_st)
1723 "%7.2f %s:%7.3f fd=%4d aq=%5dKB vq=%5dKB sq=%5dB f=%"PRId64
"/%"PRId64
" \r",
1725 (
is->audio_st &&
is->video_st) ?
"A-V" : (
is->video_st ?
"M-V" : (
is->audio_st ?
"M-A" :
" ")),
1727 is->frame_drops_early +
is->frame_drops_late,
1731 is->video_st ?
is->viddec.avctx->pts_correction_num_faulty_dts : 0,
1732 is->video_st ?
is->viddec.avctx->pts_correction_num_faulty_pts : 0);
1735 fprintf(stderr,
"%s", buf.str);
1742 last_time = cur_time;
1751 #if defined(DEBUG_SYNC)
1752 printf(
"frame_type=%c pts=%0.3f\n",
1797 diff -
is->frame_last_filter_delay < 0 &&
1798 is->viddec.pkt_serial ==
is->vidclk.serial &&
1799 is->videoq.nb_packets) {
1800 is->frame_drops_early++;
1828 outputs->filter_ctx = source_ctx;
1833 inputs->filter_ctx = sink_ctx;
1858 char sws_flags_str[512] =
"";
1859 char buffersrc_args[256];
1865 int nb_pix_fmts = 0;
1879 if (!strcmp(e->
key,
"sws_flags")) {
1880 av_strlcatf(sws_flags_str,
sizeof(sws_flags_str),
"%s=%s:",
"flags", e->
value);
1884 if (strlen(sws_flags_str))
1885 sws_flags_str[strlen(sws_flags_str)-1] =
'\0';
1889 snprintf(buffersrc_args,
sizeof(buffersrc_args),
1890 "video_size=%dx%d:pix_fmt=%d:time_base=%d/%d:pixel_aspect=%d/%d",
1892 is->video_st->time_base.num,
is->video_st->time_base.den,
1895 av_strlcatf(buffersrc_args,
sizeof(buffersrc_args),
":frame_rate=%d/%d", fr.
num, fr.
den);
1899 "ffplay_buffer", buffersrc_args,
NULL,
1905 "ffplay_buffersink",
NULL,
NULL, graph);
1912 last_filter = filt_out;
1916 #define INSERT_FILT(name, arg) do { \
1917 AVFilterContext *filt_ctx; \
1919 ret = avfilter_graph_create_filter(&filt_ctx, \
1920 avfilter_get_by_name(name), \
1921 "ffplay_" name, arg, NULL, graph); \
1925 ret = avfilter_link(filt_ctx, 0, last_filter, 0); \
1929 last_filter = filt_ctx; \
1935 if (fabs(theta - 90) < 1.0) {
1936 INSERT_FILT(
"transpose",
"clock");
1937 }
else if (fabs(theta - 180) < 1.0) {
1938 INSERT_FILT(
"hflip",
NULL);
1939 INSERT_FILT(
"vflip",
NULL);
1940 }
else if (fabs(theta - 270) < 1.0) {
1941 INSERT_FILT(
"transpose",
"cclock");
1942 }
else if (fabs(theta) > 1.0) {
1943 char rotate_buf[64];
1944 snprintf(rotate_buf,
sizeof(rotate_buf),
"%f*PI/180", theta);
1945 INSERT_FILT(
"rotate", rotate_buf);
1952 is->in_video_filter = filt_src;
1953 is->out_video_filter = filt_out;
1959 static int configure_audio_filters(
VideoState *
is,
const char *afilters,
int force_output_format)
1966 char aresample_swr_opts[512] =
"";
1968 char asrc_args[256];
1978 if (strlen(aresample_swr_opts))
1979 aresample_swr_opts[strlen(aresample_swr_opts)-1] =
'\0';
1980 av_opt_set(
is->agraph,
"aresample_swr_opts", aresample_swr_opts, 0);
1983 "sample_rate=%d:sample_fmt=%s:channels=%d:time_base=%d/%d",
1985 is->audio_filter_src.channels,
1986 1,
is->audio_filter_src.freq);
1987 if (
is->audio_filter_src.channel_layout)
1989 ":channel_layout=0x%"PRIx64,
is->audio_filter_src.channel_layout);
1993 asrc_args,
NULL,
is->agraph);
2009 if (force_output_format) {
2027 is->in_audio_filter = filt_asrc;
2028 is->out_audio_filter = filt_asink;
2043 int last_serial = -1;
2044 int64_t dec_channel_layout;
2067 is->audio_filter_src.channel_layout != dec_channel_layout ||
2068 is->audio_filter_src.freq !=
frame->sample_rate ||
2069 is->auddec.pkt_serial != last_serial;
2072 char buf1[1024], buf2[1024];
2076 "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",
2080 is->audio_filter_src.fmt =
frame->format;
2081 is->audio_filter_src.channels =
frame->channels;
2082 is->audio_filter_src.channel_layout = dec_channel_layout;
2083 is->audio_filter_src.freq =
frame->sample_rate;
2084 last_serial =
is->auddec.pkt_serial;
2086 if ((
ret = configure_audio_filters(
is, afilters, 1)) < 0)
2101 af->
serial =
is->auddec.pkt_serial;
2108 if (
is->audioq.serial !=
is->auddec.pkt_serial)
2112 is->auddec.finished =
is->auddec.pkt_serial;
2151 int last_serial = -1;
2152 int last_vfilter_idx = 0;
2166 if ( last_w !=
frame->width
2167 || last_h !=
frame->height
2168 || last_format !=
frame->format
2169 || last_serial !=
is->viddec.pkt_serial
2170 || last_vfilter_idx !=
is->vfilter_idx) {
2172 "Video frame changed from size:%dx%d format:%s serial:%d to size:%dx%d format:%s serial:%d\n",
2184 if ((
ret = configure_video_filters(graph,
is, vfilters_list ? vfilters_list[
is->vfilter_idx] :
NULL,
frame)) < 0) {
2187 event.user.data1 =
is;
2188 SDL_PushEvent(&event);
2191 filt_in =
is->in_video_filter;
2192 filt_out =
is->out_video_filter;
2193 last_w =
frame->width;
2194 last_h =
frame->height;
2195 last_format =
frame->format;
2196 last_serial =
is->viddec.pkt_serial;
2197 last_vfilter_idx =
is->vfilter_idx;
2211 is->viddec.finished =
is->viddec.pkt_serial;
2218 is->frame_last_filter_delay = 0;
2226 if (
is->videoq.serial !=
is->viddec.pkt_serial)
2258 if (got_subtitle &&
sp->sub.format == 0) {
2262 sp->serial =
is->subdec.pkt_serial;
2263 sp->width =
is->subdec.avctx->width;
2264 sp->height =
is->subdec.avctx->height;
2269 }
else if (got_subtitle) {
2286 memcpy(
is->sample_array +
is->sample_array_index,
samples,
len *
sizeof(
short));
2288 is->sample_array_index +=
len;
2290 is->sample_array_index = 0;
2299 int wanted_nb_samples = nb_samples;
2303 double diff, avg_diff;
2304 int min_nb_samples, max_nb_samples;
2309 is->audio_diff_cum =
diff +
is->audio_diff_avg_coef *
is->audio_diff_cum;
2312 is->audio_diff_avg_count++;
2315 avg_diff =
is->audio_diff_cum * (1.0 -
is->audio_diff_avg_coef);
2317 if (fabs(avg_diff) >=
is->audio_diff_threshold) {
2318 wanted_nb_samples = nb_samples + (
int)(
diff *
is->audio_src.freq);
2321 wanted_nb_samples = av_clip(wanted_nb_samples, min_nb_samples, max_nb_samples);
2324 diff, avg_diff, wanted_nb_samples - nb_samples,
2325 is->audio_clock,
is->audio_diff_threshold);
2330 is->audio_diff_avg_count = 0;
2331 is->audio_diff_cum = 0;
2335 return wanted_nb_samples;
2347 int data_size, resampled_data_size;
2348 int64_t dec_channel_layout;
2350 int wanted_nb_samples;
2367 }
while (af->
serial !=
is->audioq.serial);
2373 dec_channel_layout =
2379 dec_channel_layout !=
is->audio_src.channel_layout ||
2384 is->audio_tgt.channel_layout,
is->audio_tgt.fmt,
is->audio_tgt.freq,
2389 "Cannot create sample rate converter for conversion of %d Hz %s %d channels to %d Hz %s %d channels!\n",
2395 is->audio_src.channel_layout = dec_channel_layout;
2404 int out_count = (int64_t)wanted_nb_samples *
is->audio_tgt.freq / af->
frame->
sample_rate + 256;
2419 if (!
is->audio_buf1)
2426 if (len2 == out_count) {
2431 is->audio_buf =
is->audio_buf1;
2435 resampled_data_size = data_size;
2438 audio_clock0 =
is->audio_clock;
2443 is->audio_clock =
NAN;
2444 is->audio_clock_serial = af->
serial;
2447 static double last_clock;
2448 printf(
"audio: delay=%0.3f clock=%0.3f clock0=%0.3f\n",
2449 is->audio_clock - last_clock,
2450 is->audio_clock, audio_clock0);
2451 last_clock =
is->audio_clock;
2454 return resampled_data_size;
2461 int audio_size, len1;
2466 if (
is->audio_buf_index >=
is->audio_buf_size) {
2468 if (audio_size < 0) {
2473 if (
is->show_mode != SHOW_MODE_VIDEO)
2475 is->audio_buf_size = audio_size;
2477 is->audio_buf_index = 0;
2479 len1 =
is->audio_buf_size -
is->audio_buf_index;
2482 if (!
is->muted &&
is->audio_buf &&
is->audio_volume == SDL_MIX_MAXVOLUME)
2483 memcpy(stream, (
uint8_t *)
is->audio_buf +
is->audio_buf_index, len1);
2485 memset(stream, 0, len1);
2486 if (!
is->muted &&
is->audio_buf)
2487 SDL_MixAudioFormat(stream, (
uint8_t *)
is->audio_buf +
is->audio_buf_index, AUDIO_S16SYS, len1,
is->audio_volume);
2491 is->audio_buf_index += len1;
2493 is->audio_write_buf_size =
is->audio_buf_size -
is->audio_buf_index;
2495 if (!
isnan(
is->audio_clock)) {
2501 static int audio_open(
void *opaque, int64_t wanted_channel_layout,
int wanted_nb_channels,
int wanted_sample_rate,
struct AudioParams *audio_hw_params)
2503 SDL_AudioSpec wanted_spec, spec;
2505 static const int next_nb_channels[] = {0, 0, 1, 6, 2, 6, 4, 6};
2506 static const int next_sample_rates[] = {0, 44100, 48000, 96000, 192000};
2507 int next_sample_rate_idx =
FF_ARRAY_ELEMS(next_sample_rates) - 1;
2509 env = SDL_getenv(
"SDL_AUDIO_CHANNELS");
2511 wanted_nb_channels = atoi(env);
2519 wanted_spec.channels = wanted_nb_channels;
2520 wanted_spec.freq = wanted_sample_rate;
2521 if (wanted_spec.freq <= 0 || wanted_spec.channels <= 0) {
2525 while (next_sample_rate_idx && next_sample_rates[next_sample_rate_idx] >= wanted_spec.freq)
2526 next_sample_rate_idx--;
2527 wanted_spec.format = AUDIO_S16SYS;
2528 wanted_spec.silence = 0;
2531 wanted_spec.userdata = opaque;
2532 while (!(
audio_dev = SDL_OpenAudioDevice(
NULL, 0, &wanted_spec, &spec, SDL_AUDIO_ALLOW_FREQUENCY_CHANGE | SDL_AUDIO_ALLOW_CHANNELS_CHANGE))) {
2534 wanted_spec.channels, wanted_spec.freq, SDL_GetError());
2535 wanted_spec.channels = next_nb_channels[
FFMIN(7, wanted_spec.channels)];
2536 if (!wanted_spec.channels) {
2537 wanted_spec.freq = next_sample_rates[next_sample_rate_idx--];
2538 wanted_spec.channels = wanted_nb_channels;
2539 if (!wanted_spec.freq) {
2541 "No more combinations to try, audio open failed\n");
2547 if (spec.format != AUDIO_S16SYS) {
2549 "SDL advised audio format %d is not supported!\n", spec.format);
2552 if (spec.channels != wanted_spec.channels) {
2554 if (!wanted_channel_layout) {
2556 "SDL advised channel count %d is not supported!\n", spec.channels);
2562 audio_hw_params->
freq = spec.freq;
2564 audio_hw_params->
channels = spec.channels;
2580 const char *forced_codec_name =
NULL;
2584 int64_t channel_layout;
2586 int stream_lowres =
lowres;
2588 if (stream_index < 0 || stream_index >= ic->
nb_streams)
2607 if (forced_codec_name)
2611 "No codec could be found with name '%s'\n", forced_codec_name);
2624 avctx->
lowres = stream_lowres;
2654 is->audio_filter_src.channels = avctx->
channels;
2657 if ((
ret = configure_audio_filters(
is, afilters, 0)) < 0)
2659 sink =
is->out_audio_filter;
2673 is->audio_hw_buf_size =
ret;
2674 is->audio_src =
is->audio_tgt;
2675 is->audio_buf_size = 0;
2676 is->audio_buf_index = 0;
2680 is->audio_diff_avg_count = 0;
2683 is->audio_diff_threshold = (double)(
is->audio_hw_buf_size) /
is->audio_tgt.bytes_per_sec;
2685 is->audio_stream = stream_index;
2686 is->audio_st = ic->
streams[stream_index];
2690 is->auddec.start_pts =
is->audio_st->start_time;
2691 is->auddec.start_pts_tb =
is->audio_st->time_base;
2698 is->video_stream = stream_index;
2699 is->video_st = ic->
streams[stream_index];
2704 is->queue_attachments_req = 1;
2707 is->subtitle_stream = stream_index;
2708 is->subtitle_st = ic->
streams[stream_index];
2730 return is->abort_request;
2734 return stream_id < 0 ||
2742 if( !strcmp(
s->iformat->name,
"rtp")
2743 || !strcmp(
s->iformat->name,
"rtsp")
2744 || !strcmp(
s->iformat->name,
"sdp")
2748 if(
s->pb && ( !strncmp(
s->url,
"rtp:", 4)
2749 || !strncmp(
s->url,
"udp:", 4)
2764 int64_t stream_start_time;
2765 int pkt_in_play_range = 0;
2767 SDL_mutex *wait_mutex = SDL_CreateMutex();
2768 int scan_all_pmts_set = 0;
2777 memset(st_index, -1,
sizeof(st_index));
2790 scan_all_pmts_set = 1;
2798 if (scan_all_pmts_set)
2819 for (
i = 0;
i < orig_nb_streams;
i++)
2825 "%s: could not find codec parameters\n",
is->filename);
2873 st_index[
i] = INT_MAX;
2901 if (codecpar->
width)
2914 if (
is->show_mode == SHOW_MODE_NONE)
2915 is->show_mode =
ret >= 0 ? SHOW_MODE_VIDEO : SHOW_MODE_RDFT;
2921 if (
is->video_stream < 0 &&
is->audio_stream < 0) {
2928 if (infinite_buffer < 0 && is->realtime)
2932 if (
is->abort_request)
2934 if (
is->paused !=
is->last_paused) {
2935 is->last_paused =
is->paused;
2941 #if CONFIG_RTSP_DEMUXER || CONFIG_MMSH_PROTOCOL
2952 int64_t seek_target =
is->seek_pos;
2953 int64_t seek_min =
is->seek_rel > 0 ? seek_target -
is->seek_rel + 2: INT64_MIN;
2954 int64_t seek_max =
is->seek_rel < 0 ? seek_target -
is->seek_rel - 2: INT64_MAX;
2961 "%s: error while seeking\n",
is->ic->url);
2963 if (
is->audio_stream >= 0) {
2967 if (
is->subtitle_stream >= 0) {
2971 if (
is->video_stream >= 0) {
2982 is->queue_attachments_req = 1;
2987 if (
is->queue_attachments_req) {
2995 is->queue_attachments_req = 0;
3005 SDL_LockMutex(wait_mutex);
3006 SDL_CondWaitTimeout(
is->continue_read_thread, wait_mutex, 10);
3007 SDL_UnlockMutex(wait_mutex);
3023 if (
is->video_stream >= 0)
3025 if (
is->audio_stream >= 0)
3027 if (
is->subtitle_stream >= 0)
3033 SDL_LockMutex(wait_mutex);
3034 SDL_CondWaitTimeout(
is->continue_read_thread, wait_mutex, 10);
3035 SDL_UnlockMutex(wait_mutex);
3044 (pkt_ts - (stream_start_time !=
AV_NOPTS_VALUE ? stream_start_time : 0)) *
3069 event.user.data1 =
is;
3070 SDL_PushEvent(&event);
3072 SDL_DestroyMutex(wait_mutex);
3083 is->last_video_stream =
is->video_stream = -1;
3084 is->last_audio_stream =
is->audio_stream = -1;
3085 is->last_subtitle_stream =
is->subtitle_stream = -1;
3106 if (!(
is->continue_read_thread = SDL_CreateCond())) {
3114 is->audio_clock_serial = -1;
3125 if (!
is->read_tid) {
3137 int start_index, stream_index;
3144 start_index =
is->last_video_stream;
3145 old_index =
is->video_stream;
3147 start_index =
is->last_audio_stream;
3148 old_index =
is->audio_stream;
3150 start_index =
is->last_subtitle_stream;
3151 old_index =
is->subtitle_stream;
3153 stream_index = start_index;
3159 for (start_index = 0; start_index <
nb_streams; start_index++)
3164 stream_index = start_index;
3174 is->last_subtitle_stream = -1;
3177 if (start_index == -1)
3181 if (stream_index == start_index)
3183 st =
is->ic->streams[p ? p->
stream_index[stream_index] : stream_index];
3201 if (p && stream_index != -1)
3221 int next =
is->show_mode;
3223 next = (next + 1) % SHOW_MODE_NB;
3224 }
while (next !=
is->show_mode && (next == SHOW_MODE_VIDEO && !
is->video_st || next != SHOW_MODE_VIDEO && !
is->audio_st));
3225 if (
is->show_mode != next) {
3226 is->force_refresh = 1;
3227 is->show_mode = next;
3232 double remaining_time = 0.0;
3234 while (!SDL_PeepEvents(event, 1, SDL_GETEVENT, SDL_FIRSTEVENT, SDL_LASTEVENT)) {
3239 if (remaining_time > 0.0)
3240 av_usleep((int64_t)(remaining_time * 1000000.0));
3242 if (
is->show_mode != SHOW_MODE_NONE && (!
is->paused ||
is->force_refresh))
3253 if (!
is->ic->nb_chapters)
3257 for (
i = 0;
i <
is->ic->nb_chapters;
i++) {
3267 if (
i >=
is->ic->nb_chapters)
3279 double incr,
pos, frac;
3284 switch (event.type) {
3286 if (
exit_on_keydown || event.key.keysym.sym == SDLK_ESCAPE || event.key.keysym.sym == SDLK_q) {
3291 if (!cur_stream->
width)
3293 switch (event.key.keysym.sym) {
3305 case SDLK_KP_MULTIPLY:
3309 case SDLK_KP_DIVIDE:
3332 if (cur_stream->
show_mode == SHOW_MODE_VIDEO && cur_stream->vfilter_idx < nb_vfilters - 1) {
3333 if (++cur_stream->vfilter_idx >= nb_vfilters)
3334 cur_stream->vfilter_idx = 0;
3336 cur_stream->vfilter_idx = 0;
3397 case SDL_MOUSEBUTTONDOWN:
3402 if (event.button.button == SDL_BUTTON_LEFT) {
3403 static int64_t last_mouse_left_click = 0;
3407 last_mouse_left_click = 0;
3412 case SDL_MOUSEMOTION:
3418 if (event.type == SDL_MOUSEBUTTONDOWN) {
3419 if (event.button.button != SDL_BUTTON_RIGHT)
3423 if (!(event.motion.state & SDL_BUTTON_RMASK))
3433 int tns, thh, tmm, tss;
3436 tmm = (tns % 3600) / 60;
3438 frac = x / cur_stream->
width;
3441 mm = (
ns % 3600) / 60;
3444 "Seek to %2.0f%% (%2d:%02d:%02d) of total duration (%2d:%02d:%02d) \n", frac*100,
3445 hh, mm,
ss, thh, tmm, tss);
3452 case SDL_WINDOWEVENT:
3453 switch (event.window.event) {
3454 case SDL_WINDOWEVENT_SIZE_CHANGED:
3461 case SDL_WINDOWEVENT_EXPOSED:
3511 if (!strcmp(
arg,
"audio"))
3513 else if (!strcmp(
arg,
"video"))
3515 else if (!strcmp(
arg,
"ext"))
3539 !strcmp(
arg,
"waves") ? SHOW_MODE_WAVES :
3540 !strcmp(
arg,
"rdft" ) ? SHOW_MODE_RDFT :
3549 "Argument '%s' provided as input filename, but '%s' was already specified.\n",
3553 if (!strcmp(filename,
"-"))
3560 const char *spec = strchr(opt,
':');
3563 "No media specifier was specified in '%s' in option '%s'\n",
3574 "Invalid media specifier '%s' in option '%s'\n", spec, opt);
3584 {
"x",
HAS_ARG, { .func_arg =
opt_width },
"force displayed width",
"width" },
3585 {
"y",
HAS_ARG, { .func_arg =
opt_height },
"force displayed height",
"height" },
3594 {
"ss",
HAS_ARG, { .func_arg =
opt_seek },
"seek to a given position in seconds",
"pos" },
3595 {
"t",
HAS_ARG, { .func_arg =
opt_duration },
"play \"duration\" seconds of audio/video",
"duration" },
3609 {
"sync",
HAS_ARG |
OPT_EXPERT, { .func_arg =
opt_sync },
"set audio-video sync. type (type=audio/video/ext)",
"type" },
3620 {
"vf",
OPT_EXPERT |
HAS_ARG, { .func_arg = opt_add_vfilter },
"set video filters",
"filter_graph" },
3621 {
"af",
OPT_STRING |
HAS_ARG, { &afilters },
"set audio filters",
"filter_graph" },
3624 {
"showmode",
HAS_ARG, { .func_arg =
opt_show_mode},
"select show mode (0 = video, 1 = waves, 2 = RDFT)",
"mode" },
3626 {
"i",
OPT_BOOL, { &
dummy},
"read specified file",
"input_file"},
3627 {
"codec",
HAS_ARG, { .func_arg =
opt_codec},
"force decoder",
"decoder_name" },
3633 "read and decode the streams to fill missing information with heuristics" },
3654 #if !CONFIG_AVFILTER
3659 printf(
"\nWhile playing:\n"
3661 "f toggle full screen\n"
3664 "9, 0 decrease and increase volume respectively\n"
3665 "/, * decrease and increase volume respectively\n"
3666 "a cycle audio channel in the current program\n"
3667 "v cycle video channel\n"
3668 "t cycle subtitle channel in the current program\n"
3670 "w cycle video filters or show modes\n"
3671 "s activate frame-step mode\n"
3672 "left/right seek backward/forward 10 seconds or to custom interval if -seek_interval is set\n"
3673 "down/up seek backward/forward 1 minute\n"
3674 "page down/page up seek backward/forward 10 minutes\n"
3675 "right mouse click seek to percentage in file corresponding to fraction of width\n"
3676 "left double-click toggle full screen\n"
3710 "Use -h to get full help or, even better, run 'man %s'\n",
program_name);
3717 flags = SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER;
3719 flags &= ~SDL_INIT_AUDIO;
3723 if (!SDL_getenv(
"SDL_AUDIO_ALSA_SET_BUFFER_SIZE"))
3724 SDL_setenv(
"SDL_AUDIO_ALSA_SET_BUFFER_SIZE",
"1", 1);
3727 flags &= ~SDL_INIT_VIDEO;
3728 if (SDL_Init (
flags)) {
3734 SDL_EventState(SDL_SYSWMEVENT, SDL_IGNORE);
3735 SDL_EventState(SDL_USEREVENT, SDL_IGNORE);
3741 int flags = SDL_WINDOW_HIDDEN;
3743 #if SDL_VERSION_ATLEAST(2,0,5)
3744 flags |= SDL_WINDOW_ALWAYS_ON_TOP;
3746 av_log(
NULL,
AV_LOG_WARNING,
"Your SDL version doesn't support SDL_WINDOW_ALWAYS_ON_TOP. Feature will be inactive.\n");
3749 flags |= SDL_WINDOW_BORDERLESS;
3751 flags |= SDL_WINDOW_RESIZABLE;
3753 SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY,
"linear");
3755 renderer = SDL_CreateRenderer(
window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);