[FFmpeg-soc] [soc]: r5915 - seek2010/seek_table_test.c

mchinen subversion at mplayerhq.hu
Wed Aug 18 09:03:03 CEST 2010


Author: mchinen
Date: Wed Aug 18 09:03:02 2010
New Revision: 5915

Log:
add test for sample accurate seeking`

Added:
   seek2010/seek_table_test.c

Added: seek2010/seek_table_test.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ seek2010/seek_table_test.c	Wed Aug 18 09:03:02 2010	(r5915)
@@ -0,0 +1,323 @@
+/*
+ * Copyright (c) 2003 Fabrice Bellard
+ * Copyright (c) 2007 Michael Niedermayer
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/** @file
+ *  Tests sample accuracy of seek by table
+ */
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "libavutil/common.h"
+#include "libavformat/avformat.h"
+
+#undef exit
+#undef printf
+#undef fprintf
+
+static char buffer[20];
+
+static const char *ret_str(int v)
+{
+    switch (v) {
+    case AVERROR_EOF:     return "-EOF";
+    case AVERROR(EIO):    return "-EIO";
+    case AVERROR(ENOMEM): return "-ENOMEM";
+    case AVERROR(EINVAL): return "-EINVAL";
+    default:
+        snprintf(buffer, sizeof(buffer), "%2d", v);
+        return buffer;
+    }
+}
+
+static void ts_str(char buffer[60], int64_t ts, AVRational base)
+{
+    double tsval;
+    if (ts == AV_NOPTS_VALUE) {
+        strcpy(buffer, " NOPTS   ");
+        return;
+    }
+    tsval = ts * av_q2d(base);
+    snprintf(buffer, 60, "%9f", tsval);
+}
+
+int main(int argc, char **argv)
+{
+    const char *filename;
+    AVFormatContext *ic = NULL;
+    AVCodecContext *avctx;
+    int i, ret, stream_id;
+    int64_t timestamp;
+    AVFormatParameters params, *ap= &params;
+    int16_t *ref_buf;
+    int16_t *test_buf;
+
+    int offset = 0;
+    int ref_len = 0;
+    int data_size;
+    AVStream* st;
+    AVCodec *codec;
+    int len;
+    int channels;
+    int done_size;
+    int j;
+    int64_t error;
+    int mismatches;
+    int64_t start_ts;
+    int new_test;
+    int done_samples;
+    int offset_samples;
+    int64_t start_pos;
+#define REF_BUF_NB_SAMPLES (44100 * 120)
+
+    ref_buf  = (int16_t*)malloc(REF_BUF_NB_SAMPLES * 2 * sizeof(*ref_buf));
+    test_buf = (int16_t*)malloc(REF_BUF_NB_SAMPLES * 2 * sizeof(*test_buf));
+
+    memset(ap, 0, sizeof(params));
+    ap->channels    = 2;
+    ap->sample_rate = 44100;
+
+    av_log_set_level(99);
+    /* initialize libavcodec, and register all codecs and formats */
+    av_register_all();
+
+    if (argc != 2) {
+        printf("usage: %s input_file\n"
+               "\n", argv[0]);
+        exit(1);
+    }
+
+    filename = argv[1];
+
+    ret = av_open_input_file(&ic, filename, NULL, 0, ap);
+    if (ret < 0) {
+        fprintf(stderr, "cannot open %s\n", filename);
+        exit(1);
+    }
+
+    ret = av_find_stream_info(ic);
+    if (ret < 0) {
+        fprintf(stderr, "%s: could not find codec parameters\n", filename);
+        exit(1);
+    }
+
+    for(i = 0; i < ic->nb_streams; i++) {
+        avctx = ic->streams[i]->codec;
+        if (avctx->codec_type == AVMEDIA_TYPE_AUDIO) {
+            if (avctx->channels > 0) {
+                channels                =
+                avctx->request_channels = FFMIN(2, avctx->channels);
+            } else {
+                channels                =
+                avctx->request_channels = 2;
+            }
+            st = ic->streams[i];
+            start_ts = st->start_time != AV_NOPTS_VALUE ?
+                       st->start_time :
+                      (st->first_dts  != AV_NOPTS_VALUE ?
+                       st->first_dts  : 0);
+
+        }
+
+        codec = avcodec_find_decoder(avctx->codec_id);
+        if (!codec || avcodec_open(avctx, codec) < 0)
+            return -1;
+    }
+    offset = 0;
+    printf("generating ref\n");
+    for(;;) {
+        AVPacket pkt, pkt_tmp;
+        AVStream* st;
+        char ts_buf[60];
+        memset(&pkt, 0, sizeof(pkt));
+        if(ret >= 0){
+            ret= av_read_frame(ic, &pkt);
+            pkt_tmp = pkt;
+            if(ret >= 0 && pkt.size > 0){
+                char dts_buf[60];
+                st= ic->streams[pkt.stream_index];
+
+                while(pkt_tmp.size > 0) {
+                    data_size = sizeof(*ref_buf) * (2 * REF_BUF_NB_SAMPLES - offset);
+                    len = avcodec_decode_audio3(st->codec, ref_buf + offset / sizeof(*ref_buf),
+                                                &data_size, &pkt);
+                    if (len < 0) {
+                        pkt_tmp.size = 0;
+                        break;
+                    }
+
+                    pkt_tmp.data += len;
+                    pkt_tmp.size -= len;
+                    if (data_size <= 0)
+                        continue;
+
+                    printf("offset %d\n",offset);
+                    offset += data_size;
+                    ts_str(dts_buf, pkt.dts, st->time_base);
+                    ts_str(ts_buf,  pkt.pts, st->time_base);
+                    printf("ref ret:%-10s st:%2d flags:%d dts:%s pts:%s pos:%7" PRId64 " size:%6d", ret_str(ret), pkt.stream_index, pkt.flags, dts_buf, ts_buf, pkt.pos, pkt.size);
+
+                    if(offset >= REF_BUF_NB_SAMPLES) {
+                        if(pkt.data)
+                            av_free_packet(&pkt);
+                        goto after_ref;
+                    }
+                }
+                if(pkt.data)
+                    av_free_packet(&pkt);
+            } else
+                printf("ref ret:%s", ret_str(ret)); // necessary to avoid trailing whitespace
+            printf("\n");
+        }
+    }
+after_ref:
+    ret     = 0;
+    ref_len = offset;
+    printf("testing seek\n");
+
+    av_build_index(ic, 0);
+
+    timestamp = 0;
+    if (ret < 0)
+        goto new_seek;
+
+    for(i = 0; ; i++) {
+        AVPacket pkt, pkt_tmp;
+        char ts_buf[60];
+
+        new_test  = 1;
+        done_size = 0;
+        if (ret < 0)
+            goto new_seek;
+        for(;;) {
+            memset(&pkt, 0, sizeof(pkt));
+            if(ret >= 0){
+                start_pos = url_ftell(ic->pb);
+                ret= av_read_frame(ic, &pkt);
+                pkt_tmp = pkt;
+                if(ret >= 0 && pkt.size > 0){
+                    char dts_buf[60];
+                    st= ic->streams[pkt.stream_index];
+
+                    while(pkt_tmp.size > 0) {
+                        if (new_test) {
+                            new_test = 0;
+                            offset   = ((pkt.dts - start_ts)   *
+                                        avctx->sample_rate     *
+                                        channels               *
+                                        av_q2d(st->time_base)) * sizeof(*test_buf);
+                            if(offset < 0 || offset >= REF_BUF_NB_SAMPLES) {
+                                printf("ERROR: negative offset\n");
+                                goto new_seek;
+                            }
+                            printf("testing offset %d, ts %f (pts %f), start_ts %f,"
+                                   "pos %lld\n",
+                                   offset,
+                                   pkt.dts  * av_q2d(st->time_base),
+                                   pkt.pts  * av_q2d(st->time_base),
+                                   start_ts * av_q2d(st->time_base),
+                                   start_pos);
+                            memset(test_buf, 0xFF, sizeof(*test_buf) * 2 * REF_BUF_NB_SAMPLES);
+                        }
+
+                        data_size = sizeof(*test_buf) * (2 * REF_BUF_NB_SAMPLES - offset);
+                        len = avcodec_decode_audio3(st->codec,
+                                                    test_buf + offset / sizeof(*test_buf),
+                                                    &data_size, &pkt);
+                        if (len < 0) {
+                            pkt_tmp.size = 0;
+                            break;
+                        }
+
+                        pkt_tmp.data += len;
+                        pkt_tmp.size -= len;
+                        if (data_size <= 0)
+                            continue;
+
+                        offset    += data_size;
+                        done_size += data_size;
+                        ts_str(dts_buf, pkt.dts, st->time_base);
+                        ts_str(ts_buf,  pkt.pts, st->time_base);
+                        printf("ref ret:%-10s st:%2d flags:%d dts:%s pts:%s pos:%7"
+                               PRId64 " size:%6d",
+                               ret_str(ret), pkt.stream_index, pkt.flags,
+                               dts_buf, ts_buf, pkt.pos, pkt.size);
+
+#define TEST_BUF_READ_MAX (44100 * 1)
+                        if(done_size >= TEST_BUF_READ_MAX) {
+                            if(pkt.data)
+                                av_free_packet(&pkt);
+                            goto single_test_done;
+                        }
+                    }
+                    if(pkt.data)
+                        av_free_packet(&pkt);
+                } else
+                    printf("ref ret:%s", ret_str(ret)); // necessary to avoid trailing whitespace
+                printf("\n");
+            }
+        }
+    single_test_done:
+        error          = 0;
+        mismatches     = 0;
+        done_samples   = done_size / sizeof(*test_buf);
+        offset_samples = offset    / sizeof(*test_buf);
+        printf("compare start %d\n", offset - done_size);
+        for (j = 0; j < done_samples; j++) {
+            error += (int) fabs(test_buf[offset_samples - done_samples + j] -
+                                ref_buf [offset_samples - done_samples + j]);
+            if (test_buf[offset_samples - done_samples + j] -
+                ref_buf [offset_samples - done_samples + j]) {
+                mismatches++;
+            }
+            if(error)
+                printf("%8d %8d  %d  %d\n", test_buf[offset_samples - done_samples + j],
+                       ref_buf [offset_samples - done_samples + j], i, j);
+        }
+
+        if(error)
+            printf("error of %lld found with %d of %d samples mismatching\n",
+                   error, mismatches, done_samples);
+        else
+            printf("No errors\n");
+
+    new_seek:
+        if(i>25) break;
+
+        stream_id = (i >> 1) % (ic->nb_streams + 1) - 1;
+        timestamp = (i * 19362894167LL) % (20 * AV_TIME_BASE) - AV_TIME_BASE;
+        if(stream_id>=0){
+            st= ic->streams[stream_id];
+            timestamp= av_rescale_q(timestamp, AV_TIME_BASE_Q, st->time_base);
+        }
+        //FIXME fully test the new seek API
+        if(i&1) ret = avformat_seek_file(ic, stream_id, INT64_MIN, timestamp, timestamp, 0);
+        else    ret = avformat_seek_file(ic, stream_id, timestamp, timestamp, INT64_MAX, 0);
+        ts_str(ts_buf, timestamp, stream_id < 0 ? AV_TIME_BASE_Q : st->time_base);
+        printf("ret:%-10s st:%2d flags:%d  ts:%s\n", ret_str(ret), stream_id, i & 1, ts_buf);
+    }
+
+    av_close_input_file(ic);
+
+    return 0;
+}


More information about the FFmpeg-soc mailing list