From: Matthieu Bouron <matthieu.bou...@gmail.com>

Further fixes from Tomas Härdin.

Signed-off-by: Luca Barbato <lu_z...@gentoo.org>
---
 libavformat/mxfdec.c        | 111 ++++++++++++++++++++++++++++++++++++++++++--
 tests/ref/seek/lavf-mxf     |   2 +-
 tests/ref/seek/lavf-mxf_d10 |   2 +-
 3 files changed, 108 insertions(+), 7 deletions(-)

diff --git a/libavformat/mxfdec.c b/libavformat/mxfdec.c
index 60e07b6..c1cf8ec 100644
--- a/libavformat/mxfdec.c
+++ b/libavformat/mxfdec.c
@@ -122,6 +122,8 @@ typedef struct {
     uint8_t track_number[4];
     AVRational edit_rate;
     int intra_only;
+    uint64_t sample_count;
+    int64_t original_duration; /* st->duration in SampleRate/EditRate units */
 } MXFTrack;
 
 typedef struct {
@@ -1427,7 +1429,7 @@ static int mxf_parse_structural_metadata(MXFContext *mxf)
         }
         st->id = source_track->track_id;
         st->priv_data = source_track;
-        st->duration = component->duration;
+        source_track->original_duration = st->duration = component->duration;
         if (st->duration == -1)
             st->duration = AV_NOPTS_VALUE;
         st->start_time = component->start_position;
@@ -1442,6 +1444,10 @@ static int mxf_parse_structural_metadata(MXFContext *mxf)
         }
         avpriv_set_pts_info(st, 64, material_track->edit_rate.den, 
material_track->edit_rate.num);
 
+        /* ensure SourceTrack EditRate == MaterialTrack EditRate since only
+         * the former is accessible via st->priv_data */
+        source_track->edit_rate = material_track->edit_rate;
+
         PRINT_KEY(mxf->fc, "data definition   ul", 
source_track->sequence->data_definition_ul);
         codec_ul = mxf_get_codec_ul(ff_mxf_data_definition_uls, 
&source_track->sequence->data_definition_ul);
         st->codec->codec_type = codec_ul->id;
@@ -1569,6 +1575,12 @@ static int mxf_parse_structural_metadata(MXFContext *mxf)
                 avpriv_set_pts_info(st, 64, 1, 48000);
             }
 
