Make parse_date return INT64_MIN in case of unparsable input.
[ffmpeg.git] / ffplay.c
index 23917ac..6ec1bcb 100644 (file)
--- a/ffplay.c
+++ b/ffplay.c
  * 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 <math.h>
+#include <limits.h>
 #include "avformat.h"
 #include "swscale.h"
+#include "avstring.h"
 
 #include "version.h"
 #include "cmdutils.h"
 #undef main /* We don't want SDL to override our main() */
 #endif
 
-#ifdef CONFIG_OS2
-#define INCL_DOS
- #include <os2.h>
- #include <stdio.h>
-
- 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
@@ -194,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;
@@ -420,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;\
@@ -435,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);
@@ -469,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;
@@ -494,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;
@@ -524,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;
@@ -579,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);
@@ -600,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;
@@ -718,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);
                 }
@@ -872,7 +865,7 @@ static int video_open(VideoState *is){
         w = 640;
         h = 480;
     }
-#ifndef CONFIG_DARWIN
+#ifndef __APPLE__
     screen = SDL_SetVideoMode(w, h, 0, flags);
 #else
     /* setting bits_per_pixel = 0 or 32 causes blank video on OS X */
@@ -1019,7 +1012,7 @@ static void video_refresh_timer(void *opaque)
 
             /* compute nominal delay */
             delay = vp->pts - is->frame_last_pts;
-            if (delay <= 0 || delay >= 1.0) {
+            if (delay <= 0 || delay >= 2.0) {
                 /* if incorrect delay, use previous one */
                 delay = is->frame_last_delay;
             }
@@ -1265,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);
@@ -1879,7 +1871,7 @@ static int decode_thread(void *arg)
 {
     VideoState *is = arg;
     AVFormatContext *ic;
-    int err, i, ret, video_index, audio_index, use_play;
+    int err, i, ret, video_index, audio_index;
     AVPacket pkt1, *pkt = &pkt1;
     AVFormatParameters params, *ap = &params;
 
@@ -1893,8 +1885,6 @@ static int decode_thread(void *arg)
     url_set_interrupt_cb(decode_interrupt_cb);
 
     memset(ap, 0, sizeof(*ap));
-    ap->initial_pause = 1; /* we force a pause when starting an RTSP
-                              stream */
 
     ap->width = frame_width;
     ap->height= frame_height;
@@ -1908,24 +1898,17 @@ static int decode_thread(void *arg)
         goto fail;
     }
     is->ic = ic;
-#ifdef CONFIG_RTSP_DEMUXER
-    use_play = (ic->iformat == &rtsp_demuxer);
-#else
-    use_play = 0;
-#endif
 
     if(genpts)
         ic->flags |= AVFMT_FLAG_GENPTS;
 
-    if (!use_play) {
-        err = av_find_stream_info(ic);
-        if (err < 0) {
-            fprintf(stderr, "%s: could not find codec parameters\n", is->filename);
-            ret = -1;
-            goto fail;
-        }
-        ic->pb.eof_reached= 0; //FIXME hack, ffplay maybe shouldnt use url_feof() to test for the end
+    err = av_find_stream_info(ic);
+    if (err < 0) {
+        fprintf(stderr, "%s: could not find codec parameters\n", is->filename);
+        ret = -1;
+        goto fail;
     }
+    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 */
     if (start_time != AV_NOPTS_VALUE) {
@@ -1942,18 +1925,6 @@ static int decode_thread(void *arg)
         }
     }
 
-    /* now we can begin to play (RTSP stream only) */
-    av_read_play(ic);
-
-    if (use_play) {
-        err = av_find_stream_info(ic);
-        if (err < 0) {
-            fprintf(stderr, "%s: could not find codec parameters\n", is->filename);
-            ret = -1;
-            goto fail;
-        }
-    }
-
     for(i = 0; i < ic->nb_streams; i++) {
         AVCodecContext *enc = ic->streams[i]->codec;
         switch(enc->codec_type) {
@@ -1962,7 +1933,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:
@@ -2003,7 +1974,7 @@ static int decode_thread(void *arg)
                 av_read_play(ic);
         }
 #ifdef CONFIG_RTSP_DEMUXER
-        if (is->paused && ic->iformat == &rtsp_demuxer) {
+        if (is->paused && !strcmp(ic->iformat->name, "rtsp")) {
             /* wait 10 ms to avoid trying to get another packet */
             /* XXX: horrible */
             SDL_Delay(10);
@@ -2109,7 +2080,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;
@@ -2225,9 +2196,9 @@ static void toggle_pause(void)
 static void step_to_next_frame(void)
 {
     if (cur_stream) {
+        /* if the stream is paused unpause it, then step */
         if (cur_stream->paused)
-            cur_stream->paused=0;
-        cur_stream->video_current_pts = get_video_clock(cur_stream);
+            stream_pause(cur_stream);
     }
     step = 1;
 }
@@ -2368,7 +2339,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);
     }
@@ -2426,13 +2397,19 @@ static 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);
+    }
 }
 
 static void opt_seek(const char *arg)
 {
     start_time = parse_date(arg, 1);
+    if (start_time == INT64_MIN) {
+        fprintf(stderr, "Invalid duration specification: %s\n", arg);
+        exit(1);
+    }
 }
 
 static void opt_debug(const char *arg)
@@ -2454,8 +2431,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" },
@@ -2463,6 +2446,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" },
@@ -2492,7 +2476,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");
@@ -2512,13 +2496,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;
 }
 
@@ -2530,25 +2513,19 @@ 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)
-    flags |= SDL_INIT_EVENTTHREAD; /* Not supported on win32 or darwin */
+#if !defined(__MINGW32__) && !defined(__APPLE__)
+    flags |= SDL_INIT_EVENTTHREAD; /* Not supported on Windows or Mac OS X */
 #endif
     if (SDL_Init (flags)) {
         fprintf(stderr, "Could not initialize SDL - %s\n", SDL_GetError());