>From 9b49a37769c7a80906e9ac3fae2c4d971f855587 Mon Sep 17 00:00:00 2001
From: Mike Scheutzow <mjs973@optonline.net>
Date: Wed,  4 Jul 2012 11:28:07 -0400
Subject: [PATCH] avidec: Fix timestamp calc for MP3 frames.

Correctly handle the demuxing of variable length MP3 frames from an
.avi container. The bad code was using the frame byte length to calculate
a timestamp, which is completely broken. The existing avi muxer already
properly handles the muxing and index creation for variable length MP3 
audio frames.

Fixes the sample file in trac 1432. Fate passes. Tested with both Constant
Frame Rate and Variable Frame Rate avi files.

Signed-off-by: Mike Scheutzow <mjs973@optonline.net>
---
 libavformat/avidec.c |   22 ++++++++++++++++++++++
 1 files changed, 22 insertions(+), 0 deletions(-)

diff --git a/libavformat/avidec.c b/libavformat/avidec.c
index fea0694..1fca257 100644
--- a/libavformat/avidec.c
+++ b/libavformat/avidec.c
@@ -116,6 +116,10 @@ static int guess_ni_flag(AVFormatContext *s);
            (tag >> 24) & 0xff,                          \
            size)
 
+/* calculate the duration of the current frame, in units of AVStream.time_base.
+ * For video, or audio frames with variable byte length, the output value
+ * is defined to be '1'.
+ */
 static inline int get_duration(AVIStream *ast, int len){
     if(ast->sample_size){
         return len;
@@ -656,6 +660,20 @@ static int avi_read_header(AVFormatContext *s)
                     if (ret < 0)
                         return ret;
                     ast->dshow_block_align= st->codec->block_align;
+                    if (st->codec->codec_id == CODEC_ID_MP3 && !ast->sample_size) {
+                        /* st->time_base gives index entry play duration */
+                        int fps = 0;
+                        if (st->time_base.num) {
+                            fps = st->time_base.den / st->time_base.num;
+                        }
+                        if (fps > 41) {
+                            // highest valid frame per sec is 48000/1152
+                            av_log(s, AV_LOG_WARNING, "st%d: MP3 frame rate is invalid (%d FPS)\n", st->id, fps);
+                        } else {
+                            /* handle frames as variable byte length */
+                            ast->dshow_block_align = 0;
+                        }
+                    }
                     if(ast->sample_size && st->codec->block_align && ast->sample_size != st->codec->block_align){
                         av_log(s, AV_LOG_WARNING, "sample size (%d) != block align (%d)\n", ast->sample_size, st->codec->block_align);
                         ast->sample_size= st->codec->block_align;
@@ -1177,6 +1195,7 @@ resync:
                 int index;
                 assert(st->index_entries);
 
+                /* retrieve index of next key frame >= ast->frame_offset */
                 index= av_index_search_timestamp(st, ast->frame_offset, 0);
                 e= &st->index_entries[index];
 
@@ -1204,6 +1223,7 @@ resync:
             } else {
                 pkt->flags |= AV_PKT_FLAG_KEY;
             }
+            /* update stream time to frame timestamp to be retrieved next. */
             ast->frame_offset += get_duration(ast, pkt->size);
         }
         ast->remaining -= size;
@@ -1294,6 +1314,8 @@ static int avi_read_idx1(AVFormatContext *s, int size)
         // switch to non-interleaved to get correct timestamps
         if(last_pos == pos)
             avi->non_interleaved= 1;
+        // in the file index, variable-frame-rate is emulated by using
+        // index entries with len==0
         if(last_idx != pos && len) {
             av_add_index_entry(st, pos, ast->cum_len, len, 0, (flags&AVIIF_INDEX) ? AVINDEX_KEYFRAME : 0);
             last_idx= pos;
-- 
1.7.4

