X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=ffplay.c;h=bca2d5cbaadc683e5a530b2ed590725459a6eb41;hb=5dbce5120b4e05dd6d784e7ed9921c1f276acea3;hp=79dc76889e00dfdb2746723c3fded1a107d5f4b2;hpb=7071924cf2308c04a4ae53dd4a2c2070bf031a56;p=ffmpeg diff --git a/ffplay.c b/ffplay.c index 79dc76889e0..bca2d5cbaad 100644 --- a/ffplay.c +++ b/ffplay.c @@ -165,6 +165,7 @@ typedef struct Frame { int format; AVRational sar; int uploaded; + int flip_v; } Frame; typedef struct FrameQueue { @@ -321,6 +322,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 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; @@ -861,12 +863,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 +884,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 { @@ -904,8 +914,8 @@ static void video_image_display(VideoState *is) if (vp->pts >= sp->pts + ((float) sp->sub.start_display_time / 1000)) { if (!sp->uploaded) { - uint8_t *pixels; - int pitch; + uint8_t* pixels[4]; + int pitch[4]; int i; if (!sp->width || !sp->height) { sp->width = vp->width; @@ -930,9 +940,9 @@ static void video_image_display(VideoState *is) 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)) { + 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); + 0, sub_rect->h, pixels, pitch); SDL_UnlockTexture(is->sub_texture); } } @@ -949,9 +959,10 @@ static void video_image_display(VideoState *is) if (upload_texture(vp->bmp, 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); + SDL_RenderCopyEx(renderer, vp->bmp, 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); @@ -1272,6 +1283,10 @@ static int video_open(VideoState *is, Frame *vp) 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); @@ -3091,7 +3106,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); @@ -3572,6 +3593,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" }, + { "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", "" },