+            /* if duration is set, rescale it from EditRate to SampleRate */
+            if (st->duration != AV_NOPTS_VALUE)
+                st->duration = av_rescale_q(st->duration,
+                                            
av_inv_q(material_track->edit_rate),
+                                            st->time_base);
+
             /* TODO: implement AV_CODEC_ID_RAWAUDIO */
             if (st->codec->codec_id == AV_CODEC_ID_PCM_S16LE) {
                 if (descriptor->bits_per_sample > 16 && 
descriptor->bits_per_sample <= 24)
@@ -2034,6 +2046,63 @@ static int64_t mxf_set_current_edit_unit(MXFContext 
*mxf, int64_t current_offset
     return next_ofs;
 }
 
+static int mxf_compute_sample_count(MXFContext *mxf, int stream_index,
+                                    uint64_t *sample_count)
+{
+    int i, total = 0, size = 0;
+    AVStream *st = mxf->fc->streams[stream_index];
+    MXFTrack *track = st->priv_data;
+    AVRational time_base = av_inv_q(track->edit_rate);
+    AVRational sample_rate = av_inv_q(st->time_base);
+    const MXFSamplesPerFrame *spf = NULL;
+
+    if ((sample_rate.num / sample_rate.den) == 48000)
+        spf = ff_mxf_get_samples_per_frame(mxf->fc, time_base);
+    if (!spf) {
+        int remainder = (sample_rate.num * time_base.num) %
+                        (time_base.den * sample_rate.den);
+        *sample_count = av_q2d(av_mul_q((AVRational){mxf->current_edit_unit, 
1},
+                                        av_mul_q(sample_rate, time_base)));
+        if (remainder)
+            av_log(mxf->fc, AV_LOG_WARNING,
+                   "seeking detected on stream #%d with time base (%d/%d) and "
+                   "sample rate (%d/%d), audio pts won't be accurate.\n",
+                   stream_index, time_base.num, time_base.den,
+                   sample_rate.num, sample_rate.den);
+        return 0;
+    }
+
+    while (spf->samples_per_frame[size]) {
+        total += spf->samples_per_frame[size];
+        size++;
+    }
+
+    if (!size)
+        return 0;
+
+    *sample_count = (mxf->current_edit_unit / size) * (uint64_t)total;
+    for (i = 0; i < mxf->current_edit_unit % size; i++) {
+        *sample_count += spf->samples_per_frame[i];
+    }
+
+    return 0;
+}
+
+static int mxf_set_audio_pts(MXFContext *mxf, AVCodecContext *codec,
+                             AVPacket *pkt)
+{
+    MXFTrack *track = mxf->fc->streams[pkt->stream_index]->priv_data;
+    int64_t bits_per_sample = av_get_bits_per_sample(codec->codec_id);
+
+    pkt->pts = track->sample_count;
+
+    if (codec->channels <= 0 || codec->channels * bits_per_sample < 8)
+        return AVERROR_INVALIDDATA;
+
+    track->sample_count += pkt->size / (codec->channels * bits_per_sample / 8);
+    return 0;
+}
+
 static int mxf_read_packet_old(AVFormatContext *s, AVPacket *pkt)
 {
     KLVPacket klv;
@@ -2058,6 +2127,7 @@ static int mxf_read_packet_old(AVFormatContext *s, 
AVPacket *pkt)
             int64_t next_ofs, next_klv;
             AVStream *st;
             MXFTrack *track;
+            AVCodecContext *codec;
 
             if (index < 0) {
                 av_log(s, AV_LOG_ERROR, "error getting stream index %d\n", 
AV_RB32(klv.key+12));
@@ -2099,7 +2169,9 @@ static int mxf_read_packet_old(AVFormatContext *s, 
AVPacket *pkt)
             pkt->stream_index = index;
             pkt->pos = klv.offset;
 
-            if (s->streams[index]->codec->codec_type == AVMEDIA_TYPE_VIDEO && 
next_ofs >= 0) {
+            codec = s->streams[index]->codec;
+
+            if (codec->codec_type == AVMEDIA_TYPE_VIDEO && next_ofs >= 0) {
                 /* mxf->current_edit_unit good - see if we have an
                  * index table to derive timestamps from */
                 MXFIndexTable *t = &mxf->index_tables[0];
@@ -2114,6 +2186,10 @@ static int mxf_read_packet_old(AVFormatContext *s, 
AVPacket *pkt)
                      * < PTS if low_delay = 0 (Sony IMX30) */
                     pkt->pts = mxf->current_edit_unit;
                 }
+            } else if (codec->codec_type == AVMEDIA_TYPE_AUDIO) {
+                int ret = mxf_set_audio_pts(mxf, codec, pkt);
+                if (ret < 0)
+                    return ret;
             }
 
             /* seek for truncated packets */
@@ -2171,13 +2247,18 @@ static int mxf_read_packet(AVFormatContext *s, AVPacket 
*pkt)
         if ((ret = av_get_packet(s->pb, pkt, size)) != size)
             return ret < 0 ? ret : AVERROR_EOF;
 
+    pkt->stream_index = 0;
+
     if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO && t->ptses &&
         mxf->current_edit_unit >= 0 && mxf->current_edit_unit < t->nb_ptses) {
         pkt->dts = mxf->current_edit_unit + t->first_dts;
         pkt->pts = t->ptses[mxf->current_edit_unit];
+    } else if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO) {
+        int ret = mxf_set_audio_pts(mxf, st->codec, pkt);
+        if (ret < 0)
+            return ret;
     }
 
-    pkt->stream_index = 0;
     mxf->current_edit_unit += edit_units;
 
     return 0;
@@ -2257,8 +2338,14 @@ static int mxf_read_seek(AVFormatContext *s, int 
stream_index, int64_t sample_ti
     int64_t seconds;
     MXFContext* mxf = s->priv_data;
     int64_t seekpos;
-    int ret;
+    int i, ret;
     MXFIndexTable *t;
+    MXFTrack *source_track = st->priv_data;
+
+    /* if audio then truncate sample_time to EditRate */
+    if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO)
+        sample_time = av_rescale_q(sample_time, st->time_base,
+                                   av_inv_q(source_track->edit_rate));
 
     if (mxf->nb_index_tables <= 0) {
     if (!s->bit_rate)
@@ -2287,7 +2374,7 @@ static int mxf_read_seek(AVFormatContext *s, int 
stream_index, int64_t sample_ti
         } else {
             /* no IndexEntryArray (one or more CBR segments)
              * make sure we don't seek past the end */
-            sample_time = FFMIN(sample_time, st->duration - 1);
+            sample_time = FFMIN(sample_time, source_track->original_duration - 
1);
         }
 
         if ((ret = mxf_edit_unit_absolute_offset(mxf, t, sample_time, 
&sample_time, &seekpos, 1)) << 0)
@@ -2297,6 +2384,20 @@ static int mxf_read_seek(AVFormatContext *s, int 
stream_index, int64_t sample_ti
         mxf->current_edit_unit = sample_time;
         avio_seek(s->pb, seekpos, SEEK_SET);
     }
+
+    // Update all tracks sample count
+    for (i = 0; i < s->nb_streams; i++) {
+        AVStream *cur_st = s->streams[i];
+        MXFTrack *cur_track = cur_st->priv_data;
+        uint64_t current_sample_count = 0;
+        if (cur_st->codec->codec_type == AVMEDIA_TYPE_AUDIO) {
+            ret = mxf_compute_sample_count(mxf, i, &current_sample_count);
+            if (ret < 0)
+                return ret;
+
+            cur_track->sample_count = current_sample_count;
+        }
+    }
     return 0;
 }
 
diff --git a/tests/ref/seek/lavf-mxf b/tests/ref/seek/lavf-mxf
index 5f2cf5d..010d6bf 100644
--- a/tests/ref/seek/lavf-mxf
+++ b/tests/ref/seek/lavf-mxf
@@ -30,7 +30,7 @@ ret: 0         st: 0 flags:1  ts: 2.400000
 ret: 0         st: 0 flags:1 dts: 0.840000 pts: 0.960000 pos: 460800 size: 
24712
 ret:-1         st: 1 flags:0  ts: 1.306667
 ret: 0         st: 1 flags:1  ts: 0.200833
-ret: 0         st: 0 flags:1 dts: 0.840000 pts: 0.960000 pos: 460800 size: 
24712
+ret: 0         st: 0 flags:1 dts:-0.040000 pts: 0.000000 pos:   6144 size: 
24801
 ret: 0         st:-1 flags:0  ts:-0.904994
 ret: 0         st: 0 flags:1 dts:-0.040000 pts: 0.000000 pos:   6144 size: 
24801
 ret: 0         st:-1 flags:1  ts: 1.989173
diff --git a/tests/ref/seek/lavf-mxf_d10 b/tests/ref/seek/lavf-mxf_d10
index e091c77..17cca29 100644
--- a/tests/ref/seek/lavf-mxf_d10
+++ b/tests/ref/seek/lavf-mxf_d10
@@ -34,7 +34,7 @@ ret: 0         st: 0 flags:1 dts: 0.960000 pts: 0.960000 
pos:5117952 size:150000
 ret: 0         st: 1 flags:0  ts: 1.306667
 ret: 0         st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos:5117952 
size:150000
 ret: 0         st: 1 flags:1  ts: 0.200833
-ret: 0         st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos:5117952 
size:150000
+ret: 0         st: 0 flags:1 dts: 0.200000 pts: 0.200000 pos:1071104 
size:150000
 ret: 0         st:-1 flags:0  ts:-0.904994
 ret: 0         st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos:   6144 
size:150000
 ret: 0         st:-1 flags:1  ts: 1.989173
-- 
1.8.5.1

_______________________________________________
libav-devel mailing list
libav-devel@libav.org
https://lists.libav.org/mailman/listinfo/libav-devel

Reply via email to