[FFmpeg-soc] [soc]: r4446 - seek_api/mpeg.c

spyfeng subversion at mplayerhq.hu
Sun Jun 14 18:39:19 CEST 2009


Author: spyfeng
Date: Sun Jun 14 18:39:19 2009
New Revision: 4446

Log:
fix some seek bugs and handle AVSEEK_FLAG_ANY. 
still need more test.

Modified:
   seek_api/mpeg.c

Modified: seek_api/mpeg.c
==============================================================================
--- seek_api/mpeg.c	Sat Jun 13 12:20:11 2009	(r4445)
+++ seek_api/mpeg.c	Sun Jun 14 18:39:19 2009	(r4446)
@@ -592,20 +592,21 @@ static int64_t mpegps_read_dts(AVFormatC
 static int find_keyframe(AVFormatContext *s, int stream_index, int64_t *ret_pos, int64_t *pts, int64_t target_ts, int flags)
 {
     AVPacket pkt1, *pkt = &pkt1;
-    int64_t pre_pts, pre_pos, size;
+    int64_t pre_pts = *pts, pre_pos = *ret_pos;
 
+    url_fseek(s->pb, *ret_pos, SEEK_SET);
     for (;;) {
         if (av_read_frame(s, pkt) < 0)
             return -1;
 
-        size = pkt->size;
         av_free_packet(pkt);
         if (!(pkt->flags & PKT_FLAG_KEY) || (stream_index != pkt->stream_index)) {
-            *ret_pos += size;
-            continue;
+            if (!(flags & AVSEEK_FLAG_ANY))
+                continue;
         }
 
         *pts = pkt->pts;
+        *ret_pos = pkt->pos;
 
         if (*pts < target_ts) {
             pre_pts = *pts;
@@ -614,7 +615,7 @@ static int find_keyframe(AVFormatContext
             break;
     }
 
-    if (flags & AVSEEK_FLAG_BACKWARD && ((pre_pts + *pts)) >> 2 > target_ts) {
+    if (flags & AVSEEK_FLAG_BACKWARD && ((pre_pts + *pts) >> 2 > target_ts)) {
         *ret_pos = pre_pts;
         *pts = pre_pos;
     }
@@ -626,12 +627,13 @@ static int mpegps_read_seek(struct AVFor
 {
     AVStream* st;
     int index;
-    int64_t pos, av_uninit(pos_min), av_uninit(pos_max), pos_limit;
+    int64_t pos, ret_pos, av_uninit(pos_min), av_uninit(pos_max), pos_limit;
     int64_t ts_min, ts_max, ret_ts, pts;
 
     if (min_ts > ts || max_ts < ts)
         return -1;
-
+    if (ts < 0)
+        ts = 0;
     if (stream_index < 0) {
         stream_index= av_find_default_stream_index(s);
         if(stream_index < 0)
@@ -641,12 +643,6 @@ static int mpegps_read_seek(struct AVFor
     } else
         st = s->streams[stream_index];
 
-    if (ts < 0) {
-        pts = ts = 0;
-        url_fseek(s->pb, 0, SEEK_SET);
-        goto success;
-    }
-
     if (st->discard >= AVDISCARD_ALL) {
         av_log(s, AV_LOG_ERROR, "Not active stream!\n");
         return -1;
@@ -660,30 +656,49 @@ static int mpegps_read_seek(struct AVFor
             e = &st->index_entries[index];
             pos = e->pos;
             pts = e->timestamp;
-            url_fseek(s->pb, pos, SEEK_SET);
             av_log(s, AV_LOG_DEBUG, "the seek pos = %"PRId64", pts  = %"PRId64", targe timestamp = %"PRId64"\n", pos, pts, ts);
 
-            if (pts == ts) { // find the target timestamp
+            if (pts == ts || (ts < pts && index == 0)) { // find the target timestamp
+                url_fseek(s->pb, pos, SEEK_SET);
                 goto success;
             }
+
+            if (flags & AVSEEK_FLAG_ANY) {
+
+                while(pts > ts) { // find the index timestamp smaller than target timestamp
+                    index--;
+                    pts = st->index_entries[index].timestamp;
+                    pos = st->index_entries[index].pos;
+                }
+
+                if (find_keyframe(s, stream_index, &pos, &pts, ts, flags) == 0) {
+                    url_fseek(s->pb, pos, SEEK_SET);
+                    goto success;
+                } else {
+                    return -1;
+                }
+            }
         }
      }
     // search the scr use binary search
-    ts_max=
-    ts_min= AV_NOPTS_VALUE;
-    pos_limit= -1;
-    pos= av_gen_search(s, stream_index, ts, pos_min, pos_max, pos_limit, ts_min, ts_max, flags, &ret_ts, mpegps_read_dts);
+    ts_max =
+    ts_min = AV_NOPTS_VALUE;
+    pos_limit = -1;
+    if (flags & AVSEEK_FLAG_ANY) // add flag AVSEEK_FLAG_BACKWARD in order to get the smaller timestamp frame, then we can use av_read_frame() get next frame
+        ret_pos = av_gen_search(s, stream_index, ts, pos_min, pos_max, pos_limit, ts_min, ts_max, flags | AVSEEK_FLAG_BACKWARD, &ret_ts, mpegps_read_dts);
+    else
+        ret_pos = av_gen_search(s, stream_index, ts, pos_min, pos_max, pos_limit, ts_min, ts_max, flags, &ret_ts, mpegps_read_dts);
     av_log(s, AV_LOG_DEBUG, "the seek pos = %"PRId64", ret_ts  = %"PRId64"\n", pos, ret_ts);
-    if(pos<0)
+    if (ret_pos<0)
         return -1;
-
-    url_fseek(s->pb, pos, SEEK_SET);
-    if (find_keyframe(s, stream_index, &pos, &ret_ts, ts, flags) == 0) {
+    if (ret_ts < pts) { // in order to find the keyframe closer to target timestamp
+        pos = ret_pos;
+        pts = ret_ts;
+    }
+    if (find_keyframe(s, stream_index, &pos, &pts, ts, flags) == 0) {
         url_fseek(s->pb, pos, SEEK_SET);
-        pts =  ret_ts;
         goto success;
     } else {
-        av_update_cur_dts(s, st, ret_ts);
         return -1;
     }
 success:


More information about the FFmpeg-soc mailing list