27 #include "config_components.h"
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
127 #define VIDEO_PICTURE_QUEUE_SIZE 3
128 #define SUBPICTURE_QUEUE_SIZE 16
129 #define SAMPLE_QUEUE_SIZE 9
130 #define FRAME_QUEUE_SIZE FFMAX(SAMPLE_QUEUE_SIZE, FFMAX(VIDEO_PICTURE_QUEUE_SIZE, SUBPICTURE_QUEUE_SIZE))
362 #define FF_QUIT_EVENT (SDL_USEREVENT + 2)
412 if (channel_count1 == 1 && channel_count2 == 1)
415 return channel_count1 != channel_count2 || fmt1 != fmt2;
437 SDL_CondSignal(q->
cond);
453 SDL_LockMutex(q->
mutex);
455 SDL_UnlockMutex(q->
mutex);
476 q->
mutex = SDL_CreateMutex();
481 q->
cond = SDL_CreateCond();
494 SDL_LockMutex(q->
mutex);
501 SDL_UnlockMutex(q->
mutex);
508 SDL_DestroyMutex(q->
mutex);
509 SDL_DestroyCond(q->
cond);
514 SDL_LockMutex(q->
mutex);
518 SDL_CondSignal(q->
cond);
520 SDL_UnlockMutex(q->
mutex);
525 SDL_LockMutex(q->
mutex);
528 SDL_UnlockMutex(q->
mutex);
537 SDL_LockMutex(q->
mutex);
562 SDL_UnlockMutex(q->
mutex);
573 d->empty_queue_cond = empty_queue_cond;
583 if (
d->queue->serial ==
d->pkt_serial) {
585 if (
d->queue->abort_request)
588 switch (
d->avctx->codec_type) {
615 d->finished =
d->pkt_serial;
625 if (
d->queue->nb_packets == 0)
626 SDL_CondSignal(
d->empty_queue_cond);
627 if (
d->packet_pending) {
628 d->packet_pending = 0;
630 int old_serial =
d->pkt_serial;
633 if (old_serial !=
d->pkt_serial) {
636 d->next_pts =
d->start_pts;
637 d->next_pts_tb =
d->start_pts_tb;
640 if (
d->queue->serial ==
d->pkt_serial)
651 if (got_frame && !
d->pkt->data) {
652 d->packet_pending = 1;
658 if (
d->pkt->buf && !
d->pkt->opaque_ref) {
662 if (!
d->pkt->opaque_ref)
669 av_log(
d->avctx,
AV_LOG_ERROR,
"Receive_frame and send_packet both returned EAGAIN, which is an API violation.\n");
670 d->packet_pending = 1;
693 if (!(
f->mutex = SDL_CreateMutex())) {
697 if (!(
f->cond = SDL_CreateCond())) {
703 f->keep_last = !!keep_last;
704 for (
i = 0;
i <
f->max_size;
i++)
713 for (
i = 0;
i <
f->max_size;
i++) {
718 SDL_DestroyMutex(
f->mutex);
719 SDL_DestroyCond(
f->cond);
724 SDL_LockMutex(
f->mutex);
725 SDL_CondSignal(
f->cond);
726 SDL_UnlockMutex(
f->mutex);
731 return &
f->queue[(
f->rindex +
f->rindex_shown) %
f->max_size];
736 return &
f->queue[(
f->rindex +
f->rindex_shown + 1) %
f->max_size];
741 return &
f->queue[
f->rindex];
747 SDL_LockMutex(
f->mutex);
748 while (
f->size >=
f->max_size &&
749 !
f->pktq->abort_request) {
750 SDL_CondWait(
f->cond,
f->mutex);
752 SDL_UnlockMutex(
f->mutex);
754 if (
f->pktq->abort_request)
757 return &
f->queue[
f->windex];
763 SDL_LockMutex(
f->mutex);
764 while (
f->size -
f->rindex_shown <= 0 &&
765 !
f->pktq->abort_request) {
766 SDL_CondWait(
f->cond,
f->mutex);
768 SDL_UnlockMutex(
f->mutex);
770 if (
f->pktq->abort_request)
773 return &
f->queue[(
f->rindex +
f->rindex_shown) %
f->max_size];
778 if (++
f->windex ==
f->max_size)
780 SDL_LockMutex(
f->mutex);
782 SDL_CondSignal(
f->cond);
783 SDL_UnlockMutex(
f->mutex);
788 if (
f->keep_last && !
f->rindex_shown) {
793 if (++
f->rindex ==
f->max_size)
795 SDL_LockMutex(
f->mutex);
797 SDL_CondSignal(
f->cond);
798 SDL_UnlockMutex(
f->mutex);
804 return f->size -
f->rindex_shown;
811 if (
f->rindex_shown &&
fp->serial ==
f->pktq->serial)
821 SDL_WaitThread(
d->decoder_tid,
NULL);
822 d->decoder_tid =
NULL;
837 static int realloc_texture(SDL_Texture **texture, Uint32 new_format,
int new_width,
int new_height, SDL_BlendMode blendmode,
int init_texture)
841 if (!*texture || SDL_QueryTexture(*texture, &
format, &access, &
w, &
h) < 0 || new_width !=
w || new_height !=
h || new_format !=
format) {
845 SDL_DestroyTexture(*texture);
846 if (!(*texture = SDL_CreateTexture(
renderer, new_format, SDL_TEXTUREACCESS_STREAMING, new_width, new_height)))
848 if (SDL_SetTextureBlendMode(*texture, blendmode) < 0)
851 if (SDL_LockTexture(*texture,
NULL, &pixels, &pitch) < 0)
853 memset(pixels, 0, pitch * new_height);
854 SDL_UnlockTexture(*texture);
856 av_log(
NULL,
AV_LOG_VERBOSE,
"Created %dx%d texture with %s.\n", new_width, new_height, SDL_GetPixelFormatName(new_format));
862 int scr_xleft,
int scr_ytop,
int scr_width,
int scr_height,
863 int pic_width,
int pic_height,
AVRational pic_sar)
876 if (
width > scr_width) {
880 x = (scr_width -
width) / 2;
881 y = (scr_height -
height) / 2;
882 rect->
x = scr_xleft + x;
883 rect->
y = scr_ytop + y;
891 *sdl_blendmode = SDL_BLENDMODE_NONE;
892 *sdl_pix_fmt = SDL_PIXELFORMAT_UNKNOWN;
897 *sdl_blendmode = SDL_BLENDMODE_BLEND;
910 SDL_BlendMode sdl_blendmode;
914 switch (sdl_pix_fmt) {
915 case SDL_PIXELFORMAT_IYUV:
942 #if SDL_VERSION_ATLEAST(2,0,8)
943 SDL_YUV_CONVERSION_MODE
mode = SDL_YUV_CONVERSION_AUTOMATIC;
946 mode = SDL_YUV_CONVERSION_JPEG;
948 mode = SDL_YUV_CONVERSION_BT709;
950 mode = SDL_YUV_CONVERSION_BT601;
952 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;
1137 if (
realloc_texture(&
s->vis_texture, SDL_PIXELFORMAT_ARGB8888,
s->width,
s->height, SDL_BLENDMODE_NONE, 1) < 0)
1140 if (
s->xpos >=
s->width)
1142 nb_display_channels=
FFMIN(nb_display_channels, 2);
1143 if (rdft_bits !=
s->rdft_bits) {
1144 const float rdft_scale = 1.0;
1148 s->rdft_bits = rdft_bits;
1152 0, 1 << rdft_bits, &rdft_scale, 0);
1154 if (err < 0 || !s->rdft_data) {
1156 s->show_mode = SHOW_MODE_WAVES;
1160 SDL_Rect
rect = {.
x =
s->xpos, .y = 0, .w = 1, .h =
s->height};
1163 for (ch = 0; ch < nb_display_channels; ch++) {
1164 data_in[ch] =
s->real_data + 2 * nb_freq * ch;
1165 data[ch] =
s->rdft_data + nb_freq * ch;
1167 for (x = 0; x < 2 * nb_freq; x++) {
1168 double w = (x-nb_freq) * (1.0 / nb_freq);
1169 data_in[ch][x] =
s->sample_array[
i] * (1.0 -
w *
w);
1174 s->rdft_fn(
s->rdft,
data[ch], data_in[ch],
sizeof(
float));
1175 data[ch][0].im =
data[ch][nb_freq].re;
1176 data[ch][nb_freq].re = 0;
1180 if (!SDL_LockTexture(
s->vis_texture, &
rect, (
void **)&pixels, &pitch)) {
1182 pixels += pitch *
s->height;
1183 for (y = 0; y <
s->height; y++) {
1184 double w = 1 / sqrt(nb_freq);
1185 int a = sqrt(
w * sqrt(
data[0][y].re *
data[0][y].re +
data[0][y].im *
data[0][y].im));
1186 int b = (nb_display_channels == 2 ) ? sqrt(
w *
hypot(
data[1][y].re,
data[1][y].im))
1191 *pixels = (
a << 16) + (
b << 8) + ((
a+
b) >> 1);
1193 SDL_UnlockTexture(
s->vis_texture);
1207 if (stream_index < 0 || stream_index >= ic->
nb_streams)
1218 is->audio_buf1_size = 0;
1245 is->audio_stream = -1;
1249 is->video_stream = -1;
1253 is->subtitle_stream = -1;
1263 is->abort_request = 1;
1264 SDL_WaitThread(
is->read_tid,
NULL);
1267 if (
is->audio_stream >= 0)
1269 if (
is->video_stream >= 0)
1271 if (
is->subtitle_stream >= 0)
1284 SDL_DestroyCond(
is->continue_read_thread);
1287 if (
is->vis_texture)
1288 SDL_DestroyTexture(
is->vis_texture);
1289 if (
is->vid_texture)
1290 SDL_DestroyTexture(
is->vid_texture);
1291 if (
is->sub_texture)
1292 SDL_DestroyTexture(
is->sub_texture);
1306 SDL_DestroyWindow(
window);
1327 if (max_width == INT_MAX && max_height == INT_MAX)
1348 SDL_SetWindowFullscreen(
window, SDL_WINDOW_FULLSCREEN_DESKTOP);
1363 SDL_SetRenderDrawColor(
renderer, 0, 0, 0, 255);
1365 if (
is->audio_st &&
is->show_mode != SHOW_MODE_VIDEO)
1367 else if (
is->video_st)
1374 if (*
c->queue_serial !=
c->serial)
1380 return c->pts_drift + time - (time -
c->last_updated) * (1.0 -
c->speed);
1387 c->last_updated = time;
1388 c->pts_drift =
c->pts - time;
1408 c->queue_serial = queue_serial;
1463 double speed =
is->extclk.speed;
1472 if (!
is->seek_req) {
1479 SDL_CondSignal(
is->continue_read_thread);
1488 if (
is->read_pause_return !=
AVERROR(ENOSYS)) {
1489 is->vidclk.paused = 0;
1494 is->paused =
is->audclk.paused =
is->vidclk.paused =
is->extclk.paused = !
is->paused;
1505 is->muted = !
is->muted;
1510 double volume_level =
is->audio_volume ? (20 *
log(
is->audio_volume / (
double)SDL_MIX_MAXVOLUME) /
log(10)) : -1000.0;
1511 int new_volume =
lrint(SDL_MIX_MAXVOLUME * pow(10.0, (volume_level + sign *
step) / 20.0));
1512 is->audio_volume =
av_clip(
is->audio_volume == new_volume ? (
is->audio_volume + sign) : new_volume, 0, SDL_MIX_MAXVOLUME);
1525 double sync_threshold,
diff = 0;
1538 if (
diff <= -sync_threshold)
1541 delay = delay +
diff;
1542 else if (
diff >= sync_threshold)
1556 if (
isnan(
duration) || duration <= 0 || duration >
is->max_frame_duration)
1585 if (
is->force_refresh ||
is->last_vis_time +
rdftspeed < time) {
1587 is->last_vis_time = time;
1589 *remaining_time =
FFMIN(*remaining_time,
is->last_vis_time +
rdftspeed - time);
1597 double last_duration,
duration, delay;
1604 if (vp->
serial !=
is->videoq.serial) {
1620 if (time < is->frame_timer + delay) {
1621 *remaining_time =
FFMIN(
is->frame_timer + delay - time, *remaining_time);
1625 is->frame_timer += delay;
1627 is->frame_timer = time;
1629 SDL_LockMutex(
is->pictq.mutex);
1632 SDL_UnlockMutex(
is->pictq.mutex);
1638 is->frame_drops_late++;
1644 if (
is->subtitle_st) {
1653 if (
sp->serial !=
is->subtitleq.serial
1654 || (
is->vidclk.pts > (
sp->pts + ((
float)
sp->sub.end_display_time / 1000)))
1659 for (
i = 0;
i <
sp->sub.num_rects;
i++) {
1664 if (!SDL_LockTexture(
is->sub_texture, (SDL_Rect *)sub_rect, (
void **)&pixels, &pitch)) {
1665 for (j = 0; j < sub_rect->h; j++, pixels += pitch)
1666 memset(pixels, 0, sub_rect->w << 2);
1667 SDL_UnlockTexture(
is->sub_texture);
1679 is->force_refresh = 1;
1681 if (
is->step && !
is->paused)
1686 if (!
display_disable &&
is->force_refresh &&
is->show_mode == SHOW_MODE_VIDEO &&
is->pictq.rindex_shown)
1689 is->force_refresh = 0;
1692 static int64_t last_time;
1694 int aqsize, vqsize, sqsize;
1698 if (!last_time || (cur_time - last_time) >= 30000) {
1703 aqsize =
is->audioq.size;
1705 vqsize =
is->videoq.size;
1706 if (
is->subtitle_st)
1707 sqsize =
is->subtitleq.size;
1709 if (
is->audio_st &&
is->video_st)
1711 else if (
is->video_st)
1713 else if (
is->audio_st)
1718 "%7.2f %s:%7.3f fd=%4d aq=%5dKB vq=%5dKB sq=%5dB f=%"PRId64
"/%"PRId64
" \r",
1720 (
is->audio_st &&
is->video_st) ?
"A-V" : (
is->video_st ?
"M-V" : (
is->audio_st ?
"M-A" :
" ")),
1722 is->frame_drops_early +
is->frame_drops_late,
1726 is->video_st ?
is->viddec.avctx->pts_correction_num_faulty_dts : 0,
1727 is->video_st ?
is->viddec.avctx->pts_correction_num_faulty_pts : 0);
1730 fprintf(stderr,
"%s", buf.str);
1737 last_time = cur_time;
1746 #if defined(DEBUG_SYNC)
1747 printf(
"frame_type=%c pts=%0.3f\n",
1792 diff -
is->frame_last_filter_delay < 0 &&
1793 is->viddec.pkt_serial ==
is->vidclk.serial &&
1794 is->videoq.nb_packets) {
1795 is->frame_drops_early++;
1822 outputs->filter_ctx = source_ctx;
1827 inputs->filter_ctx = sink_ctx;
1852 char sws_flags_str[512] =
"";
1853 char buffersrc_args[256];
1859 int nb_pix_fmts = 0;
1873 if (!strcmp(e->
key,
"sws_flags")) {
1874 av_strlcatf(sws_flags_str,
sizeof(sws_flags_str),
"%s=%s:",
"flags", e->
value);
1878 if (strlen(sws_flags_str))
1879 sws_flags_str[strlen(sws_flags_str)-1] =
'\0';
1883 snprintf(buffersrc_args,
sizeof(buffersrc_args),
1884 "video_size=%dx%d:pix_fmt=%d:time_base=%d/%d:pixel_aspect=%d/%d",
1886 is->video_st->time_base.num,
is->video_st->time_base.den,
1889 av_strlcatf(buffersrc_args,
sizeof(buffersrc_args),
":frame_rate=%d/%d", fr.
num, fr.
den);
1893 "ffplay_buffer", buffersrc_args,
NULL,
1899 "ffplay_buffersink",
NULL,
NULL, graph);
1906 last_filter = filt_out;
1910 #define INSERT_FILT(name, arg) do { \
1911 AVFilterContext *filt_ctx; \
1913 ret = avfilter_graph_create_filter(&filt_ctx, \
1914 avfilter_get_by_name(name), \
1915 "ffplay_" name, arg, NULL, graph); \
1919 ret = avfilter_link(filt_ctx, 0, last_filter, 0); \
1923 last_filter = filt_ctx; \
1932 if (!displaymatrix) {
1934 is->video_st->codecpar->nb_coded_side_data,
1941 if (
fabs(theta - 90) < 1.0) {
1943 }
else if (
fabs(theta - 180) < 1.0) {
1946 }
else if (
fabs(theta - 270) < 1.0) {
1948 }
else if (
fabs(theta) > 1.0) {
1949 char rotate_buf[64];
1950 snprintf(rotate_buf,
sizeof(rotate_buf),
"%f*PI/180", theta);
1958 is->in_video_filter = filt_src;
1959 is->out_video_filter = filt_out;
1970 char aresample_swr_opts[512] =
"";
1973 char asrc_args[256];
1985 if (strlen(aresample_swr_opts))
1986 aresample_swr_opts[strlen(aresample_swr_opts)-1] =
'\0';
1987 av_opt_set(
is->agraph,
"aresample_swr_opts", aresample_swr_opts, 0);
1992 "sample_rate=%d:sample_fmt=%s:time_base=%d/%d:channel_layout=%s",
1994 1,
is->audio_filter_src.freq, bp.str);
1998 asrc_args,
NULL,
is->agraph);
2014 if (force_output_format) {
2028 is->in_audio_filter = filt_asrc;
2029 is->out_audio_filter = filt_asink;
2044 int last_serial = -1;
2065 is->auddec.pkt_serial != last_serial;
2068 char buf1[1024], buf2[1024];
2072 "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",
2073 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,
2081 last_serial =
is->auddec.pkt_serial;
2098 af->
serial =
is->auddec.pkt_serial;
2104 if (
is->audioq.serial !=
is->auddec.pkt_serial)
2108 is->auddec.finished =
is->auddec.pkt_serial;
2120 d->decoder_tid = SDL_CreateThread(
fn, thread_name,
arg);
2121 if (!
d->decoder_tid) {
2143 int last_serial = -1;
2144 int last_vfilter_idx = 0;
2159 || last_serial !=
is->viddec.pkt_serial
2160 || last_vfilter_idx !=
is->vfilter_idx) {
2162 "Video frame changed from size:%dx%d format:%s serial:%d to size:%dx%d format:%s serial:%d\n",
2177 event.user.data1 =
is;
2178 SDL_PushEvent(&event);
2181 filt_in =
is->in_video_filter;
2182 filt_out =
is->out_video_filter;
2186 last_serial =
is->viddec.pkt_serial;
2187 last_vfilter_idx =
is->vfilter_idx;
2203 is->viddec.finished =
is->viddec.pkt_serial;
2212 is->frame_last_filter_delay = 0;
2218 if (
is->videoq.serial !=
is->viddec.pkt_serial)
2247 if (got_subtitle &&
sp->sub.format == 0) {
2251 sp->serial =
is->subdec.pkt_serial;
2252 sp->width =
is->subdec.avctx->width;
2253 sp->height =
is->subdec.avctx->height;
2258 }
else if (got_subtitle) {
2275 memcpy(
is->sample_array +
is->sample_array_index,
samples,
len *
sizeof(
short));
2277 is->sample_array_index +=
len;
2279 is->sample_array_index = 0;
2288 int wanted_nb_samples = nb_samples;
2292 double diff, avg_diff;
2293 int min_nb_samples, max_nb_samples;
2298 is->audio_diff_cum =
diff +
is->audio_diff_avg_coef *
is->audio_diff_cum;
2301 is->audio_diff_avg_count++;
2304 avg_diff =
is->audio_diff_cum * (1.0 -
is->audio_diff_avg_coef);
2306 if (
fabs(avg_diff) >=
is->audio_diff_threshold) {
2307 wanted_nb_samples = nb_samples + (
int)(
diff *
is->audio_src.freq);
2310 wanted_nb_samples =
av_clip(wanted_nb_samples, min_nb_samples, max_nb_samples);
2313 diff, avg_diff, wanted_nb_samples - nb_samples,
2314 is->audio_clock,
is->audio_diff_threshold);
2319 is->audio_diff_avg_count = 0;
2320 is->audio_diff_cum = 0;
2324 return wanted_nb_samples;
2336 int data_size, resampled_data_size;
2338 int wanted_nb_samples;
2355 }
while (af->
serial !=
is->audioq.serial);
2369 &
is->audio_tgt.ch_layout,
is->audio_tgt.fmt,
is->audio_tgt.freq,
2374 "Cannot create sample rate converter for conversion of %d Hz %s %d channels to %d Hz %s %d channels!\n",
2388 uint8_t **
out = &
is->audio_buf1;
2389 int out_count = (int64_t)wanted_nb_samples *
is->audio_tgt.freq / af->
frame->
sample_rate + 256;
2404 if (!
is->audio_buf1)
2411 if (len2 == out_count) {
2416 is->audio_buf =
is->audio_buf1;
2420 resampled_data_size = data_size;
2423 audio_clock0 =
is->audio_clock;
2428 is->audio_clock =
NAN;
2429 is->audio_clock_serial = af->
serial;
2432 static double last_clock;
2433 printf(
"audio: delay=%0.3f clock=%0.3f clock0=%0.3f\n",
2434 is->audio_clock - last_clock,
2435 is->audio_clock, audio_clock0);
2436 last_clock =
is->audio_clock;
2439 return resampled_data_size;
2446 int audio_size, len1;
2451 if (
is->audio_buf_index >=
is->audio_buf_size) {
2453 if (audio_size < 0) {
2458 if (
is->show_mode != SHOW_MODE_VIDEO)
2460 is->audio_buf_size = audio_size;
2462 is->audio_buf_index = 0;
2464 len1 =
is->audio_buf_size -
is->audio_buf_index;
2467 if (!
is->muted &&
is->audio_buf &&
is->audio_volume == SDL_MIX_MAXVOLUME)
2468 memcpy(stream, (uint8_t *)
is->audio_buf +
is->audio_buf_index, len1);
2470 memset(stream, 0, len1);
2471 if (!
is->muted &&
is->audio_buf)
2472 SDL_MixAudioFormat(stream, (uint8_t *)
is->audio_buf +
is->audio_buf_index, AUDIO_S16SYS, len1,
is->audio_volume);
2476 is->audio_buf_index += len1;
2478 is->audio_write_buf_size =
is->audio_buf_size -
is->audio_buf_index;
2480 if (!
isnan(
is->audio_clock)) {
2488 SDL_AudioSpec wanted_spec, spec;
2490 static const int next_nb_channels[] = {0, 0, 1, 6, 2, 6, 4, 6};
2491 static const int next_sample_rates[] = {0, 44100, 48000, 96000, 192000};
2492 int next_sample_rate_idx =
FF_ARRAY_ELEMS(next_sample_rates) - 1;
2493 int wanted_nb_channels = wanted_channel_layout->
nb_channels;
2495 env = SDL_getenv(
"SDL_AUDIO_CHANNELS");
2497 wanted_nb_channels = atoi(env);
2505 wanted_nb_channels = wanted_channel_layout->
nb_channels;
2506 wanted_spec.channels = wanted_nb_channels;
2507 wanted_spec.freq = wanted_sample_rate;
2508 if (wanted_spec.freq <= 0 || wanted_spec.channels <= 0) {
2512 while (next_sample_rate_idx && next_sample_rates[next_sample_rate_idx] >= wanted_spec.freq)
2513 next_sample_rate_idx--;
2514 wanted_spec.format = AUDIO_S16SYS;
2515 wanted_spec.silence = 0;
2518 wanted_spec.userdata = opaque;
2519 while (!(
audio_dev = SDL_OpenAudioDevice(
NULL, 0, &wanted_spec, &spec, SDL_AUDIO_ALLOW_FREQUENCY_CHANGE | SDL_AUDIO_ALLOW_CHANNELS_CHANGE))) {
2521 wanted_spec.channels, wanted_spec.freq, SDL_GetError());
2522 wanted_spec.channels = next_nb_channels[
FFMIN(7, wanted_spec.channels)];
2523 if (!wanted_spec.channels) {
2524 wanted_spec.freq = next_sample_rates[next_sample_rate_idx--];
2525 wanted_spec.channels = wanted_nb_channels;
2526 if (!wanted_spec.freq) {
2528 "No more combinations to try, audio open failed\n");
2534 if (spec.format != AUDIO_S16SYS) {
2536 "SDL advised audio format %d is not supported!\n", spec.format);
2539 if (spec.channels != wanted_spec.channels) {
2544 "SDL advised channel count %d is not supported!\n", spec.channels);
2550 audio_hw_params->
freq = spec.freq;
2599 const char *forced_codec_name =
NULL;
2605 int stream_lowres =
lowres;
2607 if (stream_index < 0 || stream_index >= ic->
nb_streams)
2626 if (forced_codec_name)
2630 "No codec could be found with name '%s'\n", forced_codec_name);
2643 avctx->
lowres = stream_lowres;
2689 sink =
is->out_audio_filter;
2699 is->audio_hw_buf_size =
ret;
2700 is->audio_src =
is->audio_tgt;
2701 is->audio_buf_size = 0;
2702 is->audio_buf_index = 0;
2706 is->audio_diff_avg_count = 0;
2709 is->audio_diff_threshold = (
double)(
is->audio_hw_buf_size) /
is->audio_tgt.bytes_per_sec;
2711 is->audio_stream = stream_index;
2712 is->audio_st = ic->
streams[stream_index];
2717 is->auddec.start_pts =
is->audio_st->start_time;
2718 is->auddec.start_pts_tb =
is->audio_st->time_base;
2725 is->video_stream = stream_index;
2726 is->video_st = ic->
streams[stream_index];
2732 is->queue_attachments_req = 1;
2735 is->subtitle_stream = stream_index;
2736 is->subtitle_st = ic->
streams[stream_index];
2760 return is->abort_request;
2764 return stream_id < 0 ||
2772 if( !strcmp(
s->iformat->name,
"rtp")
2773 || !strcmp(
s->iformat->name,
"rtsp")
2774 || !strcmp(
s->iformat->name,
"sdp")
2778 if(
s->pb && ( !strncmp(
s->url,
"rtp:", 4)
2779 || !strncmp(
s->url,
"udp:", 4)
2794 int64_t stream_start_time;
2795 int pkt_in_play_range = 0;
2797 SDL_mutex *wait_mutex = SDL_CreateMutex();
2798 int scan_all_pmts_set = 0;
2807 memset(st_index, -1,
sizeof(st_index));
2826 scan_all_pmts_set = 1;
2834 if (scan_all_pmts_set)
2854 "Error setting up avformat_find_stream_info() options\n");
2861 for (
i = 0;
i < orig_nb_streams;
i++)
2867 "%s: could not find codec parameters\n",
is->filename);
2917 st_index[
i] = INT_MAX;
2945 if (codecpar->
width)
2958 if (
is->show_mode == SHOW_MODE_NONE)
2959 is->show_mode =
ret >= 0 ? SHOW_MODE_VIDEO : SHOW_MODE_RDFT;
2965 if (
is->video_stream < 0 &&
is->audio_stream < 0) {
2972 if (infinite_buffer < 0 && is->realtime)
2976 if (
is->abort_request)
2978 if (
is->paused !=
is->last_paused) {
2979 is->last_paused =
is->paused;
2985 #if CONFIG_RTSP_DEMUXER || CONFIG_MMSH_PROTOCOL
2996 int64_t seek_target =
is->seek_pos;
2997 int64_t seek_min =
is->seek_rel > 0 ? seek_target -
is->seek_rel + 2: INT64_MIN;
2998 int64_t seek_max =
is->seek_rel < 0 ? seek_target -
is->seek_rel - 2: INT64_MAX;
3005 "%s: error while seeking\n",
is->ic->url);
3007 if (
is->audio_stream >= 0)
3009 if (
is->subtitle_stream >= 0)
3011 if (
is->video_stream >= 0)
3020 is->queue_attachments_req = 1;
3025 if (
is->queue_attachments_req) {
3032 is->queue_attachments_req = 0;
3042 SDL_LockMutex(wait_mutex);
3043 SDL_CondWaitTimeout(
is->continue_read_thread, wait_mutex, 10);
3044 SDL_UnlockMutex(wait_mutex);
3060 if (
is->video_stream >= 0)
3062 if (
is->audio_stream >= 0)
3064 if (
is->subtitle_stream >= 0)
3074 SDL_LockMutex(wait_mutex);
3075 SDL_CondWaitTimeout(
is->continue_read_thread, wait_mutex, 10);
3076 SDL_UnlockMutex(wait_mutex);
3085 (pkt_ts - (stream_start_time !=
AV_NOPTS_VALUE ? stream_start_time : 0)) *
3111 event.user.data1 =
is;
3112 SDL_PushEvent(&event);
3114 SDL_DestroyMutex(wait_mutex);
3126 is->last_video_stream =
is->video_stream = -1;
3127 is->last_audio_stream =
is->audio_stream = -1;
3128 is->last_subtitle_stream =
is->subtitle_stream = -1;
3149 if (!(
is->continue_read_thread = SDL_CreateCond())) {
3157 is->audio_clock_serial = -1;
3168 if (!
is->read_tid) {
3180 int start_index, stream_index;
3187 start_index =
is->last_video_stream;
3188 old_index =
is->video_stream;
3190 start_index =
is->last_audio_stream;
3191 old_index =
is->audio_stream;
3193 start_index =
is->last_subtitle_stream;
3194 old_index =
is->subtitle_stream;
3196 stream_index = start_index;
3202 for (start_index = 0; start_index <
nb_streams; start_index++)
3207 stream_index = start_index;
3217 is->last_subtitle_stream = -1;
3220 if (start_index == -1)
3224 if (stream_index == start_index)
3226 st =
is->ic->streams[p ? p->
stream_index[stream_index] : stream_index];
3244 if (p && stream_index != -1)
3264 int next =
is->show_mode;
3266 next = (next + 1) % SHOW_MODE_NB;
3267 }
while (next !=
is->show_mode && (next == SHOW_MODE_VIDEO && !
is->video_st || next != SHOW_MODE_VIDEO && !
is->audio_st));
3268 if (
is->show_mode != next) {
3269 is->force_refresh = 1;
3270 is->show_mode = next;
3275 double remaining_time = 0.0;
3277 while (!SDL_PeepEvents(event, 1, SDL_GETEVENT, SDL_FIRSTEVENT, SDL_LASTEVENT)) {
3282 if (remaining_time > 0.0)
3283 av_usleep((int64_t)(remaining_time * 1000000.0));
3285 if (
is->show_mode != SHOW_MODE_NONE && (!
is->paused ||
is->force_refresh))
3296 if (!
is->ic->nb_chapters)
3300 for (
i = 0;
i <
is->ic->nb_chapters;
i++) {
3310 if (
i >=
is->ic->nb_chapters)
3322 double incr,
pos, frac;
3327 switch (event.type) {
3329 if (
exit_on_keydown || event.key.keysym.sym == SDLK_ESCAPE || event.key.keysym.sym == SDLK_q) {
3334 if (!cur_stream->
width)
3336 switch (event.key.keysym.sym) {
3348 case SDLK_KP_MULTIPLY:
3352 case SDLK_KP_DIVIDE:
3436 case SDL_MOUSEBUTTONDOWN:
3441 if (event.button.button == SDL_BUTTON_LEFT) {
3442 static int64_t last_mouse_left_click = 0;
3446 last_mouse_left_click = 0;
3451 case SDL_MOUSEMOTION:
3457 if (event.type == SDL_MOUSEBUTTONDOWN) {
3458 if (event.button.button != SDL_BUTTON_RIGHT)
3462 if (!(event.motion.state & SDL_BUTTON_RMASK))
3472 int tns, thh, tmm, tss;
3475 tmm = (tns % 3600) / 60;
3477 frac = x / cur_stream->
width;
3480 mm = (
ns % 3600) / 60;
3483 "Seek to %2.0f%% (%2d:%02d:%02d) of total duration (%2d:%02d:%02d) \n", frac*100,
3484 hh, mm,
ss, thh, tmm, tss);
3491 case SDL_WINDOWEVENT:
3492 switch (event.window.event) {
3493 case SDL_WINDOWEVENT_SIZE_CHANGED:
3502 case SDL_WINDOWEVENT_EXPOSED:
3550 if (!strcmp(
arg,
"audio"))
3552 else if (!strcmp(
arg,
"video"))
3554 else if (!strcmp(
arg,
"ext"))
3566 !strcmp(
arg,
"waves") ? SHOW_MODE_WAVES :
3567 !strcmp(
arg,
"rdft" ) ? SHOW_MODE_RDFT : SHOW_MODE_NONE;
3583 "Argument '%s' provided as input filename, but '%s' was already specified.\n",
3587 if (!strcmp(filename,
"-"))
3596 const char *spec = strchr(opt,
':');
3599 "No media specifier was specified in '%s' in option '%s'\n",
3610 "Invalid media specifier '%s' in option '%s'\n", spec, opt);
3620 {
"x",
HAS_ARG, { .func_arg =
opt_width },
"force displayed width",
"width" },
3621 {
"y",
HAS_ARG, { .func_arg =
opt_height },
"force displayed height",
"height" },
3643 {
"sync",
HAS_ARG |
OPT_EXPERT, { .func_arg =
opt_sync },
"set audio-video sync. type (type=audio/video/ext)",
"type" },
3656 {
"showmode",
HAS_ARG, { .func_arg =
opt_show_mode},
"select show mode (0 = video, 1 = waves, 2 = RDFT)",
"mode" },
3657 {
"i",
OPT_BOOL, { &
dummy},
"read specified file",
"input_file"},
3658 {
"codec",
HAS_ARG, { .func_arg =
opt_codec},
"force decoder",
"decoder_name" },
3664 "read and decode the streams to fill missing information with heuristics" },
3689 printf(
"\nWhile playing:\n"
3691 "f toggle full screen\n"
3694 "9, 0 decrease and increase volume respectively\n"
3695 "/, * decrease and increase volume respectively\n"
3696 "a cycle audio channel in the current program\n"
3697 "v cycle video channel\n"
3698 "t cycle subtitle channel in the current program\n"
3700 "w cycle video filters or show modes\n"
3701 "s activate frame-step mode\n"
3702 "left/right seek backward/forward 10 seconds or to custom interval if -seek_interval is set\n"
3703 "down/up seek backward/forward 1 minute\n"
3704 "page down/page up seek backward/forward 10 minutes\n"
3705 "right mouse click seek to percentage in file corresponding to fraction of width\n"
3706 "left double-click toggle full screen\n"
3740 "Use -h to get full help or, even better, run 'man %s'\n",
program_name);
3747 flags = SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER;
3749 flags &= ~SDL_INIT_AUDIO;
3753 if (!SDL_getenv(
"SDL_AUDIO_ALSA_SET_BUFFER_SIZE"))
3754 SDL_setenv(
"SDL_AUDIO_ALSA_SET_BUFFER_SIZE",
"1", 1);
3757 flags &= ~SDL_INIT_VIDEO;
3758 if (SDL_Init (
flags)) {
3764 SDL_EventState(SDL_SYSWMEVENT, SDL_IGNORE);
3765 SDL_EventState(SDL_USEREVENT, SDL_IGNORE);
3768 int flags = SDL_WINDOW_HIDDEN;
3770 #if SDL_VERSION_ATLEAST(2,0,5)
3771 flags |= SDL_WINDOW_ALWAYS_ON_TOP;
3773 av_log(
NULL,
AV_LOG_WARNING,
"Your SDL version doesn't support SDL_WINDOW_ALWAYS_ON_TOP. Feature will be inactive.\n");
3776 flags |= SDL_WINDOW_BORDERLESS;
3778 flags |= SDL_WINDOW_RESIZABLE;
3780 #ifdef SDL_HINT_VIDEO_X11_NET_WM_BYPASS_COMPOSITOR
3781 SDL_SetHint(SDL_HINT_VIDEO_X11_NET_WM_BYPASS_COMPOSITOR,
"0");
3790 #if SDL_VERSION_ATLEAST(2, 0, 6)
3791 flags |= SDL_WINDOW_VULKAN;
3799 SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY,
"linear");
3817 renderer = SDL_CreateRenderer(
window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);