[Ffmpeg-devel] [PATCH] Add True Audio Seeking Support

Måns Rullgård mans
Fri Mar 30 23:21:04 CEST 2007


"Masahiro Kiyota" <hiro3726 at gmail.com> writes:

> Hi,
>
> The attached patch enables applications using libavc/libavf as backend
> (e.g. mplayer) to seek True Audio streams.
>
> In order to enable seeking true audio stream in mplayer, I made some
> changes to tta_read_header() and tta_read_packet() in addition to
> implementing tta_read_seek().
>
> Tested on mplayer and ffplay.
>
> With friendly regards,
> Masahiro
>
> --- libavformat/tta.c.orig      2007-03-30 22:41:59.000000000 +0900
> +++ libavformat/tta.c   2007-03-30 22:54:45.000000000 +0900
> @@ -21,8 +21,10 @@
>  #include "avformat.h"
>  #include "bitstream.h"
>  
> +#define FRAME_TIME 1.04489795918367346939

WTF is this?  I think it deserves a comment at the least.  I also
suspect it ought really be a fraction.

>  typedef struct {
> -    int totalframes, currentframe;
> +    int totalframes, currentframe, firstpos;
>      uint32_t *seektable;
>  } TTAContext;
>  
> @@ -36,6 +38,16 @@ static int tta_probe(AVProbeData *p)
>      return 0;
>  }
>  
> +static uint32_t get_pos(uint32_t *seek_table, int frm)
> +{
> +    uint32_t *st, ret = 0;
> +    

Trailing whitespace.

> +    for (st = seek_table; st < (seek_table + frm); st += 1) {

Useless parens.  Use st++ instead.

> +        ret += *st;
> +    }
> +    return ret;
> +}

This is inefficient.  It could be calculated once along with the
seektable array instead?  Alternatively, to save some memory, store
only the offsets and calculate the sizes when needed.

>  static int tta_read_header(AVFormatContext *s, AVFormatParameters *ap)
>  {
>      TTAContext *c = s->priv_data;
> @@ -64,7 +76,7 @@ static int tta_read_header(AVFormatConte
>  
>      url_fskip(&s->pb, 4); // header crc
>  
> -    framelen = 1.04489795918367346939 * samplerate;
> +    framelen = FRAME_TIME * samplerate;

Things like this should really be done as separate patches.

>      c->totalframes = datalen / framelen + ((datalen % framelen) ? 1 : 0);
>      c->currentframe = 0;
>  
> @@ -99,7 +111,10 @@ static int tta_read_header(AVFormatConte
>      st->codec->extradata = av_mallocz(st->codec->extradata_size+FF_INPUT_BUFFER_PADDING_SIZE);
>      url_fseek(&s->pb, start, SEEK_SET); // or SEEK_CUR and -size ? :)
>      get_buffer(&s->pb, st->codec->extradata, st->codec->extradata_size);
> -
> +    

Trailing whitespace.

> +    c->firstpos = start + st->codec->extradata_size;
> +    s->start_time = 0;
> +    s->duration = FRAME_TIME * c->totalframes * AV_TIME_BASE; // not precise?

If you made FRAME_TIME a fraction this could probably be made
precise.  In fact, the stream timebase should be set to whatever that
fraction is.  Then duration will simply be the frame count.

>      return 0;
>  }
>  
> @@ -109,18 +124,18 @@ static int tta_read_packet(AVFormatConte
>      int ret, size;
>  
>      // FIXME!
> -    if (c->currentframe > c->totalframes)
> +    if (c->currentframe >= c->totalframes)
>          size = 0;
>      else
>          size = c->seektable[c->currentframe];
>  
> -    c->currentframe++;
> -
>      if (av_new_packet(pkt, size) < 0)
>          return AVERROR_IO;
>  
>      pkt->pos = url_ftell(&s->pb);
>      pkt->stream_index = 0;
> +    pkt->pts = (c->currentframe > 0) ? (FRAME_TIME * (c->currentframe) / av_q2d(s->streams[0]->time_base)) : 1;

This looks convoluted.  It could be simplified if the proper timebase
was set instead.

> +    

Trailing whitespace.

>      ret = get_buffer(&s->pb, pkt->data, size);
>      if (ret <= 0) {
>          av_free_packet(pkt);
> @@ -129,6 +144,8 @@ static int tta_read_packet(AVFormatConte
>      pkt->size = ret;
>  //    av_log(s, AV_LOG_INFO, "TTA packet #%d desired size: %d read size: %d at pos %d\n",
>  //        c->currentframe, size, ret, pkt->pos);
> +    c->currentframe++;
> +
>      return 0; //ret;
>  }
>  
> @@ -140,6 +157,25 @@ static int tta_read_close(AVFormatContex
>      return 0;
>  }
>  
> +static int tta_read_seek(AVFormatContext *s, int stream_index, int64_t pts, int flags) 

Trailing whitespace.

> +{
> +    TTAContext *c = s->priv_data;
> +    uint32_t to_frm, seek_pos;
> +    

Trailing whitespace.

> +    if (c->seektable) {
> +        pts = (pts > 0) ? pts : 0;

PTS is usually unsigned, no?

> +        to_frm = (uint32_t)(pts * av_q2d(s->streams[0]->time_base) / FRAME_TIME);

Yuck.  Just set the timebase and be done with it.

> +        if (to_frm >= c->totalframes) return -1; // beyond the end of stream

Put the return -1 on a new line.

> +        

Trailing whitespace.

> +        seek_pos = get_pos(c->seektable, to_frm) + c->firstpos;

See above.

> +//        av_log(s, AV_LOG_INFO, "TTA read_seek time: %lf, to_frame: %d (pos: %x)\n", pts * av_q2d(s->streams[0]->time_base), to_frm, seek_pos);
> +        

Trailing whitespace.

> +        url_fseek(&s->pb, seek_pos, SEEK_SET);
> +        c->currentframe = to_frm;
> +    }
> +    return 0;
> +}
> +
>  AVInputFormat tta_demuxer = {
>      "tta",
>      "true-audio",
> @@ -148,5 +184,6 @@ AVInputFormat tta_demuxer = {
>      tta_read_header,
>      tta_read_packet,
>      tta_read_close,
> +    tta_read_seek,
>      .extensions = "tta",
>  };

I suggest first cleaning up the timebase mess in patch of its own
before adding seeking.

-- 
M?ns Rullg?rd
mans at mansr.com




More information about the ffmpeg-devel mailing list