]> git.sesse.net Git - ffmpeg/blobdiff - libavformat/oggdec.c
asf: Check return value of more avio_seek calls
[ffmpeg] / libavformat / oggdec.c
index 655da35dd45e7647daf6f883d1d9487e4d152de7..62dab851fc1db5f6af2e53d564b1deaff4a2cfad 100644 (file)
@@ -29,7 +29,6 @@
     DEALINGS IN THE SOFTWARE.
 **/
 
-
 #include <stdio.h>
 #include "oggdec.h"
 #include "avformat.h"
@@ -93,14 +92,24 @@ static int ogg_restore(AVFormatContext *s, int discard)
     ogg->state = ost->next;
 
     if (!discard){
+        struct ogg_stream *old_streams = ogg->streams;
+
         for (i = 0; i < ogg->nstreams; i++)
             av_free (ogg->streams[i].buf);
 
         avio_seek (bc, ost->pos, SEEK_SET);
         ogg->curidx = ost->curidx;
         ogg->nstreams = ost->nstreams;
-        memcpy(ogg->streams, ost->streams,
-               ost->nstreams * sizeof(*ogg->streams));
+        ogg->streams = av_realloc (ogg->streams,
+                                   ogg->nstreams * sizeof (*ogg->streams));
+
+        if (ogg->streams) {
+            memcpy(ogg->streams, ost->streams,
+                   ost->nstreams * sizeof(*ogg->streams));
+        } else {
+            av_free(old_streams);
+            ogg->nstreams = 0;
+        }
     }
 
     av_free (ost);
@@ -201,7 +210,7 @@ static int ogg_read_page(AVFormatContext *s, int *str)
     uint8_t sync[4];
     int sp = 0;
 
-    ret = avio_read (bc, sync, 4);
+    ret = avio_read(bc, sync, 4);
     if (ret < 4)
         return ret < 0 ? ret : AVERROR_EOF;
 
@@ -240,7 +249,8 @@ static int ogg_read_page(AVFormatContext *s, int *str)
 
             for (n = 0; n < ogg->nstreams; n++) {
                 av_freep(&ogg->streams[n].buf);
-                av_freep(&ogg->streams[n].private);
+                if (!ogg->state || ogg->state->streams[n].private != ogg->streams[n].private)
+                    av_freep(&ogg->streams[n].private);
             }
             ogg->curidx   = -1;
             ogg->nstreams = 0;
@@ -258,7 +268,7 @@ static int ogg_read_page(AVFormatContext *s, int *str)
     if(os->psize > 0)
         ogg_new_buf(ogg, idx);
 
-    ret = avio_read (bc, os->segments, nsegs);
+    ret = avio_read(bc, os->segments, nsegs);
     if (ret < nsegs)
         return ret < 0 ? ret : AVERROR_EOF;
 
@@ -291,7 +301,7 @@ static int ogg_read_page(AVFormatContext *s, int *str)
         os->buf = nb;
     }
 
-    ret = avio_read (bc, os->buf + os->bufpos, size);
+    ret = avio_read(bc, os->buf + os->bufpos, size);
     if (ret < size)
         return ret < 0 ? ret : AVERROR_EOF;
 
@@ -320,7 +330,7 @@ static int ogg_packet(AVFormatContext *s, int *str, int *dstart, int *dsize,
         idx = ogg->curidx;
 
         while (idx < 0){
-            ret = ogg_read_page (s, &idx);
+            ret = ogg_read_page(s, &idx);
             if (ret < 0)
                 return ret;
         }
@@ -436,7 +446,7 @@ static int ogg_get_headers(AVFormatContext *s)
     int ret;
 
     do{
-        ret = ogg_packet (s, NULL, NULL, NULL, NULL);
+        ret = ogg_packet(s, NULL, NULL, NULL, NULL);
         if (ret < 0)
             return ret;
     }while (!ogg->headers);
@@ -451,6 +461,7 @@ static int ogg_get_length(AVFormatContext *s)
     struct ogg *ogg = s->priv_data;
     int i;
     int64_t size, end;
+    int streams_left=0;
 
     if(!s->pb->seekable)
         return 0;
@@ -472,8 +483,14 @@ static int ogg_get_length(AVFormatContext *s)
             ogg->streams[i].codec) {
             s->streams[i]->duration =
                 ogg_gptopts (s, i, ogg->streams[i].granule, NULL);
-            if (s->streams[i]->start_time != AV_NOPTS_VALUE)
+            if (s->streams[i]->start_time != AV_NOPTS_VALUE){
                 s->streams[i]->duration -= s->streams[i]->start_time;
+                streams_left-= (ogg->streams[i].got_start==-1);
+                ogg->streams[i].got_start= 1;
+            }else if(!ogg->streams[i].got_start){
+                ogg->streams[i].got_start= -1;
+                streams_left++;
+            }
         }
     }
 
