59 #include <SDL_thread.h>
66 #define MAX_QUEUE_SIZE (15 * 1024 * 1024)
68 #define EXTERNAL_CLOCK_MIN_FRAMES 2
69 #define EXTERNAL_CLOCK_MAX_FRAMES 10
72 #define SDL_AUDIO_MIN_BUFFER_SIZE 512
74 #define SDL_AUDIO_MAX_CALLBACKS_PER_SEC 30
77 #define SDL_VOLUME_STEP (0.75)
80 #define AV_SYNC_THRESHOLD_MIN 0.04
82 #define AV_SYNC_THRESHOLD_MAX 0.1
84 #define AV_SYNC_FRAMEDUP_THRESHOLD 0.1
86 #define AV_NOSYNC_THRESHOLD 10.0
89 #define SAMPLE_CORRECTION_PERCENT_MAX 10
92 #define EXTERNAL_CLOCK_SPEED_MIN 0.900
93 #define EXTERNAL_CLOCK_SPEED_MAX 1.010
94 #define EXTERNAL_CLOCK_SPEED_STEP 0.001
97 #define AUDIO_DIFF_AVG_NB 20
100 #define REFRESH_RATE 0.01
104 #define SAMPLE_ARRAY_SIZE (8 * 65536)
106 #define CURSOR_HIDE_DELAY 1000000
108 #define USE_ONEPASS_SUBTITLE_RENDER 1
128 #define VIDEO_PICTURE_QUEUE_SIZE 3
129 #define SUBPICTURE_QUEUE_SIZE 16
130 #define SAMPLE_QUEUE_SIZE 9
131 #define FRAME_QUEUE_SIZE FFMAX(SAMPLE_QUEUE_SIZE, FFMAX(VIDEO_PICTURE_QUEUE_SIZE, SUBPICTURE_QUEUE_SIZE))
350 static const char **vfilters_list =
NULL;
351 static int nb_vfilters = 0;
352 static char *afilters =
NULL;
362 #define FF_QUIT_EVENT (SDL_USEREVENT + 2)
396 static int opt_add_vfilter(
void *optctx,
const char *opt,
const char *
arg)
399 vfilters_list[nb_vfilters - 1] =
arg;
409 if (channel_count1 == 1 && channel_count2 == 1)
412 return channel_count1 != channel_count2 || fmt1 != fmt2;
419 return channel_layout;
444 SDL_CondSignal(q->
cond);
460 SDL_LockMutex(q->
mutex);
462 SDL_UnlockMutex(q->
mutex);
483 q->
mutex = SDL_CreateMutex();
488 q->
cond = SDL_CreateCond();
501 SDL_LockMutex(q->
mutex);
510 SDL_UnlockMutex(q->
mutex);
517 SDL_DestroyMutex(q->
mutex);
518 SDL_DestroyCond(q->
cond);
523 SDL_LockMutex(q->
mutex);
527 SDL_CondSignal(q->
cond);
529 SDL_UnlockMutex(q->
mutex);
534 SDL_LockMutex(q->
mutex);
537 SDL_UnlockMutex(q->
mutex);
546 SDL_LockMutex(q->
mutex);
572 SDL_UnlockMutex(q->
mutex);
583 d->empty_queue_cond = empty_queue_cond;
593 if (
d->queue->serial ==
d->pkt_serial) {
595 if (
d->queue->abort_request)
598 switch (
d->avctx->codec_type) {
625 d->finished =
d->pkt_serial;
635 if (
d->queue->nb_packets == 0)
636 SDL_CondSignal(
d->empty_queue_cond);
637 if (
d->packet_pending) {
638 d->packet_pending = 0;
640 int old_serial =
d->pkt_serial;
643 if (old_serial !=
d->pkt_serial) {
646 d->next_pts =
d->start_pts;
647 d->next_pts_tb =
d->start_pts_tb;
650 if (
d->queue->serial ==
d->pkt_serial)
661 if (got_frame && !
d->pkt->data) {
662 d->packet_pending = 1;
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;
909 SDL_BlendMode sdl_blendmode;
911 if (
realloc_texture(tex, sdl_pix_fmt == SDL_PIXELFORMAT_UNKNOWN ? SDL_PIXELFORMAT_ARGB8888 : sdl_pix_fmt,
frame->width,
frame->height, sdl_blendmode, 0) < 0)
913 switch (sdl_pix_fmt) {
914 case SDL_PIXELFORMAT_UNKNOWN:
919 if (*img_convert_ctx !=
NULL) {
922 if (!SDL_LockTexture(*tex,
NULL, (
void **)pixels, pitch)) {
924 0,
frame->height, pixels, pitch);
925 SDL_UnlockTexture(*tex);
932 case SDL_PIXELFORMAT_IYUV:
933 if (
frame->linesize[0] > 0 &&
frame->linesize[1] > 0 &&
frame->linesize[2] > 0) {
937 }
else if (
frame->linesize[0] < 0 &&
frame->linesize[1] < 0 &&
frame->linesize[2] < 0) {
947 if (
frame->linesize[0] < 0) {
959 #if SDL_VERSION_ATLEAST(2,0,8)
960 SDL_YUV_CONVERSION_MODE
mode = SDL_YUV_CONVERSION_AUTOMATIC;
963 mode = SDL_YUV_CONVERSION_JPEG;
965 mode = SDL_YUV_CONVERSION_BT709;
967 mode = SDL_YUV_CONVERSION_BT601;
969 SDL_SetYUVConversionMode(
mode);
980 if (
is->subtitle_st) {
984 if (vp->
pts >=
sp->pts + ((
float)
sp->sub.start_display_time / 1000)) {
989 if (!
sp->width || !
sp->height) {
993 if (
realloc_texture(&
is->sub_texture, SDL_PIXELFORMAT_ARGB8888,
sp->width,
sp->height, SDL_BLENDMODE_BLEND, 1) < 0)
996 for (
i = 0;
i <
sp->sub.num_rects;
i++) {
1000 sub_rect->
y =
av_clip(sub_rect->
y, 0,
sp->height);
1001 sub_rect->
w =
av_clip(sub_rect->
w, 0,
sp->width - sub_rect->
x);
1002 sub_rect->
h =
av_clip(sub_rect->
h, 0,
sp->height - sub_rect->
y);
1008 if (!
is->sub_convert_ctx) {
1012 if (!SDL_LockTexture(
is->sub_texture, (SDL_Rect *)sub_rect, (
void **)pixels, pitch)) {
1013 sws_scale(
is->sub_convert_ctx, (
const uint8_t *
const *)sub_rect->data, sub_rect->linesize,
1014 0, sub_rect->h, pixels, pitch);
1015 SDL_UnlockTexture(
is->sub_texture);
1038 #if USE_ONEPASS_SUBTITLE_RENDER
1042 double xratio = (double)
rect.
w / (
double)
sp->width;
1043 double yratio = (double)
rect.
h / (
double)
sp->height;
1044 for (
i = 0;
i <
sp->sub.num_rects;
i++) {
1045 SDL_Rect *sub_rect = (SDL_Rect*)
sp->sub.rects[
i];
1046 SDL_Rect target = {.x =
rect.
x + sub_rect->x * xratio,
1047 .y =
rect.
y + sub_rect->y * yratio,
1048 .w = sub_rect->w * xratio,
1049 .h = sub_rect->h * yratio};
1050 SDL_RenderCopy(
renderer,
is->sub_texture, sub_rect, &target);
1058 return a < 0 ?
a%
b +
b :
a%
b;
1063 int i, i_start, x, y1, y, ys, delay, n, nb_display_channels;
1066 int rdft_bits, nb_freq;
1068 for (rdft_bits = 1; (1 << rdft_bits) < 2 *
s->height; rdft_bits++)
1070 nb_freq = 1 << (rdft_bits - 1);
1076 int data_used=
s->show_mode == SHOW_MODE_WAVES ?
s->width : (2*nb_freq);
1078 delay =
s->audio_write_buf_size;
1085 delay -= (time_diff *
s->audio_tgt.freq) / 1000000;
1088 delay += 2 * data_used;
1089 if (delay < data_used)
1093 if (
s->show_mode == SHOW_MODE_WAVES) {
1097 int a =
s->sample_array[idx];
1102 if (
h < score && (
b ^
c) < 0) {
1109 s->last_i_start = i_start;
1111 i_start =
s->last_i_start;
1114 if (
s->show_mode == SHOW_MODE_WAVES) {
1115 SDL_SetRenderDrawColor(
renderer, 255, 255, 255, 255);
1118 h =
s->height / nb_display_channels;
1121 for (ch = 0; ch < nb_display_channels; ch++) {
1123 y1 =
s->ytop + ch *
h + (
h / 2);
1124 for (x = 0; x <
s->width; x++) {
1125 y = (
s->sample_array[
i] * h2) >> 15;
1139 SDL_SetRenderDrawColor(
renderer, 0, 0, 255, 255);
1141 for (ch = 1; ch < nb_display_channels; ch++) {
1142 y =
s->ytop + ch *
h;
1146 if (
realloc_texture(&
s->vis_texture, SDL_PIXELFORMAT_ARGB8888,
s->width,
s->height, SDL_BLENDMODE_NONE, 1) < 0)
1149 if (
s->xpos >=
s->width)
1151 nb_display_channels=
FFMIN(nb_display_channels, 2);
1152 if (rdft_bits !=
s->rdft_bits) {
1156 s->rdft_bits = rdft_bits;
1159 if (!
s->rdft || !
s->rdft_data){
1161 s->show_mode = SHOW_MODE_WAVES;
1164 SDL_Rect
rect = {.
x =
s->xpos, .y = 0, .w = 1, .h =
s->height};
1167 for (ch = 0; ch < nb_display_channels; ch++) {
1168 data[ch] =
s->rdft_data + 2 * nb_freq * ch;
1170 for (x = 0; x < 2 * nb_freq; x++) {
1171 double w = (x-nb_freq) * (1.0 / nb_freq);
1172 data[ch][x] =
s->sample_array[
i] * (1.0 -
w *
w);
1181 if (!SDL_LockTexture(
s->vis_texture, &
rect, (
void **)&pixels, &pitch)) {
1183 pixels += pitch *
s->height;
1184 for (y = 0; y <
s->height; y++) {
1185 double w = 1 / sqrt(nb_freq);
1186 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]));
1187 int b = (nb_display_channels == 2 ) ? sqrt(
w *
hypot(
data[1][2 * y + 0],
data[1][2 * y + 1]))
1192 *pixels = (
a << 16) + (
b << 8) + ((
a+
b) >> 1);
1194 SDL_UnlockTexture(
s->vis_texture);
1208 if (stream_index < 0 || stream_index >= ic->
nb_streams)
1219 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);
1288 if (
is->vis_texture)
1289 SDL_DestroyTexture(
is->vis_texture);
1290 if (
is->vid_texture)
1291 SDL_DestroyTexture(
is->vid_texture);
1292 if (
is->sub_texture)
1293 SDL_DestroyTexture(
is->sub_texture);
1305 SDL_DestroyWindow(
window);
1328 if (max_width == INT_MAX && max_height == INT_MAX)
1349 SDL_SetWindowFullscreen(
window, SDL_WINDOW_FULLSCREEN_DESKTOP);
1364 SDL_SetRenderDrawColor(
renderer, 0, 0, 0, 255);
1366 if (
is->audio_st &&
is->show_mode != SHOW_MODE_VIDEO)
1368 else if (
is->video_st)
1375 if (*
c->queue_serial !=
c->serial)
1381 return c->pts_drift + time - (time -
c->last_updated) * (1.0 -
c->speed);
1388 c->last_updated = time;
1389 c->pts_drift =
c->pts - time;
1409 c->queue_serial = queue_serial;
1464 double speed =
is->extclk.speed;
1473 if (!
is->seek_req) {
1480 SDL_CondSignal(
is->continue_read_thread);
1489 if (
is->read_pause_return !=
AVERROR(ENOSYS)) {
1490 is->vidclk.paused = 0;
1495 is->paused =
is->audclk.paused =
is->vidclk.paused =
is->extclk.paused = !
is->paused;
1506 is->muted = !
is->muted;
1511 double volume_level =
is->audio_volume ? (20 * log(
is->audio_volume / (
double)SDL_MIX_MAXVOLUME) / log(10)) : -1000.0;
1512 int new_volume =
lrint(SDL_MIX_MAXVOLUME * pow(10.0, (volume_level + sign *
step) / 20.0));
1513 is->audio_volume =
av_clip(
is->audio_volume == new_volume ? (
is->audio_volume + sign) : new_volume, 0, SDL_MIX_MAXVOLUME);
1526 double sync_threshold,
diff = 0;
1539 if (
diff <= -sync_threshold)
1542 delay = delay +
diff;
1543 else if (
diff >= sync_threshold)
1557 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++;
1811 int nb_filters =
graph->nb_filters;
1823 outputs->filter_ctx = source_ctx;
1828 inputs->filter_ctx = sink_ctx;
1840 for (
i = 0;
i <
graph->nb_filters - nb_filters;
i++)
1853 char sws_flags_str[512] =
"";
1854 char buffersrc_args[256];
1860 int nb_pix_fmts = 0;
1874 if (!strcmp(e->
key,
"sws_flags")) {
1875 av_strlcatf(sws_flags_str,
sizeof(sws_flags_str),
"%s=%s:",
"flags", e->
value);
1879 if (strlen(sws_flags_str))
1880 sws_flags_str[strlen(sws_flags_str)-1] =
'\0';
1884 snprintf(buffersrc_args,
sizeof(buffersrc_args),
1885 "video_size=%dx%d:pix_fmt=%d:time_base=%d/%d:pixel_aspect=%d/%d",
1887 is->video_st->time_base.num,
is->video_st->time_base.den,
1890 av_strlcatf(buffersrc_args,
sizeof(buffersrc_args),
":frame_rate=%d/%d", fr.
num, fr.
den);
1894 "ffplay_buffer", buffersrc_args,
NULL,
1907 last_filter = filt_out;
1911 #define INSERT_FILT(name, arg) do { \
1912 AVFilterContext *filt_ctx; \
1914 ret = avfilter_graph_create_filter(&filt_ctx, \
1915 avfilter_get_by_name(name), \
1916 "ffplay_" name, arg, NULL, graph); \
1920 ret = avfilter_link(filt_ctx, 0, last_filter, 0); \
1924 last_filter = filt_ctx; \
1931 if (
fabs(theta - 90) < 1.0) {
1932 INSERT_FILT(
"transpose",
"clock");
1933 }
else if (
fabs(theta - 180) < 1.0) {
1934 INSERT_FILT(
"hflip",
NULL);
1935 INSERT_FILT(
"vflip",
NULL);
1936 }
else if (
fabs(theta - 270) < 1.0) {
1937 INSERT_FILT(
"transpose",
"cclock");
1938 }
else if (
fabs(theta) > 1.0) {
1939 char rotate_buf[64];
1940 snprintf(rotate_buf,
sizeof(rotate_buf),
"%f*PI/180", theta);
1941 INSERT_FILT(
"rotate", rotate_buf);
1948 is->in_video_filter = filt_src;
1949 is->out_video_filter = filt_out;
1955 static int configure_audio_filters(
VideoState *
is,
const char *afilters,
int force_output_format)
1962 char aresample_swr_opts[512] =
"";
1964 char asrc_args[256];
1974 if (strlen(aresample_swr_opts))
1975 aresample_swr_opts[strlen(aresample_swr_opts)-1] =
'\0';
1976 av_opt_set(
is->agraph,
"aresample_swr_opts", aresample_swr_opts, 0);
1979 "sample_rate=%d:sample_fmt=%s:channels=%d:time_base=%d/%d",
1981 is->audio_filter_src.channels,
1982 1,
is->audio_filter_src.freq);
1983 if (
is->audio_filter_src.channel_layout)
1985 ":channel_layout=0x%"PRIx64,
is->audio_filter_src.channel_layout);
1989 asrc_args,
NULL,
is->agraph);
2005 if (force_output_format) {
2007 channels [0] =
is->audio_tgt.channel_layout ? -1 :
is->audio_tgt.channels;
2023 is->in_audio_filter = filt_asrc;
2024 is->out_audio_filter = filt_asink;
2039 int last_serial = -1;
2040 int64_t dec_channel_layout;
2063 is->audio_filter_src.channel_layout != dec_channel_layout ||
2064 is->audio_filter_src.freq !=
frame->sample_rate ||
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",
2076 is->audio_filter_src.fmt =
frame->format;
2077 is->audio_filter_src.channels =
frame->channels;
2078 is->audio_filter_src.channel_layout = dec_channel_layout;
2079 is->audio_filter_src.freq =
frame->sample_rate;
2080 last_serial =
is->auddec.pkt_serial;
2082 if ((
ret = configure_audio_filters(
is, afilters, 1)) < 0)
2097 af->
serial =
is->auddec.pkt_serial;
2104 if (
is->audioq.serial !=
is->auddec.pkt_serial)
2108 is->auddec.finished =
is->auddec.pkt_serial;
2123 d->decoder_tid = SDL_CreateThread(
fn, thread_name,
arg);
2124 if (!
d->decoder_tid) {
2147 int last_serial = -1;
2148 int last_vfilter_idx = 0;
2162 if ( last_w !=
frame->width
2163 || last_h !=
frame->height
2164 || last_format !=
frame->format
2165 || last_serial !=
is->viddec.pkt_serial
2166 || last_vfilter_idx !=
is->vfilter_idx) {
2168 "Video frame changed from size:%dx%d format:%s serial:%d to size:%dx%d format:%s serial:%d\n",
2180 if ((
ret = configure_video_filters(
graph,
is, vfilters_list ? vfilters_list[
is->vfilter_idx] :
NULL,
frame)) < 0) {
2183 event.user.data1 =
is;
2184 SDL_PushEvent(&event);
2187 filt_in =
is->in_video_filter;
2188 filt_out =
is->out_video_filter;
2189 last_w =
frame->width;
2190 last_h =
frame->height;
2191 last_format =
frame->format;
2192 last_serial =
is->viddec.pkt_serial;
2193 last_vfilter_idx =
is->vfilter_idx;
2207 is->viddec.finished =
is->viddec.pkt_serial;
2214 is->frame_last_filter_delay = 0;
2222 if (
is->videoq.serial !=
is->viddec.pkt_serial)
2254 if (got_subtitle &&
sp->sub.format == 0) {
2258 sp->serial =
is->subdec.pkt_serial;
2259 sp->width =
is->subdec.avctx->width;
2260 sp->height =
is->subdec.avctx->height;
2265 }
else if (got_subtitle) {
2282 memcpy(
is->sample_array +
is->sample_array_index,
samples,
len *
sizeof(
short));
2284 is->sample_array_index +=
len;
2286 is->sample_array_index = 0;
2295 int wanted_nb_samples = nb_samples;
2299 double diff, avg_diff;
2300 int min_nb_samples, max_nb_samples;
2305 is->audio_diff_cum =
diff +
is->audio_diff_avg_coef *
is->audio_diff_cum;
2308 is->audio_diff_avg_count++;
2311 avg_diff =
is->audio_diff_cum * (1.0 -
is->audio_diff_avg_coef);
2313 if (
fabs(avg_diff) >=
is->audio_diff_threshold) {
2314 wanted_nb_samples = nb_samples + (
int)(
diff *
is->audio_src.freq);
2317 wanted_nb_samples =
av_clip(wanted_nb_samples, min_nb_samples, max_nb_samples);
2320 diff, avg_diff, wanted_nb_samples - nb_samples,
2321 is->audio_clock,
is->audio_diff_threshold);
2326 is->audio_diff_avg_count = 0;
2327 is->audio_diff_cum = 0;
2331 return wanted_nb_samples;
2343 int data_size, resampled_data_size;
2344 int64_t dec_channel_layout;
2346 int wanted_nb_samples;
2363 }
while (af->
serial !=
is->audioq.serial);
2369 dec_channel_layout =
2375 dec_channel_layout !=
is->audio_src.channel_layout ||
2380 is->audio_tgt.channel_layout,
is->audio_tgt.fmt,
is->audio_tgt.freq,
2385 "Cannot create sample rate converter for conversion of %d Hz %s %d channels to %d Hz %s %d channels!\n",
2391 is->audio_src.channel_layout = dec_channel_layout;
2399 uint8_t **
out = &
is->audio_buf1;
2400 int out_count = (int64_t)wanted_nb_samples *
is->audio_tgt.freq / af->
frame->
sample_rate + 256;
2415 if (!
is->audio_buf1)
2422 if (len2 == out_count) {
2427 is->audio_buf =
is->audio_buf1;
2431 resampled_data_size = data_size;
2434 audio_clock0 =
is->audio_clock;
2439 is->audio_clock =
NAN;
2440 is->audio_clock_serial = af->
serial;
2443 static double last_clock;
2444 printf(
"audio: delay=%0.3f clock=%0.3f clock0=%0.3f\n",
2445 is->audio_clock - last_clock,
2446 is->audio_clock, audio_clock0);
2447 last_clock =
is->audio_clock;
2450 return resampled_data_size;
2457 int audio_size, len1;
2462 if (
is->audio_buf_index >=
is->audio_buf_size) {
2464 if (audio_size < 0) {
2469 if (
is->show_mode != SHOW_MODE_VIDEO)
2471 is->audio_buf_size = audio_size;
2473 is->audio_buf_index = 0;
2475 len1 =
is->audio_buf_size -
is->audio_buf_index;
2478 if (!
is->muted &&
is->audio_buf &&
is->audio_volume == SDL_MIX_MAXVOLUME)
2479 memcpy(stream, (uint8_t *)
is->audio_buf +
is->audio_buf_index, len1);
2481 memset(stream, 0, len1);
2482 if (!
is->muted &&
is->audio_buf)
2483 SDL_MixAudioFormat(stream, (uint8_t *)
is->audio_buf +
is->audio_buf_index, AUDIO_S16SYS, len1,
is->audio_volume);
2487 is->audio_buf_index += len1;
2489 is->audio_write_buf_size =
is->audio_buf_size -
is->audio_buf_index;
2491 if (!
isnan(
is->audio_clock)) {
2497 static int audio_open(
void *opaque, int64_t wanted_channel_layout,
int wanted_nb_channels,
int wanted_sample_rate,
struct AudioParams *audio_hw_params)
2499 SDL_AudioSpec wanted_spec, spec;
2501 static const int next_nb_channels[] = {0, 0, 1, 6, 2, 6, 4, 6};
2502 static const int next_sample_rates[] = {0, 44100, 48000, 96000, 192000};
2503 int next_sample_rate_idx =
FF_ARRAY_ELEMS(next_sample_rates) - 1;
2505 env = SDL_getenv(
"SDL_AUDIO_CHANNELS");
2507 wanted_nb_channels = atoi(env);
2515 wanted_spec.channels = wanted_nb_channels;
2516 wanted_spec.freq = wanted_sample_rate;
2517 if (wanted_spec.freq <= 0 || wanted_spec.channels <= 0) {
2521 while (next_sample_rate_idx && next_sample_rates[next_sample_rate_idx] >= wanted_spec.freq)
2522 next_sample_rate_idx--;
2523 wanted_spec.format = AUDIO_S16SYS;
2524 wanted_spec.silence = 0;
2527 wanted_spec.userdata = opaque;
2528 while (!(
audio_dev = SDL_OpenAudioDevice(
NULL, 0, &wanted_spec, &spec, SDL_AUDIO_ALLOW_FREQUENCY_CHANGE | SDL_AUDIO_ALLOW_CHANNELS_CHANGE))) {
2530 wanted_spec.channels, wanted_spec.freq, SDL_GetError());
2531 wanted_spec.channels = next_nb_channels[
FFMIN(7, wanted_spec.channels)];
2532 if (!wanted_spec.channels) {
2533 wanted_spec.freq = next_sample_rates[next_sample_rate_idx--];
2534 wanted_spec.channels = wanted_nb_channels;
2535 if (!wanted_spec.freq) {
2537 "No more combinations to try, audio open failed\n");
2543 if (spec.format != AUDIO_S16SYS) {
2545 "SDL advised audio format %d is not supported!\n", spec.format);
2548 if (spec.channels != wanted_spec.channels) {
2550 if (!wanted_channel_layout) {
2552 "SDL advised channel count %d is not supported!\n", spec.channels);
2558 audio_hw_params->
freq = spec.freq;
2560 audio_hw_params->
channels = spec.channels;
2576 const char *forced_codec_name =
NULL;
2580 int64_t channel_layout;
2582 int stream_lowres =
lowres;
2584 if (stream_index < 0 || stream_index >= ic->
nb_streams)
2603 if (forced_codec_name)
2607 "No codec could be found with name '%s'\n", forced_codec_name);
2620 avctx->
lowres = stream_lowres;
2648 is->audio_filter_src.channels = avctx->
channels;
2651 if ((
ret = configure_audio_filters(
is, afilters, 0)) < 0)
2653 sink =
is->out_audio_filter;
2667 is->audio_hw_buf_size =
ret;
2668 is->audio_src =
is->audio_tgt;
2669 is->audio_buf_size = 0;
2670 is->audio_buf_index = 0;
2674 is->audio_diff_avg_count = 0;
2677 is->audio_diff_threshold = (double)(
is->audio_hw_buf_size) /
is->audio_tgt.bytes_per_sec;
2679 is->audio_stream = stream_index;
2680 is->audio_st = ic->
streams[stream_index];
2685 is->auddec.start_pts =
is->audio_st->start_time;
2686 is->auddec.start_pts_tb =
is->audio_st->time_base;
2693 is->video_stream = stream_index;
2694 is->video_st = ic->
streams[stream_index];
2700 is->queue_attachments_req = 1;
2703 is->subtitle_stream = stream_index;
2704 is->subtitle_st = ic->
streams[stream_index];
2727 return is->abort_request;
2731 return stream_id < 0 ||
2739 if( !strcmp(
s->iformat->name,
"rtp")
2740 || !strcmp(
s->iformat->name,
"rtsp")
2741 || !strcmp(
s->iformat->name,
"sdp")
2745 if(
s->pb && ( !strncmp(
s->url,
"rtp:", 4)
2746 || !strncmp(
s->url,
"udp:", 4)
2761 int64_t stream_start_time;
2762 int pkt_in_play_range = 0;
2764 SDL_mutex *wait_mutex = SDL_CreateMutex();
2765 int scan_all_pmts_set = 0;
2774 memset(st_index, -1,
sizeof(st_index));
2793 scan_all_pmts_set = 1;
2801 if (scan_all_pmts_set)
2822 for (
i = 0;
i < orig_nb_streams;
i++)
2828 "%s: could not find codec parameters\n",
is->filename);
2876 st_index[
i] = INT_MAX;
2904 if (codecpar->
width)
2917 if (
is->show_mode == SHOW_MODE_NONE)
2918 is->show_mode =
ret >= 0 ? SHOW_MODE_VIDEO : SHOW_MODE_RDFT;
2924 if (
is->video_stream < 0 &&
is->audio_stream < 0) {
2931 if (infinite_buffer < 0 && is->realtime)
2935 if (
is->abort_request)
2937 if (
is->paused !=
is->last_paused) {
2938 is->last_paused =
is->paused;
2944 #if CONFIG_RTSP_DEMUXER || CONFIG_MMSH_PROTOCOL
2955 int64_t seek_target =
is->seek_pos;
2956 int64_t seek_min =
is->seek_rel > 0 ? seek_target -
is->seek_rel + 2: INT64_MIN;
2957 int64_t seek_max =
is->seek_rel < 0 ? seek_target -
is->seek_rel - 2: INT64_MAX;
2964 "%s: error while seeking\n",
is->ic->url);
2966 if (
is->audio_stream >= 0)
2968 if (
is->subtitle_stream >= 0)
2970 if (
is->video_stream >= 0)
2979 is->queue_attachments_req = 1;
2984 if (
is->queue_attachments_req) {
2991 is->queue_attachments_req = 0;
3001 SDL_LockMutex(wait_mutex);
3002 SDL_CondWaitTimeout(
is->continue_read_thread, wait_mutex, 10);
3003 SDL_UnlockMutex(wait_mutex);
3019 if (
is->video_stream >= 0)
3021 if (
is->audio_stream >= 0)
3023 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)) *
3070 event.user.data1 =
is;
3071 SDL_PushEvent(&event);
3073 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"
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);
3738 int flags = SDL_WINDOW_HIDDEN;
3740 #if SDL_VERSION_ATLEAST(2,0,5)
3741 flags |= SDL_WINDOW_ALWAYS_ON_TOP;
3743 av_log(
NULL,
AV_LOG_WARNING,
"Your SDL version doesn't support SDL_WINDOW_ALWAYS_ON_TOP. Feature will be inactive.\n");
3746 flags |= SDL_WINDOW_BORDERLESS;
3748 flags |= SDL_WINDOW_RESIZABLE;
3750 #ifdef SDL_HINT_VIDEO_X11_NET_WM_BYPASS_COMPOSITOR
3751 SDL_SetHint(SDL_HINT_VIDEO_X11_NET_WM_BYPASS_COMPOSITOR,
"0");
3754 SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY,
"linear");
3756 renderer = SDL_CreateRenderer(
window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);