X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=ffplay.c;h=5a2c7728fc98609093d00efc97703ad950639440;hb=93931143feb05f745a960dcc9e2e69e50de3e890;hp=1c79e2492ddafa51d73810a63bd648203cdcd59f;hpb=99b01e458c268cf18ac0981e644e0f835957498a;p=ffmpeg diff --git a/ffplay.c b/ffplay.c index 1c79e2492dd..5a2c7728fc9 100644 --- a/ffplay.c +++ b/ffplay.c @@ -82,7 +82,8 @@ const int program_birth_year = 2003; #define AUDIO_DIFF_AVG_NB 20 /* NOTE: the size must be big enough to compensate the hardware audio buffersize size */ -#define SAMPLE_ARRAY_SIZE (2 * 65536) +/* TODO: We assume that a decoded and resampled frame fits into this buffer */ +#define SAMPLE_ARRAY_SIZE (8 * 65536) static int sws_flags = SWS_BICUBIC; @@ -95,12 +96,12 @@ typedef struct PacketQueue { SDL_cond *cond; } PacketQueue; -#define VIDEO_PICTURE_QUEUE_SIZE 3 +#define VIDEO_PICTURE_QUEUE_SIZE 4 #define SUBPICTURE_QUEUE_SIZE 4 typedef struct VideoPicture { - double pts; ///< presentation time stamp for this picture - int64_t pos; ///< byte position in file + double pts; // presentation timestamp for this picture + int64_t pos; // byte position in file int skip; SDL_Overlay *bmp; int width, height; /* source height & width */ @@ -209,13 +210,13 @@ typedef struct VideoState { double frame_last_returned_time; double frame_last_filter_delay; int64_t frame_last_dropped_pos; - double video_clock; ///< pts of last decoded frame / predicted pts of next decoded frame + double video_clock; // pts of last decoded frame / predicted pts of next decoded frame int video_stream; AVStream *video_st; PacketQueue videoq; - double video_current_pts; ///< current displayed pts (different from video_clock if frame fifos are used) - double video_current_pts_drift; ///< video_current_pts - time (av_gettime) at which we updated video_current_pts - used to have running video pts - int64_t video_current_pos; ///< current displayed file pos + double video_current_pts; // current displayed pts (different from video_clock if frame fifos are used) + double video_current_pts_drift; // video_current_pts - time (av_gettime) at which we updated video_current_pts - used to have running video pts + int64_t video_current_pos; // current displayed file pos VideoPicture pictq[VIDEO_PICTURE_QUEUE_SIZE]; int pictq_size, pictq_rindex, pictq_windex; SDL_mutex *pictq_mutex; @@ -229,8 +230,8 @@ typedef struct VideoState { int step; #if CONFIG_AVFILTER - AVFilterContext *in_video_filter; ///< the first filter in the video chain - AVFilterContext *out_video_filter; ///< the last filter in the video chain + AVFilterContext *in_video_filter; // the first filter in the video chain + AVFilterContext *out_video_filter; // the last filter in the video chain int use_dr1; FrameBuffer *buffer_pool; #endif @@ -277,7 +278,7 @@ static int exit_on_keydown; static int exit_on_mousedown; static int loop = 1; static int framedrop = -1; -static int infinite_buffer = 0; +static int infinite_buffer = -1; static enum ShowMode show_mode = SHOW_MODE_NONE; static const char *audio_codec_name; static const char *subtitle_codec_name; @@ -299,10 +300,7 @@ static AVPacket flush_pkt; static SDL_Surface *screen; -void av_noreturn exit_program(int ret) -{ - exit(ret); -} +static int packet_queue_put(PacketQueue *q, AVPacket *pkt); static int packet_queue_put_private(PacketQueue *q, AVPacket *pkt) { @@ -1144,7 +1142,7 @@ static void pictq_prev_picture(VideoState *is) { prevvp = &is->pictq[(is->pictq_rindex + VIDEO_PICTURE_QUEUE_SIZE - 1) % VIDEO_PICTURE_QUEUE_SIZE]; if (prevvp->allocated && !prevvp->skip) { SDL_LockMutex(is->pictq_mutex); - if (is->pictq_size < VIDEO_PICTURE_QUEUE_SIZE) { + if (is->pictq_size < VIDEO_PICTURE_QUEUE_SIZE - 1) { if (--is->pictq_rindex == -1) is->pictq_rindex = VIDEO_PICTURE_QUEUE_SIZE - 1; is->pictq_size++; @@ -1173,6 +1171,8 @@ static void video_refresh(void *opaque) SubPicture *sp, *sp2; if (is->video_st) { + if (is->force_refresh) + pictq_prev_picture(is); retry: if (is->pictq_size == 0) { SDL_LockMutex(is->pictq_mutex); @@ -1385,7 +1385,7 @@ static int queue_picture(VideoState *is, AVFrame *src_frame, double pts1, int64_ SDL_LockMutex(is->pictq_mutex); /* keep the last already displayed picture in the queue */ - while (is->pictq_size >= VIDEO_PICTURE_QUEUE_SIZE - 1 && + while (is->pictq_size >= VIDEO_PICTURE_QUEUE_SIZE - 2 && !is->videoq.abort_request) { SDL_CondWait(is->pictq_cond, is->pictq_mutex); } @@ -1463,7 +1463,7 @@ static int queue_picture(VideoState *is, AVFrame *src_frame, double pts1, int64_ sws_flags = av_get_int(sws_opts, "sws_flags", NULL); is->img_convert_ctx = sws_getCachedContext(is->img_convert_ctx, vp->width, vp->height, src_frame->format, vp->width, vp->height, - PIX_FMT_YUV420P, sws_flags, NULL, NULL, NULL); + AV_PIX_FMT_YUV420P, sws_flags, NULL, NULL, NULL); if (is->img_convert_ctx == NULL) { fprintf(stderr, "Cannot initialize the conversion context\n"); exit(1); @@ -1599,7 +1599,7 @@ fail: static int configure_video_filters(AVFilterGraph *graph, VideoState *is, const char *vfilters) { - static const enum PixelFormat pix_fmts[] = { PIX_FMT_YUV420P, PIX_FMT_NONE }; + static const enum AVPixelFormat pix_fmts[] = { AV_PIX_FMT_YUV420P, AV_PIX_FMT_NONE }; char sws_flags_str[128]; char buffersrc_args[256]; int ret; @@ -1671,7 +1671,7 @@ static int video_thread(void *arg) AVFilterContext *filt_out = NULL, *filt_in = NULL; int last_w = 0; int last_h = 0; - enum PixelFormat last_format = -2; + enum AVPixelFormat last_format = -2; if (codec->codec->capabilities & CODEC_CAP_DR1) { is->use_dr1 = 1; @@ -1792,7 +1792,7 @@ static int video_thread(void *arg) avfilter_graph_free(&graph); #endif av_free_packet(&pkt); - av_free(frame); + avcodec_free_frame(&frame); return 0; } @@ -1837,8 +1837,9 @@ static int subtitle_thread(void *arg) avcodec_decode_subtitle2(is->subtitle_st->codec, &sp->sub, &got_subtitle, pkt); - if (got_subtitle && sp->sub.format == 0) { + if (sp->sub.pts != AV_NOPTS_VALUE) + pts = sp->sub.pts / (double)AV_TIME_BASE; sp->pts = pts; for (i = 0; i < sp->sub.num_rects; i++) @@ -1973,34 +1974,34 @@ static int audio_decode_frame(VideoState *is, double *pts_ptr) flush_complete = 1; continue; } - data_size = av_samples_get_buffer_size(NULL, dec->channels, + data_size = av_samples_get_buffer_size(NULL, is->frame->channels, is->frame->nb_samples, - dec->sample_fmt, 1); + is->frame->format, 1); dec_channel_layout = - (dec->channel_layout && dec->channels == av_get_channel_layout_nb_channels(dec->channel_layout)) ? - dec->channel_layout : av_get_default_channel_layout(dec->channels); + (is->frame->channel_layout && is->frame->channels == av_get_channel_layout_nb_channels(is->frame->channel_layout)) ? + is->frame->channel_layout : av_get_default_channel_layout(is->frame->channels); wanted_nb_samples = synchronize_audio(is, is->frame->nb_samples); - if (dec->sample_fmt != is->audio_src.fmt || - dec_channel_layout != is->audio_src.channel_layout || - dec->sample_rate != is->audio_src.freq || - (wanted_nb_samples != is->frame->nb_samples && !is->swr_ctx)) { + if (is->frame->format != is->audio_src.fmt || + dec_channel_layout != is->audio_src.channel_layout || + is->frame->sample_rate != is->audio_src.freq || + (wanted_nb_samples != is->frame->nb_samples && !is->swr_ctx)) { swr_free(&is->swr_ctx); is->swr_ctx = swr_alloc_set_opts(NULL, is->audio_tgt.channel_layout, is->audio_tgt.fmt, is->audio_tgt.freq, - dec_channel_layout, dec->sample_fmt, dec->sample_rate, + dec_channel_layout, is->frame->format, is->frame->sample_rate, 0, NULL); if (!is->swr_ctx || swr_init(is->swr_ctx) < 0) { fprintf(stderr, "Cannot create sample rate converter for conversion of %d Hz %s %d channels to %d Hz %s %d channels!\n", - dec->sample_rate, av_get_sample_fmt_name(dec->sample_fmt), dec->channels, + is->frame->sample_rate, av_get_sample_fmt_name(is->frame->format), (int)is->frame->channels, is->audio_tgt.freq, av_get_sample_fmt_name(is->audio_tgt.fmt), is->audio_tgt.channels); break; } is->audio_src.channel_layout = dec_channel_layout; - is->audio_src.channels = dec->channels; - is->audio_src.freq = dec->sample_rate; - is->audio_src.fmt = dec->sample_fmt; + is->audio_src.channels = is->frame->channels; + is->audio_src.freq = is->frame->sample_rate; + is->audio_src.fmt = is->frame->format; } if (is->swr_ctx) { @@ -2008,8 +2009,8 @@ static int audio_decode_frame(VideoState *is, double *pts_ptr) uint8_t *out[] = {is->audio_buf2}; int out_count = sizeof(is->audio_buf2) / is->audio_tgt.channels / av_get_bytes_per_sample(is->audio_tgt.fmt); if (wanted_nb_samples != is->frame->nb_samples) { - if (swr_set_compensation(is->swr_ctx, (wanted_nb_samples - is->frame->nb_samples) * is->audio_tgt.freq / dec->sample_rate, - wanted_nb_samples * is->audio_tgt.freq / dec->sample_rate) < 0) { + if (swr_set_compensation(is->swr_ctx, (wanted_nb_samples - is->frame->nb_samples) * is->audio_tgt.freq / is->frame->sample_rate, + wanted_nb_samples * is->audio_tgt.freq / is->frame->sample_rate) < 0) { fprintf(stderr, "swr_set_compensation() failed\n"); break; } @@ -2034,7 +2035,7 @@ static int audio_decode_frame(VideoState *is, double *pts_ptr) pts = is->audio_clock; *pts_ptr = pts; is->audio_clock += (double)data_size / - (dec->channels * dec->sample_rate * av_get_bytes_per_sample(dec->sample_fmt)); + (is->frame->channels * is->frame->sample_rate * av_get_bytes_per_sample(is->frame->format)); #ifdef DEBUG { static double last_clock; @@ -2292,7 +2293,7 @@ static void stream_component_close(VideoState *is, int stream_index) swr_free(&is->swr_ctx); av_freep(&is->audio_buf1); is->audio_buf = NULL; - av_freep(&is->frame); + avcodec_free_frame(&is->frame); if (is->rdft) { av_rdft_end(is->rdft); @@ -2362,6 +2363,22 @@ static int decode_interrupt_cb(void *ctx) return is->abort_request; } +static int is_realtime(AVFormatContext *s) +{ + if( !strcmp(s->iformat->name, "rtp") + || !strcmp(s->iformat->name, "rtsp") + || !strcmp(s->iformat->name, "sdp") + ) + return 1; + + if(s->pb && ( !strncmp(s->filename, "rtp:", 4) + || !strncmp(s->filename, "udp:", 4) + ) + ) + return 1; + return 0; +} + /* this thread gets the stream from the disk or the network */ static int read_thread(void *arg) { @@ -2484,6 +2501,9 @@ static int read_thread(void *arg) goto fail; } + if (infinite_buffer < 0 && is_realtime(ic)) + infinite_buffer = 1; + for (;;) { if (is->abort_request) break; @@ -2537,7 +2557,7 @@ static int read_thread(void *arg) } /* if the queue are full, no need to read more */ - if (!infinite_buffer && + if (infinite_buffer<1 && (is->audioq.size + is->videoq.size + is->subtitleq.size > MAX_QUEUE_SIZE || ( (is->audioq .nb_packets > MIN_FRAMES || is->audio_stream < 0 || is->audioq.abort_request) && (is->videoq .nb_packets > MIN_FRAMES || is->video_stream < 0 || is->videoq.abort_request) @@ -2582,7 +2602,9 @@ static int read_thread(void *arg) eof = 1; if (ic->pb && ic->pb->error) break; - SDL_Delay(100); /* wait for user event */ + SDL_LockMutex(wait_mutex); + SDL_CondWaitTimeout(is->continue_read_thread, wait_mutex, 10); + SDL_UnlockMutex(wait_mutex); continue; } /* check if packet is in play range specified by user, then queue, otherwise discard */ @@ -2898,8 +2920,6 @@ static void event_loop(VideoState *cur_stream) alloc_picture(event.user.data1); break; case FF_REFRESH_EVENT: - if (cur_stream->force_refresh) - pictq_prev_picture(event.user.data1); video_refresh(event.user.data1); cur_stream->refresh = 0; break; @@ -2984,7 +3004,7 @@ static void opt_input_file(void *optctx, const char *filename) if (input_filename) { fprintf(stderr, "Argument '%s' provided as input filename, but '%s' was already specified.\n", filename, input_filename); - exit_program(1); + exit(1); } if (!strcmp(filename, "-")) filename = "pipe:";