X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=ffplay.c;h=6325e6f99961844d79395788f532881554bf2dde;hb=08b098169be079c4f124a351fda6764fbcd10e79;hp=79dc76889e00dfdb2746723c3fded1a107d5f4b2;hpb=68b0d7e0be66bfa8141f8bd3eaa004b8104b8c34;p=ffmpeg diff --git a/ffplay.c b/ffplay.c index 79dc76889e0..6325e6f9996 100644 --- a/ffplay.c +++ b/ffplay.c @@ -158,13 +158,12 @@ typedef struct Frame { double pts; /* presentation timestamp for the frame */ double duration; /* estimated duration of the frame */ int64_t pos; /* byte position of the frame in the input file */ - SDL_Texture *bmp; - int allocated; int width; int height; int format; AVRational sar; int uploaded; + int flip_v; } Frame; typedef struct FrameQueue { @@ -273,6 +272,7 @@ typedef struct VideoState { double last_vis_time; SDL_Texture *vis_texture; SDL_Texture *sub_texture; + SDL_Texture *vid_texture; int subtitle_stream; AVStream *subtitle_st; @@ -321,6 +321,8 @@ static int subtitle_disable; static const char* wanted_stream_spec[AVMEDIA_TYPE_NB] = {0}; static int seek_by_bytes = -1; static int display_disable; +static int borderless; +static int startup_volume = 100; static int show_status = 1; static int av_sync_type = AV_SYNC_AUDIO_MASTER; static int64_t start_time = AV_NOPTS_VALUE; @@ -355,7 +357,6 @@ static int64_t audio_callback_time; static AVPacket flush_pkt; -#define FF_ALLOC_EVENT (SDL_USEREVENT) #define FF_QUIT_EVENT (SDL_USEREVENT + 2) static SDL_Window *window; @@ -390,8 +391,6 @@ int64_t get_valid_channel_layout(int64_t channel_layout, int channels) return 0; } -static void free_picture(Frame *vp); - static int packet_queue_put_private(PacketQueue *q, AVPacket *pkt) { MyAVPacketList *pkt1; @@ -675,7 +674,6 @@ static void frame_queue_destory(FrameQueue *f) Frame *vp = &f->queue[i]; frame_queue_unref_item(vp); av_frame_free(&vp->frame); - free_picture(vp); } SDL_DestroyMutex(f->mutex); SDL_DestroyCond(f->cond); @@ -796,14 +794,6 @@ static inline void fill_rectangle(int x, int y, int w, int h) SDL_RenderFillRect(renderer, &rect); } -static void free_picture(Frame *vp) -{ - if (vp->bmp) { - SDL_DestroyTexture(vp->bmp); - vp->bmp = NULL; - } -} - static int realloc_texture(SDL_Texture **texture, Uint32 new_format, int new_width, int new_height, SDL_BlendMode blendmode, int init_texture) { Uint32 format; @@ -861,12 +851,20 @@ static int upload_texture(SDL_Texture *tex, AVFrame *frame, struct SwsContext ** int ret = 0; switch (frame->format) { case AV_PIX_FMT_YUV420P: + if (frame->linesize[0] < 0 || frame->linesize[1] < 0 || frame->linesize[2] < 0) { + av_log(NULL, AV_LOG_ERROR, "Negative linesize is not supported for YUV.\n"); + return -1; + } ret = SDL_UpdateYUVTexture(tex, NULL, frame->data[0], frame->linesize[0], frame->data[1], frame->linesize[1], frame->data[2], frame->linesize[2]); break; case AV_PIX_FMT_BGRA: - ret = SDL_UpdateTexture(tex, NULL, frame->data[0], frame->linesize[0]); + if (frame->linesize[0] < 0) { + ret = SDL_UpdateTexture(tex, NULL, frame->data[0] + frame->linesize[0] * (frame->height - 1), -frame->linesize[0]); + } else { + ret = SDL_UpdateTexture(tex, NULL, frame->data[0], frame->linesize[0]); + } break; default: /* This should only happen if we are not using avfilter... */ @@ -874,11 +872,11 @@ static int upload_texture(SDL_Texture *tex, AVFrame *frame, struct SwsContext ** frame->width, frame->height, frame->format, frame->width, frame->height, AV_PIX_FMT_BGRA, sws_flags, NULL, NULL, NULL); if (*img_convert_ctx != NULL) { - uint8_t *pixels; - int pitch; - if (!SDL_LockTexture(tex, NULL, (void **)&pixels, &pitch)) { + uint8_t *pixels[4]; + int pitch[4]; + if (!SDL_LockTexture(tex, NULL, (void **)pixels, pitch)) { sws_scale(*img_convert_ctx, (const uint8_t * const *)frame->data, frame->linesize, - 0, frame->height, &pixels, &pitch); + 0, frame->height, pixels, pitch); SDL_UnlockTexture(tex); } } else { @@ -897,78 +895,80 @@ static void video_image_display(VideoState *is) SDL_Rect rect; vp = frame_queue_peek_last(&is->pictq); - if (vp->bmp) { - if (is->subtitle_st) { - if (frame_queue_nb_remaining(&is->subpq) > 0) { - sp = frame_queue_peek(&is->subpq); - - if (vp->pts >= sp->pts + ((float) sp->sub.start_display_time / 1000)) { - if (!sp->uploaded) { - uint8_t *pixels; - int pitch; - int i; - if (!sp->width || !sp->height) { - sp->width = vp->width; - sp->height = vp->height; - } - if (realloc_texture(&is->sub_texture, SDL_PIXELFORMAT_ARGB8888, sp->width, sp->height, SDL_BLENDMODE_BLEND, 1) < 0) + if (is->subtitle_st) { + if (frame_queue_nb_remaining(&is->subpq) > 0) { + sp = frame_queue_peek(&is->subpq); + + if (vp->pts >= sp->pts + ((float) sp->sub.start_display_time / 1000)) { + if (!sp->uploaded) { + uint8_t* pixels[4]; + int pitch[4]; + int i; + if (!sp->width || !sp->height) { + sp->width = vp->width; + sp->height = vp->height; + } + if (realloc_texture(&is->sub_texture, SDL_PIXELFORMAT_ARGB8888, sp->width, sp->height, SDL_BLENDMODE_BLEND, 1) < 0) + return; + + for (i = 0; i < sp->sub.num_rects; i++) { + AVSubtitleRect *sub_rect = sp->sub.rects[i]; + + sub_rect->x = av_clip(sub_rect->x, 0, sp->width ); + sub_rect->y = av_clip(sub_rect->y, 0, sp->height); + sub_rect->w = av_clip(sub_rect->w, 0, sp->width - sub_rect->x); + sub_rect->h = av_clip(sub_rect->h, 0, sp->height - sub_rect->y); + + is->sub_convert_ctx = sws_getCachedContext(is->sub_convert_ctx, + sub_rect->w, sub_rect->h, AV_PIX_FMT_PAL8, + sub_rect->w, sub_rect->h, AV_PIX_FMT_BGRA, + 0, NULL, NULL, NULL); + if (!is->sub_convert_ctx) { + av_log(NULL, AV_LOG_FATAL, "Cannot initialize the conversion context\n"); return; - - for (i = 0; i < sp->sub.num_rects; i++) { - AVSubtitleRect *sub_rect = sp->sub.rects[i]; - - sub_rect->x = av_clip(sub_rect->x, 0, sp->width ); - sub_rect->y = av_clip(sub_rect->y, 0, sp->height); - sub_rect->w = av_clip(sub_rect->w, 0, sp->width - sub_rect->x); - sub_rect->h = av_clip(sub_rect->h, 0, sp->height - sub_rect->y); - - is->sub_convert_ctx = sws_getCachedContext(is->sub_convert_ctx, - sub_rect->w, sub_rect->h, AV_PIX_FMT_PAL8, - sub_rect->w, sub_rect->h, AV_PIX_FMT_BGRA, - 0, NULL, NULL, NULL); - if (!is->sub_convert_ctx) { - av_log(NULL, AV_LOG_FATAL, "Cannot initialize the conversion context\n"); - return; - } - if (!SDL_LockTexture(is->sub_texture, (SDL_Rect *)sub_rect, (void **)&pixels, &pitch)) { - sws_scale(is->sub_convert_ctx, (const uint8_t * const *)sub_rect->data, sub_rect->linesize, - 0, sub_rect->h, &pixels, &pitch); - SDL_UnlockTexture(is->sub_texture); - } } - sp->uploaded = 1; + if (!SDL_LockTexture(is->sub_texture, (SDL_Rect *)sub_rect, (void **)pixels, pitch)) { + sws_scale(is->sub_convert_ctx, (const uint8_t * const *)sub_rect->data, sub_rect->linesize, + 0, sub_rect->h, pixels, pitch); + SDL_UnlockTexture(is->sub_texture); + } } - } else - sp = NULL; - } + sp->uploaded = 1; + } + } else + sp = NULL; } + } - calculate_display_rect(&rect, is->xleft, is->ytop, is->width, is->height, vp->width, vp->height, vp->sar); + calculate_display_rect(&rect, is->xleft, is->ytop, is->width, is->height, vp->width, vp->height, vp->sar); - if (!vp->uploaded) { - if (upload_texture(vp->bmp, vp->frame, &is->img_convert_ctx) < 0) - return; - vp->uploaded = 1; - } + if (!vp->uploaded) { + int sdl_pix_fmt = vp->frame->format == AV_PIX_FMT_YUV420P ? SDL_PIXELFORMAT_YV12 : SDL_PIXELFORMAT_ARGB8888; + if (realloc_texture(&is->vid_texture, sdl_pix_fmt, vp->frame->width, vp->frame->height, SDL_BLENDMODE_NONE, 0) < 0) + return; + if (upload_texture(is->vid_texture, vp->frame, &is->img_convert_ctx) < 0) + return; + vp->uploaded = 1; + vp->flip_v = vp->frame->linesize[0] < 0; + } - SDL_RenderCopy(renderer, vp->bmp, NULL, &rect); - if (sp) { + SDL_RenderCopyEx(renderer, is->vid_texture, NULL, &rect, 0, NULL, vp->flip_v ? SDL_FLIP_VERTICAL : 0); + if (sp) { #if USE_ONEPASS_SUBTITLE_RENDER - SDL_RenderCopy(renderer, is->sub_texture, NULL, &rect); + SDL_RenderCopy(renderer, is->sub_texture, NULL, &rect); #else - int i; - double xratio = (double)rect.w / (double)sp->width; - double yratio = (double)rect.h / (double)sp->height; - for (i = 0; i < sp->sub.num_rects; i++) { - SDL_Rect *sub_rect = (SDL_Rect*)sp->sub.rects[i]; - SDL_Rect target = {.x = rect.x + sub_rect->x * xratio, - .y = rect.y + sub_rect->y * yratio, - .w = sub_rect->w * xratio, - .h = sub_rect->h * yratio}; - SDL_RenderCopy(renderer, is->sub_texture, sub_rect, &target); - } -#endif + int i; + double xratio = (double)rect.w / (double)sp->width; + double yratio = (double)rect.h / (double)sp->height; + for (i = 0; i < sp->sub.num_rects; i++) { + SDL_Rect *sub_rect = (SDL_Rect*)sp->sub.rects[i]; + SDL_Rect target = {.x = rect.x + sub_rect->x * xratio, + .y = rect.y + sub_rect->y * yratio, + .w = sub_rect->w * xratio, + .h = sub_rect->h * yratio}; + SDL_RenderCopy(renderer, is->sub_texture, sub_rect, &target); } +#endif } } @@ -1206,6 +1206,8 @@ static void stream_close(VideoState *is) av_free(is->filename); if (is->vis_texture) SDL_DestroyTexture(is->vis_texture); + if (is->vid_texture) + SDL_DestroyTexture(is->vid_texture); if (is->sub_texture) SDL_DestroyTexture(is->sub_texture); av_free(is); @@ -1246,13 +1248,10 @@ static void set_default_window_size(int width, int height, AVRational sar) default_height = rect.h; } -static int video_open(VideoState *is, Frame *vp) +static int video_open(VideoState *is) { int w,h; - if (vp && vp->width) - set_default_window_size(vp->width, vp->height, vp->sar); - if (screen_width) { w = screen_width; h = screen_height; @@ -1267,11 +1266,17 @@ static int video_open(VideoState *is, Frame *vp) window_title = input_filename; if (is_full_screen) flags |= SDL_WINDOW_FULLSCREEN_DESKTOP; + if (borderless) + flags |= SDL_WINDOW_BORDERLESS; window = SDL_CreateWindow(window_title, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, w, h, flags); SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear"); if (window) { SDL_RendererInfo info; renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC); + if (!renderer) { + av_log(NULL, AV_LOG_WARNING, "Failed to initialize a hardware accelerated renderer: %s\n", SDL_GetError()); + renderer = SDL_CreateRenderer(window, -1, 0); + } if (renderer) { if (!SDL_GetRendererInfo(renderer, &info)) av_log(NULL, AV_LOG_VERBOSE, "Initialized %s renderer.\n", info.name); @@ -1296,7 +1301,7 @@ static int video_open(VideoState *is, Frame *vp) static void video_display(VideoState *is) { if (!window) - video_open(is, NULL); + video_open(is); SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255); SDL_RenderClear(renderer); @@ -1663,38 +1668,6 @@ display: } } -/* allocate a picture (needs to do that in main thread to avoid - potential locking problems */ -static void alloc_picture(VideoState *is) -{ - Frame *vp; - int sdl_format; - - vp = &is->pictq.queue[is->pictq.windex]; - - video_open(is, vp); - - if (vp->format == AV_PIX_FMT_YUV420P) - sdl_format = SDL_PIXELFORMAT_YV12; - else - sdl_format = SDL_PIXELFORMAT_ARGB8888; - - if (realloc_texture(&vp->bmp, sdl_format, vp->width, vp->height, SDL_BLENDMODE_NONE, 0) < 0) { - /* SDL allocates a buffer smaller than requested if the video - * overlay hardware is unable to support the requested size. */ - av_log(NULL, AV_LOG_FATAL, - "Error: the video system does not support an image\n" - "size of %dx%d pixels. Try using -lowres or -vf \"scale=w:h\"\n" - "to reduce the image size.\n", vp->width, vp->height ); - do_exit(is); - } - - SDL_LockMutex(is->pictq.mutex); - vp->allocated = 1; - SDL_CondSignal(is->pictq.cond); - SDL_UnlockMutex(is->pictq.mutex); -} - static int queue_picture(VideoState *is, AVFrame *src_frame, double pts, double duration, int64_t pos, int serial) { Frame *vp; @@ -1710,51 +1683,19 @@ static int queue_picture(VideoState *is, AVFrame *src_frame, double pts, double vp->sar = src_frame->sample_aspect_ratio; vp->uploaded = 0; - /* alloc or resize hardware picture buffer */ - if (!vp->bmp || !vp->allocated || - vp->width != src_frame->width || - vp->height != src_frame->height || - vp->format != src_frame->format) { - SDL_Event event; - - vp->allocated = 0; - vp->width = src_frame->width; - vp->height = src_frame->height; - vp->format = src_frame->format; + vp->width = src_frame->width; + vp->height = src_frame->height; + vp->format = src_frame->format; - /* the allocation must be done in the main thread to avoid - locking problems. */ - event.type = FF_ALLOC_EVENT; - event.user.data1 = is; - SDL_PushEvent(&event); + vp->pts = pts; + vp->duration = duration; + vp->pos = pos; + vp->serial = serial; - /* wait until the picture is allocated */ - SDL_LockMutex(is->pictq.mutex); - while (!vp->allocated && !is->videoq.abort_request) { - SDL_CondWait(is->pictq.cond, is->pictq.mutex); - } - /* if the queue is aborted, we have to pop the pending ALLOC event or wait for the allocation to complete */ - if (is->videoq.abort_request && SDL_PeepEvents(&event, 1, SDL_GETEVENT, FF_ALLOC_EVENT, FF_ALLOC_EVENT) != 1) { - while (!vp->allocated && !is->abort_request) { - SDL_CondWait(is->pictq.cond, is->pictq.mutex); - } - } - SDL_UnlockMutex(is->pictq.mutex); + set_default_window_size(vp->width, vp->height, vp->sar); - if (is->videoq.abort_request) - return -1; - } - - /* if the frame is not skipped, then display it */ - if (vp->bmp) { - vp->pts = pts; - vp->duration = duration; - vp->pos = pos; - vp->serial = serial; - - av_frame_move_ref(vp->frame, src_frame); - frame_queue_push(&is->pictq); - } + av_frame_move_ref(vp->frame, src_frame); + frame_queue_push(&is->pictq); return 0; } @@ -2061,7 +2002,7 @@ static int audio_thread(void *arg) goto the_end; while ((ret = av_buffersink_get_frame_flags(is->out_audio_filter, frame, 0)) >= 0) { - tb = is->out_audio_filter->inputs[0]->time_base; + tb = av_buffersink_get_time_base(is->out_audio_filter); #endif if (!(af = frame_queue_peek_writable(&is->sampq))) goto the_end; @@ -2169,7 +2110,7 @@ static int video_thread(void *arg) last_format = frame->format; last_serial = is->viddec.pkt_serial; last_vfilter_idx = is->vfilter_idx; - frame_rate = filt_out->inputs[0]->frame_rate; + frame_rate = av_buffersink_get_frame_rate(filt_out); } ret = av_buffersrc_add_frame(filt_in, frame); @@ -2190,7 +2131,7 @@ static int video_thread(void *arg) is->frame_last_filter_delay = av_gettime_relative() / 1000000.0 - is->frame_last_returned_time; if (fabs(is->frame_last_filter_delay) > AV_NOSYNC_THRESHOLD / 10.0) is->frame_last_filter_delay = 0; - tb = filt_out->inputs[0]->time_base; + tb = av_buffersink_get_time_base(filt_out); #endif duration = (frame_rate.num && frame_rate.den ? av_q2d((AVRational){frame_rate.den, frame_rate.num}) : 0); pts = (frame->pts == AV_NOPTS_VALUE) ? NAN : frame->pts * av_q2d(tb); @@ -2627,7 +2568,7 @@ static int stream_component_open(VideoState *is, int stream_index) case AVMEDIA_TYPE_AUDIO: #if CONFIG_AVFILTER { - AVFilterLink *link; + AVFilterContext *sink; is->audio_filter_src.freq = avctx->sample_rate; is->audio_filter_src.channels = avctx->channels; @@ -2635,10 +2576,10 @@ static int stream_component_open(VideoState *is, int stream_index) is->audio_filter_src.fmt = avctx->sample_fmt; if ((ret = configure_audio_filters(is, afilters, 0)) < 0) goto fail; - link = is->out_audio_filter->inputs[0]; - sample_rate = link->sample_rate; - nb_channels = avfilter_link_get_channels(link); - channel_layout = link->channel_layout; + sink = is->out_audio_filter; + sample_rate = av_buffersink_get_sample_rate(sink); + nb_channels = av_buffersink_get_channels(sink); + channel_layout = av_buffersink_get_channel_layout(sink); } #else sample_rate = avctx->sample_rate; @@ -3091,7 +3032,13 @@ static VideoState *stream_open(const char *filename, AVInputFormat *iformat) init_clock(&is->audclk, &is->audioq.serial); init_clock(&is->extclk, &is->extclk.serial); is->audio_clock_serial = -1; - is->audio_volume = SDL_MIX_MAXVOLUME; + if (startup_volume < 0) + av_log(NULL, AV_LOG_WARNING, "-volume=%d < 0, setting to 0\n", startup_volume); + if (startup_volume > 100) + av_log(NULL, AV_LOG_WARNING, "-volume=%d > 100, setting to 100\n", startup_volume); + startup_volume = av_clip(startup_volume, 0, 100); + startup_volume = av_clip(SDL_MIX_MAXVOLUME * startup_volume / 100, 0, SDL_MIX_MAXVOLUME); + is->audio_volume = startup_volume; is->muted = 0; is->av_sync_type = av_sync_type; is->read_tid = SDL_CreateThread(read_thread, "read_thread", is); @@ -3440,9 +3387,6 @@ static void event_loop(VideoState *cur_stream) case FF_QUIT_EVENT: do_exit(cur_stream); break; - case FF_ALLOC_EVENT: - alloc_picture(event.user.data1); - break; default: break; } @@ -3572,6 +3516,8 @@ static const OptionDef options[] = { { "t", HAS_ARG, { .func_arg = opt_duration }, "play \"duration\" seconds of audio/video", "duration" }, { "bytes", OPT_INT | HAS_ARG, { &seek_by_bytes }, "seek by bytes 0=off 1=on -1=auto", "val" }, { "nodisp", OPT_BOOL, { &display_disable }, "disable graphical display" }, + { "noborder", OPT_BOOL, { &borderless }, "borderless window" }, + { "volume", OPT_INT | HAS_ARG, { &startup_volume}, "set startup volume 0=min 100=max", "volume" }, { "f", HAS_ARG, { .func_arg = opt_format }, "force format", "fmt" }, { "pix_fmt", HAS_ARG | OPT_EXPERT | OPT_VIDEO, { .func_arg = opt_frame_pix_fmt }, "set pixel format", "format" }, { "stats", OPT_BOOL | OPT_EXPERT, { &show_status }, "show status", "" },