X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=ffplay.c;h=cbbeb79d240c45c3e981b3dd309b91ddfc0941f8;hb=a677e0cf14198709c890f4e61516b7f13e803dc4;hp=ecf2c5be396ac085979a2f6343715955721537c3;hpb=2a89ee9a63f0ef787f81f388c118e64c4515f158;p=ffmpeg diff --git a/ffplay.c b/ffplay.c index ecf2c5be396..cbbeb79d240 100644 --- a/ffplay.c +++ b/ffplay.c @@ -18,9 +18,12 @@ * License along with FFmpeg; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#define HAVE_AV_CONFIG_H + +#include +#include #include "avformat.h" #include "swscale.h" +#include "avstring.h" #include "version.h" #include "cmdutils.h" @@ -32,22 +35,7 @@ #undef main /* We don't want SDL to override our main() */ #endif -#ifdef CONFIG_OS2 -#define INCL_DOS - #include - #include - - void MorphToPM() - { - PPIB pib; - PTIB tib; - - DosGetInfoBlocks(&tib, &pib); - - // Change flag from VIO to PM: - if (pib->pib_ultype==2) pib->pib_ultype = 3; - } -#endif +#undef exit //#define DEBUG_SYNC @@ -192,6 +180,7 @@ static enum PixelFormat frame_pix_fmt = PIX_FMT_NONE; static int audio_disable; static int video_disable; static int wanted_audio_stream= 0; +static int wanted_video_stream= 0; static int seek_by_bytes; static int display_disable; static int show_status; @@ -211,6 +200,7 @@ static enum AVDiscard skip_idct= AVDISCARD_DEFAULT; static enum AVDiscard skip_loop_filter= AVDISCARD_DEFAULT; static int error_resilience = FF_ER_CAREFUL; static int error_concealment = 3; +static int decoder_reorder_pts= 0; /* current context */ static int is_full_screen; @@ -417,7 +407,7 @@ void fill_border(VideoState *s, int x, int y, int w, int h, int color) #define YUVA_IN(y, u, v, a, s, pal)\ {\ - unsigned int val = ((const uint32_t *)(pal))[*(const uint8_t*)s];\ + unsigned int val = ((const uint32_t *)(pal))[*(const uint8_t*)(s)];\ a = (val >> 24) & 0xff;\ y = (val >> 16) & 0xff;\ u = (val >> 8) & 0xff;\ @@ -432,31 +422,36 @@ void fill_border(VideoState *s, int x, int y, int w, int h, int color) #define BPP 1 -static void blend_subrect(AVPicture *dst, const AVSubtitleRect *rect) +static void blend_subrect(AVPicture *dst, const AVSubtitleRect *rect, int imgw, int imgh) { int wrap, wrap3, width2, skip2; int y, u, v, a, u1, v1, a1, w, h; uint8_t *lum, *cb, *cr; const uint8_t *p; const uint32_t *pal; - - lum = dst->data[0] + rect->y * dst->linesize[0]; - cb = dst->data[1] + (rect->y >> 1) * dst->linesize[1]; - cr = dst->data[2] + (rect->y >> 1) * dst->linesize[2]; - - width2 = (rect->w + 1) >> 1; - skip2 = rect->x >> 1; + int dstx, dsty, dstw, dsth; + + dstx = FFMIN(FFMAX(rect->x, 0), imgw); + dstw = FFMIN(FFMAX(rect->w, 0), imgw - dstx); + dsty = FFMIN(FFMAX(rect->y, 0), imgh); + dsth = FFMIN(FFMAX(rect->h, 0), imgh - dsty); + lum = dst->data[0] + dsty * dst->linesize[0]; + cb = dst->data[1] + (dsty >> 1) * dst->linesize[1]; + cr = dst->data[2] + (dsty >> 1) * dst->linesize[2]; + + width2 = (dstw + 1) >> 1; + skip2 = dstx >> 1; wrap = dst->linesize[0]; wrap3 = rect->linesize; p = rect->bitmap; pal = rect->rgba_palette; /* Now in YCrCb! */ - if (rect->y & 1) { - lum += rect->x; + if (dsty & 1) { + lum += dstx; cb += skip2; cr += skip2; - if (rect->x & 1) { + if (dstx & 1) { YUVA_IN(y, u, v, a, p, pal); lum[0] = ALPHA_BLEND(a, lum[0], y, 0); cb[0] = ALPHA_BLEND(a >> 2, cb[0], u, 0); @@ -466,7 +461,7 @@ static void blend_subrect(AVPicture *dst, const AVSubtitleRect *rect) lum++; p += BPP; } - for(w = rect->w - (rect->x & 1); w >= 2; w -= 2) { + for(w = dstw - (dstx & 1); w >= 2; w -= 2) { YUVA_IN(y, u, v, a, p, pal); u1 = u; v1 = v; @@ -491,17 +486,17 @@ static void blend_subrect(AVPicture *dst, const AVSubtitleRect *rect) cb[0] = ALPHA_BLEND(a >> 2, cb[0], u, 0); cr[0] = ALPHA_BLEND(a >> 2, cr[0], v, 0); } - p += wrap3 + (wrap3 - rect->w * BPP); - lum += wrap + (wrap - rect->w - rect->x); + p += wrap3 + (wrap3 - dstw * BPP); + lum += wrap + (wrap - dstw - dstx); cb += dst->linesize[1] - width2 - skip2; cr += dst->linesize[2] - width2 - skip2; } - for(h = rect->h - (rect->y & 1); h >= 2; h -= 2) { - lum += rect->x; + for(h = dsth - (dsty & 1); h >= 2; h -= 2) { + lum += dstx; cb += skip2; cr += skip2; - if (rect->x & 1) { + if (dstx & 1) { YUVA_IN(y, u, v, a, p, pal); u1 = u; v1 = v; @@ -521,7 +516,7 @@ static void blend_subrect(AVPicture *dst, const AVSubtitleRect *rect) p += -wrap3 + BPP; lum += -wrap + 1; } - for(w = rect->w - (rect->x & 1); w >= 2; w -= 2) { + for(w = dstw - (dstx & 1); w >= 2; w -= 2) { YUVA_IN(y, u, v, a, p, pal); u1 = u; v1 = v; @@ -576,18 +571,18 @@ static void blend_subrect(AVPicture *dst, const AVSubtitleRect *rect) p += -wrap3 + BPP; lum += -wrap + 1; } - p += wrap3 + (wrap3 - rect->w * BPP); - lum += wrap + (wrap - rect->w - rect->x); + p += wrap3 + (wrap3 - dstw * BPP); + lum += wrap + (wrap - dstw - dstx); cb += dst->linesize[1] - width2 - skip2; cr += dst->linesize[2] - width2 - skip2; } /* handle odd height */ if (h) { - lum += rect->x; + lum += dstx; cb += skip2; cr += skip2; - if (rect->x & 1) { + if (dstx & 1) { YUVA_IN(y, u, v, a, p, pal); lum[0] = ALPHA_BLEND(a, lum[0], y, 0); cb[0] = ALPHA_BLEND(a >> 2, cb[0], u, 0); @@ -597,7 +592,7 @@ static void blend_subrect(AVPicture *dst, const AVSubtitleRect *rect) lum++; p += BPP; } - for(w = rect->w - (rect->x & 1); w >= 2; w -= 2) { + for(w = dstw - (dstx & 1); w >= 2; w -= 2) { YUVA_IN(y, u, v, a, p, pal); u1 = u; v1 = v; @@ -715,7 +710,8 @@ static void video_image_display(VideoState *is) pict.linesize[2] = vp->bmp->pitches[1]; for (i = 0; i < sp->sub.num_rects; i++) - blend_subrect(&pict, &sp->sub.rects[i]); + blend_subrect(&pict, &sp->sub.rects[i], + vp->bmp->w, vp->bmp->h); SDL_UnlockYUVOverlay (vp->bmp); } @@ -869,7 +865,7 @@ static int video_open(VideoState *is){ w = 640; h = 480; } -#ifndef CONFIG_DARWIN +#ifndef SYS_DARWIN screen = SDL_SetVideoMode(w, h, 0, flags); #else /* setting bits_per_pixel = 0 or 32 causes blank video on OS X */ @@ -1262,15 +1258,14 @@ static int queue_picture(VideoState *is, AVFrame *src_frame, double pts) pict.linesize[0] = vp->bmp->pitches[0]; pict.linesize[1] = vp->bmp->pitches[2]; pict.linesize[2] = vp->bmp->pitches[1]; + img_convert_ctx = sws_getCachedContext(img_convert_ctx, + is->video_st->codec->width, is->video_st->codec->height, + is->video_st->codec->pix_fmt, + is->video_st->codec->width, is->video_st->codec->height, + dst_pix_fmt, sws_flags, NULL, NULL, NULL); if (img_convert_ctx == NULL) { - img_convert_ctx = sws_getContext(is->video_st->codec->width, - is->video_st->codec->height, is->video_st->codec->pix_fmt, - is->video_st->codec->width, is->video_st->codec->height, - dst_pix_fmt, sws_flags, NULL, NULL, NULL); - if (img_convert_ctx == NULL) { - fprintf(stderr, "Cannot initialize the conversion context\n"); - exit(1); - } + fprintf(stderr, "Cannot initialize the conversion context\n"); + exit(1); } sws_scale(img_convert_ctx, src_frame->data, src_frame->linesize, 0, is->video_st->codec->height, pict.data, pict.linesize); @@ -1328,6 +1323,21 @@ static int output_picture2(VideoState *is, AVFrame *src_frame, double pts1) return queue_picture(is, src_frame, pts); } +static uint64_t global_video_pkt_pts= AV_NOPTS_VALUE; + +static int my_get_buffer(struct AVCodecContext *c, AVFrame *pic){ + int ret= avcodec_default_get_buffer(c, pic); + uint64_t *pts= av_malloc(sizeof(uint64_t)); + *pts= global_video_pkt_pts; + pic->opaque= pts; + return ret; +} + +static void my_release_buffer(struct AVCodecContext *c, AVFrame *pic){ + if(pic) av_freep(&pic->opaque); + avcodec_default_release_buffer(c, pic); +} + static int video_thread(void *arg) { VideoState *is = arg; @@ -1350,19 +1360,26 @@ static int video_thread(void *arg) /* NOTE: ipts is the PTS of the _first_ picture beginning in this packet, if any */ - pts = 0; - if (pkt->dts != AV_NOPTS_VALUE) - pts = av_q2d(is->video_st->time_base)*pkt->dts; + global_video_pkt_pts= pkt->pts; + len1 = avcodec_decode_video(is->video_st->codec, + frame, &got_picture, + pkt->data, pkt->size); + + if( (decoder_reorder_pts || pkt->dts == AV_NOPTS_VALUE) + && frame->opaque && *(uint64_t*)frame->opaque != AV_NOPTS_VALUE) + pts= *(uint64_t*)frame->opaque; + else if(pkt->dts != AV_NOPTS_VALUE) + pts= pkt->dts; + else + pts= 0; + pts *= av_q2d(is->video_st->time_base); - len1 = avcodec_decode_video(is->video_st->codec, - frame, &got_picture, - pkt->data, pkt->size); // if (len1 < 0) // break; - if (got_picture) { - if (output_picture2(is, frame, pts) < 0) - goto the_end; - } + if (got_picture) { + if (output_picture2(is, frame, pts) < 0) + goto the_end; + } av_free_packet(pkt); if (step) if (cur_stream) @@ -1735,6 +1752,9 @@ static int stream_component_open(VideoState *is, int stream_index) packet_queue_init(&is->videoq); is->video_tid = SDL_CreateThread(video_thread, is); + + enc-> get_buffer= my_get_buffer; + enc->release_buffer= my_release_buffer; break; case CODEC_TYPE_SUBTITLE: is->subtitle_stream = stream_index; @@ -1880,7 +1900,7 @@ static int decode_thread(void *arg) goto fail; } is->ic = ic; -#ifdef CONFIG_NETWORK +#ifdef CONFIG_RTSP_DEMUXER use_play = (ic->iformat == &rtsp_demuxer); #else use_play = 0; @@ -1896,7 +1916,7 @@ static int decode_thread(void *arg) ret = -1; goto fail; } - ic->pb.eof_reached= 0; //FIXME hack, ffplay maybe shouldnt use url_feof() to test for the end + ic->pb.eof_reached= 0; //FIXME hack, ffplay maybe should not use url_feof() to test for the end } /* if seeking requested, we execute it */ @@ -1934,7 +1954,7 @@ static int decode_thread(void *arg) audio_index = i; break; case CODEC_TYPE_VIDEO: - if (video_index < 0 && !video_disable) + if ((video_index < 0 || wanted_video_stream-- > 0) && !video_disable) video_index = i; break; default: @@ -1967,7 +1987,6 @@ static int decode_thread(void *arg) for(;;) { if (is->abort_request) break; -#ifdef CONFIG_NETWORK if (is->paused != is->last_paused) { is->last_paused = is->paused; if (is->paused) @@ -1975,6 +1994,7 @@ static int decode_thread(void *arg) else av_read_play(ic); } +#ifdef CONFIG_RTSP_DEMUXER if (is->paused && ic->iformat == &rtsp_demuxer) { /* wait 10 ms to avoid trying to get another packet */ /* XXX: horrible */ @@ -2081,7 +2101,7 @@ static VideoState *stream_open(const char *filename, AVInputFormat *iformat) is = av_mallocz(sizeof(VideoState)); if (!is) return NULL; - pstrcpy(is->filename, sizeof(is->filename), filename); + av_strlcpy(is->filename, filename, sizeof(is->filename)); is->iformat = iformat; is->ytop = 0; is->xleft = 0; @@ -2340,7 +2360,7 @@ static void event_loop(void) static void opt_frame_size(const char *arg) { - if (parse_image_size(&frame_width, &frame_height, arg) < 0) { + if (av_parse_video_frame_size(&frame_width, &frame_height, arg) < 0) { fprintf(stderr, "Incorrect frame size\n"); exit(1); } @@ -2350,7 +2370,7 @@ static void opt_frame_size(const char *arg) } } -void opt_width(const char *arg) +static void opt_width(const char *arg) { screen_width = atoi(arg); if(screen_width<=0){ @@ -2359,7 +2379,7 @@ void opt_width(const char *arg) } } -void opt_height(const char *arg) +static void opt_height(const char *arg) { screen_height = atoi(arg); if(screen_height<=0){ @@ -2382,15 +2402,15 @@ static void opt_frame_pix_fmt(const char *arg) frame_pix_fmt = avcodec_get_pix_fmt(arg); } -#ifdef CONFIG_NETWORK -void opt_rtp_tcp(void) +#ifdef CONFIG_RTSP_DEMUXER +static void opt_rtp_tcp(void) { /* only tcp protocol */ rtsp_default_protocols = (1 << RTSP_PROTOCOL_RTP_TCP); } #endif -void opt_sync(const char *arg) +static void opt_sync(const char *arg) { if (!strcmp(arg, "audio")) av_sync_type = AV_SYNC_AUDIO_MASTER; @@ -2398,11 +2418,13 @@ void opt_sync(const char *arg) av_sync_type = AV_SYNC_VIDEO_MASTER; else if (!strcmp(arg, "ext")) av_sync_type = AV_SYNC_EXTERNAL_CLOCK; - else + else { show_help(); + exit(1); + } } -void opt_seek(const char *arg) +static void opt_seek(const char *arg) { start_time = parse_date(arg, 1); } @@ -2426,8 +2448,14 @@ static void opt_thread_count(const char *arg) #endif } +static void opt_show_help(void) +{ + show_help(); + exit(0); +} + const OptionDef options[] = { - { "h", 0, {(void*)show_help}, "show help" }, + { "h", 0, {(void*)opt_show_help}, "show help" }, { "x", HAS_ARG, {(void*)opt_width}, "force displayed width", "width" }, { "y", HAS_ARG, {(void*)opt_height}, "force displayed height", "height" }, { "s", HAS_ARG | OPT_VIDEO, {(void*)opt_frame_size}, "set frame size (WxH or abbreviation)", "size" }, @@ -2435,6 +2463,7 @@ const OptionDef options[] = { { "an", OPT_BOOL, {(void*)&audio_disable}, "disable audio" }, { "vn", OPT_BOOL, {(void*)&video_disable}, "disable video" }, { "ast", OPT_INT | HAS_ARG | OPT_EXPERT, {(void*)&wanted_audio_stream}, "", "" }, + { "vst", OPT_INT | HAS_ARG | OPT_EXPERT, {(void*)&wanted_video_stream}, "", "" }, { "ss", HAS_ARG, {(void*)&opt_seek}, "seek to a given position in seconds", "pos" }, { "bytes", OPT_BOOL, {(void*)&seek_by_bytes}, "seek by bytes" }, { "nodisp", OPT_BOOL, {(void*)&display_disable}, "disable graphical display" }, @@ -2446,6 +2475,7 @@ const OptionDef options[] = { { "vismv", HAS_ARG | OPT_EXPERT, {(void*)opt_vismv}, "visualize motion vectors", "" }, { "fast", OPT_BOOL | OPT_EXPERT, {(void*)&fast}, "non spec compliant optimizations", "" }, { "genpts", OPT_BOOL | OPT_EXPERT, {(void*)&genpts}, "generate pts", "" }, + { "drp", OPT_BOOL |OPT_EXPERT, {(void*)&decoder_reorder_pts}, "let decoder reorder pts", ""}, { "lowres", OPT_INT | HAS_ARG | OPT_EXPERT, {(void*)&lowres}, "", "" }, { "skiploop", OPT_INT | HAS_ARG | OPT_EXPERT, {(void*)&skip_loop_filter}, "", "" }, { "skipframe", OPT_INT | HAS_ARG | OPT_EXPERT, {(void*)&skip_frame}, "", "" }, @@ -2453,7 +2483,7 @@ const OptionDef options[] = { { "idct", OPT_INT | HAS_ARG | OPT_EXPERT, {(void*)&idct}, "set idct algo", "algo" }, { "er", OPT_INT | HAS_ARG | OPT_EXPERT, {(void*)&error_resilience}, "set error detection threshold (0-4)", "threshold" }, { "ec", OPT_INT | HAS_ARG | OPT_EXPERT, {(void*)&error_concealment}, "set error concealment options", "bit_mask" }, -#ifdef CONFIG_NETWORK +#ifdef CONFIG_RTSP_DEMUXER { "rtp_tcp", OPT_EXPERT, {(void*)&opt_rtp_tcp}, "force RTP/TCP protocol usage", "" }, #endif { "sync", HAS_ARG | OPT_EXPERT, {(void*)opt_sync}, "set audio-video sync. type (type=audio/video/ext)", "type" }, @@ -2463,7 +2493,7 @@ const OptionDef options[] = { void show_help(void) { - printf("ffplay version " FFMPEG_VERSION ", Copyright (c) 2003-2006 Fabrice Bellard, et al.\n" + printf("ffplay version " FFMPEG_VERSION ", Copyright (c) 2003-2007 Fabrice Bellard, et al.\n" "usage: ffplay [options] input_file\n" "Simple media player\n"); printf("\n"); @@ -2483,13 +2513,12 @@ void show_help(void) "down/up seek backward/forward 1 minute\n" "mouse click seek to percentage in file corresponding to fraction of width\n" ); - exit(1); } -void parse_arg_file(const char *filename) +void opt_input_file(const char *filename) { if (!strcmp(filename, "-")) - filename = "pipe:"; + filename = "pipe:"; input_filename = filename; } @@ -2501,24 +2530,18 @@ int main(int argc, char **argv) /* register all codecs, demux and protocols */ av_register_all(); - #ifdef CONFIG_OS2 - MorphToPM(); // Morph the VIO application to a PM one to be able to use Win* functions + parse_options(argc, argv, options, opt_input_file); - // Make stdout and stderr unbuffered - setbuf( stdout, NULL ); - setbuf( stderr, NULL ); - #endif - - parse_options(argc, argv, options); - - if (!input_filename) + if (!input_filename) { show_help(); + exit(1); + } if (display_disable) { video_disable = 1; } flags = SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER; -#if !defined(__MINGW32__) && !defined(CONFIG_DARWIN) +#if !defined(__MINGW32__) && !defined(SYS_DARWIN) flags |= SDL_INIT_EVENTTHREAD; /* Not supported on win32 or darwin */ #endif if (SDL_Init (flags)) {