few bistream fixes and verbosity tweaks
[ffmpeg.git] / ffplay.c
index 6fbb91e..2df39d9 100644 (file)
--- a/ffplay.c
+++ b/ffplay.c
 #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
+
 #if defined(__linux__)
 #define HAVE_X11
 #endif
@@ -46,7 +63,7 @@
 #define SDL_AUDIO_BUFFER_SIZE 1024
 
 /* no AV sync correction is done if below the AV sync threshold */
-#define AV_SYNC_THRESHOLD 0.08
+#define AV_SYNC_THRESHOLD 0.01
 /* no AV correction is done if too big error */
 #define AV_NOSYNC_THRESHOLD 10.0
 
@@ -92,6 +109,7 @@ typedef struct VideoState {
     int paused;
     int last_paused;
     int seek_req;
+    int seek_flags;
     int64_t seek_pos;
     AVFormatContext *ic;
     int dtg_active_format;
@@ -113,7 +131,7 @@ typedef struct VideoState {
     /* samples output by the codec. we reserve more space for avsync
        compensation */
     uint8_t audio_buf[(AVCODEC_MAX_AUDIO_FRAME_SIZE * 3) / 2]; 
-    int audio_buf_size; /* in bytes */
+    unsigned int audio_buf_size; /* in bytes */
     int audio_buf_index; /* in bytes */
     AVPacket audio_pkt;
     uint8_t *audio_pkt_data;
@@ -143,6 +161,9 @@ typedef struct VideoState {
     SDL_mutex *pictq_mutex;
     SDL_cond *pictq_cond;
     
+    SDL_mutex *video_decoder_mutex;
+    SDL_mutex *audio_decoder_mutex;
+
     //    QETimer *video_timer;
     char filename[1024];
     int width, height, xleft, ytop;
@@ -168,6 +189,11 @@ static int64_t start_time = AV_NOPTS_VALUE;
 static int debug = 0;
 static int debug_mv = 0;
 static int step = 0;
+static int thread_count = 1;
+static int workaround_bugs = 1;
+static int fast = 0;
+static int lowres = 0;
+static int idct = FF_IDCT_AUTO;
 
 /* current context */
 static int is_full_screen;
@@ -195,6 +221,7 @@ static void packet_queue_flush(PacketQueue *q)
     for(pkt = q->first_pkt; pkt != NULL; pkt = pkt1) {
         pkt1 = pkt->next;
         av_free_packet(&pkt->pkt);
+        av_freep(&pkt);
     }
     q->last_pkt = NULL;
     q->first_pkt = NULL;
@@ -583,10 +610,11 @@ static double get_master_clock(VideoState *is)
 }
 
 /* seek in the stream */
-static void stream_seek(VideoState *is, int64_t pos)
+static void stream_seek(VideoState *is, int64_t pos, int rel)
 {
     is->seek_pos = pos;
     is->seek_req = 1;
+    is->seek_flags = rel < 0 ? AVSEEK_FLAG_BACKWARD : 0;
 }
 
 /* pause or resume the video */
@@ -609,7 +637,7 @@ static void video_refresh_timer(void *opaque)
     if (is->video_st) {
         if (is->pictq_size == 0) {
             /* if no picture, need to wait */
-            schedule_refresh(is, 40);
+            schedule_refresh(is, 1);
         } else {
             /* dequeue the picture */
             vp = &is->pictq[is->pictq_rindex];
@@ -839,16 +867,6 @@ static int output_picture2(VideoState *is, AVFrame *src_frame, double pts1)
     
     pts = pts1;
 
-    /* if B frames are present, and if the current picture is a I
-       or P frame, we use the last pts */
-    if (is->video_st->codec.has_b_frames && 
-        src_frame->pict_type != FF_B_TYPE) {
-        /* use last pts */
-        pts = is->video_last_P_pts;
-        /* get the pts for the next I or P frame if present */
-        is->video_last_P_pts = pts1;
-    }
-
     if (pts != 0) {
         /* update video clock with pts, if present */
         is->video_clock = pts;
@@ -856,8 +874,7 @@ static int output_picture2(VideoState *is, AVFrame *src_frame, double pts1)
         pts = is->video_clock;
     }
     /* update video clock for next frame */
-    frame_delay = (double)is->video_st->codec.frame_rate_base / 
-        (double)is->video_st->codec.frame_rate;
+    frame_delay = av_q2d(is->video_st->codec.time_base);
     /* for MPEG2, the frame can be repeated, so we update the
        clock accordingly */
     if (src_frame->repeat_pict) {
@@ -898,28 +915,20 @@ 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->pts != AV_NOPTS_VALUE)
-            pts = (double)pkt->pts / AV_TIME_BASE;
-
-        if (is->video_st->codec.codec_id == CODEC_ID_RAWVIDEO) {
-            avpicture_fill((AVPicture *)frame, pkt->data, 
-                           is->video_st->codec.pix_fmt,
-                           is->video_st->codec.width,
-                           is->video_st->codec.height);
-            frame->pict_type = FF_I_TYPE;
-            if (output_picture2(is, frame, pts) < 0)
-                goto the_end;
-        } else {
+        if (pkt->dts != AV_NOPTS_VALUE)
+            pts = av_q2d(is->video_st->time_base)*pkt->dts;
+
+            SDL_LockMutex(is->video_decoder_mutex);
             len1 = avcodec_decode_video(&is->video_st->codec, 
                                         frame, &got_picture, 
                                         pkt->data, pkt->size);
-            if (len1 < 0)
-                break;
+            SDL_UnlockMutex(is->video_decoder_mutex);
+//            if (len1 < 0)
+//                break;
             if (got_picture) {
                 if (output_picture2(is, frame, pts) < 0)
                     goto the_end;
             }
-        }
         av_free_packet(pkt);
         if (step) 
             if (cur_stream)
@@ -1038,9 +1047,11 @@ static int audio_decode_frame(VideoState *is, uint8_t *audio_buf, double *pts_pt
     for(;;) {
         /* NOTE: the audio packet can contain several frames */
         while (is->audio_pkt_size > 0) {
+            SDL_LockMutex(is->audio_decoder_mutex);
             len1 = avcodec_decode_audio(&is->audio_st->codec, 
                                         (int16_t *)audio_buf, &data_size, 
                                         is->audio_pkt_data, is->audio_pkt_size);
+            SDL_UnlockMutex(is->audio_decoder_mutex);
             if (len1 < 0) {
                 /* if error, we skip the frame */
                 is->audio_pkt_size = 0;
@@ -1085,7 +1096,7 @@ static int audio_decode_frame(VideoState *is, uint8_t *audio_buf, double *pts_pt
         
         /* if update the audio clock with the pts */
         if (pkt->pts != AV_NOPTS_VALUE) {
-            is->audio_clock = (double)pkt->pts / AV_TIME_BASE;
+            is->audio_clock = av_q2d(is->audio_st->time_base)*pkt->pts;
         }
     }
 }
@@ -1166,9 +1177,21 @@ static int stream_component_open(VideoState *is, int stream_index)
     }
 
     codec = avcodec_find_decoder(enc->codec_id);
+    enc->debug_mv = debug_mv;
+    enc->debug = debug;
+    enc->workaround_bugs = workaround_bugs;
+    enc->lowres = lowres;
+    if(lowres) enc->flags |= CODEC_FLAG_EMU_EDGE;
+    enc->idct_algo= idct;
+    if(fast) enc->flags2 |= CODEC_FLAG2_FAST;
     if (!codec ||
         avcodec_open(enc, codec) < 0)
         return -1;
+#if defined(HAVE_THREADS)
+    if(thread_count>1)
+        avcodec_thread_init(enc, thread_count);
+#endif
+    enc->thread_count= thread_count;
     switch(enc->codec_type) {
     case CODEC_TYPE_AUDIO:
         is->audio_stream = stream_index;
@@ -1197,8 +1220,6 @@ static int stream_component_open(VideoState *is, int stream_index)
 
         packet_queue_init(&is->videoq);
         is->video_tid = SDL_CreateThread(video_thread, is);
-        enc->debug = debug;
-        enc->debug_mv = debug_mv;
         break;
     default:
         break;
@@ -1319,6 +1340,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
     }
 
     /* if seeking requested, we execute it */
@@ -1329,7 +1351,7 @@ static int decode_thread(void *arg)
         /* add the stream start time */
         if (ic->start_time != AV_NOPTS_VALUE)
             timestamp += ic->start_time;
-        ret = av_seek_frame(ic, -1, timestamp);
+        ret = av_seek_frame(ic, -1, timestamp, AVSEEK_FLAG_BACKWARD);
         if (ret < 0) {
             fprintf(stderr, "%s: could not seek to position %0.3f\n", 
                     is->filename, (double)timestamp / AV_TIME_BASE);
@@ -1406,7 +1428,7 @@ static int decode_thread(void *arg)
 #endif
         if (is->seek_req) {
             /* XXX: must lock decoder threads */
-            ret = av_seek_frame(is->ic, -1, is->seek_pos);
+            ret = av_seek_frame(is->ic, -1, is->seek_pos, is->seek_flags);
             if (ret < 0) {
                 fprintf(stderr, "%s: error while seeking\n", is->ic->filename);
             }else{
@@ -1415,6 +1437,9 @@ static int decode_thread(void *arg)
                 }
                 if (is->video_stream >= 0) {
                     packet_queue_flush(&is->videoq);
+                    SDL_LockMutex(is->video_decoder_mutex);
+                    avcodec_flush_buffers(&ic->streams[video_index]->codec);
+                    SDL_UnlockMutex(is->video_decoder_mutex);
                 }
             }
             is->seek_req = 0;
@@ -1422,14 +1447,19 @@ static int decode_thread(void *arg)
 
         /* if the queue are full, no need to read more */
         if (is->audioq.size > MAX_AUDIOQ_SIZE ||
-            is->videoq.size > MAX_VIDEOQ_SIZE) {
+            is->videoq.size > MAX_VIDEOQ_SIZE || 
+            url_feof(&ic->pb)) {
             /* wait 10 ms */
             SDL_Delay(10);
             continue;
         }
         ret = av_read_frame(ic, pkt);
         if (ret < 0) {
-            break;
+           if (url_feof(&ic->pb) && url_ferror(&ic->pb) == 0) {
+                SDL_Delay(100); /* wait for user event */
+               continue;
+           } else
+               break;
         }
         if (pkt->stream_index == is->audio_stream) {
             packet_queue_put(&is->audioq, pkt);
@@ -1489,6 +1519,9 @@ static VideoState *stream_open(const char *filename, AVInputFormat *iformat)
     /* start video display */
     is->pictq_mutex = SDL_CreateMutex();
     is->pictq_cond = SDL_CreateCond();
+    
+    is->audio_decoder_mutex = SDL_CreateMutex();
+    is->video_decoder_mutex = SDL_CreateMutex();
 
     /* add the refresh timer to draw the picture */
     schedule_refresh(is, 40);
@@ -1520,6 +1553,8 @@ static void stream_close(VideoState *is)
     }
     SDL_DestroyMutex(is->pictq_mutex);
     SDL_DestroyCond(is->pictq_cond);
+    SDL_DestroyMutex(is->audio_decoder_mutex);
+    SDL_DestroyMutex(is->video_decoder_mutex);
 }
 
 void stream_cycle_channel(VideoState *is, int codec_type)
@@ -1674,7 +1709,7 @@ void event_loop(void)
                 if (cur_stream) {
                     pos = get_master_clock(cur_stream);
                     pos += incr;
-                    stream_seek(cur_stream, (int64_t)(pos * AV_TIME_BASE));
+                    stream_seek(cur_stream, (int64_t)(pos * AV_TIME_BASE), incr);
                 }
                 break;
             default:
@@ -1696,7 +1731,7 @@ void event_loop(void)
                ss = (ns%60);
                fprintf(stderr, "Seek to %2.0f%% (%2d:%02d:%02d) of total duration (%2d:%02d:%02d)       \n", frac*100,
                        hh, mm, ss, thh, tmm, tss);
-               stream_seek(cur_stream, (int64_t)(cur_stream->ic->start_time+frac*cur_stream->ic->duration));
+               stream_seek(cur_stream, (int64_t)(cur_stream->ic->start_time+frac*cur_stream->ic->duration), 0);
            }
            break;
         case SDL_VIDEORESIZE:
@@ -1791,6 +1826,14 @@ static void opt_vismv(const char *arg)
 {
     debug_mv = atoi(arg);
 }
+
+static void opt_thread_count(const char *arg)
+{
+    thread_count= atoi(arg);
+#if !defined(HAVE_THREADS)
+    fprintf(stderr, "Warning: not compiled with thread support, using thread emulation\n");
+#endif
+}
     
 const OptionDef options[] = {
     { "h", 0, {(void*)show_help}, "show help" },    
@@ -1808,11 +1851,16 @@ const OptionDef options[] = {
     { "img", HAS_ARG, {(void*)opt_image_format}, "force image format", "img_fmt" },
     { "stats", OPT_BOOL | OPT_EXPERT, {(void*)&show_status}, "show status", "" },
     { "debug", HAS_ARG | OPT_EXPERT, {(void*)opt_debug}, "print specific debug info", "" },
+    { "bug", OPT_INT | HAS_ARG | OPT_EXPERT, {(void*)&workaround_bugs}, "workaround bugs", "" },
     { "vismv", HAS_ARG | OPT_EXPERT, {(void*)opt_vismv}, "visualize motion vectors", "" },
+    { "fast", OPT_BOOL | OPT_EXPERT, {(void*)&fast}, "non spec compliant optimizations", "" },
+    { "lowres", OPT_INT | HAS_ARG | OPT_EXPERT, {(void*)&lowres}, "", "" },
+    { "idct", OPT_INT | HAS_ARG | OPT_EXPERT, {(void*)&idct}, "set idct algo",  "algo" },
 #ifdef CONFIG_NETWORK
     { "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" },
+    { "sync", HAS_ARG | OPT_EXPERT, {(void*)opt_sync}, "set audio-video sync. type (type=audio/video/ext)", "type" },
+    { "threads", HAS_ARG | OPT_EXPERT, {(void*)opt_thread_count}, "thread count", "count" },
     { NULL, },
 };
 
@@ -1855,6 +1903,14 @@ 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
+      // Make stdout and stderr unbuffered
+      setbuf( stdout, NULL );
+      setbuf( stderr, NULL );
+    #endif
+
     parse_options(argc, argv, options);
 
     if (!input_filename)