@@ -484,9 +501,15 @@ static int ogg_get_length(AVFormatContext *s)
     while (!ogg_read_page (s, &i)){
         if (ogg->streams[i].granule != -1 && ogg->streams[i].granule != 0 &&
             ogg->streams[i].codec) {
-            s->streams[i]->duration -=
-                ogg_gptopts (s, i, ogg->streams[i].granule, NULL);
-            break;
+            if(s->streams[i]->duration && s->streams[i]->start_time == AV_NOPTS_VALUE && !ogg->streams[i].got_start){
+                int64_t start= ogg_gptopts (s, i, ogg->streams[i].granule, NULL);
+                if(av_rescale_q(start, s->streams[i]->time_base, AV_TIME_BASE_Q) > AV_TIME_BASE)
+                    s->streams[i]->duration -= start;
+                ogg->streams[i].got_start= 1;
+                streams_left--;
+            }
+            if(streams_left<=0)
+                break;
         }
     }
     ogg_restore (s, 0);
@@ -500,10 +523,9 @@ static int ogg_read_header(AVFormatContext *s, AVFormatParameters *ap)
     int ret, i;
     ogg->curidx = -1;
     //linear headers seek from start
-    ret = ogg_get_headers (s);
-    if (ret < 0){
+    ret = ogg_get_headers(s);
+    if (ret < 0)
         return ret;
-    }
 
     for (i = 0; i < ogg->nstreams; i++)
         if (ogg->streams[i].header < 0)
@@ -550,15 +572,16 @@ static int ogg_read_packet(AVFormatContext *s, AVPacket *pkt)
 {
     struct ogg *ogg;
     struct ogg_stream *os;
-    int idx = -1;
+    int idx = -1, ret;
     int pstart, psize;
     int64_t fpos, pts, dts;
 
     //Get an ogg packet
 retry:
     do{
-        if (ogg_packet (s, &idx, &pstart, &psize, &fpos) < 0)
-            return AVERROR(EIO);
+        ret = ogg_packet(s, &idx, &pstart, &psize, &fpos);
+        if (ret < 0)
+            return ret;
     }while (idx < 0 || !s->streams[idx]);
 
     ogg = s->priv_data;
@@ -572,8 +595,9 @@ retry:
     os->keyframe_seek = 0;
 
     //Alloc a pkt
-    if (av_new_packet (pkt, psize) < 0)
-        return AVERROR(EIO);
+    ret = av_new_packet(pkt, psize);
+    if (ret < 0)
+        return ret;
     pkt->stream_index = idx;
     memcpy (pkt->data, os->buf + pstart, psize);
 
@@ -603,15 +627,15 @@ static int64_t ogg_read_timestamp(AVFormatContext *s, int stream_index,
                                   int64_t *pos_arg, int64_t pos_limit)
 {
     struct ogg *ogg = s->priv_data;
-    struct ogg_stream *os = ogg->streams + stream_index;
     AVIOContext *bc = s->pb;
     int64_t pts = AV_NOPTS_VALUE;
-    int i;
+    int i = -1;
     avio_seek(bc, *pos_arg, SEEK_SET);
     ogg_reset(ogg);
 
     while (avio_tell(bc) < pos_limit && !ogg_packet(s, &i, NULL, NULL, pos_arg)) {
         if (i == stream_index) {
+            struct ogg_stream *os = ogg->streams + stream_index;
             pts = ogg_calc_pts(s, i, NULL);
             if (os->keyframe_seek && !(os->pflags & AV_PKT_FLAG_KEY))
                 pts = AV_NOPTS_VALUE;
@@ -637,6 +661,7 @@ static int ogg_read_seek(AVFormatContext *s, int stream_index,
         os->keyframe_seek = 1;
 
     ret = av_seek_frame_binary(s, stream_index, timestamp, flags);
+    os = ogg->streams + stream_index;
     if (ret < 0)
         os->keyframe_seek = 0;
     return ret;