]> git.sesse.net Git - ffmpeg/blobdiff - libavformat/ogg2.c
Check context before accessing its field.
[ffmpeg] / libavformat / ogg2.c
index 2d88a92bcfd0f0c528802eabcd7dfee79b3e4b41..ebc7567d58f88fa55d341a942941b104a2a4801d 100644 (file)
@@ -2,7 +2,7 @@
  * Ogg bitstream support
  * Luca Barbato <lu_zero@gentoo.org>
  * Based on tcvp implementation
- * 
+ *
  */
 
 /**
 
 static ogg_codec_t *ogg_codecs[] = {
     &vorbis_codec,
+    &theora_codec,
+    &flac_codec,
+    &old_flac_codec,
+    &ogm_video_codec,
+    &ogm_audio_codec,
+    &ogm_old_codec,
     NULL
 };
 
-#if 0                           // CONFIG_ENCODERS
+#if 0                           // CONFIG_MUXERS
 static int
 ogg_write_header (AVFormatContext * avfcontext)
 {
@@ -60,10 +66,10 @@ ogg_write_trailer (AVFormatContext * avfcontext)
 }
 
 
-static AVOutputFormat ogg_oformat = {
+AVOutputFormat ogg_muxer = {
     "ogg",
-    "Ogg Vorbis",
-    "audio/x-vorbis",
+    "Ogg format",
+    "application/ogg",
     "ogg",
     sizeof (OggContext),
     CODEC_ID_VORBIS,
@@ -72,7 +78,7 @@ static AVOutputFormat ogg_oformat = {
     ogg_write_packet,
     ogg_write_trailer,
 };
-#endif //CONFIG_ENCODERS
+#endif //CONFIG_MUXERS
 
 //FIXME We could avoid some structure duplication
 static int
@@ -85,6 +91,7 @@ ogg_save (AVFormatContext * s)
     ost->pos = url_ftell (&s->pb);;
     ost->curidx = ogg->curidx;
     ost->next = ogg->state;
+    ost->nstreams = ogg->nstreams;
     memcpy(ost->streams, ogg->streams, ogg->nstreams * sizeof(*ogg->streams));
 
     for (i = 0; i < ogg->nstreams; i++){
@@ -118,8 +125,9 @@ ogg_restore (AVFormatContext * s, int discard)
 
         url_fseek (bc, ost->pos, SEEK_SET);
         ogg->curidx = ost->curidx;
-        memcpy (ogg->streams, ost->streams,
-        ogg->nstreams * sizeof (*ogg->streams));
+        ogg->nstreams = ost->nstreams;
+        memcpy(ogg->streams, ost->streams,
+               ost->nstreams * sizeof(*ogg->streams));
     }
 
     av_free (ost);
@@ -188,20 +196,35 @@ ogg_new_stream (AVFormatContext * s, uint32_t serial)
     os = ogg->streams + idx;
     os->serial = serial;
     os->bufsize = DECODER_BUFFER_SIZE;
-    os->buf = av_malloc (os->bufsize);
-    memset (os->buf, 0, os->bufsize);
+    os->buf = av_malloc(os->bufsize);
     os->header = -1;
 
     st = av_new_stream (s, idx);
     if (!st)
-        return AVERROR_NOMEM;
+        return AVERROR(ENOMEM);
 
     av_set_pts_info(st, 64, 1, 1000000);
-    st->start_time = 0;
 
     return idx;
 }
 
+static int
+ogg_new_buf(ogg_t *ogg, int idx)
+{
+    ogg_stream_t *os = ogg->streams + idx;
+    uint8_t *nb = av_malloc(os->bufsize);
+    int size = os->bufpos - os->pstart;
+    if(os->buf){
+        memcpy(nb, os->buf + os->pstart, size);
+        av_free(os->buf);
+    }
+    os->buf = nb;
+    os->bufpos = size;
+    os->pstart = 0;
+
+    return 0;
+}
+
 static int
 ogg_read_page (AVFormatContext * s, int *str)
 {
@@ -215,7 +238,7 @@ ogg_read_page (AVFormatContext * s, int *str)
     uint32_t seq;
     uint32_t crc;
     int size, idx;
-    char sync[4];
+    uint8_t sync[4];
     int sp = 0;
 
     if (get_buffer (bc, sync, 4) < 4)
@@ -259,6 +282,9 @@ ogg_read_page (AVFormatContext * s, int *str)
 
     os = ogg->streams + idx;
 
+    if(os->psize > 0)
+        ogg_new_buf(ogg, idx);
+
     if (get_buffer (bc, os->segments, nsegs) < nsegs)
         return -1;
 
@@ -284,7 +310,6 @@ ogg_read_page (AVFormatContext * s, int *str)
 
     if (os->bufsize - os->bufpos < size){
         uint8_t *nb = av_malloc (os->bufsize *= 2);
-        memset (nb, 0, os->bufsize);
         memcpy (nb, os->buf, os->bufpos);
         av_free (os->buf);
         os->buf = nb;
@@ -305,7 +330,7 @@ ogg_read_page (AVFormatContext * s, int *str)
 }
 
 static int
-ogg_packet (AVFormatContext * s, int *str)
+ogg_packet (AVFormatContext * s, int *str, int *dstart, int *dsize)
 {
     ogg_t *ogg = s->priv_data;
     int idx;
@@ -358,14 +383,6 @@ ogg_packet (AVFormatContext * s, int *str)
         }
 
         if (!complete && os->segp == os->nsegs){
-            uint8_t *nb = av_malloc (os->bufsize);
-            int size = os->bufpos - os->pstart;
-            memset (nb, 0, os->bufsize);
-            memcpy (nb, os->buf + os->pstart, size);
-            av_free (os->buf);
-            os->buf = nb;
-            os->bufpos = size;
-            os->pstart = 0;
             ogg->curidx = -1;
         }
     }while (!complete);
@@ -396,6 +413,12 @@ ogg_packet (AVFormatContext * s, int *str)
             os->codec->packet (s, idx);
         if (str)
             *str = idx;
+        if (dstart)
+            *dstart = os->pstart;
+        if (dsize)
+            *dsize = os->psize;
+        os->pstart += os->psize;
+        os->psize = 0;
     }
 
     os->seq++;
@@ -411,7 +434,7 @@ ogg_get_headers (AVFormatContext * s)
     ogg_t *ogg = s->priv_data;
 
     do{
-        if (ogg_packet (s, NULL) < 0)
+        if (ogg_packet (s, NULL, NULL, NULL) < 0)
             return -1;
     }while (!ogg->headers);
 
@@ -425,17 +448,14 @@ ogg_get_headers (AVFormatContext * s)
 static uint64_t
 ogg_gptopts (AVFormatContext * s, int i, uint64_t gp)
 {
-    AVStream *st = s->streams[i];
-    AVCodecContext *codec = &st->codec;
+    ogg_t *ogg = s->priv_data;
+    ogg_stream_t *os = ogg->streams + i;
     uint64_t pts = AV_NOPTS_VALUE;
 
-    if (codec->codec_type == CODEC_TYPE_AUDIO){
-        pts = gp * 1000000LL / codec->sample_rate;
-    }else if (codec->codec_type == CODEC_TYPE_VIDEO){
-//FIXME
-        pts = gp * 1000000LL / codec->sample_rate;
-//  pts = gp * st->video.frame_rate.den * 27000000LL /
-//      st->video.frame_rate.num;
+    if(os->codec->gptopts){
+        pts = os->codec->gptopts(s, i, gp);
+    } else {
+        pts = gp;
     }
 
     return pts;
@@ -446,21 +466,27 @@ static int
 ogg_get_length (AVFormatContext * s)
 {
     ogg_t *ogg = s->priv_data;
-    URLContext *h = url_fileno (&s->pb);
     int idx = -1, i;
-//FIXME: get the right ctx flag to know if is seekable or not
-//    if(ogg->f->flags & URL_FLAG_STREAMED)
-//  return 0;
+    offset_t size, end;
+
+    if(s->pb.is_streamed)
+        return 0;
 
 // already set
     if (s->duration != AV_NOPTS_VALUE)
         return 0;
 
+    size = url_fsize(&s->pb);
+    if(size < 0)
+        return 0;
+    end = size > MAX_PAGE_SIZE? size - MAX_PAGE_SIZE: size;
+
     ogg_save (s);
-    url_seek (h, -MAX_PAGE_SIZE, SEEK_END);
+    url_fseek (&s->pb, end, SEEK_SET);
 
     while (!ogg_read_page (s, &i)){
-        if (ogg->streams[i].granule != -1 && ogg->streams[i].granule != 0)
+        if (ogg->streams[i].granule != -1 && ogg->streams[i].granule != 0 &&
+            ogg->streams[i].codec)
             idx = i;
     }
 
@@ -469,7 +495,17 @@ ogg_get_length (AVFormatContext * s)
             ogg_gptopts (s, idx, ogg->streams[idx].granule);
     }
 
-    ogg->size = url_filesize(h);
+    ogg->size = size;
+    ogg_restore (s, 0);
+    ogg_save (s);
+    while (!ogg_read_page (s, &i)) {
+        if (i == idx && ogg->streams[i].granule != -1 && ogg->streams[i].granule != 0)
+            break;
+    }
+    if (i == idx) {
+        s->streams[idx]->start_time = ogg_gptopts (s, idx, ogg->streams[idx].granule);
+        s->streams[idx]->duration -= s->streams[idx]->start_time;
+    }
     ogg_restore (s, 0);
 
     return 0;
@@ -500,29 +536,28 @@ ogg_read_packet (AVFormatContext * s, AVPacket * pkt)
     ogg_t *ogg;
     ogg_stream_t *os;
     int idx = -1;
+    int pstart, psize;
 
-    //Get an ogg packet 
+    //Get an ogg packet
     do{
-        if (ogg_packet (s, &idx) < 0)
-            return AVERROR_IO;
+        if (ogg_packet (s, &idx, &pstart, &psize) < 0)
+            return AVERROR(EIO);
     }while (idx < 0 || !s->streams[idx]);
 
     ogg = s->priv_data;
     os = ogg->streams + idx;
 
     //Alloc a pkt
-    if (av_new_packet (pkt, os->psize) < 0)
-        return AVERROR_IO;
+    if (av_new_packet (pkt, psize) < 0)
+        return AVERROR(EIO);
     pkt->stream_index = idx;
-    memcpy (pkt->data, os->buf + os->pstart, os->psize);
+    memcpy (pkt->data, os->buf + pstart, psize);
     if (os->lastgp != -1LL){
         pkt->pts = ogg_gptopts (s, idx, os->lastgp);
         os->lastgp = -1;
     }
-    //next
-    os->pstart += os->psize;
-    os->psize = 0;
-    return os->psize;
+
+    return psize;
 }
 
 
@@ -534,110 +569,55 @@ ogg_read_close (AVFormatContext * s)
 
     for (i = 0; i < ogg->nstreams; i++){
         av_free (ogg->streams[i].buf);
-        av_freep (&s->streams[i]->codec.extradata);
+        av_free (ogg->streams[i].private);
     }
     av_free (ogg->streams);
     return 0;
 }
 
 
-static int
-ogg_read_seek (AVFormatContext * s, int stream_index, int64_t target_ts,
-               int flags)
+static int64_t
+ogg_read_timestamp (AVFormatContext * s, int stream_index, int64_t * pos_arg,
+                    int64_t pos_limit)
 {
     ogg_t *ogg = s->priv_data;
     ByteIOContext *bc = &s->pb;
-    uint64_t min = 0, max = ogg->size;
-    uint64_t tmin = 0, tmax = s->duration;
     int64_t pts = AV_NOPTS_VALUE;
-
-    ogg_save (s);
-
-    while (min <= max){
-        uint64_t p = min + (max - min) * target_ts / (tmax - tmin);
-        int i = -1;
-
-        url_fseek (bc, p, SEEK_SET);
-
-        while (!ogg_read_page (s, &i)){
-            if (ogg->streams[i].granule != 0 && ogg->streams[i].granule != -1)
-                break;
-        }
-
-        if (i == -1)
-            break;
-
-        pts = ogg_gptopts (s, i, ogg->streams[i].granule);
-        p = url_ftell (bc);
-
-        if (ABS (pts - target_ts) < 1000000LL)
+    int i;
+    url_fseek(bc, *pos_arg, SEEK_SET);
+    while (url_ftell(bc) < pos_limit && !ogg_read_page (s, &i)) {
+        if (ogg->streams[i].granule != -1 && ogg->streams[i].granule != 0 &&
+            ogg->streams[i].codec && i == stream_index) {
+            pts = ogg_gptopts(s, i, ogg->streams[i].granule);
+            // FIXME: this is the position of the packet after the one with above
+            // pts.
+            *pos_arg = url_ftell(bc);
             break;
-
-        if (pts > target_ts){
-            max = p;
-            tmax = pts;
-        }else{
-            min = p;
-            tmin = pts;
         }
     }
-
-    if (ABS (pts - target_ts) < 1000000LL){
-        ogg_restore (s, 1);
-        ogg_reset (ogg);
-    }else{
-        ogg_restore (s, 0);
-        pts = AV_NOPTS_VALUE;
-    }
-
+    ogg_reset(ogg);
     return pts;
-
-#if 0
-    //later...
-    int64_t pos;
-    if (av_seek_frame_binary (s, stream_index, target_ts, flags) < 0)
-        return -1;
-    pos = url_ftell (&s->pb);
-    ogg_read_timestamp (s, stream_index, &pos, pos - 1);
-#endif
-
 }
 
-#if 0
-static int64_t
-ogg_read_timestamp (AVFormatContext * s, int stream_index, int64_t * pos_arg,
-                    int64_t pos_limit)
+static int ogg_probe(AVProbeData *p)
 {
-    ogg_t *ogg = s->priv_data;
-    ByteIOContext *bc = &s->pb;
-    int64_t pos, pts;
-
-    if (*pos_arg < 0)
-        return AV_NOPTS_VALUE;
-
-    pos = *pos_arg;
+    if (p->buf[0] == 'O' && p->buf[1] == 'g' &&
+        p->buf[2] == 'g' && p->buf[3] == 'S' &&
+        p->buf[4] == 0x0 && p->buf[5] <= 0x7 )
+        return AVPROBE_SCORE_MAX;
+    else
+        return 0;
 }
-#endif
 
-static AVInputFormat ogg_iformat = {
+AVInputFormat ogg_demuxer = {
     "ogg",
     "Ogg",
     sizeof (ogg_t),
-    NULL,
+    ogg_probe,
     ogg_read_header,
     ogg_read_packet,
     ogg_read_close,
-    ogg_read_seek,
-// ogg_read_timestamp, 
+    NULL,
+    ogg_read_timestamp,
     .extensions = "ogg",
 };
-
-int
-ogg_init (void)
-{
-#if 0 // CONFIG_ENCODERS
-    av_register_output_format (&ogg_oformat);
-#endif
-    av_register_input_format (&ogg_iformat);
-    return 0;
-}