X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=ffplay.c;h=cf138dc51513eaba4f8392ba3e2288e4ddb64c14;hb=62c8dc46429bd75a27142c142f8c50139d8a0702;hp=967679e60b03f9f3c5a89989fbacaf519d42e6c9;hpb=448f2972f9f9e325139d5e19a8147994f465928e;p=ffmpeg diff --git a/ffplay.c b/ffplay.c index 967679e60b0..cf138dc5151 100644 --- a/ffplay.c +++ b/ffplay.c @@ -73,8 +73,8 @@ const int program_birth_year = 2003; /* Calculate actual buffer size keeping in mind not cause too frequent audio callbacks */ #define SDL_AUDIO_MAX_CALLBACKS_PER_SEC 30 -/* Step size for volume control */ -#define SDL_VOLUME_STEP (SDL_MIX_MAXVOLUME / 50) +/* Step size for volume control in dB */ +#define SDL_VOLUME_STEP (0.75) /* no AV sync correction is done if below the minimum AV sync threshold */ #define AV_SYNC_THRESHOLD_MIN 0.04 @@ -158,8 +158,6 @@ 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; @@ -274,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; @@ -322,6 +321,7 @@ 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; @@ -357,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; @@ -392,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; @@ -677,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); @@ -798,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; @@ -907,79 +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[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) + 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; - vp->flip_v = vp->frame->linesize[0] < 0; - } + 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_RenderCopyEx(renderer, vp->bmp, NULL, &rect, 0, NULL, vp->flip_v ? SDL_FLIP_VERTICAL : 0); - 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 } } @@ -1217,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); @@ -1257,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; @@ -1273,11 +1261,15 @@ static int video_open(VideoState *is, Frame *vp) } if (!window) { - int flags = SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE; + int flags = SDL_WINDOW_SHOWN; if (!window_title) window_title = input_filename; if (is_full_screen) flags |= SDL_WINDOW_FULLSCREEN_DESKTOP; + if (borderless) + flags |= SDL_WINDOW_BORDERLESS; + else + flags |= SDL_WINDOW_RESIZABLE; window = SDL_CreateWindow(window_title, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, w, h, flags); SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear"); if (window) { @@ -1311,7 +1303,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); @@ -1458,9 +1450,11 @@ static void toggle_mute(VideoState *is) is->muted = !is->muted; } -static void update_volume(VideoState *is, int sign, int step) +static void update_volume(VideoState *is, int sign, double step) { - is->audio_volume = av_clip(is->audio_volume + sign * step, 0, SDL_MIX_MAXVOLUME); + double volume_level = is->audio_volume ? (20 * log(is->audio_volume / (double)SDL_MIX_MAXVOLUME) / log(10)) : -1000.0; + int new_volume = lrint(SDL_MIX_MAXVOLUME * pow(10.0, (volume_level + sign * step) / 20.0)); + is->audio_volume = av_clip(is->audio_volume == new_volume ? (is->audio_volume + sign) : new_volume, 0, SDL_MIX_MAXVOLUME); } static void step_to_next_frame(VideoState *is) @@ -1678,38 +1672,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; @@ -1725,51 +1687,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; - - /* 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); - - /* 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); + vp->width = src_frame->width; + vp->height = src_frame->height; + vp->format = src_frame->format; - if (is->videoq.abort_request) - return -1; - } + vp->pts = pts; + vp->duration = duration; + vp->pos = pos; + vp->serial = serial; - /* if the frame is not skipped, then display it */ - if (vp->bmp) { - vp->pts = pts; - vp->duration = duration; - vp->pos = pos; - vp->serial = serial; + set_default_window_size(vp->width, vp->height, vp->sar); - 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; } @@ -3461,9 +3391,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; } @@ -3593,6 +3520,7 @@ 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" },