/* TODO: We assume that a decoded and resampled frame fits into this buffer */
#define SAMPLE_ARRAY_SIZE (8 * 65536)
+#define CURSOR_HIDE_DELAY 1000000
+
static int64_t sws_flags = SWS_BICUBIC;
typedef struct MyAVPacketList {
int force_refresh;
int paused;
int last_paused;
- int que_attachments_req;
+ int queue_attachments_req;
int seek_req;
int seek_flags;
int64_t seek_pos;
static const char *subtitle_codec_name;
static const char *video_codec_name;
static int rdftspeed = 20;
+static int64_t cursor_last_shown;
+static int cursor_hidden = 0;
#if CONFIG_AVFILTER
static char *vfilters = NULL;
#endif
{
int i, i_start, x, y1, y, ys, delay, n, nb_display_channels;
int ch, channels, h, h2, bgcolor, fgcolor;
- int16_t time_diff;
+ int64_t time_diff;
int rdft_bits, nb_freq;
for (rdft_bits = 1; (1 << rdft_bits) < 2 * s->height; rdft_bits++)
if (!is->paused && get_master_sync_type(is) == AV_SYNC_EXTERNAL_CLOCK && is->realtime)
check_external_clock_speed(is);
+ if (!display_disable && is->show_mode != SHOW_MODE_VIDEO && is->audio_st)
+ video_display(is);
+
if (is->video_st) {
if (is->force_refresh)
pictq_prev_picture(is);
is->frame_last_dropped_pts = AV_NOPTS_VALUE;
}
SDL_UnlockMutex(is->pictq_mutex);
- // nothing to do, no picture to display in the que
+ // nothing to do, no picture to display in the queue
} else {
double last_duration, duration, delay;
/* dequeue the picture */
if (is->pictq_size > 1) {
VideoPicture *nextvp = &is->pictq[(is->pictq_rindex + 1) % VIDEO_PICTURE_QUEUE_SIZE];
duration = nextvp->pts - vp->pts;
- if((framedrop>0 || (framedrop && get_master_sync_type(is) != AV_SYNC_VIDEO_MASTER)) && time > is->frame_timer + duration){
+ if(!is->step && (framedrop>0 || (framedrop && get_master_sync_type(is) != AV_SYNC_VIDEO_MASTER)) && time > is->frame_timer + duration){
is->frame_drops_late++;
pictq_next_picture(is);
goto retry;
display:
/* display picture */
- if (!display_disable)
+ if (!display_disable && is->show_mode == SHOW_MODE_VIDEO)
video_display(is);
pictq_next_picture(is);
- }
- } else if (is->audio_st) {
- /* draw the next audio frame */
- /* if only audio stream, then display the audio bars (better
- than nothing, just to test the implementation */
-
- /* display picture */
- if (!display_disable)
- video_display(is);
+ if (is->step && !is->paused)
+ stream_toggle_pause(is);
+ }
}
is->force_refresh = 0;
if (show_status) {
SDL_UnlockMutex(is->pictq_mutex);
}
+static void duplicate_right_border_pixels(SDL_Overlay *bmp) {
+ int i, width, height;
+ Uint8 *p, *maxp;
+ for (i = 0; i < 3; i++) {
+ width = bmp->w;
+ height = bmp->h;
+ if (i > 0) {
+ width >>= 1;
+ height >>= 1;
+ }
+ if (bmp->pitches[i] > width) {
+ maxp = bmp->pixels[i] + bmp->pitches[i] * height - 1;
+ for (p = bmp->pixels[i] + width - 1; p < maxp; p += bmp->pitches[i])
+ *(p+1) = *p;
+ }
+ }
+}
+
static int queue_picture(VideoState *is, AVFrame *src_frame, double pts1, int64_t pos, int serial)
{
VideoPicture *vp;
sws_scale(is->img_convert_ctx, src_frame->data, src_frame->linesize,
0, vp->height, pict.data, pict.linesize);
#endif
+ /* workaround SDL PITCH_WORKAROUND */
+ duplicate_right_border_pixels(vp->bmp);
/* update the bitmap content */
SDL_UnlockYUVOverlay(vp->bmp);
avcodec_flush_buffers(is->video_st->codec);
SDL_LockMutex(is->pictq_mutex);
- // Make sure there are no long delay timers (ideally we should just flush the que but thats harder)
+ // Make sure there are no long delay timers (ideally we should just flush the queue but that's harder)
for (i = 0; i < VIDEO_PICTURE_QUEUE_SIZE; i++) {
is->pictq[i].skip = 1;
}
return ret;
}
-static int configure_video_filters(AVFilterGraph *graph, VideoState *is, const char *vfilters)
+static int configure_video_filters(AVFilterGraph *graph, VideoState *is, const char *vfilters, AVFrame *frame)
{
static const enum AVPixelFormat pix_fmts[] = { AV_PIX_FMT_YUV420P, AV_PIX_FMT_NONE };
char sws_flags_str[128];
snprintf(buffersrc_args, sizeof(buffersrc_args),
"video_size=%dx%d:pix_fmt=%d:time_base=%d/%d:pixel_aspect=%d/%d",
- codec->width, codec->height, codec->pix_fmt,
+ frame->width, frame->height, frame->format,
is->video_st->time_base.num, is->video_st->time_base.den,
codec->sample_aspect_ratio.num, FFMAX(codec->sample_aspect_ratio.den, 1));
continue;
#if CONFIG_AVFILTER
- if ( last_w != is->video_st->codec->width
- || last_h != is->video_st->codec->height
- || last_format != is->video_st->codec->pix_fmt) {
+ if ( last_w != frame->width
+ || last_h != frame->height
+ || last_format != frame->format) {
av_log(NULL, AV_LOG_INFO, "Frame changed from size:%dx%d to size:%dx%d\n",
- last_w, last_h, is->video_st->codec->width, is->video_st->codec->height);
+ last_w, last_h, frame->width, frame->height);
avfilter_graph_free(&graph);
graph = avfilter_graph_alloc();
- if ((ret = configure_video_filters(graph, is, vfilters)) < 0) {
+ if ((ret = configure_video_filters(graph, is, vfilters, frame)) < 0) {
SDL_Event event;
event.type = FF_QUIT_EVENT;
event.user.data1 = is;
}
filt_in = is->in_video_filter;
filt_out = is->out_video_filter;
- last_w = is->video_st->codec->width;
- last_h = is->video_st->codec->height;
- last_format = is->video_st->codec->pix_fmt;
+ last_w = frame->width;
+ last_h = frame->height;
+ last_format = frame->format;
}
frame->pts = pts_int;
if (ret < 0)
goto the_end;
-
- if (is->step)
- stream_toggle_pause(is);
}
the_end:
avcodec_flush_buffers(is->video_st->codec);
AVFormatContext *ic = is->ic;
AVCodecContext *avctx;
AVCodec *codec;
+ const char *forced_codec_name = NULL;
AVDictionary *opts;
AVDictionaryEntry *t = NULL;
codec = avcodec_find_decoder(avctx->codec_id);
switch(avctx->codec_type){
- case AVMEDIA_TYPE_AUDIO : is->last_audio_stream = stream_index; if(audio_codec_name ) codec= avcodec_find_decoder_by_name( audio_codec_name); break;
- case AVMEDIA_TYPE_SUBTITLE: is->last_subtitle_stream = stream_index; if(subtitle_codec_name) codec= avcodec_find_decoder_by_name(subtitle_codec_name); break;
- case AVMEDIA_TYPE_VIDEO : is->last_video_stream = stream_index; if(video_codec_name ) codec= avcodec_find_decoder_by_name( video_codec_name); break;
- }
- if (!codec)
+ case AVMEDIA_TYPE_AUDIO : is->last_audio_stream = stream_index; forced_codec_name = audio_codec_name; break;
+ case AVMEDIA_TYPE_SUBTITLE: is->last_subtitle_stream = stream_index; forced_codec_name = subtitle_codec_name; break;
+ case AVMEDIA_TYPE_VIDEO : is->last_video_stream = stream_index; forced_codec_name = video_codec_name; break;
+ }
+ if (forced_codec_name)
+ codec = avcodec_find_decoder_by_name(forced_codec_name);
+ if (!codec) {
+ if (forced_codec_name) fprintf(stderr, "No codec could be found with name '%s'\n", forced_codec_name);
+ else fprintf(stderr, "No codec could be found with id %d\n", avctx->codec_id);
return -1;
+ }
+ avctx->codec_id = codec->id;
avctx->workaround_bugs = workaround_bugs;
avctx->lowres = lowres;
if(avctx->lowres > codec->max_lowres){
is->seek_req = 0;
eof = 0;
}
- if (is->que_attachments_req) {
+ if (is->queue_attachments_req) {
avformat_queue_attached_pictures(ic);
- is->que_attachments_req = 0;
+ is->queue_attachments_req = 0;
}
/* if the queue are full, no need to read more */
is->continue_read_thread = SDL_CreateCond();
- update_external_clock_pts(is, 0.0);
+ //FIXME: use a cleaner way to signal obsolete external clock...
+ update_external_clock_pts(is, (double)AV_NOPTS_VALUE);
update_external_clock_speed(is, 1.0);
is->audio_current_pts_drift = -av_gettime() / 1000000.0;
is->video_current_pts_drift = is->audio_current_pts_drift;
stream_component_close(is, old_index);
stream_component_open(is, stream_index);
if (codec_type == AVMEDIA_TYPE_VIDEO)
- is->que_attachments_req = 1;
+ is->queue_attachments_req = 1;
}
break;
}
case SDL_MOUSEMOTION:
+ if (cursor_hidden) {
+ SDL_ShowCursor(1);
+ cursor_hidden = 0;
+ }
+ cursor_last_shown = av_gettime();
if (event.type == SDL_MOUSEBUTTONDOWN) {
x = event.button.x;
} else {
alloc_picture(event.user.data1);
break;
case FF_REFRESH_EVENT:
+ if (!cursor_hidden && av_gettime() - cursor_last_shown > CURSOR_HIDE_DELAY) {
+ SDL_ShowCursor(0);
+ cursor_hidden = 1;
+ }
video_refresh(event.user.data1);
cur_stream->refresh = 0;
break;
input_filename = filename;
}
-static int opt_codec(void *o, const char *opt, const char *arg)
+static int opt_codec(void *optctx, const char *opt, const char *arg)
{
- switch(opt[strlen(opt)-1]){
- case 'a' : audio_codec_name = arg; break;
- case 's' : subtitle_codec_name = arg; break;
- case 'v' : video_codec_name = arg; break;
- }
- return 0;
+ const char *spec = strchr(opt, ':');
+ if (!spec) {
+ fprintf(stderr, "No media specifier was specified in '%s' in option '%s'\n",
+ arg, opt);
+ return AVERROR(EINVAL);
+ }
+ spec++;
+ switch (spec[0]) {
+ case 'a' : audio_codec_name = arg; break;
+ case 's' : subtitle_codec_name = arg; break;
+ case 'v' : video_codec_name = arg; break;
+ default:
+ fprintf(stderr, "Invalid media specifier '%s' in option '%s'\n", spec, opt);
+ return AVERROR(EINVAL);
+ }
+ return 0;
}
static int dummy;
{ "showmode", HAS_ARG, { .func_arg = opt_show_mode}, "select show mode (0 = video, 1 = waves, 2 = RDFT)", "mode" },
{ "default", HAS_ARG | OPT_AUDIO | OPT_VIDEO | OPT_EXPERT, { .func_arg = opt_default }, "generic catch all option", "" },
{ "i", OPT_BOOL, { &dummy}, "read specified file", "input_file"},
- { "codec", HAS_ARG, { .func_arg = opt_codec}, "force decoder", "decoder" },
+ { "codec", HAS_ARG, { .func_arg = opt_codec}, "force decoder", "decoder_name" },
+ { "acodec", HAS_ARG | OPT_STRING | OPT_EXPERT, { &audio_codec_name }, "force audio decoder", "decoder_name" },
+ { "scodec", HAS_ARG | OPT_STRING | OPT_EXPERT, { &subtitle_codec_name }, "force subtitle decoder", "decoder_name" },
+ { "vcodec", HAS_ARG | OPT_STRING | OPT_EXPERT, { &video_codec_name }, "force video decoder", "decoder_name" },
{ NULL, },
};