59 #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))
352 static const char **vfilters_list =
NULL;
353 static int nb_vfilters = 0;
354 static char *afilters =
NULL;
364 #define FF_QUIT_EVENT (SDL_USEREVENT + 2)
398 static int opt_add_vfilter(
void *optctx,
const char *opt,
const char *
arg)
401 vfilters_list[nb_vfilters - 1] =
arg;
411 if (channel_count1 == 1 && channel_count2 == 1)
414 return channel_count1 != channel_count2 || fmt1 != fmt2;
421 return channel_layout;
446 SDL_CondSignal(q->
cond);
462 SDL_LockMutex(q->
mutex);
464 SDL_UnlockMutex(q->
mutex);
485 q->
mutex = SDL_CreateMutex();
490 q->
cond = SDL_CreateCond();
503 SDL_LockMutex(q->
mutex);
512 SDL_UnlockMutex(q->
mutex);
519 SDL_DestroyMutex(q->
mutex);
520 SDL_DestroyCond(q->
cond);
525 SDL_LockMutex(q->
mutex);
529 SDL_CondSignal(q->
cond);
531 SDL_UnlockMutex(q->
mutex);
536 SDL_LockMutex(q->
mutex);
539 SDL_UnlockMutex(q->
mutex);
548 SDL_LockMutex(q->
mutex);
574 SDL_UnlockMutex(q->
mutex);
663 if (got_frame && !d->
pkt->
data) {
671 av_log(d->
avctx,
AV_LOG_ERROR,
"Receive_frame and send_packet both returned EAGAIN, which is an API violation.\n");
695 if (!(
f->mutex = SDL_CreateMutex())) {
699 if (!(
f->cond = SDL_CreateCond())) {
705 f->keep_last = !!keep_last;
706 for (
i = 0;
i <
f->max_size;
i++)
715 for (
i = 0;
i <
f->max_size;
i++) {
720 SDL_DestroyMutex(
f->mutex);
721 SDL_DestroyCond(
f->cond);
726 SDL_LockMutex(
f->mutex);
727 SDL_CondSignal(
f->cond);
728 SDL_UnlockMutex(
f->mutex);
733 return &
f->queue[(
f->rindex +
f->rindex_shown) %
f->max_size];
738 return &
f->queue[(
f->rindex +
f->rindex_shown + 1) %
f->max_size];
743 return &
f->queue[
f->rindex];
749 SDL_LockMutex(
f->mutex);
750 while (
f->size >=
f->max_size &&
751 !
f->pktq->abort_request) {
752 SDL_CondWait(
f->cond,
f->mutex);
754 SDL_UnlockMutex(
f->mutex);
756 if (
f->pktq->abort_request)
759 return &
f->queue[
f->windex];
765 SDL_LockMutex(
f->mutex);
766 while (
f->size -
f->rindex_shown <= 0 &&
767 !
f->pktq->abort_request) {
768 SDL_CondWait(
f->cond,
f->mutex);
770 SDL_UnlockMutex(
f->mutex);
772 if (
f->pktq->abort_request)
775 return &
f->queue[(
f->rindex +
f->rindex_shown) %
f->max_size];
780 if (++
f->windex ==
f->max_size)
782 SDL_LockMutex(
f->mutex);
784 SDL_CondSignal(
f->cond);
785 SDL_UnlockMutex(
f->mutex);
790 if (
f->keep_last && !
f->rindex_shown) {
795 if (++
f->rindex ==
f->max_size)
797 SDL_LockMutex(
f->mutex);
799 SDL_CondSignal(
f->cond);
800 SDL_UnlockMutex(
f->mutex);
806 return f->size -
f->rindex_shown;
813 if (
f->rindex_shown &&
fp->serial ==
f->pktq->serial)
839 static int realloc_texture(SDL_Texture **texture, Uint32 new_format,
int new_width,
int new_height, SDL_BlendMode blendmode,
int init_texture)
843 if (!*texture || SDL_QueryTexture(*texture, &
format, &access, &
w, &
h) < 0 || new_width !=
w || new_height !=
h || new_format !=
format) {
847 SDL_DestroyTexture(*texture);
848 if (!(*texture = SDL_CreateTexture(
renderer, new_format, SDL_TEXTUREACCESS_STREAMING, new_width, new_height)))
850 if (SDL_SetTextureBlendMode(*texture, blendmode) < 0)
853 if (SDL_LockTexture(*texture,
NULL, &pixels, &pitch) < 0)
855 memset(pixels, 0, pitch * new_height);
856 SDL_UnlockTexture(*texture);
858 av_log(
NULL,
AV_LOG_VERBOSE,
"Created %dx%d texture with %s.\n", new_width, new_height, SDL_GetPixelFormatName(new_format));
864 int scr_xleft,
int scr_ytop,
int scr_width,
int scr_height,
865 int pic_width,
int pic_height,
AVRational pic_sar)
878 if (
width > scr_width) {
882 x = (scr_width -
width) / 2;
883 y = (scr_height -
height) / 2;
884 rect->
x = scr_xleft + x;
885 rect->
y = scr_ytop + y;
893 *sdl_blendmode = SDL_BLENDMODE_NONE;
894 *sdl_pix_fmt = SDL_PIXELFORMAT_UNKNOWN;
899 *sdl_blendmode = SDL_BLENDMODE_BLEND;
911 SDL_BlendMode sdl_blendmode;
913 if (
realloc_texture(tex, sdl_pix_fmt == SDL_PIXELFORMAT_UNKNOWN ? SDL_PIXELFORMAT_ARGB8888 : sdl_pix_fmt,
frame->width,
frame->height, sdl_blendmode, 0) < 0)
915 switch (sdl_pix_fmt) {
916 case SDL_PIXELFORMAT_UNKNOWN:
921 if (*img_convert_ctx !=
NULL) {
924 if (!SDL_LockTexture(*tex,
NULL, (
void **)pixels, pitch)) {
926 0,
frame->height, pixels, pitch);
927 SDL_UnlockTexture(*tex);
934 case SDL_PIXELFORMAT_IYUV:
935 if (
frame->linesize[0] > 0 &&
frame->linesize[1] > 0 &&
frame->linesize[2] > 0) {
939 }
else if (
frame->linesize[0] < 0 &&
frame->linesize[1] < 0 &&
frame->linesize[2] < 0) {
949 if (
frame->linesize[0] < 0) {
961 #if SDL_VERSION_ATLEAST(2,0,8)
962 SDL_YUV_CONVERSION_MODE
mode = SDL_YUV_CONVERSION_AUTOMATIC;
965 mode = SDL_YUV_CONVERSION_JPEG;
967 mode = SDL_YUV_CONVERSION_BT709;
969 mode = SDL_YUV_CONVERSION_BT601;
971 SDL_SetYUVConversionMode(
mode);
982 if (
is->subtitle_st) {
986 if (vp->
pts >=
sp->pts + ((
float)
sp->sub.start_display_time / 1000)) {
991 if (!
sp->width || !
sp->height) {
995 if (
realloc_texture(&
is->sub_texture, SDL_PIXELFORMAT_ARGB8888,
sp->width,
sp->height, SDL_BLENDMODE_BLEND, 1) < 0)
998 for (
i = 0;
i <
sp->sub.num_rects;
i++) {
1001 sub_rect->
x =
av_clip(sub_rect->
x, 0,
sp->width );
1002 sub_rect->
y =
av_clip(sub_rect->
y, 0,
sp->height);
1003 sub_rect->
w =
av_clip(sub_rect->
w, 0,
sp->width - sub_rect->
x);
1004 sub_rect->
h =
av_clip(sub_rect->
h, 0,
sp->height - sub_rect->
y);
1010 if (!
is->sub_convert_ctx) {
1014 if (!SDL_LockTexture(
is->sub_texture, (SDL_Rect *)sub_rect, (
void **)pixels, pitch)) {
1015 sws_scale(
is->sub_convert_ctx, (
const uint8_t *
const *)sub_rect->data, sub_rect->linesize,
1016 0, sub_rect->h, pixels, pitch);
1017 SDL_UnlockTexture(
is->sub_texture);
1040 #if USE_ONEPASS_SUBTITLE_RENDER
1044 double xratio = (double)
rect.
w / (
double)
sp->width;
1045 double yratio = (double)
rect.
h / (
double)
sp->height;
1046 for (
i = 0;
i <
sp->sub.num_rects;
i++) {
1047 SDL_Rect *sub_rect = (SDL_Rect*)
sp->sub.rects[
i];
1048 SDL_Rect target = {.x =
rect.
x + sub_rect->x * xratio,
1049 .y =
rect.
y + sub_rect->y * yratio,
1050 .w = sub_rect->w * xratio,
1051 .h = sub_rect->h * yratio};
1052 SDL_RenderCopy(
renderer,
is->sub_texture, sub_rect, &target);
1060 return a < 0 ?
a%
b +
b :
a%
b;
1065 int i, i_start, x, y1, y, ys, delay, n, nb_display_channels;
1068 int rdft_bits, nb_freq;
1070 for (rdft_bits = 1; (1 << rdft_bits) < 2 *
s->height; rdft_bits++)
1072 nb_freq = 1 << (rdft_bits - 1);
1078 int data_used=
s->show_mode == SHOW_MODE_WAVES ?
s->width : (2*nb_freq);
1080 delay =
s->audio_write_buf_size;
1087 delay -= (time_diff *
s->audio_tgt.freq) / 1000000;
1090 delay += 2 * data_used;
1091 if (delay < data_used)
1095 if (
s->show_mode == SHOW_MODE_WAVES) {
1099 int a =
s->sample_array[idx];
1104 if (
h < score && (
b ^
c) < 0) {
1111 s->last_i_start = i_start;
1113 i_start =
s->last_i_start;
1116 if (
s->show_mode == SHOW_MODE_WAVES) {
1117 SDL_SetRenderDrawColor(
renderer, 255, 255, 255, 255);
1120 h =
s->height / nb_display_channels;
1123 for (ch = 0; ch < nb_display_channels; ch++) {
1125 y1 =
s->ytop + ch *
h + (
h / 2);
1126 for (x = 0; x <
s->width; x++) {
1127 y = (
s->sample_array[
i] * h2) >> 15;
1141 SDL_SetRenderDrawColor(
renderer, 0, 0, 255, 255);
1143 for (ch = 1; ch < nb_display_channels; ch++) {
1144 y =
s->ytop + ch *
h;
1148 if (
realloc_texture(&
s->vis_texture, SDL_PIXELFORMAT_ARGB8888,
s->width,
s->height, SDL_BLENDMODE_NONE, 1) < 0)
1151 if (
s->xpos >=
s->width)
1153 nb_display_channels=
FFMIN(nb_display_channels, 2);
1154 if (rdft_bits !=
s->rdft_bits) {
1158 s->rdft_bits = rdft_bits;
1161 if (!
s->rdft || !
s->rdft_data){
1163 s->show_mode = SHOW_MODE_WAVES;
1166 SDL_Rect
rect = {.
x =
s->xpos, .y = 0, .w = 1, .h =
s->height};
1169 for (ch = 0; ch < nb_display_channels; ch++) {
1170 data[ch] =
s->rdft_data + 2 * nb_freq * ch;
1172 for (x = 0; x < 2 * nb_freq; x++) {
1173 double w = (x-nb_freq) * (1.0 / nb_freq);
1174 data[ch][x] =
s->sample_array[
i] * (1.0 -
w *
w);
1183 if (!SDL_LockTexture(
s->vis_texture, &
rect, (
void **)&pixels, &pitch)) {
1185 pixels += pitch *
s->height;
1186 for (y = 0; y <
s->height; y++) {
1187 double w = 1 / sqrt(nb_freq);
1188 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]));
1189 int b = (nb_display_channels == 2 ) ? sqrt(
w *
hypot(
data[1][2 * y + 0],
data[1][2 * y + 1]))
1194 *pixels = (
a << 16) + (
b << 8) + ((
a+
b) >> 1);
1196 SDL_UnlockTexture(
s->vis_texture);
1210 if (stream_index < 0 || stream_index >= ic->
nb_streams)
1221 is->audio_buf1_size = 0;
1247 is->audio_stream = -1;
1251 is->video_stream = -1;
1255 is->subtitle_stream = -1;
1265 is->abort_request = 1;
1266 SDL_WaitThread(
is->read_tid,
NULL);
1269 if (
is->audio_stream >= 0)
1271 if (
is->video_stream >= 0)
1273 if (
is->subtitle_stream >= 0)
1286 SDL_DestroyCond(
is->continue_read_thread);
1290 if (
is->vis_texture)
1291 SDL_DestroyTexture(
is->vis_texture);
1292 if (
is->vid_texture)
1293 SDL_DestroyTexture(
is->vid_texture);
1294 if (
is->sub_texture)
1295 SDL_DestroyTexture(
is->sub_texture);
1307 SDL_DestroyWindow(
window);
1330 if (max_width == INT_MAX && max_height == INT_MAX)
1351 SDL_SetWindowFullscreen(
window, SDL_WINDOW_FULLSCREEN_DESKTOP);
1366 SDL_SetRenderDrawColor(
renderer, 0, 0, 0, 255);
1368 if (
is->audio_st &&
is->show_mode != SHOW_MODE_VIDEO)
1370 else if (
is->video_st)
1377 if (*
c->queue_serial !=
c->serial)
1383 return c->pts_drift + time - (time -
c->last_updated) * (1.0 -
c->speed);
1390 c->last_updated = time;
1391 c->pts_drift =
c->pts - time;
1411 c->queue_serial = queue_serial;
1466 double speed =
is->extclk.speed;
1475 if (!
is->seek_req) {
1482 SDL_CondSignal(
is->continue_read_thread);
1491 if (
is->read_pause_return !=
AVERROR(ENOSYS)) {
1492 is->vidclk.paused = 0;
1497 is->paused =
is->audclk.paused =
is->vidclk.paused =
is->extclk.paused = !
is->paused;
1508 is->muted = !
is->muted;
1513 double volume_level =
is->audio_volume ? (20 * log(
is->audio_volume / (
double)SDL_MIX_MAXVOLUME) / log(10)) : -1000.0;
1514 int new_volume =
lrint(SDL_MIX_MAXVOLUME * pow(10.0, (volume_level + sign *
step) / 20.0));
1515 is->audio_volume =
av_clip(
is->audio_volume == new_volume ? (
is->audio_volume + sign) : new_volume, 0, SDL_MIX_MAXVOLUME);
1528 double sync_threshold,
diff = 0;
1541 if (
diff <= -sync_threshold)
1544 delay = delay +
diff;
1545 else if (
diff >= sync_threshold)
1559 if (
isnan(
duration) || duration <= 0 || duration >
is->max_frame_duration)
1587 if (
is->force_refresh ||
is->last_vis_time +
rdftspeed < time) {
1589 is->last_vis_time = time;
1591 *remaining_time =
FFMIN(*remaining_time,
is->last_vis_time +
rdftspeed - time);
1599 double last_duration,
duration, delay;
1606 if (vp->
serial !=
is->videoq.serial) {
1622 if (time < is->frame_timer + delay) {
1623 *remaining_time =
FFMIN(
is->frame_timer + delay - time, *remaining_time);
1627 is->frame_timer += delay;
1629 is->frame_timer = time;
1631 SDL_LockMutex(
is->pictq.mutex);
1634 SDL_UnlockMutex(
is->pictq.mutex);
1640 is->frame_drops_late++;
1646 if (
is->subtitle_st) {
1655 if (
sp->serial !=
is->subtitleq.serial
1656 || (
is->vidclk.pts > (
sp->pts + ((
float)
sp->sub.end_display_time / 1000)))
1661 for (
i = 0;
i <
sp->sub.num_rects;
i++) {
1666 if (!SDL_LockTexture(
is->sub_texture, (SDL_Rect *)sub_rect, (
void **)&pixels, &pitch)) {
1667 for (j = 0; j < sub_rect->h; j++, pixels += pitch)
1668 memset(pixels, 0, sub_rect->w << 2);
1669 SDL_UnlockTexture(
is->sub_texture);
1681 is->force_refresh = 1;
1683 if (
is->step && !
is->paused)
1688 if (!
display_disable &&
is->force_refresh &&
is->show_mode == SHOW_MODE_VIDEO &&
is->pictq.rindex_shown)
1691 is->force_refresh = 0;
1694 static int64_t last_time;
1696 int aqsize, vqsize, sqsize;
1700 if (!last_time || (cur_time - last_time) >= 30000) {
1705 aqsize =
is->audioq.size;
1707 vqsize =
is->videoq.size;
1708 if (
is->subtitle_st)
1709 sqsize =
is->subtitleq.size;
1711 if (
is->audio_st &&
is->video_st)
1713 else if (
is->video_st)
1715 else if (
is->audio_st)
1720 "%7.2f %s:%7.3f fd=%4d aq=%5dKB vq=%5dKB sq=%5dB f=%"PRId64
"/%"PRId64
" \r",
1722 (
is->audio_st &&
is->video_st) ?
"A-V" : (
is->video_st ?
"M-V" : (
is->audio_st ?
"M-A" :
" ")),
1724 is->frame_drops_early +
is->frame_drops_late,
1728 is->video_st ?
is->viddec.avctx->pts_correction_num_faulty_dts : 0,
1729 is->video_st ?
is->viddec.avctx->pts_correction_num_faulty_pts : 0);
1732 fprintf(stderr,
"%s", buf.str);
1739 last_time = cur_time;
1748 #if defined(DEBUG_SYNC)
1749 printf(
"frame_type=%c pts=%0.3f\n",
1794 diff -
is->frame_last_filter_delay < 0 &&
1795 is->viddec.pkt_serial ==
is->vidclk.serial &&
1796 is->videoq.nb_packets) {
1797 is->frame_drops_early++;
1825 outputs->filter_ctx = source_ctx;
1830 inputs->filter_ctx = sink_ctx;
1855 char sws_flags_str[512] =
"";
1856 char buffersrc_args[256];
1862 int nb_pix_fmts = 0;
1876 if (!strcmp(e->
key,
"sws_flags")) {
1877 av_strlcatf(sws_flags_str,
sizeof(sws_flags_str),
"%s=%s:",
"flags", e->
value);
1881 if (strlen(sws_flags_str))
1882 sws_flags_str[strlen(sws_flags_str)-1] =
'\0';
1886 snprintf(buffersrc_args,
sizeof(buffersrc_args),
1887 "video_size=%dx%d:pix_fmt=%d:time_base=%d/%d:pixel_aspect=%d/%d",
1889 is->video_st->time_base.num,
is->video_st->time_base.den,
1892 av_strlcatf(buffersrc_args,
sizeof(buffersrc_args),
":frame_rate=%d/%d", fr.
num, fr.
den);
1896 "ffplay_buffer", buffersrc_args,
NULL,
1902 "ffplay_buffersink",
NULL,
NULL, graph);
1909 last_filter = filt_out;
1913 #define INSERT_FILT(name, arg) do { \
1914 AVFilterContext *filt_ctx; \
1916 ret = avfilter_graph_create_filter(&filt_ctx, \
1917 avfilter_get_by_name(name), \
1918 "ffplay_" name, arg, NULL, graph); \
1922 ret = avfilter_link(filt_ctx, 0, last_filter, 0); \
1926 last_filter = filt_ctx; \
1932 if (
fabs(theta - 90) < 1.0) {
1933 INSERT_FILT(
"transpose",
"clock");
1934 }
else if (
fabs(theta - 180) < 1.0) {
1935 INSERT_FILT(
"hflip",
NULL);
1936 INSERT_FILT(
"vflip",
NULL);
1937 }
else if (
fabs(theta - 270) < 1.0) {
1938 INSERT_FILT(
"transpose",
"cclock");
1939 }
else if (
fabs(theta) > 1.0) {
1940 char rotate_buf[64];
1941 snprintf(rotate_buf,
sizeof(rotate_buf),
"%f*PI/180", theta);
1942 INSERT_FILT(
"rotate", rotate_buf);
1949 is->in_video_filter = filt_src;
1950 is->out_video_filter = filt_out;
1956 static int configure_audio_filters(
VideoState *
is,
const char *afilters,
int force_output_format)
1963 char aresample_swr_opts[512] =
"";
1965 char asrc_args[256];
1975 if (strlen(aresample_swr_opts))
1976 aresample_swr_opts[strlen(aresample_swr_opts)-1] =
'\0';
1977 av_opt_set(
is->agraph,
"aresample_swr_opts", aresample_swr_opts, 0);
1980 "sample_rate=%d:sample_fmt=%s:channels=%d:time_base=%d/%d",
1982 is->audio_filter_src.channels,
1983 1,
is->audio_filter_src.freq);
1984 if (
is->audio_filter_src.channel_layout)
1986 ":channel_layout=0x%"PRIx64,
is->audio_filter_src.channel_layout);
1990 asrc_args,
NULL,
is->agraph);
2006 if (force_output_format) {
2008 channels [0] =
is->audio_tgt.channel_layout ? -1 :
is->audio_tgt.channels;
2024 is->in_audio_filter = filt_asrc;
2025 is->out_audio_filter = filt_asink;
2040 int last_serial = -1;
2041 int64_t dec_channel_layout;
2064 is->audio_filter_src.channel_layout != dec_channel_layout ||
2065 is->audio_filter_src.freq !=
frame->sample_rate ||
2066 is->auddec.pkt_serial != last_serial;
2069 char buf1[1024], buf2[1024];
2073 "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",
2077 is->audio_filter_src.fmt =
frame->format;
2078 is->audio_filter_src.channels =
frame->channels;
2079 is->audio_filter_src.channel_layout = dec_channel_layout;
2080 is->audio_filter_src.freq =
frame->sample_rate;
2081 last_serial =
is->auddec.pkt_serial;
2083 if ((
ret = configure_audio_filters(
is, afilters, 1)) < 0)
2098 af->
serial =
is->auddec.pkt_serial;
2105 if (
is->audioq.serial !=
is->auddec.pkt_serial)
2109 is->auddec.finished =
is->auddec.pkt_serial;
2148 int last_serial = -1;
2149 int last_vfilter_idx = 0;
2163 if ( last_w !=
frame->width
2164 || last_h !=
frame->height
2165 || last_format !=
frame->format
2166 || last_serial !=
is->viddec.pkt_serial
2167 || last_vfilter_idx !=
is->vfilter_idx) {
2169 "Video frame changed from size:%dx%d format:%s serial:%d to size:%dx%d format:%s serial:%d\n",
2181 if ((
ret = configure_video_filters(graph,
is, vfilters_list ? vfilters_list[
is->vfilter_idx] :
NULL,
frame)) < 0) {
2184 event.user.data1 =
is;
2185 SDL_PushEvent(&event);
2188 filt_in =
is->in_video_filter;
2189 filt_out =
is->out_video_filter;
2190 last_w =
frame->width;
2191 last_h =
frame->height;
2192 last_format =
frame->format;
2193 last_serial =
is->viddec.pkt_serial;
2194 last_vfilter_idx =
is->vfilter_idx;
2208 is->viddec.finished =
is->viddec.pkt_serial;
2215 is->frame_last_filter_delay = 0;
2223 if (
is->videoq.serial !=
is->viddec.pkt_serial)
2255 if (got_subtitle &&
sp->sub.format == 0) {
2259 sp->serial =
is->subdec.pkt_serial;
2260 sp->width =
is->subdec.avctx->width;
2261 sp->height =
is->subdec.avctx->height;
2266 }
else if (got_subtitle) {
2283 memcpy(
is->sample_array +
is->sample_array_index,
samples,
len *
sizeof(
short));
2285 is->sample_array_index +=
len;
2287 is->sample_array_index = 0;
2296 int wanted_nb_samples = nb_samples;
2300 double diff, avg_diff;
2301 int min_nb_samples, max_nb_samples;
2306 is->audio_diff_cum =
diff +
is->audio_diff_avg_coef *
is->audio_diff_cum;
2309 is->audio_diff_avg_count++;
2312 avg_diff =
is->audio_diff_cum * (1.0 -
is->audio_diff_avg_coef);
2314 if (
fabs(avg_diff) >=
is->audio_diff_threshold) {
2315 wanted_nb_samples = nb_samples + (
int)(
diff *
is->audio_src.freq);
2318 wanted_nb_samples =
av_clip(wanted_nb_samples, min_nb_samples, max_nb_samples);
2321 diff, avg_diff, wanted_nb_samples - nb_samples,
2322 is->audio_clock,
is->audio_diff_threshold);
2327 is->audio_diff_avg_count = 0;
2328 is->audio_diff_cum = 0;
2332 return wanted_nb_samples;
2344 int data_size, resampled_data_size;
2345 int64_t dec_channel_layout;
2347 int wanted_nb_samples;
2364 }
while (af->
serial !=
is->audioq.serial);
2370 dec_channel_layout =
2376 dec_channel_layout !=
is->audio_src.channel_layout ||
2381 is->audio_tgt.channel_layout,
is->audio_tgt.fmt,
is->audio_tgt.freq,
2386 "Cannot create sample rate converter for conversion of %d Hz %s %d channels to %d Hz %s %d channels!\n",
2392 is->audio_src.channel_layout = dec_channel_layout;
2401 int out_count = (int64_t)wanted_nb_samples *
is->audio_tgt.freq / af->
frame->
sample_rate + 256;
2416 if (!
is->audio_buf1)
2423 if (len2 == out_count) {
2428 is->audio_buf =
is->audio_buf1;
2432 resampled_data_size = data_size;
2435 audio_clock0 =
is->audio_clock;
2440 is->audio_clock =
NAN;
2441 is->audio_clock_serial = af->
serial;
2444 static double last_clock;
2445 printf(
"audio: delay=%0.3f clock=%0.3f clock0=%0.3f\n",
2446 is->audio_clock - last_clock,
2447 is->audio_clock, audio_clock0);
2448 last_clock =
is->audio_clock;
2451 return resampled_data_size;
2458 int audio_size, len1;
2463 if (
is->audio_buf_index >=
is->audio_buf_size) {
2465 if (audio_size < 0) {
2470 if (
is->show_mode != SHOW_MODE_VIDEO)
2472 is->audio_buf_size = audio_size;
2474 is->audio_buf_index = 0;
2476 len1 =
is->audio_buf_size -
is->audio_buf_index;
2479 if (!
is->muted &&
is->audio_buf &&
is->audio_volume == SDL_MIX_MAXVOLUME)
2480 memcpy(stream, (
uint8_t *)
is->audio_buf +
is->audio_buf_index, len1);
2482 memset(stream, 0, len1);
2483 if (!
is->muted &&
is->audio_buf)
2484 SDL_MixAudioFormat(stream, (
uint8_t *)
is->audio_buf +
is->audio_buf_index, AUDIO_S16SYS, len1,
is->audio_volume);
2488 is->audio_buf_index += len1;
2490 is->audio_write_buf_size =
is->audio_buf_size -
is->audio_buf_index;
2492 if (!
isnan(
is->audio_clock)) {
2498 static int audio_open(
void *opaque, int64_t wanted_channel_layout,
int wanted_nb_channels,
int wanted_sample_rate,
struct AudioParams *audio_hw_params)
2500 SDL_AudioSpec wanted_spec, spec;
2502 static const int next_nb_channels[] = {0, 0, 1, 6, 2, 6, 4, 6};
2503 static const int next_sample_rates[] = {0, 44100, 48000, 96000, 192000};
2504 int next_sample_rate_idx =
FF_ARRAY_ELEMS(next_sample_rates) - 1;
2506 env = SDL_getenv(
"SDL_AUDIO_CHANNELS");
2508 wanted_nb_channels = atoi(env);
2516 wanted_spec.channels = wanted_nb_channels;
2517 wanted_spec.freq = wanted_sample_rate;
2518 if (wanted_spec.freq <= 0 || wanted_spec.channels <= 0) {
2522 while (next_sample_rate_idx && next_sample_rates[next_sample_rate_idx] >= wanted_spec.freq)
2523 next_sample_rate_idx--;
2524 wanted_spec.format = AUDIO_S16SYS;
2525 wanted_spec.silence = 0;
2528 wanted_spec.userdata = opaque;
2529 while (!(
audio_dev = SDL_OpenAudioDevice(
NULL, 0, &wanted_spec, &spec, SDL_AUDIO_ALLOW_FREQUENCY_CHANGE | SDL_AUDIO_ALLOW_CHANNELS_CHANGE))) {
2531 wanted_spec.channels, wanted_spec.freq, SDL_GetError());
2532 wanted_spec.channels = next_nb_channels[
FFMIN(7, wanted_spec.channels)];
2533 if (!wanted_spec.channels) {
2534 wanted_spec.freq = next_sample_rates[next_sample_rate_idx--];
2535 wanted_spec.channels = wanted_nb_channels;
2536 if (!wanted_spec.freq) {
2538 "No more combinations to try, audio open failed\n");
2544 if (spec.format != AUDIO_S16SYS) {
2546 "SDL advised audio format %d is not supported!\n", spec.format);
2549 if (spec.channels != wanted_spec.channels) {
2551 if (!wanted_channel_layout) {
2553 "SDL advised channel count %d is not supported!\n", spec.channels);
2559 audio_hw_params->
freq = spec.freq;
2561 audio_hw_params->
channels = spec.channels;
2577 const char *forced_codec_name =
NULL;
2581 int64_t channel_layout;
2583 int stream_lowres =
lowres;
2585 if (stream_index < 0 || stream_index >= ic->
nb_streams)
2604 if (forced_codec_name)
2608 "No codec could be found with name '%s'\n", forced_codec_name);
2621 avctx->
lowres = stream_lowres;
2649 is->audio_filter_src.channels = avctx->
channels;
2652 if ((
ret = configure_audio_filters(
is, afilters, 0)) < 0)
2654 sink =
is->out_audio_filter;
2668 is->audio_hw_buf_size =
ret;
2669 is->audio_src =
is->audio_tgt;
2670 is->audio_buf_size = 0;
2671 is->audio_buf_index = 0;
2675 is->audio_diff_avg_count = 0;
2678 is->audio_diff_threshold = (double)(
is->audio_hw_buf_size) /
is->audio_tgt.bytes_per_sec;
2680 is->audio_stream = stream_index;
2681 is->audio_st = ic->
streams[stream_index];
2686 is->auddec.start_pts =
is->audio_st->start_time;
2687 is->auddec.start_pts_tb =
is->audio_st->time_base;
2694 is->video_stream = stream_index;
2695 is->video_st = ic->
streams[stream_index];
2701 is->queue_attachments_req = 1;
2704 is->subtitle_stream = stream_index;
2705 is->subtitle_st = ic->
streams[stream_index];
2728 return is->abort_request;
2732 return stream_id < 0 ||
2740 if( !strcmp(
s->iformat->name,
"rtp")
2741 || !strcmp(
s->iformat->name,
"rtsp")
2742 || !strcmp(
s->iformat->name,
"sdp")
2746 if(
s->pb && ( !strncmp(
s->url,
"rtp:", 4)
2747 || !strncmp(
s->url,
"udp:", 4)
2762 int64_t stream_start_time;
2763 int pkt_in_play_range = 0;
2765 SDL_mutex *wait_mutex = SDL_CreateMutex();
2766 int scan_all_pmts_set = 0;
2775 memset(st_index, -1,
sizeof(st_index));
2794 scan_all_pmts_set = 1;
2802 if (scan_all_pmts_set)
2823 for (
i = 0;
i < orig_nb_streams;
i++)
2829 "%s: could not find codec parameters\n",
is->filename);
2877 st_index[
i] = INT_MAX;
2905 if (codecpar->
width)
2918 if (
is->show_mode == SHOW_MODE_NONE)
2919 is->show_mode =
ret >= 0 ? SHOW_MODE_VIDEO : SHOW_MODE_RDFT;
2925 if (
is->video_stream < 0 &&
is->audio_stream < 0) {
2932 if (infinite_buffer < 0 && is->realtime)
2936 if (
is->abort_request)
2938 if (
is->paused !=
is->last_paused) {
2939 is->last_paused =
is->paused;
2945 #if CONFIG_RTSP_DEMUXER || CONFIG_MMSH_PROTOCOL
2956 int64_t seek_target =
is->seek_pos;
2957 int64_t seek_min =
is->seek_rel > 0 ? seek_target -
is->seek_rel + 2: INT64_MIN;
2958 int64_t seek_max =
is->seek_rel < 0 ? seek_target -
is->seek_rel - 2: INT64_MAX;
2965 "%s: error while seeking\n",
is->ic->url);
2967 if (
is->audio_stream >= 0)
2969 if (
is->subtitle_stream >= 0)
2971 if (
is->video_stream >= 0)
2980 is->queue_attachments_req = 1;
2985 if (
is->queue_attachments_req) {
2992 is->queue_attachments_req = 0;
3002 SDL_LockMutex(wait_mutex);
3003 SDL_CondWaitTimeout(
is->continue_read_thread, wait_mutex, 10);
3004 SDL_UnlockMutex(wait_mutex);
3020 if (
is->video_stream >= 0)
3022 if (
is->audio_stream >= 0)
3024 if (
is->subtitle_stream >= 0)
3034 SDL_LockMutex(wait_mutex);
3035 SDL_CondWaitTimeout(
is->continue_read_thread, wait_mutex, 10);
3036 SDL_UnlockMutex(wait_mutex);
3045 (pkt_ts - (stream_start_time !=
AV_NOPTS_VALUE ? stream_start_time : 0)) *
3071 event.user.data1 =
is;
3072 SDL_PushEvent(&event);
3074 SDL_DestroyMutex(wait_mutex);
3085 is->last_video_stream =
is->video_stream = -1;
3086 is->last_audio_stream =
is->audio_stream = -1;
3087 is->last_subtitle_stream =
is->subtitle_stream = -1;
3108 if (!(
is->continue_read_thread = SDL_CreateCond())) {
3116 is->audio_clock_serial = -1;
3127 if (!
is->read_tid) {
3139 int start_index, stream_index;
3146 start_index =
is->last_video_stream;
3147 old_index =
is->video_stream;
3149 start_index =
is->last_audio_stream;
3150 old_index =
is->audio_stream;
3152 start_index =
is->last_subtitle_stream;
3153 old_index =
is->subtitle_stream;
3155 stream_index = start_index;
3161 for (start_index = 0; start_index <
nb_streams; start_index++)
3166 stream_index = start_index;
3176 is->last_subtitle_stream = -1;
3179 if (start_index == -1)
3183 if (stream_index == start_index)
3185 st =
is->ic->streams[p ? p->
stream_index[stream_index] : stream_index];
3203 if (p && stream_index != -1)
3223 int next =
is->show_mode;
3225 next = (next + 1) % SHOW_MODE_NB;
3226 }
while (next !=
is->show_mode && (next == SHOW_MODE_VIDEO && !
is->video_st || next != SHOW_MODE_VIDEO && !
is->audio_st));
3227 if (
is->show_mode != next) {
3228 is->force_refresh = 1;
3229 is->show_mode = next;
3234 double remaining_time = 0.0;
3236 while (!SDL_PeepEvents(event, 1, SDL_GETEVENT, SDL_FIRSTEVENT, SDL_LASTEVENT)) {
3241 if (remaining_time > 0.0)
3242 av_usleep((int64_t)(remaining_time * 1000000.0));
3244 if (
is->show_mode != SHOW_MODE_NONE && (!
is->paused ||
is->force_refresh))
3255 if (!
is->ic->nb_chapters)
3259 for (
i = 0;
i <
is->ic->nb_chapters;
i++) {
3269 if (
i >=
is->ic->nb_chapters)
3281 double incr,
pos, frac;
3286 switch (event.type) {
3288 if (
exit_on_keydown || event.key.keysym.sym == SDLK_ESCAPE || event.key.keysym.sym == SDLK_q) {
3293 if (!cur_stream->
width)
3295 switch (event.key.keysym.sym) {
3307 case SDLK_KP_MULTIPLY:
3311 case SDLK_KP_DIVIDE:
3334 if (cur_stream->
show_mode == SHOW_MODE_VIDEO && cur_stream->vfilter_idx < nb_vfilters - 1) {
3335 if (++cur_stream->vfilter_idx >= nb_vfilters)
3336 cur_stream->vfilter_idx = 0;
3338 cur_stream->vfilter_idx = 0;
3399 case SDL_MOUSEBUTTONDOWN:
3404 if (event.button.button == SDL_BUTTON_LEFT) {
3405 static int64_t last_mouse_left_click = 0;
3409 last_mouse_left_click = 0;
3414 case SDL_MOUSEMOTION:
3420 if (event.type == SDL_MOUSEBUTTONDOWN) {
3421 if (event.button.button != SDL_BUTTON_RIGHT)
3425 if (!(event.motion.state & SDL_BUTTON_RMASK))
3435 int tns, thh, tmm, tss;
3438 tmm = (tns % 3600) / 60;
3440 frac = x / cur_stream->
width;
3443 mm = (
ns % 3600) / 60;
3446 "Seek to %2.0f%% (%2d:%02d:%02d) of total duration (%2d:%02d:%02d) \n", frac*100,
3447 hh, mm,
ss, thh, tmm, tss);
3454 case SDL_WINDOWEVENT:
3455 switch (event.window.event) {
3456 case SDL_WINDOWEVENT_SIZE_CHANGED:
3463 case SDL_WINDOWEVENT_EXPOSED:
3513 if (!strcmp(
arg,
"audio"))
3515 else if (!strcmp(
arg,
"video"))
3517 else if (!strcmp(
arg,
"ext"))
3541 !strcmp(
arg,
"waves") ? SHOW_MODE_WAVES :
3542 !strcmp(
arg,
"rdft" ) ? SHOW_MODE_RDFT :
3551 "Argument '%s' provided as input filename, but '%s' was already specified.\n",
3555 if (!strcmp(filename,
"-"))
3562 const char *spec = strchr(opt,
':');
3565 "No media specifier was specified in '%s' in option '%s'\n",
3576 "Invalid media specifier '%s' in option '%s'\n", spec, opt);
3586 {
"x",
HAS_ARG, { .func_arg =
opt_width },
"force displayed width",
"width" },
3587 {
"y",
HAS_ARG, { .func_arg =
opt_height },
"force displayed height",
"height" },
3596 {
"ss",
HAS_ARG, { .func_arg =
opt_seek },
"seek to a given position in seconds",
"pos" },
3597 {
"t",
HAS_ARG, { .func_arg =
opt_duration },
"play \"duration\" seconds of audio/video",
"duration" },
3611 {
"sync",
HAS_ARG |
OPT_EXPERT, { .func_arg =
opt_sync },
"set audio-video sync. type (type=audio/video/ext)",
"type" },
3622 {
"vf",
OPT_EXPERT |
HAS_ARG, { .func_arg = opt_add_vfilter },
"set video filters",
"filter_graph" },
3623 {
"af",
OPT_STRING |
HAS_ARG, { &afilters },
"set audio filters",
"filter_graph" },
3626 {
"showmode",
HAS_ARG, { .func_arg =
opt_show_mode},
"select show mode (0 = video, 1 = waves, 2 = RDFT)",
"mode" },
3628 {
"i",
OPT_BOOL, { &
dummy},
"read specified file",
"input_file"},
3629 {
"codec",
HAS_ARG, { .func_arg =
opt_codec},
"force decoder",
"decoder_name" },
3635 "read and decode the streams to fill missing information with heuristics" },
3656 #if !CONFIG_AVFILTER
3661 printf(
"\nWhile playing:\n"
3663 "f toggle full screen\n"
3666 "9, 0 decrease and increase volume respectively\n"
3667 "/, * decrease and increase volume respectively\n"
3668 "a cycle audio channel in the current program\n"
3669 "v cycle video channel\n"
3670 "t cycle subtitle channel in the current program\n"
3672 "w cycle video filters or show modes\n"
3673 "s activate frame-step mode\n"
3674 "left/right seek backward/forward 10 seconds or to custom interval if -seek_interval is set\n"
3675 "down/up seek backward/forward 1 minute\n"
3676 "page down/page up seek backward/forward 10 minutes\n"
3677 "right mouse click seek to percentage in file corresponding to fraction of width\n"
3678 "left double-click toggle full screen\n"
3712 "Use -h to get full help or, even better, run 'man %s'\n",
program_name);
3719 flags = SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER;
3721 flags &= ~SDL_INIT_AUDIO;
3725 if (!SDL_getenv(
"SDL_AUDIO_ALSA_SET_BUFFER_SIZE"))
3726 SDL_setenv(
"SDL_AUDIO_ALSA_SET_BUFFER_SIZE",
"1", 1);
3729 flags &= ~SDL_INIT_VIDEO;
3730 if (SDL_Init (
flags)) {
3736 SDL_EventState(SDL_SYSWMEVENT, SDL_IGNORE);
3737 SDL_EventState(SDL_USEREVENT, SDL_IGNORE);
3740 int flags = SDL_WINDOW_HIDDEN;
3742 #if SDL_VERSION_ATLEAST(2,0,5)
3743 flags |= SDL_WINDOW_ALWAYS_ON_TOP;
3745 av_log(
NULL,
AV_LOG_WARNING,
"Your SDL version doesn't support SDL_WINDOW_ALWAYS_ON_TOP. Feature will be inactive.\n");
3748 flags |= SDL_WINDOW_BORDERLESS;
3750 flags |= SDL_WINDOW_RESIZABLE;
3752 SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY,
"linear");
3754 renderer = SDL_CreateRenderer(
window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);